Introduction
Acute Lymphoblastic Leukemia (ALL)
ALL treatment is broadly divided into 2 phases - Intensive Phase and
Maintenance Phase. The intensive phase of treatment is further divided
into 4 sub-phases – induction, consolidation, interim maintenance and
delayed intensification [1].
Maintenance therapy (MT), the longest phase of ALL treatment consists
of ~2 years (96 weeks or 8 cycles - 12 weeks per cycle) [1]. Patients are advised to visit
hospital every alternate week (every two weeks) for consultation and on
a weekly basis in case of toxicities (neutropenia, thrombocytopenia or
any other). Overall, a patient should ideally have a minimum of 48
visits during MT. During each visit, patient’s blood report is examined
for the following parameters - absolute neutrophil count (ANC), platelet
count (PLT) and hemoglobin (HB) to adjust (or
dose titrations) the drugs: 6-mercaptopurine (6MP) and Methotrexate
(MTX) that are prescribed on weekly basis.
Package
ALL studies, across the globe, have shown that delivering optimal MT
is crucial to achieve better treatment outcomes [2]. Delivering optimal MT is ensured by
prescribing maximum tolerated 6MP and MTX doses that are adjusted
patient’s hospital visit. In view of this, the package was created to
analyse and visualize the ALL MT data (ANC/PLT/HB/6MP/MTX). The use of package
would assist physicians to evaluate MT for a given patient or a cohort
at any center. Although, the package was developed considering the
ICiCLe-ALL-14 protocol [1] as
default, it can be used to analyze data from centers with different MT
protocols. In case of different protocol, the user will need to alter
the defined parameters specific to protocol as function arguments.
Using this package the user may:
Convert maintenance sheets (Tata Medical Center Kolkata, India
format or user dependent) into a cleaner, single csv with longitudinal
data for each patient.
Analyze MT
Evaluate real time dosing decisions (stop, reduce or increase) by
the physicians during MT based on MT dosing guidelines for the
individual patient or cohort [3].
Evaluate hematological toxicities - neutropenia, thrombocytopenia
and anemia during MT for the individual patient or cohort.
Evaluate/plot median time to first 6MP dose increase for the
individual patient or cohort [3].
# library(allMT)
Data
The data recording sheet used by TMC can be downloaded/copied
as
# Uncomment below line before running the snippet
# library(allMT)
pat_data <- system.file("extdata/tmc_data/", "UPN_916.xls", package = "allMT")
dest_path <- getwd() # user may choose a different destination
file.copy(pat_data, dest_path)
#> [1] TRUE
To use functions of the package, the data needs to be in a
specific format as described in below example. Sample data for 3 individual
patient is available as UPN_914, UPN_915, and UPN_916 as rda with the
library for viewing. Additionally, UPN_914, UPN_915, UPN_916, UPN_917
and UPN_918 are present under the folder “/extdata/processed_data/” as
csv format to run any examples.
Data can be checked or saved as
# Below code should work for any user independent of OS
# pat_data <- system.file("extdata/processed_data/", "UPN_916.csv", package = "allMT")
# pat_df <- utils::read.csv(pat_data, header = TRUE, sep = ",")
# # head(pat_df)
Functions
Convert Data
convert_tmc_format()
- Convert information recorded
in the TMC datasheet format to a format that will be used by package
functions.
convert_external_format()
- Convert MT information
(user defined) to a format that will be used by package functions.
Note: User need to ensure the MT information is stored
in an excel or csv with column names as - Dates, ANC, PLT, MP, MTX. The
function will convert this sheet into required format.
The output of both the functions will result in standard patient csv
files (as described Data section) saved in a folder defined by the
user.
Analyze MT Data
At individual
patient level
plot_progression()
- Plot line graph showing
historical longitudinal trends of ANC, 6MP and MTX for a single patient.
This function can be use by the doctors during the MT clinic to monitor
patients’ MT dose prescription and treatment response in real
time.
summarize_cycle_progression()
- Plot SM data per
cycle for given patient data. Utility as above.
At cohort
level
summarize_cohortMT()
- Plot scatter plot (SM) for
all the patients from user defined cohort.
compare_cohorts()
- Plot scatter plot (SM) for all
the patients present in user defined multiple cohorts (more than 1
cohort) . Two methods of cohort comparison can be considered for
analysis as mentioned below:
Evaluate Physicians’
Dosing Decisions
assess_stop_doses()
- The function evaluates the
incidence of ‘No Dose’ physician’s decisions that are NOT supported by
protocol-based target blood counts.
assess_reduced_doses()
- The function evaluates the
incidence of ‘Reduce Dose’ physician’s decisions that are NOT supported
by protocol-based target blood counts.
assess_increased_doses()
- The function evaluates
the incidence of ‘Increase Dose’ physician’s decisions that are NOT
supported by protocol-based target blood counts.
Note: Depending upon value provided for the argument
‘input_files_path’ as a
- path to a file for single patient csv - resulting output will be
analysis for single patient
- path to a folder (cohort) with multiple csv - resulting output will
be analysis carried for the cohort of patients’ csv files present in the
folder
Evaluate
Hematological Toxicities
assess_neutropenia()
- The function evaluates number
of neutropenia episodes as per the neutropenia definition provided in
‘anc_range’ argument - c(a,b). a is defined as highest value of ANC
threshold for neutropenic condition, and b is defined as ANC value above
which neutropenic condition is said to be recovered.
assess_thrombocytopenia()
- The function evaluates
number of thrombocytopenia episodes as per the thrombocytopenia
definition provided in ‘plt_range’ argument - c(a,b). a is defined as
highest value of PLT threshold for thrombocytopenia condition, and b is
defined as PLT value above which thrombocytopenic condition is said to
be recovered.
assess_anemia()
- The function evaluates number of
anemia episodes as per the anemia definition provided in ‘hb_range’
argument - c(a,b). a is defined as highest value of Hb threshold for
anemia condition, and b is defined as Hb value above which anemic
condition is said to be recovered.
Note: Depending upon value provided for the argument
‘input_files_path’ as a
- path to a file for single patient csv - resulting output will be
analysis for single patient
- path to a folder (cohort) with multiple csv - resulting output will
analysis be carried for the cohort of patients’ csv files present in the
folder
Time to
First-Dose-Increase
time_to_first_dose_increase()
- Plot the graph showing
median time to first 6MP dose increase for the cohort (if input file is
an individual patient instead of cohort, function displays value for an
individual patient in question)
References
[1]
N.
Das et al., “Protocol for ICiCLe-ALL-14
(InPOG-ALL-15-01): A prospective, risk stratified, randomised,
multicentre, open label, controlled therapeutic trial for newly
diagnosed childhood acute lymphoblastic leukaemia in india,”
Trials, vol. 23, no. 1, pp. 1–20, 2022.
[2]
K.
Schmiegelow, S. N. Nielsen, T. L. Frandsen, and J. Nersting,
“Mercaptopurine/methotrexate maintenance therapy of childhood
acute lymphoblastic leukemia: Clinical facts and fiction,”
Journal of pediatric hematology/oncology, vol. 36, no. 7, p.
503, 2014.
[3]
T.
D. Mungle, “Modelling clinical decision processes to optimise
maintenance chemotherapy in children with acute lymphoblastic
leukaemia,” PhD thesis, IIT Kharagpur, 2020.
LS0tCnRpdGxlOiAiQW5hbHl6ZSBBY3V0ZSBMeW1waG9ibGFzdGljIExldWtlbWlhIE1haW50ZW5hbmNlIFRoZXJhcHkiCiMgc3VidGl0bGU6ICJUdXNoYXIgTXVuZ2xlJF4xJCReLCQkXjIkLCBBbmFueWEgTWFoYWRldmFuJF4yJCIKYXV0aG9yOgogIC0gbmFtZTogIlR1c2hhciBNdW5nbGUkXjEkJF4sJCReKiQkXiwkJF4rJCwgQW5hbnlhIE1haGFkZXZhbiReMSQkXiwkJF4qJCwgU2hla2hhciBLcmlzaG5hbiReMSQiCiAgICBhZmZpbGlhdGlvbjogJF4xJFRhdGEgVHJhbnNsYXRpb25hbCBDYW5jZXIgUmVzZWFyY2ggQ2VudHJlIChUVENSQyksIFRhdGEgTWVkaWNhbCBDZW50ZXIgKFRNQyksIEtvbGthdGEsIEluZGlhOyAkXiokY29udHJpYnV0ZWQgZXF1YWxseQogICAgZW1haWw6ICReKyQgQ29ycmVzcG9uZGVuY2UgLSB0dXNoYXIubXVuZ2xlQGdtYWlsLmNvbQogICAgI2VtYWlsOiAkXiokQ29ycmVzcG9uZGVuY2UgLSB0dXNoYXIubXVuZ2xlQGdtYWlsLmNvbQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgcm1hcmtkb3duOjpodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgIyB0aGVtZTogY2VydWxlYW4KICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogVFJVRQp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5e0FuYWx5emUgQWN1dGUgTHltcGhvYmxhc3RpYyBMZXVrZW1pYSBNYWludGVuYW5jZSBUaGVyYXB5fQogICVcVmlnbmV0dGVFbmNvZGluZ3tVVEYtOH0KICAlXFZpZ25ldHRlRW5naW5le2tuaXRyOjpybWFya2Rvd259CkVuY29kaW5nOiBVVEYtOApiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCmNzbDogaWVlZS5jc2wKbGluay1jaXRhdGlvbnM6IHRydWUKIyBjc3M6ICIuLi9zdHlsZXMuY3NzIgplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY29sbGFwc2UgPSBUUlVFLAogIGNvbW1lbnQgPSAiIz4iCikKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGJpYnRleCkKbGlicmFyeShib29rZG93bikKCnJlZnMgPC0gcmVhZC5iaWIoInJlZmVyZW5jZXMuYmliIikKa2V5cyA8LSBuYW1lcyhyZWZzKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBJbnRyb2R1Y3Rpb24KCioqKkFjdXRlIEx5bXBob2JsYXN0aWMgTGV1a2VtaWEqKiogKEFMTCkKCkFMTCB0cmVhdG1lbnQgaXMgYnJvYWRseSBkaXZpZGVkIGludG8gMiBwaGFzZXMgLSBJbnRlbnNpdmUgUGhhc2UgYW5kIE1haW50ZW5hbmNlIFBoYXNlLiBUaGUgaW50ZW5zaXZlIHBoYXNlIG9mIHRyZWF0bWVudCBpcyBmdXJ0aGVyIGRpdmlkZWQgaW50byA0IHN1Yi1waGFzZXMgLS0gaW5kdWN0aW9uLCBjb25zb2xpZGF0aW9uLCBpbnRlcmltIG1haW50ZW5hbmNlIGFuZCBkZWxheWVkIGludGVuc2lmaWNhdGlvbiBbQGRhczIwMjJwcm90b2NvbF0uCgpNYWludGVuYW5jZSB0aGVyYXB5IChNVCksIHRoZSBsb25nZXN0IHBoYXNlIG9mIEFMTCB0cmVhdG1lbnQgY29uc2lzdHMgb2YgXH4yIHllYXJzICg5NiB3ZWVrcyBvciA4IGN5Y2xlcyAtIDEyIHdlZWtzIHBlciBjeWNsZSkgW0BkYXMyMDIycHJvdG9jb2xdLiBQYXRpZW50cyBhcmUgYWR2aXNlZCB0byB2aXNpdCBob3NwaXRhbCBldmVyeSBhbHRlcm5hdGUgd2VlayAoZXZlcnkgdHdvIHdlZWtzKSBmb3IgY29uc3VsdGF0aW9uIGFuZCBvbiBhIHdlZWtseSBiYXNpcyBpbiBjYXNlIG9mIHRveGljaXRpZXMgKG5ldXRyb3BlbmlhLCB0aHJvbWJvY3l0b3BlbmlhIG9yIGFueSBvdGhlcikuIE92ZXJhbGwsIGEgcGF0aWVudCBzaG91bGQgaWRlYWxseSBoYXZlIGEgbWluaW11bSBvZiA0OCB2aXNpdHMgZHVyaW5nIE1ULiBEdXJpbmcgZWFjaCB2aXNpdCwgcGF0aWVudCdzIGJsb29kIHJlcG9ydCBpcyBleGFtaW5lZCBmb3IgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIC0gYWJzb2x1dGUgbmV1dHJvcGhpbCBjb3VudCAoQU5DKSwgcGxhdGVsZXQgY291bnQgKFBMVCkgYW5kIGhlbW9nbG9iaW4gKEhCKSB0byAqKiphZGp1c3QqKiogKG9yIGRvc2UgdGl0cmF0aW9ucykgdGhlIGRydWdzOiA2LW1lcmNhcHRvcHVyaW5lICg2TVApIGFuZCBNZXRob3RyZXhhdGUgKE1UWCkgdGhhdCBhcmUgcHJlc2NyaWJlZCBvbiB3ZWVrbHkgYmFzaXMuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgUGFja2FnZQoKQUxMIHN0dWRpZXMsIGFjcm9zcyB0aGUgZ2xvYmUsIGhhdmUgc2hvd24gdGhhdCBkZWxpdmVyaW5nIG9wdGltYWwgTVQgaXMgY3J1Y2lhbCB0byBhY2hpZXZlIGJldHRlciB0cmVhdG1lbnQgb3V0Y29tZXMgW0BzY2htaWVnZWxvdzIwMTRtZXJjYXB0b3B1cmluZV0uIERlbGl2ZXJpbmcgb3B0aW1hbCBNVCBpcyBlbnN1cmVkIGJ5IHByZXNjcmliaW5nIG1heGltdW0gdG9sZXJhdGVkIDZNUCBhbmQgTVRYIGRvc2VzIHRoYXQgYXJlIGFkanVzdGVkIHBhdGllbnQncyBob3NwaXRhbCB2aXNpdC4gSW4gdmlldyBvZiB0aGlzLCB0aGUgcGFja2FnZSB3YXMgY3JlYXRlZCB0byBhbmFseXNlIGFuZCB2aXN1YWxpemUgdGhlIEFMTCBNVCBkYXRhIChBTkMvUExUL0hCLzZNUC9NVFgpW14xXS4gVGhlIHVzZSBvZiBwYWNrYWdlIHdvdWxkIGFzc2lzdCBwaHlzaWNpYW5zIHRvIGV2YWx1YXRlIE1UIGZvciBhIGdpdmVuIHBhdGllbnQgb3IgYSBjb2hvcnQgYXQgYW55IGNlbnRlci4gQWx0aG91Z2gsIHRoZSBwYWNrYWdlIHdhcyBkZXZlbG9wZWQgY29uc2lkZXJpbmcgdGhlIElDaUNMZS1BTEwtMTQgcHJvdG9jb2wgW0BkYXMyMDIycHJvdG9jb2xdIGFzIGRlZmF1bHQsIGl0IGNhbiBiZSB1c2VkIHRvIGFuYWx5emUgZGF0YSBmcm9tIGNlbnRlcnMgd2l0aCBkaWZmZXJlbnQgTVQgcHJvdG9jb2xzLiBJbiBjYXNlIG9mIGRpZmZlcmVudCBwcm90b2NvbCwgdGhlIHVzZXIgd2lsbCBuZWVkIHRvIGFsdGVyIHRoZSBkZWZpbmVkIHBhcmFtZXRlcnMgc3BlY2lmaWMgdG8gcHJvdG9jb2wgYXMgZnVuY3Rpb24gYXJndW1lbnRzLgoKW14xXTogVGhlIHdvcmsgd2FzIGluaXRpYXRlZCBhcyBwYXJ0IG9mIFR1c2hhciBNdW5nbGUncyBQaEQgYXQgSUlUIEtoYXJhZ3B1ciBbQG11bmdsZTIwMjBtb2RlbGxpbmddIGFuZCB0aGVuIGNvbnRpbnVlZCBhdCBUVENSQywgVGF0YSBNZWRpY2FsIENlbnRlciwgS29sa2F0YS4KClVzaW5nIHRoaXMgcGFja2FnZSB0aGUgdXNlciBtYXk6CgoxLiAgQ29udmVydCBtYWludGVuYW5jZSBzaGVldHMgKFRhdGEgTWVkaWNhbCBDZW50ZXIgS29sa2F0YSwgSW5kaWEgZm9ybWF0IG9yIHVzZXIgZGVwZW5kZW50KSBpbnRvIGEgY2xlYW5lciwgc2luZ2xlIGNzdiB3aXRoIGxvbmdpdHVkaW5hbCBkYXRhIGZvciBlYWNoIHBhdGllbnQuCgoyLiAgQW5hbHl6ZSBNVAoKICAgIC0gICBBdCBhbiBpbmRpdmlkdWFsIHBhdGllbnQgbGV2ZWwKCiAgICAgICAgLSAgIFRvIHRyYWNrIHBhdGllbnQncyBNVCBwcm9ncmVzc2lvbiBkdXJpbmcgb3IgYWZ0ZXIgdGhlcmFweSBbQG11bmdsZTIwMjBtb2RlbGxpbmddLgoKICAgICAgICAtICAgVG8gdHJhY2sgcGF0aWVudCdzIGN5Y2xlLWJ5LWN5Y2xlIE1UIHByb2dyZXNzaW9uIGR1cmluZyBvciBhZnRlciB0aGUgdGhlcmFweSB1c2luZyBzdW1tYXJ5IG1lYXN1cmUgKFNNKSB3ZWlnaHRlZCBtZWFuICg2TVBcKk1UWCkgdnMgd2VpZ2h0ZWQgbWVhbiBBTkMgcGFyYW1ldGVycyBpbiBhIHNjYXR0ZXJwbG90LgoKICAgIC0gICBBdCBjb2hvcnQgbGV2ZWwKCiAgICAgICAgLSAgIFNNIHBsb3QgdG8gYW5hbHl6ZSBNVCBmb3IgYSBnaXZlbiBjb2hvcnQgZGVmaW5lZCBieSB0aGUgdXNlci4gU00gaXMgZXZhbHVhdGVkIGZvciBlYWNoIHBhdGllbnQgYW5kIHBsb3R0ZWQgdG9nZXRoZXIgdG8gcmVwcmVzZW50IHRoZSBlbnRpcmUgY29ob3J0IFtAbXVuZ2xlMjAyMG1vZGVsbGluZ10uCgogICAgICAgIC0gICBDb21wYXJlIFNNIGZvciB0d28gZGlmZmVyZW50IGNvaG9ydCBkZWZpbmVkIGJ5IHRoZSB1c2VyIHRvIGV2YWx1YXRlIE1UIHByYWN0aWNlLiBDb2hvcnQgY29tcGFyaXNvbnMgY2FuIGluY2x1ZGUgY2xpbmljYWwgaW50ZXJ2ZW50aW9ucywgeWVhci13aXNlIHByYWN0aWNlIGV2b2x1dGlvbiwgcGF0aWVudHMgdHJlYXRlZCBieSB0d28gZGlmZmVyZW50IHNldCBvZiBwaHlzaWNpYW5zLCBvciBhcyB1c2VyIHNlZSBpdCBmaXQgW0BtdW5nbGUyMDIwbW9kZWxsaW5nXS4KCjMuICBFdmFsdWF0ZSByZWFsIHRpbWUgZG9zaW5nIGRlY2lzaW9ucyAoc3RvcCwgcmVkdWNlIG9yIGluY3JlYXNlKSBieSB0aGUgcGh5c2ljaWFucyBkdXJpbmcgTVQgYmFzZWQgb24gTVQgZG9zaW5nIGd1aWRlbGluZXMgZm9yIHRoZSBpbmRpdmlkdWFsIHBhdGllbnQgb3IgY29ob3J0IFtAbXVuZ2xlMjAyMG1vZGVsbGluZ10uCgo0LiAgRXZhbHVhdGUgaGVtYXRvbG9naWNhbCB0b3hpY2l0aWVzIC0gbmV1dHJvcGVuaWEsIHRocm9tYm9jeXRvcGVuaWEgYW5kIGFuZW1pYSBkdXJpbmcgTVQgZm9yIHRoZSBpbmRpdmlkdWFsIHBhdGllbnQgb3IgY29ob3J0LgoKNS4gIEV2YWx1YXRlL3Bsb3QgbWVkaWFuIHRpbWUgdG8gZmlyc3QgNk1QIGRvc2UgaW5jcmVhc2UgZm9yIHRoZSBpbmRpdmlkdWFsIHBhdGllbnQgb3IgY29ob3J0IFtAbXVuZ2xlMjAyMG1vZGVsbGluZ10uCgpgYGB7ciBzZXR1cH0KIyBsaWJyYXJ5KGFsbE1UKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBEYXRhCgoxLiAgVGhlIGRhdGEgcmVjb3JkaW5nIHNoZWV0IHVzZWQgYnkgVE1DIGNhbiBiZSBkb3dubG9hZGVkL2NvcGllZCBhcwoKICAgIGBgYHtyfQogICAgIyBVbmNvbW1lbnQgYmVsb3cgbGluZSBiZWZvcmUgcnVubmluZyB0aGUgc25pcHBldAogICAgIyBsaWJyYXJ5KGFsbE1UKQogICAgcGF0X2RhdGEgPC0gc3lzdGVtLmZpbGUoImV4dGRhdGEvdG1jX2RhdGEvIiwgIlVQTl85MTYueGxzIiwgcGFja2FnZSA9ICJhbGxNVCIpCiAgICBkZXN0X3BhdGggPC0gZ2V0d2QoKSAjIHVzZXIgbWF5IGNob29zZSBhIGRpZmZlcmVudCBkZXN0aW5hdGlvbiAKICAgIGZpbGUuY29weShwYXRfZGF0YSwgZGVzdF9wYXRoKQogICAgYGBgCgoyLiAgVG8gdXNlIGZ1bmN0aW9ucyBvZiB0aGUgcGFja2FnZSwgdGhlIGRhdGEgbmVlZHMgdG8gYmUgaW4gYSBzcGVjaWZpYyBmb3JtYXQgYXMgZGVzY3JpYmVkIGluIGJlbG93IGV4YW1wbGUuIFNhbXBsZSBkYXRhW14yXSBmb3IgMyBpbmRpdmlkdWFsIHBhdGllbnQgaXMgYXZhaWxhYmxlIGFzIFVQTl85MTQsIFVQTl85MTUsIGFuZCBVUE5fOTE2IGFzIHJkYSB3aXRoIHRoZSBsaWJyYXJ5IGZvciB2aWV3aW5nLiBBZGRpdGlvbmFsbHksIFVQTl85MTQsIFVQTl85MTUsIFVQTl85MTYsIFVQTl85MTcgYW5kIFVQTl85MTggYXJlIHByZXNlbnQgdW5kZXIgdGhlIGZvbGRlciAiL2V4dGRhdGEvcHJvY2Vzc2VkX2RhdGEvIiBhcyBjc3YgZm9ybWF0IHRvIHJ1biBhbnkgZXhhbXBsZXMuCgogICAgRGF0YSBjYW4gYmUgY2hlY2tlZCBvciBzYXZlZCBhcwogICAgCiAgICBgYGB7cn0KICAgICMgQmVsb3cgY29kZSBzaG91bGQgd29yayBmb3IgYW55IHVzZXIgaW5kZXBlbmRlbnQgb2YgT1MKICAgICMgcGF0X2RhdGEgPC0gc3lzdGVtLmZpbGUoImV4dGRhdGEvcHJvY2Vzc2VkX2RhdGEvIiwgIlVQTl85MTYuY3N2IiwgcGFja2FnZSA9ICJhbGxNVCIpCiAgICAjIHBhdF9kZiA8LSB1dGlsczo6cmVhZC5jc3YocGF0X2RhdGEsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIikKICAgICMgIyBoZWFkKHBhdF9kZikKCiAgICBgYGAKClteMl06IEV0aGljcyBhcHByb3ZhbCBzdGF0ZW1lbnQ6IFRoZSBhbm9ueW1pemVkIGNsaW5pY2FsIGRhdGEgc2V0IHJlZmVycyB0byBwYXRpZW50cyB0cmVhdGVkIG9uIHRoZSBJQ2lDTGUtQUxMLTE0IHRyZWF0bWVudCBwcm90b2NvbCBhdCB0aGUgVGF0YSBNZWRpY2FsIENlbnRlciBLb2xrYXRhIChpbnN0aXR1dGlvbmFsIHJldmlldyBib2FyZCBhcHByb3ZhbCBFQy9UTUMvMTIvMTMgZm9yIHRoZSB0cmVhdG1lbnQgcHJvdG9jb2wpLiBGdW5kaW5nIHN1cHBvcnQgZm9yIHRoZSBJQ2lDTGUtQUxMLTE0IGNsaW5pY2FsIHN0dWR5IChDbGluaWNhbCBUcmlhbHMgUmVnaXN0cnktSW5kaWEgcmVmZXJlbmNlIENUUkkvMjAxNS8xMi8wMDY0MzQpIHdhcyBwcm92aWRlZCBieSB0aGUgTmF0aW9uYWwgQ2FuY2VyIEdyaWQgKDIwMTYvMDAxOyAyMDE2LSkgYW5kIHRoZSBJbmRpYW4gQ291bmNpbCBvZiBNZWRpY2FsIFJlc2VhcmNoICg3OS8xNTkvMjAxNS9OQ0QtSUlJOyAyMDE3LTE5KS4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBGdW5jdGlvbnMKCiMjIENvbnZlcnQgRGF0YQoKLSAgIGBjb252ZXJ0X3RtY19mb3JtYXQoKWAgLSBDb252ZXJ0IGluZm9ybWF0aW9uIHJlY29yZGVkIGluIHRoZSBUTUMgZGF0YXNoZWV0IGZvcm1hdCB0byBhIGZvcm1hdCB0aGF0IHdpbGwgYmUgdXNlZCBieSBwYWNrYWdlIGZ1bmN0aW9ucy4KCi0gICBgY29udmVydF9leHRlcm5hbF9mb3JtYXQoKWAgLSBDb252ZXJ0IE1UIGluZm9ybWF0aW9uICh1c2VyIGRlZmluZWQpIHRvIGEgZm9ybWF0IHRoYXQgd2lsbCBiZSB1c2VkIGJ5IHBhY2thZ2UgZnVuY3Rpb25zLlwKICAgIFsqTm90ZToqXXsudW5kZXJsaW5lfSBVc2VyIG5lZWQgdG8gZW5zdXJlIHRoZSBNVCBpbmZvcm1hdGlvbiBpcyBzdG9yZWQgaW4gYW4gZXhjZWwgb3IgY3N2IHdpdGggY29sdW1uIG5hbWVzIGFzIC0gRGF0ZXMsIEFOQywgUExULCBNUCwgTVRYLiBUaGUgZnVuY3Rpb24gd2lsbCBjb252ZXJ0IHRoaXMgc2hlZXQgaW50byByZXF1aXJlZCBmb3JtYXQuCgpUaGUgb3V0cHV0IG9mIGJvdGggdGhlIGZ1bmN0aW9ucyB3aWxsIHJlc3VsdCBpbiBzdGFuZGFyZCBwYXRpZW50IGNzdiBmaWxlcyAoYXMgZGVzY3JpYmVkIERhdGEgc2VjdGlvbikgc2F2ZWQgaW4gYSBmb2xkZXIgZGVmaW5lZCBieSB0aGUgdXNlci4KCiMjIEFuYWx5emUgTVQgRGF0YQoKIyMjIEF0IGluZGl2aWR1YWwgcGF0aWVudCBsZXZlbAoKLSAgIGBwbG90X3Byb2dyZXNzaW9uKClgIC0gUGxvdCBsaW5lIGdyYXBoIHNob3dpbmcgaGlzdG9yaWNhbCBsb25naXR1ZGluYWwgdHJlbmRzIG9mIEFOQywgNk1QIGFuZCBNVFggZm9yIGEgc2luZ2xlIHBhdGllbnQuIFRoaXMgZnVuY3Rpb24gY2FuIGJlIHVzZSBieSB0aGUgZG9jdG9ycyBkdXJpbmcgdGhlIE1UIGNsaW5pYyB0byBtb25pdG9yIHBhdGllbnRzJyBNVCBkb3NlIHByZXNjcmlwdGlvbiBhbmQgdHJlYXRtZW50IHJlc3BvbnNlIGluIHJlYWwgdGltZS4KCi0gICBgc3VtbWFyaXplX2N5Y2xlX3Byb2dyZXNzaW9uKClgIC0gUGxvdCBTTSBkYXRhIHBlciBjeWNsZSBmb3IgZ2l2ZW4gcGF0aWVudCBkYXRhLiBVdGlsaXR5IGFzIGFib3ZlLgoKIyMjIEF0IGNvaG9ydCBsZXZlbAoKLSAgIGBzdW1tYXJpemVfY29ob3J0TVQoKWAgLSBQbG90IHNjYXR0ZXIgcGxvdCAoU00pIGZvciBhbGwgdGhlIHBhdGllbnRzIGZyb20gdXNlciBkZWZpbmVkIGNvaG9ydC4KCi0gICBgY29tcGFyZV9jb2hvcnRzKClgIC0gUGxvdCBzY2F0dGVyIHBsb3QgKFNNKSBmb3IgYWxsIHRoZSBwYXRpZW50cyBwcmVzZW50IGluIHVzZXIgZGVmaW5lZCBtdWx0aXBsZSBjb2hvcnRzIChtb3JlIHRoYW4gMSBjb2hvcnQpIC4gVHdvIG1ldGhvZHMgb2YgY29ob3J0IGNvbXBhcmlzb24gY2FuIGJlIGNvbnNpZGVyZWQgZm9yIGFuYWx5c2lzIGFzIG1lbnRpb25lZCBiZWxvdzoKCiAgICAtICAgTWV0aG9kIDEgLSBDb21wYXJpc29uIGJldHdlZW4gY29ob3J0cyB0aGF0IGJlZ2FuIE1UIGJlZm9yZSBhbmQgYWZ0ZXIgYSBwYXJ0aWN1bGFyIHVzZXItcHJvdmlkZWQgZGF0ZS4KCiAgICAtICAgTWV0aG9kIDIgLSBDb21wYXJpc29uIGJldHdlZW4gbW9yZSB0aGFuIDEgY29ob3J0cyBwcmUtZGV0ZXJtaW5lZCBieSB0aGUgdXNlci4KCiMjIEV2YWx1YXRlIFBoeXNpY2lhbnMnIERvc2luZyBEZWNpc2lvbnMKCi0gICBgYXNzZXNzX3N0b3BfZG9zZXMoKWAgLSBUaGUgZnVuY3Rpb24gZXZhbHVhdGVzIHRoZSBpbmNpZGVuY2Ugb2YgJ05vIERvc2UnIHBoeXNpY2lhbidzIGRlY2lzaW9ucyB0aGF0IGFyZSBOT1Qgc3VwcG9ydGVkIGJ5IHByb3RvY29sLWJhc2VkIHRhcmdldCBibG9vZCBjb3VudHMuCgotICAgYGFzc2Vzc19yZWR1Y2VkX2Rvc2VzKClgIC0gVGhlIGZ1bmN0aW9uIGV2YWx1YXRlcyB0aGUgaW5jaWRlbmNlIG9mICdSZWR1Y2UgRG9zZScgcGh5c2ljaWFuJ3MgZGVjaXNpb25zIHRoYXQgYXJlIE5PVCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wtYmFzZWQgdGFyZ2V0IGJsb29kIGNvdW50cy4KCi0gICBgYXNzZXNzX2luY3JlYXNlZF9kb3NlcygpYCAtIFRoZSBmdW5jdGlvbiBldmFsdWF0ZXMgdGhlIGluY2lkZW5jZSBvZiAnSW5jcmVhc2UgRG9zZScgcGh5c2ljaWFuJ3MgZGVjaXNpb25zIHRoYXQgYXJlIE5PVCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wtYmFzZWQgdGFyZ2V0IGJsb29kIGNvdW50cy4KCiAgICBbKk5vdGU6Kl17LnVuZGVybGluZX0gRGVwZW5kaW5nIHVwb24gdmFsdWUgcHJvdmlkZWQgZm9yIHRoZSBhcmd1bWVudCAnaW5wdXRfZmlsZXNfcGF0aCcgYXMgYQoKICAgIDEuICBwYXRoIHRvIGEgZmlsZSBmb3Igc2luZ2xlIHBhdGllbnQgY3N2IC0gcmVzdWx0aW5nIG91dHB1dCB3aWxsIGJlIGFuYWx5c2lzIGZvciBzaW5nbGUgcGF0aWVudAogICAgMi4gIHBhdGggdG8gYSBmb2xkZXIgKGNvaG9ydCkgd2l0aCBtdWx0aXBsZSBjc3YgLSByZXN1bHRpbmcgb3V0cHV0IHdpbGwgYmUgYW5hbHlzaXMgY2FycmllZCBmb3IgdGhlIGNvaG9ydCBvZiBwYXRpZW50cycgY3N2IGZpbGVzIHByZXNlbnQgaW4gdGhlIGZvbGRlcgoKIyMgRXZhbHVhdGUgSGVtYXRvbG9naWNhbCBUb3hpY2l0aWVzCgotICAgYGFzc2Vzc19uZXV0cm9wZW5pYSgpYCAtIFRoZSBmdW5jdGlvbiBldmFsdWF0ZXMgbnVtYmVyIG9mIG5ldXRyb3BlbmlhIGVwaXNvZGVzIGFzIHBlciB0aGUgbmV1dHJvcGVuaWEgZGVmaW5pdGlvbiBwcm92aWRlZCBpbiAnYW5jX3JhbmdlJyBhcmd1bWVudCAtIGMoYSxiKS4gYSBpcyBkZWZpbmVkIGFzIGhpZ2hlc3QgdmFsdWUgb2YgQU5DIHRocmVzaG9sZCBmb3IgbmV1dHJvcGVuaWMgY29uZGl0aW9uLCBhbmQgYiBpcyBkZWZpbmVkIGFzIEFOQyB2YWx1ZSBhYm92ZSB3aGljaCBuZXV0cm9wZW5pYyBjb25kaXRpb24gaXMgc2FpZCB0byBiZSByZWNvdmVyZWQuCgotICAgYGFzc2Vzc190aHJvbWJvY3l0b3BlbmlhKClgIC0gVGhlIGZ1bmN0aW9uIGV2YWx1YXRlcyBudW1iZXIgb2YgdGhyb21ib2N5dG9wZW5pYSBlcGlzb2RlcyBhcyBwZXIgdGhlIHRocm9tYm9jeXRvcGVuaWEgZGVmaW5pdGlvbiBwcm92aWRlZCBpbiAncGx0X3JhbmdlJyBhcmd1bWVudCAtIGMoYSxiKS4gYSBpcyBkZWZpbmVkIGFzIGhpZ2hlc3QgdmFsdWUgb2YgUExUIHRocmVzaG9sZCBmb3IgdGhyb21ib2N5dG9wZW5pYSBjb25kaXRpb24sIGFuZCBiIGlzIGRlZmluZWQgYXMgUExUIHZhbHVlIGFib3ZlIHdoaWNoIHRocm9tYm9jeXRvcGVuaWMgY29uZGl0aW9uIGlzIHNhaWQgdG8gYmUgcmVjb3ZlcmVkLgoKLSAgIGBhc3Nlc3NfYW5lbWlhKClgIC0gVGhlIGZ1bmN0aW9uIGV2YWx1YXRlcyBudW1iZXIgb2YgYW5lbWlhIGVwaXNvZGVzIGFzIHBlciB0aGUgYW5lbWlhIGRlZmluaXRpb24gcHJvdmlkZWQgaW4gJ2hiX3JhbmdlJyBhcmd1bWVudCAtIGMoYSxiKS4gYSBpcyBkZWZpbmVkIGFzIGhpZ2hlc3QgdmFsdWUgb2YgSGIgdGhyZXNob2xkIGZvciBhbmVtaWEgY29uZGl0aW9uLCBhbmQgYiBpcyBkZWZpbmVkIGFzIEhiIHZhbHVlIGFib3ZlIHdoaWNoIGFuZW1pYyBjb25kaXRpb24gaXMgc2FpZCB0byBiZSByZWNvdmVyZWQuCgpbKk5vdGU6Kl17LnVuZGVybGluZX0gRGVwZW5kaW5nIHVwb24gdmFsdWUgcHJvdmlkZWQgZm9yIHRoZSBhcmd1bWVudCAnaW5wdXRfZmlsZXNfcGF0aCcgYXMgYQoKMS4gIHBhdGggdG8gYSBmaWxlIGZvciBzaW5nbGUgcGF0aWVudCBjc3YgLSByZXN1bHRpbmcgb3V0cHV0IHdpbGwgYmUgYW5hbHlzaXMgZm9yIHNpbmdsZSBwYXRpZW50CjIuICBwYXRoIHRvIGEgZm9sZGVyIChjb2hvcnQpIHdpdGggbXVsdGlwbGUgY3N2IC0gcmVzdWx0aW5nIG91dHB1dCB3aWxsIGFuYWx5c2lzIGJlIGNhcnJpZWQgZm9yIHRoZSBjb2hvcnQgb2YgcGF0aWVudHMnIGNzdiBmaWxlcyBwcmVzZW50IGluIHRoZSBmb2xkZXIKCiMjIFRpbWUgdG8gRmlyc3QtRG9zZS1JbmNyZWFzZQoKLSAgIGB0aW1lX3RvX2ZpcnN0X2Rvc2VfaW5jcmVhc2UoKWAgLSBQbG90IHRoZSBncmFwaCBzaG93aW5nIG1lZGlhbiB0aW1lIHRvIGZpcnN0IDZNUCBkb3NlIGluY3JlYXNlIGZvciB0aGUgY29ob3J0IChpZiBpbnB1dCBmaWxlIGlzIGFuIGluZGl2aWR1YWwgcGF0aWVudCBpbnN0ZWFkIG9mIGNvaG9ydCwgZnVuY3Rpb24gZGlzcGxheXMgdmFsdWUgZm9yIGFuIGluZGl2aWR1YWwgcGF0aWVudCBpbiBxdWVzdGlvbikKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBSZWZlcmVuY2VzCg==