Data preprocessing and QC

Procedure

fMRI data was preprocessed in fMRIPrep (see description below for specifics). Used MRIQC (v0.14.2) individual and group reports to inspect image quality for anatomical and functional images. Link to tracking sheet.

More documentation and details on my fmriprep and MRIQC usage in the notebook Tutorial: BIDS, fMRIPrep, MRIQC

Excluded subjects

  • sub-142 [D142] was excluded from analysis due to excessive movement (max FD 11mm. at txA, consistent other movements up to 5-6mm at txA, 3.8mm at txB).
  • sub-147 [D142] was excluded due to FOV issue at txB (a fair amount of brain outside FOV). This wasn’t a problem for the task data that I’m aware of, so it was likely caused by him moving out of the FOV between sequences.

fMRIPrep

Boilerplate from fmriprep reports:

Results included in this manuscript come from preprocessing performed using fMRIPprep 1.1.8 (@fmriprep1; @fmriprep2; RRID:SCR_016216), which is based on Nipype 1.1.3 (@nipype1; @nipype2; RRID:SCR_002502).

Anatomical data preprocessing
A total of 2 T1-weighted (T1w) images were found within the input BIDS dataset. All of them were corrected for intensity non-uniformity (INU) using N4BiasFieldCorrection [@n4, ANTs 2.2.0]. A T1w-reference map was computed after registration of 2 T1w images (after INU-correction) using mri_robust_template [FreeSurfer 6.0.1, @fs_template]. The T1w-reference was then skull-stripped using antsBrainExtraction.sh (ANTs 2.2.0), using OASIS as target template. Brain surfaces were reconstructed using recon-all [FreeSurfer 6.0.1, RRID:SCR_001847, @fs_reconall], and the brain mask estimated previously was refined with a custom variation of the method to reconcile ANTs-derived and FreeSurfer-derived segmentations of the cortical gray-matter of Mindboggle [RRID:SCR_002438, @mindboggle]. Spatial normalization to the ICBM 152 Nonlinear Asymmetrical template version 2009c [@mni, RRID:SCR_008796] was performed through nonlinear registration with antsRegistration [ANTs 2.2.0, RRID:SCR_004757, @ants], using brain-extracted versions of both T1w volume and template. Brain tissue segmentation of cerebrospinal fluid (CSF), white-matter (WM) and gray-matter (GM) was performed on the brain-extracted T1w using fast [FSL 5.0.9, RRID:SCR_002823, @fsl_fast].

Functional data preprocessing
For each of the 2 BOLD runs found per subject (across all tasks and sessions), the following preprocessing was performed. First, a reference volume and its skull-stripped version were generated using a custom methodology of fMRIPrep. A deformation field to correct for susceptibility distortions was estimated based on fMRIPrep’s fieldmap-less approach. The deformation field is that resulting from co-registering the BOLD reference to the same-subject T1w-reference with its intensity inverted [@fieldmapless1; @fieldmapless2]. Registration is performed with antsRegistration (ANTs 2.2.0), and the process regularized by constraining deformation to be nonzero only along the phase-encoding direction, and modulated with an average fieldmap template [@fieldmapless3]. Based on the estimated susceptibility distortion, an unwarped BOLD reference was calculated for a more accurate co-registration with the anatomical reference. The BOLD reference was then co-registered to the T1w reference using bbregister (FreeSurfer) which implements boundary-based registration [@bbr]. Co-registration was configured with nine degrees of freedom to account for distortions remaining in the BOLD reference. Head-motion parameters with respect to the BOLD reference (transformation matrices, and six corresponding rotation and translation parameters) are estimated before any spatiotemporal filtering using mcflirt [FSL 5.0.9, @mcflirt]. BOLD runs were slice-time corrected using 3dTshift from AFNI [@afni, RRID:SCR_005927]. The BOLD time-series (including slice-timing correction when applied) were resampled onto their original, native space by applying a single, composite transform to correct for head-motion and susceptibility distortions. These resampled BOLD time-series will be referred to as preprocessed BOLD in original space, or just preprocessed BOLD. Automatic removal of motion artifacts using independent component analysis [ICA-AROMA, @aroma] was performed on the preprocessed BOLD on MNI space time-series after a spatial smoothing with an isotropic, Gaussian kernel of 6mm FWHM (full-width half-maximum). Corresponding “non-aggresively” denoised runs were produced after such smoothing. Additionally, the “aggressive” noise-regressors were collected and placed in the corresponding confounds file. The BOLD time-series were resampled to MNI152NLin2009cAsym standard space, generating a preprocessed BOLD run in MNI152NLin2009cAsym space. Several confounding time-series were calculated based on the preprocessed BOLD: framewise displacement (FD), DVARS and three region-wise global signals. FD and DVARS are calculated for each functional run, both using their implementations in Nipype [following the definitions by @power_fd_dvars]. The three global signals are extracted within the CSF, the WM, and the whole-brain masks. Additionally, a set of physiological regressors were extracted to allow for component-based noise correction [*CompCor*, @compcor]. Principal components are estimated after high-pass filtering the preprocessed BOLD time-series (using a discrete cosine filter with 128s cut-off) for the two CompCor variants: temporal (tCompCor) and anatomical (aCompCor). Six tCompCor components are then calculated from the top 5% variable voxels within a mask covering the subcortical regions. This subcortical mask is obtained by heavily eroding the brain mask, which ensures it does not include cortical GM regions. For aCompCor, six components are calculated within the intersection of the aforementioned mask and the union of CSF and WM masks calculated in T1w space, after their projection to the native space of each functional run (using the inverse BOLD-to-T1w transformation). The head-motion estimates calculated in the correction step were also placed within the corresponding confounds file. The BOLD time-series, were resampled to surfaces on the following spaces: fsaverage5. All resamplings can be performed with a single interpolation step by composing all the pertinent transformations (i.e. head-motion transform matrices, susceptibility distortion correction when available, and co-registrations to anatomical and template spaces). Gridded (volumetric) resamplings were performed using antsApplyTransforms (ANTs), configured with Lanczos interpolation to minimize the smoothing effects of other kernels [@lanczos]. Non-gridded (surface) resamplings were performed using mri_vol2surf (FreeSurfer).

Many internal operations of fMRIPrep use Nilearn 0.4.2 [@nilearn, RRID:SCR_001362], mostly within the functional processing workflow. For more details of the pipeline, see the section corresponding to workflows in fMRIPrep’s documentation.

MRIQC

Methods described on the readthedocs site. I ran the classifier on the T1w images and inspected the images flagged as likely problems (based on quality, i.e. classifier probability metric > .50):

    118_ses-txA
    122_ses-txB
    130_ses-txA
    130_ses-txB
    137_ses-txB
    142_ses-txA
    142_ses-txB
    148_ses-txA
    148_ses-txB

Apart from sub-142 (who I had already decided to drop), none of the anatomical images were poor enough quality in my eyes to drop given that I am only using them for registration purposes and the Freesurfer bbregister for BOLD-T1w registration seems to be pretty robust.

  • Note that for a few subjects (sub-142, sub-147), I had already used the T1w from one of their sessions as the anatomical image for both sessions because of breathing/coughing/movement artifacts (which means I swapped out the bad one for the okay one when I did the BIDS dataset conversion and DICOM import).

Pre-GIFT steps

Reorganize data

Within /data/derivatives/, make a new directory for the GIFT analyses and outputs:

$ cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/
$ mkdir -p gift/{analyses-spr-2019, data-smoothed, data-denoised}

data-denoised/ is for the non-aggressively denoised images from ICA AROMA. Note: Did not actually end up using the denoised images because the number of components they generated was way too high (>100) and my computer couldn’t handle it. I can fix this in future analyses by setting the number of ICs to estimate rather than asking GIFT to estimate it from the data.

data-smoothed/ is for the non-denoised images, which will be smoothed in a later step.

We will move all of the preprocessed functional images from fmriprep here because when we smooth them later, SPM will dump the smoothed images into the original folder and I don’t want those mixed in with the fmriprep derivatives directories.1

# this command finds files up to 4 subfolders down ending in the specified string/extension,
# then it copies those files to a new location while replicating the origin directory structure

$  cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/fmriprep
$  find . -type f -depth 4 -name "*smoothAROMAnonaggr_preproc.nii.gz" -print0 | cpio -pmd0 /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-denoised/
  
  $  cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/fmriprep
$  find . -type f -depth 4 -name "*task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii" -print0 | cpio -pmd0 /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/

GIFT requires files to be organized within individual subject folders, with different folders within the subject folder for each session if multiple (here, ses-txA and ses-txB). It will not find files in subdirectories within the session folder, so we need to move each .nii file up one level (i.e., to data-smoothed/sub-101/txA instead of data-smoothed/sub-101/txA/func). I just did this by drag & dropping, couldn’t figure out an efficient command line way to do it.

Move the excluded subjects to their own separate folder:

$  cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed # or /data-denoised
$  mv 'sub-142' 'sub-147' /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/excluded-subjects

Finally, if using the denoised images, unzip the .nii.gz files (N/A if using the non-denoised images) so that GIFT can work with them.

$ gunzip -r data-denoised/ *.nii.gz

This recursively looks for files ending in *.nii.gz within data-denoised/, and uses gunzip to extract them.

Smooth images

GIFT suggests that images are smoothed prior to running the gICA (however they also note, _“if your goal is to examine potential artifacts in your data, then you may not want to smooth, since the artifacts can be”hidden" by the smoothing process.“_) The fmriprep does not perform spatial smoothing so this needs to happen if using the non-denoised preprocessed images. The ICA-AROMA non-aggressively denoised images have already been smoothed with an isotropic 6mm FWHM Gaussian kernel.

For the non-denoised images, I chose to use a 4mm FWHM Gaussian kernel because we may be interested in smaller subcortical structures.

SPM smooth

Use the batch interface of SPM to apply only the spatial smoothing module to preprocessed images. Make a new folder batch within /gift/analyses-spr-2019 for all of the batch scripts we’ll be using (both SPM and GIFT).

For smoothing, you need to modify two scripts: spm_smooth_rest.m and spm_smooth_rest_job.m. Both are generated when you use the batch editor in the SPM12 GUI to set up smoothing on one participant, then select “save batch and script” to save the script from the batch editor GUI as a template that you can edit.

The way the SPM batch interface works, the _job file contains inputs and parameters, such as a list of files to apply the function to and other parameters. When you run spm_smooth_rest.m, it calls on spm_smooth_rest_job.m.

First, open Matlab (I’m using 2016b).

Then, get the filepaths for all of the images to be smoothed using the script below in Matlab.2

%% Make a variable called "inputs" 
%  containing paths to all files ending in '*task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii' 
%  (these images are the non-denoised outputs from fmriprep)

% This script recursively gets the names and paths of all the files ending in the specified extension
% then it puts those into a structure with cells "folder" and "name".
% We then get those cells out of the structure and combine the two using 'strcat' to get the complete filepath

cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed;
dirData = dir('**/*task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii');

folder = cell2table(transpose({dirData.folder}));
names = cell2table(transpose({dirData.name}));

names.Properties.VariableNames = {'filename'};
folder.Properties.VariableNames = {'path'};

files = strcat(folder.path,'/',names.filename);

Open the cell array files (should be 76x1 cell) by double-clicking on it, and copy the contents of the first column.

spm_smooth_rest_job.m

Open spm_smooth_rest_job.m and paste the contents of files into the place where SPM wants you to tell it which data to work on (matlabbatch{1}.spm.spatial.smooth.data = {''}).

Also change the FWHM to “[4 4 4]” and the prefix to “4mmSmoothed_”3:

matlabbatch{1}.spm.spatial.smooth.data = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/sub-101/ses-txA/sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii';
    '/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/sub-101/ses-txB/sub-101_ses-txB_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii'}; % all files you want to smooth should be listed in this field, separated by ;
matlabbatch{1}.spm.spatial.smooth.fwhm = [4 4 4];
matlabbatch{1}.spm.spatial.smooth.dtype = 0;
matlabbatch{1}.spm.spatial.smooth.im = 0;
matlabbatch{1}.spm.spatial.smooth.prefix = '4mmSmoothed_';
spm_smooth_rest.m

You shouldn’t need to edit anything here apart from changing nrun = X; to nrun = 1;.

% List of open inputs
nrun = 1;
jobfile = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/spm_smooth_rest_job.m'};
jobs = repmat(jobfile, 1, nrun);
inputs = cell(0, nrun);
for crun = 1:nrun
end
spm('defaults', 'FMRI');
spm_jobman('run', jobs, inputs{:});

Finally, type run('/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/spm_smooth_rest.m') in the Matlab command window, hit enter, and wait for it to complete smoothing for all of the files. This will take a while (about a minute or two per subject on my Mac) so be patient.

AFNI 3dresample

For the non-denoised images, GIFT fails when it tries to create a group mask before running the PCA4 due to the fact that some of the images have slightly different dimensions (ugh), I’m guessing due to slight protocol changes around the time when the scanner was updated. This doesn’t seem to be an issue for the ICA-AROMA denoised images for some reason.

Used AFNI’s 3dinfo and 3dresample tools, as well as the error/warnings log from the BIDS validator (which gave some warnings about some subjects/sessions having different dimensions) to identify affected sessions and to standardize dataset dimensions.s

Note that, apparently, small differences in dimensions (e.g., 1 or 2 voxels) aren’t a problem, as this only seems to affect the subjects/sessions with the following warning:

    Type:       Warning
  File:     sub-119_ses-txA_task-rest_bold.nii
    Location:       data/sub-119/ses-txA/func/sub-119_ses-txA_task-rest_bold.nii
    Reason:      The most common set of dimensions is: 92,80,29,180 (voxels), This file has the dimensions: 88,84,29,180 (voxels). The most common resolution is: 2.61mm x 2.61mm x 4.38mm x 2.00s, This file has the resolution: 2.50mm x 2.50mm x 4.38mm x 2.00s.

How did I figure this out? I tried running GIFT on a bunch of different subsets of the data (e.g., first third of subjects, last third) to try to narrow down which ones were causing it to crash. Then once I had an idea of around where they were in the dataset, I looked in the BIDS validator log, guessed that I could start with the people with the larger differences, moved their subject folders out of derivatives/gift/data-smoothed/, and tried to run GIFT again. It ran, which confirmed my hypothesis.

First, install AFNI: https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/background_install/install_instructs/steps_mac.html Don’t need to install netpbm or R (already have R, don’t need netpbm) but did need to open XQuartz and > “Check for Updates” > install any updates.

To run AFNI from Terminal, type: source ~/.bashrc afni (see discussion of error message & solution here: https://afni.nimh.nih.gov/afni/community/board/read.php?1,158888,158908#msg-158908)

Within /data/derivatives/, make a new directory for the AFNI outputs:

$ cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/
$ mkdir -p afni/{data-3dresample}

# if you need to copy ALL of the subjects' files over (this preserves directory structure):
# $ cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/
# $  find . -type f -depth 4 -name "4mmSmoothed.nii*" -print0 | cpio -pmd0  /Users/sarenseeley/Desktop/restingstate/data/derivatives/afni/data-3dresample/

# to copy to flat folder (only do this if you need to copy ALL of the subjects' files over)
# cp `find . -name "4mm*"` /Users/sarenseeley/Desktop/restingstate/data/derivatives/afni/data-3dresample   

Move the 4mmSmoothed* files from sub-101/ses-txA, sub-117/ses-txA, sub-119/ses-txA, sub-121/ses-txA and sub-122/ses-txB into derivatives/afni/data-3dresample. AFNI should be able to cope with subdirectories (I think?) but I haven’t figured that out yet. So, dump everything into the same data folder.

Note: In AFNI, a “dataset” means the file itself (e.g., 4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii), not a folder containing subdirectories.

3dinfo

Documentation: https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dinfo.html

Running 3dinfo will show information about the “dataset”, including dimensions:

$ 3dinfo 4mmSmoothed_sub-117_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc_3dresampled.nii

Example output:

++ 3dinfo: AFNI version=AFNI_19.0.24 (Mar  8 2019) [64-bit]
Dataset File:    4mmSmoothed_sub-117_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc_3dresampled.nii
Identifier Code: XYZ_qc1srKfckc7Z7t_aWfiPVQ  Creation Date: Sat Mar 16 16:28:37 2019
Template Space:  TLRC
Dataset Type:    Echo Planar (-epan)
Byte Order:      LSB_FIRST {assumed} [this CPU native = LSB_FIRST]
Storage Mode:    NIFTI
Storage Space:   216,270,000 (216 million) bytes
Geometry String: "MATRIX(-2.609,0,0,96,0,-2.609,0,132,0,0,4.375,-78):75,89,45"
Data Axes Tilt:  Plumb
Data Axes Orientation:
  first  (x) = Left-to-Right
  second (y) = Posterior-to-Anterior
  third  (z) = Inferior-to-Superior   [-orient LPI]
R-to-L extent:   -97.066 [R] -to-    96.000 [L] -step-     2.609 mm [ 75 voxels]
A-to-P extent:   -97.592 [A] -to-   132.000 [P] -step-     2.609 mm [ 89 voxels]
I-to-S extent:   -78.000 [I] -to-   114.500 [S] -step-     4.375 mm [ 45 voxels]
Number of time steps = 180  Time step = 1.00000s  Origin = 0.00000s
  -- At sub-brick #0 '?' datum type is float:     -4.60834 to       573.885
  -- At sub-brick #1 '?' datum type is float:     -4.66345 to       662.353
  -- At sub-brick #2 '?' datum type is float:     -4.29606 to       568.889
** For info on all 180 sub-bricks, use '3dinfo -verb' **`
3dresample

Documentation: https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dresample.html

3dresample -master allows you to change the dimensions of a specified “dataset” (aka NIFTI file) to match another “dataset” (aka NIFTI file). So this is what we want to do to fix the issue with some subjects/sessions having slightly different dimensions that causes GIFT to crash.

General usage: 3dresample -master [dataset you want to use as template, ending in .nii for NIFTI files] -prefix [what you want the new dataset to be named, ending in .nii for NIFTI files] -input [dataset to be resampled, ending in .nii for NIFTI files]

Run the below lines:

$ 3dresample -master 4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii -prefix 4mmSmoothed_sub-117_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc_3dresampled.nii  -input 4mmSmoothed_sub-117_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii
$ 3dresample -master 4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii -prefix 4mmSmoothed_sub-119_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc_3dresampled.nii  -input 4mmSmoothed_sub-119_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii
$ 3dresample -master 4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii -prefix 4mmSmoothed_sub-121_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc_3dresampled.nii  -input 4mmSmoothed_sub-121_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii
$ 3dresample -master 4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii -prefix 4mmSmoothed_sub-122_ses-txB_task-rest_bold_space-MNI152NLin2009cAsym_preproc_3dresampled.nii  -input 4mmSmoothed_sub-122_ses-txB_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii

Then move the new files (*_3rdresampled.nii) to their respective folders. Because GIFT is going to look for files starting with *4mmSmooth, delete the original smoothed files so the session folder only has two files: (1) the non-smoothed preprocessed file and (2) the new 3dresampled file. Note: I ended up removing the _3rdresampled suffix once those files were in their folders within derivatives/gift/ because it was making it more complicated to edit some batch scripts.

Now you are ready to run GIFT! (The PCA part, anyway…)

random AFNI bits

AFNI’s GUI is amazingly confusing.

Look for datasets recursively:

$ cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/afni
$ afni -R data-3dresample

Regressors (single-subject)

Don’t technically need the single-subject design matrix for resting state data as GIFT does not use the design matrix when running the PCA/ICA. However, you could use the design matrix to provide temporal regressors which can be used for temporal sorting of components (on the single-subject level) in order to identify components that are particularly correlated with motion parameters or CSF/white matter signal fluctuations.

If you have task data, you DO need a design matrix for temporal sorting in order to identify task-related components.

Create regressors files

Based on https://neurostars.org/t/confounds-from-fmriprep-which-one-would-you-use-for-glm/326/4, I want to set up the design matrix to include the the motion parameters X, Y, Z, RotX, RotY, and RotZ as well as GlobalSignal, CSF and WhiteMatter. These columns are located in the sub-*_ses-tx*_task-rest_bold_confounds.tsv files that fmriprep generates (one per subject/session, within /func).

Note: It is not necessary to use the “NonSteadyStateOutliers” column because I set the GIFT batch script to exclude the first 3 volumes (based on MRIQC group report, this is the max number of dummy volumes for any subject).

Each subject and session needs a .txt or .mat file containing the regressors.

The confounds.tsv files list one row per volume. 180 volumes = 180 rows. So we need to specify for SPM that these are in scans (aka volumes) rather than seconds.

First, we need to use R convert the TSV files to CSV (easier to work with), create new files with only the columns we want to include as multiple regressors for the SPM design matrix, and save those new files as .txt files to /derivatives/gift/analyses-spr-2019/batch/regressors/.

library(tidyverse)
filter <- dplyr::filter
select <- dplyr::select

# get a list of all of the confounds.tsv files
filenames <- list.files(path = "~/Desktop/restingstate/data/derivatives/fmriprep", pattern = "confounds.tsv", full.names = TRUE, recursive = TRUE)
dir <- "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/regressors"

# convert tsv to csv files
lapply(filenames, function(f) {
  df = read_tsv(f)
  write.csv(df, gsub("tsv", "csv", f), row.names=FALSE)
})

# get a list of the confounds.csv files
filenames.csv <- list.files(path = "~/Desktop/restingstate/data/derivatives/fmriprep", pattern = "confounds.csv", full.names = TRUE, recursive = TRUE)
# this means we now have both TSV and CSV versions of the confounds files, so can delete TSVs

# here's what I modified from something I found online...
# first, create an object with the directory name
the_dir <- "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/regressors"

check_create_dir <- function(the_dir) {
  if (!dir.exists(the_dir)) {
  dir.create(the_dir, recursive = TRUE) }
} # a function to check if the directory exists

# check to see if the directory exists (make it if it doesn't)
check_create_dir(the_dir)

# read in files (selected columns only) and write new files
for (file in filenames.csv) {
  # read in the csv
  the_data <- read_csv(file, col_names = TRUE, col_types=cols_only(
  GlobalSignal  = col_number(),
  CSF   = col_number(),
  WhiteMatter   = col_number(),
  X = col_number(),
  Y = col_number(),
  Z = col_number(),
  RotX  = col_number(),
  RotY  = col_number(),
  RotZ  = col_number())) 
  # remove first 3 rows since we are dropping the first 3 TRs and starting with the 4th volume
  the_data <- the_data[-c(1:3), ]
  # write the csv to a new file
  write_csv(the_data, file.path(paste0(the_dir, "/", basename(file))), col_names = FALSE) 
  # col_names must be false, SPM doesn't want headers in the txt files
  # but this means you need to make sure you double-check the order of the regressors if/when labeling them later
}

# rename the files with the suffix "_regressors.txt" vs. "_confounds.csv.txt":
filenames.txt <- list.files(path = "~/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/regressors", pattern = "confounds.csv", full.names = TRUE, recursive = TRUE)
  sapply(filenames.txt,FUN=function(file){
      file.rename(from=file,to=sub(pattern="confounds.csv",replacement="regressors.txt",file))
})

All of the new _regressors.txt files we just generated are located in Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/regressors

SPM design matrices

One design matrix (SPM.mat) per subject, per session. Scripts are located in /data/derivatives/gift/analyses-spr-19/batch/multi_regressor_jobs

spm_1stleveldesign_rest_job_[subj#]tx[A/B]_job.m

This file will look like the following, except here only the first (MNI152NLin2009cAsym_preproc.nii,4) and last (MNI152NLin2009cAsym_preproc.nii,180) file are shown below.

Note: For 4D NIFTI files, SPM requires specifying each 3D file individually using the comma and number following the nii suffix, e.g., *preproc.nii,4 refers to the fourth volume. If you are using the file selector GUI, it only shows you the single un-numbered file by default. In order to select all of the relevant volumes, specify 4:180 in the filter field.

%-----------------------------------------------------------------------
% Job saved on 22-Mar-2019 12:32:49 by cfg_util (rev $Rev: 6460 $)
% spm SPM - SPM12 (6685)
% cfg_basicio BasicIO - Unknown
%-----------------------------------------------------------------------
matlabbatch{1}.spm.stats.fmri_spec.dir = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/sub-101/ses-txA'};
matlabbatch{1}.spm.stats.fmri_spec.timing.units = 'scans';
matlabbatch{1}.spm.stats.fmri_spec.timing.RT = 2;
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t = 16;
matlabbatch{1}.spm.stats.fmri_spec.timing.fmri_t0 = 8;
%%
matlabbatch{1}.spm.stats.fmri_spec.sess.scans = {
                                                 '/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/sub-101/ses-txA/4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii,4'
                                                 '/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/sub-101/ses-txA/4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_preproc.nii,180'
                                                 };
%%
matlabbatch{1}.spm.stats.fmri_spec.sess.cond = struct('name', {}, 'onset', {}, 'duration', {}, 'tmod', {}, 'pmod', {}, 'orth', {});
matlabbatch{1}.spm.stats.fmri_spec.sess.multi = {''};
matlabbatch{1}.spm.stats.fmri_spec.sess.regress = struct('name', {}, 'val', {});
matlabbatch{1}.spm.stats.fmri_spec.sess.multi_reg = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/regressors/sub-101_ses-txA_task-rest_bold_regressors.txt'};
matlabbatch{1}.spm.stats.fmri_spec.sess.hpf = 128;
matlabbatch{1}.spm.stats.fmri_spec.fact = struct('name', {}, 'levels', {});
matlabbatch{1}.spm.stats.fmri_spec.bases.hrf.derivs = [1 1];
matlabbatch{1}.spm.stats.fmri_spec.volt = 1;
matlabbatch{1}.spm.stats.fmri_spec.global = 'None';
matlabbatch{1}.spm.stats.fmri_spec.mthresh = 0.8;
matlabbatch{1}.spm.stats.fmri_spec.mask = {''};
matlabbatch{1}.spm.stats.fmri_spec.cvi = 'AR(1)';
spm_1stleveldesign_rest_job_all_job.m

I combined all of the individual spm_1stleveldesign_rest_job_[subj#]tx[A/B]_job.m scripts into one single SPM job in order to avoid running individual scripts if I don’t need to.

spm_1stleveldesign_rest_job_all.m
% List of open inputs
nrun = 1; % enter the number of runs here
jobfile = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/multi_regressor_jobs/spm_1stleveldesign_rest_job_all_job.m'};
jobs = repmat(jobfile, 1, nrun);
inputs = cell(0, nrun);
for crun = 1:nrun
end
spm('defaults', 'FMRI');
spm_jobman('run', jobs, inputs{:});

Usage: run('/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/multi_regressor_jobs/spm_1stleveldesign_rest_job_all.m')

This generates individual design matrix SPM.mat files and puts them into their appropriate subject/session folders.

Regressors (group-level)

A design matrix with group-level regressors/covariates is used for post-ICA analyses in SPM. Note: this design matrix is created later, after the gICA is completed.

Create group-level file

Data (one value per subject/session for each variable) come from two places: the group BOLD report generated by MRIQC, and the master dataset. For the SPR poster analysis, I created a new dataset containing mean framewise displacement and two subsets of other variables from the master dataset - one containing the measure total scores, and the other containing demographic and health-related variables.

# read in master dataset
data <- readRDS("~/Dropbox/GLASS Lab/OT Study/data/master-dataset/ot-fmri_master-dataset_020719.rds")

# read in MRQC group stats to get mean FD 
mriqc <- read_tsv("~/Desktop/restingstate/data/derivatives/mriqc/group_bold.tsv", col_names = TRUE, col_types=cols_only(
  bids_name = col_character(),
  fd_mean   = col_number()))

# split up mriqc by session
mriqc_A <- dplyr::filter(mriqc, grepl("ses-txA",bids_name))
mriqc_B <- dplyr::filter(mriqc, grepl("ses-txB",bids_name))

# then rename for merging with master dataset variables
mriqc_A <- rename(mriqc_A, ID = bids_name, 
       fd_mean_txA = fd_mean)

mriqc_B <- rename(mriqc_B, ID = bids_name, 
       fd_mean_txB = fd_mean)

mriqc_A <- mutate_if(tibble::as_tibble(mriqc_A), 
                                is.character, 
                                stringr::str_replace_all, pattern = "sub-", replacement = "D")
mriqc_A <- mutate_if(tibble::as_tibble(mriqc_A), 
                                is.character, 
                                stringr::str_replace_all, pattern = "_ses-txA_task-rest_bold", replacement = "")

mriqc_B <- mutate_if(tibble::as_tibble(mriqc_B), 
                                is.character, 
                                stringr::str_replace_all, pattern = "sub-", replacement = "D")
mriqc_B <- mutate_if(tibble::as_tibble(mriqc_B), 
                                is.character, 
                                stringr::str_replace_all, pattern = "_ses-txB_task-rest_bold", replacement = "")

mean_fd <- left_join(mriqc_A, mriqc_B, by="ID")

# add the fd_mean variables to a subset of variables from the master dataset

# make a subset of measure total scores
tots <- data[, grep('^tot|ID', names(data))]

# get a list of variable names to pick out the ones I want
names <- names(data)
cat(names, sep="\n")

# make a subset of other variables in master dataset
group <- subset(data, select=c(ID,
                               sex_m,
                               age,
                               age_yrs,
                               knowbefore_y,
                               caretaker_y,
                               education,
                               highestdegree,
                               education_other,
                               employment,
                               householdsize,
                               householdsize_adult,
                               householdsize_income,
                               ethnicity_hisp,
                               race,
                               race_other,
                               learnaboutstudy,
                               meds_y,
                               meds_rxonly,
                               meds_psychoactive,
                               meds_hrt,
                               meds_hormone_opiate,
                               meds_total,
                               majorhealthprobs_y,
                               majorhealthprobs_what,
                               postmenopausal_y,
                               n_pregnancies,
                               n_livebirths,
                               n_nursed,
                               alcohol,
                               smoking_y,
                               smoking_howlong,
                               smoking_perday,
                               caffeine_perday,
                               exercise,
                               timesincedeath,
                               yrs_together,
                               group,
                               group_20mFU,
                               timetorest_A,
                               timetorest_B,
                               timeto20mFU,
                               timeto20mFU_mos,
                               post_sroe_1_A,
                               post_sroe_2_A,
                               post_sroe_3_A,
                               post_sroe_1_B,
                               post_sroe_2_B,
                               post_sroe_3_B,
                               rs2254298,
                               rs2268498,
                               rs53576,
                               rs2254298_A.carrier,
                               rs2268498_C.carrier,
                               rs53576_A.carrier))

# merge all the group data
rest_data <- left_join(group, tots, by="ID") %>% left_join(., mean_fd)

# replace "D" prefix in ID to "sub-" to be BIDS-compliant
rest_data <- rest_data %>% 
  mutate(ID = str_replace(ID, "D", "sub-"))

# save as a .rds file and a csv file
write_csv(rest_data, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/group_covariates.csv")
saveRDS(rest_data, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/group_covariates.rds")

# and save a version without sub-142, sub-147 (excluded from GIFT analyses)
# this is what I will use to set up the model specification in SPM
rest_data_no_subs142147 <- filter(rest_data, !grepl("sub-142|sub-147",ID)) 
write_csv(rest_data, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/group_covariates_no-142-147.csv")

I was also saving some of these individually for use with MANCOVAN…

# save the variables of interest individually for use in MANCOVAN toolbox 
age <- as_tibble(rest_data_no_subs142147$age_yrs)
write_csv(age, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/age.txt", col_names = FALSE)

sex <- as_tibble(rest_data_no_subs142147$sex_m)
write_csv(sex, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/sex.txt", col_names = FALSE)

group <- as_tibble(rest_data_no_subs142147$group)
write_csv(group, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/group.txt", col_names = FALSE)

bdi <- as_tibble(rest_data_no_subs142147$tot_bdi)
write_csv(bdi, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/bdi.txt", col_names = FALSE)

ysl <- as_tibble(rest_data_no_subs142147$tot_ysl)
write_csv(ysl, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/ysl.txt", col_names = FALSE)

icg <- as_tibble(rest_data_no_subs142147$tot_icg)
write_csv(icg, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/icg.txt", col_names = FALSE)

meds_totaln <- as_tibble(rest_data_no_subs142147$meds_total)
write_csv(meds_totaln, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/meds_totaln.txt", col_names = FALSE)

timesincedeath <- as_tibble(rest_data_no_subs142147$timesincedeath)
write_csv(timesincedeath, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/timesincedeath.txt", col_names = FALSE)

timetorest_A <- as_tibble(rest_data_no_subs142147$timetorest_A)
write_csv(timetorest_A, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/timetorest_txA.txt", col_names = FALSE)

timetorest_B <- as_tibble(rest_data_no_subs142147$timetorest_B)
write_csv(timetorest_B, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/timetorest_txB.txt", col_names = FALSE)

meanFD_txA <- as_tibble(rest_data_no_subs142147$fd_mean_txA)
write_csv(meanFD_txA, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/meanFD_txA.txt", col_names = FALSE)

meanFD_txB <- as_tibble(rest_data_no_subs142147$fd_mean_txB)
write_csv(meanFD_txB, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/group-covariates/meanFD_txB.txt", col_names = FALSE)

From these group data, can also do things like comparing how much people moved on average by group:

Mean FD is not significantly different between treatments or groups, and is not correlated with total ICG score, BDI score, or pre-scan STAI (state anxiety). It is also not significantly associated with age.

IMPORTANT

Will be noted again below, but make sure that when you’re importing and using the group covariates file to set up a design matrix, the subject order matches the order in which the files are listed in the SPM design, as well as matching any renumbering of subjects that GIFT has done (e.g., what GIFT says is subject 38 is the 38th file – NOT sub-038).

For each design matrix, you will likely need a different group covariates file with the rows ordered the way that the files are ordered in SPM (e.g., if you are entering subjects for whom group=0 as your first group, and for whom group=1 as your second group, all of the files for subjects in the first group will be listed first in the design matrix).

(Don’t need to do anything about this now, but just be really aware of it when you get to the point of running group SPM stats with these covariates later).

GIFT (Group ICA of fMRI Toolbox)

“It is a MATLAB toolbox which implements multiple algorithms for independent component analysis and blind source separation of group (and single subject) functional magnetic resonance imaging data.” Download and documentation available here: http://mialab.mrn.org/software/gift/index.html

For the poster analyses, I looked at treatment A alone.

Note: txA is referred to as “session 1” in GIFT (it labels sessions and subjects based on alphanumerical order of file/folder names).

Note:If you want to compare two sessions (or two groups), you should run them in a single ICA so that the component numbers match.

Data reduction

Run PCA & ICA #1

Use batch file Input_data_subjects_restingstate_txA.m to input data and initiate the analysis. Parameters used for the PCA and ICA data reduction steps are described in /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__ica_parameter_info.mat.

Wait [hours] for it to finish.

Open GIFT by entering gift in the Matlab command line. Click the “Display GUI” button to look at the identified ICs in different ways (group, single-subject, means, timecourses, only specific ICs, etc.) You can edit display defaults, such as Z threshold to use for display, using the menu in the upper left corner of the window.

Write a summary of results to HTML by clicking the “Results Summary” button. View the HTML report, which shows ICASSO stability estimate plots as well as component spatial maps, timecourses, and spectra.

Identify noise ICs

Based on spatial distribution, power spectra (including fALFF) and ICASSO stability estimates.

Allen et al., 2011:

2.5.1 RSN selection We identified a subset of C1 components considered to be RSNs (as opposed to physiological artifacts) by inspecting the aggregate SMs and average power spectra (see below; Figure 1, step 3).Four viewers rated the components from 0 (definite artifact) to 1 (certain RSN) based on expectations that RSNs should exhibit peak activations in gray matter, low spatial overlap with known vascular, ventricular, motion, and susceptibility artifacts, and TCs dominated by low frequency fluctuations (Cordes et al., 2000). To facilitate evaluation, spectra were characterized with two metrics used previously to classify components (Robinson et al., 2009): dynamic range, the difference between the peak power and minimum power at frequencies to the right of the peak, and low frequency to high frequency power ratio, the ratio of the integral of spectral power below 0.10 Hz to the integral of power between 0.15 and 0.25 Hz (Figure 3).

FYI:

ALFF is defined as the total power within the frequency range between 0.01 and 0.1 Hz, and thus indexes the strength or intensity of LFO. f/ALFF is defined as the power within the low-frequency range (0.01-0.1 Hz) divided by the total power in the entire detectable frequency range, and represents the relative contribution of specific LFO to the whole frequency range (Zuo et al., 2010).

You can also use the “Component Labeller” tool in GIFT to see how closely your ICs resemble established functional RSNs using the Stanford templates. From the GIFT manual:

3.12.8 Component Labeler Option is provided to label components given the templates of interest. We provide templates in icatb/icatb_templates/RSN.zip file and description about the templates in icatb/icatb_templates/RSN.txt. Each component is correlated with the given templates and best template is selected based on the maximum correlation value.

Good ICs should have higher correlation values. Note that the labeller tries to correlate all of the voxels across the brain so the correlation values will likely be moderate, not very high.

Remove noise ICs

I removed the following ICs:

  • Eyeballs: 23, 38, 40, 41, 44
  • Motion: 3, 5, 10, 35
  • CSF: 8, 26, 34 (my notes are unclear here - may have removed 2 and 22 as well)
  • Other: 1, 4, 12, 17, 21, 27

If I wasn’t sure, I erred on the side of caution and left it in. Hence leaving in some that I couldn’t tell if they were physiological artifact or legit subcortical stuff.

After selecting the components to remove, GIFT will rewrite the data. At this point, GIFT creates generic subject and session numbers based on how many of each there are and the order in which it encounters the files (so for these data, subjects are labelled Sub_001 through Sub_038, and the session folder that was txA is now called 1). I created a file that links the original subject IDs and GIFT rewritten data IDs (key_link-giftIDs-studyIDs.csv) located within /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_data. This will be important later.

New data were written to /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_data.

Run ICA #2

GIFT was run a second time on the noise-components-removed data. Results and outputs of this analysis are located within /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_results.

Parameters used for the PCA and ICA data reduction steps are described in /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_results/gift_txA_noisecompsremoved__ica_parameter_info.mat. This time, I asked it to use 30 as the number of ICs vs. estimating from the data.

Pick ICs

Based on the same criteria as used to determine noise components (stability, separation, and other ICASSO metrics, spatial distribution, power, fALFF), I selected six ICs to focus on.

I did notice that the fALFF scores overall were lower than those described in the Allen et al. (2011) paper, and decreased from those seen in the first run of the ICA. All of the below components had good stability and separation.

  • IC1: Labelled as precuneus network, majority seems to be in cuneus, r = .31 with the RNS template precuneus network, fALFF = 3.4.
  • IC5: Labelled as DMN/mPFC/PCC, r = .26, fALFF = 2.89.
  • IC9: Labelled as R CEN/dlPFC, r = .27, fALFF = 2.17.
  • IC12: Labelled as DMN/MTL, r = .39, fALFF = 2.81.
  • IC20: Labelled as DMN/mPFC/PCC, r = .40, fALFF = 1.25.

I also looked at IC2, which was labelled as SN/aI/dACC but wasn’t too convinced it was that so dropped it (potential MR artifact?). Neurosynth decoder says the t map is most similar to primary motor cortex and a lot of somatosensory and movement-related terms. For future analyses, since there was no SN IC that was identified, may want to do a semi-blind ICA using the SN template for spatial constraint.

There were a number of other components that seemed decent and correlated with sensorimotor, language, auditory, visual, and visuospatial networks.

The fact that GIFT identified multiple ICs related to a single given network (e.g., DMN, visual) suggests that I probably could have gone down to 20 so that there wasn’t as much splitting of networks. OTOH, it’s interesting to see how the different DMN components relate to different mental functions (per comparison to Neurosynth meta-analytic maps) given that there is evidence for parcellation of these large-scale networks.

SPM stats

You can do this either via the “SPM Stats” button in GIFT or just fire up SPM. The first step is to run a one-sample T test which tests the effect against null. This creates a thresholded mask that can be used to mask subsequent analyses to constrain tests to just those voxels where a particular component showed supra-threshold signal. Note: you may or may not want to use the mask in later analyses. It depends: if you want to look just for intranetwork effects, then use it. If you are interested in areas outside the IC/network, then don’t.

The next step was a two-sample t test on the individual images for each component with mean framewise displacement, age, sex, time since death, psychoactive medications (coded 0/1), and BDI score included as covariates. The t test compared CG and NCG. Note that voxelwise tests are testing for group differences in the spatial maps.

Results

At my exploratory p < .001 level there were a number of tiny clusters that showed up in one or both contrasts. Not too interesting. However, the CG > NCG contrast for IC1 did reveal a small cluster in the left dorsal precentral gyrus (-23 -20 75, k = 17) that was significantly more correlated with the IC1 timecourse (I think? not 100% clear on interpretation) in the CG group than the NCG group, T = 6.83, Z = 5.26, voxelwise p uncorrected = < .001, pFDR = .028, pFWE = .004 (.027 for clusterwise).

CG > NCG: precentral gyrus

The precentral gyrus is involved in movement and motor imagery, but may also play a role in person-specific patterns of brain activity (Thornton & Mitchell, 2017; coordinates not listed) and reward outcome in addiction (fMRI meta analysis: Luijten et al., 2017 JAMA; coordinates extremely close to ours for the addicted > control contrast, see their table e5).

marsbar (ROI analysis)

To look further at the precentral gyrus, I used marsbar to create a functional ROI (a mask of the cluster) and extract parameter estimates per subject. Then read these data into R to conduct subsequent analyses.

install.packages("R.matlab")
library(R.matlab)
library(tidyverse)
library(ggpubr)
library(psych)

# read mat file with beta weights from CG > NCG contrast in the precentral gyrus cluster from IC1
roidata <- readMat("/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_results/gift_txA_noisecompsremoved__marsbar_roi_results/cg_ncg_-23_-20_75_comp01_betas.mat", 1)

betas <- as.tibble(roidata[[1]][[2]][[1]]) %>% rename(roi_betas_CGvNCG_comp01_precentralgyrus = V1)
beta_sub <- as.tibble(roidata[[1]][[1]][[1]]) %>% rename(fname = V1)

betas <-bind_cols(beta_sub, betas) %>% mutate(fname = str_replace(fname, "/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_results/gift_txA_noisecompsremoved__scaling_components_files/sub-", "file")) %>% mutate(fname = str_replace(fname, "_component_ica_ses-1_.nii", ""))

key <- read_csv("/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/results_no-sub-142_drop-3-vols_regressors_intnorm_txA/gift_txA__noise-comps-removed_results/key_link-giftIDs-studyIDs.csv")

betas <- left_join(betas, key, by="fname")

# now ready to merge betas with data
data <- readRDS("~/Dropbox/GLASS Lab/OT Study/data/master-dataset/ot-fmri_master-dataset_020719.rds")

data_spr19 <- left_join(data, betas, by="ID")

Correlations:

# first used YSL item 10 as the sort of prototypic index of yearning..
corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$ysl_10) # "Feeling of wanting back is so strong it is indescribable..."

# then looked at YSL total
corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$tot_ysl) # not significantly correlated

At MFO’s suggestion, looked separately at affective and cognitive aspects of yearning:

# subset YSL into cognitive and affective subscales and calculate totals
ysl_cog <- subset(data_spr19, select=c("ysl_2","ysl_4", "ysl_8", "ysl_11", "ysl_14"))
data_spr19$tot_ysl_cog <- rowSums(ysl_cog, na.rm=TRUE) 
describe(data_spr19$tot_ysl_cog)

ysl_aff <- subset(data_spr19, select=c("ysl_6","ysl_7", "ysl_10", "ysl_16", "ysl_21"))
data_spr19$tot_ysl_aff <- rowSums(ysl_aff, na.rm=TRUE) 
describe(data_spr19$tot_ysl_aff)

# is the relationship with precentral gyrus specific to affective items, or not?
corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$tot_ysl_cog) # r = .31, p = .06
corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$tot_ysl_aff) # r = .40, p = .01

Are these correlations significantly different from each other?

For the below results:
  • Null hypothesis is that the true difference in overlapping correlations IS equal to 0.
  • Alternative hypothesis is that the true difference in correlations IS NOT equal to 0.
  • Conclusions based on Steiger’s (1980) z and Zou’s (2007) confidence interval.

    library(cocor)
    # correlation of postcentral gyrus betas (j) and YSL-cog (k):
    jk <- corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$tot_ysl_cog) # r = .31, p = .058
    # correlation of postcentral gyrus betas (j) and YSL-aff (h):
    jh <- corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$tot_ysl_aff) # r = .40, p = .012
    # correlation of YSL-cog (k) and YSL-aff (h), dropping D142 & D147:
    data_spr19 <- filter(data_spr19, !grepl("D142|D147",ID))
                                        
    kh <- corr.test(data_spr19$tot_ysl_cog, data_spr19$tot_ysl_aff) # r = .89, p < .001
    cocor.dep.groups.overlap(r.jk=+(jk[[1]]), r.jh=+(jh[[1]]), r.kh=+(kh[[1]]), n=38, alternative="two.sided", alpha=0.05, conf.level=0.95, null.value=0)
    
      Results of a comparison of two overlapping correlations based on dependent groups
    
    Comparison between r.jk = 0.31 and r.jh = 0.4023
    Difference: r.jk - r.jh = -0.0923
    Related correlation: r.kh = 0.8939
    Group size: n = 38
    Null hypothesis: r.jk is equal to r.jh
    Alternative hypothesis: r.jk is not equal to r.jh (two-sided)
    Alpha: 0.05
    
    pearson1898: Pearson and Filon's z (1898)
      z = -1.3201, p-value = 0.1868
      Null hypothesis retained
    
    hotelling1940: Hotelling's t (1940)
      t = -1.3044, df = 35, p-value = 0.2006
      Null hypothesis retained
    
    williams1959: Williams' t (1959)
      t = -1.3042, df = 35, p-value = 0.2007
      Null hypothesis retained
    
    olkin1967: Olkin's z (1967)
      z = -1.3201, p-value = 0.1868
      Null hypothesis retained
    
    dunn1969: Dunn and Clark's z (1969)
      z = -1.2796, p-value = 0.2007
      Null hypothesis retained
    
    hendrickson1970: Hendrickson, Stanley, and Hills' (1970) modification of Williams' t (1959)
      t = -1.3044, df = 35, p-value = 0.2006
      Null hypothesis retained
    
    steiger1980: Steiger's (1980) modification of Dunn and Clark's z (1969) using average correlations
      z = -1.2752, p-value = 0.2022
      Null hypothesis retained
    
    meng1992: Meng, Rosenthal, and Rubin's z (1992)
      z = -1.2738, p-value = 0.2028
      Null hypothesis retained
      95% confidence interval for r.jk - r.jh: -0.2687 0.0570
      Null hypothesis retained (Interval includes 0)
    
    hittner2003: Hittner, May, and Silver's (2003) modification of Dunn and Clark's z (1969) using a backtransformed average Fisher's (1921) Z procedure
      z = -1.2748, p-value = 0.2024
      Null hypothesis retained
    
    zou2007: Zou's (2007) confidence interval
      95% confidence interval for r.jk - r.jh: -0.2510 0.0538
      Null hypothesis retained (Interval includes 0)

    Null hypothesis retained: the correlations of YSL-Aff and YSL-Cog with the precentral gyrus parameter estimates are NOT significantly different from each other.

    However, I realized that correlating the YSL and beta weights is a circular analysis: (1) ICG and YSL totals are highly correlated at .84 (p < .001), (2) the ICG was used to determine CG vs. NCG group, so (3) the voxels that emerged in the t test for group are biased towards being related to YSL totals. To account for this, need to include tot_icg in the linear model.

    I also included BISBAS Reward Responsiveness in the model to try to control for overall trait approach bias. Selected BISBAS-RR because it was the index of approach bias that differed significantly between NCG and CG groups, whereas Drive and Fun-Seeking did not (BIS subscale also differed between groups, with CG being higher in BIS than NCG).

    t.test(data_spr19$tot_bisbas_basrr ~ data_spr19$group) # CG < NCG, p = .027
    
        Welch Two Sample t-test
    
    data:  data_spr19$tot_bisbas_basrr by data_spr19$group
    t = 2.3895, df = 18.611, p-value = 0.02763
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     0.2307184 3.5258034
    sample estimates:
    mean in group NCG  mean in group CG 
             16.47826          14.60000 
    t.test(data_spr19$tot_bisbas_basdr ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$tot_bisbas_basdr by data_spr19$group
    t = 0.9539, df = 26.927, p-value = 0.3486
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -0.9410345  2.5758171
    sample estimates:
    mean in group NCG  mean in group CG 
             9.217391          8.400000 
    t.test(data_spr19$tot_bisbas_basfun ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$tot_bisbas_basfun by data_spr19$group
    t = 0.99494, df = 23.163, p-value = 0.33
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -0.8595628  2.4537657
    sample estimates:
    mean in group NCG  mean in group CG 
            10.130435          9.333333 
    t.test(data_spr19$tot_bisbas_bis ~ data_spr19$group) # CG > NCG, p = .044
    
        Welch Two Sample t-test
    
    data:  data_spr19$tot_bisbas_bis by data_spr19$group
    t = -2.1799, df = 21.698, p-value = 0.0404
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -5.9977837 -0.1471438
    sample estimates:
    mean in group NCG  mean in group CG 
             18.26087          21.33333 
    t.test(data_spr19$gAAT_bias_death_A ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$gAAT_bias_death_A by data_spr19$group
    t = 1.5305, df = 32.228, p-value = 0.1356
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -12.55152  88.50607
    sample estimates:
    mean in group NCG  mean in group CG 
             30.47727          -7.50000 
    t.test(data_spr19$gAAT_bias_neutral_A ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$gAAT_bias_neutral_A by data_spr19$group
    t = 1.2019, df = 33.912, p-value = 0.2377
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -19.89916  77.49007
    sample estimates:
    mean in group NCG  mean in group CG 
             51.79545          23.00000 
    t.test(data_spr19$gAAT_bias_spouse_A ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$gAAT_bias_spouse_A by data_spr19$group
    t = 1.0843, df = 33.073, p-value = 0.2861
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -21.91864  71.95198
    sample estimates:
    mean in group NCG  mean in group CG 
             52.25000          27.23333 
    t.test(data_spr19$gAAT_bias_stranger_A ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$gAAT_bias_stranger_A by data_spr19$group
    t = 0.41214, df = 34.156, p-value = 0.6828
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -43.74911  66.01275
    sample estimates:
    mean in group NCG  mean in group CG 
             29.43182          18.30000 
    t.test(data_spr19$gAAT_bias_whoto_A ~ data_spr19$group) # no sig diff
    
        Welch Two Sample t-test
    
    data:  data_spr19$gAAT_bias_whoto_A by data_spr19$group
    t = 0.57733, df = 30.814, p-value = 0.5679
    alternative hypothesis: true difference in means is not equal to 0
    95 percent confidence interval:
     -40.64803  72.73591
    sample estimates:
    mean in group NCG  mean in group CG 
             42.47727          26.43333 

    Interestingly, the NCG group is actually higher in Reward Responsiveness than CG on average.

    plot(data_spr19$tot_bisbas_basrr ~ data_spr19$group)

    Regression models

    summary(c)
    
    
    Call:
    lm(formula = roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + 
        tot_bisbas_basrr + tot_ysl_aff, data = data_spr19)
    
    Residuals:
         Min       1Q   Median       3Q      Max 
    -16.9493  -1.5333   0.0369   1.7970   8.2247 
    
    Coefficients:
                     Estimate Std. Error t value Pr(>|t|)  
    (Intercept)       1.58123    5.93663   0.266   0.7916  
    tot_icg          -0.07472    0.09574  -0.780   0.4405  
    tot_bisbas_basrr -0.50907    0.33163  -1.535   0.1340  
    tot_ysl_aff       0.47217    0.22359   2.112   0.0421 *
    ---
    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
    
    Residual standard error: 4.398 on 34 degrees of freedom
    Multiple R-squared:  0.2212,    Adjusted R-squared:  0.1524 
    F-statistic: 3.218 on 3 and 34 DF,  p-value: 0.0348

    Model c, which includes YSL-Affective (but not YSL-Cognitive or YSL total) scores, is predictive of precentral gyrus activation controlling for overall grief severity and reward responsiveness.

    Regression plot

    summary(c)
    
    
    Call:
    lm(formula = roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + 
        tot_bisbas_basrr + tot_ysl_aff, data = data_spr19)
    
    Residuals:
         Min       1Q   Median       3Q      Max 
    -16.9493  -1.5333   0.0369   1.7970   8.2247 
    
    Coefficients:
                     Estimate Std. Error t value Pr(>|t|)  
    (Intercept)       1.58123    5.93663   0.266   0.7916  
    tot_icg          -0.07472    0.09574  -0.780   0.4405  
    tot_bisbas_basrr -0.50907    0.33163  -1.535   0.1340  
    tot_ysl_aff       0.47217    0.22359   2.112   0.0421 *
    ---
    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
    
    Residual standard error: 4.398 on 34 degrees of freedom
    Multiple R-squared:  0.2212,    Adjusted R-squared:  0.1524 
    F-statistic: 3.218 on 3 and 34 DF,  p-value: 0.0348
    ggplotRegression(c)

    Wordcloud

    Follows the approach from the Bethlehem et al. (2017) oxytocin ICA paper: > “To better characterize the components showing an oxytocin-related effect on connectivity we used the decoder function in NeuroSynth34 to compare the whole-brain component maps with large-scale automated meta-analysis maps within NeuroSynth. The top 100 terms (excluding terms for brain regions) ranked by the correlation strength between the component map and the meta-analytic map were visualized as a word cloud using the wordcloud library in R, with the size of the font scaled by correlation strength.”

    To do this, I first uploaded the component spatial maps to Neurosynth and used the “decoder” function to view the terms associated with the correlations between the component map and meta-analytic map. I copied these terms and their correlation values to CSV files and removed all terms related to brain regions (such as “dlpfc”, “gyrus”, or “anterior posterior”).

    Then

    library(wordcloud)
    library(RColorBrewer)
    library(viridis) # use the "viridis" package for color palette (viridis palettes are colorblind-safe, many ggplot2 and RColorBrewer palettes are not)
    
    # demo the package using code from RColorBrewer
    n = 8 # change this to however many bins you want to see, a high number like 200 will show more of a spectrum
    image(
      1:n, 1, as.matrix(1:n),
      col = viridis(n, option = "D"),
      xlab = "viridis n", ylab = "", xaxt = "n", yaxt = "n", bty = "n"
    )
  • Import data from MATLAB marsbar ROI output

    plot(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ysl)

    library(psych) corr.test(rest_data_no_subs142147\(fd_mean_txA, rest_data_no_subs142147\)tot_icg)

    corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_1) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_2) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_3) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_4) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_5) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_6) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_7) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_8) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_9) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_10) # “Feeling of wanting back is so strong it is indescribable…” corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_11) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_12) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_13) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_14) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_15) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_16) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_17) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_18) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_19) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_20) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)ysl_21)

    corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_approp) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_blame) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_cherish) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_future) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_life) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_others) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_self) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)gcq_24) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)gcq_30) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_threat) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_gcq_world)

    corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ecrrs_global_anx) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ecrrs_global_avoid) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ecrrs_spouse_anx) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ecrrs_spouse_avoid)

    corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ucla_loneliness) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_bisbas_basdr) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_bisbas_basfun) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_bisbas_basrr) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_bisbas_bis)

    corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ppss_fa) corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)tot_ppss_fr)

    corr.test(data_spr19\(roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19\)gAAT_bias_whoto_A)

    data_spr19\(gAAT_bias_spouse_A <- data_spr19\)gAAT_RT_spouse_push_A - data_spr19\(gAAT_RT_spouse_pull_A data_spr19\)gAAT_bias_whoto_A <- data_spr19\(gAAT_RT_whoto_push_A - data_spr19\)gAAT_RT_whoto_pull_A data_spr19\(gAAT_bias_stranger_A <- data_spr19\)gAAT_RT_stranger_push_A - data_spr19\(gAAT_RT_stranger_pull_A data_spr19\)gAAT_bias_death_A <- data_spr19\(gAAT_RT_death_push_A - data_spr19\)gAAT_RT_death_pull_A data_spr19\(gAAT_bias_neutral_A <- data_spr19\)gAAT_RT_neutral_push_A - data_spr19$gAAT_RT_neutral_pull_A

    
    library(ggplot2)
    
    # Color by groups and facet
    #::::::::::::::::::::::::::::::::::::::::::::::::::::
    sp <- ggscatter(p, x = "roi_betas_CGvNCG_comp01_precentralgyrus", y = "ysl_10",
       color = "group", palette = "jco",
       add = "reg.line", conf.int = TRUE)
    sp + stat_cor(aes(color = group), label.x = 3)
    
    stat_cor(data = p, method = "pearson")
    
    p <- na.omit(subset(data_spr19, select=c("roi_betas_CGvNCG_comp01_precentralgyrus", "ysl_10", "group"))) # remove two people who were dropped from the imaging analysis
    
    # scatterplot
    sp <- ggscatter(p, x = "roi_betas_CGvNCG_comp01_precentralgyrus", y = "ysl_10",
       add = "reg.line",  # Add regression line
       add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
       conf.int = TRUE # Add confidence interval
       )
    # Add correlation coefficient
    sp + stat_cor(method = "pearson", label.x = 3, label.y = 6)
    
    # Use R2 instead of R
    ggscatter(p, x = "roi_betas_CGvNCG_comp01_precentralgyrus", y = "ysl_10", add = "reg.line",
              add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
              conf.int = TRUE, color="group") +
     stat_cor(
       aes(label = paste(..rr.label.., ..p.label.., sep = "~`,`~")),
      label.x = 3
    )
    
    corr.test(data_spr19$ysl_10, data_spr19$icg_2)
    plot(data_spr19$ysl_10, data_spr19$tot_icg)

    # Regression: predict ROI activation from

    
    
    a <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + tot_bisbas_basrr, data = data_spr19)
    b <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + tot_bisbas_basrr + tot_ysl_aff, data = data_spr19)
    anova(a,b)
    summary(a)
    summary(b)
    ggplotRegression(f)
    
    c <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + tot_bisbas_basrr + tot_ysl_cog, data = data_spr19)
    anova(a,c)
    summary(c)
    
    z <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + gAAT_spouse_v_str_A + tot_ysl_aff, data = data_spr19)
    summary(z)
    
    ggsave(ggplotRegression(b))
    ggsave("~/Desktop/regression.png", plot = last_plot(), device = NULL, path = NULL,
      scale = 1, width = 8, units = c("in"), dpi = 600)
    
    
    ggplotRegression <- function (fit) {
    ggplot(fit$model, aes_string(x = names(fit$model)[4], y = names(fit$model)[1])) + 
      geom_point() +
      stat_smooth(method = "lm", col = "blue") +
      labs(title = paste("R^2 = ",signif(summary(fit)$r.squared, 2),
                         "\nIntercept = ",signif(fit$coef[[1]],3 ),
                         "\nSlope =",signif(fit$coef[[4]], 2),
                         "\np =",signif(summary(fit)$coef[4,4], 2))) +
        xlab("Yearning in Situations of Loss - Affective Subscale") +
        ylab("ROI at -23, -20, 75 (betas)")
    }
    
    
    library(apaTables)
    apa.reg.table(b, filename="~/Dropbox/Dissertation/SPR-2019-poster/regressiontable.doc", table.number=1)
    
    ## Using behavioral data
    # create a variable for spouse - stranger
    neuvstr <- group <- subset(data_spr19, select=c(ID,
                                   gAAT_RT_spouse_pull_A,
                                   gAAT_RT_stranger_pull_A))
    
    spvstr$gAAT_spouse_v_str_A <- spvstr$gAAT_RT_spouse_pull_A-spvstr$gAAT_RT_stranger_pull_A
    
    data_spr19 <- left_join(data_spr19, spvstr, by = "ID")
    
    e <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg + gAAT_bias_spouse_A, data = data_spr19)
    f <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg +  gAAT_bias_spouse_A + tot_ysl_aff, data = data_spr19)
    anova(e,f)
    summary(e)
    summary(f)
    
    g <- lm(roi_betas_CGvNCG_comp01_precentralgyrus ~ tot_icg +  gAAT_bias_spouse_A + tot_ysl_cog, data = data_spr19)
    anova(e,g)
    summary(g)
    
    data_spr19 <- left_join(data_spr19, mean_fd, by="ID")
    
    ####
    # QUESTIONS:
    #  INCLUDE COVARS IN REGRESSION MODEL?
    #  HOW TO TEST SPECIFICITY TO YEARNING VS. OTHER CG SX?
      
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$gAAT_spouse_v_str)
    plot(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data_spr19$gAAT_spouse_v_str)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_blame)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_cherish)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_future)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_life)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_others)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_self)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_threat)
    corr.test(data_spr19$roi_betas_CGvNCG_comp01_precentralgyrus, data$tot_gcq_world)

    Footnotes


    1. I’m sure there’s probably a way to modify this in SPM defaults but didn’t want to get too far into the weeds with that.

    2. Note: dir only searches recursively in Matlab 2016b and later. In earlier versions, it will only look for files in the specified directory and ignore any subdirectories.

    3. Ideally this would be a suffix rather than a prefix to be more consistent with BIDS naming standards, but so far haven’t figured that out.

    4. See error message here: https://sourceforge.net/p/icatb/mailman/message/31511448/
      I tried to address this by creating my own group mask and telling GIFT to use that instead of making its own, but ran into the same issue of the mask differing in dimensions from some of the data. Instructions below (adapted from http://www.jpeelle.net/mri/misc/creating_explicit_mask.html):

      How to make a group brain mask
      GIFT allows you to provide a user-specified mask, otherwise it will calculate one for you by default. Copy all of the BOLD mask files generated by fmriprep: $ find /Users/sarenseeley/Desktop/restingstate/data/derivatives/fmriprep -name "*task-rest_bold_space-MNI152NLin2009cAsym_brainmask.nii.gz" -depth 4 | xargs -I {} cp {} /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/mask Unzip them:

      $ cd /Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/mask
      $ gunzip *brainmask.nii.gz

      gunzip --keep will keep the .gz files (by default they’re removed).
      We need to smooth them because having smoothed the images, some of the voxels will now be outside of the mask that fmriprep calculated on the unsmoothed images.
      Smooth them with a 4mm Gaussian kernel:
      In Matlab, do the same as above to get file names and add them to spm_smooth_mask_job.m. In spm_smooth_mask.m, change the line jobfile = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/spm_smooth_rest_job.m'}; to jobfile = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/spm_smooth_mask_job.m'};

      %% in matlab:
      run('/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/spm_smooth_mask.m')
      %% in matlab, edit spm_smooth_mask_job.m accordingly:
      matlabbatch{1}.spm.util.imcalc.input = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/mask/4mmSmoothed_sub-101_ses-txA_task-rest_bold_space-MNI152NLin2009cAsym_brainmask.nii,1'
        '/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/mask/4mmSmoothed_sub-101_ses-txB_task-rest_bold_space-MNI152NLin2009cAsym_brainmask.nii,1'};
      %%
      matlabbatch{1}.spm.util.imcalc.output = 'group_bold_mask';
      matlabbatch{1}.spm.util.imcalc.outdir = {'/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/data-smoothed/mask'};
      matlabbatch{1}.spm.util.imcalc.expression = 'all(X)';
      matlabbatch{1}.spm.util.imcalc.var = struct('name', {}, 'value', {});
      matlabbatch{1}.spm.util.imcalc.options.dmtx = 1;
      matlabbatch{1}.spm.util.imcalc.options.mask = 0;
      matlabbatch{1}.spm.util.imcalc.options.interp = 1;
      matlabbatch{1}.spm.util.imcalc.options.dtype = 4;
      %% in matlab:
      run('/Users/sarenseeley/Desktop/restingstate/data/derivatives/gift/analyses-spr-2019/batch/imcalc_group_mask.m')
    LS0tCnRpdGxlOiAiQW5hbHlzZXMgZm9yIFNQUiAyMDE5IHBvc3RlciIKYXV0aG9yOiAiU2FyZW4gU2VlbGV5IgpkYXRlOiAiTGFzdCB1cGRhdGVkIDAzLTI5LTIwMTkiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdGhlbWU6ICJkZWZhdWx0IgotLS0KIyBEYXRhIHByZXByb2Nlc3NpbmcgYW5kIFFDCiMjIFByb2NlZHVyZQpmTVJJIGRhdGEgd2FzIHByZXByb2Nlc3NlZCBpbiBgZk1SSVByZXBgIChzZWUgZGVzY3JpcHRpb24gYmVsb3cgZm9yIHNwZWNpZmljcykuIFVzZWQgYE1SSVFDYCAodjAuMTQuMikgaW5kaXZpZHVhbCBhbmQgZ3JvdXAgcmVwb3J0cyB0byBpbnNwZWN0IGltYWdlIHF1YWxpdHkgZm9yIGFuYXRvbWljYWwgYW5kIGZ1bmN0aW9uYWwgaW1hZ2VzLiBbTGluayB0byB0cmFja2luZyBzaGVldF0oaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMTduUW0wZnJCWVVTSmdIM0hnM3lONktfMlpqeldpaWI5aGRGazBqOXg3dU0vZWRpdD91c3A9c2hhcmluZykuIAoKTW9yZSBkb2N1bWVudGF0aW9uIGFuZCBkZXRhaWxzIG9uIG15IGBmbXJpcHJlcGAgYW5kIGBNUklRQ2AgdXNhZ2UgaW4gdGhlIG5vdGVib29rIFsqVHV0b3JpYWw6IEJJRFMsIGZNUklQcmVwLCBNUklRQypdKGh0dHA6Ly9ycHVicy5jb20vc2FyZW5zZWVsZXkvNDYzOTQxKQoKIyMjIEV4Y2x1ZGVkIHN1YmplY3RzCgo8dWw+PGxpPioqc3ViLTE0MioqIFtEMTQyXSB3YXMgZXhjbHVkZWQgZnJvbSBhbmFseXNpcyBkdWUgdG8gZXhjZXNzaXZlIG1vdmVtZW50IChtYXggRkQgMTFtbS4gYXQgdHhBLCBjb25zaXN0ZW50IG90aGVyIG1vdmVtZW50cyB1cCB0byA1LTZtbSBhdCB0eEEsIDMuOG1tIGF0IHR4QikuCjxsaT4qKnN1Yi0xNDcqKiBbRDE0Ml0gd2FzIGV4Y2x1ZGVkIGR1ZSB0byBGT1YgaXNzdWUgYXQgdHhCIChhIGZhaXIgYW1vdW50IG9mIGJyYWluIG91dHNpZGUgRk9WKS4gVGhpcyB3YXNuJ3QgYSBwcm9ibGVtIGZvciB0aGUgdGFzayBkYXRhIHRoYXQgSSdtIGF3YXJlIG9mLCBzbyBpdCB3YXMgbGlrZWx5IGNhdXNlZCBieSBoaW0gbW92aW5nIG91dCBvZiB0aGUgRk9WIGJldHdlZW4gc2VxdWVuY2VzLiA8L2xpPjwvbGk+PC91bD4KCiMjIyBmTVJJUHJlcApCb2lsZXJwbGF0ZSBmcm9tIGBmbXJpcHJlcGAgcmVwb3J0czoKCj5SZXN1bHRzIGluY2x1ZGVkIGluIHRoaXMgbWFudXNjcmlwdCBjb21lIGZyb20gcHJlcHJvY2Vzc2luZwpwZXJmb3JtZWQgdXNpbmcgKmZNUklQcHJlcCogMS4xLjggKEBmbXJpcHJlcDE7IEBmbXJpcHJlcDI7IFJSSUQ6U0NSXzAxNjIxNiksCndoaWNoIGlzIGJhc2VkIG9uICpOaXB5cGUqIDEuMS4zIChAbmlweXBlMTsgQG5pcHlwZTI7IFJSSUQ6U0NSXzAwMjUwMikuCjxwPgo8cD4qKkFuYXRvbWljYWwgZGF0YSBwcmVwcm9jZXNzaW5nKiogPGJyPgpBIHRvdGFsIG9mIDIgVDEtd2VpZ2h0ZWQgKFQxdykgaW1hZ2VzIHdlcmUgZm91bmQgd2l0aGluIHRoZSBpbnB1dApCSURTIGRhdGFzZXQuCkFsbCBvZiB0aGVtIHdlcmUgY29ycmVjdGVkIGZvciBpbnRlbnNpdHkgbm9uLXVuaWZvcm1pdHkgKElOVSkKdXNpbmcgYE40Qmlhc0ZpZWxkQ29ycmVjdGlvbmAgW0BuNCwgQU5UcyAyLjIuMF0uCkEgVDF3LXJlZmVyZW5jZSBtYXAgd2FzIGNvbXB1dGVkIGFmdGVyIHJlZ2lzdHJhdGlvbiBvZgoyIFQxdyBpbWFnZXMgKGFmdGVyIElOVS1jb3JyZWN0aW9uKSB1c2luZwpgbXJpX3JvYnVzdF90ZW1wbGF0ZWAgW0ZyZWVTdXJmZXIgNi4wLjEsIEBmc190ZW1wbGF0ZV0uClRoZSBUMXctcmVmZXJlbmNlIHdhcyB0aGVuIHNrdWxsLXN0cmlwcGVkIHVzaW5nIGBhbnRzQnJhaW5FeHRyYWN0aW9uLnNoYAooQU5UcyAyLjIuMCksIHVzaW5nIE9BU0lTIGFzIHRhcmdldCB0ZW1wbGF0ZS4KQnJhaW4gc3VyZmFjZXMgd2VyZSByZWNvbnN0cnVjdGVkIHVzaW5nIGByZWNvbi1hbGxgIFtGcmVlU3VyZmVyIDYuMC4xLApSUklEOlNDUl8wMDE4NDcsIEBmc19yZWNvbmFsbF0sIGFuZCB0aGUgYnJhaW4gbWFzayBlc3RpbWF0ZWQKcHJldmlvdXNseSB3YXMgcmVmaW5lZCB3aXRoIGEgY3VzdG9tIHZhcmlhdGlvbiBvZiB0aGUgbWV0aG9kIHRvIHJlY29uY2lsZQpBTlRzLWRlcml2ZWQgYW5kIEZyZWVTdXJmZXItZGVyaXZlZCBzZWdtZW50YXRpb25zIG9mIHRoZSBjb3J0aWNhbApncmF5LW1hdHRlciBvZiBNaW5kYm9nZ2xlIFtSUklEOlNDUl8wMDI0MzgsIEBtaW5kYm9nZ2xlXS4KU3BhdGlhbCBub3JtYWxpemF0aW9uIHRvIHRoZSBJQ0JNIDE1MiBOb25saW5lYXIgQXN5bW1ldHJpY2FsCnRlbXBsYXRlIHZlcnNpb24gMjAwOWMgW0BtbmksIFJSSUQ6U0NSXzAwODc5Nl0gd2FzIHBlcmZvcm1lZAp0aHJvdWdoIG5vbmxpbmVhciByZWdpc3RyYXRpb24gd2l0aCBgYW50c1JlZ2lzdHJhdGlvbmAKW0FOVHMgMi4yLjAsIFJSSUQ6U0NSXzAwNDc1NywgQGFudHNdLCB1c2luZwpicmFpbi1leHRyYWN0ZWQgdmVyc2lvbnMgb2YgYm90aCBUMXcgdm9sdW1lIGFuZCB0ZW1wbGF0ZS4KQnJhaW4gdGlzc3VlIHNlZ21lbnRhdGlvbiBvZiBjZXJlYnJvc3BpbmFsIGZsdWlkIChDU0YpLAp3aGl0ZS1tYXR0ZXIgKFdNKSBhbmQgZ3JheS1tYXR0ZXIgKEdNKSB3YXMgcGVyZm9ybWVkIG9uCnRoZSBicmFpbi1leHRyYWN0ZWQgVDF3IHVzaW5nIGBmYXN0YCBbRlNMIDUuMC45LCBSUklEOlNDUl8wMDI4MjMsCkBmc2xfZmFzdF0uCjxwPioqRnVuY3Rpb25hbCBkYXRhIHByZXByb2Nlc3NpbmcqKiA8YnI+CkZvciBlYWNoIG9mIHRoZSAyIEJPTEQgcnVucyBmb3VuZCBwZXIgc3ViamVjdCAoYWNyb3NzIGFsbAp0YXNrcyBhbmQgc2Vzc2lvbnMpLCB0aGUgZm9sbG93aW5nIHByZXByb2Nlc3Npbmcgd2FzIHBlcmZvcm1lZC4KRmlyc3QsIGEgcmVmZXJlbmNlIHZvbHVtZSBhbmQgaXRzIHNrdWxsLXN0cmlwcGVkIHZlcnNpb24gd2VyZSBnZW5lcmF0ZWQKdXNpbmcgYSBjdXN0b20gbWV0aG9kb2xvZ3kgb2YgKmZNUklQcmVwKi4KQSBkZWZvcm1hdGlvbiBmaWVsZCB0byBjb3JyZWN0IGZvciBzdXNjZXB0aWJpbGl0eSBkaXN0b3J0aW9ucyB3YXMgZXN0aW1hdGVkCmJhc2VkIG9uICpmTVJJUHJlcConcyAqZmllbGRtYXAtbGVzcyogYXBwcm9hY2guClRoZSBkZWZvcm1hdGlvbiBmaWVsZCBpcyB0aGF0IHJlc3VsdGluZyBmcm9tIGNvLXJlZ2lzdGVyaW5nIHRoZSBCT0xEIHJlZmVyZW5jZQp0byB0aGUgc2FtZS1zdWJqZWN0IFQxdy1yZWZlcmVuY2Ugd2l0aCBpdHMgaW50ZW5zaXR5IGludmVydGVkIFtAZmllbGRtYXBsZXNzMTsKQGZpZWxkbWFwbGVzczJdLgpSZWdpc3RyYXRpb24gaXMgcGVyZm9ybWVkIHdpdGggYGFudHNSZWdpc3RyYXRpb25gIChBTlRzIDIuMi4wKSwgYW5kCnRoZSBwcm9jZXNzIHJlZ3VsYXJpemVkIGJ5IGNvbnN0cmFpbmluZyBkZWZvcm1hdGlvbiB0byBiZSBub256ZXJvIG9ubHkKYWxvbmcgdGhlIHBoYXNlLWVuY29kaW5nIGRpcmVjdGlvbiwgYW5kIG1vZHVsYXRlZCB3aXRoIGFuIGF2ZXJhZ2UgZmllbGRtYXAKdGVtcGxhdGUgW0BmaWVsZG1hcGxlc3MzXS4KQmFzZWQgb24gdGhlIGVzdGltYXRlZCBzdXNjZXB0aWJpbGl0eSBkaXN0b3J0aW9uLCBhbgp1bndhcnBlZCBCT0xEIHJlZmVyZW5jZSB3YXMgY2FsY3VsYXRlZCBmb3IgYSBtb3JlIGFjY3VyYXRlCmNvLXJlZ2lzdHJhdGlvbiB3aXRoIHRoZSBhbmF0b21pY2FsIHJlZmVyZW5jZS4KVGhlIEJPTEQgcmVmZXJlbmNlIHdhcyB0aGVuIGNvLXJlZ2lzdGVyZWQgdG8gdGhlIFQxdyByZWZlcmVuY2UgdXNpbmcKYGJicmVnaXN0ZXJgIChGcmVlU3VyZmVyKSB3aGljaCBpbXBsZW1lbnRzIGJvdW5kYXJ5LWJhc2VkIHJlZ2lzdHJhdGlvbiBbQGJicl0uCkNvLXJlZ2lzdHJhdGlvbiB3YXMgY29uZmlndXJlZCB3aXRoIG5pbmUgZGVncmVlcyBvZiBmcmVlZG9tIHRvIGFjY291bnQKZm9yIGRpc3RvcnRpb25zIHJlbWFpbmluZyBpbiB0aGUgQk9MRCByZWZlcmVuY2UuCkhlYWQtbW90aW9uIHBhcmFtZXRlcnMgd2l0aCByZXNwZWN0IHRvIHRoZSBCT0xEIHJlZmVyZW5jZQoodHJhbnNmb3JtYXRpb24gbWF0cmljZXMsIGFuZCBzaXggY29ycmVzcG9uZGluZyByb3RhdGlvbiBhbmQgdHJhbnNsYXRpb24KcGFyYW1ldGVycykgYXJlIGVzdGltYXRlZCBiZWZvcmUgYW55IHNwYXRpb3RlbXBvcmFsIGZpbHRlcmluZyB1c2luZwpgbWNmbGlydGAgW0ZTTCA1LjAuOSwgQG1jZmxpcnRdLgpCT0xEIHJ1bnMgd2VyZSBzbGljZS10aW1lIGNvcnJlY3RlZCB1c2luZyBgM2RUc2hpZnRgIGZyb20KQUZOSSAgW0BhZm5pLCBSUklEOlNDUl8wMDU5MjddLgpUaGUgQk9MRCB0aW1lLXNlcmllcyAoaW5jbHVkaW5nIHNsaWNlLXRpbWluZyBjb3JyZWN0aW9uIHdoZW4gYXBwbGllZCkKd2VyZSByZXNhbXBsZWQgb250byB0aGVpciBvcmlnaW5hbCwgbmF0aXZlIHNwYWNlIGJ5IGFwcGx5aW5nCmEgc2luZ2xlLCBjb21wb3NpdGUgdHJhbnNmb3JtIHRvIGNvcnJlY3QgZm9yIGhlYWQtbW90aW9uIGFuZApzdXNjZXB0aWJpbGl0eSBkaXN0b3J0aW9ucy4KVGhlc2UgcmVzYW1wbGVkIEJPTEQgdGltZS1zZXJpZXMgd2lsbCBiZSByZWZlcnJlZCB0byBhcyAqcHJlcHJvY2Vzc2VkCkJPTEQgaW4gb3JpZ2luYWwgc3BhY2UqLCBvciBqdXN0ICpwcmVwcm9jZXNzZWQgQk9MRCouCkF1dG9tYXRpYyByZW1vdmFsIG9mIG1vdGlvbiBhcnRpZmFjdHMgdXNpbmcgaW5kZXBlbmRlbnQgY29tcG9uZW50IGFuYWx5c2lzCltJQ0EtQVJPTUEsIEBhcm9tYV0gd2FzIHBlcmZvcm1lZCBvbiB0aGUgKnByZXByb2Nlc3NlZCBCT0xEIG9uIE1OSSBzcGFjZSoKdGltZS1zZXJpZXMgYWZ0ZXIgYSBzcGF0aWFsIHNtb290aGluZyB3aXRoIGFuIGlzb3Ryb3BpYywgR2F1c3NpYW4ga2VybmVsCm9mIDZtbSBGV0hNIChmdWxsLXdpZHRoIGhhbGYtbWF4aW11bSkuCkNvcnJlc3BvbmRpbmcgIm5vbi1hZ2dyZXNpdmVseSIgZGVub2lzZWQgcnVucyB3ZXJlIHByb2R1Y2VkIGFmdGVyIHN1Y2gKc21vb3RoaW5nLgpBZGRpdGlvbmFsbHksIHRoZSAiYWdncmVzc2l2ZSIgbm9pc2UtcmVncmVzc29ycyB3ZXJlIGNvbGxlY3RlZCBhbmQgcGxhY2VkCmluIHRoZSBjb3JyZXNwb25kaW5nIGNvbmZvdW5kcyBmaWxlLgpUaGUgQk9MRCB0aW1lLXNlcmllcyB3ZXJlIHJlc2FtcGxlZCB0byBNTkkxNTJOTGluMjAwOWNBc3ltIHN0YW5kYXJkIHNwYWNlLApnZW5lcmF0aW5nIGEgKnByZXByb2Nlc3NlZCBCT0xEIHJ1biBpbiBNTkkxNTJOTGluMjAwOWNBc3ltIHNwYWNlKi4KU2V2ZXJhbCBjb25mb3VuZGluZyB0aW1lLXNlcmllcyB3ZXJlIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlCipwcmVwcm9jZXNzZWQgQk9MRCo6IGZyYW1ld2lzZSBkaXNwbGFjZW1lbnQgKEZEKSwgRFZBUlMgYW5kCnRocmVlIHJlZ2lvbi13aXNlIGdsb2JhbCBzaWduYWxzLgpGRCBhbmQgRFZBUlMgYXJlIGNhbGN1bGF0ZWQgZm9yIGVhY2ggZnVuY3Rpb25hbCBydW4sIGJvdGggdXNpbmcgdGhlaXIKaW1wbGVtZW50YXRpb25zIGluICpOaXB5cGUqIFtmb2xsb3dpbmcgdGhlIGRlZmluaXRpb25zIGJ5IEBwb3dlcl9mZF9kdmFyc10uClRoZSB0aHJlZSBnbG9iYWwgc2lnbmFscyBhcmUgZXh0cmFjdGVkIHdpdGhpbiB0aGUgQ1NGLCB0aGUgV00sIGFuZAp0aGUgd2hvbGUtYnJhaW4gbWFza3MuCkFkZGl0aW9uYWxseSwgYSBzZXQgb2YgcGh5c2lvbG9naWNhbCByZWdyZXNzb3JzIHdlcmUgZXh0cmFjdGVkIHRvCmFsbG93IGZvciBjb21wb25lbnQtYmFzZWQgbm9pc2UgY29ycmVjdGlvbiBbKkNvbXBDb3IqLCBAY29tcGNvcl0uClByaW5jaXBhbCBjb21wb25lbnRzIGFyZSBlc3RpbWF0ZWQgYWZ0ZXIgaGlnaC1wYXNzIGZpbHRlcmluZyB0aGUKKnByZXByb2Nlc3NlZCBCT0xEKiB0aW1lLXNlcmllcyAodXNpbmcgYSBkaXNjcmV0ZSBjb3NpbmUgZmlsdGVyIHdpdGgKMTI4cyBjdXQtb2ZmKSBmb3IgdGhlIHR3byAqQ29tcENvciogdmFyaWFudHM6IHRlbXBvcmFsICh0Q29tcENvcikKYW5kIGFuYXRvbWljYWwgKGFDb21wQ29yKS4KU2l4IHRDb21wQ29yIGNvbXBvbmVudHMgYXJlIHRoZW4gY2FsY3VsYXRlZCBmcm9tIHRoZSB0b3AgNSUgdmFyaWFibGUKdm94ZWxzIHdpdGhpbiBhIG1hc2sgY292ZXJpbmcgdGhlIHN1YmNvcnRpY2FsIHJlZ2lvbnMuClRoaXMgc3ViY29ydGljYWwgbWFzayBpcyBvYnRhaW5lZCBieSBoZWF2aWx5IGVyb2RpbmcgdGhlIGJyYWluIG1hc2ssCndoaWNoIGVuc3VyZXMgaXQgZG9lcyBub3QgaW5jbHVkZSBjb3J0aWNhbCBHTSByZWdpb25zLgpGb3IgYUNvbXBDb3IsIHNpeCBjb21wb25lbnRzIGFyZSBjYWxjdWxhdGVkIHdpdGhpbiB0aGUgaW50ZXJzZWN0aW9uIG9mCnRoZSBhZm9yZW1lbnRpb25lZCBtYXNrIGFuZCB0aGUgdW5pb24gb2YgQ1NGIGFuZCBXTSBtYXNrcyBjYWxjdWxhdGVkCmluIFQxdyBzcGFjZSwgYWZ0ZXIgdGhlaXIgcHJvamVjdGlvbiB0byB0aGUgbmF0aXZlIHNwYWNlIG9mIGVhY2gKZnVuY3Rpb25hbCBydW4gKHVzaW5nIHRoZSBpbnZlcnNlIEJPTEQtdG8tVDF3IHRyYW5zZm9ybWF0aW9uKS4KVGhlIGhlYWQtbW90aW9uIGVzdGltYXRlcyBjYWxjdWxhdGVkIGluIHRoZSBjb3JyZWN0aW9uIHN0ZXAgd2VyZSBhbHNvCnBsYWNlZCB3aXRoaW4gdGhlIGNvcnJlc3BvbmRpbmcgY29uZm91bmRzIGZpbGUuClRoZSBCT0xEIHRpbWUtc2VyaWVzLCB3ZXJlIHJlc2FtcGxlZCB0byBzdXJmYWNlcyBvbiB0aGUgZm9sbG93aW5nCnNwYWNlczogKmZzYXZlcmFnZTUqLgpBbGwgcmVzYW1wbGluZ3MgY2FuIGJlIHBlcmZvcm1lZCB3aXRoICphIHNpbmdsZSBpbnRlcnBvbGF0aW9uCnN0ZXAqIGJ5IGNvbXBvc2luZyBhbGwgdGhlIHBlcnRpbmVudCB0cmFuc2Zvcm1hdGlvbnMgKGkuZS4gaGVhZC1tb3Rpb24KdHJhbnNmb3JtIG1hdHJpY2VzLCBzdXNjZXB0aWJpbGl0eSBkaXN0b3J0aW9uIGNvcnJlY3Rpb24gd2hlbiBhdmFpbGFibGUsCmFuZCBjby1yZWdpc3RyYXRpb25zIHRvIGFuYXRvbWljYWwgYW5kIHRlbXBsYXRlIHNwYWNlcykuCkdyaWRkZWQgKHZvbHVtZXRyaWMpIHJlc2FtcGxpbmdzIHdlcmUgcGVyZm9ybWVkIHVzaW5nIGBhbnRzQXBwbHlUcmFuc2Zvcm1zYCAoQU5UcyksCmNvbmZpZ3VyZWQgd2l0aCBMYW5jem9zIGludGVycG9sYXRpb24gdG8gbWluaW1pemUgdGhlIHNtb290aGluZwplZmZlY3RzIG9mIG90aGVyIGtlcm5lbHMgW0BsYW5jem9zXS4KTm9uLWdyaWRkZWQgKHN1cmZhY2UpIHJlc2FtcGxpbmdzIHdlcmUgcGVyZm9ybWVkIHVzaW5nIGBtcmlfdm9sMnN1cmZgCihGcmVlU3VyZmVyKS48cD4KTWFueSBpbnRlcm5hbCBvcGVyYXRpb25zIG9mICpmTVJJUHJlcCogdXNlCipOaWxlYXJuKiAwLjQuMiBbQG5pbGVhcm4sIFJSSUQ6U0NSXzAwMTM2Ml0sCm1vc3RseSB3aXRoaW4gdGhlIGZ1bmN0aW9uYWwgcHJvY2Vzc2luZyB3b3JrZmxvdy4KRm9yIG1vcmUgZGV0YWlscyBvZiB0aGUgcGlwZWxpbmUsIHNlZSBbdGhlIHNlY3Rpb24gY29ycmVzcG9uZGluZwp0byB3b3JrZmxvd3MgaW4gKmZNUklQcmVwKidzIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vZm1yaXByZXAucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L3dvcmtmbG93cy5odG1sICJGTVJJUHJlcCdzIGRvY3VtZW50YXRpb24iKS4KCiMjIyBNUklRQwpNZXRob2RzIGRlc2NyaWJlZCBvbiB0aGUgW3JlYWR0aGVkb2NzIHNpdGVdKGh0dHBzOi8vbXJpcWMucmVhZHRoZWRvY3MuaW8vZW4vc3RhYmxlLykuIEkgcmFuIFt0aGUgY2xhc3NpZmllcl0oaHR0cHM6Ly9tcmlxYy5yZWFkdGhlZG9jcy5pby9lbi9zdGFibGUvY2xhc3NpZmllci5odG1sKSBvbiB0aGUgVDF3IGltYWdlcyBhbmQgaW5zcGVjdGVkIHRoZSBpbWFnZXMgZmxhZ2dlZCBhcyBsaWtlbHkgcHJvYmxlbXMgKGJhc2VkIG9uIHF1YWxpdHksIGkuZS4gY2xhc3NpZmllciBwcm9iYWJpbGl0eSBtZXRyaWMgPiAuNTApOiAKCjx1bD4xMThfc2VzLXR4QTxicj4KMTIyX3Nlcy10eEI8YnI+CjEzMF9zZXMtdHhBPGJyPgoxMzBfc2VzLXR4Qjxicj4KMTM3X3Nlcy10eEI8YnI+CjE0Ml9zZXMtdHhBPGJyPgoxNDJfc2VzLXR4Qjxicj4KMTQ4X3Nlcy10eEE8YnI+CjE0OF9zZXMtdHhCPGJyPjwvdWw+CgpBcGFydCBmcm9tIHN1Yi0xNDIgKHdobyBJIGhhZCBhbHJlYWR5IGRlY2lkZWQgdG8gZHJvcCksIG5vbmUgb2YgdGhlIGFuYXRvbWljYWwgaW1hZ2VzIHdlcmUgcG9vciBlbm91Z2ggcXVhbGl0eSBpbiBteSBleWVzIHRvIGRyb3AgZ2l2ZW4gdGhhdCBJIGFtIG9ubHkgdXNpbmcgdGhlbSBmb3IgcmVnaXN0cmF0aW9uIHB1cnBvc2VzIGFuZCB0aGUgRnJlZXN1cmZlciBgYmJyZWdpc3RlcmAgZm9yIEJPTEQtVDF3IHJlZ2lzdHJhdGlvbiBzZWVtcyB0byBiZSBwcmV0dHkgcm9idXN0LiAKCiogTm90ZSB0aGF0IGZvciBhIGZldyBzdWJqZWN0cyAoc3ViLTE0Miwgc3ViLTE0NyksIEkgaGFkIGFscmVhZHkgdXNlZCB0aGUgVDF3IGZyb20gKm9uZSogb2YgdGhlaXIgc2Vzc2lvbnMgYXMgdGhlIGFuYXRvbWljYWwgaW1hZ2UgZm9yICpib3RoKiBzZXNzaW9ucyBiZWNhdXNlIG9mIGJyZWF0aGluZy9jb3VnaGluZy9tb3ZlbWVudCBhcnRpZmFjdHMgKHdoaWNoIG1lYW5zIEkgc3dhcHBlZCBvdXQgdGhlIGJhZCBvbmUgZm9yIHRoZSBva2F5IG9uZSB3aGVuIEkgZGlkIHRoZSBCSURTIGRhdGFzZXQgY29udmVyc2lvbiBhbmQgRElDT00gaW1wb3J0KS4gCgojIFByZS1HSUZUIHN0ZXBzCgojIyBSZW9yZ2FuaXplIGRhdGEKCldpdGhpbiBgL2RhdGEvZGVyaXZhdGl2ZXMvYCwgbWFrZSBhIG5ldyBkaXJlY3RvcnkgZm9yIHRoZSBHSUZUIGFuYWx5c2VzIGFuZCBvdXRwdXRzOiAKYGBge3VuaXh9CiQgY2QgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvCiQgbWtkaXIgLXAgZ2lmdC97YW5hbHlzZXMtc3ByLTIwMTksIGRhdGEtc21vb3RoZWQsIGRhdGEtZGVub2lzZWR9CmBgYAoKYGRhdGEtZGVub2lzZWQvYCBpcyBmb3IgdGhlIG5vbi1hZ2dyZXNzaXZlbHkgZGVub2lzZWQgaW1hZ2VzIGZyb20gSUNBIEFST01BLiBfKipOb3RlOiBEaWQgbm90IGFjdHVhbGx5IGVuZCB1cCB1c2luZyB0aGUgZGVub2lzZWQgaW1hZ2VzIGJlY2F1c2UgdGhlIG51bWJlciBvZiBjb21wb25lbnRzIHRoZXkgZ2VuZXJhdGVkIHdhcyB3YXkgdG9vIGhpZ2ggKD4xMDApIGFuZCBteSBjb21wdXRlciBjb3VsZG4ndCBoYW5kbGUgaXQuIEkgY2FuIGZpeCB0aGlzIGluIGZ1dHVyZSBhbmFseXNlcyBieSBzZXR0aW5nIHRoZSBudW1iZXIgb2YgSUNzIHRvIGVzdGltYXRlIHJhdGhlciB0aGFuIGFza2luZyBHSUZUIHRvIGVzdGltYXRlIGl0IGZyb20gdGhlIGRhdGEuKipfCgpgZGF0YS1zbW9vdGhlZC9gIGlzIGZvciB0aGUgbm9uLWRlbm9pc2VkIGltYWdlcywgd2hpY2ggd2lsbCBiZSBzbW9vdGhlZCBpbiBhIGxhdGVyIHN0ZXAuCgpXZSB3aWxsIG1vdmUgYWxsIG9mIHRoZSBwcmVwcm9jZXNzZWQgZnVuY3Rpb25hbCBpbWFnZXMgZnJvbSBgZm1yaXByZXBgIGhlcmUgYmVjYXVzZSB3aGVuIHdlIHNtb290aCB0aGVtIGxhdGVyLCBTUE0gd2lsbCBkdW1wIHRoZSBzbW9vdGhlZCBpbWFnZXMgaW50byB0aGUgb3JpZ2luYWwgZm9sZGVyIGFuZCBJIGRvbid0IHdhbnQgdGhvc2UgbWl4ZWQgaW4gd2l0aCB0aGUgYGZtcmlwcmVwYCBkZXJpdmF0aXZlcyBkaXJlY3Rvcmllcy5bXjFdIAoKYGBge3VuaXh9CiMgdGhpcyBjb21tYW5kIGZpbmRzIGZpbGVzIHVwIHRvIDQgc3ViZm9sZGVycyBkb3duIGVuZGluZyBpbiB0aGUgc3BlY2lmaWVkIHN0cmluZy9leHRlbnNpb24sCiMgdGhlbiBpdCBjb3BpZXMgdGhvc2UgZmlsZXMgdG8gYSBuZXcgbG9jYXRpb24gd2hpbGUgcmVwbGljYXRpbmcgdGhlIG9yaWdpbiBkaXJlY3Rvcnkgc3RydWN0dXJlCgokICBjZCAvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9mbXJpcHJlcAokICBmaW5kIC4gLXR5cGUgZiAtZGVwdGggNCAtbmFtZSAiKnNtb290aEFST01Bbm9uYWdncl9wcmVwcm9jLm5paS5neiIgLXByaW50MCB8IGNwaW8gLXBtZDAgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9kYXRhLWRlbm9pc2VkLwogIAogICQgIGNkIC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2ZtcmlwcmVwCiQgIGZpbmQgLiAtdHlwZSBmIC1kZXB0aCA0IC1uYW1lICIqdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paSIgLXByaW50MCB8IGNwaW8gLXBtZDAgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9kYXRhLXNtb290aGVkLwpgYGAKCkdJRlQgcmVxdWlyZXMgZmlsZXMgdG8gYmUgb3JnYW5pemVkIHdpdGhpbiBpbmRpdmlkdWFsIHN1YmplY3QgZm9sZGVycywgd2l0aCBkaWZmZXJlbnQgZm9sZGVycyB3aXRoaW4gdGhlIHN1YmplY3QgZm9sZGVyIGZvciBlYWNoIHNlc3Npb24gaWYgbXVsdGlwbGUgKGhlcmUsIGBzZXMtdHhBYCBhbmQgYHNlcy10eEJgKS4gSXQgd2lsbCAqKm5vdCoqIGZpbmQgZmlsZXMgaW4gc3ViZGlyZWN0b3JpZXMgd2l0aGluIHRoZSBzZXNzaW9uIGZvbGRlciwgc28gd2UgbmVlZCB0byBtb3ZlIGVhY2ggYC5uaWlgIGZpbGUgdXAgb25lIGxldmVsIChpLmUuLCB0byBgZGF0YS1zbW9vdGhlZC9zdWItMTAxL3R4QWAgaW5zdGVhZCBvZiBgZGF0YS1zbW9vdGhlZC9zdWItMTAxL3R4QS9mdW5jYCkuICBJIGp1c3QgZGlkIHRoaXMgYnkgZHJhZyAmIGRyb3BwaW5nLCBjb3VsZG4ndCBmaWd1cmUgb3V0IGFuIGVmZmljaWVudCBjb21tYW5kIGxpbmUgd2F5IHRvIGRvIGl0LgoKTW92ZSB0aGUgZXhjbHVkZWQgc3ViamVjdHMgdG8gdGhlaXIgb3duIHNlcGFyYXRlIGZvbGRlcjoKYGBge3VuaXh9CiQgIGNkIC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZGF0YS1zbW9vdGhlZCAjIG9yIC9kYXRhLWRlbm9pc2VkCiQgIG12ICdzdWItMTQyJyAnc3ViLTE0NycgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9leGNsdWRlZC1zdWJqZWN0cwpgYGAKCkZpbmFsbHksIGlmIHVzaW5nIHRoZSBkZW5vaXNlZCBpbWFnZXMsIHVuemlwIHRoZSBgLm5paS5nemAgZmlsZXMgKE4vQSBpZiB1c2luZyB0aGUgbm9uLWRlbm9pc2VkIGltYWdlcykgc28gdGhhdCBHSUZUIGNhbiB3b3JrIHdpdGggdGhlbS4gCmBgYAokIGd1bnppcCAtciBkYXRhLWRlbm9pc2VkLyAqLm5paS5negpgYGAKVGhpcyByZWN1cnNpdmVseSBsb29rcyBmb3IgZmlsZXMgZW5kaW5nIGluICoubmlpLmd6IHdpdGhpbiBgZGF0YS1kZW5vaXNlZC9gLCBhbmQgdXNlcyBgZ3VuemlwYCB0byBleHRyYWN0IHRoZW0uCgojIyBTbW9vdGggaW1hZ2VzCkdJRlQgc3VnZ2VzdHMgdGhhdCBpbWFnZXMgYXJlIHNtb290aGVkIHByaW9yIHRvIHJ1bm5pbmcgdGhlIGdJQ0EgKGhvd2V2ZXIgdGhleSBhbHNvIG5vdGUsIF8iaWYgeW91ciBnb2FsIGlzIHRvIGV4YW1pbmUgcG90ZW50aWFsIGFydGlmYWN0cyBpbiB5b3VyIGRhdGEsIHRoZW4geW91IG1heSBub3Qgd2FudCB0byBzbW9vdGgsIHNpbmNlIHRoZSBhcnRpZmFjdHMgY2FuIGJlICJoaWRkZW4iIGJ5IHRoZSBzbW9vdGhpbmcgcHJvY2Vzcy4iXykgVGhlIGBmbXJpcHJlcGAgZG9lcyBub3QgcGVyZm9ybSBzcGF0aWFsIHNtb290aGluZyBzbyB0aGlzIG5lZWRzIHRvIGhhcHBlbiBpZiB1c2luZyB0aGUgbm9uLWRlbm9pc2VkIHByZXByb2Nlc3NlZCBpbWFnZXMuIFRoZSBJQ0EtQVJPTUEgbm9uLWFnZ3Jlc3NpdmVseSBkZW5vaXNlZCBpbWFnZXMgaGF2ZSBhbHJlYWR5IGJlZW4gc21vb3RoZWQgd2l0aCBhbiBpc290cm9waWMgNm1tIEZXSE0gR2F1c3NpYW4ga2VybmVsLiAKCkZvciB0aGUgbm9uLWRlbm9pc2VkIGltYWdlcywgSSBjaG9zZSB0byB1c2UgYSA0bW0gRldITSBHYXVzc2lhbiBrZXJuZWwgYmVjYXVzZSB3ZSBtYXkgYmUgaW50ZXJlc3RlZCBpbiBzbWFsbGVyIHN1YmNvcnRpY2FsIHN0cnVjdHVyZXMuCgojIyMgU1BNIHNtb290aApVc2UgdGhlIGJhdGNoIGludGVyZmFjZSBvZiBTUE0gdG8gYXBwbHkgb25seSB0aGUgc3BhdGlhbCBzbW9vdGhpbmcgbW9kdWxlIHRvIHByZXByb2Nlc3NlZCBpbWFnZXMuIE1ha2UgYSBuZXcgZm9sZGVyIGBiYXRjaGAgd2l0aGluIGAvZ2lmdC9hbmFseXNlcy1zcHItMjAxOWAgZm9yIGFsbCBvZiB0aGUgYmF0Y2ggc2NyaXB0cyB3ZSdsbCBiZSB1c2luZyAoYm90aCBTUE0gYW5kIEdJRlQpLgoKRm9yIHNtb290aGluZywgeW91IG5lZWQgdG8gbW9kaWZ5ICoqdHdvKiogc2NyaXB0czogYHNwbV9zbW9vdGhfcmVzdC5tYCBhbmQgYHNwbV9zbW9vdGhfcmVzdF9qb2IubWAuIEJvdGggYXJlIGdlbmVyYXRlZCB3aGVuIHlvdSB1c2UgdGhlIGJhdGNoIGVkaXRvciBpbiB0aGUgU1BNMTIgR1VJIHRvIHNldCB1cCBzbW9vdGhpbmcgb24gb25lIHBhcnRpY2lwYW50LCB0aGVuIHNlbGVjdCAiKnNhdmUgYmF0Y2ggYW5kIHNjcmlwdCoiIHRvIHNhdmUgdGhlIHNjcmlwdCBmcm9tIHRoZSBiYXRjaCBlZGl0b3IgR1VJIGFzIGEgdGVtcGxhdGUgdGhhdCB5b3UgY2FuIGVkaXQuCgpUaGUgd2F5IHRoZSBTUE0gYmF0Y2ggaW50ZXJmYWNlIHdvcmtzLCB0aGUgYF9qb2JgIGZpbGUgY29udGFpbnMgaW5wdXRzIGFuZCBwYXJhbWV0ZXJzLCBzdWNoIGFzIGEgbGlzdCBvZiBmaWxlcyB0byBhcHBseSB0aGUgZnVuY3Rpb24gdG8gYW5kIG90aGVyIHBhcmFtZXRlcnMuIFdoZW4geW91IHJ1biBgc3BtX3Ntb290aF9yZXN0Lm1gLCBpdCBjYWxscyBvbiBgc3BtX3Ntb290aF9yZXN0X2pvYi5tYC4KCkZpcnN0LCBvcGVuIE1hdGxhYiAoSSdtIHVzaW5nIDIwMTZiKS4KClRoZW4sIGdldCB0aGUgZmlsZXBhdGhzIGZvciBhbGwgb2YgdGhlIGltYWdlcyB0byBiZSBzbW9vdGhlZCB1c2luZyB0aGUgc2NyaXB0IGJlbG93IGluIE1hdGxhYi5bXjJdCgpgYGAKJSUgTWFrZSBhIHZhcmlhYmxlIGNhbGxlZCAiaW5wdXRzIiAKJSAgY29udGFpbmluZyBwYXRocyB0byBhbGwgZmlsZXMgZW5kaW5nIGluICcqdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paScgCiUgICh0aGVzZSBpbWFnZXMgYXJlIHRoZSBub24tZGVub2lzZWQgb3V0cHV0cyBmcm9tIGZtcmlwcmVwKQoKJSBUaGlzIHNjcmlwdCByZWN1cnNpdmVseSBnZXRzIHRoZSBuYW1lcyBhbmQgcGF0aHMgb2YgYWxsIHRoZSBmaWxlcyBlbmRpbmcgaW4gdGhlIHNwZWNpZmllZCBleHRlbnNpb24KJSB0aGVuIGl0IHB1dHMgdGhvc2UgaW50byBhIHN0cnVjdHVyZSB3aXRoIGNlbGxzICJmb2xkZXIiIGFuZCAibmFtZSIuCiUgV2UgdGhlbiBnZXQgdGhvc2UgY2VsbHMgb3V0IG9mIHRoZSBzdHJ1Y3R1cmUgYW5kIGNvbWJpbmUgdGhlIHR3byB1c2luZyAnc3RyY2F0JyB0byBnZXQgdGhlIGNvbXBsZXRlIGZpbGVwYXRoCgpjZCAvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2RhdGEtc21vb3RoZWQ7CmRpckRhdGEgPSBkaXIoJyoqLyp0YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2MubmlpJyk7Cgpmb2xkZXIgPSBjZWxsMnRhYmxlKHRyYW5zcG9zZSh7ZGlyRGF0YS5mb2xkZXJ9KSk7Cm5hbWVzID0gY2VsbDJ0YWJsZSh0cmFuc3Bvc2Uoe2RpckRhdGEubmFtZX0pKTsKCm5hbWVzLlByb3BlcnRpZXMuVmFyaWFibGVOYW1lcyA9IHsnZmlsZW5hbWUnfTsKZm9sZGVyLlByb3BlcnRpZXMuVmFyaWFibGVOYW1lcyA9IHsncGF0aCd9OwoKZmlsZXMgPSBzdHJjYXQoZm9sZGVyLnBhdGgsJy8nLG5hbWVzLmZpbGVuYW1lKTsKYGBgCgpPcGVuIHRoZSBjZWxsIGFycmF5IGBmaWxlc2AgKHNob3VsZCBiZSA3NngxIGNlbGwpIGJ5IGRvdWJsZS1jbGlja2luZyBvbiBpdCwgYW5kIGNvcHkgdGhlIGNvbnRlbnRzIG9mIHRoZSBmaXJzdCBjb2x1bW4uCgojIyMjIyBzcG1fc21vb3RoX3Jlc3Rfam9iLm0KT3BlbiBgc3BtX3Ntb290aF9yZXN0X2pvYi5tYCBhbmQgcGFzdGUgdGhlIGNvbnRlbnRzIG9mIGBmaWxlc2AgaW50byB0aGUgcGxhY2Ugd2hlcmUgU1BNIHdhbnRzIHlvdSB0byB0ZWxsIGl0IHdoaWNoIGRhdGEgdG8gd29yayBvbiAoYG1hdGxhYmJhdGNoezF9LnNwbS5zcGF0aWFsLnNtb290aC5kYXRhID0geycnfWApLiAKCkFsc28gY2hhbmdlIHRoZSBGV0hNIHRvICJbNCA0IDRdIiBhbmQgdGhlIHByZWZpeCB0byAiNG1tU21vb3RoZWRfIlteM106CgpgYGAKbWF0bGFiYmF0Y2h7MX0uc3BtLnNwYXRpYWwuc21vb3RoLmRhdGEgPSB7Jy9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZGF0YS1zbW9vdGhlZC9zdWItMTAxL3Nlcy10eEEvc3ViLTEwMV9zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvYy5uaWknOwogICAgJy9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZGF0YS1zbW9vdGhlZC9zdWItMTAxL3Nlcy10eEIvc3ViLTEwMV9zZXMtdHhCX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvYy5uaWknfTsgJSBhbGwgZmlsZXMgeW91IHdhbnQgdG8gc21vb3RoIHNob3VsZCBiZSBsaXN0ZWQgaW4gdGhpcyBmaWVsZCwgc2VwYXJhdGVkIGJ5IDsKbWF0bGFiYmF0Y2h7MX0uc3BtLnNwYXRpYWwuc21vb3RoLmZ3aG0gPSBbNCA0IDRdOwptYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGguZHR5cGUgPSAwOwptYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGguaW0gPSAwOwptYXRsYWJiYXRjaHsxfS5zcG0uc3BhdGlhbC5zbW9vdGgucHJlZml4ID0gJzRtbVNtb290aGVkXyc7CmBgYAojIyMjIyBzcG1fc21vb3RoX3Jlc3QubQpZb3Ugc2hvdWxkbid0IG5lZWQgdG8gZWRpdCBhbnl0aGluZyBoZXJlIGFwYXJ0IGZyb20gY2hhbmdpbmcgYG5ydW4gPSBYO2AgdG8gYG5ydW4gPSAxO2AuIApgYGAKJSBMaXN0IG9mIG9wZW4gaW5wdXRzCm5ydW4gPSAxOwpqb2JmaWxlID0geycvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL3NwbV9zbW9vdGhfcmVzdF9qb2IubSd9Owpqb2JzID0gcmVwbWF0KGpvYmZpbGUsIDEsIG5ydW4pOwppbnB1dHMgPSBjZWxsKDAsIG5ydW4pOwpmb3IgY3J1biA9IDE6bnJ1bgplbmQKc3BtKCdkZWZhdWx0cycsICdGTVJJJyk7CnNwbV9qb2JtYW4oJ3J1bicsIGpvYnMsIGlucHV0c3s6fSk7CmBgYAoKRmluYWxseSwgdHlwZSBgcnVuKCcvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL3NwbV9zbW9vdGhfcmVzdC5tJylgIGluIHRoZSBNYXRsYWIgY29tbWFuZCB3aW5kb3csIGhpdCBlbnRlciwgYW5kIHdhaXQgZm9yIGl0IHRvIGNvbXBsZXRlIHNtb290aGluZyBmb3IgYWxsIG9mIHRoZSBmaWxlcy4gVGhpcyB3aWxsIHRha2UgYSB3aGlsZSAoYWJvdXQgYSBtaW51dGUgb3IgdHdvIHBlciBzdWJqZWN0IG9uIG15IE1hYykgc28gYmUgcGF0aWVudC4KCgojIyBBRk5JIDNkcmVzYW1wbGUgCgpGb3IgdGhlIG5vbi1kZW5vaXNlZCBpbWFnZXMsIEdJRlQgZmFpbHMgd2hlbiBpdCB0cmllcyB0byBjcmVhdGUgYSBncm91cCBtYXNrIGJlZm9yZSBydW5uaW5nIHRoZSBQQ0FbXjRdIGR1ZSB0byB0aGUgZmFjdCB0aGF0IHNvbWUgb2YgdGhlIGltYWdlcyBoYXZlIHNsaWdodGx5IGRpZmZlcmVudCBkaW1lbnNpb25zICh1Z2gpLCBJJ20gZ3Vlc3NpbmcgZHVlIHRvIHNsaWdodCBwcm90b2NvbCBjaGFuZ2VzIGFyb3VuZCB0aGUgdGltZSB3aGVuIHRoZSBzY2FubmVyIHdhcyB1cGRhdGVkLiBUaGlzIGRvZXNuJ3Qgc2VlbSB0byBiZSBhbiBpc3N1ZSBmb3IgdGhlIElDQS1BUk9NQSBkZW5vaXNlZCBpbWFnZXMgZm9yIHNvbWUgcmVhc29uLgoKVXNlZCBBRk5JJ3MgYDNkaW5mb2AgYW5kIGAzZHJlc2FtcGxlYCB0b29scywgYXMgd2VsbCBhcyB0aGUgZXJyb3Ivd2FybmluZ3MgbG9nIGZyb20gdGhlIEJJRFMgdmFsaWRhdG9yICh3aGljaCBnYXZlIHNvbWUgd2FybmluZ3MgYWJvdXQgc29tZSBzdWJqZWN0cy9zZXNzaW9ucyBoYXZpbmcgZGlmZmVyZW50IGRpbWVuc2lvbnMpIHRvIGlkZW50aWZ5IGFmZmVjdGVkIHNlc3Npb25zIGFuZCB0byBzdGFuZGFyZGl6ZSBkYXRhc2V0IGRpbWVuc2lvbnMucwoKTm90ZSB0aGF0LCBhcHBhcmVudGx5LCBzbWFsbCBkaWZmZXJlbmNlcyBpbiBkaW1lbnNpb25zIChlLmcuLCAxIG9yIDIgdm94ZWxzKSBhcmVuJ3QgYSBwcm9ibGVtLCBhcyB0aGlzIG9ubHkgc2VlbXMgdG8gYWZmZWN0IHRoZSBzdWJqZWN0cy9zZXNzaW9ucyB3aXRoIHRoZSBmb2xsb3dpbmcgd2FybmluZzoKYGBgCglUeXBlOgkJV2FybmluZwogIEZpbGU6CQlzdWItMTE5X3Nlcy10eEFfdGFzay1yZXN0X2JvbGQubmlpCglMb2NhdGlvbjoJCWRhdGEvc3ViLTExOS9zZXMtdHhBL2Z1bmMvc3ViLTExOV9zZXMtdHhBX3Rhc2stcmVzdF9ib2xkLm5paQoJUmVhc29uOgkJIFRoZSBtb3N0IGNvbW1vbiBzZXQgb2YgZGltZW5zaW9ucyBpczogOTIsODAsMjksMTgwICh2b3hlbHMpLCBUaGlzIGZpbGUgaGFzIHRoZSBkaW1lbnNpb25zOiA4OCw4NCwyOSwxODAgKHZveGVscykuIFRoZSBtb3N0IGNvbW1vbiByZXNvbHV0aW9uIGlzOiAyLjYxbW0geCAyLjYxbW0geCA0LjM4bW0geCAyLjAwcywgVGhpcyBmaWxlIGhhcyB0aGUgcmVzb2x1dGlvbjogMi41MG1tIHggMi41MG1tIHggNC4zOG1tIHggMi4wMHMuCmBgYAoqSG93IGRpZCBJIGZpZ3VyZSB0aGlzIG91dD8gSSB0cmllZCBydW5uaW5nIEdJRlQgb24gYSBidW5jaCBvZiBkaWZmZXJlbnQgc3Vic2V0cyBvZiB0aGUgZGF0YSAoZS5nLiwgZmlyc3QgdGhpcmQgb2Ygc3ViamVjdHMsIGxhc3QgdGhpcmQpIHRvIHRyeSB0byBuYXJyb3cgZG93biB3aGljaCBvbmVzIHdlcmUgY2F1c2luZyBpdCB0byBjcmFzaC4gVGhlbiBvbmNlIEkgaGFkIGFuIGlkZWEgb2YgYXJvdW5kIHdoZXJlIHRoZXkgd2VyZSBpbiB0aGUgZGF0YXNldCwgSSBsb29rZWQgaW4gdGhlIEJJRFMgdmFsaWRhdG9yIGxvZywgZ3Vlc3NlZCB0aGF0IEkgY291bGQgc3RhcnQgd2l0aCB0aGUgcGVvcGxlIHdpdGggdGhlIGxhcmdlciBkaWZmZXJlbmNlcywgbW92ZWQgdGhlaXIgc3ViamVjdCBmb2xkZXJzIG91dCBvZiBkZXJpdmF0aXZlcy9naWZ0L2RhdGEtc21vb3RoZWQvLCBhbmQgdHJpZWQgdG8gcnVuIEdJRlQgYWdhaW4uIEl0IHJhbiwgd2hpY2ggY29uZmlybWVkIG15IGh5cG90aGVzaXMuKgoKRmlyc3QsIGluc3RhbGwgQUZOSTogaHR0cHM6Ly9hZm5pLm5pbWgubmloLmdvdi9wdWIvZGlzdC9kb2MvaHRtbGRvYy9iYWNrZ3JvdW5kX2luc3RhbGwvaW5zdGFsbF9pbnN0cnVjdHMvc3RlcHNfbWFjLmh0bWwKKkRvbid0IG5lZWQgdG8gaW5zdGFsbCBuZXRwYm0gb3IgUiAoYWxyZWFkeSBoYXZlIFIsIGRvbid0IG5lZWQgbmV0cGJtKSBidXQgZGlkIG5lZWQgdG8gb3BlbiBYUXVhcnR6IGFuZCA+ICJDaGVjayBmb3IgVXBkYXRlcyIgPiBpbnN0YWxsIGFueSB1cGRhdGVzLioKClRvIHJ1biBBRk5JIGZyb20gVGVybWluYWwsIHR5cGU6CmBzb3VyY2Ugfi8uYmFzaHJjIGFmbmlgIChzZWUgZGlzY3Vzc2lvbiBvZiBlcnJvciBtZXNzYWdlICYgc29sdXRpb24gaGVyZTogaHR0cHM6Ly9hZm5pLm5pbWgubmloLmdvdi9hZm5pL2NvbW11bml0eS9ib2FyZC9yZWFkLnBocD8xLDE1ODg4OCwxNTg5MDgjbXNnLTE1ODkwOCkKCldpdGhpbiBgL2RhdGEvZGVyaXZhdGl2ZXMvYCwgbWFrZSBhIG5ldyBkaXJlY3RvcnkgZm9yIHRoZSBBRk5JIG91dHB1dHM6IApgYGB7dW5peH0KJCBjZCAvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy8KJCBta2RpciAtcCBhZm5pL3tkYXRhLTNkcmVzYW1wbGV9CgojIGlmIHlvdSBuZWVkIHRvIGNvcHkgQUxMIG9mIHRoZSBzdWJqZWN0cycgZmlsZXMgb3ZlciAodGhpcyBwcmVzZXJ2ZXMgZGlyZWN0b3J5IHN0cnVjdHVyZSk6CiMgJCBjZCAvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2RhdGEtc21vb3RoZWQvCiMgJCAgZmluZCAuIC10eXBlIGYgLWRlcHRoIDQgLW5hbWUgIjRtbVNtb290aGVkLm5paSoiIC1wcmludDAgfCBjcGlvIC1wbWQwICAvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9hZm5pL2RhdGEtM2RyZXNhbXBsZS8KCiMgdG8gY29weSB0byBmbGF0IGZvbGRlciAob25seSBkbyB0aGlzIGlmIHlvdSBuZWVkIHRvIGNvcHkgQUxMIG9mIHRoZSBzdWJqZWN0cycgZmlsZXMgb3ZlcikKIyBjcCBgZmluZCAuIC1uYW1lICI0bW0qImAgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvYWZuaS9kYXRhLTNkcmVzYW1wbGUgICAKCmBgYAoKTW92ZSB0aGUgYDRtbVNtb290aGVkKmAgZmlsZXMgZnJvbSBgc3ViLTEwMS9zZXMtdHhBYCwgYHN1Yi0xMTcvc2VzLXR4QWAsIGBzdWItMTE5L3Nlcy10eEFgLCBgc3ViLTEyMS9zZXMtdHhBYCBhbmQgYHN1Yi0xMjIvc2VzLXR4QmAgaW50byBgZGVyaXZhdGl2ZXMvYWZuaS9kYXRhLTNkcmVzYW1wbGVgLiBBRk5JICpzaG91bGQqIGJlIGFibGUgdG8gY29wZSB3aXRoIHN1YmRpcmVjdG9yaWVzIChJIHRoaW5rPykgYnV0IEkgaGF2ZW4ndCBmaWd1cmVkIHRoYXQgb3V0IHlldC4gU28sIGR1bXAgZXZlcnl0aGluZyBpbnRvIHRoZSBzYW1lIGRhdGEgZm9sZGVyLiAKCioqTm90ZTogSW4gQUZOSSwgYSAiZGF0YXNldCIgbWVhbnMgdGhlIGZpbGUgaXRzZWxmIChlLmcuLCBgNG1tU21vb3RoZWRfc3ViLTEwMV9zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvYy5uaWlgKSwgbm90IGEgZm9sZGVyIGNvbnRhaW5pbmcgc3ViZGlyZWN0b3JpZXMuKioKCiMjIyMjIDNkaW5mbwpEb2N1bWVudGF0aW9uOiBodHRwczovL2FmbmkubmltaC5uaWguZ292L3B1Yi9kaXN0L2RvYy9wcm9ncmFtX2hlbHAvM2RpbmZvLmh0bWwKClJ1bm5pbmcgYDNkaW5mb2Agd2lsbCBzaG93IGluZm9ybWF0aW9uIGFib3V0IHRoZSAiZGF0YXNldCIsIGluY2x1ZGluZyBkaW1lbnNpb25zOgpgYGAKJCAzZGluZm8gNG1tU21vb3RoZWRfc3ViLTExN19zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvY18zZHJlc2FtcGxlZC5uaWkKYGBgCkV4YW1wbGUgb3V0cHV0OgpgYGAKKysgM2RpbmZvOiBBRk5JIHZlcnNpb249QUZOSV8xOS4wLjI0IChNYXIgIDggMjAxOSkgWzY0LWJpdF0KRGF0YXNldCBGaWxlOiAgICA0bW1TbW9vdGhlZF9zdWItMTE3X3Nlcy10eEFfdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jXzNkcmVzYW1wbGVkLm5paQpJZGVudGlmaWVyIENvZGU6IFhZWl9xYzFzcktmY2tjN1o3dF9hV2ZpUFZRICBDcmVhdGlvbiBEYXRlOiBTYXQgTWFyIDE2IDE2OjI4OjM3IDIwMTkKVGVtcGxhdGUgU3BhY2U6ICBUTFJDCkRhdGFzZXQgVHlwZTogICAgRWNobyBQbGFuYXIgKC1lcGFuKQpCeXRlIE9yZGVyOiAgICAgIExTQl9GSVJTVCB7YXNzdW1lZH0gW3RoaXMgQ1BVIG5hdGl2ZSA9IExTQl9GSVJTVF0KU3RvcmFnZSBNb2RlOiAgICBOSUZUSQpTdG9yYWdlIFNwYWNlOiAgIDIxNiwyNzAsMDAwICgyMTYgbWlsbGlvbikgYnl0ZXMKR2VvbWV0cnkgU3RyaW5nOiAiTUFUUklYKC0yLjYwOSwwLDAsOTYsMCwtMi42MDksMCwxMzIsMCwwLDQuMzc1LC03OCk6NzUsODksNDUiCkRhdGEgQXhlcyBUaWx0OiAgUGx1bWIKRGF0YSBBeGVzIE9yaWVudGF0aW9uOgogIGZpcnN0ICAoeCkgPSBMZWZ0LXRvLVJpZ2h0CiAgc2Vjb25kICh5KSA9IFBvc3Rlcmlvci10by1BbnRlcmlvcgogIHRoaXJkICAoeikgPSBJbmZlcmlvci10by1TdXBlcmlvciAgIFstb3JpZW50IExQSV0KUi10by1MIGV4dGVudDogICAtOTcuMDY2IFtSXSAtdG8tICAgIDk2LjAwMCBbTF0gLXN0ZXAtICAgICAyLjYwOSBtbSBbIDc1IHZveGVsc10KQS10by1QIGV4dGVudDogICAtOTcuNTkyIFtBXSAtdG8tICAgMTMyLjAwMCBbUF0gLXN0ZXAtICAgICAyLjYwOSBtbSBbIDg5IHZveGVsc10KSS10by1TIGV4dGVudDogICAtNzguMDAwIFtJXSAtdG8tICAgMTE0LjUwMCBbU10gLXN0ZXAtICAgICA0LjM3NSBtbSBbIDQ1IHZveGVsc10KTnVtYmVyIG9mIHRpbWUgc3RlcHMgPSAxODAgIFRpbWUgc3RlcCA9IDEuMDAwMDBzICBPcmlnaW4gPSAwLjAwMDAwcwogIC0tIEF0IHN1Yi1icmljayAjMCAnPycgZGF0dW0gdHlwZSBpcyBmbG9hdDogICAgIC00LjYwODM0IHRvICAgICAgIDU3My44ODUKICAtLSBBdCBzdWItYnJpY2sgIzEgJz8nIGRhdHVtIHR5cGUgaXMgZmxvYXQ6ICAgICAtNC42NjM0NSB0byAgICAgICA2NjIuMzUzCiAgLS0gQXQgc3ViLWJyaWNrICMyICc/JyBkYXR1bSB0eXBlIGlzIGZsb2F0OiAgICAgLTQuMjk2MDYgdG8gICAgICAgNTY4Ljg4OQoqKiBGb3IgaW5mbyBvbiBhbGwgMTgwIHN1Yi1icmlja3MsIHVzZSAnM2RpbmZvIC12ZXJiJyAqKmAKYGBgCgojIyMjIyAzZHJlc2FtcGxlCkRvY3VtZW50YXRpb246IGh0dHBzOi8vYWZuaS5uaW1oLm5paC5nb3YvcHViL2Rpc3QvZG9jL3Byb2dyYW1faGVscC8zZHJlc2FtcGxlLmh0bWwKCmAzZHJlc2FtcGxlIC1tYXN0ZXJgIGFsbG93cyB5b3UgdG8gY2hhbmdlIHRoZSBkaW1lbnNpb25zIG9mIGEgc3BlY2lmaWVkICJkYXRhc2V0IiAoYWthIE5JRlRJIGZpbGUpIHRvIG1hdGNoIGFub3RoZXIgImRhdGFzZXQiIChha2EgTklGVEkgZmlsZSkuIFNvIHRoaXMgaXMgd2hhdCB3ZSB3YW50IHRvIGRvIHRvIGZpeCB0aGUgaXNzdWUgd2l0aCBzb21lIHN1YmplY3RzL3Nlc3Npb25zIGhhdmluZyBzbGlnaHRseSBkaWZmZXJlbnQgZGltZW5zaW9ucyB0aGF0IGNhdXNlcyBHSUZUIHRvIGNyYXNoLgoKR2VuZXJhbCB1c2FnZTogYDNkcmVzYW1wbGUgLW1hc3RlciBbZGF0YXNldCB5b3Ugd2FudCB0byB1c2UgYXMgdGVtcGxhdGUsIGVuZGluZyBpbiAubmlpIGZvciBOSUZUSSBmaWxlc10gLXByZWZpeCBbd2hhdCB5b3Ugd2FudCB0aGUgbmV3IGRhdGFzZXQgdG8gYmUgbmFtZWQsIGVuZGluZyBpbiAubmlpIGZvciBOSUZUSSBmaWxlc10gLWlucHV0IFtkYXRhc2V0IHRvIGJlIHJlc2FtcGxlZCwgZW5kaW5nIGluIC5uaWkgZm9yIE5JRlRJIGZpbGVzXWAKClJ1biB0aGUgYmVsb3cgbGluZXM6CmBgYAokIDNkcmVzYW1wbGUgLW1hc3RlciA0bW1TbW9vdGhlZF9zdWItMTAxX3Nlcy10eEFfdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paSAtcHJlZml4IDRtbVNtb290aGVkX3N1Yi0xMTdfc2VzLXR4QV90YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2NfM2RyZXNhbXBsZWQubmlpICAtaW5wdXQgNG1tU21vb3RoZWRfc3ViLTExN19zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvYy5uaWkKJCAzZHJlc2FtcGxlIC1tYXN0ZXIgNG1tU21vb3RoZWRfc3ViLTEwMV9zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvYy5uaWkgLXByZWZpeCA0bW1TbW9vdGhlZF9zdWItMTE5X3Nlcy10eEFfdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jXzNkcmVzYW1wbGVkLm5paSAgLWlucHV0IDRtbVNtb290aGVkX3N1Yi0xMTlfc2VzLXR4QV90YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2MubmlpCiQgM2RyZXNhbXBsZSAtbWFzdGVyIDRtbVNtb290aGVkX3N1Yi0xMDFfc2VzLXR4QV90YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2MubmlpIC1wcmVmaXggNG1tU21vb3RoZWRfc3ViLTEyMV9zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvY18zZHJlc2FtcGxlZC5uaWkgIC1pbnB1dCA0bW1TbW9vdGhlZF9zdWItMTIxX3Nlcy10eEFfdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paQokIDNkcmVzYW1wbGUgLW1hc3RlciA0bW1TbW9vdGhlZF9zdWItMTAxX3Nlcy10eEFfdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paSAtcHJlZml4IDRtbVNtb290aGVkX3N1Yi0xMjJfc2VzLXR4Ql90YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2NfM2RyZXNhbXBsZWQubmlpICAtaW5wdXQgNG1tU21vb3RoZWRfc3ViLTEyMl9zZXMtdHhCX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fcHJlcHJvYy5uaWkKYGBgClRoZW4gbW92ZSB0aGUgbmV3IGZpbGVzIChgKl8zcmRyZXNhbXBsZWQubmlpYCkgdG8gdGhlaXIgcmVzcGVjdGl2ZSBmb2xkZXJzLiBCZWNhdXNlIEdJRlQgaXMgZ29pbmcgdG8gbG9vayBmb3IgZmlsZXMgc3RhcnRpbmcgd2l0aCBgKjRtbVNtb290aGAsIGRlbGV0ZSB0aGUgb3JpZ2luYWwgc21vb3RoZWQgZmlsZXMgc28gdGhlIHNlc3Npb24gZm9sZGVyIG9ubHkgaGFzIHR3byBmaWxlczogKDEpIHRoZSBub24tc21vb3RoZWQgcHJlcHJvY2Vzc2VkIGZpbGUgYW5kICgyKSB0aGUgbmV3IDNkcmVzYW1wbGVkIGZpbGUuICpOb3RlOiBJIGVuZGVkIHVwIHJlbW92aW5nIHRoZSBgXzNyZHJlc2FtcGxlZGAgc3VmZml4IG9uY2UgdGhvc2UgZmlsZXMgd2VyZSBpbiB0aGVpciBmb2xkZXJzIHdpdGhpbiBgZGVyaXZhdGl2ZXMvZ2lmdC9gIGJlY2F1c2UgaXQgd2FzIG1ha2luZyBpdCBtb3JlIGNvbXBsaWNhdGVkIHRvIGVkaXQgc29tZSBiYXRjaCBzY3JpcHRzLioKCk5vdyB5b3UgYXJlIHJlYWR5IHRvIHJ1biBHSUZUISAoVGhlIFBDQSBwYXJ0LCBhbnl3YXkuLi4pCgojIyMjIyByYW5kb20gQUZOSSBiaXRzCkFGTkkncyBHVUkgaXMgKmFtYXppbmdseSogY29uZnVzaW5nLgoKTG9vayBmb3IgZGF0YXNldHMgcmVjdXJzaXZlbHk6CmBgYHt1bml4fQokIGNkIC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2FmbmkKJCBhZm5pIC1SIGRhdGEtM2RyZXNhbXBsZQpgYGAKCgojIyBSZWdyZXNzb3JzIChzaW5nbGUtc3ViamVjdCkKRG9uJ3QgdGVjaG5pY2FsbHkgbmVlZCB0aGUgc2luZ2xlLXN1YmplY3QgZGVzaWduIG1hdHJpeCBmb3IgcmVzdGluZyBzdGF0ZSBkYXRhIGFzIEdJRlQgZG9lcyBub3QgdXNlIHRoZSBkZXNpZ24gbWF0cml4IHdoZW4gcnVubmluZyB0aGUgUENBL0lDQS4gSG93ZXZlciwgeW91IGNvdWxkIHVzZSB0aGUgZGVzaWduIG1hdHJpeCB0byBwcm92aWRlIHRlbXBvcmFsIHJlZ3Jlc3NvcnMgd2hpY2ggY2FuIGJlIHVzZWQgZm9yIHRlbXBvcmFsIHNvcnRpbmcgb2YgY29tcG9uZW50cyAob24gdGhlIHNpbmdsZS1zdWJqZWN0IGxldmVsKSBpbiBvcmRlciB0byBpZGVudGlmeSBjb21wb25lbnRzIHRoYXQgYXJlIHBhcnRpY3VsYXJseSBjb3JyZWxhdGVkIHdpdGggbW90aW9uIHBhcmFtZXRlcnMgb3IgQ1NGL3doaXRlIG1hdHRlciBzaWduYWwgZmx1Y3R1YXRpb25zLgoKSWYgeW91IGhhdmUgdGFzayBkYXRhLCB5b3UgRE8gbmVlZCBhIGRlc2lnbiBtYXRyaXggZm9yIHRlbXBvcmFsIHNvcnRpbmcgaW4gb3JkZXIgdG8gaWRlbnRpZnkgdGFzay1yZWxhdGVkIGNvbXBvbmVudHMuCgojIyMgQ3JlYXRlIHJlZ3Jlc3NvcnMgZmlsZXMKQmFzZWQgb24gaHR0cHM6Ly9uZXVyb3N0YXJzLm9yZy90L2NvbmZvdW5kcy1mcm9tLWZtcmlwcmVwLXdoaWNoLW9uZS13b3VsZC15b3UtdXNlLWZvci1nbG0vMzI2LzQsIEkgd2FudCB0byBzZXQgdXAgdGhlIGRlc2lnbiBtYXRyaXggdG8gaW5jbHVkZSB0aGUgdGhlIG1vdGlvbiBwYXJhbWV0ZXJzIGBYYCwgYFlgLCBgWmAsIGBSb3RYYCwgYFJvdFlgLCBhbmQgYFJvdFpgIGFzIHdlbGwgYXMgYEdsb2JhbFNpZ25hbGAsIGBDU0ZgIGFuZCBgV2hpdGVNYXR0ZXJgLiBUaGVzZSBjb2x1bW5zIGFyZSBsb2NhdGVkIGluIHRoZSBgc3ViLSpfc2VzLXR4Kl90YXNrLXJlc3RfYm9sZF9jb25mb3VuZHMudHN2YCBmaWxlcyB0aGF0IGZtcmlwcmVwIGdlbmVyYXRlcyAob25lIHBlciBzdWJqZWN0L3Nlc3Npb24sIHdpdGhpbiBgL2Z1bmNgKS4KCipOb3RlOiBJdCBpcyBub3QgbmVjZXNzYXJ5IHRvIHVzZSB0aGUgIk5vblN0ZWFkeVN0YXRlT3V0bGllcnMiIGNvbHVtbiBiZWNhdXNlIEkgc2V0IHRoZSBHSUZUIGJhdGNoIHNjcmlwdCB0byBleGNsdWRlIHRoZSBmaXJzdCAzIHZvbHVtZXMgKGJhc2VkIG9uIE1SSVFDIGdyb3VwIHJlcG9ydCwgdGhpcyBpcyB0aGUgbWF4IG51bWJlciBvZiBkdW1teSB2b2x1bWVzIGZvciBhbnkgc3ViamVjdCkuKiAKCkVhY2ggc3ViamVjdCBhbmQgc2Vzc2lvbiBuZWVkcyBhIC50eHQgb3IgLm1hdCBmaWxlIGNvbnRhaW5pbmcgdGhlIHJlZ3Jlc3NvcnMuIAoKVGhlIGBjb25mb3VuZHMudHN2YCBmaWxlcyBsaXN0IG9uZSByb3cgcGVyIHZvbHVtZS4gMTgwIHZvbHVtZXMgPSAxODAgcm93cy4gU28gd2UgbmVlZCB0byBzcGVjaWZ5IGZvciBTUE0gdGhhdCB0aGVzZSBhcmUgaW4gc2NhbnMgKGFrYSB2b2x1bWVzKSByYXRoZXIgdGhhbiBzZWNvbmRzLgoKRmlyc3QsIHdlIG5lZWQgdG8gdXNlIFIgY29udmVydCB0aGUgVFNWIGZpbGVzIHRvIENTViAoZWFzaWVyIHRvIHdvcmsgd2l0aCksIGNyZWF0ZSBuZXcgZmlsZXMgd2l0aCBvbmx5IHRoZSBjb2x1bW5zIHdlIHdhbnQgdG8gaW5jbHVkZSBhcyBtdWx0aXBsZSByZWdyZXNzb3JzIGZvciB0aGUgU1BNIGRlc2lnbiBtYXRyaXgsIGFuZCBzYXZlIHRob3NlIG5ldyBmaWxlcyBhcyBgLnR4dGAgZmlsZXMgdG8gYC9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL3JlZ3Jlc3NvcnMvYC4gCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmZpbHRlciA8LSBkcGx5cjo6ZmlsdGVyCnNlbGVjdCA8LSBkcGx5cjo6c2VsZWN0CgojIGdldCBhIGxpc3Qgb2YgYWxsIG9mIHRoZSBjb25mb3VuZHMudHN2IGZpbGVzCmZpbGVuYW1lcyA8LSBsaXN0LmZpbGVzKHBhdGggPSAifi9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2ZtcmlwcmVwIiwgcGF0dGVybiA9ICJjb25mb3VuZHMudHN2IiwgZnVsbC5uYW1lcyA9IFRSVUUsIHJlY3Vyc2l2ZSA9IFRSVUUpCmRpciA8LSAiL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9hbmFseXNlcy1zcHItMjAxOS9iYXRjaC9yZWdyZXNzb3JzIgoKIyBjb252ZXJ0IHRzdiB0byBjc3YgZmlsZXMKbGFwcGx5KGZpbGVuYW1lcywgZnVuY3Rpb24oZikgewogIGRmID0gcmVhZF90c3YoZikKICB3cml0ZS5jc3YoZGYsIGdzdWIoInRzdiIsICJjc3YiLCBmKSwgcm93Lm5hbWVzPUZBTFNFKQp9KQoKIyBnZXQgYSBsaXN0IG9mIHRoZSBjb25mb3VuZHMuY3N2IGZpbGVzCmZpbGVuYW1lcy5jc3YgPC0gbGlzdC5maWxlcyhwYXRoID0gIn4vRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9mbXJpcHJlcCIsIHBhdHRlcm4gPSAiY29uZm91bmRzLmNzdiIsIGZ1bGwubmFtZXMgPSBUUlVFLCByZWN1cnNpdmUgPSBUUlVFKQojIHRoaXMgbWVhbnMgd2Ugbm93IGhhdmUgYm90aCBUU1YgYW5kIENTViB2ZXJzaW9ucyBvZiB0aGUgY29uZm91bmRzIGZpbGVzLCBzbyBjYW4gZGVsZXRlIFRTVnMKCiMgaGVyZSdzIHdoYXQgSSBtb2RpZmllZCBmcm9tIHNvbWV0aGluZyBJIGZvdW5kIG9ubGluZS4uLgojIGZpcnN0LCBjcmVhdGUgYW4gb2JqZWN0IHdpdGggdGhlIGRpcmVjdG9yeSBuYW1lCnRoZV9kaXIgPC0gIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvYmF0Y2gvcmVncmVzc29ycyIKCmNoZWNrX2NyZWF0ZV9kaXIgPC0gZnVuY3Rpb24odGhlX2RpcikgewogIGlmICghZGlyLmV4aXN0cyh0aGVfZGlyKSkgewogIGRpci5jcmVhdGUodGhlX2RpciwgcmVjdXJzaXZlID0gVFJVRSkgfQp9ICMgYSBmdW5jdGlvbiB0byBjaGVjayBpZiB0aGUgZGlyZWN0b3J5IGV4aXN0cwoKIyBjaGVjayB0byBzZWUgaWYgdGhlIGRpcmVjdG9yeSBleGlzdHMgKG1ha2UgaXQgaWYgaXQgZG9lc24ndCkKY2hlY2tfY3JlYXRlX2Rpcih0aGVfZGlyKQoKIyByZWFkIGluIGZpbGVzIChzZWxlY3RlZCBjb2x1bW5zIG9ubHkpIGFuZCB3cml0ZSBuZXcgZmlsZXMKZm9yIChmaWxlIGluIGZpbGVuYW1lcy5jc3YpIHsKICAjIHJlYWQgaW4gdGhlIGNzdgogIHRoZV9kYXRhIDwtIHJlYWRfY3N2KGZpbGUsIGNvbF9uYW1lcyA9IFRSVUUsIGNvbF90eXBlcz1jb2xzX29ubHkoCiAgR2xvYmFsU2lnbmFsCT0gY29sX251bWJlcigpLAogIENTRgk9IGNvbF9udW1iZXIoKSwKICBXaGl0ZU1hdHRlcgk9IGNvbF9udW1iZXIoKSwKICBYCT0gY29sX251bWJlcigpLAogIFkJPSBjb2xfbnVtYmVyKCksCiAgWgk9IGNvbF9udW1iZXIoKSwKICBSb3RYCT0gY29sX251bWJlcigpLAogIFJvdFkJPSBjb2xfbnVtYmVyKCksCiAgUm90Wgk9IGNvbF9udW1iZXIoKSkpIAogICMgcmVtb3ZlIGZpcnN0IDMgcm93cyBzaW5jZSB3ZSBhcmUgZHJvcHBpbmcgdGhlIGZpcnN0IDMgVFJzIGFuZCBzdGFydGluZyB3aXRoIHRoZSA0dGggdm9sdW1lCiAgdGhlX2RhdGEgPC0gdGhlX2RhdGFbLWMoMTozKSwgXQogICMgd3JpdGUgdGhlIGNzdiB0byBhIG5ldyBmaWxlCiAgd3JpdGVfY3N2KHRoZV9kYXRhLCBmaWxlLnBhdGgocGFzdGUwKHRoZV9kaXIsICIvIiwgYmFzZW5hbWUoZmlsZSkpKSwgY29sX25hbWVzID0gRkFMU0UpIAogICMgY29sX25hbWVzIG11c3QgYmUgZmFsc2UsIFNQTSBkb2Vzbid0IHdhbnQgaGVhZGVycyBpbiB0aGUgdHh0IGZpbGVzCiAgIyBidXQgdGhpcyBtZWFucyB5b3UgbmVlZCB0byBtYWtlIHN1cmUgeW91IGRvdWJsZS1jaGVjayB0aGUgb3JkZXIgb2YgdGhlIHJlZ3Jlc3NvcnMgaWYvd2hlbiBsYWJlbGluZyB0aGVtIGxhdGVyCn0KCiMgcmVuYW1lIHRoZSBmaWxlcyB3aXRoIHRoZSBzdWZmaXggIl9yZWdyZXNzb3JzLnR4dCIgdnMuICJfY29uZm91bmRzLmNzdi50eHQiOgpmaWxlbmFtZXMudHh0IDwtIGxpc3QuZmlsZXMocGF0aCA9ICJ+L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9hbmFseXNlcy1zcHItMjAxOS9iYXRjaC9yZWdyZXNzb3JzIiwgcGF0dGVybiA9ICJjb25mb3VuZHMuY3N2IiwgZnVsbC5uYW1lcyA9IFRSVUUsIHJlY3Vyc2l2ZSA9IFRSVUUpCiAgc2FwcGx5KGZpbGVuYW1lcy50eHQsRlVOPWZ1bmN0aW9uKGZpbGUpewogICAgICBmaWxlLnJlbmFtZShmcm9tPWZpbGUsdG89c3ViKHBhdHRlcm49ImNvbmZvdW5kcy5jc3YiLHJlcGxhY2VtZW50PSJyZWdyZXNzb3JzLnR4dCIsZmlsZSkpCn0pCgpgYGAKCkFsbCBvZiB0aGUgbmV3IGBfcmVncmVzc29ycy50eHRgIGZpbGVzIHdlIGp1c3QgZ2VuZXJhdGVkIGFyZSBsb2NhdGVkIGluIGBVc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvYmF0Y2gvcmVncmVzc29yc2AKCiMjIyBTUE0gZGVzaWduIG1hdHJpY2VzCgpPbmUgZGVzaWduIG1hdHJpeCAoYFNQTS5tYXRgKSBwZXIgc3ViamVjdCwgcGVyIHNlc3Npb24uIFNjcmlwdHMgYXJlIGxvY2F0ZWQgaW4gYC9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTE5L2JhdGNoL211bHRpX3JlZ3Jlc3Nvcl9qb2JzYAoKCiMjIyMjIHNwbV8xc3RsZXZlbGRlc2lnbl9yZXN0X2pvYl9bc3ViaiNddHhbQS9CXV9qb2IubQoKVGhpcyBmaWxlIHdpbGwgbG9vayBsaWtlIHRoZSBmb2xsb3dpbmcsIGV4Y2VwdCBoZXJlIG9ubHkgdGhlIGZpcnN0IChgTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paSw0YCkgYW5kIGxhc3QgKGBNTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2MubmlpLDE4MGApIGZpbGUgYXJlIHNob3duIGJlbG93LiAKCl9Ob3RlOiBGb3IgNEQgTklGVEkgZmlsZXMsIFNQTSByZXF1aXJlcyBzcGVjaWZ5aW5nIGVhY2ggM0QgZmlsZSBpbmRpdmlkdWFsbHkgdXNpbmcgdGhlIGNvbW1hIGFuZCBudW1iZXIgZm9sbG93aW5nIHRoZSBgbmlpYCBzdWZmaXgsIGUuZy4sIGAqcHJlcHJvYy5uaWksNGAgcmVmZXJzIHRvIHRoZSBmb3VydGggdm9sdW1lLiBJZiB5b3UgYXJlIHVzaW5nIHRoZSBmaWxlIHNlbGVjdG9yIEdVSSwgaXQgb25seSBzaG93cyB5b3UgdGhlIHNpbmdsZSB1bi1udW1iZXJlZCBmaWxlIGJ5IGRlZmF1bHQuIEluIG9yZGVyIHRvIHNlbGVjdCBhbGwgb2YgdGhlIHJlbGV2YW50IHZvbHVtZXMsIHNwZWNpZnkgYDQ6MTgwYCBpbiB0aGUgZmlsdGVyIGZpZWxkLl8KCmBgYHttYXRsYWJ9CiUtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQolIEpvYiBzYXZlZCBvbiAyMi1NYXItMjAxOSAxMjozMjo0OSBieSBjZmdfdXRpbCAocmV2ICRSZXY6IDY0NjAgJCkKJSBzcG0gU1BNIC0gU1BNMTIgKDY2ODUpCiUgY2ZnX2Jhc2ljaW8gQmFzaWNJTyAtIFVua25vd24KJS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuZGlyID0geycvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2RhdGEtc21vb3RoZWQvc3ViLTEwMS9zZXMtdHhBJ307Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMudGltaW5nLnVuaXRzID0gJ3NjYW5zJzsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy50aW1pbmcuUlQgPSAyOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnRpbWluZy5mbXJpX3QgPSAxNjsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy50aW1pbmcuZm1yaV90MCA9IDg7CiUlCm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuc2Vzcy5zY2FucyA9IHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICcvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2RhdGEtc21vb3RoZWQvc3ViLTEwMS9zZXMtdHhBLzRtbVNtb290aGVkX3N1Yi0xMDFfc2VzLXR4QV90YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX3ByZXByb2MubmlpLDQnCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9kYXRhLXNtb290aGVkL3N1Yi0xMDEvc2VzLXR4QS80bW1TbW9vdGhlZF9zdWItMTAxX3Nlcy10eEFfdGFzay1yZXN0X2JvbGRfc3BhY2UtTU5JMTUyTkxpbjIwMDljQXN5bV9wcmVwcm9jLm5paSwxODAnCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9OwolJQptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MuY29uZCA9IHN0cnVjdCgnbmFtZScsIHt9LCAnb25zZXQnLCB7fSwgJ2R1cmF0aW9uJywge30sICd0bW9kJywge30sICdwbW9kJywge30sICdvcnRoJywge30pOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MubXVsdGkgPSB7Jyd9OwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MucmVncmVzcyA9IHN0cnVjdCgnbmFtZScsIHt9LCAndmFsJywge30pOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLnNlc3MubXVsdGlfcmVnID0geycvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL3JlZ3Jlc3NvcnMvc3ViLTEwMV9zZXMtdHhBX3Rhc2stcmVzdF9ib2xkX3JlZ3Jlc3NvcnMudHh0J307Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuc2Vzcy5ocGYgPSAxMjg7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMuZmFjdCA9IHN0cnVjdCgnbmFtZScsIHt9LCAnbGV2ZWxzJywge30pOwptYXRsYWJiYXRjaHsxfS5zcG0uc3RhdHMuZm1yaV9zcGVjLmJhc2VzLmhyZi5kZXJpdnMgPSBbMSAxXTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy52b2x0ID0gMTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5nbG9iYWwgPSAnTm9uZSc7Cm1hdGxhYmJhdGNoezF9LnNwbS5zdGF0cy5mbXJpX3NwZWMubXRocmVzaCA9IDAuODsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5tYXNrID0geycnfTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnN0YXRzLmZtcmlfc3BlYy5jdmkgPSAnQVIoMSknOwoKYGBgCgojIyMjIyBzcG1fMXN0bGV2ZWxkZXNpZ25fcmVzdF9qb2JfYWxsX2pvYi5tCkkgY29tYmluZWQgYWxsIG9mIHRoZSBpbmRpdmlkdWFsIGBzcG1fMXN0bGV2ZWxkZXNpZ25fcmVzdF9qb2JfW3N1YmojXXR4W0EvQl1fam9iLm1gIHNjcmlwdHMgaW50byBvbmUgc2luZ2xlIFNQTSBqb2IgaW4gb3JkZXIgdG8gYXZvaWQgcnVubmluZyBpbmRpdmlkdWFsIHNjcmlwdHMgaWYgSSBkb24ndCBuZWVkIHRvLgoKIyMjIyMgc3BtXzFzdGxldmVsZGVzaWduX3Jlc3Rfam9iX2FsbC5tCgpgYGB7bWF0bGFifQolIExpc3Qgb2Ygb3BlbiBpbnB1dHMKbnJ1biA9IDE7ICUgZW50ZXIgdGhlIG51bWJlciBvZiBydW5zIGhlcmUKam9iZmlsZSA9IHsnL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9hbmFseXNlcy1zcHItMjAxOS9iYXRjaC9tdWx0aV9yZWdyZXNzb3Jfam9icy9zcG1fMXN0bGV2ZWxkZXNpZ25fcmVzdF9qb2JfYWxsX2pvYi5tJ307CmpvYnMgPSByZXBtYXQoam9iZmlsZSwgMSwgbnJ1bik7CmlucHV0cyA9IGNlbGwoMCwgbnJ1bik7CmZvciBjcnVuID0gMTpucnVuCmVuZApzcG0oJ2RlZmF1bHRzJywgJ0ZNUkknKTsKc3BtX2pvYm1hbigncnVuJywgam9icywgaW5wdXRzezp9KTsKYGBgCgoKVXNhZ2U6IGBydW4oJy9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvYmF0Y2gvbXVsdGlfcmVncmVzc29yX2pvYnMvc3BtXzFzdGxldmVsZGVzaWduX3Jlc3Rfam9iX2FsbC5tJylgCgpUaGlzIGdlbmVyYXRlcyBpbmRpdmlkdWFsIGRlc2lnbiBtYXRyaXggYFNQTS5tYXRgIGZpbGVzIGFuZCBwdXRzIHRoZW0gaW50byB0aGVpciBhcHByb3ByaWF0ZSBzdWJqZWN0L3Nlc3Npb24gZm9sZGVycy4KCgojIyBSZWdyZXNzb3JzIChncm91cC1sZXZlbCkKCkEgZGVzaWduIG1hdHJpeCB3aXRoIGdyb3VwLWxldmVsIHJlZ3Jlc3NvcnMvY292YXJpYXRlcyBpcyB1c2VkIGZvciBwb3N0LUlDQSBhbmFseXNlcyBpbiBTUE0uIF8qKk5vdGU6IHRoaXMgZGVzaWduIG1hdHJpeCBpcyBjcmVhdGVkIGxhdGVyLCBhZnRlciB0aGUgZ0lDQSBpcyBjb21wbGV0ZWQuKipfCgojIyMgQ3JlYXRlIGdyb3VwLWxldmVsIGZpbGUKRGF0YSAob25lIHZhbHVlIHBlciBzdWJqZWN0L3Nlc3Npb24gZm9yIGVhY2ggdmFyaWFibGUpIGNvbWUgZnJvbSB0d28gcGxhY2VzOiB0aGUgZ3JvdXAgQk9MRCByZXBvcnQgZ2VuZXJhdGVkIGJ5IGBNUklRQ2AsIGFuZCB0aGUgbWFzdGVyIGRhdGFzZXQuIEZvciB0aGUgU1BSIHBvc3RlciBhbmFseXNpcywgSSBjcmVhdGVkIGEgbmV3IGRhdGFzZXQgY29udGFpbmluZyBtZWFuIGZyYW1ld2lzZSBkaXNwbGFjZW1lbnQgYW5kIHR3byBzdWJzZXRzIG9mIG90aGVyIHZhcmlhYmxlcyBmcm9tIHRoZSBtYXN0ZXIgZGF0YXNldCAtIG9uZSBjb250YWluaW5nIHRoZSBtZWFzdXJlIHRvdGFsIHNjb3JlcywgYW5kIHRoZSBvdGhlciBjb250YWluaW5nIGRlbW9ncmFwaGljIGFuZCBoZWFsdGgtcmVsYXRlZCB2YXJpYWJsZXMuCgpgYGB7cn0KIyByZWFkIGluIG1hc3RlciBkYXRhc2V0CmRhdGEgPC0gcmVhZFJEUygifi9Ecm9wYm94L0dMQVNTIExhYi9PVCBTdHVkeS9kYXRhL21hc3Rlci1kYXRhc2V0L290LWZtcmlfbWFzdGVyLWRhdGFzZXRfMDIwNzE5LnJkcyIpCgojIHJlYWQgaW4gTVJRQyBncm91cCBzdGF0cyB0byBnZXQgbWVhbiBGRCAKbXJpcWMgPC0gcmVhZF90c3YoIn4vRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9tcmlxYy9ncm91cF9ib2xkLnRzdiIsIGNvbF9uYW1lcyA9IFRSVUUsIGNvbF90eXBlcz1jb2xzX29ubHkoCiAgYmlkc19uYW1lCT0gY29sX2NoYXJhY3RlcigpLAogIGZkX21lYW4JPSBjb2xfbnVtYmVyKCkpKQoKIyBzcGxpdCB1cCBtcmlxYyBieSBzZXNzaW9uCm1yaXFjX0EgPC0gZHBseXI6OmZpbHRlcihtcmlxYywgZ3JlcGwoInNlcy10eEEiLGJpZHNfbmFtZSkpCm1yaXFjX0IgPC0gZHBseXI6OmZpbHRlcihtcmlxYywgZ3JlcGwoInNlcy10eEIiLGJpZHNfbmFtZSkpCgojIHRoZW4gcmVuYW1lIGZvciBtZXJnaW5nIHdpdGggbWFzdGVyIGRhdGFzZXQgdmFyaWFibGVzCm1yaXFjX0EgPC0gcmVuYW1lKG1yaXFjX0EsIElEID0gYmlkc19uYW1lLCAKICAgICAgIGZkX21lYW5fdHhBID0gZmRfbWVhbikKCm1yaXFjX0IgPC0gcmVuYW1lKG1yaXFjX0IsIElEID0gYmlkc19uYW1lLCAKICAgICAgIGZkX21lYW5fdHhCID0gZmRfbWVhbikKCm1yaXFjX0EgPC0gbXV0YXRlX2lmKHRpYmJsZTo6YXNfdGliYmxlKG1yaXFjX0EpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5jaGFyYWN0ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCwgcGF0dGVybiA9ICJzdWItIiwgcmVwbGFjZW1lbnQgPSAiRCIpCm1yaXFjX0EgPC0gbXV0YXRlX2lmKHRpYmJsZTo6YXNfdGliYmxlKG1yaXFjX0EpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5jaGFyYWN0ZXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3I6OnN0cl9yZXBsYWNlX2FsbCwgcGF0dGVybiA9ICJfc2VzLXR4QV90YXNrLXJlc3RfYm9sZCIsIHJlcGxhY2VtZW50ID0gIiIpCgptcmlxY19CIDwtIG11dGF0ZV9pZih0aWJibGU6OmFzX3RpYmJsZShtcmlxY19CKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMuY2hhcmFjdGVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwsIHBhdHRlcm4gPSAic3ViLSIsIHJlcGxhY2VtZW50ID0gIkQiKQptcmlxY19CIDwtIG11dGF0ZV9pZih0aWJibGU6OmFzX3RpYmJsZShtcmlxY19CKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMuY2hhcmFjdGVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwsIHBhdHRlcm4gPSAiX3Nlcy10eEJfdGFzay1yZXN0X2JvbGQiLCByZXBsYWNlbWVudCA9ICIiKQoKbWVhbl9mZCA8LSBsZWZ0X2pvaW4obXJpcWNfQSwgbXJpcWNfQiwgYnk9IklEIikKCiMgYWRkIHRoZSBmZF9tZWFuIHZhcmlhYmxlcyB0byBhIHN1YnNldCBvZiB2YXJpYWJsZXMgZnJvbSB0aGUgbWFzdGVyIGRhdGFzZXQKCiMgbWFrZSBhIHN1YnNldCBvZiBtZWFzdXJlIHRvdGFsIHNjb3Jlcwp0b3RzIDwtIGRhdGFbLCBncmVwKCdedG90fElEJywgbmFtZXMoZGF0YSkpXQoKIyBnZXQgYSBsaXN0IG9mIHZhcmlhYmxlIG5hbWVzIHRvIHBpY2sgb3V0IHRoZSBvbmVzIEkgd2FudApuYW1lcyA8LSBuYW1lcyhkYXRhKQpjYXQobmFtZXMsIHNlcD0iXG4iKQoKIyBtYWtlIGEgc3Vic2V0IG9mIG90aGVyIHZhcmlhYmxlcyBpbiBtYXN0ZXIgZGF0YXNldApncm91cCA8LSBzdWJzZXQoZGF0YSwgc2VsZWN0PWMoSUQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXhfbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZV95cnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrbm93YmVmb3JlX3ksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXJldGFrZXJfeSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkdWNhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hlc3RkZWdyZWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjYXRpb25fb3RoZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbXBsb3ltZW50LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91c2Vob2xkc2l6ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXNlaG9sZHNpemVfYWR1bHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VzZWhvbGRzaXplX2luY29tZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV0aG5pY2l0eV9oaXNwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFjZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhY2Vfb3RoZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZWFybmFib3V0c3R1ZHksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWRzX3ksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWRzX3J4b25seSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lZHNfcHN5Y2hvYWN0aXZlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVkc19ocnQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWRzX2hvcm1vbmVfb3BpYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVkc190b3RhbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ham9yaGVhbHRocHJvYnNfeSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ham9yaGVhbHRocHJvYnNfd2hhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3RtZW5vcGF1c2FsX3ksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuX3ByZWduYW5jaWVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9saXZlYmlydGhzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9udXJzZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGNvaG9sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc21va2luZ195LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc21va2luZ19ob3dsb25nLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc21va2luZ19wZXJkYXksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWZmZWluZV9wZXJkYXksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGVyY2lzZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVzaW5jZWRlYXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeXJzX3RvZ2V0aGVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF8yMG1GVSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWV0b3Jlc3RfQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWV0b3Jlc3RfQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWV0bzIwbUZVLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGltZXRvMjBtRlVfbW9zLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdF9zcm9lXzFfQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3Rfc3JvZV8yX0EsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3N0X3Nyb2VfM19BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdF9zcm9lXzFfQiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc3Rfc3JvZV8yX0IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3N0X3Nyb2VfM19CLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnMyMjU0Mjk4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnMyMjY4NDk4LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnM1MzU3NiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJzMjI1NDI5OF9BLmNhcnJpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByczIyNjg0OThfQy5jYXJyaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnM1MzU3Nl9BLmNhcnJpZXIpKQoKIyBtZXJnZSBhbGwgdGhlIGdyb3VwIGRhdGEKcmVzdF9kYXRhIDwtIGxlZnRfam9pbihncm91cCwgdG90cywgYnk9IklEIikgJT4lIGxlZnRfam9pbiguLCBtZWFuX2ZkKQoKIyByZXBsYWNlICJEIiBwcmVmaXggaW4gSUQgdG8gInN1Yi0iIHRvIGJlIEJJRFMtY29tcGxpYW50CnJlc3RfZGF0YSA8LSByZXN0X2RhdGEgJT4lIAogIG11dGF0ZShJRCA9IHN0cl9yZXBsYWNlKElELCAiRCIsICJzdWItIikpCgojIHNhdmUgYXMgYSAucmRzIGZpbGUgYW5kIGEgY3N2IGZpbGUKd3JpdGVfY3N2KHJlc3RfZGF0YSwgIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZ3JvdXAtY292YXJpYXRlcy9ncm91cF9jb3ZhcmlhdGVzLmNzdiIpCnNhdmVSRFMocmVzdF9kYXRhLCAiL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9ncm91cC1jb3ZhcmlhdGVzL2dyb3VwX2NvdmFyaWF0ZXMucmRzIikKCiMgYW5kIHNhdmUgYSB2ZXJzaW9uIHdpdGhvdXQgc3ViLTE0Miwgc3ViLTE0NyAoZXhjbHVkZWQgZnJvbSBHSUZUIGFuYWx5c2VzKQojIHRoaXMgaXMgd2hhdCBJIHdpbGwgdXNlIHRvIHNldCB1cCB0aGUgbW9kZWwgc3BlY2lmaWNhdGlvbiBpbiBTUE0KcmVzdF9kYXRhX25vX3N1YnMxNDIxNDcgPC0gZmlsdGVyKHJlc3RfZGF0YSwgIWdyZXBsKCJzdWItMTQyfHN1Yi0xNDciLElEKSkgCndyaXRlX2NzdihyZXN0X2RhdGEsICIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2dyb3VwLWNvdmFyaWF0ZXMvZ3JvdXBfY292YXJpYXRlc19uby0xNDItMTQ3LmNzdiIpCmBgYAoKSSB3YXMgYWxzbyBzYXZpbmcgc29tZSBvZiB0aGVzZSBpbmRpdmlkdWFsbHkgZm9yIHVzZSB3aXRoIE1BTkNPVkFOLi4uCmBgYHtyfQojIHNhdmUgdGhlIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCBpbmRpdmlkdWFsbHkgZm9yIHVzZSBpbiBNQU5DT1ZBTiB0b29sYm94IAphZ2UgPC0gYXNfdGliYmxlKHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JGFnZV95cnMpCndyaXRlX2NzdihhZ2UsICIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2dyb3VwLWNvdmFyaWF0ZXMvYWdlLnR4dCIsIGNvbF9uYW1lcyA9IEZBTFNFKQoKc2V4IDwtIGFzX3RpYmJsZShyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRzZXhfbSkKd3JpdGVfY3N2KHNleCwgIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZ3JvdXAtY292YXJpYXRlcy9zZXgudHh0IiwgY29sX25hbWVzID0gRkFMU0UpCgpncm91cCA8LSBhc190aWJibGUocmVzdF9kYXRhX25vX3N1YnMxNDIxNDckZ3JvdXApCndyaXRlX2Nzdihncm91cCwgIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZ3JvdXAtY292YXJpYXRlcy9ncm91cC50eHQiLCBjb2xfbmFtZXMgPSBGQUxTRSkKCmJkaSA8LSBhc190aWJibGUocmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdG90X2JkaSkKd3JpdGVfY3N2KGJkaSwgIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZ3JvdXAtY292YXJpYXRlcy9iZGkudHh0IiwgY29sX25hbWVzID0gRkFMU0UpCgp5c2wgPC0gYXNfdGliYmxlKHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JHRvdF95c2wpCndyaXRlX2Nzdih5c2wsICIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2dyb3VwLWNvdmFyaWF0ZXMveXNsLnR4dCIsIGNvbF9uYW1lcyA9IEZBTFNFKQoKaWNnIDwtIGFzX3RpYmJsZShyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyR0b3RfaWNnKQp3cml0ZV9jc3YoaWNnLCAiL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9ncm91cC1jb3ZhcmlhdGVzL2ljZy50eHQiLCBjb2xfbmFtZXMgPSBGQUxTRSkKCm1lZHNfdG90YWxuIDwtIGFzX3RpYmJsZShyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRtZWRzX3RvdGFsKQp3cml0ZV9jc3YobWVkc190b3RhbG4sICIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2dyb3VwLWNvdmFyaWF0ZXMvbWVkc190b3RhbG4udHh0IiwgY29sX25hbWVzID0gRkFMU0UpCgp0aW1lc2luY2VkZWF0aCA8LSBhc190aWJibGUocmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdGltZXNpbmNlZGVhdGgpCndyaXRlX2Nzdih0aW1lc2luY2VkZWF0aCwgIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZ3JvdXAtY292YXJpYXRlcy90aW1lc2luY2VkZWF0aC50eHQiLCBjb2xfbmFtZXMgPSBGQUxTRSkKCnRpbWV0b3Jlc3RfQSA8LSBhc190aWJibGUocmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdGltZXRvcmVzdF9BKQp3cml0ZV9jc3YodGltZXRvcmVzdF9BLCAiL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9ncm91cC1jb3ZhcmlhdGVzL3RpbWV0b3Jlc3RfdHhBLnR4dCIsIGNvbF9uYW1lcyA9IEZBTFNFKQoKdGltZXRvcmVzdF9CIDwtIGFzX3RpYmJsZShyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyR0aW1ldG9yZXN0X0IpCndyaXRlX2Nzdih0aW1ldG9yZXN0X0IsICIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2dyb3VwLWNvdmFyaWF0ZXMvdGltZXRvcmVzdF90eEIudHh0IiwgY29sX25hbWVzID0gRkFMU0UpCgptZWFuRkRfdHhBIDwtIGFzX3RpYmJsZShyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QSkKd3JpdGVfY3N2KG1lYW5GRF90eEEsICIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2dyb3VwLWNvdmFyaWF0ZXMvbWVhbkZEX3R4QS50eHQiLCBjb2xfbmFtZXMgPSBGQUxTRSkKCm1lYW5GRF90eEIgPC0gYXNfdGliYmxlKHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JGZkX21lYW5fdHhCKQp3cml0ZV9jc3YobWVhbkZEX3R4QiwgIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZ3JvdXAtY292YXJpYXRlcy9tZWFuRkRfdHhCLnR4dCIsIGNvbF9uYW1lcyA9IEZBTFNFKQpgYGAKCkZyb20gdGhlc2UgZ3JvdXAgZGF0YSwgY2FuIGFsc28gZG8gdGhpbmdzIGxpa2UgY29tcGFyaW5nIGhvdyBtdWNoIHBlb3BsZSBtb3ZlZCBvbiBhdmVyYWdlIGJ5IGdyb3VwOgpgYGB7cn0KbGlicmFyeShwc3ljaCkKCiMgY29tcGFyaW5nIG1lYW4gRkQgYmV0d2VlbiB0cmVhdG1lbnRzIChBL0IpIGFuZCBncm91cHM6CnQudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QSwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckZmRfbWVhbl90eEIsCiAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBwYWlyZWQgPSBUUlVFLCB2YXIuZXF1YWwgPSBGQUxTRSkgIyBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQKCnQudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QSwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckZmRfbWVhbl90eEIsCiAgICAgICBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBwYWlyZWQgPSBUUlVFLCB2YXIuZXF1YWwgPSBGQUxTRSkgIyBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQKICAKdC50ZXN0KGZkX21lYW5fdHhBIH4gZ3JvdXAsIGRhdGE9cmVzdF9kYXRhX25vX3N1YnMxNDIxNDcpICMgbm90IHNpZ25pZmljYW50bHkgZGlmZmVyZW50Cgp0LnRlc3QoZmRfbWVhbl90eEIgfiBncm91cCwgZGF0YT1yZXN0X2RhdGFfbm9fc3ViczE0MjE0NykgIyBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgKHAgPCAuMDgpIHRob3VnaCB0aGUgTkNHIGdyb3VwIG92ZXJhbGwgaGFzIGEgaGlnaGVyIG1lYW4gRkQgYXQgdHhCICguMzcgdnMgLjI3KSAKCmNvcnIudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QSwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdG90X2ljZykgCmNvcnIudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QiwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdG90X2ljZykgCmNvcnIudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QSwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdG90X2JkaSkgCmNvcnIudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QiwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdG90X2JkaSkgCmNvcnIudGVzdChyZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRmZF9tZWFuX3R4QSwgcmVzdF9kYXRhX25vX3N1YnMxNDIxNDckdG90X3ByZV9zdGFpX0EpIApjb3JyLnRlc3QocmVzdF9kYXRhX25vX3N1YnMxNDIxNDckZmRfbWVhbl90eEIsIHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JHRvdF9wcmVfc3RhaV9CKSAKY29yci50ZXN0KHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JGZkX21lYW5fdHhBLCByZXN0X2RhdGFfbm9fc3ViczE0MjE0NyRhZ2VfeXJzKQpjb3JyLnRlc3QocmVzdF9kYXRhX25vX3N1YnMxNDIxNDckZmRfbWVhbl90eEIsIHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JGFnZV95cnMpIApgYGAKTWVhbiBGRCBpcyBub3Qgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgYmV0d2VlbiB0cmVhdG1lbnRzIG9yIGdyb3VwcywgYW5kIGlzIG5vdCBjb3JyZWxhdGVkIHdpdGggdG90YWwgSUNHIHNjb3JlLCBCREkgc2NvcmUsIG9yIHByZS1zY2FuIFNUQUkgKHN0YXRlIGFueGlldHkpLiBJdCBpcyBhbHNvIG5vdCBzaWduaWZpY2FudGx5IGFzc29jaWF0ZWQgd2l0aCBhZ2UuCgojIyMgSU1QT1JUQU5UIApXaWxsIGJlIG5vdGVkIGFnYWluIGJlbG93LCBidXQgbWFrZSBzdXJlIHRoYXQgd2hlbiB5b3UncmUgaW1wb3J0aW5nIGFuZCB1c2luZyB0aGUgZ3JvdXAgY292YXJpYXRlcyBmaWxlIHRvIHNldCB1cCBhIGRlc2lnbiBtYXRyaXgsIHRoZSBzdWJqZWN0IG9yZGVyIG1hdGNoZXMgdGhlIG9yZGVyIGluIHdoaWNoIHRoZSBmaWxlcyBhcmUgbGlzdGVkIGluIHRoZSBTUE0gZGVzaWduLCBhcyB3ZWxsIGFzIG1hdGNoaW5nIGFueSByZW51bWJlcmluZyBvZiBzdWJqZWN0cyB0aGF0IEdJRlQgaGFzIGRvbmUgKGUuZy4sIHdoYXQgR0lGVCBzYXlzIGlzIHN1YmplY3QgMzggaXMgdGhlIDM4dGggZmlsZSAtLSBOT1Qgc3ViLTAzOCkuICAKCkZvciBlYWNoIGRlc2lnbiBtYXRyaXgsIHlvdSB3aWxsIGxpa2VseSBuZWVkIGEgZGlmZmVyZW50IGdyb3VwIGNvdmFyaWF0ZXMgZmlsZSB3aXRoIHRoZSByb3dzIG9yZGVyZWQgdGhlIHdheSB0aGF0IHRoZSBmaWxlcyBhcmUgb3JkZXJlZCBpbiBTUE0gKGUuZy4sIGlmIHlvdSBhcmUgZW50ZXJpbmcgc3ViamVjdHMgZm9yIHdob20gYGdyb3VwYD0wIGFzIHlvdXIgZmlyc3QgZ3JvdXAsIGFuZCBmb3Igd2hvbSBgZ3JvdXBgPTEgYXMgeW91ciBzZWNvbmQgZ3JvdXAsIGFsbCBvZiB0aGUgZmlsZXMgZm9yIHN1YmplY3RzIGluIHRoZSBmaXJzdCBncm91cCB3aWxsIGJlIGxpc3RlZCBmaXJzdCBpbiB0aGUgZGVzaWduIG1hdHJpeCkuCgooRG9uJ3QgbmVlZCB0byBkbyBhbnl0aGluZyBhYm91dCB0aGlzIG5vdywgYnV0IGp1c3QgYmUgcmVhbGx5IGF3YXJlIG9mIGl0IHdoZW4geW91IGdldCB0byB0aGUgcG9pbnQgb2YgcnVubmluZyBncm91cCBTUE0gc3RhdHMgd2l0aCB0aGVzZSBjb3ZhcmlhdGVzIGxhdGVyKS4KCgojIEdJRlQgKEdyb3VwIElDQSBvZiBmTVJJIFRvb2xib3gpCioiSXQgaXMgYSBNQVRMQUIgdG9vbGJveCB3aGljaCBpbXBsZW1lbnRzIG11bHRpcGxlIGFsZ29yaXRobXMgZm9yIGluZGVwZW5kZW50IGNvbXBvbmVudCBhbmFseXNpcyBhbmQgYmxpbmQgc291cmNlIHNlcGFyYXRpb24gb2YgZ3JvdXAgKGFuZCBzaW5nbGUgc3ViamVjdCkgZnVuY3Rpb25hbCBtYWduZXRpYyByZXNvbmFuY2UgaW1hZ2luZyBkYXRhLiIqIERvd25sb2FkIGFuZCBkb2N1bWVudGF0aW9uIGF2YWlsYWJsZSBoZXJlOiBodHRwOi8vbWlhbGFiLm1ybi5vcmcvc29mdHdhcmUvZ2lmdC9pbmRleC5odG1sIAoKRm9yIHRoZSBwb3N0ZXIgYW5hbHlzZXMsIEkgbG9va2VkIGF0IHRyZWF0bWVudCBBIGFsb25lLgoKXyoqTm90ZTogdHhBIGlzIHJlZmVycmVkIHRvIGFzICJzZXNzaW9uIDEiIGluIEdJRlQgKGl0IGxhYmVscyBzZXNzaW9ucyBhbmQgc3ViamVjdHMgYmFzZWQgb24gYWxwaGFudW1lcmljYWwgb3JkZXIgb2YgZmlsZS9mb2xkZXIgbmFtZXMpLioqXwoKXyoqTm90ZTpJZiB5b3Ugd2FudCB0byBjb21wYXJlIHR3byBzZXNzaW9ucyAob3IgdHdvIGdyb3VwcyksIHlvdSBzaG91bGQgcnVuIHRoZW0gaW4gYSBzaW5nbGUgSUNBIHNvIHRoYXQgdGhlIGNvbXBvbmVudCBudW1iZXJzIG1hdGNoLioqXwoKIyMgRGF0YSByZWR1Y3Rpb24KCiMjIyBSdW4gUENBICYgSUNBICMxClVzZSBiYXRjaCBmaWxlIGBJbnB1dF9kYXRhX3N1YmplY3RzX3Jlc3RpbmdzdGF0ZV90eEEubWAgdG8gaW5wdXQgZGF0YSBhbmQgaW5pdGlhdGUgdGhlIGFuYWx5c2lzLiBQYXJhbWV0ZXJzIHVzZWQgZm9yIHRoZSBQQ0EgYW5kIElDQSBkYXRhIHJlZHVjdGlvbiBzdGVwcyBhcmUgZGVzY3JpYmVkIGluIGAvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L3Jlc3VsdHNfbm8tc3ViLTE0Ml9kcm9wLTMtdm9sc19yZWdyZXNzb3JzX2ludG5vcm1fdHhBL2dpZnRfdHhBX19pY2FfcGFyYW1ldGVyX2luZm8ubWF0YC4gCgpXYWl0IFtob3Vyc10gZm9yIGl0IHRvIGZpbmlzaC4KCk9wZW4gR0lGVCBieSBlbnRlcmluZyBgZ2lmdGAgaW4gdGhlIE1hdGxhYiBjb21tYW5kIGxpbmUuIENsaWNrIHRoZSAiRGlzcGxheSBHVUkiIGJ1dHRvbiB0byBsb29rIGF0IHRoZSBpZGVudGlmaWVkIElDcyBpbiBkaWZmZXJlbnQgd2F5cyAoZ3JvdXAsIHNpbmdsZS1zdWJqZWN0LCBtZWFucywgdGltZWNvdXJzZXMsIG9ubHkgc3BlY2lmaWMgSUNzLCBldGMuKSBZb3UgY2FuIGVkaXQgZGlzcGxheSBkZWZhdWx0cywgc3VjaCBhcyBaIHRocmVzaG9sZCB0byB1c2UgZm9yIGRpc3BsYXksIHVzaW5nIHRoZSBtZW51IGluIHRoZSB1cHBlciBsZWZ0IGNvcm5lciBvZiB0aGUgd2luZG93LgoKV3JpdGUgYSBzdW1tYXJ5IG9mIHJlc3VsdHMgdG8gSFRNTCBieSBjbGlja2luZyB0aGUgIlJlc3VsdHMgU3VtbWFyeSIgYnV0dG9uLiBWaWV3IHRoZSBIVE1MIHJlcG9ydCwgd2hpY2ggc2hvd3MgSUNBU1NPIHN0YWJpbGl0eSBlc3RpbWF0ZSBwbG90cyBhcyB3ZWxsIGFzIGNvbXBvbmVudCBzcGF0aWFsIG1hcHMsIHRpbWVjb3Vyc2VzLCBhbmQgc3BlY3RyYS4KCiMjIyBJZGVudGlmeSBub2lzZSBJQ3MKQmFzZWQgb24gc3BhdGlhbCBkaXN0cmlidXRpb24sIHBvd2VyIHNwZWN0cmEgKGluY2x1ZGluZyBmQUxGRikgYW5kIElDQVNTTyBzdGFiaWxpdHkgZXN0aW1hdGVzLgoKQWxsZW4gZXQgYWwuLCAyMDExOgoKPjIuNS4xIFJTTiBzZWxlY3Rpb24KV2UgaWRlbnRpZmllZCBhIHN1YnNldCBvZiBDMSBjb21wb25lbnRzIGNvbnNpZGVyZWQgdG8gYmUgUlNOcyAoYXMgb3Bwb3NlZCB0byBwaHlzaW9sb2dpY2FsIGFydGlmYWN0cykgYnkgaW5zcGVjdGluZyB0aGUgYWdncmVnYXRlIFNNcyBhbmQgYXZlcmFnZSBwb3dlciBzcGVjdHJhIChzZWUgYmVsb3c7IEZpZ3VyZSAxLCBzdGVwIDMpLkZvdXIgdmlld2VycyByYXRlZCB0aGUgY29tcG9uZW50cyBmcm9tIDAgKGRlZmluaXRlIGFydGlmYWN0KSB0byAxIChjZXJ0YWluIFJTTikgYmFzZWQgb24gZXhwZWN0YXRpb25zIHRoYXQgUlNOcyBzaG91bGQgZXhoaWJpdCBwZWFrIGFjdGl2YXRpb25zIGluIGdyYXkgbWF0dGVyLCBsb3cgc3BhdGlhbCBvdmVybGFwIHdpdGgga25vd24gdmFzY3VsYXIsIHZlbnRyaWN1bGFyLCBtb3Rpb24sIGFuZCBzdXNjZXB0aWJpbGl0eSBhcnRpZmFjdHMsIGFuZCBUQ3MgZG9taW5hdGVkIGJ5IGxvdyBmcmVxdWVuY3kgZmx1Y3R1YXRpb25zIChDb3JkZXMgZXQgYWwuLCAyMDAwKS4gVG8gZmFjaWxpdGF0ZSBldmFsdWF0aW9uLCBzcGVjdHJhIHdlcmUgY2hhcmFjdGVyaXplZCB3aXRoIHR3byBtZXRyaWNzIHVzZWQgcHJldmlvdXNseSB0byBjbGFzc2lmeSBjb21wb25lbnRzIChSb2JpbnNvbiBldCBhbC4sIDIwMDkpOiBkeW5hbWljIHJhbmdlLCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBwZWFrIHBvd2VyIGFuZCBtaW5pbXVtIHBvd2VyIGF0IGZyZXF1ZW5jaWVzIHRvIHRoZSByaWdodCBvZiB0aGUgcGVhaywgYW5kIGxvdyBmcmVxdWVuY3kgdG8gaGlnaCBmcmVxdWVuY3kgcG93ZXIgcmF0aW8sIHRoZSByYXRpbyBvZiB0aGUgaW50ZWdyYWwgb2Ygc3BlY3RyYWwgcG93ZXIgYmVsb3cgMC4xMCBIeiB0byB0aGUgaW50ZWdyYWwgb2YgcG93ZXIgYmV0d2VlbiAwLjE1IGFuZCAwLjI1IEh6IChGaWd1cmUgMykuIAoKX0ZZSTpfIAoKPiBBTEZGIGlzIGRlZmluZWQgYXMgdGhlIHRvdGFsIHBvd2VyIHdpdGhpbiB0aGUgZnJlcXVlbmN5IHJhbmdlIGJldHdlZW4gMC4wMSBhbmQgMC4xIEh6LCBhbmQgdGh1cyBpbmRleGVzIHRoZSBzdHJlbmd0aCBvciBpbnRlbnNpdHkgb2YgTEZPLiBmL0FMRkYgaXMgZGVmaW5lZCBhcyB0aGUgcG93ZXIgd2l0aGluIHRoZSBsb3ctZnJlcXVlbmN5IHJhbmdlICgwLjAxLTAuMSBIeikgZGl2aWRlZCBieSB0aGUgdG90YWwgcG93ZXIgaW4gdGhlIGVudGlyZSBkZXRlY3RhYmxlIGZyZXF1ZW5jeSByYW5nZSwgYW5kIHJlcHJlc2VudHMgdGhlIHJlbGF0aXZlIGNvbnRyaWJ1dGlvbiBvZiBzcGVjaWZpYyBMRk8gdG8gdGhlIHdob2xlIGZyZXF1ZW5jeSByYW5nZSAoWnVvIGV0IGFsLiwgMjAxMCkuCgpZb3UgY2FuIGFsc28gdXNlIHRoZSAiQ29tcG9uZW50IExhYmVsbGVyIiB0b29sIGluIEdJRlQgdG8gc2VlIGhvdyBjbG9zZWx5IHlvdXIgSUNzIHJlc2VtYmxlIGVzdGFibGlzaGVkIGZ1bmN0aW9uYWwgUlNOcyB1c2luZyB0aGUgU3RhbmZvcmQgdGVtcGxhdGVzLiBGcm9tIHRoZSBHSUZUIG1hbnVhbDoKCj4gMy4xMi44IENvbXBvbmVudCBMYWJlbGVyCk9wdGlvbiBpcyBwcm92aWRlZCB0byBsYWJlbCBjb21wb25lbnRzIGdpdmVuIHRoZSB0ZW1wbGF0ZXMgb2YgaW50ZXJlc3QuIFdlIHByb3ZpZGUgdGVtcGxhdGVzIGluIGljYXRiL2ljYXRiX3RlbXBsYXRlcy9SU04uemlwIGZpbGUgYW5kIGRlc2NyaXB0aW9uIGFib3V0IHRoZSB0ZW1wbGF0ZXMgaW4gaWNhdGIvaWNhdGJfdGVtcGxhdGVzL1JTTi50eHQuIEVhY2ggY29tcG9uZW50IGlzIGNvcnJlbGF0ZWQgd2l0aCB0aGUgZ2l2ZW4gdGVtcGxhdGVzIGFuZCBiZXN0IHRlbXBsYXRlIGlzIHNlbGVjdGVkIGJhc2VkIG9uIHRoZSBtYXhpbXVtIGNvcnJlbGF0aW9uIHZhbHVlLgoKR29vZCBJQ3Mgc2hvdWxkIGhhdmUgaGlnaGVyIGNvcnJlbGF0aW9uIHZhbHVlcy4gTm90ZSB0aGF0IHRoZSBsYWJlbGxlciB0cmllcyB0byBjb3JyZWxhdGUgYWxsIG9mIHRoZSB2b3hlbHMgYWNyb3NzIHRoZSBicmFpbiBzbyB0aGUgY29ycmVsYXRpb24gdmFsdWVzIHdpbGwgbGlrZWx5IGJlIG1vZGVyYXRlLCBub3QgdmVyeSBoaWdoLgoKIyMjIFJlbW92ZSBub2lzZSBJQ3MKSSByZW1vdmVkIHRoZSBmb2xsb3dpbmcgSUNzOgoKKiBFeWViYWxsczogMjMsIDM4LCA0MCwgNDEsIDQ0CiogTW90aW9uOiAzLCA1LCAxMCwgMzUKKiBDU0Y6IDgsIDI2LCAzNCAobXkgbm90ZXMgYXJlIHVuY2xlYXIgaGVyZSAtIG1heSBoYXZlIHJlbW92ZWQgMiBhbmQgMjIgYXMgd2VsbCkKKiBPdGhlcjogMSwgNCwgMTIsIDE3LCAyMSwgMjcKCklmIEkgd2Fzbid0IHN1cmUsIEkgZXJyZWQgb24gdGhlIHNpZGUgb2YgY2F1dGlvbiBhbmQgbGVmdCBpdCBpbi4gSGVuY2UgbGVhdmluZyBpbiBzb21lIHRoYXQgSSBjb3VsZG4ndCB0ZWxsIGlmIHRoZXkgd2VyZSBwaHlzaW9sb2dpY2FsIGFydGlmYWN0IG9yIGxlZ2l0IHN1YmNvcnRpY2FsIHN0dWZmLiAKCkFmdGVyIHNlbGVjdGluZyB0aGUgY29tcG9uZW50cyB0byByZW1vdmUsIEdJRlQgd2lsbCByZXdyaXRlIHRoZSBkYXRhLiBBdCB0aGlzIHBvaW50LCBHSUZUIGNyZWF0ZXMgZ2VuZXJpYyBzdWJqZWN0IGFuZCBzZXNzaW9uIG51bWJlcnMgYmFzZWQgb24gaG93IG1hbnkgb2YgZWFjaCB0aGVyZSBhcmUgYW5kIHRoZSBvcmRlciBpbiB3aGljaCBpdCBlbmNvdW50ZXJzIHRoZSBmaWxlcyAoc28gZm9yIHRoZXNlIGRhdGEsIHN1YmplY3RzIGFyZSBsYWJlbGxlZCBgU3ViXzAwMWAgdGhyb3VnaCBgU3ViXzAzOGAsIGFuZCB0aGUgc2Vzc2lvbiBmb2xkZXIgdGhhdCB3YXMgYHR4QWAgaXMgbm93IGNhbGxlZCBgMWApLiBJIGNyZWF0ZWQgYSBmaWxlIHRoYXQgbGlua3MgdGhlIG9yaWdpbmFsIHN1YmplY3QgSURzIGFuZCBHSUZUIHJld3JpdHRlbiBkYXRhIElEcyAoYGtleV9saW5rLWdpZnRJRHMtc3R1ZHlJRHMuY3N2YCkgbG9jYXRlZCB3aXRoaW4gYC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvcmVzdWx0c19uby1zdWItMTQyX2Ryb3AtMy12b2xzX3JlZ3Jlc3NvcnNfaW50bm9ybV90eEEvZ2lmdF90eEFfX25vaXNlLWNvbXBzLXJlbW92ZWRfZGF0YWAuIFRoaXMgd2lsbCBiZSBpbXBvcnRhbnQgbGF0ZXIuCgpOZXcgZGF0YSB3ZXJlIHdyaXR0ZW4gdG8gYC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvcmVzdWx0c19uby1zdWItMTQyX2Ryb3AtMy12b2xzX3JlZ3Jlc3NvcnNfaW50bm9ybV90eEEvZ2lmdF90eEFfX25vaXNlLWNvbXBzLXJlbW92ZWRfZGF0YWAuCgojIyMgUnVuIElDQSAjMgpHSUZUIHdhcyBydW4gYSBzZWNvbmQgdGltZSBvbiB0aGUgbm9pc2UtY29tcG9uZW50cy1yZW1vdmVkIGRhdGEuIFJlc3VsdHMgYW5kIG91dHB1dHMgb2YgdGhpcyBhbmFseXNpcyBhcmUgbG9jYXRlZCB3aXRoaW4gYC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvcmVzdWx0c19uby1zdWItMTQyX2Ryb3AtMy12b2xzX3JlZ3Jlc3NvcnNfaW50bm9ybV90eEEvZ2lmdF90eEFfX25vaXNlLWNvbXBzLXJlbW92ZWRfcmVzdWx0c2AuIAoKUGFyYW1ldGVycyB1c2VkIGZvciB0aGUgUENBIGFuZCBJQ0EgZGF0YSByZWR1Y3Rpb24gc3RlcHMgYXJlIGRlc2NyaWJlZCBpbiBgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9hbmFseXNlcy1zcHItMjAxOS9yZXN1bHRzX25vLXN1Yi0xNDJfZHJvcC0zLXZvbHNfcmVncmVzc29yc19pbnRub3JtX3R4QS9naWZ0X3R4QV9fbm9pc2UtY29tcHMtcmVtb3ZlZF9yZXN1bHRzL2dpZnRfdHhBX25vaXNlY29tcHNyZW1vdmVkX19pY2FfcGFyYW1ldGVyX2luZm8ubWF0YC4gVGhpcyB0aW1lLCBJIGFza2VkIGl0IHRvIHVzZSAzMCBhcyB0aGUgbnVtYmVyIG9mIElDcyB2cy4gZXN0aW1hdGluZyBmcm9tIHRoZSBkYXRhLgoKIyMjIFBpY2sgSUNzCkJhc2VkIG9uIHRoZSBzYW1lIGNyaXRlcmlhIGFzIHVzZWQgdG8gZGV0ZXJtaW5lIG5vaXNlIGNvbXBvbmVudHMgKHN0YWJpbGl0eSwgc2VwYXJhdGlvbiwgYW5kIG90aGVyIElDQVNTTyBtZXRyaWNzLCBzcGF0aWFsIGRpc3RyaWJ1dGlvbiwgcG93ZXIsIGZBTEZGKSwgSSBzZWxlY3RlZCBzaXggSUNzIHRvIGZvY3VzIG9uLgoKSSBkaWQgbm90aWNlIHRoYXQgdGhlIGZBTEZGIHNjb3JlcyBvdmVyYWxsIHdlcmUgbG93ZXIgdGhhbiB0aG9zZSBkZXNjcmliZWQgaW4gdGhlIEFsbGVuIGV0IGFsLiAoMjAxMSkgcGFwZXIsIGFuZCBkZWNyZWFzZWQgZnJvbSB0aG9zZSBzZWVuIGluIHRoZSBmaXJzdCBydW4gb2YgdGhlIElDQS4gQWxsIG9mIHRoZSBiZWxvdyBjb21wb25lbnRzIGhhZCBnb29kIHN0YWJpbGl0eSBhbmQgc2VwYXJhdGlvbi4KCiogSUMxOiBMYWJlbGxlZCBhcyBwcmVjdW5ldXMgbmV0d29yaywgbWFqb3JpdHkgc2VlbXMgdG8gYmUgaW4gY3VuZXVzLCByID0gLjMxIHdpdGggdGhlIFJOUyB0ZW1wbGF0ZSBwcmVjdW5ldXMgbmV0d29yaywgZkFMRkYgPSAzLjQuCiogSUM1OiBMYWJlbGxlZCBhcyBETU4vbVBGQy9QQ0MsIHIgPSAuMjYsIGZBTEZGID0gMi44OS4gCiogSUM5OiBMYWJlbGxlZCBhcyBSIENFTi9kbFBGQywgciA9IC4yNywgZkFMRkYgPSAyLjE3LgoqIElDMTI6IExhYmVsbGVkIGFzIERNTi9NVEwsIHIgPSAuMzksIGZBTEZGID0gMi44MS4KKiBJQzIwOiBMYWJlbGxlZCBhcyBETU4vbVBGQy9QQ0MsIHIgPSAuNDAsIGZBTEZGID0gMS4yNS4KCkkgYWxzbyBsb29rZWQgYXQgSUMyLCB3aGljaCB3YXMgbGFiZWxsZWQgYXMgU04vYUkvZEFDQyBidXQgd2Fzbid0IHRvbyBjb252aW5jZWQgaXQgd2FzIHRoYXQgc28gZHJvcHBlZCBpdCAocG90ZW50aWFsIE1SIGFydGlmYWN0PykuIE5ldXJvc3ludGggZGVjb2RlciBzYXlzIHRoZSB0IG1hcCBpcyBtb3N0IHNpbWlsYXIgdG8gcHJpbWFyeSBtb3RvciBjb3J0ZXggYW5kIGEgbG90IG9mIHNvbWF0b3NlbnNvcnkgYW5kIG1vdmVtZW50LXJlbGF0ZWQgdGVybXMuIF8qKkZvciBmdXR1cmUgYW5hbHlzZXMsIHNpbmNlIHRoZXJlIHdhcyBubyBTTiBJQyB0aGF0IHdhcyBpZGVudGlmaWVkLCBtYXkgd2FudCB0byBkbyBhIHNlbWktYmxpbmQgSUNBIHVzaW5nIHRoZSBTTiB0ZW1wbGF0ZSBmb3Igc3BhdGlhbCBjb25zdHJhaW50LioqXwoKVGhlcmUgd2VyZSBhIG51bWJlciBvZiBvdGhlciBjb21wb25lbnRzIHRoYXQgc2VlbWVkIGRlY2VudCBhbmQgY29ycmVsYXRlZCB3aXRoIHNlbnNvcmltb3RvciwgbGFuZ3VhZ2UsIGF1ZGl0b3J5LCB2aXN1YWwsIGFuZCB2aXN1b3NwYXRpYWwgbmV0d29ya3MuIAoKVGhlIGZhY3QgdGhhdCBHSUZUIGlkZW50aWZpZWQgbXVsdGlwbGUgSUNzIHJlbGF0ZWQgdG8gYSBzaW5nbGUgZ2l2ZW4gbmV0d29yayAoZS5nLiwgRE1OLCB2aXN1YWwpIHN1Z2dlc3RzIHRoYXQgSSBwcm9iYWJseSBjb3VsZCBoYXZlIGdvbmUgZG93biB0byAyMCBzbyB0aGF0IHRoZXJlIHdhc24ndCBhcyBtdWNoIHNwbGl0dGluZyBvZiBuZXR3b3Jrcy4gT1RPSCwgaXQncyBpbnRlcmVzdGluZyB0byBzZWUgaG93IHRoZSBkaWZmZXJlbnQgRE1OIGNvbXBvbmVudHMgcmVsYXRlIHRvIGRpZmZlcmVudCBtZW50YWwgZnVuY3Rpb25zIChwZXIgY29tcGFyaXNvbiB0byBOZXVyb3N5bnRoIG1ldGEtYW5hbHl0aWMgbWFwcykgZ2l2ZW4gdGhhdCB0aGVyZSBpcyBldmlkZW5jZSBmb3IgcGFyY2VsbGF0aW9uIG9mIHRoZXNlIGxhcmdlLXNjYWxlIG5ldHdvcmtzLgoKIyMgU1BNIHN0YXRzCllvdSBjYW4gZG8gdGhpcyBlaXRoZXIgdmlhIHRoZSAiU1BNIFN0YXRzIiBidXR0b24gaW4gR0lGVCBvciBqdXN0IGZpcmUgdXAgU1BNLiBUaGUgZmlyc3Qgc3RlcCBpcyB0byBydW4gYSBvbmUtc2FtcGxlIFQgdGVzdCB3aGljaCB0ZXN0cyB0aGUgZWZmZWN0IGFnYWluc3QgbnVsbC4gVGhpcyBjcmVhdGVzIGEgdGhyZXNob2xkZWQgbWFzayB0aGF0IGNhbiBiZSB1c2VkIHRvIG1hc2sgc3Vic2VxdWVudCBhbmFseXNlcyB0byBjb25zdHJhaW4gdGVzdHMgdG8ganVzdCB0aG9zZSB2b3hlbHMgd2hlcmUgYSBwYXJ0aWN1bGFyIGNvbXBvbmVudCBzaG93ZWQgc3VwcmEtdGhyZXNob2xkIHNpZ25hbC4gXypOb3RlOiB5b3UgbWF5IG9yIG1heSBub3Qgd2FudCB0byB1c2UgdGhlIG1hc2sgaW4gbGF0ZXIgYW5hbHlzZXMuIEl0IGRlcGVuZHM6IGlmIHlvdSB3YW50IHRvIGxvb2sganVzdCBmb3IgaW50cmFuZXR3b3JrIGVmZmVjdHMsIHRoZW4gdXNlIGl0LiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gYXJlYXMgb3V0c2lkZSB0aGUgSUMvbmV0d29yaywgdGhlbiBkb24ndC4qXwoKVGhlIG5leHQgc3RlcCB3YXMgYSB0d28tc2FtcGxlIHQgdGVzdCBvbiB0aGUgaW5kaXZpZHVhbCBpbWFnZXMgZm9yIGVhY2ggY29tcG9uZW50IHdpdGggbWVhbiBmcmFtZXdpc2UgZGlzcGxhY2VtZW50LCBhZ2UsIHNleCwgdGltZSBzaW5jZSBkZWF0aCwgcHN5Y2hvYWN0aXZlIG1lZGljYXRpb25zIChjb2RlZCAwLzEpLCBhbmQgQkRJIHNjb3JlIGluY2x1ZGVkIGFzIGNvdmFyaWF0ZXMuIFRoZSB0IHRlc3QgY29tcGFyZWQgQ0cgYW5kIE5DRy4gTm90ZSB0aGF0IHZveGVsd2lzZSB0ZXN0cyBhcmUgdGVzdGluZyBmb3IgZ3JvdXAgZGlmZmVyZW5jZXMgaW4gdGhlIHNwYXRpYWwgbWFwcy4KCiMjIyBSZXN1bHRzCkF0IG15IGV4cGxvcmF0b3J5IF9wXyA8IC4wMDEgbGV2ZWwgdGhlcmUgd2VyZSBhIG51bWJlciBvZiB0aW55IGNsdXN0ZXJzIHRoYXQgc2hvd2VkIHVwIGluIG9uZSBvciBib3RoIGNvbnRyYXN0cy4gTm90IHRvbyBpbnRlcmVzdGluZy4gSG93ZXZlciwgdGhlIENHID4gTkNHIGNvbnRyYXN0IGZvciBJQzEgZGlkIHJldmVhbCBhIHNtYWxsIGNsdXN0ZXIgaW4gdGhlIGxlZnQgZG9yc2FsIHByZWNlbnRyYWwgZ3lydXMgKC0yMyAtMjAgNzUsIF9rXyA9IDE3KSB0aGF0IHdhcyBzaWduaWZpY2FudGx5IG1vcmUgY29ycmVsYXRlZCB3aXRoIHRoZSBJQzEgdGltZWNvdXJzZSAoSSB0aGluaz8gbm90IDEwMCUgY2xlYXIgb24gaW50ZXJwcmV0YXRpb24pIGluIHRoZSBDRyBncm91cCB0aGFuIHRoZSBOQ0cgZ3JvdXAsIF9UXyA9IDYuODMsIF9aXyA9IDUuMjYsIHZveGVsd2lzZSBfcF8gdW5jb3JyZWN0ZWQgPSA8IC4wMDEsIF9wRkRSXyA9IC4wMjgsIF9wRldFXyA9IC4wMDQgKC4wMjcgZm9yIGNsdXN0ZXJ3aXNlKS4gCgojIyMjIENHID4gTkNHOiBwcmVjZW50cmFsIGd5cnVzClRoZSBwcmVjZW50cmFsIGd5cnVzIGlzIGludm9sdmVkIGluIG1vdmVtZW50IGFuZCBtb3RvciBpbWFnZXJ5LCBidXQgbWF5IGFsc28gcGxheSBhIHJvbGUgaW4gcGVyc29uLXNwZWNpZmljIHBhdHRlcm5zIG9mIGJyYWluIGFjdGl2aXR5IChUaG9ybnRvbiAmIE1pdGNoZWxsLCAyMDE3OyBjb29yZGluYXRlcyBub3QgbGlzdGVkKSBhbmQgcmV3YXJkIG91dGNvbWUgaW4gYWRkaWN0aW9uIChmTVJJIG1ldGEgYW5hbHlzaXM6IEx1aWp0ZW4gZXQgYWwuLCAyMDE3IEpBTUE7IGNvb3JkaW5hdGVzIGV4dHJlbWVseSBjbG9zZSB0byBvdXJzIGZvciB0aGUgYWRkaWN0ZWQgPiBjb250cm9sIGNvbnRyYXN0LCBzZWUgdGhlaXIgdGFibGUgZTUpLgoKIyBtYXJzYmFyIChST0kgYW5hbHlzaXMpClRvIGxvb2sgZnVydGhlciBhdCB0aGUgcHJlY2VudHJhbCBneXJ1cywgSSB1c2VkIG1hcnNiYXIgdG8gY3JlYXRlIGEgZnVuY3Rpb25hbCBST0kgKGEgbWFzayBvZiB0aGUgY2x1c3RlcikgYW5kIGV4dHJhY3QgcGFyYW1ldGVyIGVzdGltYXRlcyBwZXIgc3ViamVjdC4gVGhlbiByZWFkIHRoZXNlIGRhdGEgaW50byBSIHRvIGNvbmR1Y3Qgc3Vic2VxdWVudCBhbmFseXNlcy4KCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJSLm1hdGxhYiIpCmxpYnJhcnkoUi5tYXRsYWIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShwc3ljaCkKCiMgcmVhZCBtYXQgZmlsZSB3aXRoIGJldGEgd2VpZ2h0cyBmcm9tIENHID4gTkNHIGNvbnRyYXN0IGluIHRoZSBwcmVjZW50cmFsIGd5cnVzIGNsdXN0ZXIgZnJvbSBJQzEKcm9pZGF0YSA8LSByZWFkTWF0KCIvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L3Jlc3VsdHNfbm8tc3ViLTE0Ml9kcm9wLTMtdm9sc19yZWdyZXNzb3JzX2ludG5vcm1fdHhBL2dpZnRfdHhBX19ub2lzZS1jb21wcy1yZW1vdmVkX3Jlc3VsdHMvZ2lmdF90eEFfbm9pc2Vjb21wc3JlbW92ZWRfX21hcnNiYXJfcm9pX3Jlc3VsdHMvY2dfbmNnXy0yM18tMjBfNzVfY29tcDAxX2JldGFzLm1hdCIsIDEpCgpiZXRhcyA8LSBhcy50aWJibGUocm9pZGF0YVtbMV1dW1syXV1bWzFdXSkgJT4lIHJlbmFtZShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgPSBWMSkKYmV0YV9zdWIgPC0gYXMudGliYmxlKHJvaWRhdGFbWzFdXVtbMV1dW1sxXV0pICU+JSByZW5hbWUoZm5hbWUgPSBWMSkKCmJldGFzIDwtYmluZF9jb2xzKGJldGFfc3ViLCBiZXRhcykgJT4lIG11dGF0ZShmbmFtZSA9IHN0cl9yZXBsYWNlKGZuYW1lLCAiL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9hbmFseXNlcy1zcHItMjAxOS9yZXN1bHRzX25vLXN1Yi0xNDJfZHJvcC0zLXZvbHNfcmVncmVzc29yc19pbnRub3JtX3R4QS9naWZ0X3R4QV9fbm9pc2UtY29tcHMtcmVtb3ZlZF9yZXN1bHRzL2dpZnRfdHhBX25vaXNlY29tcHNyZW1vdmVkX19zY2FsaW5nX2NvbXBvbmVudHNfZmlsZXMvc3ViLSIsICJmaWxlIikpICU+JSBtdXRhdGUoZm5hbWUgPSBzdHJfcmVwbGFjZShmbmFtZSwgIl9jb21wb25lbnRfaWNhX3Nlcy0xXy5uaWkiLCAiIikpCgprZXkgPC0gcmVhZF9jc3YoIi9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvYW5hbHlzZXMtc3ByLTIwMTkvcmVzdWx0c19uby1zdWItMTQyX2Ryb3AtMy12b2xzX3JlZ3Jlc3NvcnNfaW50bm9ybV90eEEvZ2lmdF90eEFfX25vaXNlLWNvbXBzLXJlbW92ZWRfcmVzdWx0cy9rZXlfbGluay1naWZ0SURzLXN0dWR5SURzLmNzdiIpCgpiZXRhcyA8LSBsZWZ0X2pvaW4oYmV0YXMsIGtleSwgYnk9ImZuYW1lIikKCiMgbm93IHJlYWR5IHRvIG1lcmdlIGJldGFzIHdpdGggZGF0YQpkYXRhIDwtIHJlYWRSRFMoIn4vRHJvcGJveC9HTEFTUyBMYWIvT1QgU3R1ZHkvZGF0YS9tYXN0ZXItZGF0YXNldC9vdC1mbXJpX21hc3Rlci1kYXRhc2V0XzAyMDcxOS5yZHMiKQoKZGF0YV9zcHIxOSA8LSBsZWZ0X2pvaW4oZGF0YSwgYmV0YXMsIGJ5PSJJRCIpCmBgYAoKQ29ycmVsYXRpb25zOgpgYGB7cn0KIyBmaXJzdCB1c2VkIFlTTCBpdGVtIDEwIGFzIHRoZSBzb3J0IG9mIHByb3RvdHlwaWMgaW5kZXggb2YgeWVhcm5pbmcuLgpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzEwKSAjICJGZWVsaW5nIG9mIHdhbnRpbmcgYmFjayBpcyBzbyBzdHJvbmcgaXQgaXMgaW5kZXNjcmliYWJsZS4uLiIKCiMgdGhlbiBsb29rZWQgYXQgWVNMIHRvdGFsCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfeXNsKSAjIG5vdCBzaWduaWZpY2FudGx5IGNvcnJlbGF0ZWQKYGBgCgpBdCBNRk8ncyBzdWdnZXN0aW9uLCBsb29rZWQgc2VwYXJhdGVseSBhdCBhZmZlY3RpdmUgYW5kIGNvZ25pdGl2ZSBhc3BlY3RzIG9mIHllYXJuaW5nOgoKYGBge3J9CiMgc3Vic2V0IFlTTCBpbnRvIGNvZ25pdGl2ZSBhbmQgYWZmZWN0aXZlIHN1YnNjYWxlcyBhbmQgY2FsY3VsYXRlIHRvdGFscwp5c2xfY29nIDwtIHN1YnNldChkYXRhX3NwcjE5LCBzZWxlY3Q9YygieXNsXzIiLCJ5c2xfNCIsICJ5c2xfOCIsICJ5c2xfMTEiLCAieXNsXzE0IikpCmRhdGFfc3ByMTkkdG90X3lzbF9jb2cgPC0gcm93U3Vtcyh5c2xfY29nLCBuYS5ybT1UUlVFKSAKZGVzY3JpYmUoZGF0YV9zcHIxOSR0b3RfeXNsX2NvZykKCnlzbF9hZmYgPC0gc3Vic2V0KGRhdGFfc3ByMTksIHNlbGVjdD1jKCJ5c2xfNiIsInlzbF83IiwgInlzbF8xMCIsICJ5c2xfMTYiLCAieXNsXzIxIikpCmRhdGFfc3ByMTkkdG90X3lzbF9hZmYgPC0gcm93U3Vtcyh5c2xfYWZmLCBuYS5ybT1UUlVFKSAKZGVzY3JpYmUoZGF0YV9zcHIxOSR0b3RfeXNsX2FmZikKCiMgaXMgdGhlIHJlbGF0aW9uc2hpcCB3aXRoIHByZWNlbnRyYWwgZ3lydXMgc3BlY2lmaWMgdG8gYWZmZWN0aXZlIGl0ZW1zLCBvciBub3Q/CmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfeXNsX2NvZykgIyByID0gLjMxLCBwID0gLjA2CmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfeXNsX2FmZikgIyByID0gLjQwLCBwID0gLjAxCmBgYAoKQXJlIHRoZXNlIGNvcnJlbGF0aW9ucyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXI/CgpGb3IgdGhlIGJlbG93IHJlc3VsdHM6CjxsaT5OdWxsIGh5cG90aGVzaXMgaXMgdGhhdCB0aGUgdHJ1ZSBkaWZmZXJlbmNlIGluIG92ZXJsYXBwaW5nIGNvcnJlbGF0aW9ucyBJUyBlcXVhbCB0byAwLgo8bGk+QWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZSB0cnVlIGRpZmZlcmVuY2UgaW4gY29ycmVsYXRpb25zIElTIE5PVCBlcXVhbCB0byAwLgo8bGk+Q29uY2x1c2lvbnMgYmFzZWQgb24gU3RlaWdlcidzICgxOTgwKSA8aT56PC9pPiBhbmQgWm91J3MgKDIwMDcpIGNvbmZpZGVuY2UgaW50ZXJ2YWwuCgpgYGB7cn0KbGlicmFyeShjb2NvcikKCiMgY29ycmVsYXRpb24gb2YgcG9zdGNlbnRyYWwgZ3lydXMgYmV0YXMgKGopIGFuZCBZU0wtY29nIChrKToKamsgPC0gY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF95c2xfY29nKSAjIHIgPSAuMzEsIHAgPSAuMDU4CgojIGNvcnJlbGF0aW9uIG9mIHBvc3RjZW50cmFsIGd5cnVzIGJldGFzIChqKSBhbmQgWVNMLWFmZiAoaCk6CmpoIDwtIGNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfeXNsX2FmZikgIyByID0gLjQwLCBwID0gLjAxMgoKIyBjb3JyZWxhdGlvbiBvZiBZU0wtY29nIChrKSBhbmQgWVNMLWFmZiAoaCksIGRyb3BwaW5nIEQxNDIgJiBEMTQ3OgpkYXRhX3NwcjE5IDwtIGZpbHRlcihkYXRhX3NwcjE5LCAhZ3JlcGwoIkQxNDJ8RDE0NyIsSUQpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKa2ggPC0gY29yci50ZXN0KGRhdGFfc3ByMTkkdG90X3lzbF9jb2csIGRhdGFfc3ByMTkkdG90X3lzbF9hZmYpICMgciA9IC44OSwgcCA8IC4wMDEKCmNvY29yLmRlcC5ncm91cHMub3ZlcmxhcChyLmprPSsoamtbWzFdXSksIHIuamg9KyhqaFtbMV1dKSwgci5raD0rKGtoW1sxXV0pLCBuPTM4LCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIiwgYWxwaGE9MC4wNSwgY29uZi5sZXZlbD0wLjk1LCBudWxsLnZhbHVlPTApCmBgYApOdWxsIGh5cG90aGVzaXMgcmV0YWluZWQ6IHRoZSBjb3JyZWxhdGlvbnMgb2YgWVNMLUFmZiBhbmQgWVNMLUNvZyB3aXRoIHRoZSBwcmVjZW50cmFsIGd5cnVzIHBhcmFtZXRlciBlc3RpbWF0ZXMgYXJlIE5PVCBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXIuIAoKSG93ZXZlciwgSSByZWFsaXplZCB0aGF0IGNvcnJlbGF0aW5nIHRoZSBZU0wgYW5kIGJldGEgd2VpZ2h0cyBpcyBhIGNpcmN1bGFyIGFuYWx5c2lzOiAoMSkgSUNHIGFuZCBZU0wgdG90YWxzIGFyZSBoaWdobHkgY29ycmVsYXRlZCBhdCAuODQgKHAgPCAuMDAxKSwgKDIpIHRoZSBJQ0cgd2FzIHVzZWQgdG8gZGV0ZXJtaW5lIENHIHZzLiBOQ0cgZ3JvdXAsIHNvICgzKSB0aGUgdm94ZWxzIHRoYXQgZW1lcmdlZCBpbiB0aGUgdCB0ZXN0IGZvciBncm91cCBhcmUgYmlhc2VkIHRvd2FyZHMgYmVpbmcgcmVsYXRlZCB0byBZU0wgdG90YWxzLiBUbyBhY2NvdW50IGZvciB0aGlzLCBuZWVkIHRvIGluY2x1ZGUgYHRvdF9pY2dgIGluIHRoZSBsaW5lYXIgbW9kZWwuCgpJIGFsc28gaW5jbHVkZWQgQklTQkFTIFJld2FyZCBSZXNwb25zaXZlbmVzcyBpbiB0aGUgbW9kZWwgdG8gdHJ5IHRvIGNvbnRyb2wgZm9yIG92ZXJhbGwgdHJhaXQgYXBwcm9hY2ggYmlhcy4gU2VsZWN0ZWQgQklTQkFTLVJSIGJlY2F1c2UgaXQgd2FzIHRoZSBpbmRleCBvZiBhcHByb2FjaCBiaWFzIHRoYXQgZGlmZmVyZWQgc2lnbmlmaWNhbnRseSBiZXR3ZWVuIE5DRyBhbmQgQ0cgZ3JvdXBzLCB3aGVyZWFzIERyaXZlIGFuZCBGdW4tU2Vla2luZyBkaWQgbm90IChCSVMgc3Vic2NhbGUgYWxzbyBkaWZmZXJlZCBiZXR3ZWVuIGdyb3Vwcywgd2l0aCBDRyBiZWluZyBoaWdoZXIgaW4gQklTIHRoYW4gTkNHKS4gCgpgYGB7cn0KIyBjb21wdXRlIGJpYXMgc2NvcmVzIGZyb20gZ0FBVCBSVCBkYXRhIGFzIGluZGV4IG9mIGJlaGF2aW9yYWwgYXBwcm9hY2gvYXZvaWQgYmlhcyBmb3IgZWFjaCBzdGltdWx1cyBjYXRlZ29yeQojIHBvc2l0aXZlIHNjb3JlcyA9IGFwcHJvYWNoIGJpYXMsIG5lZ2F0aXZlIHNjb3JlcyA9IGF2b2lkIGJpYXMKZGF0YV9zcHIxOSRnQUFUX2JpYXNfc3BvdXNlX0EgPC0gZGF0YV9zcHIxOSRnQUFUX1JUX3Nwb3VzZV9wdXNoX0EgLSBkYXRhX3NwcjE5JGdBQVRfUlRfc3BvdXNlX3B1bGxfQQpkYXRhX3NwcjE5JGdBQVRfYmlhc193aG90b19BIDwtIGRhdGFfc3ByMTkkZ0FBVF9SVF93aG90b19wdXNoX0EgLSBkYXRhX3NwcjE5JGdBQVRfUlRfd2hvdG9fcHVsbF9BCmRhdGFfc3ByMTkkZ0FBVF9iaWFzX3N0cmFuZ2VyX0EgPC0gZGF0YV9zcHIxOSRnQUFUX1JUX3N0cmFuZ2VyX3B1c2hfQSAtIGRhdGFfc3ByMTkkZ0FBVF9SVF9zdHJhbmdlcl9wdWxsX0EKZGF0YV9zcHIxOSRnQUFUX2JpYXNfZGVhdGhfQSA8LSBkYXRhX3NwcjE5JGdBQVRfUlRfZGVhdGhfcHVzaF9BIC0gZGF0YV9zcHIxOSRnQUFUX1JUX2RlYXRoX3B1bGxfQQpkYXRhX3NwcjE5JGdBQVRfYmlhc19uZXV0cmFsX0EgPC0gZGF0YV9zcHIxOSRnQUFUX1JUX25ldXRyYWxfcHVzaF9BIC0gZGF0YV9zcHIxOSRnQUFUX1JUX25ldXRyYWxfcHVsbF9BCgojIHQgdGVzdHMKdC50ZXN0KGRhdGFfc3ByMTkkdG90X2Jpc2Jhc19iYXNyciB+IGRhdGFfc3ByMTkkZ3JvdXApICMgQ0cgPCBOQ0csIHAgPSAuMDI3CnQudGVzdChkYXRhX3NwcjE5JHRvdF9iaXNiYXNfYmFzZHIgfiBkYXRhX3NwcjE5JGdyb3VwKSAjIG5vIHNpZyBkaWZmCnQudGVzdChkYXRhX3NwcjE5JHRvdF9iaXNiYXNfYmFzZnVuIH4gZGF0YV9zcHIxOSRncm91cCkgIyBubyBzaWcgZGlmZgp0LnRlc3QoZGF0YV9zcHIxOSR0b3RfYmlzYmFzX2JpcyB+IGRhdGFfc3ByMTkkZ3JvdXApICMgQ0cgPiBOQ0csIHAgPSAuMDQ0CnQudGVzdChkYXRhX3NwcjE5JGdBQVRfYmlhc19kZWF0aF9BIH4gZGF0YV9zcHIxOSRncm91cCkgIyBubyBzaWcgZGlmZgp0LnRlc3QoZGF0YV9zcHIxOSRnQUFUX2JpYXNfbmV1dHJhbF9BIH4gZGF0YV9zcHIxOSRncm91cCkgIyBubyBzaWcgZGlmZgp0LnRlc3QoZGF0YV9zcHIxOSRnQUFUX2JpYXNfc3BvdXNlX0EgfiBkYXRhX3NwcjE5JGdyb3VwKSAjIG5vIHNpZyBkaWZmCnQudGVzdChkYXRhX3NwcjE5JGdBQVRfYmlhc19zdHJhbmdlcl9BIH4gZGF0YV9zcHIxOSRncm91cCkgIyBubyBzaWcgZGlmZgp0LnRlc3QoZGF0YV9zcHIxOSRnQUFUX2JpYXNfd2hvdG9fQSB+IGRhdGFfc3ByMTkkZ3JvdXApICMgbm8gc2lnIGRpZmYKYGBgCgpJbnRlcmVzdGluZ2x5LCB0aGUgTkNHIGdyb3VwIGlzIGFjdHVhbGx5IGhpZ2hlciBpbiBSZXdhcmQgUmVzcG9uc2l2ZW5lc3MgdGhhbiBDRyBvbiBhdmVyYWdlLiAgCgpgYGB7cn0KcGxvdChkYXRhX3NwcjE5JHRvdF9iaXNiYXNfYmFzcnIgfiBkYXRhX3NwcjE5JGdyb3VwKQpgYGAKCiMjIFJlZ3Jlc3Npb24gbW9kZWxzCmBgYHtyfQojIFlTTCB0b3RhbAphIDwtIGxtKHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cyB+IHRvdF9pY2cgKyB0b3RfYmlzYmFzX2Jhc3JyLCBkYXRhID0gZGF0YV9zcHIxOSkKYiA8LSBsbShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgfiB0b3RfaWNnICsgdG90X2Jpc2Jhc19iYXNyciArIHRvdF95c2wsIGRhdGEgPSBkYXRhX3NwcjE5KQpzdW1tYXJ5KGEpCnN1bW1hcnkoYikKYW5vdmEoYSxiKQoKIyBZU0wgLSBhZmZlY3RpdmUgaXRlbXMKYyA8LSBsbShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgfiB0b3RfaWNnICsgdG90X2Jpc2Jhc19iYXNyciArIHRvdF95c2xfYWZmLCBkYXRhID0gZGF0YV9zcHIxOSkKc3VtbWFyeShjKQphbm92YShhLGMpCgojIFlTTCAtIGNvZ25pdGl2ZSBpdGVtcwpkIDwtIGxtKHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cyB+IHRvdF9pY2cgKyB0b3RfYmlzYmFzX2Jhc3JyICsgdG90X3lzbF9jb2csIGRhdGEgPSBkYXRhX3NwcjE5KQpzdW1tYXJ5KGQpCmFub3ZhKGEsZCkKCmBgYApNb2RlbCBgY2AsIHdoaWNoIGluY2x1ZGVzIFlTTC1BZmZlY3RpdmUgKGJ1dCBub3QgWVNMLUNvZ25pdGl2ZSBvciBZU0wgdG90YWwpIHNjb3JlcywgaXMgcHJlZGljdGl2ZSBvZiBwcmVjZW50cmFsIGd5cnVzIGFjdGl2YXRpb24gY29udHJvbGxpbmcgZm9yIG92ZXJhbGwgZ3JpZWYgc2V2ZXJpdHkgYW5kIHJld2FyZCByZXNwb25zaXZlbmVzcy4gCgojIyBSZWdyZXNzaW9uIHBsb3QKYGBge3J9CiMgbWFrZSBhIGZ1bmN0aW9uIHRvIHBsb3QgYSByZWdyZXNzaW9uIGxpbmUgdy9zdGF0cyBmcm9tIGEgbW9kZWwgdy9tdWx0aXBsZSBwcmVkaWN0b3JzCiMgZ290IHRoaXMgZnJvbSBodHRwczovL3Nlam9obnN0b24uY29tLzIwMTIvMDgvMDkvYS1xdWljay1hbmQtZWFzeS1mdW5jdGlvbi10by1wbG90LWxtLXJlc3VsdHMtaW4tci8KIyBub3RlIHRoYXQgaWYgeW91IHdhbnQgdG8gZ3JhcGggb3RoZXIgcHJlZGljdG9ycywgeW91IGhhdmUgdG8gY2hhbmdlIHRoZSBpbmRleGluZyB0byByZWZsZWN0IHRoYXQgY29lZmZpY2llbnQgCmdncGxvdFJlZ3Jlc3Npb24gPC0gZnVuY3Rpb24gKGZpdCkgewpnZ3Bsb3QoZml0JG1vZGVsLCBhZXNfc3RyaW5nKHggPSBuYW1lcyhmaXQkbW9kZWwpWzRdLCB5ID0gbmFtZXMoZml0JG1vZGVsKVsxXSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAiYmx1ZSIpICsKICBsYWJzKHRpdGxlID0gcGFzdGUoIlJeMiA9ICIsc2lnbmlmKHN1bW1hcnkoZml0KSRyLnNxdWFyZWQsIDIpLAogICAgICAgICAgICAgICAgICAgICAiXG5JbnRlcmNlcHQgPSAiLHNpZ25pZihmaXQkY29lZltbMV1dLDMgKSwKICAgICAgICAgICAgICAgICAgICAgIlxuU2xvcGUgPSIsc2lnbmlmKGZpdCRjb2VmW1s0XV0sIDIpLAogICAgICAgICAgICAgICAgICAgICAiXG5wID0iLHNpZ25pZihzdW1tYXJ5KGZpdCkkY29lZls0LDRdLCAyKSkpICsKICAgIHhsYWIoIlllYXJuaW5nIGluIFNpdHVhdGlvbnMgb2YgTG9zcyAtIEFmZmVjdGl2ZSBTdWJzY2FsZSIpICsKICAgIHlsYWIoIlJPSSBhdCAtMjMsIC0yMCwgNzUgKGJldGFzKSIpCn0KCnN1bW1hcnkoYykKZ2dwbG90UmVncmVzc2lvbihjKQoKZ2dwbG90KGMsIGFlcyh5ID0gcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCB4ID0gdG90X3lzbF9hZmYpKSArIAogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIpCgpnZ3NhdmUoZ2dwbG90UmVncmVzc2lvbihjKSkKZ2dzYXZlKCJ+L0Ryb3Bib3gvRGlzc2VydGF0aW9uL1NQUi0yMDE5LXBvc3Rlci9yZWdyZXNzaW9uX3lzbC1hZmYucG5nIiwgcGxvdCA9IGxhc3RfcGxvdCgpLCBkZXZpY2UgPSBOVUxMLCBwYXRoID0gTlVMTCwKICBzY2FsZSA9IDEsIHdpZHRoID0gOCwgdW5pdHMgPSBjKCJpbiIpLCBkcGkgPSA2MDApCmBgYAoKIyMgV29yZGNsb3VkCkZvbGxvd3MgdGhlIGFwcHJvYWNoIGZyb20gdGhlIEJldGhsZWhlbSBldCBhbC4gKDIwMTcpIG94eXRvY2luIElDQSBwYXBlcjogCj4gICJUbyBiZXR0ZXIgY2hhcmFjdGVyaXplIHRoZSBjb21wb25lbnRzIHNob3dpbmcgYW4gb3h5dG9jaW4tcmVsYXRlZCBlZmZlY3Qgb24gY29ubmVjdGl2aXR5IHdlIHVzZWQgdGhlIGRlY29kZXIgZnVuY3Rpb24gaW4gTmV1cm9TeW50aDM0IHRvIGNvbXBhcmUgdGhlIHdob2xlLWJyYWluIGNvbXBvbmVudCBtYXBzIHdpdGggbGFyZ2Utc2NhbGUgYXV0b21hdGVkIG1ldGEtYW5hbHlzaXMgbWFwcyB3aXRoaW4gTmV1cm9TeW50aC4gVGhlIHRvcCAxMDAgdGVybXMgKGV4Y2x1ZGluZyB0ZXJtcyBmb3IgYnJhaW4gcmVnaW9ucykgcmFua2VkIGJ5IHRoZSBjb3JyZWxhdGlvbiBzdHJlbmd0aCBiZXR3ZWVuIHRoZSBjb21wb25lbnQgbWFwIGFuZCB0aGUgbWV0YS1hbmFseXRpYyBtYXAgd2VyZSB2aXN1YWxpemVkIGFzIGEgd29yZCBjbG91ZCB1c2luZyB0aGUgd29yZGNsb3VkIGxpYnJhcnkgaW4gUiwgd2l0aCB0aGUgc2l6ZSBvZiB0aGUgZm9udCBzY2FsZWQgYnkgY29ycmVsYXRpb24gc3RyZW5ndGguIgoKVG8gZG8gdGhpcywgSSBmaXJzdCB1cGxvYWRlZCB0aGUgY29tcG9uZW50IHNwYXRpYWwgbWFwcyB0byBOZXVyb3N5bnRoIGFuZCB1c2VkIHRoZSAiZGVjb2RlciIgZnVuY3Rpb24gdG8gdmlldyB0aGUgdGVybXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgY29tcG9uZW50IG1hcCBhbmQgbWV0YS1hbmFseXRpYyBtYXAuIEkgY29waWVkIHRoZXNlIHRlcm1zIGFuZCB0aGVpciBjb3JyZWxhdGlvbiB2YWx1ZXMgdG8gQ1NWIGZpbGVzIGFuZCByZW1vdmVkIGFsbCB0ZXJtcyByZWxhdGVkIHRvIGJyYWluIHJlZ2lvbnMgKHN1Y2ggYXMgImRscGZjIiwgImd5cnVzIiwgb3IgImFudGVyaW9yIHBvc3RlcmlvciIpLgoKVGhlbgpgYGB7cn0KbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KHZpcmlkaXMpICMgdXNlIHRoZSAidmlyaWRpcyIgcGFja2FnZSBmb3IgY29sb3IgcGFsZXR0ZSAodmlyaWRpcyBwYWxldHRlcyBhcmUgY29sb3JibGluZC1zYWZlLCBtYW55IGdncGxvdDIgYW5kIFJDb2xvckJyZXdlciBwYWxldHRlcyBhcmUgbm90KQoKIyBkZW1vIHRoZSBwYWNrYWdlIHVzaW5nIGNvZGUgZnJvbSBSQ29sb3JCcmV3ZXIKbiA9IDggIyBjaGFuZ2UgdGhpcyB0byBob3dldmVyIG1hbnkgYmlucyB5b3Ugd2FudCB0byBzZWUsIGEgaGlnaCBudW1iZXIgbGlrZSAyMDAgd2lsbCBzaG93IG1vcmUgb2YgYSBzcGVjdHJ1bQppbWFnZSgKICAxOm4sIDEsIGFzLm1hdHJpeCgxOm4pLAogIGNvbCA9IHZpcmlkaXMobiwgb3B0aW9uID0gIkQiKSwKICB4bGFiID0gInZpcmlkaXMgbiIsIHlsYWIgPSAiIiwgeGF4dCA9ICJuIiwgeWF4dCA9ICJuIiwgYnR5ID0gIm4iCikKYGBgCgoKIyBJbXBvcnQgZGF0YSBmcm9tIE1BVExBQiBtYXJzYmFyIFJPSSBvdXRwdXQKCgpwbG90KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF95c2wpCgoKbGlicmFyeShwc3ljaCkKY29yci50ZXN0KHJlc3RfZGF0YV9ub19zdWJzMTQyMTQ3JGZkX21lYW5fdHhBLCByZXN0X2RhdGFfbm9fc3ViczE0MjE0NyR0b3RfaWNnKQoKCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfMSkgCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfMikKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHlzbF8zKSAKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHlzbF80KSAKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHlzbF81KQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzYpIApjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzcpIApjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzgpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfOSkgCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfMTApICMgIkZlZWxpbmcgb2Ygd2FudGluZyBiYWNrIGlzIHNvIHN0cm9uZyBpdCBpcyBpbmRlc2NyaWJhYmxlLi4uIgpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzExKSAKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHlzbF8xMikgCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfMTMpIApjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzE0KQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzE1KSAKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHlzbF8xNikgCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfMTcpIApjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzE4KSAKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHlzbF8xOSkgCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR5c2xfMjApIApjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkeXNsXzIxKQoKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF9nY3FfYXBwcm9wKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2djcV9ibGFtZSkKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF9nY3FfY2hlcmlzaCkKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF9nY3FfZnV0dXJlKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2djcV9saWZlKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2djcV9vdGhlcnMpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfZ2NxX3NlbGYpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSRnY3FfMjQpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSRnY3FfMzApCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfZ2NxX3RocmVhdCkKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF9nY3Ffd29ybGQpCgpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2VjcnJzX2dsb2JhbF9hbngpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfZWNycnNfZ2xvYmFsX2F2b2lkKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2VjcnJzX3Nwb3VzZV9hbngpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfZWNycnNfc3BvdXNlX2F2b2lkKQoKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JHRvdF91Y2xhX2xvbmVsaW5lc3MpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfYmlzYmFzX2Jhc2RyKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2Jpc2Jhc19iYXNmdW4pCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfYmlzYmFzX2Jhc3JyKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X2Jpc2Jhc19iaXMpCgpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGFfc3ByMTkkdG90X3Bwc3NfZmEpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YV9zcHIxOSR0b3RfcHBzc19mcikKCgoKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JGdBQVRfYmlhc193aG90b19BKQoKZGF0YV9zcHIxOSRnQUFUX2JpYXNfc3BvdXNlX0EgPC0gZGF0YV9zcHIxOSRnQUFUX1JUX3Nwb3VzZV9wdXNoX0EgLSBkYXRhX3NwcjE5JGdBQVRfUlRfc3BvdXNlX3B1bGxfQQpkYXRhX3NwcjE5JGdBQVRfYmlhc193aG90b19BIDwtIGRhdGFfc3ByMTkkZ0FBVF9SVF93aG90b19wdXNoX0EgLSBkYXRhX3NwcjE5JGdBQVRfUlRfd2hvdG9fcHVsbF9BCmRhdGFfc3ByMTkkZ0FBVF9iaWFzX3N0cmFuZ2VyX0EgPC0gZGF0YV9zcHIxOSRnQUFUX1JUX3N0cmFuZ2VyX3B1c2hfQSAtIGRhdGFfc3ByMTkkZ0FBVF9SVF9zdHJhbmdlcl9wdWxsX0EKZGF0YV9zcHIxOSRnQUFUX2JpYXNfZGVhdGhfQSA8LSBkYXRhX3NwcjE5JGdBQVRfUlRfZGVhdGhfcHVzaF9BIC0gZGF0YV9zcHIxOSRnQUFUX1JUX2RlYXRoX3B1bGxfQQpkYXRhX3NwcjE5JGdBQVRfYmlhc19uZXV0cmFsX0EgPC0gZGF0YV9zcHIxOSRnQUFUX1JUX25ldXRyYWxfcHVzaF9BIC0gZGF0YV9zcHIxOSRnQUFUX1JUX25ldXRyYWxfcHVsbF9BCgoKCgoKYGBge3J9CgpsaWJyYXJ5KGdncGxvdDIpCgojIENvbG9yIGJ5IGdyb3VwcyBhbmQgZmFjZXQKIzo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6OjoKc3AgPC0gZ2dzY2F0dGVyKHAsIHggPSAicm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzIiwgeSA9ICJ5c2xfMTAiLAogICBjb2xvciA9ICJncm91cCIsIHBhbGV0dGUgPSAiamNvIiwKICAgYWRkID0gInJlZy5saW5lIiwgY29uZi5pbnQgPSBUUlVFKQpzcCArIHN0YXRfY29yKGFlcyhjb2xvciA9IGdyb3VwKSwgbGFiZWwueCA9IDMpCgpzdGF0X2NvcihkYXRhID0gcCwgbWV0aG9kID0gInBlYXJzb24iKQoKcCA8LSBuYS5vbWl0KHN1YnNldChkYXRhX3NwcjE5LCBzZWxlY3Q9Yygicm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzIiwgInlzbF8xMCIsICJncm91cCIpKSkgIyByZW1vdmUgdHdvIHBlb3BsZSB3aG8gd2VyZSBkcm9wcGVkIGZyb20gdGhlIGltYWdpbmcgYW5hbHlzaXMKCiMgc2NhdHRlcnBsb3QKc3AgPC0gZ2dzY2F0dGVyKHAsIHggPSAicm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzIiwgeSA9ICJ5c2xfMTAiLAogICBhZGQgPSAicmVnLmxpbmUiLCAgIyBBZGQgcmVncmVzc2lvbiBsaW5lCiAgIGFkZC5wYXJhbXMgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBmaWxsID0gImxpZ2h0Z3JheSIpLCAjIEN1c3RvbWl6ZSByZWcuIGxpbmUKICAgY29uZi5pbnQgPSBUUlVFICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICAgKQojIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudApzcCArIHN0YXRfY29yKG1ldGhvZCA9ICJwZWFyc29uIiwgbGFiZWwueCA9IDMsIGxhYmVsLnkgPSA2KQoKIyBVc2UgUjIgaW5zdGVhZCBvZiBSCmdnc2NhdHRlcihwLCB4ID0gInJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cyIsIHkgPSAieXNsXzEwIiwgYWRkID0gInJlZy5saW5lIiwKICAgICAgICAgIGFkZC5wYXJhbXMgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBmaWxsID0gImxpZ2h0Z3JheSIpLCAjIEN1c3RvbWl6ZSByZWcuIGxpbmUKICAgICAgICAgIGNvbmYuaW50ID0gVFJVRSwgY29sb3I9Imdyb3VwIikgKwogc3RhdF9jb3IoCiAgIGFlcyhsYWJlbCA9IHBhc3RlKC4ucnIubGFiZWwuLiwgLi5wLmxhYmVsLi4sIHNlcCA9ICJ+YCxgfiIpKSwKICBsYWJlbC54ID0gMwopCgpjb3JyLnRlc3QoZGF0YV9zcHIxOSR5c2xfMTAsIGRhdGFfc3ByMTkkaWNnXzIpCnBsb3QoZGF0YV9zcHIxOSR5c2xfMTAsIGRhdGFfc3ByMTkkdG90X2ljZykKYGBgCgojIyAjIFJlZ3Jlc3Npb246IHByZWRpY3QgUk9JIGFjdGl2YXRpb24gZnJvbSAKYGBge3J9CgoKYSA8LSBsbShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgfiB0b3RfaWNnICsgdG90X2Jpc2Jhc19iYXNyciwgZGF0YSA9IGRhdGFfc3ByMTkpCmIgPC0gbG0ocm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzIH4gdG90X2ljZyArIHRvdF9iaXNiYXNfYmFzcnIgKyB0b3RfeXNsX2FmZiwgZGF0YSA9IGRhdGFfc3ByMTkpCmFub3ZhKGEsYikKc3VtbWFyeShhKQpzdW1tYXJ5KGIpCmdncGxvdFJlZ3Jlc3Npb24oZikKCmMgPC0gbG0ocm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzIH4gdG90X2ljZyArIHRvdF9iaXNiYXNfYmFzcnIgKyB0b3RfeXNsX2NvZywgZGF0YSA9IGRhdGFfc3ByMTkpCmFub3ZhKGEsYykKc3VtbWFyeShjKQoKeiA8LSBsbShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgfiB0b3RfaWNnICsgZ0FBVF9zcG91c2Vfdl9zdHJfQSArIHRvdF95c2xfYWZmLCBkYXRhID0gZGF0YV9zcHIxOSkKc3VtbWFyeSh6KQoKZ2dzYXZlKGdncGxvdFJlZ3Jlc3Npb24oYikpCmdnc2F2ZSgifi9EZXNrdG9wL3JlZ3Jlc3Npb24ucG5nIiwgcGxvdCA9IGxhc3RfcGxvdCgpLCBkZXZpY2UgPSBOVUxMLCBwYXRoID0gTlVMTCwKICBzY2FsZSA9IDEsIHdpZHRoID0gOCwgdW5pdHMgPSBjKCJpbiIpLCBkcGkgPSA2MDApCgoKZ2dwbG90UmVncmVzc2lvbiA8LSBmdW5jdGlvbiAoZml0KSB7CmdncGxvdChmaXQkbW9kZWwsIGFlc19zdHJpbmcoeCA9IG5hbWVzKGZpdCRtb2RlbClbNF0sIHkgPSBuYW1lcyhmaXQkbW9kZWwpWzFdKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJibHVlIikgKwogIGxhYnModGl0bGUgPSBwYXN0ZSgiUl4yID0gIixzaWduaWYoc3VtbWFyeShmaXQpJHIuc3F1YXJlZCwgMiksCiAgICAgICAgICAgICAgICAgICAgICJcbkludGVyY2VwdCA9ICIsc2lnbmlmKGZpdCRjb2VmW1sxXV0sMyApLAogICAgICAgICAgICAgICAgICAgICAiXG5TbG9wZSA9IixzaWduaWYoZml0JGNvZWZbWzRdXSwgMiksCiAgICAgICAgICAgICAgICAgICAgICJcbnAgPSIsc2lnbmlmKHN1bW1hcnkoZml0KSRjb2VmWzQsNF0sIDIpKSkgKwogICAgeGxhYigiWWVhcm5pbmcgaW4gU2l0dWF0aW9ucyBvZiBMb3NzIC0gQWZmZWN0aXZlIFN1YnNjYWxlIikgKwogICAgeWxhYigiUk9JIGF0IC0yMywgLTIwLCA3NSAoYmV0YXMpIikKfQoKCmxpYnJhcnkoYXBhVGFibGVzKQphcGEucmVnLnRhYmxlKGIsIGZpbGVuYW1lPSJ+L0Ryb3Bib3gvRGlzc2VydGF0aW9uL1NQUi0yMDE5LXBvc3Rlci9yZWdyZXNzaW9udGFibGUuZG9jIiwgdGFibGUubnVtYmVyPTEpCgpgYGAKCgoKCgpgYGB7cn0KIyMgVXNpbmcgYmVoYXZpb3JhbCBkYXRhCiMgY3JlYXRlIGEgdmFyaWFibGUgZm9yIHNwb3VzZSAtIHN0cmFuZ2VyCm5ldXZzdHIgPC0gZ3JvdXAgPC0gc3Vic2V0KGRhdGFfc3ByMTksIHNlbGVjdD1jKElELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0FBVF9SVF9zcG91c2VfcHVsbF9BLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ0FBVF9SVF9zdHJhbmdlcl9wdWxsX0EpKQoKc3B2c3RyJGdBQVRfc3BvdXNlX3Zfc3RyX0EgPC0gc3B2c3RyJGdBQVRfUlRfc3BvdXNlX3B1bGxfQS1zcHZzdHIkZ0FBVF9SVF9zdHJhbmdlcl9wdWxsX0EKCmRhdGFfc3ByMTkgPC0gbGVmdF9qb2luKGRhdGFfc3ByMTksIHNwdnN0ciwgYnkgPSAiSUQiKQoKZSA8LSBsbShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgfiB0b3RfaWNnICsgZ0FBVF9iaWFzX3Nwb3VzZV9BLCBkYXRhID0gZGF0YV9zcHIxOSkKZiA8LSBsbShyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMgfiB0b3RfaWNnICsgIGdBQVRfYmlhc19zcG91c2VfQSArIHRvdF95c2xfYWZmLCBkYXRhID0gZGF0YV9zcHIxOSkKYW5vdmEoZSxmKQpzdW1tYXJ5KGUpCnN1bW1hcnkoZikKCmcgPC0gbG0ocm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzIH4gdG90X2ljZyArICBnQUFUX2JpYXNfc3BvdXNlX0EgKyB0b3RfeXNsX2NvZywgZGF0YSA9IGRhdGFfc3ByMTkpCmFub3ZhKGUsZykKc3VtbWFyeShnKQoKZGF0YV9zcHIxOSA8LSBsZWZ0X2pvaW4oZGF0YV9zcHIxOSwgbWVhbl9mZCwgYnk9IklEIikKCiMjIyMKIyBRVUVTVElPTlM6CiMgIElOQ0xVREUgQ09WQVJTIElOIFJFR1JFU1NJT04gTU9ERUw/CiMgIEhPVyBUTyBURVNUIFNQRUNJRklDSVRZIFRPIFlFQVJOSU5HIFZTLiBPVEhFUiBDRyBTWD8KICAKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JGdBQVRfc3BvdXNlX3Zfc3RyKQpwbG90KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhX3NwcjE5JGdBQVRfc3BvdXNlX3Zfc3RyKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGEkdG90X2djcV9ibGFtZSkKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhJHRvdF9nY3FfY2hlcmlzaCkKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhJHRvdF9nY3FfZnV0dXJlKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGEkdG90X2djcV9saWZlKQpjb3JyLnRlc3QoZGF0YV9zcHIxOSRyb2lfYmV0YXNfQ0d2TkNHX2NvbXAwMV9wcmVjZW50cmFsZ3lydXMsIGRhdGEkdG90X2djcV9vdGhlcnMpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YSR0b3RfZ2NxX3NlbGYpCmNvcnIudGVzdChkYXRhX3NwcjE5JHJvaV9iZXRhc19DR3ZOQ0dfY29tcDAxX3ByZWNlbnRyYWxneXJ1cywgZGF0YSR0b3RfZ2NxX3RocmVhdCkKY29yci50ZXN0KGRhdGFfc3ByMTkkcm9pX2JldGFzX0NHdk5DR19jb21wMDFfcHJlY2VudHJhbGd5cnVzLCBkYXRhJHRvdF9nY3Ffd29ybGQpCmBgYAoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKIyBGb290bm90ZXMKW14xXTogSSdtIHN1cmUgdGhlcmUncyBwcm9iYWJseSBhIHdheSB0byBtb2RpZnkgdGhpcyBpbiBTUE0gZGVmYXVsdHMgYnV0IGRpZG4ndCB3YW50IHRvIGdldCB0b28gZmFyIGludG8gdGhlIHdlZWRzIHdpdGggdGhhdC4KW14yXTogTm90ZTogYGRpcmAgb25seSBzZWFyY2hlcyByZWN1cnNpdmVseSBpbiBNYXRsYWIgMjAxNmIgYW5kIGxhdGVyLiBJbiBlYXJsaWVyIHZlcnNpb25zLCBpdCB3aWxsIG9ubHkgbG9vayBmb3IgZmlsZXMgaW4gdGhlIHNwZWNpZmllZCBkaXJlY3RvcnkgYW5kIGlnbm9yZSBhbnkgc3ViZGlyZWN0b3JpZXMuClteM106IElkZWFsbHkgdGhpcyB3b3VsZCBiZSBhIHN1ZmZpeCByYXRoZXIgdGhhbiBhIHByZWZpeCB0byBiZSBtb3JlIGNvbnNpc3RlbnQgd2l0aCBCSURTIG5hbWluZyBzdGFuZGFyZHMsIGJ1dCBzbyBmYXIgaGF2ZW4ndCBmaWd1cmVkIHRoYXQgb3V0LgpbXjRdOiBTZWUgZXJyb3IgbWVzc2FnZSBoZXJlOiBodHRwczovL3NvdXJjZWZvcmdlLm5ldC9wL2ljYXRiL21haWxtYW4vbWVzc2FnZS8zMTUxMTQ0OC8gPGJyPkkgdHJpZWQgdG8gYWRkcmVzcyB0aGlzIGJ5IGNyZWF0aW5nIG15IG93biBncm91cCBtYXNrIGFuZCB0ZWxsaW5nIEdJRlQgdG8gdXNlIHRoYXQgaW5zdGVhZCBvZiBtYWtpbmcgaXRzIG93biwgYnV0IHJhbiBpbnRvIHRoZSBzYW1lIGlzc3VlIG9mIHRoZSBtYXNrIGRpZmZlcmluZyBpbiBkaW1lbnNpb25zIGZyb20gc29tZSBvZiB0aGUgZGF0YS4gSW5zdHJ1Y3Rpb25zIGJlbG93IChhZGFwdGVkIGZyb20gaHR0cDovL3d3dy5qcGVlbGxlLm5ldC9tcmkvbWlzYy9jcmVhdGluZ19leHBsaWNpdF9tYXNrLmh0bWwpOjxwPgoqKkhvdyB0byBtYWtlIGEgZ3JvdXAgYnJhaW4gbWFzayoqPGJyPgpHSUZUIGFsbG93cyB5b3UgdG8gcHJvdmlkZSBhIHVzZXItc3BlY2lmaWVkIG1hc2ssIG90aGVyd2lzZSBpdCB3aWxsIGNhbGN1bGF0ZSBvbmUgZm9yIHlvdSBieSBkZWZhdWx0LiAKQ29weSBhbGwgb2YgdGhlIEJPTEQgbWFzayBmaWxlcyBnZW5lcmF0ZWQgYnkgZm1yaXByZXA6IGAkIGZpbmQgL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZm1yaXByZXAgLW5hbWUgIip0YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX2JyYWlubWFzay5uaWkuZ3oiIC1kZXB0aCA0IHwgeGFyZ3MgLUkge30gY3Age30gL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9kYXRhLXNtb290aGVkL21hc2tgClVuemlwIHRoZW06CmBgYAokIGNkIC9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZGF0YS1zbW9vdGhlZC9tYXNrCiQgZ3VuemlwICpicmFpbm1hc2submlpLmd6CmBgYApgZ3VuemlwIC0ta2VlcGAgd2lsbCBrZWVwIHRoZSAuZ3ogZmlsZXMgKGJ5IGRlZmF1bHQgdGhleSdyZSByZW1vdmVkKS48YnI+CldlIG5lZWQgdG8gc21vb3RoIHRoZW0gYmVjYXVzZSBoYXZpbmcgc21vb3RoZWQgdGhlIGltYWdlcywgc29tZSBvZiB0aGUgdm94ZWxzIHdpbGwgbm93IGJlIG91dHNpZGUgb2YgdGhlIG1hc2sgdGhhdCBmbXJpcHJlcCBjYWxjdWxhdGVkIG9uIHRoZSB1bnNtb290aGVkIGltYWdlcy48YnI+ClNtb290aCB0aGVtIHdpdGggYSA0bW0gR2F1c3NpYW4ga2VybmVsOjxicj4KSW4gTWF0bGFiLCBkbyB0aGUgc2FtZSBhcyBhYm92ZSB0byBnZXQgZmlsZSBuYW1lcyBhbmQgYWRkIHRoZW0gdG8gYHNwbV9zbW9vdGhfbWFza19qb2IubWAuIEluIGBzcG1fc21vb3RoX21hc2subWAsIGNoYW5nZSB0aGUgbGluZSBgam9iZmlsZSA9IHsnL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9hbmFseXNlcy1zcHItMjAxOS9iYXRjaC9zcG1fc21vb3RoX3Jlc3Rfam9iLm0nfTtgIHRvIGBqb2JmaWxlID0geycvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL3NwbV9zbW9vdGhfbWFza19qb2IubSd9O2AKYGBgCiUlIGluIG1hdGxhYjoKcnVuKCcvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL3NwbV9zbW9vdGhfbWFzay5tJykKYGBgCmBgYAolJSBpbiBtYXRsYWIsIGVkaXQgc3BtX3Ntb290aF9tYXNrX2pvYi5tIGFjY29yZGluZ2x5OgptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMuaW5wdXQgPSB7Jy9Vc2Vycy9zYXJlbnNlZWxleS9EZXNrdG9wL3Jlc3RpbmdzdGF0ZS9kYXRhL2Rlcml2YXRpdmVzL2dpZnQvZGF0YS1zbW9vdGhlZC9tYXNrLzRtbVNtb290aGVkX3N1Yi0xMDFfc2VzLXR4QV90YXNrLXJlc3RfYm9sZF9zcGFjZS1NTkkxNTJOTGluMjAwOWNBc3ltX2JyYWlubWFzay5uaWksMScKICAnL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9kYXRhLXNtb290aGVkL21hc2svNG1tU21vb3RoZWRfc3ViLTEwMV9zZXMtdHhCX3Rhc2stcmVzdF9ib2xkX3NwYWNlLU1OSTE1Mk5MaW4yMDA5Y0FzeW1fYnJhaW5tYXNrLm5paSwxJ307CiUlCm1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5vdXRwdXQgPSAnZ3JvdXBfYm9sZF9tYXNrJzsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm91dGRpciA9IHsnL1VzZXJzL3NhcmVuc2VlbGV5L0Rlc2t0b3AvcmVzdGluZ3N0YXRlL2RhdGEvZGVyaXZhdGl2ZXMvZ2lmdC9kYXRhLXNtb290aGVkL21hc2snfTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLmV4cHJlc3Npb24gPSAnYWxsKFgpJzsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLnZhciA9IHN0cnVjdCgnbmFtZScsIHt9LCAndmFsdWUnLCB7fSk7Cm1hdGxhYmJhdGNoezF9LnNwbS51dGlsLmltY2FsYy5vcHRpb25zLmRtdHggPSAxOwptYXRsYWJiYXRjaHsxfS5zcG0udXRpbC5pbWNhbGMub3B0aW9ucy5tYXNrID0gMDsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm9wdGlvbnMuaW50ZXJwID0gMTsKbWF0bGFiYmF0Y2h7MX0uc3BtLnV0aWwuaW1jYWxjLm9wdGlvbnMuZHR5cGUgPSA0OwpgYGAKYGBgCiUlIGluIG1hdGxhYjoKcnVuKCcvVXNlcnMvc2FyZW5zZWVsZXkvRGVza3RvcC9yZXN0aW5nc3RhdGUvZGF0YS9kZXJpdmF0aXZlcy9naWZ0L2FuYWx5c2VzLXNwci0yMDE5L2JhdGNoL2ltY2FsY19ncm91cF9tYXNrLm0nKQpgYGA=