Introduction

This RMarkdown script provides a comprehensive workflow for establishing a normal CD4+ T-cell differentiation trajectory and subsequently projecting Sézary syndrome cell lines onto this reference. The goal is to identify the potential cell of origin for malignant T cells in Sézary syndrome by understanding their position within the normal T-cell developmental landscape. This approach addresses the critical need for a biological reference to interpret the differentiation state of malignant cells.

Overall Workflow

  1. Data Loading and Initial Processing: Load and perform basic quality control on two distinct normal CD4+ T-cell datasets: CD4T_lab (your lab-processed data) and CD4T_10x (publicly available 10x Genomics PBMC-derived CD4+ T cells).
  2. Integration using Seurat RPCA: Integrate these two datasets using Seurat’s Reciprocal PCA (RPCA) integration method to effectively remove batch effects while preserving biological variation.
  3. Cell Type Annotation: Annotate the integrated normal CD4+ T cells using a combination of Azimuth (for robust reference mapping) and SingleR (for fine-grained annotation against a comprehensive reference database). The annotation will focus on identifying and ordering classical CD4+ T-cell differentiation states (e.g., Naive, Central Memory, Effector Memory, Regulatory T cells).
  4. Monocle3 Trajectory Inference: Construct a pseudotime trajectory on the integrated and annotated normal CD4+ T-cell dataset using Monocle3. The trajectory will be rooted in the most naive CD4+ T-cell population.
  5. Sézary Cell Projection: Project your previously analyzed Sézary cell lines onto this established normal CD4+ T-cell trajectory. This will allow for direct comparison of the differentiation states of malignant cells relative to normal T-cell development.
  6. Analysis and Visualization: Analyze gene expression changes along the normal trajectory and assess where the Sézary cells fall, providing insights into their differentiation arrest or deviation.

Data Requirements

Before running this script, ensure you have the following data prepared:

  • CD4T_lab Seurat Object: A Seurat object containing your lab-processed normal CD4+ T-cell data. This should have undergone initial QC and basic processing (e.g., normalization, scaling, variable feature identification).
  • CD4T_10x Seurat Object: A Seurat object containing CD4+ T cells extracted from a publicly available 10x Genomics PBMC dataset. This should also be pre-processed similarly to your CD4T_lab data.
  • sezary_cell_lines Seurat Object: Your integrated Seurat object containing the Sézary syndrome cell lines (RNA, CITE-seq, TCR data), which you have already processed and analyzed. This object should have a UMAP reduction and cell type annotations.

Note on Data Preparation: It is crucial that both normal CD4+ T-cell datasets and your Sézary cell line dataset share common gene sets and ideally similar processing steps up to the point of integration to ensure compatibility.

Phase 1: Data Loading and Subsetting Normal Controls (SCTransform Compatible)

This phase focuses on loading your main Seurat object (All_sample_Merged) which has already been processed with SCTransform and 3000 features. We will then subset the normal CD4+ T-cell controls (CD4T_lab and CD4T_10x) based on their orig.ident values. This ensures that all subsequent analyses on these normal controls leverage the consistent SCT assay and feature set.

Load Libraries

library(Seurat)
library(tidyverse)
library(patchwork)

# Set a consistent ggplot2 theme
theme_set(theme_bw() + theme(text = element_text(size = 12)))

Load Main Seurat Object (All_sample_Merged) and Inspect Sample Composition

Replace path/to/your/All_sample_Merged.rds with the actual path to your main Seurat object. This object should already contain the SCT assay as its default, with 3000 variable features.

# Ensure the SCT assay is the default
DefaultAssay(main_seurat) <- "SCT"

# Inspect the orig.ident to see all sample identifiers
print("Sample composition in orig.ident:")
[1] "Sample composition in orig.ident:"
print(table(main_seurat$orig.ident))

      L1       L2       L3       L4       L5       L6       L7 CD4T_lab CD4T_10x 
    5825     5935     6428     6006     6022     5148     5331     5106     3504 
# Visualize sample distribution (using the UMAP from the main object)
sample_plot <- DimPlot(main_seurat, reduction = "umap", group.by = "orig.ident", label = TRUE) +
  ggtitle("All Samples in Main Seurat Object (SCTransformed)")
print(sample_plot)


print(main_seurat)
An object of class Seurat 
62900 features across 49305 samples within 6 assays 
Active assay: SCT (26176 features, 3000 variable features)
 3 layers present: counts, data, scale.data
 5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
 5 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony

Subset Normal CD4+ T-cell Controls

Now we will extract only the normal control samples (CD4T_lab and CD4T_10x) from the main object to create our reference trajectory. These subsetted objects will automatically inherit the SCT assay.

# Subset normal CD4+ T-cell controls based on orig.ident
# Adjust the identifiers if they are named differently in your data
normal_controls <- subset(main_seurat, subset = orig.ident %in% c("CD4T_lab", "CD4T_10x"))

# Verify the subsetting worked correctly
print("Normal controls after subsetting:")
[1] "Normal controls after subsetting:"
print(table(normal_controls$orig.ident))

CD4T_lab CD4T_10x 
    5106     3504 
# Add a \'dataset\' metadata column for clarity
normal_controls$dataset <- normal_controls$orig.ident

# Ensure SCT assay is default for the subsetted object
DefaultAssay(normal_controls) <- "SCT"

# Basic QC visualization for the normal controls
# Note: If percent.mt, nCount_RNA, nFeature_RNA were regressed out during SCTransform,
# these plots might show less variation. However, they are still useful for checking.
if(!"percent.mt" %in% colnames(normal_controls@meta.data)) {
  normal_controls[["percent.mt"]] <- PercentageFeatureSet(normal_controls, pattern = "^MT-")
}

vln_plot_normal <- VlnPlot(normal_controls, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), 
                          group.by = "dataset", ncol = 3, pt.size = 0.1) 
print(vln_plot_normal)


# Optional: Apply additional QC filtering if needed (though already done on main object)
 normal_controls <- subset(normal_controls, subset = nFeature_RNA > 200 & nFeature_RNA < 4000 & percent.mt < 6)

print(paste("Total normal control cells:", ncol(normal_controls)))
[1] "Total normal control cells: 8457"
print(paste("CD4T_lab cells:", sum(normal_controls$orig.ident == "CD4T_lab")))
[1] "CD4T_lab cells: 5053"
print(paste("CD4T_10x cells:", sum(normal_controls$orig.ident == "CD4T_10x")))
[1] "CD4T_10x cells: 3404"
print(normal_controls)
An object of class Seurat 
62900 features across 8457 samples within 6 assays 
Active assay: SCT (26176 features, 3000 variable features)
 3 layers present: counts, data, scale.data
 5 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3
 5 dimensional reductions calculated: integrated_dr, ref.umap, pca, umap, harmony
vln_plot_normal <- VlnPlot(normal_controls, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), 
                          group.by = "dataset", ncol = 3, pt.size = 0.1) 
print(vln_plot_normal)

Prepare for Integration

Since these samples were processed together in your main object, they should already share the same gene set and basic preprocessing. We will now split them and prepare for RPCA integration to remove any remaining batch effects between the two normal control datasets in the SCT assay.

# Split the normal controls object by dataset for integration
normal_list <- SplitObject(normal_controls, split.by = "orig.ident")

# Verify the split
print("Split normal controls:")
[1] "Split normal controls:"
for(i in names(normal_list)) {
  print(paste(i, ":", ncol(normal_list[[i]]), "cells"))
}
[1] "CD4T_lab : 5053 cells"
[1] "CD4T_10x : 3404 cells"
# SCTransform has already been applied to the main object, so we don't need to run it again here.
# However, for RPCA, we need to ensure the `SCT` assay is the default for each object in the list.
for (i in 1:length(normal_list)) {
  DefaultAssay(normal_list[[i]]) <- "SCT"
}

# Merge objects
temp_merged <- merge(normal_list[["CD4T_lab"]], y = normal_list[["CD4T_10x"]],
                     add.cell.ids = c("Lab", "10x"), project = "NormalCD4T_PreIntegration")

DefaultAssay(temp_merged) <- "SCT"

# Use SCTransform variable features from each object and combine them
# Seurat recommends taking the top variable features from each object (union or intersection)
var_features_lab <- VariableFeatures(normal_list[["CD4T_lab"]])
var_features_10x <- VariableFeatures(normal_list[["CD4T_10x"]])

# Combine and remove unwanted genes
combined_var_features <- setdiff(union(var_features_lab, var_features_10x), 
                                 grep("^HLA-|^TR[ABGD]|^IG[HKL]|^XIST$", rownames(temp_merged), value = TRUE))

# Assign to merged object
VariableFeatures(temp_merged) <- combined_var_features

# Now PCA will work
temp_merged <- RunPCA(temp_merged, verbose = FALSE)


# Visualize the elbow plot
ElbowPlot(temp_merged, ndims = 50) + ggtitle("PCA Elbow Plot - Normal Controls")


temp_merged <- RunUMAP(temp_merged, dims = 1:15, verbose = FALSE)

# Plot UMAP colored by dataset to show potential batch effect
pre_integration_plot <- DimPlot(temp_merged, reduction = "umap", group.by = "dataset") +
  ggtitle("Normal Controls before RPCA Integration (SCT Assay)")
print(pre_integration_plot)


DimPlot(temp_merged, reduction = "umap", group.by = "predicted.celltype.l2", label = TRUE, label.box = T, repel = T)

DimPlot(temp_merged, reduction = "umap", group.by = "Prediction", label = TRUE, label.box = T, repel = T)



# Clean up temporary object
rm(temp_merged)
gc()
             used    (Mb) gc trigger    (Mb)   max used    (Mb)
Ncells    4190807   223.9    7567777   404.2    7567777   404.2
Vcells 1608502678 12272.0 2608179701 19898.9 2233257975 17038.5
print("Normal controls prepared for RPCA integration using SCT assay.")
[1] "Normal controls prepared for RPCA integration using SCT assay."

Phase 2: Integration using Seurat RPCA (SCTransform Compatible)

This phase details the integration of the CD4T_lab and CD4T_10x datasets using Seurat’s Reciprocal PCA (RPCA) integration method. Since your data has been processed with SCTransform, we will ensure that the integration steps are compatible with the SCT assay. RPCA is particularly effective for integrating datasets with significant biological differences or large batch effects, as it identifies shared biological signals while minimizing technical variation. This is crucial for creating a unified reference map for normal CD4+ T-cell differentiation.

Why RPCA with SCTransform?

When working with SCTransform data, it’s important to use integration methods that are designed to work with the corrected counts or normalized values produced by SCTransform. RPCA, when combined with PrepSCTIntegration and specifying normalization.method = "SCT", ensures that the integration leverages the benefits of SCTransform’s improved normalization and variance stabilization. This leads to more accurate anchor finding and better batch effect correction.

Perform RPCA Integration

# Increase future global size to 5 GB (adjust as needed)
options(future.globals.maxSize = 5 * 1024^3)  # 5 GB

# List of Seurat objects to integrate (normal_list created in Phase 1)

# For SCTransform data, we need to run `PrepSCTIntegration` before finding anchors.
# This function ensures that the SCT assay is properly prepared for integration.
normal_list <- PrepSCTIntegration(object.list = normal_list, anchor.features = 3000, verbose = FALSE)

# Select integration features
# When using PrepSCTIntegration, features are already selected, but we can re-confirm.
features <- SelectIntegrationFeatures(object.list = normal_list, nfeatures = 3000)

# Remove unwanted genes from integration features
unwanted_genes <- grep("^HLA-|^TR[ABGD]|^IG[HKL]|^XIST$", features, value = TRUE)
features <- setdiff(features, unwanted_genes)

# Find integration anchors using RPCA
# We specify `normalization.method = "SCT"` to ensure anchors are found on SCT-normalized data.
cd4t_anchors <- FindIntegrationAnchors(object.list = normal_list, anchor.features = features, 
                                       normalization.method = "SCT", reduction = "rpca", verbose = FALSE)

  |                                                  | 0 % ~calculating  
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=05s  
# Integrate the datasets
# This step uses the identified anchors to correct for batch effects and create a combined expression matrix
cd4t_integrated <- IntegrateData(anchorset = cd4t_anchors, normalization.method = "SCT", verbose = FALSE)
[1] 1
[1] 2
print(cd4t_integrated)
An object of class Seurat 
65786 features across 8457 samples within 7 assays 
Active assay: integrated (2886 features, 2886 variable features)
 2 layers present: data, scale.data
 6 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3, SCT

Scale and Perform Dimensionality Reduction on Integrated Data

After integration, we need to scale the integrated data, perform PCA, and then generate a UMAP embedding to visualize the integrated cell populations. The integrated assay now contains the batch-corrected expression values, derived from the SCT-normalized data.

# Set default assay to 'integrated' for downstream analysis
DefaultAssay(cd4t_integrated) <- "integrated"


# Remove unwanted genes from variable features
unwanted_genes <- grep("^HLA-|^TR[ABGD]|^IG[HKL]|^XIST$|^MALAT1$", 
                       rownames(cd4t_integrated), value = TRUE)
VariableFeatures(cd4t_integrated) <- setdiff(VariableFeatures(cd4t_integrated), unwanted_genes)
# Confirm removal
VariableFeatures(cd4t_integrated)[1:10]  # just to inspect the first few
 [1] "CCL17" "CCL1"  "CCL4"  "PPBP"  "CCL3"  "OASL"  "IFIT2" "GZMB"  "XCL1"  "CSF2" 
# Run PCA on the integrated data
# When using SCTransform, scaling is typically handled by the SCTransform function itself.
# The `integrated` assay is already scaled for PCA by the integration process.
cd4t_integrated <- RunPCA(cd4t_integrated, npcs = 50, verbose = FALSE)

# Visualize elbow plot
ElbowPlot(cd4t_integrated, ndims = 50) + ggtitle("Elbow Plot - Integrated Normal CD4T")


# Run UMAP on the integrated data
cd4t_integrated <- RunUMAP(cd4t_integrated, reduction = "pca", dims = 1:20, verbose = FALSE)

# Find clusters on the integrated data
cd4t_integrated <- FindNeighbors(cd4t_integrated, reduction = "pca", dims = 1:20, verbose = FALSE)
cd4t_integrated <- FindClusters(cd4t_integrated, resolution = c(0.2, 0.3,0.4, 0.5), verbose = FALSE)

print(cd4t_integrated)
An object of class Seurat 
65786 features across 8457 samples within 7 assays 
Active assay: integrated (2886 features, 2885 variable features)
 2 layers present: data, scale.data
 6 other assays present: RNA, ADT, prediction.score.celltype.l1, prediction.score.celltype.l2, prediction.score.celltype.l3, SCT
 2 dimensional reductions calculated: pca, umap

Visualize Integrated Data

Now, we can visualize the integrated data to confirm that batch effects have been successfully removed and that cells from different datasets are well-mixed within their respective biological populations.

# Plot UMAP colored by dataset to show successful integration
integrated_plot_dataset <- DimPlot(cd4t_integrated, reduction = "umap", group.by = "dataset") +
  ggtitle("UMAP after RPCA Integration (Batch Effect Removed)")
print(integrated_plot_dataset)


# Plot UMAP colored by cluster to see the clustering results
integrated_plot_clusters <- DimPlot(cd4t_integrated, reduction = "umap", group.by = "integrated_snn_res.0.2", label = TRUE) +
  ggtitle("UMAP of Integrated Normal CD4+ T Cells (Clusters)")
print(integrated_plot_clusters)


# Combine plots for comparison
combined_integration_plots <- integrated_plot_dataset + integrated_plot_clusters
print(combined_integration_plots)


DimPlot(cd4t_integrated, reduction = "umap", group.by = "integrated_snn_res.0.3", label = TRUE, label.box = T, repel = T)

DimPlot(cd4t_integrated, reduction = "umap", group.by = "integrated_snn_res.0.4", label = TRUE, label.box = T, repel = T)

DimPlot(cd4t_integrated, reduction = "umap", group.by = "integrated_snn_res.0.5", label = TRUE, label.box = T, repel = T)


DimPlot(cd4t_integrated, reduction = "umap", group.by = "predicted.celltype.l2", label = TRUE, label.box = T, repel = T)

DimPlot(cd4t_integrated, reduction = "umap", group.by = "Prediction", label = TRUE, label.box = T, repel = T)



# Save the integrated object for subsequent steps
saveRDS(cd4t_integrated, "integrated_normal_cd4t_seurat_object.rds")

print("RPCA integration complete. Integrated Seurat object saved.")
[1] "RPCA integration complete. Integrated Seurat object saved."

Phase 3: Cell Type Annotation and Differentiation Path Ordering (Using Existing Annotations)

Since your integrated object already contains cell type annotations from Azimuth (Prediction and predicted.celltype.l2 columns), we will utilize these existing annotations to define the CD4+ T-cell differentiation path. This phase focuses on organizing these annotations into a biologically meaningful order for trajectory inference, following the approach used by Cerapio et al. for CD8+ T cells, but adapted for CD4+ T-cell differentiation.

Load Integrated Seurat Object (if starting from here)

If you are running this script in sections, ensure you load the cd4t_integrated object saved from the previous phase.

# Uncomment and run if starting from this phase
# library(Seurat)
# cd4t_integrated <- readRDS("path/to/save/integrated_normal_cd4t_seurat_object.rds")
# DefaultAssay(cd4t_integrated) <- "integrated"
# print(cd4t_integrated)

Inspect Existing Cell Type Annotations

First, let’s examine the existing cell type annotations in your integrated object to understand what CD4+ T-cell subsets are present.

# Check available metadata columns
print("Available metadata columns:")
[1] "Available metadata columns:"
print(colnames(cd4t_integrated@meta.data))
 [1] "orig.ident"                         "nCount_RNA"                        
 [3] "nFeature_RNA"                       "nCount_ADT"                        
 [5] "nFeature_ADT"                       "nUMI"                              
 [7] "ngene"                              "cell_line"                         
 [9] "Patient_origin"                     "Patient_Immunophenotype"           
[11] "condition_of_amplification_in_vivo" "culture_medium"                    
[13] "Stromal_cells"                      "Cell_line_Immunophenotype"         
[15] "TP53_mutation"                      "age_at_diagnosis"                  
[17] "stage_diagnosis"                    "stage_analysis"                    
[19] "Treatments_analysis"                "TCRVB2"                            
[21] "CD3_M"                              "CD30_M"                            
[23] "CCR4_M"                             "CD162_BL"                          
[25] "CD26_BL"                            "CD7_M"                             
[27] "CLA_BD"                             "CD4_BD"                            
[29] "CCR7_M"                             "CD45RO_BD"                         
[31] "CD45RA_BD"                          "CellName"                          
[33] "percent.mt"                         "CD26_BD"                           
[35] "CD45RA_M"                           "predicted.celltype.l1.score"       
[37] "predicted.celltype.l1"              "predicted.celltype.l2.score"       
[39] "predicted.celltype.l2"              "predicted.celltype.l3.score"       
[41] "predicted.celltype.l3"              "mapping.score"                     
[43] "percent.rb"                         "nCount_SCT"                        
[45] "nFeature_SCT"                       "S.Score"                           
[47] "G2M.Score"                          "Phase"                             
[49] "old.ident"                          "CC.Difference"                     
[51] "SCT_snn_res.0.4"                    "SCT_snn_res.0.5"                   
[53] "SCT_snn_res.0.6"                    "SCT_snn_res.0.7"                   
[55] "SCT_snn_res.0.8"                    "seurat_clusters"                   
[57] "harmony_res_0.1"                    "harmony_res_0.2"                   
[59] "harmony_res_0.3"                    "harmony_res_0.4"                   
[61] "harmony_res_0.5"                    "harmony_res_0.6"                   
[63] "harmony_res_0.7"                    "harmony_res_0.8"                   
[65] "harmony_res_0.9"                    "harmony_res_1"                     
[67] "harmony_res_1.2"                    "predicted.celltype.l1_backup"      
[69] "predicted.celltype.l2_backup"       "predicted.celltype.l3_backup"      
[71] "Prediction"                         "Cluster"                           
[73] "Uncertainty_score"                  "Condition"                         
[75] "dataset"                            "integrated_snn_res.0.5"            
[77] "integrated_snn_res.0.2"             "integrated_snn_res.0.3"            
[79] "integrated_snn_res.0.4"            
# Inspect the existing annotations
if("Prediction" %in% colnames(cd4t_integrated@meta.data)) {
  print("Prediction column cell types:")
  print(table(cd4t_integrated$Prediction))
}
[1] "Prediction column cell types:"

  CD4 proliferation             CD4 Tcm            CD4 Tisg CD4 Tisg cell-death              CD4 Tn 
                 13                2429                  42                 190                5689 
           CD4 Tstr              None T 
                  5                  89 
if("predicted.celltype.l2" %in% colnames(cd4t_integrated@meta.data)) {
  print("predicted.celltype.l2 column cell types:")
  print(table(cd4t_integrated$predicted.celltype.l2))
}
[1] "predicted.celltype.l2 column cell types:"

  CD4 CTL CD4 Naive   CD4 TCM   CD4 TEM 
       12      1834      6530        81 
# Visualize existing annotations
if("Prediction" %in% colnames(cd4t_integrated@meta.data)) {
  p_prediction <- DimPlot(cd4t_integrated, reduction = "umap", group.by = "Prediction", label = TRUE, repel = TRUE) +
    ggtitle("Existing Cell Type Annotations (Prediction)")
  print(p_prediction)
}


if("predicted.celltype.l2" %in% colnames(cd4t_integrated@meta.data)) {
  p_predicted_l2 <- DimPlot(cd4t_integrated, reduction = "umap", group.by = "predicted.celltype.l2", label = TRUE, repel = TRUE) +
    ggtitle("Existing Cell Type Annotations (predicted.celltype.l2)")
  print(p_predicted_l2)
}


# Check cluster composition
table(cd4t_integrated$integrated_snn_res.0.5, cd4t_integrated$predicted.celltype.l2)
   
    CD4 CTL CD4 Naive CD4 TCM CD4 TEM
  0       0       383    1786       3
  1       3         3    1749      21
  2       8         0    1234      53
  3       0       853     429       1
  4       0       563     547       0
  5       0        17     676       3
  6       0        15      93       0
  7       1         0      16       0
# Check cluster composition
table(cd4t_integrated$integrated_snn_res.0.5, cd4t_integrated$Prediction)
   
    CD4 proliferation CD4 Tcm CD4 Tisg CD4 Tisg cell-death CD4 Tn CD4 Tstr None T
  0                 0      31       21                   0   2109        4      7
  1                 0    1226        8                   0    531        0     11
  2                 0     988       11                   1    293        0      2
  3                 0      86        0                   0   1196        0      1
  4                 0      78        0                   0   1031        1      0
  5                 0      20        2                 189    465        0     20
  6                 0       0        0                   0     60        0     48
  7                13       0        0                   0      4        0      0
markers <- c("CCR7","SELL","IL7R","TCF7","GZMK","GZMB","IFNG","PRF1","NKG7","MKI67","TOP2A","FOXP3","IL2RA")
avg_exp <- AverageExpression(cd4t_integrated, assays = "SCT", features = markers)
avg_exp$SCT
13 x 8 sparse Matrix of class "dgCMatrix"
                g0          g1           g2           g3           g4          g5         g6        g7
CCR7  4.5543278085 3.094594595  1.610038610 3.2447388932 2.8513513514 3.318965517 1.81481481 1.4705882
SELL  3.1652854512 3.228040541  2.573745174 5.0413094310 4.0729729730 1.251436782 1.88888889 2.9411765
IL7R  1.5828729282 6.864864865 10.414671815 6.7100545596 4.5720720721 3.580459770 4.67592593 4.7647059
TCF7  3.7269797422 2.426238739  3.005405405 5.1371784879 4.2198198198 2.172413793 3.46296296 2.6470588
GZMK  0.0161141805 0.074324324  0.288030888 0.0187061574 0.0108108108 0.037356322 .          0.4117647
GZMB  0.0004604052 0.004504505  0.005405405 0.0007794232 0.0018018018 .           .          .        
IFNG  0.0004604052 0.001126126  0.009266409 0.0031176929 0.0027027027 0.004310345 .          .        
PRF1  0.0156537753 0.036599099  0.135907336 0.1013250195 0.0954954955 0.025862069 0.01851852 0.2941176
NKG7  0.0041436464 0.015765766  0.103474903 0.0077942323 0.0063063063 0.002873563 .          0.6470588
MKI67 0.0027624309 0.002815315  0.009266409 0.0023382697 0.0027027027 .           0.01851852 .        
TOP2A 0.0023020258 0.008445946  0.009266409 0.0007794232 0.0009009009 .           .          .        
FOXP3 0.0188766114 0.032094595  0.107335907 0.0077942323 0.0045045045 0.011494253 .          .        
IL2RA 0.0686003683 0.069819820  0.121235521 0.0163678878 0.0081081081 0.081896552 0.20370370 .        
library(pheatmap)
pheatmap(avg_exp$SCT, cluster_rows = FALSE, cluster_cols = FALSE,
         main = "CD4 T-cell marker expression per cluster")

Define CD4+ T-cell Differentiation Path

Based on the existing annotations, we will create a ordered differentiation path similar to Cerapio et al.’s approach. The typical CD4+ T-cell differentiation progression follows: Naive CD4+ T cells (CD4Tn) → Central Memory (CD4Tcm) → Effector Memory (CD4Tem) → potentially other specialized subsets.

# Ensure cluster column exists
table(cd4t_integrated$integrated_snn_res.0.5)

   0    1    2    3    4    5    6    7 
2172 1776 1295 1283 1110  696  108   17 
# Map clusters to differentiation stages based on marker expression
cluster_to_stage <- c(
  "0" = "CD4Tn",          # g0: CCR7, SELL, IL7R high → Naive
  "1" = "CD4Tcm",         # g1: CCR7, SELL, IL7R high → Central Memory
  "2" = "CD4Tcm_CTL",     # g2: IL7R very high, moderate cytotoxic markers → Hybrid central memory / early CTL
  "3" = "CD4Tn",          # g3: CCR7, TCF7, SELL high → Naive
  "4" = "CD4Tcm",         # g4: CCR7, TCF7 → Central Memory
  "5" = "CD4Tcm",         # g5: MKI67/TOP2A low → treat as central memory (not proliferating)
  "6" = "CD4Tcm",         # g6: MKI67/TOP2A low → treat as central memory
  "7" = "CD4Tctl"         # g7: GZMK, PRF1, NKG7 high → Cytotoxic
)

# Assign differentiation stage to each cell
diff_stage_vec <- sapply(cd4t_integrated$integrated_snn_res.0.5, 
                         function(x) cluster_to_stage[as.character(x)])
names(diff_stage_vec) <- colnames(cd4t_integrated)
cd4t_integrated <- AddMetaData(cd4t_integrated, metadata = diff_stage_vec, col.name = "differentiation_stage")

# Set ordered factor for trajectory or plotting
differentiation_order <- c("CD4Tn", "CD4Tcm", "CD4Tcm_CTL", "CD4Tctl")
cd4t_integrated$differentiation_stage <- factor(cd4t_integrated$differentiation_stage, 
                                                levels = differentiation_order)

# Check cluster counts
table(cd4t_integrated$differentiation_stage)

     CD4Tn     CD4Tcm CD4Tcm_CTL    CD4Tctl 
      3455       3690       1295         17 
# # Use the more detailed annotation column (predicted.celltype.l2 if available, otherwise Prediction)
# if("predicted.celltype.l2" %in% colnames(cd4t_integrated@meta.data)) {
#   cd4t_integrated$cell_type_detailed <- cd4t_integrated$predicted.celltype.l2
# } else if("Prediction" %in% colnames(cd4t_integrated@meta.data)) {
#   cd4t_integrated$cell_type_detailed <- cd4t_integrated$Prediction
# } else {
#   stop("Neither 'Prediction' nor 'predicted.celltype.l2' columns found in metadata")
# }
# 
# # Map detailed cell types to differentiation stages
# # You may need to adjust these mappings based on your actual annotation results
# cd4t_integrated$differentiation_stage <- cd4t_integrated$cell_type_detailed
# 
# # Create a mapping from detailed cell types to ordered differentiation stages
# # This is a template - adjust based on your actual cell type names
# differentiation_mapping <- c(
#   # Naive CD4+ T cells (earliest stage)
#   "CD4 Naive" = "CD4Tn",
#   "CD4 Tn" = "CD4Tn",
#   
#   
#   # Central Memory CD4+ T cells
#   "CD4 TCM" = "CD4Tcm", 
#   "CD4 Tcm" = "CD4Tcm",
#  
# 
#   # Effector Memory CD4+ T cells
#   "CD4 TEM" = "CD4Tem",
#   
#   # Cytotoxic CD4+ T cells
#   "CD4 CTL" = "CD4ctl",
#   
#   
#   # Other CD4+ subsets (adjust as needed)
#   "CD4 proliferation" = "CD4p",
# )
# 
# # Apply the mapping
# for(original_name in names(differentiation_mapping)) {
#   cd4t_integrated$differentiation_stage[cd4t_integrated$cell_type_detailed == original_name] <- differentiation_mapping[original_name]
# }
# 
# # Check the mapping results
# print("Differentiation stage mapping results:")
# print(table(cd4t_integrated$differentiation_stage))
# 
# # Define the biological order for trajectory inference (from naive to most differentiated)
# differentiation_order <- c("CD4Tn", "CD4Tcm", "CD4Tem", "CD4Tctl", "CD4p")
# 
# # Filter to only include stages present in the data
# present_stages <- intersect(differentiation_order, unique(cd4t_integrated$differentiation_stage))
# cd4t_integrated$differentiation_stage <- factor(cd4t_integrated$differentiation_stage, levels = present_stages)
# 
# print("Final differentiation stages (in order):")
# print(levels(cd4t_integrated$differentiation_stage))

Visualize Differentiation Path

# Plot the ordered differentiation stages
p_diff_stages <- DimPlot(cd4t_integrated, reduction = "umap", group.by = "differentiation_stage", label = TRUE, repel = TRUE) +
  ggtitle("CD4+ T-cell Differentiation Stages (Ordered)") +
  theme(legend.position = "bottom")
print(p_diff_stages)


# Create a summary table of cell counts per stage
stage_summary <- table(cd4t_integrated$differentiation_stage, cd4t_integrated$dataset)
print("Cell counts per differentiation stage by dataset:")
[1] "Cell counts per differentiation stage by dataset:"
print(stage_summary)
            
             CD4T_10x CD4T_lab
  CD4Tn          1278     2177
  CD4Tcm         1169     2521
  CD4Tcm_CTL      944      351
  CD4Tctl          13        4
# Visualize marker genes for validation
# These are canonical CD4+ T-cell differentiation markers
marker_genes <- c("CCR7", "SELL", "IL7R", "CD44", "GZMB", "PRF1", "FOXP3", "CXCR5", "BCL6")
available_markers <- intersect(marker_genes, rownames(cd4t_integrated))

if(length(available_markers) > 0) {
  # Switch to SCT assay for marker visualization
  DefaultAssay(cd4t_integrated) <- "SCT"
  
  p_markers <- FeaturePlot(cd4t_integrated, features = available_markers, ncol = 3, reduction = "umap")
  print(p_markers)
  
  # Switch back to integrated assay
  DefaultAssay(cd4t_integrated) <- "integrated"
}


# Save the annotated object
saveRDS(cd4t_integrated, "annotated_normal_cd4t_seurat_object.rds")

print("Cell type annotation and differentiation path ordering complete.")
[1] "Cell type annotation and differentiation path ordering complete."

Phase 4: Monocle3 Trajectory Inference on Normal CD4+ T Cells (SCTransform Compatible)

With the integrated and accurately annotated normal CD4+ T-cell dataset, we can now proceed with constructing the differentiation trajectory using Monocle3. This will establish the reference map onto which the Sézary cells will later be projected. Monocle3 is well-suited for this task due to its ability to model complex, branching trajectories and assign pseudotime values, representing the progression of cells through a biological process.

Why Monocle3 with SCTransform Data?

When working with SCTransform-processed data, it’s important to understand how Monocle3 handles the different assays. While we used the integrated assay for dimensionality reduction and clustering, Monocle3 typically works best with raw counts or log-normalized data for its core trajectory inference algorithms. The SCT assay contains corrected counts that can be used, but we’ll primarily use the RNA assay’s counts for Monocle3 while leveraging the UMAP embedding from our integrated analysis.

Load Annotated Integrated Seurat Object (if starting from here)

If you are running this script in sections, ensure you load the cd4t_integrated object saved from the previous phase.

# Uncomment and run if starting from this phase
# library(Seurat)
# cd4t_integrated <- readRDS("path/to/save/annotated_normal_cd4t_seurat_object.rds")
# DefaultAssay(cd4t_integrated) <- "integrated"
# print(cd4t_integrated)

Install and Load Monocle3

# Install Monocle3 if not already installed
# BiocManager::install(c("monocle3"))
library(monocle3)
library(Seurat)
library(tidyverse)
library(patchwork)

Prepare Data for Monocle3

Monocle3 requires a cell_data_set (CDS) object. We will convert our integrated Seurat object into a CDS object, ensuring that the UMAP embedding and the differentiation_stage annotations are correctly transferred. It’s important to use the RNA assay’s raw counts for Monocle3’s core functions, even though the integrated assay was used for dimensionality reduction.

# Ensure the RNA assay is available and contains counts
# Monocle3 typically works best with raw counts for accurate dispersion estimation
DefaultAssay(cd4t_integrated) <- "RNA"

#  Join the RNA layers
cd4t_integrated <- JoinLayers(cd4t_integrated, new.assay = "RNA")

# Extract expression matrix (raw counts)
# Using counts is generally recommended for Monocle3
expression_matrix <- GetAssayData(cd4t_integrated, assay = "RNA", slot = "counts")

# Extract cell metadata
cell_metadata <- cd4t_integrated@meta.data

# Create gene metadata (simple dataframe with gene names)
gene_metadata <- data.frame(gene_short_name = rownames(expression_matrix), 
                           row.names = rownames(expression_matrix))

# Create the CDS object
cds_normal <- new_cell_data_set(expression_matrix, 
                               cell_metadata = cell_metadata, 
                               gene_metadata = gene_metadata)

# Add the UMAP embedding from Seurat to the CDS object
# Monocle3 can use the existing UMAP embedding from our integrated analysis
if("umap" %in% names(cd4t_integrated@reductions)) {
  cds_normal@int_colData@listData$reducedDims$UMAP <- cd4t_integrated@reductions$umap@cell.embeddings
} else {
  stop("UMAP reduction not found in Seurat object. Please ensure it's computed.")
}

# Add partitions (clusters) from Seurat to CDS
# This is important for Monocle3's graph learning
partitions <- as.factor(cd4t_integrated$seurat_clusters)
names(partitions) <- colnames(cd4t_integrated)
cds_normal@clusters$UMAP$partitions <- partitions

print(cds_normal)
class: cell_data_set 
dim: 36601 8457 
metadata(1): cds_version
assays(1): counts
rownames(36601): MIR1302-2HG FAM138A ... AC007325.4 AC007325.2
rowData names(1): gene_short_name
colnames(8457): PBMC_AAACCTGAGAAACCAT-1 PBMC_AAACCTGAGCGTAATA-1 ... PBMC_10x_TTTGTCATCTCTGAGA-1
  PBMC_10x_TTTGTCATCTTCGAGA-1
colData names(81): orig.ident nCount_RNA ... differentiation_stage Size_Factor
reducedDimNames(1): UMAP
mainExpName: NULL
altExpNames(0):

Learn Principal Graph

Monocle3 learns a principal graph that represents the trajectory structure. This graph connects cells based on their proximity in the reduced-dimensional space (UMAP in our case).


# The main issue was that you were assigning factors with biological labels as partitions, but Monocle3 requires character vectors, and if use_partition=TRUE, partitions must be simple IDs (e.g., "1"). Once you fixed partitions and ensured UMAP rownames matched CDS colnames, learn_graph() worked.


# Assign clusters
cds_normal@clusters$UMAP$clusters <- as.character(cds_normal$cd4t_stage)
names(cds_normal@clusters$UMAP$clusters) <- colnames(cds_normal)

# Assign partitions (can just set all to "1" if using use_partition = FALSE)
cds_normal@clusters$UMAP$partitions <- rep("1", ncol(cds_normal))
names(cds_normal@clusters$UMAP$partitions) <- colnames(cds_normal)

# Ensure UMAP embedding rownames match colnames of CDS
umap_mat <- reducedDims(cds_normal)$UMAP
umap_mat <- umap_mat[colnames(cds_normal), , drop = FALSE]
reducedDims(cds_normal)$UMAP <- as.matrix(umap_mat)

stopifnot(all(names(cds_normal@clusters$UMAP$partitions) == colnames(cds_normal)))
stopifnot(all(rownames(reducedDims(cds_normal)$UMAP) == colnames(cds_normal)))


# ------------------------------
# Learn the principal graph
# ------------------------------
cds_normal <- learn_graph(cds_normal, use_partition = TRUE)

  |                                                                                                              
  |                                                                                                        |   0%
  |                                                                                                              
  |========================================================================================================| 100%
# Plot the learned graph colored by differentiation stage
p_graph_stages <- plot_cells(cds_normal, color_cells_by = "differentiation_stage", 
           label_groups_by_cluster = FALSE, 
           label_leaves = FALSE, 
           label_branch_points = FALSE, 
           graph_label_size = 4) +
  ggtitle("Monocle3 Graph on Normal CD4+ T Cells (by Differentiation Stage)")
print(p_graph_stages)


# Plot the learned graph colored by dataset to ensure no batch effects
p_graph_dataset <- plot_cells(cds_normal, color_cells_by = "dataset", 
           label_groups_by_cluster = FALSE, 
           label_leaves = FALSE, 
           label_branch_points = FALSE, 
           graph_label_size = 4) +
  ggtitle("Monocle3 Graph on Normal CD4+ T Cells (by Dataset)")
print(p_graph_dataset)

NA
NA

Order Cells in Pseudotime

This is the core step where cells are ordered along the learned trajectory. You need to specify a “root” node (start point) for the trajectory. For normal CD4+ T-cell differentiation, the root should typically be the Naive CD4+ T-cell population (CD4Tn).

# 1️⃣ Get naive CD4Tn cells
naive_cells <- colnames(cds_normal)[cds_normal$differentiation_stage == "CD4Tn"]

if(length(naive_cells) > 0) {
  # 2️⃣ Map cells to their closest principal graph nodes
  closest_vertex <- cds_normal@principal_graph_aux$UMAP$pr_graph_cell_proj_closest_vertex
  closest_vertex <- as.matrix(closest_vertex[colnames(cds_normal), , drop = FALSE])
  
  # 3️⃣ Get the most frequent node among naive cells (preserve original values)
  root_pr_nodes <- names(which.max(table(closest_vertex[naive_cells, 1])))
  
  # 4️⃣ Convert numeric IDs to the proper "Y_" format if needed
  if(!grepl("^Y_", root_pr_nodes)) {
    root_pr_nodes <- paste0("Y_", root_pr_nodes)
  }
  
  # 5️⃣ Check validity
  valid_nodes <- igraph::V(principal_graph(cds_normal)$UMAP)$name
  if(!(root_pr_nodes %in% valid_nodes)) {
    stop(paste("Selected root node", root_pr_nodes, "not found in principal graph."))
  }
  
  # 6️⃣ Order cells
  cds_normal <- order_cells(cds_normal, root_pr_nodes = root_pr_nodes)
  
} else {
  cds_normal <- order_cells(cds_normal)
  warning("No CD4Tn cells found. Using automatic root selection.")
}

Visualize Pseudotime Trajectory

# Plot cells colored by pseudotime
p_pseudotime <- plot_cells(cds_normal, color_cells_by = "pseudotime", 
           label_groups_by_cluster = FALSE, 
           label_leaves = FALSE, 
           label_branch_points = FALSE, 
           graph_label_size = 4) +
  ggtitle("Normal CD4+ T-cell Trajectory (Pseudotime)")
print(p_pseudotime)


# Plot cells colored by differentiation stage with pseudotime trajectory
p_stages_trajectory <- plot_cells(cds_normal, color_cells_by = "differentiation_stage", 
           label_groups_by_cluster = TRUE, 
           label_leaves = TRUE, 
           label_branch_points = TRUE, 
           graph_label_size = 4) +
  ggtitle("Normal CD4+ T-cell Trajectory (Differentiation Stages)")
print(p_stages_trajectory)


# Create a combined plot
combined_trajectory_plots <- p_pseudotime + p_stages_trajectory
print(combined_trajectory_plots)


# Summary statistics
print("Pseudotime summary:")
[1] "Pseudotime summary:"
print(summary(cds_normal@principal_graph_aux@listData$UMAP$pseudotime))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.809  11.181  12.903  21.074  29.368 
print("Pseudotime by differentiation stage:")
[1] "Pseudotime by differentiation stage:"
pseudotime_by_stage <- aggregate(cds_normal@principal_graph_aux@listData$UMAP$pseudotime, 
                                by = list(cds_normal@colData$differentiation_stage), 
                                FUN = function(x) c(mean = mean(x, na.rm = TRUE), 
                                                   median = median(x, na.rm = TRUE),
                                                   sd = sd(x, na.rm = TRUE)))
print(pseudotime_by_stage)

Identify Trajectory-Associated Genes

Find genes that change expression along the pseudotime trajectory. These genes will be important for understanding the biological processes underlying CD4+ T-cell differentiation and for projecting Sézary cells.

print(paste("Number of trajectory-associated genes:", nrow(significant_trajectory_genes)))
[1] "Number of trajectory-associated genes: 11234"
print("Top 10 trajectory-associated genes:")
[1] "Top 10 trajectory-associated genes:"
print(head(significant_trajectory_genes, 10))

# Plot expression of top trajectory genes
if(nrow(significant_trajectory_genes) > 0) {
  top_genes <- rownames(significant_trajectory_genes)[1:min(6, nrow(significant_trajectory_genes))]
  
  p_trajectory_genes <- plot_cells(cds_normal, genes = top_genes, 
                                  show_trajectory_graph = TRUE, 
                                  label_cell_groups = FALSE, 
                                  label_leaves = FALSE)
  print(p_trajectory_genes)
}

# ------------------------------
# Filter for significant genes (FDR < 0.05)
# ------------------------------
significant_trajectory_genes <- trajectory_genes %>% 
  dplyr::filter(q_value < 0.05)

cat("Number of trajectory-associated genes:", nrow(significant_trajectory_genes), "\n")
Number of trajectory-associated genes: 8725 
if(nrow(significant_trajectory_genes) > 0) {
  
  # ------------------------------
  # Select top genes by Moran's I (strongest trajectory association)
  # ------------------------------
  top_genes <- significant_trajectory_genes %>% 
    dplyr::arrange(desc(morans_I)) %>% 
    dplyr::slice_head(n = 6) %>% 
    dplyr::pull(gene_short_name)
  
  cat("Top trajectory-associated genes:\n")
  print(top_genes)
  
  # ------------------------------
  # Plot expression of top trajectory genes along trajectory
  # ------------------------------
  p_trajectory_genes <- plot_cells(
    cds_normal, 
    genes = top_genes,
    show_trajectory_graph = TRUE, 
    label_cell_groups = FALSE, 
    label_leaves = FALSE
  )
  print(p_trajectory_genes)
  
} else {
  warning("No significant trajectory-associated genes found (q_value < 0.05).")
}
Top trajectory-associated genes:
[1] "RPL30"  "RPS15A" "RPL41"  "RPS12"  "RPL32"  "RPS14" 

# -----------------------------
# Filter for significant genes (q < 0.05)
# -----------------------------
significant_trajectory_genes <- trajectory_genes[trajectory_genes$q_value < 0.05, ]

# -----------------------------
# Remove ribosomal and mitochondrial genes
# Ribosomal: start with "RPL" or "RPS"
# Mitochondrial: start with "MT-"
# -----------------------------
significant_trajectory_genes <- significant_trajectory_genes[!grepl("^RPL|^RPS|^MT-", significant_trajectory_genes$gene_short_name), ]

# -----------------------------
# Sort by Moran's I (effect size)
# -----------------------------
significant_trajectory_genes <- significant_trajectory_genes[order(-significant_trajectory_genes$morans_I), ]

# -----------------------------
# Print summary and top genes
# -----------------------------
cat("Number of trajectory-associated genes after filtering:", nrow(significant_trajectory_genes), "\n")
Number of trajectory-associated genes after filtering: 11127 
cat("Top 10 trajectory-associated genes:\n")
Top 10 trajectory-associated genes:
print(head(significant_trajectory_genes$gene_short_name, 10))
 [1] "EEF1A1" "B2M"    "HLA-B"  "TPT1"   "FTH1"   "FAU"    "TXNIP"  "NACA"   "PTMA"   "TMSB4X"
# -----------------------------
# Plot top genes along trajectory
# -----------------------------
top_genes <- head(significant_trajectory_genes$gene_short_name, 6)
if(length(top_genes) > 0) {
  p_trajectory_genes <- plot_cells(cds_normal, genes = top_genes, 
                                   show_trajectory_graph = TRUE, 
                                   label_cell_groups = FALSE, 
                                   label_leaves = FALSE)
  print(p_trajectory_genes)
}

Save Monocle3 CDS Object

# Save the CDS object with trajectory information
saveRDS(cds_normal, "normal_cd4t_monocle3_cds.rds")

# Also save key trajectory information back to the Seurat object
cd4t_integrated$monocle3_pseudotime <- cds_normal@principal_graph_aux@listData$UMAP$pseudotime
cd4t_integrated$monocle3_partition <- cds_normal@clusters$UMAP$partitions

# Save updated Seurat object
saveRDS(cd4t_integrated, "normal_cd4t_with_trajectory.rds")

print("Monocle3 trajectory inference complete. Objects saved.")
[1] "Monocle3 trajectory inference complete. Objects saved."

Function to get the earliest principal node for a given cell type

This function helps select a node within the specified cell type that is closest to the graph’s

Phase 5: Projecting Sézary Cell Lines onto the Normal CD4+ T-cell Trajectory

This is a critical phase where we leverage the established normal CD4+ T-cell trajectory to understand the differentiation state of your Sézary syndrome cell lines. By projecting the malignant cells onto this normal reference, we can identify where they map within the healthy developmental landscape, providing insights into their potential cell of origin and any differentiation arrest or deviation.

Load Sézary Cell Line Seurat Object

Load your pre-processed and integrated Sézary cell line Seurat object. This object should contain RNA expression data, UMAP embeddings, and any relevant metadata (e.g., patient ID, cell line ID, TCR clonotypes).

# Load your integrated Sézary cell line Seurat object
sezary_obj <- readRDS("integrated_sezary_seurat_object.rds")

# Ensure the RNA assay is set as default for projection
DefaultAssay(sezary_obj) <- "RNA"

print(sezary_obj)

Prepare Sézary Data for Projection

To project the Sézary cells onto the normal trajectory, we need to ensure their data is compatible with the Monocle3 CDS object of normal cells. This involves ensuring common genes and using the SCT assay data, as your Sézary object was also processed with SCTransform.

# Ensure the SCT assay is the default for the Sézary object
DefaultAssay(sezary_obj) <- "SCT"

# Extract expression matrix (SCT normalized data)
# We use the 'data' slot of the SCT assay, which contains corrected and normalized values
sezary_expression_matrix <- GetAssayData(sezary_obj, assay = "SCT", slot = "data")

# Ensure common genes between normal CDS and Sézary expression matrix
# We should use the features that were used for SCTransform (3000 features)
# For projection, it's crucial to use the same feature set as the reference trajectory.
common_features <- intersect(rownames(sezary_expression_matrix), fData(cds_normal)$gene_short_name)

sezary_expression_matrix_filtered <- sezary_expression_matrix[common_features, ]

# Create a temporary CDS object for Sézary cells (optional, but good for consistency)
sezary_cell_metadata <- sezary_obj@meta.data
sezary_gene_metadata <- data.frame(gene_short_name = common_features, row.names = common_features)

cds_sezary_temp <- new_cell_data_set(sezary_expression_matrix_filtered,
                                     cell_metadata = sezary_cell_metadata,
                                     gene_metadata = sezary_gene_metadata)

# Add UMAP embedding from Sézary object to temporary CDS
# Ensure the UMAP reduction name matches what's in your Seurat object
if("umap" %in% names(sezary_obj@reductions)) {
  cds_sezary_temp@int_colData@listData$reducedDims$UMAP <- sezary_obj@reductions$umap@cell.embeddings
} else {
  stop("UMAP reduction not found in Sézary Seurat object. Please ensure it's computed.")
}

print(cds_sezary_temp)

Project Sézary Cells onto Normal Trajectory

Monocle3 provides functions to project new cells onto an existing principal graph. This allows us to see where the Sézary cells fall within the normal CD4+ T-cell differentiation landscape.

# Combine the normal and Sézary CDS objects for projection
# This step essentially adds the Sézary cells to the existing graph of normal cells
# and finds their closest projection onto the learned trajectory.

# First, ensure that the column names of the expression matrices are unique
colnames(sezary_expression_matrix_filtered) <- paste0("sezary_", colnames(sezary_expression_matrix_filtered))

# Combine expression matrices
combined_expression_matrix <- cbind(exprs(cds_normal), sezary_expression_matrix_filtered)

# Combine cell metadata
# Ensure metadata columns are consistent or handled appropriately
# For simplicity, we'll create a new combined metadata, preserving key columns
combined_cell_metadata <- rbind(
  colData(cds_normal) %>% as.data.frame() %>% select(any_of(c("dataset", "orig.ident", "differentiation_stage_ordered", "azimuth_cell_type", "seurat_clusters"))),
  sezary_cell_metadata %>% as.data.frame() %>% mutate(dataset = "Sézary", 
                                                     differentiation_stage_ordered = "Sézary", 
                                                     azimuth_cell_type = "Sézary") %>% 
    select(any_of(c("dataset", "orig.ident", "differentiation_stage_ordered", "azimuth_cell_type", "seurat_clusters")))
)

# Ensure row names match column names of expression matrix
rownames(combined_cell_metadata) <- colnames(combined_expression_matrix)

# Combine gene metadata (should be the same)
combined_gene_metadata <- fData(cds_normal)

# Create a new CDS object with combined data
cds_combined <- new_cell_data_set(combined_expression_matrix,
                                  cell_metadata = combined_cell_metadata,
                                  gene_metadata = combined_gene_metadata)

# Transfer UMAP embedding from original CDS objects
# This is a crucial step to ensure cells are placed correctly in the UMAP space
combined_umap <- rbind(reducedDims(cds_normal)$UMAP, reducedDims(cds_sezary_temp)$UMAP)
rownames(combined_umap) <- colnames(combined_expression_matrix)
cds_combined@int_colData@listData$reducedDims$UMAP <- combined_umap

# Transfer graph from normal CDS to combined CDS
cds_combined@principal_graph <- cds_normal@principal_graph
cds_combined@principal_graph_aux <- cds_normal@principal_graph_aux

# Project cells onto the existing graph
# This will calculate pseudotime for the Sézary cells based on the normal trajectory
cds_combined <- order_cells(cds_combined, root_pr_nodes = root_node_id) # Use the same root node as for normal cells

print(cds_combined)

Visualize Projection and Interpret Results

Now we can visualize the combined dataset, with Sézary cells projected onto the normal CD4+ T-cell trajectory. This will allow us to see their relative position and infer their differentiation state.

# Plot the combined trajectory, colored by original dataset (normal vs. Sézary)
plot_cells(cds_combined, color_cells_by = "dataset", 
           label_groups_by_cluster = FALSE, 
           label_leaves = FALSE, 
           label_branch_points = FALSE, 
           graph_label_size = 4) +
  ggtitle("Sézary Cells Projected onto Normal CD4+ T-cell Trajectory")

# Plot the combined trajectory, colored by differentiation stage (for normal cells) and Sézary for malignant
plot_cells(cds_combined, color_cells_by = "differentiation_stage_ordered", 
           label_groups_by_cluster = TRUE, 
           label_leaves = FALSE, 
           label_branch_points = FALSE, 
           graph_label_size = 4) +
  ggtitle("Differentiation Stages and Sézary Cell Projection")

# Plot pseudotime for all cells
plot_cells(cds_combined, color_cells_by = "pseudotime", 
           label_groups_by_cluster = FALSE, 
           label_leaves = FALSE, 
           label_branch_points = FALSE, 
           graph_label_size = 4) +
  ggtitle("Pseudotime of Combined Normal and Sézary Cells")

# Analyze pseudotime distribution for Sézary cells
sezary_pseudotime_df <- colData(cds_combined) %>% 
  as.data.frame() %>% 
  filter(dataset == "Sézary") %>% 
  select(pseudotime, orig.ident)

ggplot(sezary_pseudotime_df, aes(x = pseudotime, fill = orig.ident)) +
  geom_density(alpha = 0.6) +
  labs(title = "Pseudotime Distribution of Sézary Cell Lines", 
       x = "Pseudotime", y = "Density") +
  theme_minimal()

# Analyze gene expression of key markers in Sézary cells along the normal pseudotime
# Define key Sézary markers (e.g., CD7, CD26, TOX, DPEP1) and T-cell differentiation markers
sezary_markers <- c("CD7", "CD26", "DPEP1", "TOX", "GATA3", "CCR7", "SELL", "CD45RA", "CD45RO")

# Filter for genes present in the combined dataset
sezary_markers_present <- sezary_markers[sezary_markers %in% fData(cds_combined)$gene_short_name]

if(length(sezary_markers_present) > 0) {
  plot_genes_in_pseudotime(cds_combined[fData(cds_combined)$gene_short_name %in% sezary_markers_present,],
                           color_cells_by = "dataset") +
    ggtitle("Key Marker Expression along Normal Trajectory (with Sézary Cells)")
}

# Further analysis: Identify which normal cell types Sézary cells are closest to
# This can be done by looking at the density of Sézary cells in different regions of the UMAP
# or by calculating distances to normal cell type centroids.

# Example: Calculate mean pseudotime for each Sézary cell line
mean_pseudotime_by_sezary_line <- sezary_pseudotime_df %>% 
  group_by(orig.ident) %>% 
  summarise(mean_pseudotime = mean(pseudotime, na.rm = TRUE)) %>% 
  arrange(mean_pseudotime)

print("Mean pseudotime for each Sézary cell line:")
print(mean_pseudotime_by_sezary_line)

# Save the combined CDS object for future reference
saveRDS(cds_combined, "path/to/save/combined_normal_sezary_cds_object.rds")

print("Sézary cell projection onto normal trajectory complete.")

Conclusion and Interpretation

This comprehensive RMarkdown script provides a robust framework for understanding the differentiation landscape of normal CD4+ T cells and, crucially, for mapping Sézary syndrome malignant cells onto this normal trajectory. By following these steps, you can gain critical insights into the potential cell of origin for Sézary syndrome and the degree to which malignant cells deviate from normal differentiation pathways.

Key Insights from this Analysis:

  • Normal CD4+ T-cell Differentiation Map: You will have a well-defined pseudotime trajectory for normal CD4+ T cells, annotated with specific differentiation stages (Naive, CM, EM, etc.).
  • Sézary Cell Positioning: The projection of Sézary cells onto this normal map will reveal their transcriptional and phenotypic proximity to specific normal CD4+ T-cell subsets. This can directly inform hypotheses about their cell of origin.
  • Differentiation Arrest/Deviation: By observing where Sézary cells cluster on the normal trajectory, you can identify if they represent a differentiation arrest at a particular stage or if they have undergone a significant deviation from normal development.
  • Gene Expression Signatures: Analysis of gene expression along the pseudotime for both normal and Sézary cells can highlight genes whose expression is dysregulated in Sézary syndrome relative to their normal counterparts at similar differentiation stages.

Next Steps and Further Considerations:

  1. Refine Annotation: Continuously refine your normal CD4+ T-cell annotations based on known markers and literature. The more accurate your normal reference, the more meaningful your projections will be.
  2. Patient-Specific Analysis: While this script integrates all Sézary cell lines, consider performing patient-specific projections to identify any inter-patient variability in the cell of origin or differentiation patterns.
  3. TCR Clonality Integration: Overlay TCR clonotype information onto the combined normal-Sézary trajectory. This can help confirm if cells mapping to a specific normal differentiation stage are indeed part of the expanded malignant clone.
  4. CITE-seq Protein Integration: Utilize your 28 surface protein markers to further validate and refine the differentiation states. Protein expression often provides a more direct phenotypic readout than RNA.
  5. Functional Validation: Computational predictions of cell of origin or differentiation arrest should ideally be followed by experimental validation (e.g., in vitro differentiation assays, functional studies of key genes).
  6. Comparison with Other Trajectory Methods: While Monocle3 is used here, consider applying Slingshot or PAGA (as discussed in the previous document) to the normal CD4+ T-cell dataset to see if they yield consistent trajectories. Robust findings across multiple methods strengthen your conclusions.
  7. Public Data Integration: Explore additional public single-cell RNA-seq datasets of normal T cells (e.g., from different tissues or developmental stages) to broaden your reference map if necessary.

This script provides a powerful foundation for your investigation into the cell of origin of Sézary syndrome. Remember to adapt the paths, thresholds, and specific cell type mappings to your unique dataset and biological questions.


LS0tCnRpdGxlOiAiTm9ybWFsIENENCsgVC1jZWxsIFJlZmVyZW5jZSBUcmFqZWN0b3J5IGFuZCBTw6l6YXJ5IENlbGwgUHJvamVjdGlvbiIKYXV0aG9yOiBOYXNpciBNYWhtb29kIEFiYmFzaQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICAjcm1kZm9ybWF0czo6cmVhZHRoZWRvd24KICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19jb2xsYXBzZWQ6IHRydWUKLS0tCgojIEludHJvZHVjdGlvbgoKVGhpcyBSTWFya2Rvd24gc2NyaXB0IHByb3ZpZGVzIGEgY29tcHJlaGVuc2l2ZSB3b3JrZmxvdyBmb3IgZXN0YWJsaXNoaW5nIGEgbm9ybWFsIENENCsgVC1jZWxsIGRpZmZlcmVudGlhdGlvbiB0cmFqZWN0b3J5IGFuZCBzdWJzZXF1ZW50bHkgcHJvamVjdGluZyBTw6l6YXJ5IHN5bmRyb21lIGNlbGwgbGluZXMgb250byB0aGlzIHJlZmVyZW5jZS4gVGhlIGdvYWwgaXMgdG8gaWRlbnRpZnkgdGhlIHBvdGVudGlhbCBjZWxsIG9mIG9yaWdpbiBmb3IgbWFsaWduYW50IFQgY2VsbHMgaW4gU8OpemFyeSBzeW5kcm9tZSBieSB1bmRlcnN0YW5kaW5nIHRoZWlyIHBvc2l0aW9uIHdpdGhpbiB0aGUgbm9ybWFsIFQtY2VsbCBkZXZlbG9wbWVudGFsIGxhbmRzY2FwZS4gVGhpcyBhcHByb2FjaCBhZGRyZXNzZXMgdGhlIGNyaXRpY2FsIG5lZWQgZm9yIGEgYmlvbG9naWNhbCByZWZlcmVuY2UgdG8gaW50ZXJwcmV0IHRoZSBkaWZmZXJlbnRpYXRpb24gc3RhdGUgb2YgbWFsaWduYW50IGNlbGxzLgoKIyMgT3ZlcmFsbCBXb3JrZmxvdwoKMS4gICoqRGF0YSBMb2FkaW5nIGFuZCBJbml0aWFsIFByb2Nlc3Npbmc6KiogTG9hZCBhbmQgcGVyZm9ybSBiYXNpYyBxdWFsaXR5IGNvbnRyb2wgb24gdHdvIGRpc3RpbmN0IG5vcm1hbCBDRDQrIFQtY2VsbCBkYXRhc2V0czogYENENFRfbGFiYCAoeW91ciBsYWItcHJvY2Vzc2VkIGRhdGEpIGFuZCBgQ0Q0VF8xMHhgIChwdWJsaWNseSBhdmFpbGFibGUgMTB4IEdlbm9taWNzIFBCTUMtZGVyaXZlZCBDRDQrIFQgY2VsbHMpLgoyLiAgKipJbnRlZ3JhdGlvbiB1c2luZyBTZXVyYXQgUlBDQToqKiBJbnRlZ3JhdGUgdGhlc2UgdHdvIGRhdGFzZXRzIHVzaW5nIFNldXJhdCdzIFJlY2lwcm9jYWwgUENBIChSUENBKSBpbnRlZ3JhdGlvbiBtZXRob2QgdG8gZWZmZWN0aXZlbHkgcmVtb3ZlIGJhdGNoIGVmZmVjdHMgd2hpbGUgcHJlc2VydmluZyBiaW9sb2dpY2FsIHZhcmlhdGlvbi4KMy4gICoqQ2VsbCBUeXBlIEFubm90YXRpb246KiogQW5ub3RhdGUgdGhlIGludGVncmF0ZWQgbm9ybWFsIENENCsgVCBjZWxscyB1c2luZyBhIGNvbWJpbmF0aW9uIG9mIEF6aW11dGggKGZvciByb2J1c3QgcmVmZXJlbmNlIG1hcHBpbmcpIGFuZCBTaW5nbGVSIChmb3IgZmluZS1ncmFpbmVkIGFubm90YXRpb24gYWdhaW5zdCBhIGNvbXByZWhlbnNpdmUgcmVmZXJlbmNlIGRhdGFiYXNlKS4gVGhlIGFubm90YXRpb24gd2lsbCBmb2N1cyBvbiBpZGVudGlmeWluZyBhbmQgb3JkZXJpbmcgY2xhc3NpY2FsIENENCsgVC1jZWxsIGRpZmZlcmVudGlhdGlvbiBzdGF0ZXMgKGUuZy4sIE5haXZlLCBDZW50cmFsIE1lbW9yeSwgRWZmZWN0b3IgTWVtb3J5LCBSZWd1bGF0b3J5IFQgY2VsbHMpLgo0LiAgKipNb25vY2xlMyBUcmFqZWN0b3J5IEluZmVyZW5jZToqKiBDb25zdHJ1Y3QgYSBwc2V1ZG90aW1lIHRyYWplY3Rvcnkgb24gdGhlIGludGVncmF0ZWQgYW5kIGFubm90YXRlZCBub3JtYWwgQ0Q0KyBULWNlbGwgZGF0YXNldCB1c2luZyBNb25vY2xlMy4gVGhlIHRyYWplY3Rvcnkgd2lsbCBiZSByb290ZWQgaW4gdGhlIG1vc3QgbmFpdmUgQ0Q0KyBULWNlbGwgcG9wdWxhdGlvbi4KNS4gICoqU8OpemFyeSBDZWxsIFByb2plY3Rpb246KiogUHJvamVjdCB5b3VyIHByZXZpb3VzbHkgYW5hbHl6ZWQgU8OpemFyeSBjZWxsIGxpbmVzIG9udG8gdGhpcyBlc3RhYmxpc2hlZCBub3JtYWwgQ0Q0KyBULWNlbGwgdHJhamVjdG9yeS4gVGhpcyB3aWxsIGFsbG93IGZvciBkaXJlY3QgY29tcGFyaXNvbiBvZiB0aGUgZGlmZmVyZW50aWF0aW9uIHN0YXRlcyBvZiBtYWxpZ25hbnQgY2VsbHMgcmVsYXRpdmUgdG8gbm9ybWFsIFQtY2VsbCBkZXZlbG9wbWVudC4KNi4gICoqQW5hbHlzaXMgYW5kIFZpc3VhbGl6YXRpb246KiogQW5hbHl6ZSBnZW5lIGV4cHJlc3Npb24gY2hhbmdlcyBhbG9uZyB0aGUgbm9ybWFsIHRyYWplY3RvcnkgYW5kIGFzc2VzcyB3aGVyZSB0aGUgU8OpemFyeSBjZWxscyBmYWxsLCBwcm92aWRpbmcgaW5zaWdodHMgaW50byB0aGVpciBkaWZmZXJlbnRpYXRpb24gYXJyZXN0IG9yIGRldmlhdGlvbi4KCiMjIERhdGEgUmVxdWlyZW1lbnRzCgpCZWZvcmUgcnVubmluZyB0aGlzIHNjcmlwdCwgZW5zdXJlIHlvdSBoYXZlIHRoZSBmb2xsb3dpbmcgZGF0YSBwcmVwYXJlZDoKCiogICAqKmBDRDRUX2xhYmAgU2V1cmF0IE9iamVjdDoqKiBBIFNldXJhdCBvYmplY3QgY29udGFpbmluZyB5b3VyIGxhYi1wcm9jZXNzZWQgbm9ybWFsIENENCsgVC1jZWxsIGRhdGEuIFRoaXMgc2hvdWxkIGhhdmUgdW5kZXJnb25lIGluaXRpYWwgUUMgYW5kIGJhc2ljIHByb2Nlc3NpbmcgKGUuZy4sIG5vcm1hbGl6YXRpb24sIHNjYWxpbmcsIHZhcmlhYmxlIGZlYXR1cmUgaWRlbnRpZmljYXRpb24pLgoqICAgKipgQ0Q0VF8xMHhgIFNldXJhdCBPYmplY3Q6KiogQSBTZXVyYXQgb2JqZWN0IGNvbnRhaW5pbmcgQ0Q0KyBUIGNlbGxzIGV4dHJhY3RlZCBmcm9tIGEgcHVibGljbHkgYXZhaWxhYmxlIDEweCBHZW5vbWljcyBQQk1DIGRhdGFzZXQuIFRoaXMgc2hvdWxkIGFsc28gYmUgcHJlLXByb2Nlc3NlZCBzaW1pbGFybHkgdG8geW91ciBgQ0Q0VF9sYWJgIGRhdGEuCiogICAqKmBzZXphcnlfY2VsbF9saW5lc2AgU2V1cmF0IE9iamVjdDoqKiBZb3VyIGludGVncmF0ZWQgU2V1cmF0IG9iamVjdCBjb250YWluaW5nIHRoZSBTw6l6YXJ5IHN5bmRyb21lIGNlbGwgbGluZXMgKFJOQSwgQ0lURS1zZXEsIFRDUiBkYXRhKSwgd2hpY2ggeW91IGhhdmUgYWxyZWFkeSBwcm9jZXNzZWQgYW5kIGFuYWx5emVkLiBUaGlzIG9iamVjdCBzaG91bGQgaGF2ZSBhIFVNQVAgcmVkdWN0aW9uIGFuZCBjZWxsIHR5cGUgYW5ub3RhdGlvbnMuCgoqKk5vdGUgb24gRGF0YSBQcmVwYXJhdGlvbjoqKiBJdCBpcyBjcnVjaWFsIHRoYXQgYm90aCBub3JtYWwgQ0Q0KyBULWNlbGwgZGF0YXNldHMgYW5kIHlvdXIgU8OpemFyeSBjZWxsIGxpbmUgZGF0YXNldCBzaGFyZSBjb21tb24gZ2VuZSBzZXRzIGFuZCBpZGVhbGx5IHNpbWlsYXIgcHJvY2Vzc2luZyBzdGVwcyB1cCB0byB0aGUgcG9pbnQgb2YgaW50ZWdyYXRpb24gdG8gZW5zdXJlIGNvbXBhdGliaWxpdHkuCgoKCgojIyBQaGFzZSAxOiBEYXRhIExvYWRpbmcgYW5kIFN1YnNldHRpbmcgTm9ybWFsIENvbnRyb2xzIChTQ1RyYW5zZm9ybSBDb21wYXRpYmxlKQoKVGhpcyBwaGFzZSBmb2N1c2VzIG9uIGxvYWRpbmcgeW91ciBtYWluIFNldXJhdCBvYmplY3QgKGBBbGxfc2FtcGxlX01lcmdlZGApIHdoaWNoIGhhcyBhbHJlYWR5IGJlZW4gcHJvY2Vzc2VkIHdpdGggYFNDVHJhbnNmb3JtYCBhbmQgMzAwMCBmZWF0dXJlcy4gV2Ugd2lsbCB0aGVuIHN1YnNldCB0aGUgbm9ybWFsIENENCsgVC1jZWxsIGNvbnRyb2xzIChgQ0Q0VF9sYWJgIGFuZCBgQ0Q0VF8xMHhgKSBiYXNlZCBvbiB0aGVpciBgb3JpZy5pZGVudGAgdmFsdWVzLiBUaGlzIGVuc3VyZXMgdGhhdCBhbGwgc3Vic2VxdWVudCBhbmFseXNlcyBvbiB0aGVzZSBub3JtYWwgY29udHJvbHMgbGV2ZXJhZ2UgdGhlIGNvbnNpc3RlbnQgYFNDVGAgYXNzYXkgYW5kIGZlYXR1cmUgc2V0LgoKIyMjIExvYWQgTGlicmFyaWVzCgpgYGB7ciBsb2FkX2xpYnJhcmllcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBhdGNod29yaykKCiMgU2V0IGEgY29uc2lzdGVudCBnZ3Bsb3QyIHRoZW1lCnRoZW1lX3NldCh0aGVtZV9idygpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSkKYGBgCgojIyMgTG9hZCBNYWluIFNldXJhdCBPYmplY3QgKGBBbGxfc2FtcGxlX01lcmdlZGApIGFuZCBJbnNwZWN0IFNhbXBsZSBDb21wb3NpdGlvbgoKUmVwbGFjZSBgcGF0aC90by95b3VyL0FsbF9zYW1wbGVfTWVyZ2VkLnJkc2Agd2l0aCB0aGUgYWN0dWFsIHBhdGggdG8geW91ciBtYWluIFNldXJhdCBvYmplY3QuIFRoaXMgb2JqZWN0IHNob3VsZCBhbHJlYWR5IGNvbnRhaW4gdGhlIGBTQ1RgIGFzc2F5IGFzIGl0cyBkZWZhdWx0LCB3aXRoIDMwMDAgdmFyaWFibGUgZmVhdHVyZXMuCgpgYGB7ciBsb2FkX21haW5fb2JqZWN0fQojIExvYWQgeW91ciBtYWluIFNldXJhdCBvYmplY3QgY29udGFpbmluZyBhbGwgc2FtcGxlcywgYWxyZWFkeSBTQ1RyYW5zZm9ybWVkCm1haW5fc2V1cmF0IDwtIHJlYWRSRFMoIi4uLzAtU2V1cmF0X1JEU19PQkpFQ1RfRklOQUwvU2V1cmF0X29iamVjdF9GaW5hbF9jaGFuZ2VzL0FsbF9zYW1wbGVzX01lcmdlZF93aXRoX1NUQ0FUX0Fubm90YXRpb25fZmluYWwtNS0wOS0yMDI1LnJkcyIpCgojIEVuc3VyZSB0aGUgU0NUIGFzc2F5IGlzIHRoZSBkZWZhdWx0CkRlZmF1bHRBc3NheShtYWluX3NldXJhdCkgPC0gIlNDVCIKCiMgSW5zcGVjdCB0aGUgb3JpZy5pZGVudCB0byBzZWUgYWxsIHNhbXBsZSBpZGVudGlmaWVycwpwcmludCgiU2FtcGxlIGNvbXBvc2l0aW9uIGluIG9yaWcuaWRlbnQ6IikKcHJpbnQodGFibGUobWFpbl9zZXVyYXQkb3JpZy5pZGVudCkpCgojIFZpc3VhbGl6ZSBzYW1wbGUgZGlzdHJpYnV0aW9uICh1c2luZyB0aGUgVU1BUCBmcm9tIHRoZSBtYWluIG9iamVjdCkKc2FtcGxlX3Bsb3QgPC0gRGltUGxvdChtYWluX3NldXJhdCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IiwgbGFiZWwgPSBUUlVFKSArCiAgZ2d0aXRsZSgiQWxsIFNhbXBsZXMgaW4gTWFpbiBTZXVyYXQgT2JqZWN0IChTQ1RyYW5zZm9ybWVkKSIpCnByaW50KHNhbXBsZV9wbG90KQoKcHJpbnQobWFpbl9zZXVyYXQpCmBgYAoKIyMjIFN1YnNldCBOb3JtYWwgQ0Q0KyBULWNlbGwgQ29udHJvbHMKCk5vdyB3ZSB3aWxsIGV4dHJhY3Qgb25seSB0aGUgbm9ybWFsIGNvbnRyb2wgc2FtcGxlcyAoYENENFRfbGFiYCBhbmQgYENENFRfMTB4YCkgZnJvbSB0aGUgbWFpbiBvYmplY3QgdG8gY3JlYXRlIG91ciByZWZlcmVuY2UgdHJhamVjdG9yeS4gVGhlc2Ugc3Vic2V0dGVkIG9iamVjdHMgd2lsbCBhdXRvbWF0aWNhbGx5IGluaGVyaXQgdGhlIGBTQ1RgIGFzc2F5LgoKYGBge3Igc3Vic2V0X25vcm1hbF9jb250cm9sc30KIyBTdWJzZXQgbm9ybWFsIENENCsgVC1jZWxsIGNvbnRyb2xzIGJhc2VkIG9uIG9yaWcuaWRlbnQKIyBBZGp1c3QgdGhlIGlkZW50aWZpZXJzIGlmIHRoZXkgYXJlIG5hbWVkIGRpZmZlcmVudGx5IGluIHlvdXIgZGF0YQpub3JtYWxfY29udHJvbHMgPC0gc3Vic2V0KG1haW5fc2V1cmF0LCBzdWJzZXQgPSBvcmlnLmlkZW50ICVpbiUgYygiQ0Q0VF9sYWIiLCAiQ0Q0VF8xMHgiKSkKCiMgVmVyaWZ5IHRoZSBzdWJzZXR0aW5nIHdvcmtlZCBjb3JyZWN0bHkKcHJpbnQoIk5vcm1hbCBjb250cm9scyBhZnRlciBzdWJzZXR0aW5nOiIpCnByaW50KHRhYmxlKG5vcm1hbF9jb250cm9scyRvcmlnLmlkZW50KSkKCiMgQWRkIGEgXCdkYXRhc2V0XCcgbWV0YWRhdGEgY29sdW1uIGZvciBjbGFyaXR5Cm5vcm1hbF9jb250cm9scyRkYXRhc2V0IDwtIG5vcm1hbF9jb250cm9scyRvcmlnLmlkZW50CgojIEVuc3VyZSBTQ1QgYXNzYXkgaXMgZGVmYXVsdCBmb3IgdGhlIHN1YnNldHRlZCBvYmplY3QKRGVmYXVsdEFzc2F5KG5vcm1hbF9jb250cm9scykgPC0gIlNDVCIKCiMgQmFzaWMgUUMgdmlzdWFsaXphdGlvbiBmb3IgdGhlIG5vcm1hbCBjb250cm9scwojIE5vdGU6IElmIHBlcmNlbnQubXQsIG5Db3VudF9STkEsIG5GZWF0dXJlX1JOQSB3ZXJlIHJlZ3Jlc3NlZCBvdXQgZHVyaW5nIFNDVHJhbnNmb3JtLAojIHRoZXNlIHBsb3RzIG1pZ2h0IHNob3cgbGVzcyB2YXJpYXRpb24uIEhvd2V2ZXIsIHRoZXkgYXJlIHN0aWxsIHVzZWZ1bCBmb3IgY2hlY2tpbmcuCmlmKCEicGVyY2VudC5tdCIgJWluJSBjb2xuYW1lcyhub3JtYWxfY29udHJvbHNAbWV0YS5kYXRhKSkgewogIG5vcm1hbF9jb250cm9sc1tbInBlcmNlbnQubXQiXV0gPC0gUGVyY2VudGFnZUZlYXR1cmVTZXQobm9ybWFsX2NvbnRyb2xzLCBwYXR0ZXJuID0gIl5NVC0iKQp9Cgp2bG5fcGxvdF9ub3JtYWwgPC0gVmxuUGxvdChub3JtYWxfY29udHJvbHMsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgIm5Db3VudF9STkEiLCAicGVyY2VudC5tdCIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJkYXRhc2V0IiwgbmNvbCA9IDMsIHB0LnNpemUgPSAwLjEpIApwcmludCh2bG5fcGxvdF9ub3JtYWwpCgojIE9wdGlvbmFsOiBBcHBseSBhZGRpdGlvbmFsIFFDIGZpbHRlcmluZyBpZiBuZWVkZWQgKHRob3VnaCBhbHJlYWR5IGRvbmUgb24gbWFpbiBvYmplY3QpCiBub3JtYWxfY29udHJvbHMgPC0gc3Vic2V0KG5vcm1hbF9jb250cm9scywgc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gMjAwICYgbkZlYXR1cmVfUk5BIDwgNDAwMCAmIHBlcmNlbnQubXQgPCA2KQoKcHJpbnQocGFzdGUoIlRvdGFsIG5vcm1hbCBjb250cm9sIGNlbGxzOiIsIG5jb2wobm9ybWFsX2NvbnRyb2xzKSkpCnByaW50KHBhc3RlKCJDRDRUX2xhYiBjZWxsczoiLCBzdW0obm9ybWFsX2NvbnRyb2xzJG9yaWcuaWRlbnQgPT0gIkNENFRfbGFiIikpKQpwcmludChwYXN0ZSgiQ0Q0VF8xMHggY2VsbHM6Iiwgc3VtKG5vcm1hbF9jb250cm9scyRvcmlnLmlkZW50ID09ICJDRDRUXzEweCIpKSkKcHJpbnQobm9ybWFsX2NvbnRyb2xzKQoKCnZsbl9wbG90X25vcm1hbCA8LSBWbG5QbG90KG5vcm1hbF9jb250cm9scywgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiLCAibkNvdW50X1JOQSIsICJwZXJjZW50Lm10IiksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gImRhdGFzZXQiLCBuY29sID0gMywgcHQuc2l6ZSA9IDAuMSkgCnByaW50KHZsbl9wbG90X25vcm1hbCkKYGBgCgojIyMgUHJlcGFyZSBmb3IgSW50ZWdyYXRpb24KClNpbmNlIHRoZXNlIHNhbXBsZXMgd2VyZSBwcm9jZXNzZWQgdG9nZXRoZXIgaW4geW91ciBtYWluIG9iamVjdCwgdGhleSBzaG91bGQgYWxyZWFkeSBzaGFyZSB0aGUgc2FtZSBnZW5lIHNldCBhbmQgYmFzaWMgcHJlcHJvY2Vzc2luZy4gV2Ugd2lsbCBub3cgc3BsaXQgdGhlbSBhbmQgcHJlcGFyZSBmb3IgUlBDQSBpbnRlZ3JhdGlvbiB0byByZW1vdmUgYW55IHJlbWFpbmluZyBiYXRjaCBlZmZlY3RzIGJldHdlZW4gdGhlIHR3byBub3JtYWwgY29udHJvbCBkYXRhc2V0cyBpbiB0aGUgYFNDVGAgYXNzYXkuCgpgYGB7ciBwcmVwYXJlX2Zvcl9pbnRlZ3JhdGlvbn0KIyBTcGxpdCB0aGUgbm9ybWFsIGNvbnRyb2xzIG9iamVjdCBieSBkYXRhc2V0IGZvciBpbnRlZ3JhdGlvbgpub3JtYWxfbGlzdCA8LSBTcGxpdE9iamVjdChub3JtYWxfY29udHJvbHMsIHNwbGl0LmJ5ID0gIm9yaWcuaWRlbnQiKQoKIyBWZXJpZnkgdGhlIHNwbGl0CnByaW50KCJTcGxpdCBub3JtYWwgY29udHJvbHM6IikKZm9yKGkgaW4gbmFtZXMobm9ybWFsX2xpc3QpKSB7CiAgcHJpbnQocGFzdGUoaSwgIjoiLCBuY29sKG5vcm1hbF9saXN0W1tpXV0pLCAiY2VsbHMiKSkKfQoKIyBTQ1RyYW5zZm9ybSBoYXMgYWxyZWFkeSBiZWVuIGFwcGxpZWQgdG8gdGhlIG1haW4gb2JqZWN0LCBzbyB3ZSBkb24ndCBuZWVkIHRvIHJ1biBpdCBhZ2FpbiBoZXJlLgojIEhvd2V2ZXIsIGZvciBSUENBLCB3ZSBuZWVkIHRvIGVuc3VyZSB0aGUgYFNDVGAgYXNzYXkgaXMgdGhlIGRlZmF1bHQgZm9yIGVhY2ggb2JqZWN0IGluIHRoZSBsaXN0Lgpmb3IgKGkgaW4gMTpsZW5ndGgobm9ybWFsX2xpc3QpKSB7CiAgRGVmYXVsdEFzc2F5KG5vcm1hbF9saXN0W1tpXV0pIDwtICJTQ1QiCn0KCiMgTWVyZ2Ugb2JqZWN0cwp0ZW1wX21lcmdlZCA8LSBtZXJnZShub3JtYWxfbGlzdFtbIkNENFRfbGFiIl1dLCB5ID0gbm9ybWFsX2xpc3RbWyJDRDRUXzEweCJdXSwKICAgICAgICAgICAgICAgICAgICAgYWRkLmNlbGwuaWRzID0gYygiTGFiIiwgIjEweCIpLCBwcm9qZWN0ID0gIk5vcm1hbENENFRfUHJlSW50ZWdyYXRpb24iKQoKRGVmYXVsdEFzc2F5KHRlbXBfbWVyZ2VkKSA8LSAiU0NUIgoKIyBVc2UgU0NUcmFuc2Zvcm0gdmFyaWFibGUgZmVhdHVyZXMgZnJvbSBlYWNoIG9iamVjdCBhbmQgY29tYmluZSB0aGVtCiMgU2V1cmF0IHJlY29tbWVuZHMgdGFraW5nIHRoZSB0b3AgdmFyaWFibGUgZmVhdHVyZXMgZnJvbSBlYWNoIG9iamVjdCAodW5pb24gb3IgaW50ZXJzZWN0aW9uKQp2YXJfZmVhdHVyZXNfbGFiIDwtIFZhcmlhYmxlRmVhdHVyZXMobm9ybWFsX2xpc3RbWyJDRDRUX2xhYiJdXSkKdmFyX2ZlYXR1cmVzXzEweCA8LSBWYXJpYWJsZUZlYXR1cmVzKG5vcm1hbF9saXN0W1siQ0Q0VF8xMHgiXV0pCgojIENvbWJpbmUgYW5kIHJlbW92ZSB1bndhbnRlZCBnZW5lcwpjb21iaW5lZF92YXJfZmVhdHVyZXMgPC0gc2V0ZGlmZih1bmlvbih2YXJfZmVhdHVyZXNfbGFiLCB2YXJfZmVhdHVyZXNfMTB4KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXAoIl5ITEEtfF5UUltBQkdEXXxeSUdbSEtMXXxeWElTVCQiLCByb3duYW1lcyh0ZW1wX21lcmdlZCksIHZhbHVlID0gVFJVRSkpCgojIEFzc2lnbiB0byBtZXJnZWQgb2JqZWN0ClZhcmlhYmxlRmVhdHVyZXModGVtcF9tZXJnZWQpIDwtIGNvbWJpbmVkX3Zhcl9mZWF0dXJlcwoKIyBOb3cgUENBIHdpbGwgd29yawp0ZW1wX21lcmdlZCA8LSBSdW5QQ0EodGVtcF9tZXJnZWQsIHZlcmJvc2UgPSBGQUxTRSkKCgojIFZpc3VhbGl6ZSB0aGUgZWxib3cgcGxvdApFbGJvd1Bsb3QodGVtcF9tZXJnZWQsIG5kaW1zID0gNTApICsgZ2d0aXRsZSgiUENBIEVsYm93IFBsb3QgLSBOb3JtYWwgQ29udHJvbHMiKQoKdGVtcF9tZXJnZWQgPC0gUnVuVU1BUCh0ZW1wX21lcmdlZCwgZGltcyA9IDE6MTUsIHZlcmJvc2UgPSBGQUxTRSkKCiMgUGxvdCBVTUFQIGNvbG9yZWQgYnkgZGF0YXNldCB0byBzaG93IHBvdGVudGlhbCBiYXRjaCBlZmZlY3QKcHJlX2ludGVncmF0aW9uX3Bsb3QgPC0gRGltUGxvdCh0ZW1wX21lcmdlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJkYXRhc2V0IikgKwogIGdndGl0bGUoIk5vcm1hbCBDb250cm9scyBiZWZvcmUgUlBDQSBJbnRlZ3JhdGlvbiAoU0NUIEFzc2F5KSIpCnByaW50KHByZV9pbnRlZ3JhdGlvbl9wbG90KQoKRGltUGxvdCh0ZW1wX21lcmdlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLmJveCA9IFQsIHJlcGVsID0gVCkKRGltUGxvdCh0ZW1wX21lcmdlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQpCgoKIyBDbGVhbiB1cCB0ZW1wb3Jhcnkgb2JqZWN0CnJtKHRlbXBfbWVyZ2VkKQpnYygpCgpwcmludCgiTm9ybWFsIGNvbnRyb2xzIHByZXBhcmVkIGZvciBSUENBIGludGVncmF0aW9uIHVzaW5nIFNDVCBhc3NheS4iKQpgYGAKCgoKCiMjIFBoYXNlIDI6IEludGVncmF0aW9uIHVzaW5nIFNldXJhdCBSUENBIChTQ1RyYW5zZm9ybSBDb21wYXRpYmxlKQoKVGhpcyBwaGFzZSBkZXRhaWxzIHRoZSBpbnRlZ3JhdGlvbiBvZiB0aGUgYENENFRfbGFiYCBhbmQgYENENFRfMTB4YCBkYXRhc2V0cyB1c2luZyBTZXVyYXQncyBSZWNpcHJvY2FsIFBDQSAoUlBDQSkgaW50ZWdyYXRpb24gbWV0aG9kLiBTaW5jZSB5b3VyIGRhdGEgaGFzIGJlZW4gcHJvY2Vzc2VkIHdpdGggYFNDVHJhbnNmb3JtYCwgd2Ugd2lsbCBlbnN1cmUgdGhhdCB0aGUgaW50ZWdyYXRpb24gc3RlcHMgYXJlIGNvbXBhdGlibGUgd2l0aCB0aGUgYFNDVGAgYXNzYXkuIFJQQ0EgaXMgcGFydGljdWxhcmx5IGVmZmVjdGl2ZSBmb3IgaW50ZWdyYXRpbmcgZGF0YXNldHMgd2l0aCBzaWduaWZpY2FudCBiaW9sb2dpY2FsIGRpZmZlcmVuY2VzIG9yIGxhcmdlIGJhdGNoIGVmZmVjdHMsIGFzIGl0IGlkZW50aWZpZXMgc2hhcmVkIGJpb2xvZ2ljYWwgc2lnbmFscyB3aGlsZSBtaW5pbWl6aW5nIHRlY2huaWNhbCB2YXJpYXRpb24uIFRoaXMgaXMgY3J1Y2lhbCBmb3IgY3JlYXRpbmcgYSB1bmlmaWVkIHJlZmVyZW5jZSBtYXAgZm9yIG5vcm1hbCBDRDQrIFQtY2VsbCBkaWZmZXJlbnRpYXRpb24uCgojIyMgV2h5IFJQQ0Egd2l0aCBTQ1RyYW5zZm9ybT8KCldoZW4gd29ya2luZyB3aXRoIGBTQ1RyYW5zZm9ybWAgZGF0YSwgaXQncyBpbXBvcnRhbnQgdG8gdXNlIGludGVncmF0aW9uIG1ldGhvZHMgdGhhdCBhcmUgZGVzaWduZWQgdG8gd29yayB3aXRoIHRoZSBjb3JyZWN0ZWQgY291bnRzIG9yIG5vcm1hbGl6ZWQgdmFsdWVzIHByb2R1Y2VkIGJ5IGBTQ1RyYW5zZm9ybWAuIFJQQ0EsIHdoZW4gY29tYmluZWQgd2l0aCBgUHJlcFNDVEludGVncmF0aW9uYCBhbmQgc3BlY2lmeWluZyBgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUImAsIGVuc3VyZXMgdGhhdCB0aGUgaW50ZWdyYXRpb24gbGV2ZXJhZ2VzIHRoZSBiZW5lZml0cyBvZiBgU0NUcmFuc2Zvcm1gJ3MgaW1wcm92ZWQgbm9ybWFsaXphdGlvbiBhbmQgdmFyaWFuY2Ugc3RhYmlsaXphdGlvbi4gVGhpcyBsZWFkcyB0byBtb3JlIGFjY3VyYXRlIGFuY2hvciBmaW5kaW5nIGFuZCBiZXR0ZXIgYmF0Y2ggZWZmZWN0IGNvcnJlY3Rpb24uCgojIyMgUGVyZm9ybSBSUENBIEludGVncmF0aW9uCgpgYGB7ciBycGNhX2ludGVncmF0aW9ufQojIEluY3JlYXNlIGZ1dHVyZSBnbG9iYWwgc2l6ZSB0byA1IEdCIChhZGp1c3QgYXMgbmVlZGVkKQpvcHRpb25zKGZ1dHVyZS5nbG9iYWxzLm1heFNpemUgPSA1ICogMTAyNF4zKSAgIyA1IEdCCgojIExpc3Qgb2YgU2V1cmF0IG9iamVjdHMgdG8gaW50ZWdyYXRlIChub3JtYWxfbGlzdCBjcmVhdGVkIGluIFBoYXNlIDEpCgojIEZvciBTQ1RyYW5zZm9ybSBkYXRhLCB3ZSBuZWVkIHRvIHJ1biBgUHJlcFNDVEludGVncmF0aW9uYCBiZWZvcmUgZmluZGluZyBhbmNob3JzLgojIFRoaXMgZnVuY3Rpb24gZW5zdXJlcyB0aGF0IHRoZSBTQ1QgYXNzYXkgaXMgcHJvcGVybHkgcHJlcGFyZWQgZm9yIGludGVncmF0aW9uLgpub3JtYWxfbGlzdCA8LSBQcmVwU0NUSW50ZWdyYXRpb24ob2JqZWN0Lmxpc3QgPSBub3JtYWxfbGlzdCwgYW5jaG9yLmZlYXR1cmVzID0gMzAwMCwgdmVyYm9zZSA9IEZBTFNFKQoKIyBTZWxlY3QgaW50ZWdyYXRpb24gZmVhdHVyZXMKIyBXaGVuIHVzaW5nIFByZXBTQ1RJbnRlZ3JhdGlvbiwgZmVhdHVyZXMgYXJlIGFscmVhZHkgc2VsZWN0ZWQsIGJ1dCB3ZSBjYW4gcmUtY29uZmlybS4KZmVhdHVyZXMgPC0gU2VsZWN0SW50ZWdyYXRpb25GZWF0dXJlcyhvYmplY3QubGlzdCA9IG5vcm1hbF9saXN0LCBuZmVhdHVyZXMgPSAzMDAwKQoKIyBSZW1vdmUgdW53YW50ZWQgZ2VuZXMgZnJvbSBpbnRlZ3JhdGlvbiBmZWF0dXJlcwp1bndhbnRlZF9nZW5lcyA8LSBncmVwKCJeSExBLXxeVFJbQUJHRF18XklHW0hLTF18XlhJU1QkIiwgZmVhdHVyZXMsIHZhbHVlID0gVFJVRSkKZmVhdHVyZXMgPC0gc2V0ZGlmZihmZWF0dXJlcywgdW53YW50ZWRfZ2VuZXMpCgojIEZpbmQgaW50ZWdyYXRpb24gYW5jaG9ycyB1c2luZyBSUENBCiMgV2Ugc3BlY2lmeSBgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUImAgdG8gZW5zdXJlIGFuY2hvcnMgYXJlIGZvdW5kIG9uIFNDVC1ub3JtYWxpemVkIGRhdGEuCmNkNHRfYW5jaG9ycyA8LSBGaW5kSW50ZWdyYXRpb25BbmNob3JzKG9iamVjdC5saXN0ID0gbm9ybWFsX2xpc3QsIGFuY2hvci5mZWF0dXJlcyA9IGZlYXR1cmVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIiwgcmVkdWN0aW9uID0gInJwY2EiLCB2ZXJib3NlID0gRkFMU0UpCgojIEludGVncmF0ZSB0aGUgZGF0YXNldHMKIyBUaGlzIHN0ZXAgdXNlcyB0aGUgaWRlbnRpZmllZCBhbmNob3JzIHRvIGNvcnJlY3QgZm9yIGJhdGNoIGVmZmVjdHMgYW5kIGNyZWF0ZSBhIGNvbWJpbmVkIGV4cHJlc3Npb24gbWF0cml4CmNkNHRfaW50ZWdyYXRlZCA8LSBJbnRlZ3JhdGVEYXRhKGFuY2hvcnNldCA9IGNkNHRfYW5jaG9ycywgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiU0NUIiwgdmVyYm9zZSA9IEZBTFNFKQoKcHJpbnQoY2Q0dF9pbnRlZ3JhdGVkKQpgYGAKCiMjIyBTY2FsZSBhbmQgUGVyZm9ybSBEaW1lbnNpb25hbGl0eSBSZWR1Y3Rpb24gb24gSW50ZWdyYXRlZCBEYXRhCgpBZnRlciBpbnRlZ3JhdGlvbiwgd2UgbmVlZCB0byBzY2FsZSB0aGUgaW50ZWdyYXRlZCBkYXRhLCBwZXJmb3JtIFBDQSwgYW5kIHRoZW4gZ2VuZXJhdGUgYSBVTUFQIGVtYmVkZGluZyB0byB2aXN1YWxpemUgdGhlIGludGVncmF0ZWQgY2VsbCBwb3B1bGF0aW9ucy4gVGhlIGBpbnRlZ3JhdGVkYCBhc3NheSBub3cgY29udGFpbnMgdGhlIGJhdGNoLWNvcnJlY3RlZCBleHByZXNzaW9uIHZhbHVlcywgZGVyaXZlZCBmcm9tIHRoZSBTQ1Qtbm9ybWFsaXplZCBkYXRhLgoKYGBge3IgaW50ZWdyYXRlZF9kaW1fcmVkdWN0aW9ufQojIFNldCBkZWZhdWx0IGFzc2F5IHRvICdpbnRlZ3JhdGVkJyBmb3IgZG93bnN0cmVhbSBhbmFseXNpcwpEZWZhdWx0QXNzYXkoY2Q0dF9pbnRlZ3JhdGVkKSA8LSAiaW50ZWdyYXRlZCIKCgojIFJlbW92ZSB1bndhbnRlZCBnZW5lcyBmcm9tIHZhcmlhYmxlIGZlYXR1cmVzCnVud2FudGVkX2dlbmVzIDwtIGdyZXAoIl5ITEEtfF5UUltBQkdEXXxeSUdbSEtMXXxeWElTVCR8Xk1BTEFUMSQiLCAKICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lcyhjZDR0X2ludGVncmF0ZWQpLCB2YWx1ZSA9IFRSVUUpClZhcmlhYmxlRmVhdHVyZXMoY2Q0dF9pbnRlZ3JhdGVkKSA8LSBzZXRkaWZmKFZhcmlhYmxlRmVhdHVyZXMoY2Q0dF9pbnRlZ3JhdGVkKSwgdW53YW50ZWRfZ2VuZXMpCiMgQ29uZmlybSByZW1vdmFsClZhcmlhYmxlRmVhdHVyZXMoY2Q0dF9pbnRlZ3JhdGVkKVsxOjEwXSAgIyBqdXN0IHRvIGluc3BlY3QgdGhlIGZpcnN0IGZldwoKCiMgUnVuIFBDQSBvbiB0aGUgaW50ZWdyYXRlZCBkYXRhCiMgV2hlbiB1c2luZyBTQ1RyYW5zZm9ybSwgc2NhbGluZyBpcyB0eXBpY2FsbHkgaGFuZGxlZCBieSB0aGUgU0NUcmFuc2Zvcm0gZnVuY3Rpb24gaXRzZWxmLgojIFRoZSBgaW50ZWdyYXRlZGAgYXNzYXkgaXMgYWxyZWFkeSBzY2FsZWQgZm9yIFBDQSBieSB0aGUgaW50ZWdyYXRpb24gcHJvY2Vzcy4KY2Q0dF9pbnRlZ3JhdGVkIDwtIFJ1blBDQShjZDR0X2ludGVncmF0ZWQsIG5wY3MgPSA1MCwgdmVyYm9zZSA9IEZBTFNFKQoKIyBWaXN1YWxpemUgZWxib3cgcGxvdApFbGJvd1Bsb3QoY2Q0dF9pbnRlZ3JhdGVkLCBuZGltcyA9IDUwKSArIGdndGl0bGUoIkVsYm93IFBsb3QgLSBJbnRlZ3JhdGVkIE5vcm1hbCBDRDRUIikKCiMgUnVuIFVNQVAgb24gdGhlIGludGVncmF0ZWQgZGF0YQpjZDR0X2ludGVncmF0ZWQgPC0gUnVuVU1BUChjZDR0X2ludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCwgdmVyYm9zZSA9IEZBTFNFKQoKIyBGaW5kIGNsdXN0ZXJzIG9uIHRoZSBpbnRlZ3JhdGVkIGRhdGEKY2Q0dF9pbnRlZ3JhdGVkIDwtIEZpbmROZWlnaGJvcnMoY2Q0dF9pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjAsIHZlcmJvc2UgPSBGQUxTRSkKY2Q0dF9pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyhjZDR0X2ludGVncmF0ZWQsIHJlc29sdXRpb24gPSBjKDAuMiwgMC4zLDAuNCwgMC41KSwgdmVyYm9zZSA9IEZBTFNFKQoKcHJpbnQoY2Q0dF9pbnRlZ3JhdGVkKQpgYGAKCiMjIyBWaXN1YWxpemUgSW50ZWdyYXRlZCBEYXRhCgpOb3csIHdlIGNhbiB2aXN1YWxpemUgdGhlIGludGVncmF0ZWQgZGF0YSB0byBjb25maXJtIHRoYXQgYmF0Y2ggZWZmZWN0cyBoYXZlIGJlZW4gc3VjY2Vzc2Z1bGx5IHJlbW92ZWQgYW5kIHRoYXQgY2VsbHMgZnJvbSBkaWZmZXJlbnQgZGF0YXNldHMgYXJlIHdlbGwtbWl4ZWQgd2l0aGluIHRoZWlyIHJlc3BlY3RpdmUgYmlvbG9naWNhbCBwb3B1bGF0aW9ucy4KCmBgYHtyIHBvc3RfaW50ZWdyYXRpb25fdW1hcH0KIyBQbG90IFVNQVAgY29sb3JlZCBieSBkYXRhc2V0IHRvIHNob3cgc3VjY2Vzc2Z1bCBpbnRlZ3JhdGlvbgppbnRlZ3JhdGVkX3Bsb3RfZGF0YXNldCA8LSBEaW1QbG90KGNkNHRfaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJkYXRhc2V0IikgKwogIGdndGl0bGUoIlVNQVAgYWZ0ZXIgUlBDQSBJbnRlZ3JhdGlvbiAoQmF0Y2ggRWZmZWN0IFJlbW92ZWQpIikKcHJpbnQoaW50ZWdyYXRlZF9wbG90X2RhdGFzZXQpCgojIFBsb3QgVU1BUCBjb2xvcmVkIGJ5IGNsdXN0ZXIgdG8gc2VlIHRoZSBjbHVzdGVyaW5nIHJlc3VsdHMKaW50ZWdyYXRlZF9wbG90X2NsdXN0ZXJzIDwtIERpbVBsb3QoY2Q0dF9pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4wLjIiLCBsYWJlbCA9IFRSVUUpICsKICBnZ3RpdGxlKCJVTUFQIG9mIEludGVncmF0ZWQgTm9ybWFsIENENCsgVCBDZWxscyAoQ2x1c3RlcnMpIikKcHJpbnQoaW50ZWdyYXRlZF9wbG90X2NsdXN0ZXJzKQoKIyBDb21iaW5lIHBsb3RzIGZvciBjb21wYXJpc29uCmNvbWJpbmVkX2ludGVncmF0aW9uX3Bsb3RzIDwtIGludGVncmF0ZWRfcGxvdF9kYXRhc2V0ICsgaW50ZWdyYXRlZF9wbG90X2NsdXN0ZXJzCnByaW50KGNvbWJpbmVkX2ludGVncmF0aW9uX3Bsb3RzKQoKRGltUGxvdChjZDR0X2ludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiaW50ZWdyYXRlZF9zbm5fcmVzLjAuMyIsIGxhYmVsID0gVFJVRSwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBUKQpEaW1QbG90KGNkNHRfaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMC40IiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQpCkRpbVBsb3QoY2Q0dF9pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4wLjUiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLmJveCA9IFQsIHJlcGVsID0gVCkKCkRpbVBsb3QoY2Q0dF9pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInByZWRpY3RlZC5jZWxsdHlwZS5sMiIsIGxhYmVsID0gVFJVRSwgbGFiZWwuYm94ID0gVCwgcmVwZWwgPSBUKQpEaW1QbG90KGNkNHRfaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJQcmVkaWN0aW9uIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5ib3ggPSBULCByZXBlbCA9IFQpCgoKIyBTYXZlIHRoZSBpbnRlZ3JhdGVkIG9iamVjdCBmb3Igc3Vic2VxdWVudCBzdGVwcwpzYXZlUkRTKGNkNHRfaW50ZWdyYXRlZCwgImludGVncmF0ZWRfbm9ybWFsX2NkNHRfc2V1cmF0X29iamVjdC5yZHMiKQoKcHJpbnQoIlJQQ0EgaW50ZWdyYXRpb24gY29tcGxldGUuIEludGVncmF0ZWQgU2V1cmF0IG9iamVjdCBzYXZlZC4iKQpgYGAKCgoKCgojIyBQaGFzZSAzOiBDZWxsIFR5cGUgQW5ub3RhdGlvbiBhbmQgRGlmZmVyZW50aWF0aW9uIFBhdGggT3JkZXJpbmcgKFVzaW5nIEV4aXN0aW5nIEFubm90YXRpb25zKQoKU2luY2UgeW91ciBpbnRlZ3JhdGVkIG9iamVjdCBhbHJlYWR5IGNvbnRhaW5zIGNlbGwgdHlwZSBhbm5vdGF0aW9ucyBmcm9tIEF6aW11dGggKGBQcmVkaWN0aW9uYCBhbmQgYHByZWRpY3RlZC5jZWxsdHlwZS5sMmAgY29sdW1ucyksIHdlIHdpbGwgdXRpbGl6ZSB0aGVzZSBleGlzdGluZyBhbm5vdGF0aW9ucyB0byBkZWZpbmUgdGhlIENENCsgVC1jZWxsIGRpZmZlcmVudGlhdGlvbiBwYXRoLiBUaGlzIHBoYXNlIGZvY3VzZXMgb24gb3JnYW5pemluZyB0aGVzZSBhbm5vdGF0aW9ucyBpbnRvIGEgYmlvbG9naWNhbGx5IG1lYW5pbmdmdWwgb3JkZXIgZm9yIHRyYWplY3RvcnkgaW5mZXJlbmNlLCBmb2xsb3dpbmcgdGhlIGFwcHJvYWNoIHVzZWQgYnkgQ2VyYXBpbyBldCBhbC4gZm9yIENEOCsgVCBjZWxscywgYnV0IGFkYXB0ZWQgZm9yIENENCsgVC1jZWxsIGRpZmZlcmVudGlhdGlvbi4KCiMjIyBMb2FkIEludGVncmF0ZWQgU2V1cmF0IE9iamVjdCAoaWYgc3RhcnRpbmcgZnJvbSBoZXJlKQoKSWYgeW91IGFyZSBydW5uaW5nIHRoaXMgc2NyaXB0IGluIHNlY3Rpb25zLCBlbnN1cmUgeW91IGxvYWQgdGhlIGBjZDR0X2ludGVncmF0ZWRgIG9iamVjdCBzYXZlZCBmcm9tIHRoZSBwcmV2aW91cyBwaGFzZS4KCmBgYHtyIGxvYWRfaW50ZWdyYXRlZF9vYmplY3RfZm9yX2Fubm90YXRpb24sIGV2YWw9RkFMU0V9CiMgVW5jb21tZW50IGFuZCBydW4gaWYgc3RhcnRpbmcgZnJvbSB0aGlzIHBoYXNlCiMgbGlicmFyeShTZXVyYXQpCiMgY2Q0dF9pbnRlZ3JhdGVkIDwtIHJlYWRSRFMoInBhdGgvdG8vc2F2ZS9pbnRlZ3JhdGVkX25vcm1hbF9jZDR0X3NldXJhdF9vYmplY3QucmRzIikKIyBEZWZhdWx0QXNzYXkoY2Q0dF9pbnRlZ3JhdGVkKSA8LSAiaW50ZWdyYXRlZCIKIyBwcmludChjZDR0X2ludGVncmF0ZWQpCmBgYAoKIyMjIEluc3BlY3QgRXhpc3RpbmcgQ2VsbCBUeXBlIEFubm90YXRpb25zCgpGaXJzdCwgbGV0J3MgZXhhbWluZSB0aGUgZXhpc3RpbmcgY2VsbCB0eXBlIGFubm90YXRpb25zIGluIHlvdXIgaW50ZWdyYXRlZCBvYmplY3QgdG8gdW5kZXJzdGFuZCB3aGF0IENENCsgVC1jZWxsIHN1YnNldHMgYXJlIHByZXNlbnQuCgpgYGB7ciBpbnNwZWN0X2V4aXN0aW5nX2Fubm90YXRpb25zfQojIENoZWNrIGF2YWlsYWJsZSBtZXRhZGF0YSBjb2x1bW5zCnByaW50KCJBdmFpbGFibGUgbWV0YWRhdGEgY29sdW1uczoiKQpwcmludChjb2xuYW1lcyhjZDR0X2ludGVncmF0ZWRAbWV0YS5kYXRhKSkKCiMgSW5zcGVjdCB0aGUgZXhpc3RpbmcgYW5ub3RhdGlvbnMKaWYoIlByZWRpY3Rpb24iICVpbiUgY29sbmFtZXMoY2Q0dF9pbnRlZ3JhdGVkQG1ldGEuZGF0YSkpIHsKICBwcmludCgiUHJlZGljdGlvbiBjb2x1bW4gY2VsbCB0eXBlczoiKQogIHByaW50KHRhYmxlKGNkNHRfaW50ZWdyYXRlZCRQcmVkaWN0aW9uKSkKfQoKaWYoInByZWRpY3RlZC5jZWxsdHlwZS5sMiIgJWluJSBjb2xuYW1lcyhjZDR0X2ludGVncmF0ZWRAbWV0YS5kYXRhKSkgewogIHByaW50KCJwcmVkaWN0ZWQuY2VsbHR5cGUubDIgY29sdW1uIGNlbGwgdHlwZXM6IikKICBwcmludCh0YWJsZShjZDR0X2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyKSkKfQoKIyBWaXN1YWxpemUgZXhpc3RpbmcgYW5ub3RhdGlvbnMKaWYoIlByZWRpY3Rpb24iICVpbiUgY29sbmFtZXMoY2Q0dF9pbnRlZ3JhdGVkQG1ldGEuZGF0YSkpIHsKICBwX3ByZWRpY3Rpb24gPC0gRGltUGxvdChjZDR0X2ludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiUHJlZGljdGlvbiIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFKSArCiAgICBnZ3RpdGxlKCJFeGlzdGluZyBDZWxsIFR5cGUgQW5ub3RhdGlvbnMgKFByZWRpY3Rpb24pIikKICBwcmludChwX3ByZWRpY3Rpb24pCn0KCmlmKCJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiICVpbiUgY29sbmFtZXMoY2Q0dF9pbnRlZ3JhdGVkQG1ldGEuZGF0YSkpIHsKICBwX3ByZWRpY3RlZF9sMiA8LSBEaW1QbG90KGNkNHRfaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJwcmVkaWN0ZWQuY2VsbHR5cGUubDIiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSkgKwogICAgZ2d0aXRsZSgiRXhpc3RpbmcgQ2VsbCBUeXBlIEFubm90YXRpb25zIChwcmVkaWN0ZWQuY2VsbHR5cGUubDIpIikKICBwcmludChwX3ByZWRpY3RlZF9sMikKfQpgYGAKYGBge3J9CgojIENoZWNrIGNsdXN0ZXIgY29tcG9zaXRpb24KdGFibGUoY2Q0dF9pbnRlZ3JhdGVkJGludGVncmF0ZWRfc25uX3Jlcy4wLjUsIGNkNHRfaW50ZWdyYXRlZCRwcmVkaWN0ZWQuY2VsbHR5cGUubDIpCgojIENoZWNrIGNsdXN0ZXIgY29tcG9zaXRpb24KdGFibGUoY2Q0dF9pbnRlZ3JhdGVkJGludGVncmF0ZWRfc25uX3Jlcy4wLjUsIGNkNHRfaW50ZWdyYXRlZCRQcmVkaWN0aW9uKQoKbWFya2VycyA8LSBjKCJDQ1I3IiwiU0VMTCIsIklMN1IiLCJUQ0Y3IiwiR1pNSyIsIkdaTUIiLCJJRk5HIiwiUFJGMSIsIk5LRzciLCJNS0k2NyIsIlRPUDJBIiwiRk9YUDMiLCJJTDJSQSIpCmF2Z19leHAgPC0gQXZlcmFnZUV4cHJlc3Npb24oY2Q0dF9pbnRlZ3JhdGVkLCBhc3NheXMgPSAiU0NUIiwgZmVhdHVyZXMgPSBtYXJrZXJzKQphdmdfZXhwJFNDVAoKbGlicmFyeShwaGVhdG1hcCkKcGhlYXRtYXAoYXZnX2V4cCRTQ1QsIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgbWFpbiA9ICJDRDQgVC1jZWxsIG1hcmtlciBleHByZXNzaW9uIHBlciBjbHVzdGVyIikKCmBgYAoKIyMjIERlZmluZSBDRDQrIFQtY2VsbCBEaWZmZXJlbnRpYXRpb24gUGF0aAoKQmFzZWQgb24gdGhlIGV4aXN0aW5nIGFubm90YXRpb25zLCB3ZSB3aWxsIGNyZWF0ZSBhIG9yZGVyZWQgZGlmZmVyZW50aWF0aW9uIHBhdGggc2ltaWxhciB0byBDZXJhcGlvIGV0IGFsLidzIGFwcHJvYWNoLiBUaGUgdHlwaWNhbCBDRDQrIFQtY2VsbCBkaWZmZXJlbnRpYXRpb24gcHJvZ3Jlc3Npb24gZm9sbG93czogTmFpdmUgQ0Q0KyBUIGNlbGxzIChDRDRUbikg4oaSIENlbnRyYWwgTWVtb3J5IChDRDRUY20pIOKGkiBFZmZlY3RvciBNZW1vcnkgKENENFRlbSkg4oaSIHBvdGVudGlhbGx5IG90aGVyIHNwZWNpYWxpemVkIHN1YnNldHMuCgpgYGB7ciB9CiMgRW5zdXJlIGNsdXN0ZXIgY29sdW1uIGV4aXN0cwp0YWJsZShjZDR0X2ludGVncmF0ZWQkaW50ZWdyYXRlZF9zbm5fcmVzLjAuNSkKCiMgTWFwIGNsdXN0ZXJzIHRvIGRpZmZlcmVudGlhdGlvbiBzdGFnZXMgYmFzZWQgb24gbWFya2VyIGV4cHJlc3Npb24KY2x1c3Rlcl90b19zdGFnZSA8LSBjKAogICIwIiA9ICJDRDRUbiIsICAgICAgICAgICMgZzA6IENDUjcsIFNFTEwsIElMN1IgaGlnaCDihpIgTmFpdmUKICAiMSIgPSAiQ0Q0VGNtIiwgICAgICAgICAjIGcxOiBDQ1I3LCBTRUxMLCBJTDdSIGhpZ2gg4oaSIENlbnRyYWwgTWVtb3J5CiAgIjIiID0gIkNENFRjbV9DVEwiLCAgICAgIyBnMjogSUw3UiB2ZXJ5IGhpZ2gsIG1vZGVyYXRlIGN5dG90b3hpYyBtYXJrZXJzIOKGkiBIeWJyaWQgY2VudHJhbCBtZW1vcnkgLyBlYXJseSBDVEwKICAiMyIgPSAiQ0Q0VG4iLCAgICAgICAgICAjIGczOiBDQ1I3LCBUQ0Y3LCBTRUxMIGhpZ2gg4oaSIE5haXZlCiAgIjQiID0gIkNENFRjbSIsICAgICAgICAgIyBnNDogQ0NSNywgVENGNyDihpIgQ2VudHJhbCBNZW1vcnkKICAiNSIgPSAiQ0Q0VGNtIiwgICAgICAgICAjIGc1OiBNS0k2Ny9UT1AyQSBsb3cg4oaSIHRyZWF0IGFzIGNlbnRyYWwgbWVtb3J5IChub3QgcHJvbGlmZXJhdGluZykKICAiNiIgPSAiQ0Q0VGNtIiwgICAgICAgICAjIGc2OiBNS0k2Ny9UT1AyQSBsb3cg4oaSIHRyZWF0IGFzIGNlbnRyYWwgbWVtb3J5CiAgIjciID0gIkNENFRjdGwiICAgICAgICAgIyBnNzogR1pNSywgUFJGMSwgTktHNyBoaWdoIOKGkiBDeXRvdG94aWMKKQoKIyBBc3NpZ24gZGlmZmVyZW50aWF0aW9uIHN0YWdlIHRvIGVhY2ggY2VsbApkaWZmX3N0YWdlX3ZlYyA8LSBzYXBwbHkoY2Q0dF9pbnRlZ3JhdGVkJGludGVncmF0ZWRfc25uX3Jlcy4wLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgY2x1c3Rlcl90b19zdGFnZVthcy5jaGFyYWN0ZXIoeCldKQpuYW1lcyhkaWZmX3N0YWdlX3ZlYykgPC0gY29sbmFtZXMoY2Q0dF9pbnRlZ3JhdGVkKQpjZDR0X2ludGVncmF0ZWQgPC0gQWRkTWV0YURhdGEoY2Q0dF9pbnRlZ3JhdGVkLCBtZXRhZGF0YSA9IGRpZmZfc3RhZ2VfdmVjLCBjb2wubmFtZSA9ICJkaWZmZXJlbnRpYXRpb25fc3RhZ2UiKQoKIyBTZXQgb3JkZXJlZCBmYWN0b3IgZm9yIHRyYWplY3Rvcnkgb3IgcGxvdHRpbmcKZGlmZmVyZW50aWF0aW9uX29yZGVyIDwtIGMoIkNENFRuIiwgIkNENFRjbSIsICJDRDRUY21fQ1RMIiwgIkNENFRjdGwiKQpjZDR0X2ludGVncmF0ZWQkZGlmZmVyZW50aWF0aW9uX3N0YWdlIDwtIGZhY3RvcihjZDR0X2ludGVncmF0ZWQkZGlmZmVyZW50aWF0aW9uX3N0YWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gZGlmZmVyZW50aWF0aW9uX29yZGVyKQoKIyBDaGVjayBjbHVzdGVyIGNvdW50cwp0YWJsZShjZDR0X2ludGVncmF0ZWQkZGlmZmVyZW50aWF0aW9uX3N0YWdlKQoKCgpgYGAKCgoKCgoKCmBgYHtyIH0KIyAjIFVzZSB0aGUgbW9yZSBkZXRhaWxlZCBhbm5vdGF0aW9uIGNvbHVtbiAocHJlZGljdGVkLmNlbGx0eXBlLmwyIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIFByZWRpY3Rpb24pCiMgaWYoInByZWRpY3RlZC5jZWxsdHlwZS5sMiIgJWluJSBjb2xuYW1lcyhjZDR0X2ludGVncmF0ZWRAbWV0YS5kYXRhKSkgewojICAgY2Q0dF9pbnRlZ3JhdGVkJGNlbGxfdHlwZV9kZXRhaWxlZCA8LSBjZDR0X2ludGVncmF0ZWQkcHJlZGljdGVkLmNlbGx0eXBlLmwyCiMgfSBlbHNlIGlmKCJQcmVkaWN0aW9uIiAlaW4lIGNvbG5hbWVzKGNkNHRfaW50ZWdyYXRlZEBtZXRhLmRhdGEpKSB7CiMgICBjZDR0X2ludGVncmF0ZWQkY2VsbF90eXBlX2RldGFpbGVkIDwtIGNkNHRfaW50ZWdyYXRlZCRQcmVkaWN0aW9uCiMgfSBlbHNlIHsKIyAgIHN0b3AoIk5laXRoZXIgJ1ByZWRpY3Rpb24nIG5vciAncHJlZGljdGVkLmNlbGx0eXBlLmwyJyBjb2x1bW5zIGZvdW5kIGluIG1ldGFkYXRhIikKIyB9CiMgCiMgIyBNYXAgZGV0YWlsZWQgY2VsbCB0eXBlcyB0byBkaWZmZXJlbnRpYXRpb24gc3RhZ2VzCiMgIyBZb3UgbWF5IG5lZWQgdG8gYWRqdXN0IHRoZXNlIG1hcHBpbmdzIGJhc2VkIG9uIHlvdXIgYWN0dWFsIGFubm90YXRpb24gcmVzdWx0cwojIGNkNHRfaW50ZWdyYXRlZCRkaWZmZXJlbnRpYXRpb25fc3RhZ2UgPC0gY2Q0dF9pbnRlZ3JhdGVkJGNlbGxfdHlwZV9kZXRhaWxlZAojIAojICMgQ3JlYXRlIGEgbWFwcGluZyBmcm9tIGRldGFpbGVkIGNlbGwgdHlwZXMgdG8gb3JkZXJlZCBkaWZmZXJlbnRpYXRpb24gc3RhZ2VzCiMgIyBUaGlzIGlzIGEgdGVtcGxhdGUgLSBhZGp1c3QgYmFzZWQgb24geW91ciBhY3R1YWwgY2VsbCB0eXBlIG5hbWVzCiMgZGlmZmVyZW50aWF0aW9uX21hcHBpbmcgPC0gYygKIyAgICMgTmFpdmUgQ0Q0KyBUIGNlbGxzIChlYXJsaWVzdCBzdGFnZSkKIyAgICJDRDQgTmFpdmUiID0gIkNENFRuIiwKIyAgICJDRDQgVG4iID0gIkNENFRuIiwKIyAgIAojICAgCiMgICAjIENlbnRyYWwgTWVtb3J5IENENCsgVCBjZWxscwojICAgIkNENCBUQ00iID0gIkNENFRjbSIsIAojICAgIkNENCBUY20iID0gIkNENFRjbSIsCiMgIAojIAojICAgIyBFZmZlY3RvciBNZW1vcnkgQ0Q0KyBUIGNlbGxzCiMgICAiQ0Q0IFRFTSIgPSAiQ0Q0VGVtIiwKIyAgIAojICAgIyBDeXRvdG94aWMgQ0Q0KyBUIGNlbGxzCiMgICAiQ0Q0IENUTCIgPSAiQ0Q0Y3RsIiwKIyAgIAojICAgCiMgICAjIE90aGVyIENENCsgc3Vic2V0cyAoYWRqdXN0IGFzIG5lZWRlZCkKIyAgICJDRDQgcHJvbGlmZXJhdGlvbiIgPSAiQ0Q0cCIsCiMgKQojIAojICMgQXBwbHkgdGhlIG1hcHBpbmcKIyBmb3Iob3JpZ2luYWxfbmFtZSBpbiBuYW1lcyhkaWZmZXJlbnRpYXRpb25fbWFwcGluZykpIHsKIyAgIGNkNHRfaW50ZWdyYXRlZCRkaWZmZXJlbnRpYXRpb25fc3RhZ2VbY2Q0dF9pbnRlZ3JhdGVkJGNlbGxfdHlwZV9kZXRhaWxlZCA9PSBvcmlnaW5hbF9uYW1lXSA8LSBkaWZmZXJlbnRpYXRpb25fbWFwcGluZ1tvcmlnaW5hbF9uYW1lXQojIH0KIyAKIyAjIENoZWNrIHRoZSBtYXBwaW5nIHJlc3VsdHMKIyBwcmludCgiRGlmZmVyZW50aWF0aW9uIHN0YWdlIG1hcHBpbmcgcmVzdWx0czoiKQojIHByaW50KHRhYmxlKGNkNHRfaW50ZWdyYXRlZCRkaWZmZXJlbnRpYXRpb25fc3RhZ2UpKQojIAojICMgRGVmaW5lIHRoZSBiaW9sb2dpY2FsIG9yZGVyIGZvciB0cmFqZWN0b3J5IGluZmVyZW5jZSAoZnJvbSBuYWl2ZSB0byBtb3N0IGRpZmZlcmVudGlhdGVkKQojIGRpZmZlcmVudGlhdGlvbl9vcmRlciA8LSBjKCJDRDRUbiIsICJDRDRUY20iLCAiQ0Q0VGVtIiwgIkNENFRjdGwiLCAiQ0Q0cCIpCiMgCiMgIyBGaWx0ZXIgdG8gb25seSBpbmNsdWRlIHN0YWdlcyBwcmVzZW50IGluIHRoZSBkYXRhCiMgcHJlc2VudF9zdGFnZXMgPC0gaW50ZXJzZWN0KGRpZmZlcmVudGlhdGlvbl9vcmRlciwgdW5pcXVlKGNkNHRfaW50ZWdyYXRlZCRkaWZmZXJlbnRpYXRpb25fc3RhZ2UpKQojIGNkNHRfaW50ZWdyYXRlZCRkaWZmZXJlbnRpYXRpb25fc3RhZ2UgPC0gZmFjdG9yKGNkNHRfaW50ZWdyYXRlZCRkaWZmZXJlbnRpYXRpb25fc3RhZ2UsIGxldmVscyA9IHByZXNlbnRfc3RhZ2VzKQojIAojIHByaW50KCJGaW5hbCBkaWZmZXJlbnRpYXRpb24gc3RhZ2VzIChpbiBvcmRlcik6IikKIyBwcmludChsZXZlbHMoY2Q0dF9pbnRlZ3JhdGVkJGRpZmZlcmVudGlhdGlvbl9zdGFnZSkpCmBgYAoKIyMjIFZpc3VhbGl6ZSBEaWZmZXJlbnRpYXRpb24gUGF0aAoKYGBge3IgdmlzdWFsaXplX2RpZmZlcmVudGlhdGlvbl9wYXRofQojIFBsb3QgdGhlIG9yZGVyZWQgZGlmZmVyZW50aWF0aW9uIHN0YWdlcwpwX2RpZmZfc3RhZ2VzIDwtIERpbVBsb3QoY2Q0dF9pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImRpZmZlcmVudGlhdGlvbl9zdGFnZSIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFKSArCiAgZ2d0aXRsZSgiQ0Q0KyBULWNlbGwgRGlmZmVyZW50aWF0aW9uIFN0YWdlcyAoT3JkZXJlZCkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCnByaW50KHBfZGlmZl9zdGFnZXMpCgojIENyZWF0ZSBhIHN1bW1hcnkgdGFibGUgb2YgY2VsbCBjb3VudHMgcGVyIHN0YWdlCnN0YWdlX3N1bW1hcnkgPC0gdGFibGUoY2Q0dF9pbnRlZ3JhdGVkJGRpZmZlcmVudGlhdGlvbl9zdGFnZSwgY2Q0dF9pbnRlZ3JhdGVkJGRhdGFzZXQpCnByaW50KCJDZWxsIGNvdW50cyBwZXIgZGlmZmVyZW50aWF0aW9uIHN0YWdlIGJ5IGRhdGFzZXQ6IikKcHJpbnQoc3RhZ2Vfc3VtbWFyeSkKCiMgVmlzdWFsaXplIG1hcmtlciBnZW5lcyBmb3IgdmFsaWRhdGlvbgojIFRoZXNlIGFyZSBjYW5vbmljYWwgQ0Q0KyBULWNlbGwgZGlmZmVyZW50aWF0aW9uIG1hcmtlcnMKbWFya2VyX2dlbmVzIDwtIGMoIkNDUjciLCAiU0VMTCIsICJJTDdSIiwgIkNENDQiLCAiR1pNQiIsICJQUkYxIiwgIkZPWFAzIiwgIkNYQ1I1IiwgIkJDTDYiKQphdmFpbGFibGVfbWFya2VycyA8LSBpbnRlcnNlY3QobWFya2VyX2dlbmVzLCByb3duYW1lcyhjZDR0X2ludGVncmF0ZWQpKQoKaWYobGVuZ3RoKGF2YWlsYWJsZV9tYXJrZXJzKSA+IDApIHsKICAjIFN3aXRjaCB0byBTQ1QgYXNzYXkgZm9yIG1hcmtlciB2aXN1YWxpemF0aW9uCiAgRGVmYXVsdEFzc2F5KGNkNHRfaW50ZWdyYXRlZCkgPC0gIlNDVCIKICAKICBwX21hcmtlcnMgPC0gRmVhdHVyZVBsb3QoY2Q0dF9pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGF2YWlsYWJsZV9tYXJrZXJzLCBuY29sID0gMywgcmVkdWN0aW9uID0gInVtYXAiKQogIHByaW50KHBfbWFya2VycykKICAKICAjIFN3aXRjaCBiYWNrIHRvIGludGVncmF0ZWQgYXNzYXkKICBEZWZhdWx0QXNzYXkoY2Q0dF9pbnRlZ3JhdGVkKSA8LSAiaW50ZWdyYXRlZCIKfQoKIyBTYXZlIHRoZSBhbm5vdGF0ZWQgb2JqZWN0CnNhdmVSRFMoY2Q0dF9pbnRlZ3JhdGVkLCAiYW5ub3RhdGVkX25vcm1hbF9jZDR0X3NldXJhdF9vYmplY3QucmRzIikKCnByaW50KCJDZWxsIHR5cGUgYW5ub3RhdGlvbiBhbmQgZGlmZmVyZW50aWF0aW9uIHBhdGggb3JkZXJpbmcgY29tcGxldGUuIikKYGBgIAoKCgojIyBQaGFzZSA0OiBNb25vY2xlMyBUcmFqZWN0b3J5IEluZmVyZW5jZSBvbiBOb3JtYWwgQ0Q0KyBUIENlbGxzIChTQ1RyYW5zZm9ybSBDb21wYXRpYmxlKQoKV2l0aCB0aGUgaW50ZWdyYXRlZCBhbmQgYWNjdXJhdGVseSBhbm5vdGF0ZWQgbm9ybWFsIENENCsgVC1jZWxsIGRhdGFzZXQsIHdlIGNhbiBub3cgcHJvY2VlZCB3aXRoIGNvbnN0cnVjdGluZyB0aGUgZGlmZmVyZW50aWF0aW9uIHRyYWplY3RvcnkgdXNpbmcgTW9ub2NsZTMuIFRoaXMgd2lsbCBlc3RhYmxpc2ggdGhlIHJlZmVyZW5jZSBtYXAgb250byB3aGljaCB0aGUgU8OpemFyeSBjZWxscyB3aWxsIGxhdGVyIGJlIHByb2plY3RlZC4gTW9ub2NsZTMgaXMgd2VsbC1zdWl0ZWQgZm9yIHRoaXMgdGFzayBkdWUgdG8gaXRzIGFiaWxpdHkgdG8gbW9kZWwgY29tcGxleCwgYnJhbmNoaW5nIHRyYWplY3RvcmllcyBhbmQgYXNzaWduIHBzZXVkb3RpbWUgdmFsdWVzLCByZXByZXNlbnRpbmcgdGhlIHByb2dyZXNzaW9uIG9mIGNlbGxzIHRocm91Z2ggYSBiaW9sb2dpY2FsIHByb2Nlc3MuCgojIyMgV2h5IE1vbm9jbGUzIHdpdGggU0NUcmFuc2Zvcm0gRGF0YT8KCldoZW4gd29ya2luZyB3aXRoIFNDVHJhbnNmb3JtLXByb2Nlc3NlZCBkYXRhLCBpdCdzIGltcG9ydGFudCB0byB1bmRlcnN0YW5kIGhvdyBNb25vY2xlMyBoYW5kbGVzIHRoZSBkaWZmZXJlbnQgYXNzYXlzLiBXaGlsZSB3ZSB1c2VkIHRoZSBgaW50ZWdyYXRlZGAgYXNzYXkgZm9yIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbiBhbmQgY2x1c3RlcmluZywgTW9ub2NsZTMgdHlwaWNhbGx5IHdvcmtzIGJlc3Qgd2l0aCByYXcgY291bnRzIG9yIGxvZy1ub3JtYWxpemVkIGRhdGEgZm9yIGl0cyBjb3JlIHRyYWplY3RvcnkgaW5mZXJlbmNlIGFsZ29yaXRobXMuIFRoZSBgU0NUYCBhc3NheSBjb250YWlucyBjb3JyZWN0ZWQgY291bnRzIHRoYXQgY2FuIGJlIHVzZWQsIGJ1dCB3ZSdsbCBwcmltYXJpbHkgdXNlIHRoZSBgUk5BYCBhc3NheSdzIGNvdW50cyBmb3IgTW9ub2NsZTMgd2hpbGUgbGV2ZXJhZ2luZyB0aGUgVU1BUCBlbWJlZGRpbmcgZnJvbSBvdXIgaW50ZWdyYXRlZCBhbmFseXNpcy4KCiMjIyBMb2FkIEFubm90YXRlZCBJbnRlZ3JhdGVkIFNldXJhdCBPYmplY3QgKGlmIHN0YXJ0aW5nIGZyb20gaGVyZSkKCklmIHlvdSBhcmUgcnVubmluZyB0aGlzIHNjcmlwdCBpbiBzZWN0aW9ucywgZW5zdXJlIHlvdSBsb2FkIHRoZSBgY2Q0dF9pbnRlZ3JhdGVkYCBvYmplY3Qgc2F2ZWQgZnJvbSB0aGUgcHJldmlvdXMgcGhhc2UuCgpgYGB7ciBsb2FkX2Fubm90YXRlZF9vYmplY3RfZm9yX21vbm9jbGUsIGV2YWw9RkFMU0V9CiMgVW5jb21tZW50IGFuZCBydW4gaWYgc3RhcnRpbmcgZnJvbSB0aGlzIHBoYXNlCiMgbGlicmFyeShTZXVyYXQpCiMgY2Q0dF9pbnRlZ3JhdGVkIDwtIHJlYWRSRFMoInBhdGgvdG8vc2F2ZS9hbm5vdGF0ZWRfbm9ybWFsX2NkNHRfc2V1cmF0X29iamVjdC5yZHMiKQojIERlZmF1bHRBc3NheShjZDR0X2ludGVncmF0ZWQpIDwtICJpbnRlZ3JhdGVkIgojIHByaW50KGNkNHRfaW50ZWdyYXRlZCkKYGBgCgojIyMgSW5zdGFsbCBhbmQgTG9hZCBNb25vY2xlMwoKYGBge3IgbG9hZF9tb25vY2xlMywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBJbnN0YWxsIE1vbm9jbGUzIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZAojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKGMoIm1vbm9jbGUzIikpCmxpYnJhcnkobW9ub2NsZTMpCmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwYXRjaHdvcmspCmBgYAoKIyMjIFByZXBhcmUgRGF0YSBmb3IgTW9ub2NsZTMKCk1vbm9jbGUzIHJlcXVpcmVzIGEgYGNlbGxfZGF0YV9zZXRgIChDRFMpIG9iamVjdC4gV2Ugd2lsbCBjb252ZXJ0IG91ciBpbnRlZ3JhdGVkIFNldXJhdCBvYmplY3QgaW50byBhIENEUyBvYmplY3QsIGVuc3VyaW5nIHRoYXQgdGhlIFVNQVAgZW1iZWRkaW5nIGFuZCB0aGUgYGRpZmZlcmVudGlhdGlvbl9zdGFnZWAgYW5ub3RhdGlvbnMgYXJlIGNvcnJlY3RseSB0cmFuc2ZlcnJlZC4gSXQncyBpbXBvcnRhbnQgdG8gdXNlIHRoZSBgUk5BYCBhc3NheSdzIHJhdyBjb3VudHMgZm9yIE1vbm9jbGUzJ3MgY29yZSBmdW5jdGlvbnMsIGV2ZW4gdGhvdWdoIHRoZSBgaW50ZWdyYXRlZGAgYXNzYXkgd2FzIHVzZWQgZm9yIGRpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbi4KCmBgYHtyIHByZXBhcmVfY2RzX25vcm1hbH0KIyBFbnN1cmUgdGhlIFJOQSBhc3NheSBpcyBhdmFpbGFibGUgYW5kIGNvbnRhaW5zIGNvdW50cwojIE1vbm9jbGUzIHR5cGljYWxseSB3b3JrcyBiZXN0IHdpdGggcmF3IGNvdW50cyBmb3IgYWNjdXJhdGUgZGlzcGVyc2lvbiBlc3RpbWF0aW9uCkRlZmF1bHRBc3NheShjZDR0X2ludGVncmF0ZWQpIDwtICJSTkEiCgojICBKb2luIHRoZSBSTkEgbGF5ZXJzCmNkNHRfaW50ZWdyYXRlZCA8LSBKb2luTGF5ZXJzKGNkNHRfaW50ZWdyYXRlZCwgbmV3LmFzc2F5ID0gIlJOQSIpCgojIEV4dHJhY3QgZXhwcmVzc2lvbiBtYXRyaXggKHJhdyBjb3VudHMpCiMgVXNpbmcgY291bnRzIGlzIGdlbmVyYWxseSByZWNvbW1lbmRlZCBmb3IgTW9ub2NsZTMKZXhwcmVzc2lvbl9tYXRyaXggPC0gR2V0QXNzYXlEYXRhKGNkNHRfaW50ZWdyYXRlZCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJjb3VudHMiKQoKIyBFeHRyYWN0IGNlbGwgbWV0YWRhdGEKY2VsbF9tZXRhZGF0YSA8LSBjZDR0X2ludGVncmF0ZWRAbWV0YS5kYXRhCgojIENyZWF0ZSBnZW5lIG1ldGFkYXRhIChzaW1wbGUgZGF0YWZyYW1lIHdpdGggZ2VuZSBuYW1lcykKZ2VuZV9tZXRhZGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IHJvd25hbWVzKGV4cHJlc3Npb25fbWF0cml4KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IHJvd25hbWVzKGV4cHJlc3Npb25fbWF0cml4KSkKCiMgQ3JlYXRlIHRoZSBDRFMgb2JqZWN0CmNkc19ub3JtYWwgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9tYXRyaXgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VsbF9tZXRhZGF0YSA9IGNlbGxfbWV0YWRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZV9tZXRhZGF0YSA9IGdlbmVfbWV0YWRhdGEpCgojIEFkZCB0aGUgVU1BUCBlbWJlZGRpbmcgZnJvbSBTZXVyYXQgdG8gdGhlIENEUyBvYmplY3QKIyBNb25vY2xlMyBjYW4gdXNlIHRoZSBleGlzdGluZyBVTUFQIGVtYmVkZGluZyBmcm9tIG91ciBpbnRlZ3JhdGVkIGFuYWx5c2lzCmlmKCJ1bWFwIiAlaW4lIG5hbWVzKGNkNHRfaW50ZWdyYXRlZEByZWR1Y3Rpb25zKSkgewogIGNkc19ub3JtYWxAaW50X2NvbERhdGFAbGlzdERhdGEkcmVkdWNlZERpbXMkVU1BUCA8LSBjZDR0X2ludGVncmF0ZWRAcmVkdWN0aW9ucyR1bWFwQGNlbGwuZW1iZWRkaW5ncwp9IGVsc2UgewogIHN0b3AoIlVNQVAgcmVkdWN0aW9uIG5vdCBmb3VuZCBpbiBTZXVyYXQgb2JqZWN0LiBQbGVhc2UgZW5zdXJlIGl0J3MgY29tcHV0ZWQuIikKfQoKIyBBZGQgcGFydGl0aW9ucyAoY2x1c3RlcnMpIGZyb20gU2V1cmF0IHRvIENEUwojIFRoaXMgaXMgaW1wb3J0YW50IGZvciBNb25vY2xlMydzIGdyYXBoIGxlYXJuaW5nCnBhcnRpdGlvbnMgPC0gYXMuZmFjdG9yKGNkNHRfaW50ZWdyYXRlZCRzZXVyYXRfY2x1c3RlcnMpCm5hbWVzKHBhcnRpdGlvbnMpIDwtIGNvbG5hbWVzKGNkNHRfaW50ZWdyYXRlZCkKY2RzX25vcm1hbEBjbHVzdGVycyRVTUFQJHBhcnRpdGlvbnMgPC0gcGFydGl0aW9ucwoKcHJpbnQoY2RzX25vcm1hbCkKYGBgCgojIyMgTGVhcm4gUHJpbmNpcGFsIEdyYXBoCgpNb25vY2xlMyBsZWFybnMgYSBwcmluY2lwYWwgZ3JhcGggdGhhdCByZXByZXNlbnRzIHRoZSB0cmFqZWN0b3J5IHN0cnVjdHVyZS4gVGhpcyBncmFwaCBjb25uZWN0cyBjZWxscyBiYXNlZCBvbiB0aGVpciBwcm94aW1pdHkgaW4gdGhlIHJlZHVjZWQtZGltZW5zaW9uYWwgc3BhY2UgKFVNQVAgaW4gb3VyIGNhc2UpLgoKYGBge3IgbW9ub2NsZV9sZWFybl9ncmFwaF9ub3JtYWx9CgojIFRoZSBtYWluIGlzc3VlIHdhcyB0aGF0IHlvdSB3ZXJlIGFzc2lnbmluZyBmYWN0b3JzIHdpdGggYmlvbG9naWNhbCBsYWJlbHMgYXMgcGFydGl0aW9ucywgYnV0IE1vbm9jbGUzIHJlcXVpcmVzIGNoYXJhY3RlciB2ZWN0b3JzLCBhbmQgaWYgdXNlX3BhcnRpdGlvbj1UUlVFLCBwYXJ0aXRpb25zIG11c3QgYmUgc2ltcGxlIElEcyAoZS5nLiwgIjEiKS4gT25jZSB5b3UgZml4ZWQgcGFydGl0aW9ucyBhbmQgZW5zdXJlZCBVTUFQIHJvd25hbWVzIG1hdGNoZWQgQ0RTIGNvbG5hbWVzLCBsZWFybl9ncmFwaCgpIHdvcmtlZC4KCgojIEFzc2lnbiBjbHVzdGVycwpjZHNfbm9ybWFsQGNsdXN0ZXJzJFVNQVAkY2x1c3RlcnMgPC0gYXMuY2hhcmFjdGVyKGNkc19ub3JtYWwkY2Q0dF9zdGFnZSkKbmFtZXMoY2RzX25vcm1hbEBjbHVzdGVycyRVTUFQJGNsdXN0ZXJzKSA8LSBjb2xuYW1lcyhjZHNfbm9ybWFsKQoKIyBBc3NpZ24gcGFydGl0aW9ucyAoY2FuIGp1c3Qgc2V0IGFsbCB0byAiMSIgaWYgdXNpbmcgdXNlX3BhcnRpdGlvbiA9IEZBTFNFKQpjZHNfbm9ybWFsQGNsdXN0ZXJzJFVNQVAkcGFydGl0aW9ucyA8LSByZXAoIjEiLCBuY29sKGNkc19ub3JtYWwpKQpuYW1lcyhjZHNfbm9ybWFsQGNsdXN0ZXJzJFVNQVAkcGFydGl0aW9ucykgPC0gY29sbmFtZXMoY2RzX25vcm1hbCkKCiMgRW5zdXJlIFVNQVAgZW1iZWRkaW5nIHJvd25hbWVzIG1hdGNoIGNvbG5hbWVzIG9mIENEUwp1bWFwX21hdCA8LSByZWR1Y2VkRGltcyhjZHNfbm9ybWFsKSRVTUFQCnVtYXBfbWF0IDwtIHVtYXBfbWF0W2NvbG5hbWVzKGNkc19ub3JtYWwpLCAsIGRyb3AgPSBGQUxTRV0KcmVkdWNlZERpbXMoY2RzX25vcm1hbCkkVU1BUCA8LSBhcy5tYXRyaXgodW1hcF9tYXQpCgpzdG9waWZub3QoYWxsKG5hbWVzKGNkc19ub3JtYWxAY2x1c3RlcnMkVU1BUCRwYXJ0aXRpb25zKSA9PSBjb2xuYW1lcyhjZHNfbm9ybWFsKSkpCnN0b3BpZm5vdChhbGwocm93bmFtZXMocmVkdWNlZERpbXMoY2RzX25vcm1hbCkkVU1BUCkgPT0gY29sbmFtZXMoY2RzX25vcm1hbCkpKQoKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgTGVhcm4gdGhlIHByaW5jaXBhbCBncmFwaAojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpjZHNfbm9ybWFsIDwtIGxlYXJuX2dyYXBoKGNkc19ub3JtYWwsIHVzZV9wYXJ0aXRpb24gPSBUUlVFKQoKIyBQbG90IHRoZSBsZWFybmVkIGdyYXBoIGNvbG9yZWQgYnkgZGlmZmVyZW50aWF0aW9uIHN0YWdlCnBfZ3JhcGhfc3RhZ2VzIDwtIHBsb3RfY2VsbHMoY2RzX25vcm1hbCwgY29sb3JfY2VsbHNfYnkgPSAiZGlmZmVyZW50aWF0aW9uX3N0YWdlIiwgCiAgICAgICAgICAgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXIgPSBGQUxTRSwgCiAgICAgICAgICAgbGFiZWxfbGVhdmVzID0gRkFMU0UsIAogICAgICAgICAgIGxhYmVsX2JyYW5jaF9wb2ludHMgPSBGQUxTRSwgCiAgICAgICAgICAgZ3JhcGhfbGFiZWxfc2l6ZSA9IDQpICsKICBnZ3RpdGxlKCJNb25vY2xlMyBHcmFwaCBvbiBOb3JtYWwgQ0Q0KyBUIENlbGxzIChieSBEaWZmZXJlbnRpYXRpb24gU3RhZ2UpIikKcHJpbnQocF9ncmFwaF9zdGFnZXMpCgojIFBsb3QgdGhlIGxlYXJuZWQgZ3JhcGggY29sb3JlZCBieSBkYXRhc2V0IHRvIGVuc3VyZSBubyBiYXRjaCBlZmZlY3RzCnBfZ3JhcGhfZGF0YXNldCA8LSBwbG90X2NlbGxzKGNkc19ub3JtYWwsIGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXQiLCAKICAgICAgICAgICBsYWJlbF9ncm91cHNfYnlfY2x1c3RlciA9IEZBTFNFLCAKICAgICAgICAgICBsYWJlbF9sZWF2ZXMgPSBGQUxTRSwgCiAgICAgICAgICAgbGFiZWxfYnJhbmNoX3BvaW50cyA9IEZBTFNFLCAKICAgICAgICAgICBncmFwaF9sYWJlbF9zaXplID0gNCkgKwogIGdndGl0bGUoIk1vbm9jbGUzIEdyYXBoIG9uIE5vcm1hbCBDRDQrIFQgQ2VsbHMgKGJ5IERhdGFzZXQpIikKcHJpbnQocF9ncmFwaF9kYXRhc2V0KQoKCmBgYAoKIyMjIE9yZGVyIENlbGxzIGluIFBzZXVkb3RpbWUKClRoaXMgaXMgdGhlIGNvcmUgc3RlcCB3aGVyZSBjZWxscyBhcmUgb3JkZXJlZCBhbG9uZyB0aGUgbGVhcm5lZCB0cmFqZWN0b3J5LiBZb3UgbmVlZCB0byBzcGVjaWZ5IGEgInJvb3QiIG5vZGUgKHN0YXJ0IHBvaW50KSBmb3IgdGhlIHRyYWplY3RvcnkuIEZvciBub3JtYWwgQ0Q0KyBULWNlbGwgZGlmZmVyZW50aWF0aW9uLCB0aGUgcm9vdCBzaG91bGQgdHlwaWNhbGx5IGJlIHRoZSBOYWl2ZSBDRDQrIFQtY2VsbCBwb3B1bGF0aW9uIChDRDRUbikuCgpgYGB7ciBtb25vY2xlX29yZGVyX2NlbGxzX25vcm1hbH0KIyAx77iP4oOjIEdldCBuYWl2ZSBDRDRUbiBjZWxscwpuYWl2ZV9jZWxscyA8LSBjb2xuYW1lcyhjZHNfbm9ybWFsKVtjZHNfbm9ybWFsJGRpZmZlcmVudGlhdGlvbl9zdGFnZSA9PSAiQ0Q0VG4iXQoKaWYobGVuZ3RoKG5haXZlX2NlbGxzKSA+IDApIHsKICAjIDLvuI/ig6MgTWFwIGNlbGxzIHRvIHRoZWlyIGNsb3Nlc3QgcHJpbmNpcGFsIGdyYXBoIG5vZGVzCiAgY2xvc2VzdF92ZXJ0ZXggPC0gY2RzX25vcm1hbEBwcmluY2lwYWxfZ3JhcGhfYXV4JFVNQVAkcHJfZ3JhcGhfY2VsbF9wcm9qX2Nsb3Nlc3RfdmVydGV4CiAgY2xvc2VzdF92ZXJ0ZXggPC0gYXMubWF0cml4KGNsb3Nlc3RfdmVydGV4W2NvbG5hbWVzKGNkc19ub3JtYWwpLCAsIGRyb3AgPSBGQUxTRV0pCiAgCiAgIyAz77iP4oOjIEdldCB0aGUgbW9zdCBmcmVxdWVudCBub2RlIGFtb25nIG5haXZlIGNlbGxzIChwcmVzZXJ2ZSBvcmlnaW5hbCB2YWx1ZXMpCiAgcm9vdF9wcl9ub2RlcyA8LSBuYW1lcyh3aGljaC5tYXgodGFibGUoY2xvc2VzdF92ZXJ0ZXhbbmFpdmVfY2VsbHMsIDFdKSkpCiAgCiAgIyA077iP4oOjIENvbnZlcnQgbnVtZXJpYyBJRHMgdG8gdGhlIHByb3BlciAiWV8iIGZvcm1hdCBpZiBuZWVkZWQKICBpZighZ3JlcGwoIl5ZXyIsIHJvb3RfcHJfbm9kZXMpKSB7CiAgICByb290X3ByX25vZGVzIDwtIHBhc3RlMCgiWV8iLCByb290X3ByX25vZGVzKQogIH0KICAKICAjIDXvuI/ig6MgQ2hlY2sgdmFsaWRpdHkKICB2YWxpZF9ub2RlcyA8LSBpZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkc19ub3JtYWwpJFVNQVApJG5hbWUKICBpZighKHJvb3RfcHJfbm9kZXMgJWluJSB2YWxpZF9ub2RlcykpIHsKICAgIHN0b3AocGFzdGUoIlNlbGVjdGVkIHJvb3Qgbm9kZSIsIHJvb3RfcHJfbm9kZXMsICJub3QgZm91bmQgaW4gcHJpbmNpcGFsIGdyYXBoLiIpKQogIH0KICAKICAjIDbvuI/ig6MgT3JkZXIgY2VsbHMKICBjZHNfbm9ybWFsIDwtIG9yZGVyX2NlbGxzKGNkc19ub3JtYWwsIHJvb3RfcHJfbm9kZXMgPSByb290X3ByX25vZGVzKQogIAp9IGVsc2UgewogIGNkc19ub3JtYWwgPC0gb3JkZXJfY2VsbHMoY2RzX25vcm1hbCkKICB3YXJuaW5nKCJObyBDRDRUbiBjZWxscyBmb3VuZC4gVXNpbmcgYXV0b21hdGljIHJvb3Qgc2VsZWN0aW9uLiIpCn0KCmBgYAoKIyMjIFZpc3VhbGl6ZSBQc2V1ZG90aW1lIFRyYWplY3RvcnkKCmBgYHtyIHZpc3VhbGl6ZV9wc2V1ZG90aW1lX25vcm1hbH0KIyBQbG90IGNlbGxzIGNvbG9yZWQgYnkgcHNldWRvdGltZQpwX3BzZXVkb3RpbWUgPC0gcGxvdF9jZWxscyhjZHNfbm9ybWFsLCBjb2xvcl9jZWxsc19ieSA9ICJwc2V1ZG90aW1lIiwgCiAgICAgICAgICAgbGFiZWxfZ3JvdXBzX2J5X2NsdXN0ZXIgPSBGQUxTRSwgCiAgICAgICAgICAgbGFiZWxfbGVhdmVzID0gRkFMU0UsIAogICAgICAgICAgIGxhYmVsX2JyYW5jaF9wb2ludHMgPSBGQUxTRSwgCiAgICAgICAgICAgZ3JhcGhfbGFiZWxfc2l6ZSA9IDQpICsKICBnZ3RpdGxlKCJOb3JtYWwgQ0Q0KyBULWNlbGwgVHJhamVjdG9yeSAoUHNldWRvdGltZSkiKQpwcmludChwX3BzZXVkb3RpbWUpCgojIFBsb3QgY2VsbHMgY29sb3JlZCBieSBkaWZmZXJlbnRpYXRpb24gc3RhZ2Ugd2l0aCBwc2V1ZG90aW1lIHRyYWplY3RvcnkKcF9zdGFnZXNfdHJhamVjdG9yeSA8LSBwbG90X2NlbGxzKGNkc19ub3JtYWwsIGNvbG9yX2NlbGxzX2J5ID0gImRpZmZlcmVudGlhdGlvbl9zdGFnZSIsIAogICAgICAgICAgIGxhYmVsX2dyb3Vwc19ieV9jbHVzdGVyID0gVFJVRSwgCiAgICAgICAgICAgbGFiZWxfbGVhdmVzID0gVFJVRSwgCiAgICAgICAgICAgbGFiZWxfYnJhbmNoX3BvaW50cyA9IFRSVUUsIAogICAgICAgICAgIGdyYXBoX2xhYmVsX3NpemUgPSA0KSArCiAgZ2d0aXRsZSgiTm9ybWFsIENENCsgVC1jZWxsIFRyYWplY3RvcnkgKERpZmZlcmVudGlhdGlvbiBTdGFnZXMpIikKcHJpbnQocF9zdGFnZXNfdHJhamVjdG9yeSkKCiMgQ3JlYXRlIGEgY29tYmluZWQgcGxvdApjb21iaW5lZF90cmFqZWN0b3J5X3Bsb3RzIDwtIHBfcHNldWRvdGltZSArIHBfc3RhZ2VzX3RyYWplY3RvcnkKcHJpbnQoY29tYmluZWRfdHJhamVjdG9yeV9wbG90cykKCiMgU3VtbWFyeSBzdGF0aXN0aWNzCnByaW50KCJQc2V1ZG90aW1lIHN1bW1hcnk6IikKcHJpbnQoc3VtbWFyeShjZHNfbm9ybWFsQHByaW5jaXBhbF9ncmFwaF9hdXhAbGlzdERhdGEkVU1BUCRwc2V1ZG90aW1lKSkKCnByaW50KCJQc2V1ZG90aW1lIGJ5IGRpZmZlcmVudGlhdGlvbiBzdGFnZToiKQpwc2V1ZG90aW1lX2J5X3N0YWdlIDwtIGFnZ3JlZ2F0ZShjZHNfbm9ybWFsQHByaW5jaXBhbF9ncmFwaF9hdXhAbGlzdERhdGEkVU1BUCRwc2V1ZG90aW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGxpc3QoY2RzX25vcm1hbEBjb2xEYXRhJGRpZmZlcmVudGlhdGlvbl9zdGFnZSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IGZ1bmN0aW9uKHgpIGMobWVhbiA9IG1lYW4oeCwgbmEucm0gPSBUUlVFKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbiA9IG1lZGlhbih4LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZCA9IHNkKHgsIG5hLnJtID0gVFJVRSkpKQpwcmludChwc2V1ZG90aW1lX2J5X3N0YWdlKQpgYGAKCiMjIyBJZGVudGlmeSBUcmFqZWN0b3J5LUFzc29jaWF0ZWQgR2VuZXMKCkZpbmQgZ2VuZXMgdGhhdCBjaGFuZ2UgZXhwcmVzc2lvbiBhbG9uZyB0aGUgcHNldWRvdGltZSB0cmFqZWN0b3J5LiBUaGVzZSBnZW5lcyB3aWxsIGJlIGltcG9ydGFudCBmb3IgdW5kZXJzdGFuZGluZyB0aGUgYmlvbG9naWNhbCBwcm9jZXNzZXMgdW5kZXJseWluZyBDRDQrIFQtY2VsbCBkaWZmZXJlbnRpYXRpb24gYW5kIGZvciBwcm9qZWN0aW5nIFPDqXphcnkgY2VsbHMuCgpgYGB7ciB0cmFqZWN0b3J5X2dlbmVzX25vcm1hbH0KIyBGaW5kIGdlbmVzIHRoYXQgdmFyeSBhbG9uZyBwc2V1ZG90aW1lCiMgVGhpcyBzdGVwIGlkZW50aWZpZXMgZ2VuZXMgd2hvc2UgZXhwcmVzc2lvbiBjaGFuZ2VzIHNpZ25pZmljYW50bHkgYWxvbmcgdGhlIHRyYWplY3RvcnkKdHJhamVjdG9yeV9nZW5lcyA8LSBncmFwaF90ZXN0KGNkc19ub3JtYWwsIG5laWdoYm9yX2dyYXBoID0gInByaW5jaXBhbF9ncmFwaCIsIGNvcmVzID0gMSkKCiMgRmlsdGVyIGZvciBzaWduaWZpY2FudCBnZW5lcwpzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzIDwtIHRyYWplY3RvcnlfZ2VuZXNbdHJhamVjdG9yeV9nZW5lcyRxX3ZhbHVlIDwgMC4wNSwgXQpzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzIDwtIHNpZ25pZmljYW50X3RyYWplY3RvcnlfZ2VuZXNbb3JkZXIoc2lnbmlmaWNhbnRfdHJhamVjdG9yeV9nZW5lcyRxX3ZhbHVlKSwgXQoKcHJpbnQocGFzdGUoIk51bWJlciBvZiB0cmFqZWN0b3J5LWFzc29jaWF0ZWQgZ2VuZXM6IiwgbnJvdyhzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzKSkpCnByaW50KCJUb3AgMTAgdHJhamVjdG9yeS1hc3NvY2lhdGVkIGdlbmVzOiIpCnByaW50KGhlYWQoc2lnbmlmaWNhbnRfdHJhamVjdG9yeV9nZW5lcywgMTApKQoKIyBQbG90IGV4cHJlc3Npb24gb2YgdG9wIHRyYWplY3RvcnkgZ2VuZXMKaWYobnJvdyhzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzKSA+IDApIHsKICB0b3BfZ2VuZXMgPC0gcm93bmFtZXMoc2lnbmlmaWNhbnRfdHJhamVjdG9yeV9nZW5lcylbMTptaW4oNiwgbnJvdyhzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzKSldCiAgCiAgcF90cmFqZWN0b3J5X2dlbmVzIDwtIHBsb3RfY2VsbHMoY2RzX25vcm1hbCwgZ2VuZXMgPSB0b3BfZ2VuZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd190cmFqZWN0b3J5X2dyYXBoID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbF9jZWxsX2dyb3VwcyA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2xlYXZlcyA9IEZBTFNFKQogIHByaW50KHBfdHJhamVjdG9yeV9nZW5lcykKfQoKIyBTYXZlIHRyYWplY3RvcnktYXNzb2NpYXRlZCBnZW5lcyBmb3IgbGF0ZXIgdXNlCndyaXRlLmNzdihzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzLCAibm9ybWFsX2NkNHRfdHJhamVjdG9yeV9nZW5lcy5jc3YiKQpgYGAKCmBgYHtyIH0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBGaWx0ZXIgZm9yIHNpZ25pZmljYW50IGdlbmVzIChGRFIgPCAwLjA1KQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzIDwtIHRyYWplY3RvcnlfZ2VuZXMgJT4lIAogIGRwbHlyOjpmaWx0ZXIocV92YWx1ZSA8IDAuMDUpCgpjYXQoIk51bWJlciBvZiB0cmFqZWN0b3J5LWFzc29jaWF0ZWQgZ2VuZXM6IiwgbnJvdyhzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzKSwgIlxuIikKCmlmKG5yb3coc2lnbmlmaWNhbnRfdHJhamVjdG9yeV9nZW5lcykgPiAwKSB7CiAgCiAgIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAjIFNlbGVjdCB0b3AgZ2VuZXMgYnkgTW9yYW4ncyBJIChzdHJvbmdlc3QgdHJhamVjdG9yeSBhc3NvY2lhdGlvbikKICAjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIHRvcF9nZW5lcyA8LSBzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzICU+JSAKICAgIGRwbHlyOjphcnJhbmdlKGRlc2MobW9yYW5zX0kpKSAlPiUgCiAgICBkcGx5cjo6c2xpY2VfaGVhZChuID0gNikgJT4lIAogICAgZHBseXI6OnB1bGwoZ2VuZV9zaG9ydF9uYW1lKQogIAogIGNhdCgiVG9wIHRyYWplY3RvcnktYXNzb2NpYXRlZCBnZW5lczpcbiIpCiAgcHJpbnQodG9wX2dlbmVzKQogIAogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgIyBQbG90IGV4cHJlc3Npb24gb2YgdG9wIHRyYWplY3RvcnkgZ2VuZXMgYWxvbmcgdHJhamVjdG9yeQogICMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgcF90cmFqZWN0b3J5X2dlbmVzIDwtIHBsb3RfY2VsbHMoCiAgICBjZHNfbm9ybWFsLCAKICAgIGdlbmVzID0gdG9wX2dlbmVzLAogICAgc2hvd190cmFqZWN0b3J5X2dyYXBoID0gVFJVRSwgCiAgICBsYWJlbF9jZWxsX2dyb3VwcyA9IEZBTFNFLCAKICAgIGxhYmVsX2xlYXZlcyA9IEZBTFNFCiAgKQogIHByaW50KHBfdHJhamVjdG9yeV9nZW5lcykKICAKfSBlbHNlIHsKICB3YXJuaW5nKCJObyBzaWduaWZpY2FudCB0cmFqZWN0b3J5LWFzc29jaWF0ZWQgZ2VuZXMgZm91bmQgKHFfdmFsdWUgPCAwLjA1KS4iKQp9CmBgYApgYGB7ciB9CiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBGaWx0ZXIgZm9yIHNpZ25pZmljYW50IGdlbmVzIChxIDwgMC4wNSkKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzIDwtIHRyYWplY3RvcnlfZ2VuZXNbdHJhamVjdG9yeV9nZW5lcyRxX3ZhbHVlIDwgMC4wNSwgXQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFJlbW92ZSByaWJvc29tYWwgYW5kIG1pdG9jaG9uZHJpYWwgZ2VuZXMKIyBSaWJvc29tYWw6IHN0YXJ0IHdpdGggIlJQTCIgb3IgIlJQUyIKIyBNaXRvY2hvbmRyaWFsOiBzdGFydCB3aXRoICJNVC0iCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kc2lnbmlmaWNhbnRfdHJhamVjdG9yeV9nZW5lcyA8LSBzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzWyFncmVwbCgiXlJQTHxeUlBTfF5NVC0iLCBzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzJGdlbmVfc2hvcnRfbmFtZSksIF0KCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBTb3J0IGJ5IE1vcmFuJ3MgSSAoZWZmZWN0IHNpemUpCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0Kc2lnbmlmaWNhbnRfdHJhamVjdG9yeV9nZW5lcyA8LSBzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzW29yZGVyKC1zaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzJG1vcmFuc19JKSwgXQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFByaW50IHN1bW1hcnkgYW5kIHRvcCBnZW5lcwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmNhdCgiTnVtYmVyIG9mIHRyYWplY3RvcnktYXNzb2NpYXRlZCBnZW5lcyBhZnRlciBmaWx0ZXJpbmc6IiwgbnJvdyhzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzKSwgIlxuIikKY2F0KCJUb3AgMTAgdHJhamVjdG9yeS1hc3NvY2lhdGVkIGdlbmVzOlxuIikKcHJpbnQoaGVhZChzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzJGdlbmVfc2hvcnRfbmFtZSwgMTApKQoKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFBsb3QgdG9wIGdlbmVzIGFsb25nIHRyYWplY3RvcnkKIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp0b3BfZ2VuZXMgPC0gaGVhZChzaWduaWZpY2FudF90cmFqZWN0b3J5X2dlbmVzJGdlbmVfc2hvcnRfbmFtZSwgNikKaWYobGVuZ3RoKHRvcF9nZW5lcykgPiAwKSB7CiAgcF90cmFqZWN0b3J5X2dlbmVzIDwtIHBsb3RfY2VsbHMoY2RzX25vcm1hbCwgZ2VuZXMgPSB0b3BfZ2VuZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfdHJhamVjdG9yeV9ncmFwaCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2NlbGxfZ3JvdXBzID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2xlYXZlcyA9IEZBTFNFKQogIHByaW50KHBfdHJhamVjdG9yeV9nZW5lcykKfQoKYGBgCgojIyMgU2F2ZSBNb25vY2xlMyBDRFMgT2JqZWN0CgpgYGB7ciBzYXZlX2Nkc19ub3JtYWx9CiMgU2F2ZSB0aGUgQ0RTIG9iamVjdCB3aXRoIHRyYWplY3RvcnkgaW5mb3JtYXRpb24Kc2F2ZVJEUyhjZHNfbm9ybWFsLCAibm9ybWFsX2NkNHRfbW9ub2NsZTNfY2RzLnJkcyIpCgojIEFsc28gc2F2ZSBrZXkgdHJhamVjdG9yeSBpbmZvcm1hdGlvbiBiYWNrIHRvIHRoZSBTZXVyYXQgb2JqZWN0CmNkNHRfaW50ZWdyYXRlZCRtb25vY2xlM19wc2V1ZG90aW1lIDwtIGNkc19ub3JtYWxAcHJpbmNpcGFsX2dyYXBoX2F1eEBsaXN0RGF0YSRVTUFQJHBzZXVkb3RpbWUKY2Q0dF9pbnRlZ3JhdGVkJG1vbm9jbGUzX3BhcnRpdGlvbiA8LSBjZHNfbm9ybWFsQGNsdXN0ZXJzJFVNQVAkcGFydGl0aW9ucwoKIyBTYXZlIHVwZGF0ZWQgU2V1cmF0IG9iamVjdApzYXZlUkRTKGNkNHRfaW50ZWdyYXRlZCwgIm5vcm1hbF9jZDR0X3dpdGhfdHJhamVjdG9yeS5yZHMiKQoKcHJpbnQoIk1vbm9jbGUzIHRyYWplY3RvcnkgaW5mZXJlbmNlIGNvbXBsZXRlLiBPYmplY3RzIHNhdmVkLiIpCmBgYAoKIyBGdW5jdGlvbiB0byBnZXQgdGhlIGVhcmxpZXN0IHByaW5jaXBhbCBub2RlIGZvciBhIGdpdmVuIGNlbGwgdHlwZQojIFRoaXMgZnVuY3Rpb24gaGVscHMgc2VsZWN0IGEgbm9kZSB3aXRoaW4gdGhlIHNwZWNpZmllZCBjZWxsIHR5cGUgdGhhdCBpcyBjbG9zZXN0IHRvIHRoZSBncmFwaCdzIAoKCgojIyBQaGFzZSA1OiBQcm9qZWN0aW5nIFPDqXphcnkgQ2VsbCBMaW5lcyBvbnRvIHRoZSBOb3JtYWwgQ0Q0KyBULWNlbGwgVHJhamVjdG9yeQoKVGhpcyBpcyBhIGNyaXRpY2FsIHBoYXNlIHdoZXJlIHdlIGxldmVyYWdlIHRoZSBlc3RhYmxpc2hlZCBub3JtYWwgQ0Q0KyBULWNlbGwgdHJhamVjdG9yeSB0byB1bmRlcnN0YW5kIHRoZSBkaWZmZXJlbnRpYXRpb24gc3RhdGUgb2YgeW91ciBTw6l6YXJ5IHN5bmRyb21lIGNlbGwgbGluZXMuIEJ5IHByb2plY3RpbmcgdGhlIG1hbGlnbmFudCBjZWxscyBvbnRvIHRoaXMgbm9ybWFsIHJlZmVyZW5jZSwgd2UgY2FuIGlkZW50aWZ5IHdoZXJlIHRoZXkgbWFwIHdpdGhpbiB0aGUgaGVhbHRoeSBkZXZlbG9wbWVudGFsIGxhbmRzY2FwZSwgcHJvdmlkaW5nIGluc2lnaHRzIGludG8gdGhlaXIgcG90ZW50aWFsIGNlbGwgb2Ygb3JpZ2luIGFuZCBhbnkgZGlmZmVyZW50aWF0aW9uIGFycmVzdCBvciBkZXZpYXRpb24uCgojIyMgTG9hZCBTw6l6YXJ5IENlbGwgTGluZSBTZXVyYXQgT2JqZWN0CgpMb2FkIHlvdXIgcHJlLXByb2Nlc3NlZCBhbmQgaW50ZWdyYXRlZCBTw6l6YXJ5IGNlbGwgbGluZSBTZXVyYXQgb2JqZWN0LiBUaGlzIG9iamVjdCBzaG91bGQgY29udGFpbiBSTkEgZXhwcmVzc2lvbiBkYXRhLCBVTUFQIGVtYmVkZGluZ3MsIGFuZCBhbnkgcmVsZXZhbnQgbWV0YWRhdGEgKGUuZy4sIHBhdGllbnQgSUQsIGNlbGwgbGluZSBJRCwgVENSIGNsb25vdHlwZXMpLgoKYGBge3IgbG9hZF9zZXphcnlfb2JqZWN0fQojIExvYWQgeW91ciBpbnRlZ3JhdGVkIFPDqXphcnkgY2VsbCBsaW5lIFNldXJhdCBvYmplY3QKc2V6YXJ5X29iaiA8LSByZWFkUkRTKCJpbnRlZ3JhdGVkX3NlemFyeV9zZXVyYXRfb2JqZWN0LnJkcyIpCgojIEVuc3VyZSB0aGUgUk5BIGFzc2F5IGlzIHNldCBhcyBkZWZhdWx0IGZvciBwcm9qZWN0aW9uCkRlZmF1bHRBc3NheShzZXphcnlfb2JqKSA8LSAiUk5BIgoKcHJpbnQoc2V6YXJ5X29iaikKYGBgCgojIyMgUHJlcGFyZSBTw6l6YXJ5IERhdGEgZm9yIFByb2plY3Rpb24KClRvIHByb2plY3QgdGhlIFPDqXphcnkgY2VsbHMgb250byB0aGUgbm9ybWFsIHRyYWplY3RvcnksIHdlIG5lZWQgdG8gZW5zdXJlIHRoZWlyIGRhdGEgaXMgY29tcGF0aWJsZSB3aXRoIHRoZSBNb25vY2xlMyBDRFMgb2JqZWN0IG9mIG5vcm1hbCBjZWxscy4gVGhpcyBpbnZvbHZlcyBlbnN1cmluZyBjb21tb24gZ2VuZXMgYW5kIHVzaW5nIHRoZSBgU0NUYCBhc3NheSBkYXRhLCBhcyB5b3VyIFPDqXphcnkgb2JqZWN0IHdhcyBhbHNvIHByb2Nlc3NlZCB3aXRoIGBTQ1RyYW5zZm9ybWAuCgpgYGB7ciBwcmVwYXJlX3NlemFyeV9mb3JfcHJvamVjdGlvbn0KIyBFbnN1cmUgdGhlIFNDVCBhc3NheSBpcyB0aGUgZGVmYXVsdCBmb3IgdGhlIFPDqXphcnkgb2JqZWN0CkRlZmF1bHRBc3NheShzZXphcnlfb2JqKSA8LSAiU0NUIgoKIyBFeHRyYWN0IGV4cHJlc3Npb24gbWF0cml4IChTQ1Qgbm9ybWFsaXplZCBkYXRhKQojIFdlIHVzZSB0aGUgJ2RhdGEnIHNsb3Qgb2YgdGhlIFNDVCBhc3NheSwgd2hpY2ggY29udGFpbnMgY29ycmVjdGVkIGFuZCBub3JtYWxpemVkIHZhbHVlcwpzZXphcnlfZXhwcmVzc2lvbl9tYXRyaXggPC0gR2V0QXNzYXlEYXRhKHNlemFyeV9vYmosIGFzc2F5ID0gIlNDVCIsIHNsb3QgPSAiZGF0YSIpCgojIEVuc3VyZSBjb21tb24gZ2VuZXMgYmV0d2VlbiBub3JtYWwgQ0RTIGFuZCBTw6l6YXJ5IGV4cHJlc3Npb24gbWF0cml4CiMgV2Ugc2hvdWxkIHVzZSB0aGUgZmVhdHVyZXMgdGhhdCB3ZXJlIHVzZWQgZm9yIFNDVHJhbnNmb3JtICgzMDAwIGZlYXR1cmVzKQojIEZvciBwcm9qZWN0aW9uLCBpdCdzIGNydWNpYWwgdG8gdXNlIHRoZSBzYW1lIGZlYXR1cmUgc2V0IGFzIHRoZSByZWZlcmVuY2UgdHJhamVjdG9yeS4KY29tbW9uX2ZlYXR1cmVzIDwtIGludGVyc2VjdChyb3duYW1lcyhzZXphcnlfZXhwcmVzc2lvbl9tYXRyaXgpLCBmRGF0YShjZHNfbm9ybWFsKSRnZW5lX3Nob3J0X25hbWUpCgpzZXphcnlfZXhwcmVzc2lvbl9tYXRyaXhfZmlsdGVyZWQgPC0gc2V6YXJ5X2V4cHJlc3Npb25fbWF0cml4W2NvbW1vbl9mZWF0dXJlcywgXQoKIyBDcmVhdGUgYSB0ZW1wb3JhcnkgQ0RTIG9iamVjdCBmb3IgU8OpemFyeSBjZWxscyAob3B0aW9uYWwsIGJ1dCBnb29kIGZvciBjb25zaXN0ZW5jeSkKc2V6YXJ5X2NlbGxfbWV0YWRhdGEgPC0gc2V6YXJ5X29iakBtZXRhLmRhdGEKc2V6YXJ5X2dlbmVfbWV0YWRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSBjb21tb25fZmVhdHVyZXMsIHJvdy5uYW1lcyA9IGNvbW1vbl9mZWF0dXJlcykKCmNkc19zZXphcnlfdGVtcCA8LSBuZXdfY2VsbF9kYXRhX3NldChzZXphcnlfZXhwcmVzc2lvbl9tYXRyaXhfZmlsdGVyZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjZWxsX21ldGFkYXRhID0gc2V6YXJ5X2NlbGxfbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX21ldGFkYXRhID0gc2V6YXJ5X2dlbmVfbWV0YWRhdGEpCgojIEFkZCBVTUFQIGVtYmVkZGluZyBmcm9tIFPDqXphcnkgb2JqZWN0IHRvIHRlbXBvcmFyeSBDRFMKIyBFbnN1cmUgdGhlIFVNQVAgcmVkdWN0aW9uIG5hbWUgbWF0Y2hlcyB3aGF0J3MgaW4geW91ciBTZXVyYXQgb2JqZWN0CmlmKCJ1bWFwIiAlaW4lIG5hbWVzKHNlemFyeV9vYmpAcmVkdWN0aW9ucykpIHsKICBjZHNfc2V6YXJ5X3RlbXBAaW50X2NvbERhdGFAbGlzdERhdGEkcmVkdWNlZERpbXMkVU1BUCA8LSBzZXphcnlfb2JqQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3MKfSBlbHNlIHsKICBzdG9wKCJVTUFQIHJlZHVjdGlvbiBub3QgZm91bmQgaW4gU8OpemFyeSBTZXVyYXQgb2JqZWN0LiBQbGVhc2UgZW5zdXJlIGl0J3MgY29tcHV0ZWQuIikKfQoKcHJpbnQoY2RzX3NlemFyeV90ZW1wKQpgYGAKCiMjIyBQcm9qZWN0IFPDqXphcnkgQ2VsbHMgb250byBOb3JtYWwgVHJhamVjdG9yeQoKTW9ub2NsZTMgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByb2plY3QgbmV3IGNlbGxzIG9udG8gYW4gZXhpc3RpbmcgcHJpbmNpcGFsIGdyYXBoLiBUaGlzIGFsbG93cyB1cyB0byBzZWUgd2hlcmUgdGhlIFPDqXphcnkgY2VsbHMgZmFsbCB3aXRoaW4gdGhlIG5vcm1hbCBDRDQrIFQtY2VsbCBkaWZmZXJlbnRpYXRpb24gbGFuZHNjYXBlLgoKYGBge3IgcHJvamVjdF9zZXphcnlfY2VsbHN9CiMgQ29tYmluZSB0aGUgbm9ybWFsIGFuZCBTw6l6YXJ5IENEUyBvYmplY3RzIGZvciBwcm9qZWN0aW9uCiMgVGhpcyBzdGVwIGVzc2VudGlhbGx5IGFkZHMgdGhlIFPDqXphcnkgY2VsbHMgdG8gdGhlIGV4aXN0aW5nIGdyYXBoIG9mIG5vcm1hbCBjZWxscwojIGFuZCBmaW5kcyB0aGVpciBjbG9zZXN0IHByb2plY3Rpb24gb250byB0aGUgbGVhcm5lZCB0cmFqZWN0b3J5LgoKIyBGaXJzdCwgZW5zdXJlIHRoYXQgdGhlIGNvbHVtbiBuYW1lcyBvZiB0aGUgZXhwcmVzc2lvbiBtYXRyaWNlcyBhcmUgdW5pcXVlCmNvbG5hbWVzKHNlemFyeV9leHByZXNzaW9uX21hdHJpeF9maWx0ZXJlZCkgPC0gcGFzdGUwKCJzZXphcnlfIiwgY29sbmFtZXMoc2V6YXJ5X2V4cHJlc3Npb25fbWF0cml4X2ZpbHRlcmVkKSkKCiMgQ29tYmluZSBleHByZXNzaW9uIG1hdHJpY2VzCmNvbWJpbmVkX2V4cHJlc3Npb25fbWF0cml4IDwtIGNiaW5kKGV4cHJzKGNkc19ub3JtYWwpLCBzZXphcnlfZXhwcmVzc2lvbl9tYXRyaXhfZmlsdGVyZWQpCgojIENvbWJpbmUgY2VsbCBtZXRhZGF0YQojIEVuc3VyZSBtZXRhZGF0YSBjb2x1bW5zIGFyZSBjb25zaXN0ZW50IG9yIGhhbmRsZWQgYXBwcm9wcmlhdGVseQojIEZvciBzaW1wbGljaXR5LCB3ZSdsbCBjcmVhdGUgYSBuZXcgY29tYmluZWQgbWV0YWRhdGEsIHByZXNlcnZpbmcga2V5IGNvbHVtbnMKY29tYmluZWRfY2VsbF9tZXRhZGF0YSA8LSByYmluZCgKICBjb2xEYXRhKGNkc19ub3JtYWwpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHNlbGVjdChhbnlfb2YoYygiZGF0YXNldCIsICJvcmlnLmlkZW50IiwgImRpZmZlcmVudGlhdGlvbl9zdGFnZV9vcmRlcmVkIiwgImF6aW11dGhfY2VsbF90eXBlIiwgInNldXJhdF9jbHVzdGVycyIpKSksCiAgc2V6YXJ5X2NlbGxfbWV0YWRhdGEgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgbXV0YXRlKGRhdGFzZXQgPSAiU8OpemFyeSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZmZlcmVudGlhdGlvbl9zdGFnZV9vcmRlcmVkID0gIlPDqXphcnkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhemltdXRoX2NlbGxfdHlwZSA9ICJTw6l6YXJ5IikgJT4lIAogICAgc2VsZWN0KGFueV9vZihjKCJkYXRhc2V0IiwgIm9yaWcuaWRlbnQiLCAiZGlmZmVyZW50aWF0aW9uX3N0YWdlX29yZGVyZWQiLCAiYXppbXV0aF9jZWxsX3R5cGUiLCAic2V1cmF0X2NsdXN0ZXJzIikpKQopCgojIEVuc3VyZSByb3cgbmFtZXMgbWF0Y2ggY29sdW1uIG5hbWVzIG9mIGV4cHJlc3Npb24gbWF0cml4CnJvd25hbWVzKGNvbWJpbmVkX2NlbGxfbWV0YWRhdGEpIDwtIGNvbG5hbWVzKGNvbWJpbmVkX2V4cHJlc3Npb25fbWF0cml4KQoKIyBDb21iaW5lIGdlbmUgbWV0YWRhdGEgKHNob3VsZCBiZSB0aGUgc2FtZSkKY29tYmluZWRfZ2VuZV9tZXRhZGF0YSA8LSBmRGF0YShjZHNfbm9ybWFsKQoKIyBDcmVhdGUgYSBuZXcgQ0RTIG9iamVjdCB3aXRoIGNvbWJpbmVkIGRhdGEKY2RzX2NvbWJpbmVkIDwtIG5ld19jZWxsX2RhdGFfc2V0KGNvbWJpbmVkX2V4cHJlc3Npb25fbWF0cml4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VsbF9tZXRhZGF0YSA9IGNvbWJpbmVkX2NlbGxfbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW5lX21ldGFkYXRhID0gY29tYmluZWRfZ2VuZV9tZXRhZGF0YSkKCiMgVHJhbnNmZXIgVU1BUCBlbWJlZGRpbmcgZnJvbSBvcmlnaW5hbCBDRFMgb2JqZWN0cwojIFRoaXMgaXMgYSBjcnVjaWFsIHN0ZXAgdG8gZW5zdXJlIGNlbGxzIGFyZSBwbGFjZWQgY29ycmVjdGx5IGluIHRoZSBVTUFQIHNwYWNlCmNvbWJpbmVkX3VtYXAgPC0gcmJpbmQocmVkdWNlZERpbXMoY2RzX25vcm1hbCkkVU1BUCwgcmVkdWNlZERpbXMoY2RzX3NlemFyeV90ZW1wKSRVTUFQKQpyb3duYW1lcyhjb21iaW5lZF91bWFwKSA8LSBjb2xuYW1lcyhjb21iaW5lZF9leHByZXNzaW9uX21hdHJpeCkKY2RzX2NvbWJpbmVkQGludF9jb2xEYXRhQGxpc3REYXRhJHJlZHVjZWREaW1zJFVNQVAgPC0gY29tYmluZWRfdW1hcAoKIyBUcmFuc2ZlciBncmFwaCBmcm9tIG5vcm1hbCBDRFMgdG8gY29tYmluZWQgQ0RTCmNkc19jb21iaW5lZEBwcmluY2lwYWxfZ3JhcGggPC0gY2RzX25vcm1hbEBwcmluY2lwYWxfZ3JhcGgKY2RzX2NvbWJpbmVkQHByaW5jaXBhbF9ncmFwaF9hdXggPC0gY2RzX25vcm1hbEBwcmluY2lwYWxfZ3JhcGhfYXV4CgojIFByb2plY3QgY2VsbHMgb250byB0aGUgZXhpc3RpbmcgZ3JhcGgKIyBUaGlzIHdpbGwgY2FsY3VsYXRlIHBzZXVkb3RpbWUgZm9yIHRoZSBTw6l6YXJ5IGNlbGxzIGJhc2VkIG9uIHRoZSBub3JtYWwgdHJhamVjdG9yeQpjZHNfY29tYmluZWQgPC0gb3JkZXJfY2VsbHMoY2RzX2NvbWJpbmVkLCByb290X3ByX25vZGVzID0gcm9vdF9ub2RlX2lkKSAjIFVzZSB0aGUgc2FtZSByb290IG5vZGUgYXMgZm9yIG5vcm1hbCBjZWxscwoKcHJpbnQoY2RzX2NvbWJpbmVkKQpgYGAKCiMjIyBWaXN1YWxpemUgUHJvamVjdGlvbiBhbmQgSW50ZXJwcmV0IFJlc3VsdHMKCk5vdyB3ZSBjYW4gdmlzdWFsaXplIHRoZSBjb21iaW5lZCBkYXRhc2V0LCB3aXRoIFPDqXphcnkgY2VsbHMgcHJvamVjdGVkIG9udG8gdGhlIG5vcm1hbCBDRDQrIFQtY2VsbCB0cmFqZWN0b3J5LiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gc2VlIHRoZWlyIHJlbGF0aXZlIHBvc2l0aW9uIGFuZCBpbmZlciB0aGVpciBkaWZmZXJlbnRpYXRpb24gc3RhdGUuCgpgYGB7ciB2aXN1YWxpemVfcHJvamVjdGlvbn0KIyBQbG90IHRoZSBjb21iaW5lZCB0cmFqZWN0b3J5LCBjb2xvcmVkIGJ5IG9yaWdpbmFsIGRhdGFzZXQgKG5vcm1hbCB2cy4gU8OpemFyeSkKcGxvdF9jZWxscyhjZHNfY29tYmluZWQsIGNvbG9yX2NlbGxzX2J5ID0gImRhdGFzZXQiLCAKICAgICAgICAgICBsYWJlbF9ncm91cHNfYnlfY2x1c3RlciA9IEZBTFNFLCAKICAgICAgICAgICBsYWJlbF9sZWF2ZXMgPSBGQUxTRSwgCiAgICAgICAgICAgbGFiZWxfYnJhbmNoX3BvaW50cyA9IEZBTFNFLCAKICAgICAgICAgICBncmFwaF9sYWJlbF9zaXplID0gNCkgKwogIGdndGl0bGUoIlPDqXphcnkgQ2VsbHMgUHJvamVjdGVkIG9udG8gTm9ybWFsIENENCsgVC1jZWxsIFRyYWplY3RvcnkiKQoKIyBQbG90IHRoZSBjb21iaW5lZCB0cmFqZWN0b3J5LCBjb2xvcmVkIGJ5IGRpZmZlcmVudGlhdGlvbiBzdGFnZSAoZm9yIG5vcm1hbCBjZWxscykgYW5kIFPDqXphcnkgZm9yIG1hbGlnbmFudApwbG90X2NlbGxzKGNkc19jb21iaW5lZCwgY29sb3JfY2VsbHNfYnkgPSAiZGlmZmVyZW50aWF0aW9uX3N0YWdlX29yZGVyZWQiLCAKICAgICAgICAgICBsYWJlbF9ncm91cHNfYnlfY2x1c3RlciA9IFRSVUUsIAogICAgICAgICAgIGxhYmVsX2xlYXZlcyA9IEZBTFNFLCAKICAgICAgICAgICBsYWJlbF9icmFuY2hfcG9pbnRzID0gRkFMU0UsIAogICAgICAgICAgIGdyYXBoX2xhYmVsX3NpemUgPSA0KSArCiAgZ2d0aXRsZSgiRGlmZmVyZW50aWF0aW9uIFN0YWdlcyBhbmQgU8OpemFyeSBDZWxsIFByb2plY3Rpb24iKQoKIyBQbG90IHBzZXVkb3RpbWUgZm9yIGFsbCBjZWxscwpwbG90X2NlbGxzKGNkc19jb21iaW5lZCwgY29sb3JfY2VsbHNfYnkgPSAicHNldWRvdGltZSIsIAogICAgICAgICAgIGxhYmVsX2dyb3Vwc19ieV9jbHVzdGVyID0gRkFMU0UsIAogICAgICAgICAgIGxhYmVsX2xlYXZlcyA9IEZBTFNFLCAKICAgICAgICAgICBsYWJlbF9icmFuY2hfcG9pbnRzID0gRkFMU0UsIAogICAgICAgICAgIGdyYXBoX2xhYmVsX3NpemUgPSA0KSArCiAgZ2d0aXRsZSgiUHNldWRvdGltZSBvZiBDb21iaW5lZCBOb3JtYWwgYW5kIFPDqXphcnkgQ2VsbHMiKQoKIyBBbmFseXplIHBzZXVkb3RpbWUgZGlzdHJpYnV0aW9uIGZvciBTw6l6YXJ5IGNlbGxzCnNlemFyeV9wc2V1ZG90aW1lX2RmIDwtIGNvbERhdGEoY2RzX2NvbWJpbmVkKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBmaWx0ZXIoZGF0YXNldCA9PSAiU8OpemFyeSIpICU+JSAKICBzZWxlY3QocHNldWRvdGltZSwgb3JpZy5pZGVudCkKCmdncGxvdChzZXphcnlfcHNldWRvdGltZV9kZiwgYWVzKHggPSBwc2V1ZG90aW1lLCBmaWxsID0gb3JpZy5pZGVudCkpICsKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjYpICsKICBsYWJzKHRpdGxlID0gIlBzZXVkb3RpbWUgRGlzdHJpYnV0aW9uIG9mIFPDqXphcnkgQ2VsbCBMaW5lcyIsIAogICAgICAgeCA9ICJQc2V1ZG90aW1lIiwgeSA9ICJEZW5zaXR5IikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBBbmFseXplIGdlbmUgZXhwcmVzc2lvbiBvZiBrZXkgbWFya2VycyBpbiBTw6l6YXJ5IGNlbGxzIGFsb25nIHRoZSBub3JtYWwgcHNldWRvdGltZQojIERlZmluZSBrZXkgU8OpemFyeSBtYXJrZXJzIChlLmcuLCBDRDcsIENEMjYsIFRPWCwgRFBFUDEpIGFuZCBULWNlbGwgZGlmZmVyZW50aWF0aW9uIG1hcmtlcnMKc2V6YXJ5X21hcmtlcnMgPC0gYygiQ0Q3IiwgIkNEMjYiLCAiRFBFUDEiLCAiVE9YIiwgIkdBVEEzIiwgIkNDUjciLCAiU0VMTCIsICJDRDQ1UkEiLCAiQ0Q0NVJPIikKCiMgRmlsdGVyIGZvciBnZW5lcyBwcmVzZW50IGluIHRoZSBjb21iaW5lZCBkYXRhc2V0CnNlemFyeV9tYXJrZXJzX3ByZXNlbnQgPC0gc2V6YXJ5X21hcmtlcnNbc2V6YXJ5X21hcmtlcnMgJWluJSBmRGF0YShjZHNfY29tYmluZWQpJGdlbmVfc2hvcnRfbmFtZV0KCmlmKGxlbmd0aChzZXphcnlfbWFya2Vyc19wcmVzZW50KSA+IDApIHsKICBwbG90X2dlbmVzX2luX3BzZXVkb3RpbWUoY2RzX2NvbWJpbmVkW2ZEYXRhKGNkc19jb21iaW5lZCkkZ2VuZV9zaG9ydF9uYW1lICVpbiUgc2V6YXJ5X21hcmtlcnNfcHJlc2VudCxdLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9jZWxsc19ieSA9ICJkYXRhc2V0IikgKwogICAgZ2d0aXRsZSgiS2V5IE1hcmtlciBFeHByZXNzaW9uIGFsb25nIE5vcm1hbCBUcmFqZWN0b3J5ICh3aXRoIFPDqXphcnkgQ2VsbHMpIikKfQoKIyBGdXJ0aGVyIGFuYWx5c2lzOiBJZGVudGlmeSB3aGljaCBub3JtYWwgY2VsbCB0eXBlcyBTw6l6YXJ5IGNlbGxzIGFyZSBjbG9zZXN0IHRvCiMgVGhpcyBjYW4gYmUgZG9uZSBieSBsb29raW5nIGF0IHRoZSBkZW5zaXR5IG9mIFPDqXphcnkgY2VsbHMgaW4gZGlmZmVyZW50IHJlZ2lvbnMgb2YgdGhlIFVNQVAKIyBvciBieSBjYWxjdWxhdGluZyBkaXN0YW5jZXMgdG8gbm9ybWFsIGNlbGwgdHlwZSBjZW50cm9pZHMuCgojIEV4YW1wbGU6IENhbGN1bGF0ZSBtZWFuIHBzZXVkb3RpbWUgZm9yIGVhY2ggU8OpemFyeSBjZWxsIGxpbmUKbWVhbl9wc2V1ZG90aW1lX2J5X3NlemFyeV9saW5lIDwtIHNlemFyeV9wc2V1ZG90aW1lX2RmICU+JSAKICBncm91cF9ieShvcmlnLmlkZW50KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fcHNldWRvdGltZSA9IG1lYW4ocHNldWRvdGltZSwgbmEucm0gPSBUUlVFKSkgJT4lIAogIGFycmFuZ2UobWVhbl9wc2V1ZG90aW1lKQoKcHJpbnQoIk1lYW4gcHNldWRvdGltZSBmb3IgZWFjaCBTw6l6YXJ5IGNlbGwgbGluZToiKQpwcmludChtZWFuX3BzZXVkb3RpbWVfYnlfc2V6YXJ5X2xpbmUpCgojIFNhdmUgdGhlIGNvbWJpbmVkIENEUyBvYmplY3QgZm9yIGZ1dHVyZSByZWZlcmVuY2UKc2F2ZVJEUyhjZHNfY29tYmluZWQsICJwYXRoL3RvL3NhdmUvY29tYmluZWRfbm9ybWFsX3NlemFyeV9jZHNfb2JqZWN0LnJkcyIpCgpwcmludCgiU8OpemFyeSBjZWxsIHByb2plY3Rpb24gb250byBub3JtYWwgdHJhamVjdG9yeSBjb21wbGV0ZS4iKQpgYGAKCgoKCgojIyBDb25jbHVzaW9uIGFuZCBJbnRlcnByZXRhdGlvbgoKVGhpcyBjb21wcmVoZW5zaXZlIFJNYXJrZG93biBzY3JpcHQgcHJvdmlkZXMgYSByb2J1c3QgZnJhbWV3b3JrIGZvciB1bmRlcnN0YW5kaW5nIHRoZSBkaWZmZXJlbnRpYXRpb24gbGFuZHNjYXBlIG9mIG5vcm1hbCBDRDQrIFQgY2VsbHMgYW5kLCBjcnVjaWFsbHksIGZvciBtYXBwaW5nIFPDqXphcnkgc3luZHJvbWUgbWFsaWduYW50IGNlbGxzIG9udG8gdGhpcyBub3JtYWwgdHJhamVjdG9yeS4gQnkgZm9sbG93aW5nIHRoZXNlIHN0ZXBzLCB5b3UgY2FuIGdhaW4gY3JpdGljYWwgaW5zaWdodHMgaW50byB0aGUgcG90ZW50aWFsIGNlbGwgb2Ygb3JpZ2luIGZvciBTw6l6YXJ5IHN5bmRyb21lIGFuZCB0aGUgZGVncmVlIHRvIHdoaWNoIG1hbGlnbmFudCBjZWxscyBkZXZpYXRlIGZyb20gbm9ybWFsIGRpZmZlcmVudGlhdGlvbiBwYXRod2F5cy4KCiMjIyBLZXkgSW5zaWdodHMgZnJvbSB0aGlzIEFuYWx5c2lzOgoKKiAgICoqTm9ybWFsIENENCsgVC1jZWxsIERpZmZlcmVudGlhdGlvbiBNYXA6KiogWW91IHdpbGwgaGF2ZSBhIHdlbGwtZGVmaW5lZCBwc2V1ZG90aW1lIHRyYWplY3RvcnkgZm9yIG5vcm1hbCBDRDQrIFQgY2VsbHMsIGFubm90YXRlZCB3aXRoIHNwZWNpZmljIGRpZmZlcmVudGlhdGlvbiBzdGFnZXMgKE5haXZlLCBDTSwgRU0sIGV0Yy4pLgoqICAgKipTw6l6YXJ5IENlbGwgUG9zaXRpb25pbmc6KiogVGhlIHByb2plY3Rpb24gb2YgU8OpemFyeSBjZWxscyBvbnRvIHRoaXMgbm9ybWFsIG1hcCB3aWxsIHJldmVhbCB0aGVpciB0cmFuc2NyaXB0aW9uYWwgYW5kIHBoZW5vdHlwaWMgcHJveGltaXR5IHRvIHNwZWNpZmljIG5vcm1hbCBDRDQrIFQtY2VsbCBzdWJzZXRzLiBUaGlzIGNhbiBkaXJlY3RseSBpbmZvcm0gaHlwb3RoZXNlcyBhYm91dCB0aGVpciBjZWxsIG9mIG9yaWdpbi4KKiAgICoqRGlmZmVyZW50aWF0aW9uIEFycmVzdC9EZXZpYXRpb246KiogQnkgb2JzZXJ2aW5nIHdoZXJlIFPDqXphcnkgY2VsbHMgY2x1c3RlciBvbiB0aGUgbm9ybWFsIHRyYWplY3RvcnksIHlvdSBjYW4gaWRlbnRpZnkgaWYgdGhleSByZXByZXNlbnQgYSBkaWZmZXJlbnRpYXRpb24gYXJyZXN0IGF0IGEgcGFydGljdWxhciBzdGFnZSBvciBpZiB0aGV5IGhhdmUgdW5kZXJnb25lIGEgc2lnbmlmaWNhbnQgZGV2aWF0aW9uIGZyb20gbm9ybWFsIGRldmVsb3BtZW50LgoqICAgKipHZW5lIEV4cHJlc3Npb24gU2lnbmF0dXJlczoqKiBBbmFseXNpcyBvZiBnZW5lIGV4cHJlc3Npb24gYWxvbmcgdGhlIHBzZXVkb3RpbWUgZm9yIGJvdGggbm9ybWFsIGFuZCBTw6l6YXJ5IGNlbGxzIGNhbiBoaWdobGlnaHQgZ2VuZXMgd2hvc2UgZXhwcmVzc2lvbiBpcyBkeXNyZWd1bGF0ZWQgaW4gU8OpemFyeSBzeW5kcm9tZSByZWxhdGl2ZSB0byB0aGVpciBub3JtYWwgY291bnRlcnBhcnRzIGF0IHNpbWlsYXIgZGlmZmVyZW50aWF0aW9uIHN0YWdlcy4KCiMjIyBOZXh0IFN0ZXBzIGFuZCBGdXJ0aGVyIENvbnNpZGVyYXRpb25zOgoKMS4gICoqUmVmaW5lIEFubm90YXRpb246KiogQ29udGludW91c2x5IHJlZmluZSB5b3VyIG5vcm1hbCBDRDQrIFQtY2VsbCBhbm5vdGF0aW9ucyBiYXNlZCBvbiBrbm93biBtYXJrZXJzIGFuZCBsaXRlcmF0dXJlLiBUaGUgbW9yZSBhY2N1cmF0ZSB5b3VyIG5vcm1hbCByZWZlcmVuY2UsIHRoZSBtb3JlIG1lYW5pbmdmdWwgeW91ciBwcm9qZWN0aW9ucyB3aWxsIGJlLgoyLiAgKipQYXRpZW50LVNwZWNpZmljIEFuYWx5c2lzOioqIFdoaWxlIHRoaXMgc2NyaXB0IGludGVncmF0ZXMgYWxsIFPDqXphcnkgY2VsbCBsaW5lcywgY29uc2lkZXIgcGVyZm9ybWluZyBwYXRpZW50LXNwZWNpZmljIHByb2plY3Rpb25zIHRvIGlkZW50aWZ5IGFueSBpbnRlci1wYXRpZW50IHZhcmlhYmlsaXR5IGluIHRoZSBjZWxsIG9mIG9yaWdpbiBvciBkaWZmZXJlbnRpYXRpb24gcGF0dGVybnMuCjMuICAqKlRDUiBDbG9uYWxpdHkgSW50ZWdyYXRpb246KiogT3ZlcmxheSBUQ1IgY2xvbm90eXBlIGluZm9ybWF0aW9uIG9udG8gdGhlIGNvbWJpbmVkIG5vcm1hbC1Tw6l6YXJ5IHRyYWplY3RvcnkuIFRoaXMgY2FuIGhlbHAgY29uZmlybSBpZiBjZWxscyBtYXBwaW5nIHRvIGEgc3BlY2lmaWMgbm9ybWFsIGRpZmZlcmVudGlhdGlvbiBzdGFnZSBhcmUgaW5kZWVkIHBhcnQgb2YgdGhlIGV4cGFuZGVkIG1hbGlnbmFudCBjbG9uZS4KNC4gICoqQ0lURS1zZXEgUHJvdGVpbiBJbnRlZ3JhdGlvbjoqKiBVdGlsaXplIHlvdXIgMjggc3VyZmFjZSBwcm90ZWluIG1hcmtlcnMgdG8gZnVydGhlciB2YWxpZGF0ZSBhbmQgcmVmaW5lIHRoZSBkaWZmZXJlbnRpYXRpb24gc3RhdGVzLiBQcm90ZWluIGV4cHJlc3Npb24gb2Z0ZW4gcHJvdmlkZXMgYSBtb3JlIGRpcmVjdCBwaGVub3R5cGljIHJlYWRvdXQgdGhhbiBSTkEuCjUuICAqKkZ1bmN0aW9uYWwgVmFsaWRhdGlvbjoqKiBDb21wdXRhdGlvbmFsIHByZWRpY3Rpb25zIG9mIGNlbGwgb2Ygb3JpZ2luIG9yIGRpZmZlcmVudGlhdGlvbiBhcnJlc3Qgc2hvdWxkIGlkZWFsbHkgYmUgZm9sbG93ZWQgYnkgZXhwZXJpbWVudGFsIHZhbGlkYXRpb24gKGUuZy4sIGluIHZpdHJvIGRpZmZlcmVudGlhdGlvbiBhc3NheXMsIGZ1bmN0aW9uYWwgc3R1ZGllcyBvZiBrZXkgZ2VuZXMpLgo2LiAgKipDb21wYXJpc29uIHdpdGggT3RoZXIgVHJhamVjdG9yeSBNZXRob2RzOioqIFdoaWxlIE1vbm9jbGUzIGlzIHVzZWQgaGVyZSwgY29uc2lkZXIgYXBwbHlpbmcgU2xpbmdzaG90IG9yIFBBR0EgKGFzIGRpc2N1c3NlZCBpbiB0aGUgcHJldmlvdXMgZG9jdW1lbnQpIHRvIHRoZSBub3JtYWwgQ0Q0KyBULWNlbGwgZGF0YXNldCB0byBzZWUgaWYgdGhleSB5aWVsZCBjb25zaXN0ZW50IHRyYWplY3Rvcmllcy4gUm9idXN0IGZpbmRpbmdzIGFjcm9zcyBtdWx0aXBsZSBtZXRob2RzIHN0cmVuZ3RoZW4geW91ciBjb25jbHVzaW9ucy4KNy4gICoqUHVibGljIERhdGEgSW50ZWdyYXRpb246KiogRXhwbG9yZSBhZGRpdGlvbmFsIHB1YmxpYyBzaW5nbGUtY2VsbCBSTkEtc2VxIGRhdGFzZXRzIG9mIG5vcm1hbCBUIGNlbGxzIChlLmcuLCBmcm9tIGRpZmZlcmVudCB0aXNzdWVzIG9yIGRldmVsb3BtZW50YWwgc3RhZ2VzKSB0byBicm9hZGVuIHlvdXIgcmVmZXJlbmNlIG1hcCBpZiBuZWNlc3NhcnkuCgpUaGlzIHNjcmlwdCBwcm92aWRlcyBhIHBvd2VyZnVsIGZvdW5kYXRpb24gZm9yIHlvdXIgaW52ZXN0aWdhdGlvbiBpbnRvIHRoZSBjZWxsIG9mIG9yaWdpbiBvZiBTw6l6YXJ5IHN5bmRyb21lLiBSZW1lbWJlciB0byBhZGFwdCB0aGUgcGF0aHMsIHRocmVzaG9sZHMsIGFuZCBzcGVjaWZpYyBjZWxsIHR5cGUgbWFwcGluZ3MgdG8geW91ciB1bmlxdWUgZGF0YXNldCBhbmQgYmlvbG9naWNhbCBxdWVzdGlvbnMuCgotLS0KCgo=