1 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.


2 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)1. 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:

  1. Convert maintenance sheets (Tata Medical Center Kolkata, India format or user dependent) into a cleaner, single csv with longitudinal data for each patient.

  2. Analyze MT

    • At an individual patient level

      • To track patient’s MT progression during or after therapy [3].

      • To track patient’s cycle-by-cycle MT progression during or after the therapy using summary measure (SM) weighted mean (6MP*MTX) vs weighted mean ANC parameters in a scatterplot.

    • At cohort level

      • SM plot to analyze MT for a given cohort defined by the user. SM is evaluated for each patient and plotted together to represent the entire cohort [3].

      • Compare SM for two different cohort defined by the user to evaluate MT practice. Cohort comparisons can include clinical interventions, year-wise practice evolution, patients treated by two different set of physicians, or as user see it fit [3].

  3. 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].

  4. Evaluate hematological toxicities - neutropenia, thrombocytopenia and anemia during MT for the individual patient or cohort.

  5. Evaluate/plot median time to first 6MP dose increase for the individual patient or cohort [3].

# library(allMT)

3 Data

  1. 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
  2. To use functions of the package, the data needs to be in a specific format as described in below example. Sample data2 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)
    

4 Functions

4.1 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.

4.2 Analyze MT Data

4.2.1 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.

4.2.2 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:

    • Method 1 - Comparison between cohorts that began MT before and after a particular user-provided date.

    • Method 2 - Comparison between more than 1 cohorts pre-determined by the user.

4.3 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

    1. path to a file for single patient csv - resulting output will be analysis for single patient
    2. 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

4.4 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

  1. path to a file for single patient csv - resulting output will be analysis for single patient
  2. 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

4.5 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.

  1. The work was initiated as part of Tushar Mungle’s PhD at IIT Kharagpur [3] and then continued at TTCRC, Tata Medical Center, Kolkata.↩︎

  2. Ethics approval statement: The anonymized clinical data set refers to patients treated on the ICiCLe-ALL-14 treatment protocol at the Tata Medical Center Kolkata (institutional review board approval EC/TMC/12/13 for the treatment protocol). Funding support for the ICiCLe-ALL-14 clinical study (Clinical Trials Registry-India reference CTRI/2015/12/006434) was provided by the National Cancer Grid (2016/001; 2016-) and the Indian Council of Medical Research (79/159/2015/NCD-III; 2017-19).↩︎

LS0tCnRpdGxlOiAiQW5hbHl6ZSBBY3V0ZSBMeW1waG9ibGFzdGljIExldWtlbWlhIE1haW50ZW5hbmNlIFRoZXJhcHkiCiMgc3VidGl0bGU6ICJUdXNoYXIgTXVuZ2xlJF4xJCReLCQkXjIkLCBBbmFueWEgTWFoYWRldmFuJF4yJCIKYXV0aG9yOgogIC0gbmFtZTogIlR1c2hhciBNdW5nbGUkXjEkJF4sJCReKiQkXiwkJF4rJCwgQW5hbnlhIE1haGFkZXZhbiReMSQkXiwkJF4qJCwgU2hla2hhciBLcmlzaG5hbiReMSQiCiAgICBhZmZpbGlhdGlvbjogJF4xJFRhdGEgVHJhbnNsYXRpb25hbCBDYW5jZXIgUmVzZWFyY2ggQ2VudHJlIChUVENSQyksIFRhdGEgTWVkaWNhbCBDZW50ZXIgKFRNQyksIEtvbGthdGEsIEluZGlhOyAkXiokY29udHJpYnV0ZWQgZXF1YWxseQogICAgZW1haWw6ICReKyQgQ29ycmVzcG9uZGVuY2UgLSB0dXNoYXIubXVuZ2xlQGdtYWlsLmNvbQogICAgI2VtYWlsOiAkXiokQ29ycmVzcG9uZGVuY2UgLSB0dXNoYXIubXVuZ2xlQGdtYWlsLmNvbQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgcm1hcmtkb3duOjpodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgIyB0aGVtZTogY2VydWxlYW4KICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogVFJVRQp2aWduZXR0ZTogPgogICVcVmlnbmV0dGVJbmRleEVudHJ5e0FuYWx5emUgQWN1dGUgTHltcGhvYmxhc3RpYyBMZXVrZW1pYSBNYWludGVuYW5jZSBUaGVyYXB5fQogICVcVmlnbmV0dGVFbmNvZGluZ3tVVEYtOH0KICAlXFZpZ25ldHRlRW5naW5le2tuaXRyOjpybWFya2Rvd259CkVuY29kaW5nOiBVVEYtOApiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCmNzbDogaWVlZS5jc2wKbGluay1jaXRhdGlvbnM6IHRydWUKIyBjc3M6ICIuLi9zdHlsZXMuY3NzIgplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgY29sbGFwc2UgPSBUUlVFLAogIGNvbW1lbnQgPSAiIz4iCikKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGJpYnRleCkKbGlicmFyeShib29rZG93bikKCnJlZnMgPC0gcmVhZC5iaWIoInJlZmVyZW5jZXMuYmliIikKa2V5cyA8LSBuYW1lcyhyZWZzKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBJbnRyb2R1Y3Rpb24KCioqKkFjdXRlIEx5bXBob2JsYXN0aWMgTGV1a2VtaWEqKiogKEFMTCkKCkFMTCB0cmVhdG1lbnQgaXMgYnJvYWRseSBkaXZpZGVkIGludG8gMiBwaGFzZXMgLSBJbnRlbnNpdmUgUGhhc2UgYW5kIE1haW50ZW5hbmNlIFBoYXNlLiBUaGUgaW50ZW5zaXZlIHBoYXNlIG9mIHRyZWF0bWVudCBpcyBmdXJ0aGVyIGRpdmlkZWQgaW50byA0IHN1Yi1waGFzZXMgLS0gaW5kdWN0aW9uLCBjb25zb2xpZGF0aW9uLCBpbnRlcmltIG1haW50ZW5hbmNlIGFuZCBkZWxheWVkIGludGVuc2lmaWNhdGlvbiBbQGRhczIwMjJwcm90b2NvbF0uCgpNYWludGVuYW5jZSB0aGVyYXB5IChNVCksIHRoZSBsb25nZXN0IHBoYXNlIG9mIEFMTCB0cmVhdG1lbnQgY29uc2lzdHMgb2YgXH4yIHllYXJzICg5NiB3ZWVrcyBvciA4IGN5Y2xlcyAtIDEyIHdlZWtzIHBlciBjeWNsZSkgW0BkYXMyMDIycHJvdG9jb2xdLiBQYXRpZW50cyBhcmUgYWR2aXNlZCB0byB2aXNpdCBob3NwaXRhbCBldmVyeSBhbHRlcm5hdGUgd2VlayAoZXZlcnkgdHdvIHdlZWtzKSBmb3IgY29uc3VsdGF0aW9uIGFuZCBvbiBhIHdlZWtseSBiYXNpcyBpbiBjYXNlIG9mIHRveGljaXRpZXMgKG5ldXRyb3BlbmlhLCB0aHJvbWJvY3l0b3BlbmlhIG9yIGFueSBvdGhlcikuIE92ZXJhbGwsIGEgcGF0aWVudCBzaG91bGQgaWRlYWxseSBoYXZlIGEgbWluaW11bSBvZiA0OCB2aXNpdHMgZHVyaW5nIE1ULiBEdXJpbmcgZWFjaCB2aXNpdCwgcGF0aWVudCdzIGJsb29kIHJlcG9ydCBpcyBleGFtaW5lZCBmb3IgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIC0gYWJzb2x1dGUgbmV1dHJvcGhpbCBjb3VudCAoQU5DKSwgcGxhdGVsZXQgY291bnQgKFBMVCkgYW5kIGhlbW9nbG9iaW4gKEhCKSB0byAqKiphZGp1c3QqKiogKG9yIGRvc2UgdGl0cmF0aW9ucykgdGhlIGRydWdzOiA2LW1lcmNhcHRvcHVyaW5lICg2TVApIGFuZCBNZXRob3RyZXhhdGUgKE1UWCkgdGhhdCBhcmUgcHJlc2NyaWJlZCBvbiB3ZWVrbHkgYmFzaXMuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgUGFja2FnZQoKQUxMIHN0dWRpZXMsIGFjcm9zcyB0aGUgZ2xvYmUsIGhhdmUgc2hvd24gdGhhdCBkZWxpdmVyaW5nIG9wdGltYWwgTVQgaXMgY3J1Y2lhbCB0byBhY2hpZXZlIGJldHRlciB0cmVhdG1lbnQgb3V0Y29tZXMgW0BzY2htaWVnZWxvdzIwMTRtZXJjYXB0b3B1cmluZV0uIERlbGl2ZXJpbmcgb3B0aW1hbCBNVCBpcyBlbnN1cmVkIGJ5IHByZXNjcmliaW5nIG1heGltdW0gdG9sZXJhdGVkIDZNUCBhbmQgTVRYIGRvc2VzIHRoYXQgYXJlIGFkanVzdGVkIHBhdGllbnQncyBob3NwaXRhbCB2aXNpdC4gSW4gdmlldyBvZiB0aGlzLCB0aGUgcGFja2FnZSB3YXMgY3JlYXRlZCB0byBhbmFseXNlIGFuZCB2aXN1YWxpemUgdGhlIEFMTCBNVCBkYXRhIChBTkMvUExUL0hCLzZNUC9NVFgpW14xXS4gVGhlIHVzZSBvZiBwYWNrYWdlIHdvdWxkIGFzc2lzdCBwaHlzaWNpYW5zIHRvIGV2YWx1YXRlIE1UIGZvciBhIGdpdmVuIHBhdGllbnQgb3IgYSBjb2hvcnQgYXQgYW55IGNlbnRlci4gQWx0aG91Z2gsIHRoZSBwYWNrYWdlIHdhcyBkZXZlbG9wZWQgY29uc2lkZXJpbmcgdGhlIElDaUNMZS1BTEwtMTQgcHJvdG9jb2wgW0BkYXMyMDIycHJvdG9jb2xdIGFzIGRlZmF1bHQsIGl0IGNhbiBiZSB1c2VkIHRvIGFuYWx5emUgZGF0YSBmcm9tIGNlbnRlcnMgd2l0aCBkaWZmZXJlbnQgTVQgcHJvdG9jb2xzLiBJbiBjYXNlIG9mIGRpZmZlcmVudCBwcm90b2NvbCwgdGhlIHVzZXIgd2lsbCBuZWVkIHRvIGFsdGVyIHRoZSBkZWZpbmVkIHBhcmFtZXRlcnMgc3BlY2lmaWMgdG8gcHJvdG9jb2wgYXMgZnVuY3Rpb24gYXJndW1lbnRzLgoKW14xXTogVGhlIHdvcmsgd2FzIGluaXRpYXRlZCBhcyBwYXJ0IG9mIFR1c2hhciBNdW5nbGUncyBQaEQgYXQgSUlUIEtoYXJhZ3B1ciBbQG11bmdsZTIwMjBtb2RlbGxpbmddIGFuZCB0aGVuIGNvbnRpbnVlZCBhdCBUVENSQywgVGF0YSBNZWRpY2FsIENlbnRlciwgS29sa2F0YS4KClVzaW5nIHRoaXMgcGFja2FnZSB0aGUgdXNlciBtYXk6CgoxLiAgQ29udmVydCBtYWludGVuYW5jZSBzaGVldHMgKFRhdGEgTWVkaWNhbCBDZW50ZXIgS29sa2F0YSwgSW5kaWEgZm9ybWF0IG9yIHVzZXIgZGVwZW5kZW50KSBpbnRvIGEgY2xlYW5lciwgc2luZ2xlIGNzdiB3aXRoIGxvbmdpdHVkaW5hbCBkYXRhIGZvciBlYWNoIHBhdGllbnQuCgoyLiAgQW5hbHl6ZSBNVAoKICAgIC0gICBBdCBhbiBpbmRpdmlkdWFsIHBhdGllbnQgbGV2ZWwKCiAgICAgICAgLSAgIFRvIHRyYWNrIHBhdGllbnQncyBNVCBwcm9ncmVzc2lvbiBkdXJpbmcgb3IgYWZ0ZXIgdGhlcmFweSBbQG11bmdsZTIwMjBtb2RlbGxpbmddLgoKICAgICAgICAtICAgVG8gdHJhY2sgcGF0aWVudCdzIGN5Y2xlLWJ5LWN5Y2xlIE1UIHByb2dyZXNzaW9uIGR1cmluZyBvciBhZnRlciB0aGUgdGhlcmFweSB1c2luZyBzdW1tYXJ5IG1lYXN1cmUgKFNNKSB3ZWlnaHRlZCBtZWFuICg2TVBcKk1UWCkgdnMgd2VpZ2h0ZWQgbWVhbiBBTkMgcGFyYW1ldGVycyBpbiBhIHNjYXR0ZXJwbG90LgoKICAgIC0gICBBdCBjb2hvcnQgbGV2ZWwKCiAgICAgICAgLSAgIFNNIHBsb3QgdG8gYW5hbHl6ZSBNVCBmb3IgYSBnaXZlbiBjb2hvcnQgZGVmaW5lZCBieSB0aGUgdXNlci4gU00gaXMgZXZhbHVhdGVkIGZvciBlYWNoIHBhdGllbnQgYW5kIHBsb3R0ZWQgdG9nZXRoZXIgdG8gcmVwcmVzZW50IHRoZSBlbnRpcmUgY29ob3J0IFtAbXVuZ2xlMjAyMG1vZGVsbGluZ10uCgogICAgICAgIC0gICBDb21wYXJlIFNNIGZvciB0d28gZGlmZmVyZW50IGNvaG9ydCBkZWZpbmVkIGJ5IHRoZSB1c2VyIHRvIGV2YWx1YXRlIE1UIHByYWN0aWNlLiBDb2hvcnQgY29tcGFyaXNvbnMgY2FuIGluY2x1ZGUgY2xpbmljYWwgaW50ZXJ2ZW50aW9ucywgeWVhci13aXNlIHByYWN0aWNlIGV2b2x1dGlvbiwgcGF0aWVudHMgdHJlYXRlZCBieSB0d28gZGlmZmVyZW50IHNldCBvZiBwaHlzaWNpYW5zLCBvciBhcyB1c2VyIHNlZSBpdCBmaXQgW0BtdW5nbGUyMDIwbW9kZWxsaW5nXS4KCjMuICBFdmFsdWF0ZSByZWFsIHRpbWUgZG9zaW5nIGRlY2lzaW9ucyAoc3RvcCwgcmVkdWNlIG9yIGluY3JlYXNlKSBieSB0aGUgcGh5c2ljaWFucyBkdXJpbmcgTVQgYmFzZWQgb24gTVQgZG9zaW5nIGd1aWRlbGluZXMgZm9yIHRoZSBpbmRpdmlkdWFsIHBhdGllbnQgb3IgY29ob3J0IFtAbXVuZ2xlMjAyMG1vZGVsbGluZ10uCgo0LiAgRXZhbHVhdGUgaGVtYXRvbG9naWNhbCB0b3hpY2l0aWVzIC0gbmV1dHJvcGVuaWEsIHRocm9tYm9jeXRvcGVuaWEgYW5kIGFuZW1pYSBkdXJpbmcgTVQgZm9yIHRoZSBpbmRpdmlkdWFsIHBhdGllbnQgb3IgY29ob3J0LgoKNS4gIEV2YWx1YXRlL3Bsb3QgbWVkaWFuIHRpbWUgdG8gZmlyc3QgNk1QIGRvc2UgaW5jcmVhc2UgZm9yIHRoZSBpbmRpdmlkdWFsIHBhdGllbnQgb3IgY29ob3J0IFtAbXVuZ2xlMjAyMG1vZGVsbGluZ10uCgpgYGB7ciBzZXR1cH0KIyBsaWJyYXJ5KGFsbE1UKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBEYXRhCgoxLiAgVGhlIGRhdGEgcmVjb3JkaW5nIHNoZWV0IHVzZWQgYnkgVE1DIGNhbiBiZSBkb3dubG9hZGVkL2NvcGllZCBhcwoKICAgIGBgYHtyfQogICAgIyBVbmNvbW1lbnQgYmVsb3cgbGluZSBiZWZvcmUgcnVubmluZyB0aGUgc25pcHBldAogICAgIyBsaWJyYXJ5KGFsbE1UKQogICAgcGF0X2RhdGEgPC0gc3lzdGVtLmZpbGUoImV4dGRhdGEvdG1jX2RhdGEvIiwgIlVQTl85MTYueGxzIiwgcGFja2FnZSA9ICJhbGxNVCIpCiAgICBkZXN0X3BhdGggPC0gZ2V0d2QoKSAjIHVzZXIgbWF5IGNob29zZSBhIGRpZmZlcmVudCBkZXN0aW5hdGlvbiAKICAgIGZpbGUuY29weShwYXRfZGF0YSwgZGVzdF9wYXRoKQogICAgYGBgCgoyLiAgVG8gdXNlIGZ1bmN0aW9ucyBvZiB0aGUgcGFja2FnZSwgdGhlIGRhdGEgbmVlZHMgdG8gYmUgaW4gYSBzcGVjaWZpYyBmb3JtYXQgYXMgZGVzY3JpYmVkIGluIGJlbG93IGV4YW1wbGUuIFNhbXBsZSBkYXRhW14yXSBmb3IgMyBpbmRpdmlkdWFsIHBhdGllbnQgaXMgYXZhaWxhYmxlIGFzIFVQTl85MTQsIFVQTl85MTUsIGFuZCBVUE5fOTE2IGFzIHJkYSB3aXRoIHRoZSBsaWJyYXJ5IGZvciB2aWV3aW5nLiBBZGRpdGlvbmFsbHksIFVQTl85MTQsIFVQTl85MTUsIFVQTl85MTYsIFVQTl85MTcgYW5kIFVQTl85MTggYXJlIHByZXNlbnQgdW5kZXIgdGhlIGZvbGRlciAiL2V4dGRhdGEvcHJvY2Vzc2VkX2RhdGEvIiBhcyBjc3YgZm9ybWF0IHRvIHJ1biBhbnkgZXhhbXBsZXMuCgogICAgRGF0YSBjYW4gYmUgY2hlY2tlZCBvciBzYXZlZCBhcwogICAgCiAgICBgYGB7cn0KICAgICMgQmVsb3cgY29kZSBzaG91bGQgd29yayBmb3IgYW55IHVzZXIgaW5kZXBlbmRlbnQgb2YgT1MKICAgICMgcGF0X2RhdGEgPC0gc3lzdGVtLmZpbGUoImV4dGRhdGEvcHJvY2Vzc2VkX2RhdGEvIiwgIlVQTl85MTYuY3N2IiwgcGFja2FnZSA9ICJhbGxNVCIpCiAgICAjIHBhdF9kZiA8LSB1dGlsczo6cmVhZC5jc3YocGF0X2RhdGEsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIikKICAgICMgIyBoZWFkKHBhdF9kZikKCiAgICBgYGAKClteMl06IEV0aGljcyBhcHByb3ZhbCBzdGF0ZW1lbnQ6IFRoZSBhbm9ueW1pemVkIGNsaW5pY2FsIGRhdGEgc2V0IHJlZmVycyB0byBwYXRpZW50cyB0cmVhdGVkIG9uIHRoZSBJQ2lDTGUtQUxMLTE0IHRyZWF0bWVudCBwcm90b2NvbCBhdCB0aGUgVGF0YSBNZWRpY2FsIENlbnRlciBLb2xrYXRhIChpbnN0aXR1dGlvbmFsIHJldmlldyBib2FyZCBhcHByb3ZhbCBFQy9UTUMvMTIvMTMgZm9yIHRoZSB0cmVhdG1lbnQgcHJvdG9jb2wpLiBGdW5kaW5nIHN1cHBvcnQgZm9yIHRoZSBJQ2lDTGUtQUxMLTE0IGNsaW5pY2FsIHN0dWR5IChDbGluaWNhbCBUcmlhbHMgUmVnaXN0cnktSW5kaWEgcmVmZXJlbmNlIENUUkkvMjAxNS8xMi8wMDY0MzQpIHdhcyBwcm92aWRlZCBieSB0aGUgTmF0aW9uYWwgQ2FuY2VyIEdyaWQgKDIwMTYvMDAxOyAyMDE2LSkgYW5kIHRoZSBJbmRpYW4gQ291bmNpbCBvZiBNZWRpY2FsIFJlc2VhcmNoICg3OS8xNTkvMjAxNS9OQ0QtSUlJOyAyMDE3LTE5KS4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBGdW5jdGlvbnMKCiMjIENvbnZlcnQgRGF0YQoKLSAgIGBjb252ZXJ0X3RtY19mb3JtYXQoKWAgLSBDb252ZXJ0IGluZm9ybWF0aW9uIHJlY29yZGVkIGluIHRoZSBUTUMgZGF0YXNoZWV0IGZvcm1hdCB0byBhIGZvcm1hdCB0aGF0IHdpbGwgYmUgdXNlZCBieSBwYWNrYWdlIGZ1bmN0aW9ucy4KCi0gICBgY29udmVydF9leHRlcm5hbF9mb3JtYXQoKWAgLSBDb252ZXJ0IE1UIGluZm9ybWF0aW9uICh1c2VyIGRlZmluZWQpIHRvIGEgZm9ybWF0IHRoYXQgd2lsbCBiZSB1c2VkIGJ5IHBhY2thZ2UgZnVuY3Rpb25zLlwKICAgIFsqTm90ZToqXXsudW5kZXJsaW5lfSBVc2VyIG5lZWQgdG8gZW5zdXJlIHRoZSBNVCBpbmZvcm1hdGlvbiBpcyBzdG9yZWQgaW4gYW4gZXhjZWwgb3IgY3N2IHdpdGggY29sdW1uIG5hbWVzIGFzIC0gRGF0ZXMsIEFOQywgUExULCBNUCwgTVRYLiBUaGUgZnVuY3Rpb24gd2lsbCBjb252ZXJ0IHRoaXMgc2hlZXQgaW50byByZXF1aXJlZCBmb3JtYXQuCgpUaGUgb3V0cHV0IG9mIGJvdGggdGhlIGZ1bmN0aW9ucyB3aWxsIHJlc3VsdCBpbiBzdGFuZGFyZCBwYXRpZW50IGNzdiBmaWxlcyAoYXMgZGVzY3JpYmVkIERhdGEgc2VjdGlvbikgc2F2ZWQgaW4gYSBmb2xkZXIgZGVmaW5lZCBieSB0aGUgdXNlci4KCiMjIEFuYWx5emUgTVQgRGF0YQoKIyMjIEF0IGluZGl2aWR1YWwgcGF0aWVudCBsZXZlbAoKLSAgIGBwbG90X3Byb2dyZXNzaW9uKClgIC0gUGxvdCBsaW5lIGdyYXBoIHNob3dpbmcgaGlzdG9yaWNhbCBsb25naXR1ZGluYWwgdHJlbmRzIG9mIEFOQywgNk1QIGFuZCBNVFggZm9yIGEgc2luZ2xlIHBhdGllbnQuIFRoaXMgZnVuY3Rpb24gY2FuIGJlIHVzZSBieSB0aGUgZG9jdG9ycyBkdXJpbmcgdGhlIE1UIGNsaW5pYyB0byBtb25pdG9yIHBhdGllbnRzJyBNVCBkb3NlIHByZXNjcmlwdGlvbiBhbmQgdHJlYXRtZW50IHJlc3BvbnNlIGluIHJlYWwgdGltZS4KCi0gICBgc3VtbWFyaXplX2N5Y2xlX3Byb2dyZXNzaW9uKClgIC0gUGxvdCBTTSBkYXRhIHBlciBjeWNsZSBmb3IgZ2l2ZW4gcGF0aWVudCBkYXRhLiBVdGlsaXR5IGFzIGFib3ZlLgoKIyMjIEF0IGNvaG9ydCBsZXZlbAoKLSAgIGBzdW1tYXJpemVfY29ob3J0TVQoKWAgLSBQbG90IHNjYXR0ZXIgcGxvdCAoU00pIGZvciBhbGwgdGhlIHBhdGllbnRzIGZyb20gdXNlciBkZWZpbmVkIGNvaG9ydC4KCi0gICBgY29tcGFyZV9jb2hvcnRzKClgIC0gUGxvdCBzY2F0dGVyIHBsb3QgKFNNKSBmb3IgYWxsIHRoZSBwYXRpZW50cyBwcmVzZW50IGluIHVzZXIgZGVmaW5lZCBtdWx0aXBsZSBjb2hvcnRzIChtb3JlIHRoYW4gMSBjb2hvcnQpIC4gVHdvIG1ldGhvZHMgb2YgY29ob3J0IGNvbXBhcmlzb24gY2FuIGJlIGNvbnNpZGVyZWQgZm9yIGFuYWx5c2lzIGFzIG1lbnRpb25lZCBiZWxvdzoKCiAgICAtICAgTWV0aG9kIDEgLSBDb21wYXJpc29uIGJldHdlZW4gY29ob3J0cyB0aGF0IGJlZ2FuIE1UIGJlZm9yZSBhbmQgYWZ0ZXIgYSBwYXJ0aWN1bGFyIHVzZXItcHJvdmlkZWQgZGF0ZS4KCiAgICAtICAgTWV0aG9kIDIgLSBDb21wYXJpc29uIGJldHdlZW4gbW9yZSB0aGFuIDEgY29ob3J0cyBwcmUtZGV0ZXJtaW5lZCBieSB0aGUgdXNlci4KCiMjIEV2YWx1YXRlIFBoeXNpY2lhbnMnIERvc2luZyBEZWNpc2lvbnMKCi0gICBgYXNzZXNzX3N0b3BfZG9zZXMoKWAgLSBUaGUgZnVuY3Rpb24gZXZhbHVhdGVzIHRoZSBpbmNpZGVuY2Ugb2YgJ05vIERvc2UnIHBoeXNpY2lhbidzIGRlY2lzaW9ucyB0aGF0IGFyZSBOT1Qgc3VwcG9ydGVkIGJ5IHByb3RvY29sLWJhc2VkIHRhcmdldCBibG9vZCBjb3VudHMuCgotICAgYGFzc2Vzc19yZWR1Y2VkX2Rvc2VzKClgIC0gVGhlIGZ1bmN0aW9uIGV2YWx1YXRlcyB0aGUgaW5jaWRlbmNlIG9mICdSZWR1Y2UgRG9zZScgcGh5c2ljaWFuJ3MgZGVjaXNpb25zIHRoYXQgYXJlIE5PVCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wtYmFzZWQgdGFyZ2V0IGJsb29kIGNvdW50cy4KCi0gICBgYXNzZXNzX2luY3JlYXNlZF9kb3NlcygpYCAtIFRoZSBmdW5jdGlvbiBldmFsdWF0ZXMgdGhlIGluY2lkZW5jZSBvZiAnSW5jcmVhc2UgRG9zZScgcGh5c2ljaWFuJ3MgZGVjaXNpb25zIHRoYXQgYXJlIE5PVCBzdXBwb3J0ZWQgYnkgcHJvdG9jb2wtYmFzZWQgdGFyZ2V0IGJsb29kIGNvdW50cy4KCiAgICBbKk5vdGU6Kl17LnVuZGVybGluZX0gRGVwZW5kaW5nIHVwb24gdmFsdWUgcHJvdmlkZWQgZm9yIHRoZSBhcmd1bWVudCAnaW5wdXRfZmlsZXNfcGF0aCcgYXMgYQoKICAgIDEuICBwYXRoIHRvIGEgZmlsZSBmb3Igc2luZ2xlIHBhdGllbnQgY3N2IC0gcmVzdWx0aW5nIG91dHB1dCB3aWxsIGJlIGFuYWx5c2lzIGZvciBzaW5nbGUgcGF0aWVudAogICAgMi4gIHBhdGggdG8gYSBmb2xkZXIgKGNvaG9ydCkgd2l0aCBtdWx0aXBsZSBjc3YgLSByZXN1bHRpbmcgb3V0cHV0IHdpbGwgYmUgYW5hbHlzaXMgY2FycmllZCBmb3IgdGhlIGNvaG9ydCBvZiBwYXRpZW50cycgY3N2IGZpbGVzIHByZXNlbnQgaW4gdGhlIGZvbGRlcgoKIyMgRXZhbHVhdGUgSGVtYXRvbG9naWNhbCBUb3hpY2l0aWVzCgotICAgYGFzc2Vzc19uZXV0cm9wZW5pYSgpYCAtIFRoZSBmdW5jdGlvbiBldmFsdWF0ZXMgbnVtYmVyIG9mIG5ldXRyb3BlbmlhIGVwaXNvZGVzIGFzIHBlciB0aGUgbmV1dHJvcGVuaWEgZGVmaW5pdGlvbiBwcm92aWRlZCBpbiAnYW5jX3JhbmdlJyBhcmd1bWVudCAtIGMoYSxiKS4gYSBpcyBkZWZpbmVkIGFzIGhpZ2hlc3QgdmFsdWUgb2YgQU5DIHRocmVzaG9sZCBmb3IgbmV1dHJvcGVuaWMgY29uZGl0aW9uLCBhbmQgYiBpcyBkZWZpbmVkIGFzIEFOQyB2YWx1ZSBhYm92ZSB3aGljaCBuZXV0cm9wZW5pYyBjb25kaXRpb24gaXMgc2FpZCB0byBiZSByZWNvdmVyZWQuCgotICAgYGFzc2Vzc190aHJvbWJvY3l0b3BlbmlhKClgIC0gVGhlIGZ1bmN0aW9uIGV2YWx1YXRlcyBudW1iZXIgb2YgdGhyb21ib2N5dG9wZW5pYSBlcGlzb2RlcyBhcyBwZXIgdGhlIHRocm9tYm9jeXRvcGVuaWEgZGVmaW5pdGlvbiBwcm92aWRlZCBpbiAncGx0X3JhbmdlJyBhcmd1bWVudCAtIGMoYSxiKS4gYSBpcyBkZWZpbmVkIGFzIGhpZ2hlc3QgdmFsdWUgb2YgUExUIHRocmVzaG9sZCBmb3IgdGhyb21ib2N5dG9wZW5pYSBjb25kaXRpb24sIGFuZCBiIGlzIGRlZmluZWQgYXMgUExUIHZhbHVlIGFib3ZlIHdoaWNoIHRocm9tYm9jeXRvcGVuaWMgY29uZGl0aW9uIGlzIHNhaWQgdG8gYmUgcmVjb3ZlcmVkLgoKLSAgIGBhc3Nlc3NfYW5lbWlhKClgIC0gVGhlIGZ1bmN0aW9uIGV2YWx1YXRlcyBudW1iZXIgb2YgYW5lbWlhIGVwaXNvZGVzIGFzIHBlciB0aGUgYW5lbWlhIGRlZmluaXRpb24gcHJvdmlkZWQgaW4gJ2hiX3JhbmdlJyBhcmd1bWVudCAtIGMoYSxiKS4gYSBpcyBkZWZpbmVkIGFzIGhpZ2hlc3QgdmFsdWUgb2YgSGIgdGhyZXNob2xkIGZvciBhbmVtaWEgY29uZGl0aW9uLCBhbmQgYiBpcyBkZWZpbmVkIGFzIEhiIHZhbHVlIGFib3ZlIHdoaWNoIGFuZW1pYyBjb25kaXRpb24gaXMgc2FpZCB0byBiZSByZWNvdmVyZWQuCgpbKk5vdGU6Kl17LnVuZGVybGluZX0gRGVwZW5kaW5nIHVwb24gdmFsdWUgcHJvdmlkZWQgZm9yIHRoZSBhcmd1bWVudCAnaW5wdXRfZmlsZXNfcGF0aCcgYXMgYQoKMS4gIHBhdGggdG8gYSBmaWxlIGZvciBzaW5nbGUgcGF0aWVudCBjc3YgLSByZXN1bHRpbmcgb3V0cHV0IHdpbGwgYmUgYW5hbHlzaXMgZm9yIHNpbmdsZSBwYXRpZW50CjIuICBwYXRoIHRvIGEgZm9sZGVyIChjb2hvcnQpIHdpdGggbXVsdGlwbGUgY3N2IC0gcmVzdWx0aW5nIG91dHB1dCB3aWxsIGFuYWx5c2lzIGJlIGNhcnJpZWQgZm9yIHRoZSBjb2hvcnQgb2YgcGF0aWVudHMnIGNzdiBmaWxlcyBwcmVzZW50IGluIHRoZSBmb2xkZXIKCiMjIFRpbWUgdG8gRmlyc3QtRG9zZS1JbmNyZWFzZQoKLSAgIGB0aW1lX3RvX2ZpcnN0X2Rvc2VfaW5jcmVhc2UoKWAgLSBQbG90IHRoZSBncmFwaCBzaG93aW5nIG1lZGlhbiB0aW1lIHRvIGZpcnN0IDZNUCBkb3NlIGluY3JlYXNlIGZvciB0aGUgY29ob3J0IChpZiBpbnB1dCBmaWxlIGlzIGFuIGluZGl2aWR1YWwgcGF0aWVudCBpbnN0ZWFkIG9mIGNvaG9ydCwgZnVuY3Rpb24gZGlzcGxheXMgdmFsdWUgZm9yIGFuIGluZGl2aWR1YWwgcGF0aWVudCBpbiBxdWVzdGlvbikKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBSZWZlcmVuY2VzCg==