WHO SMART Guidelines - HIV
0.4.3 - ci-build

WHO SMART Guidelines - HIV - Local Development build (v0.4.3) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

: HIVCommon - JSON Representation

Draft as of 2025-02-07

Raw json | Download

{
  "resourceType" : "Library",
  "id" : "HIVCommon",
  "meta" : {
    "profile" : [
      🔗 "http://hl7.org/fhir/uv/crmi/StructureDefinition/crmi-shareablelibrary"🔗 ,
      "http://hl7.org/fhir/uv/crmi/StructureDefinition/crmi-publishablelibrary"🔗 ,
      "http://hl7.org/fhir/uv/cql/StructureDefinition/cql-library"🔗 ,
      "http://hl7.org/fhir/uv/cql/StructureDefinition/cql-module"
    ]
  },
  "text" : {
    "status" : "extensions",
    "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n<div>\n    <table class=\"grid dict\">\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Title: </b></th>\n            <td style=\"padding-left: 4px;\">HIVCommon</td>\n        </tr>\n        \n\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Id: </b></th>\n            <td style=\"padding-left: 4px;\">HIVCommon</td>\n        </tr>\n        \n\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Version: </b></th>\n            <td style=\"padding-left: 4px;\">0.4.3</td>\n        </tr>\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Url: </b></th>\n            <td style=\"padding-left: 4px;\"><a href=\"Library-HIVCommon.html\">HIVCommon</a></td>\n        </tr>\n        \n\n        \n\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Status: </b></th>\n            <td style=\"padding-left: 4px;\">draft</td>\n        </tr>\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Experimental: </b></th>\n            <td style=\"padding-left: 4px;\">true</td>\n        </tr>\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Type: </b></th>\n            <td style=\"padding-left: 4px;\">\n                \n                    \n                        \n                        <p style=\"margin-bottom: 5px;\">\n                            <b>system: </b> <span><a href=\"http://terminology.hl7.org/6.0.2/CodeSystem-library-type.html\">http://terminology.hl7.org/CodeSystem/library-type</a></span>\n                        </p>\n                        \n                        \n                        <p style=\"margin-bottom: 5px;\">\n                            <b>code: </b> <span>logic-library</span>\n                        </p>\n                        \n                        \n                    \n                \n                \n            </td>\n        </tr>\n        \n\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Date: </b></th>\n            <td style=\"padding-left: 4px;\">2025-02-07 14:15:45+0000</td>\n        </tr>\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Publisher: </b></th>\n            <td style=\"padding-left: 4px;\">WHO</td>\n        </tr>\n        \n\n        \n        <tr>\n            <th scope=\"row\"><b>Description: </b></th>\n            <td style=\"padding-left: 4px;\"><div><p>Description not yet available for HIVCommon.</p>\n</div></td>\n        </tr>\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n\n        \n        \n        <tr>\n          <td colspan=\"2\">\n            <table>\n              <tr><th><a id=\"cql-content\"><b>Content: </b></a> text/cql</th></tr>\n              <tr><td><pre><code class=\"language-cql\">library HIVCommon version '0.0.1' \n\nusing FHIR version '4.0.1'\n\ninclude FHIRHelpers version '4.0.1'\ninclude WHOCommon called WCom\n\ninclude HIVConcepts called Concepts\ninclude HIVConceptsCustom called CustomConcepts\n\ncontext Patient\n\n//VERIFIED\n\n\n//DRAFT\n\n//need to add Time to start ART (within 7, 30 or 90 days of diagnosis, as per country guidelines)\n//need to add Disaggregation by time since diagnosis\n  \n\n\n/* \n* DAK has codes for HAART misspecified \n* ICD-10 Z92.2\tOther prophylactic chemotherapy\t\t\n* LOINC &quot;54825-5\t&quot;\tOn scheduled pain medication regimen in last 7 days\n*\n* Should discuss \n*/\n\n\n\n\n\n\n\n/*\n* Kenya EMR defined as HIV positive condition\n* Will need to discuss if produce flags through conditions for concepts to use in indicator calculation such as HIV positive and On ART\n* However, we have moved forward with a more prescriptive approach \n* Inevitably our approach requires that certain data elements be available\n*/\n\n/*\n * HIV Treatment during the measurement period\n * uses dosage and dispensation amount to estimate last day of medication\n * medication should be dispensed before end of measurement period\n * medication should last until after 28 days after the end of the measurement period\n * This takes into account lost to follow up\n */\n\n/*\n*define &quot;HIV Treatment during the measurement period&quot;:\n*   [MedicationDispense] MD\n*    where MD.status in { 'final', 'amended', 'corrected' }\n*    and MD.medication ~ 'Antiretroviral'\n*    and MD.whenHandedOver before end of &quot;Measurement Period&quot;\n*    and (MD.whenHandedOver + MD.dosageInstruction[0].timing.repeat.duration.value * MedicationDispense.quantity.value) after (measurementPeriod.end - 28 days)\n*/ \n\n/*\n* Immunization defines HAART as\n*  exists([MedicationAdministration] A where ExtractMedicationCode(A.medication) in IMMZc.&quot;ARV Drugs&quot; and A.status = 'in-progress')\n* I believe this is the incorrect resource unless they mean to say that medication is given during a medical encounter\n* would like to discuss \n*/ \n\n/** \n * Patient Deceased During Measurement Period\n * Immunization defines this as true when is a boolean. This may have the effect of deleting a person from indicators in all calculations\n * Should intend to use when patient.deceased FHIR boolean was updated to TRUE if no other date is available\n * Kenya EMR example does not account for when deceased is just a boolean\n */\n\n\n/*\ndefine &quot;PREP Prescription Days&quot;:\n  Sum(\n    (\n      collapse (\n        [MedicationRequest] MR\n          where MR.status = 'completed'\n          and MR.intent = 'order'\n          and MR.medication ~ Concepts.&quot;PrEP for HIV prevention&quot;\n        return WComV2.&quot;Prescription Relevant Period&quot;( MR ) intersect &quot;Measurement Period&quot;\n      )\n    ) PREPUseInterval\n      return days between start of PREPUseInterval and end of PREPUseInterval\n  )\n*/\n\n\ndefine function GetDurationInDays(value FHIR.Duration): // returns Decimal:\n    case value.code.value\n      when 'a' then value.value * 365.0\n      when 'mo' then value.value.value * 30.0\n      when 'wk' then value.value.value * 7.0\n      when 'd' then value.value.value\n      when 'h' then value.value.value / 24.0\n      when 'min' then value.value.value / 60.0 / 24.0\n      when 's' then value.value.value / 60.0 / 60.0 / 24.0\n      when 'ms' then value.value.value / 60.0 / 60.0 / 24.0 / 1000.0\n      else Message(1000, true, 'Undefined', 'Error', 'Unsupported duration unit ' + value.code.value)\n    end\n\ndefine function &quot;Prescription Relevant Period&quot;(prescription FHIR.MedicationRequest):\n  if (\n    prescription.authoredOn is not null and prescription.dispenseRequest is not null\n      and prescription.dispenseRequest.expectedSupplyDuration is not null\n  )\n  then Interval[\n    date from prescription.authoredOn,\n    date from prescription.authoredOn + System.Quantity{ value: GetDurationInDays(prescription.dispenseRequest.expectedSupplyDuration), unit: 'days' }\n  ]\n  else null\n\n//System.Integer\ndefine function ToDaily(frequency System.Integer, period System.Quantity):\n  case period.unit\n    when 'h' then frequency * (24.0 / period.value)\n    when 'min' then frequency * (24.0 / period.value) * 60\n    when 's' then frequency * (24.0 / period.value) * 60 * 60\n    when 'd' then frequency * (24.0 / period.value) / 24\n    when 'wk' then frequency * (24.0 / period.value) / (24 * 7)\n    when 'mo' then frequency * (24.0 / period.value) / (24 * 30) /* assuming 30 days in month */\n    when 'a' then frequency * (24.0 / period.value) / (24 * 365) /* assuming 365 days in year */\n    when 'hour' then frequency * (24.0 / period.value)\n    when 'minute' then frequency * (24.0 / period.value) * 60\n    when 'second' then frequency * (24.0 / period.value) * 60 * 60\n    when 'day' then frequency * (24.0 / period.value) / 24\n    when 'week' then frequency * (24.0 / period.value) / (24 * 7)\n    when 'month' then frequency * (24.0 / period.value) / (24 * 30) /* assuming 30 days in month */\n    when 'year' then frequency * (24.0 / period.value) / (24 * 365) /* assuming 365 days in year */\n    when 'hours' then frequency * (24.0 / period.value)\n    when 'minutes' then frequency * (24.0 / period.value) * 60\n    when 'seconds' then frequency * (24.0 / period.value) * 60 * 60\n    when 'days' then frequency * (24.0 / period.value) / 24\n    when 'weeks' then frequency * (24.0 / period.value) / (24 * 7)\n    when 'months' then frequency * (24.0 / period.value) / (24 * 30) /* assuming 30 days in month */\n    when 'years' then frequency * (24.0 / period.value) / (24 * 365) /* assuming 365 days in year */\n    else null\n  end\n\n  define function &quot;HasEnd&quot;(period Interval&lt;DateTime&gt; ):\n  not (end of period is null\n    or end of period = maximum DateTime\n)\n\n  define fluent function MedicationRequestPeriod(Request MedicationRequest):\n  Request R\n    let\n      dosage: singleton from R.dosageInstruction,\n      doseAndRate: singleton from dosage.doseAndRate,\n      doseRange: doseAndRate.dose as Range,\n      doseQuantity: doseAndRate.dose as SimpleQuantity,\n      dose: Coalesce(end of doseRange, doseQuantity),\n      timing: dosage.timing,\n      frequency: Coalesce(timing.repeat.frequencyMax, timing.repeat.frequency),\n      period: System.Quantity { value: timing.repeat.period, unit: timing.repeat.periodUnit.value },\n      dosesPerDay: Coalesce(ToDaily(FHIRHelpers.ToInteger(frequency), period), Count(timing.repeat.timeOfDay), 1.0),\n      boundsPeriod: timing.repeat.bounds as Period,\n      daysSupply: R.dispenseRequest.expectedSupplyDuration,\n      quantity: R.dispenseRequest.quantity,\n      refills: Coalesce(R.dispenseRequest.numberOfRepeatsAllowed, 0),\n      startDate:\n        Coalesce(\n          start of boundsPeriod,\n          start of R.dispenseRequest.validityPeriod,\n          R.authoredOn\n        )\n    return\n      if HasEnd(boundsPeriod) then\n        Interval[startDate, end of boundsPeriod]\n      else\n        (\n          Coalesce(daysSupply, quantity / (dose * dosesPerDay))\n            * (1 + refills)\n        ) durationInDays\n          return Interval[startDate, startDate + durationInDays]\n\n\ndefine function &quot;DosesPerDay&quot;(frequency Code):\n\t/*Calculates the cumulative dose per day for each prescription*/\n\tcase\n\t\twhen frequency ~ CustomConcepts.&quot;Once daily (qualifier value)&quot; then 1.0\n\t\twhen frequency ~ CustomConcepts.&quot;Twice a day (qualifier value)&quot; then 2.0\n\t\twhen frequency ~ CustomConcepts.&quot;Three times daily (qualifier value)&quot; then 3.0\n\t\twhen frequency ~ CustomConcepts.&quot;Four times daily (qualifier value)&quot; then 4.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every twenty four hours (qualifier value)&quot; then 1.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every twelve hours (qualifier value)&quot; then 2.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every thirty six hours (qualifier value)&quot; then 0.67\n\t\twhen frequency ~ CustomConcepts.&quot;Every eight hours (qualifier value)&quot; then 3.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every four hours (qualifier value)&quot; then 6.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every six hours (qualifier value)&quot; then 4.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every seventy two hours (qualifier value)&quot; then 0.34\n\t\twhen frequency ~ CustomConcepts.&quot;Every forty eight hours (qualifier value)&quot; then 0.5\n\t\twhen frequency ~ CustomConcepts.&quot;Every eight to twelve hours (qualifier value)&quot; then 2.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every six to eight hours (qualifier value)&quot; then 3.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every three to four hours (qualifier value)&quot; then 6.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every three to six hours (qualifier value)&quot; then 4.0\n\t\twhen frequency ~ CustomConcepts.&quot;Every two to four hours (qualifier value)&quot; then 6.0\n\t\twhen frequency ~ CustomConcepts.&quot;One to four times a day (qualifier value)&quot; then 4.0\n\t\twhen frequency ~ CustomConcepts.&quot;One to three times a day (qualifier value)&quot; then 3.0\n\t\twhen frequency ~ CustomConcepts.&quot;One to two times a day (qualifier value)&quot; then 2.0\n\t\telse null \n\tend\n\n  //define function &quot;GetMedicationDailyDose&quot;(dosage Quantity, dosesPerDay Decimal):\n  //dosage * Quantity { value: dosesPerDay, unit: '/d' }\n\n\ndefine fluent function dailyDose(Request &quot;MedicationRequest&quot;):\n  Request R\n    let\n      dosage: singleton from R.dosageInstruction,\n      doseAndRate: singleton from dosage.doseAndRate,\n      timing: dosage.timing,\n      frequency: Coalesce(timing.repeat.frequencyMax, timing.repeat.frequency),\n      period: System.Quantity { value: timing.repeat.period, unit: timing.repeat.periodUnit.value },\n      doseRange: doseAndRate.dose as Range,\n      doseQuantity: doseAndRate.dose as SimpleQuantity,\n      dose: Coalesce(doseRange.high, doseQuantity),\n      dosesPerDay: Coalesce(ToDaily(frequency, period), Count(timing.repeat.timeOfDay), 1.0),\n      quantity: R.dispenseRequest.quantity\n    return\n      quantity / (dose * dosesPerDay)\n\ndefine fluent function dailyDose(Dispense &quot;MedicationDispense&quot;):\n  Dispense D\n    let\n      dosage: singleton from D.dosageInstruction,\n      doseAndRate: singleton from dosage.doseAndRate,\n      timing: dosage.timing,\n      frequency: Coalesce(timing.repeat.frequencyMax, timing.repeat.frequency),\n      period: System.Quantity { value: timing.repeat.period, unit: timing.repeat.periodUnit.value },\n      doseRange: doseAndRate.dose as Range,\n      doseQuantity: doseAndRate.dose as SimpleQuantity,\n      dose: Coalesce(doseRange.high, doseQuantity),\n      dosesPerDay: Coalesce(ToDaily(frequency, period), Count(timing.repeat.timeOfDay), 1.0)\n    return\n      D.quantity / (dose * dosesPerDay)\n\n\n\n\n\n\n\n  \n  \n\n\n//need to define\n  define STI_testing:\n    [Procedure] P\n  where P.status = 'completed'\n  and P.code ~ Concepts.&quot;STI testing and treatment services&quot; \n\n\n/**\n * @description Takes a choice between a Medication and a CodeableConcept and returns just the code of the medication\n */\ndefine function ExtractMedicationCode(choice Choice&lt;FHIR.CodeableConcept, FHIR.Reference&gt;):\n  case\n\t  when choice is FHIR.CodeableConcept then\n    \tchoice as FHIR.CodeableConcept\n    when choice is FHIR.Reference then\n      First([Medication] M \n        where M.id = Last(Split(choice.reference, '/'))\n        return M.code as FHIR.CodeableConcept)\n    else\n      Message(null as FHIR.CodeableConcept, true, '1', 'Error', 'Cannot compute a medication code') // TODO: I'm sure that this is supported somehow?\n  end\n\n/**\n * @description Returns the code of an Observation CodeableConcept\n */\ndefine fluent function getObservationCode(observation FHIR.Observation):\n  case \n    when observation.code is FHIR.CodeableConcept then (observation.value as CodeableConcept).coding.code\n    else null\n  end\n  \n/**\n * @description Returns a list of codes of an a list of Observations\n */\ndefine fluent function getObservationCodes(obslist List&lt;FHIR.Observation&gt;):\n  obslist obs return obs.getObservationCode()\n\n\n</code></pre></td></tr>\n            </table>\n          </td>\n        </tr>\n        \n        \n        \n    </table>\n</div>\n</div>"
  },
  "extension" : [
    {
      "url" : "http://hl7.org/fhir/StructureDefinition/cqf-knowledgeCapability",
      "valueCode" : "computable"
    }
  ],
  "url" : "http://smart.who.int/hiv/Library/HIVCommon",
  "version" : "0.4.3",
  "name" : "HIVCommon",
  "title" : "HIVCommon",
  "status" : "draft",
  "experimental" : true,
  "type" : {
    "coding" : [
      {
        "system" : "http://terminology.hl7.org/CodeSystem/library-type",
        "code" : "logic-library"
      }
    ]
  },
  "date" : "2025-02-07T14:15:45+00:00",
  "publisher" : "WHO",
  "contact" : [
    {
      "name" : "WHO",
      "telecom" : [
        {
          "system" : "url",
          "value" : "http://who.int"
        }
      ]
    }
  ],
  "description" : "Description not yet available for HIVCommon.",
  "content" : [
    {
      "contentType" : "text/cql",
      "data" : "bGlicmFyeSBISVZDb21tb24gdmVyc2lvbiAnMC4wLjEnIAoKdXNpbmcgRkhJUiB2ZXJzaW9uICc0LjAuMScKCmluY2x1ZGUgRkhJUkhlbHBlcnMgdmVyc2lvbiAnNC4wLjEnCmluY2x1ZGUgV0hPQ29tbW9uIGNhbGxlZCBXQ29tCgppbmNsdWRlIEhJVkNvbmNlcHRzIGNhbGxlZCBDb25jZXB0cwppbmNsdWRlIEhJVkNvbmNlcHRzQ3VzdG9tIGNhbGxlZCBDdXN0b21Db25jZXB0cwoKY29udGV4dCBQYXRpZW50CgovL1ZFUklGSUVECgoKLy9EUkFGVAoKLy9uZWVkIHRvIGFkZCBUaW1lIHRvIHN0YXJ0IEFSVCAod2l0aGluIDcsIDMwIG9yIDkwIGRheXMgb2YgZGlhZ25vc2lzLCBhcyBwZXIgY291bnRyeSBndWlkZWxpbmVzKQovL25lZWQgdG8gYWRkIERpc2FnZ3JlZ2F0aW9uIGJ5IHRpbWUgc2luY2UgZGlhZ25vc2lzCiAgCgoKLyogCiogREFLIGhhcyBjb2RlcyBmb3IgSEFBUlQgbWlzc3BlY2lmaWVkIAoqIElDRC0xMCBaOTIuMglPdGhlciBwcm9waHlsYWN0aWMgY2hlbW90aGVyYXB5CQkKKiBMT0lOQyAiNTQ4MjUtNQkiCU9uIHNjaGVkdWxlZCBwYWluIG1lZGljYXRpb24gcmVnaW1lbiBpbiBsYXN0IDcgZGF5cwoqCiogU2hvdWxkIGRpc2N1c3MgCiovCgoKCgoKCgovKgoqIEtlbnlhIEVNUiBkZWZpbmVkIGFzIEhJViBwb3NpdGl2ZSBjb25kaXRpb24KKiBXaWxsIG5lZWQgdG8gZGlzY3VzcyBpZiBwcm9kdWNlIGZsYWdzIHRocm91Z2ggY29uZGl0aW9ucyBmb3IgY29uY2VwdHMgdG8gdXNlIGluIGluZGljYXRvciBjYWxjdWxhdGlvbiBzdWNoIGFzIEhJViBwb3NpdGl2ZSBhbmQgT24gQVJUCiogSG93ZXZlciwgd2UgaGF2ZSBtb3ZlZCBmb3J3YXJkIHdpdGggYSBtb3JlIHByZXNjcmlwdGl2ZSBhcHByb2FjaCAKKiBJbmV2aXRhYmx5IG91ciBhcHByb2FjaCByZXF1aXJlcyB0aGF0IGNlcnRhaW4gZGF0YSBlbGVtZW50cyBiZSBhdmFpbGFibGUKKi8KCi8qCiAqIEhJViBUcmVhdG1lbnQgZHVyaW5nIHRoZSBtZWFzdXJlbWVudCBwZXJpb2QKICogdXNlcyBkb3NhZ2UgYW5kIGRpc3BlbnNhdGlvbiBhbW91bnQgdG8gZXN0aW1hdGUgbGFzdCBkYXkgb2YgbWVkaWNhdGlvbgogKiBtZWRpY2F0aW9uIHNob3VsZCBiZSBkaXNwZW5zZWQgYmVmb3JlIGVuZCBvZiBtZWFzdXJlbWVudCBwZXJpb2QKICogbWVkaWNhdGlvbiBzaG91bGQgbGFzdCB1bnRpbCBhZnRlciAyOCBkYXlzIGFmdGVyIHRoZSBlbmQgb2YgdGhlIG1lYXN1cmVtZW50IHBlcmlvZAogKiBUaGlzIHRha2VzIGludG8gYWNjb3VudCBsb3N0IHRvIGZvbGxvdyB1cAogKi8KCi8qCipkZWZpbmUgIkhJViBUcmVhdG1lbnQgZHVyaW5nIHRoZSBtZWFzdXJlbWVudCBwZXJpb2QiOgoqICAgW01lZGljYXRpb25EaXNwZW5zZV0gTUQKKiAgICB3aGVyZSBNRC5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnIH0KKiAgICBhbmQgTUQubWVkaWNhdGlvbiB+ICdBbnRpcmV0cm92aXJhbCcKKiAgICBhbmQgTUQud2hlbkhhbmRlZE92ZXIgYmVmb3JlIGVuZCBvZiAiTWVhc3VyZW1lbnQgUGVyaW9kIgoqICAgIGFuZCAoTUQud2hlbkhhbmRlZE92ZXIgKyBNRC5kb3NhZ2VJbnN0cnVjdGlvblswXS50aW1pbmcucmVwZWF0LmR1cmF0aW9uLnZhbHVlICogTWVkaWNhdGlvbkRpc3BlbnNlLnF1YW50aXR5LnZhbHVlKSBhZnRlciAobWVhc3VyZW1lbnRQZXJpb2QuZW5kIC0gMjggZGF5cykKKi8gCgovKgoqIEltbXVuaXphdGlvbiBkZWZpbmVzIEhBQVJUIGFzCiogIGV4aXN0cyhbTWVkaWNhdGlvbkFkbWluaXN0cmF0aW9uXSBBIHdoZXJlIEV4dHJhY3RNZWRpY2F0aW9uQ29kZShBLm1lZGljYXRpb24pIGluIElNTVpjLiJBUlYgRHJ1Z3MiIGFuZCBBLnN0YXR1cyA9ICdpbi1wcm9ncmVzcycpCiogSSBiZWxpZXZlIHRoaXMgaXMgdGhlIGluY29ycmVjdCByZXNvdXJjZSB1bmxlc3MgdGhleSBtZWFuIHRvIHNheSB0aGF0IG1lZGljYXRpb24gaXMgZ2l2ZW4gZHVyaW5nIGEgbWVkaWNhbCBlbmNvdW50ZXIKKiB3b3VsZCBsaWtlIHRvIGRpc2N1c3MgCiovIAoKLyoqIAogKiBQYXRpZW50IERlY2Vhc2VkIER1cmluZyBNZWFzdXJlbWVudCBQZXJpb2QKICogSW1tdW5pemF0aW9uIGRlZmluZXMgdGhpcyBhcyB0cnVlIHdoZW4gaXMgYSBib29sZWFuLiBUaGlzIG1heSBoYXZlIHRoZSBlZmZlY3Qgb2YgZGVsZXRpbmcgYSBwZXJzb24gZnJvbSBpbmRpY2F0b3JzIGluIGFsbCBjYWxjdWxhdGlvbnMKICogU2hvdWxkIGludGVuZCB0byB1c2Ugd2hlbiBwYXRpZW50LmRlY2Vhc2VkIEZISVIgYm9vbGVhbiB3YXMgdXBkYXRlZCB0byBUUlVFIGlmIG5vIG90aGVyIGRhdGUgaXMgYXZhaWxhYmxlCiAqIEtlbnlhIEVNUiBleGFtcGxlIGRvZXMgbm90IGFjY291bnQgZm9yIHdoZW4gZGVjZWFzZWQgaXMganVzdCBhIGJvb2xlYW4KICovCgoKLyoKZGVmaW5lICJQUkVQIFByZXNjcmlwdGlvbiBEYXlzIjoKICBTdW0oCiAgICAoCiAgICAgIGNvbGxhcHNlICgKICAgICAgICBbTWVkaWNhdGlvblJlcXVlc3RdIE1SCiAgICAgICAgICB3aGVyZSBNUi5zdGF0dXMgPSAnY29tcGxldGVkJwogICAgICAgICAgYW5kIE1SLmludGVudCA9ICdvcmRlcicKICAgICAgICAgIGFuZCBNUi5tZWRpY2F0aW9uIH4gQ29uY2VwdHMuIlByRVAgZm9yIEhJViBwcmV2ZW50aW9uIgogICAgICAgIHJldHVybiBXQ29tVjIuIlByZXNjcmlwdGlvbiBSZWxldmFudCBQZXJpb2QiKCBNUiApIGludGVyc2VjdCAiTWVhc3VyZW1lbnQgUGVyaW9kIgogICAgICApCiAgICApIFBSRVBVc2VJbnRlcnZhbAogICAgICByZXR1cm4gZGF5cyBiZXR3ZWVuIHN0YXJ0IG9mIFBSRVBVc2VJbnRlcnZhbCBhbmQgZW5kIG9mIFBSRVBVc2VJbnRlcnZhbAogICkKKi8KCgpkZWZpbmUgZnVuY3Rpb24gR2V0RHVyYXRpb25JbkRheXModmFsdWUgRkhJUi5EdXJhdGlvbik6IC8vIHJldHVybnMgRGVjaW1hbDoKICAgIGNhc2UgdmFsdWUuY29kZS52YWx1ZQogICAgICB3aGVuICdhJyB0aGVuIHZhbHVlLnZhbHVlICogMzY1LjAKICAgICAgd2hlbiAnbW8nIHRoZW4gdmFsdWUudmFsdWUudmFsdWUgKiAzMC4wCiAgICAgIHdoZW4gJ3drJyB0aGVuIHZhbHVlLnZhbHVlLnZhbHVlICogNy4wCiAgICAgIHdoZW4gJ2QnIHRoZW4gdmFsdWUudmFsdWUudmFsdWUKICAgICAgd2hlbiAnaCcgdGhlbiB2YWx1ZS52YWx1ZS52YWx1ZSAvIDI0LjAKICAgICAgd2hlbiAnbWluJyB0aGVuIHZhbHVlLnZhbHVlLnZhbHVlIC8gNjAuMCAvIDI0LjAKICAgICAgd2hlbiAncycgdGhlbiB2YWx1ZS52YWx1ZS52YWx1ZSAvIDYwLjAgLyA2MC4wIC8gMjQuMAogICAgICB3aGVuICdtcycgdGhlbiB2YWx1ZS52YWx1ZS52YWx1ZSAvIDYwLjAgLyA2MC4wIC8gMjQuMCAvIDEwMDAuMAogICAgICBlbHNlIE1lc3NhZ2UoMTAwMCwgdHJ1ZSwgJ1VuZGVmaW5lZCcsICdFcnJvcicsICdVbnN1cHBvcnRlZCBkdXJhdGlvbiB1bml0ICcgKyB2YWx1ZS5jb2RlLnZhbHVlKQogICAgZW5kCgpkZWZpbmUgZnVuY3Rpb24gIlByZXNjcmlwdGlvbiBSZWxldmFudCBQZXJpb2QiKHByZXNjcmlwdGlvbiBGSElSLk1lZGljYXRpb25SZXF1ZXN0KToKICBpZiAoCiAgICBwcmVzY3JpcHRpb24uYXV0aG9yZWRPbiBpcyBub3QgbnVsbCBhbmQgcHJlc2NyaXB0aW9uLmRpc3BlbnNlUmVxdWVzdCBpcyBub3QgbnVsbAogICAgICBhbmQgcHJlc2NyaXB0aW9uLmRpc3BlbnNlUmVxdWVzdC5leHBlY3RlZFN1cHBseUR1cmF0aW9uIGlzIG5vdCBudWxsCiAgKQogIHRoZW4gSW50ZXJ2YWxbCiAgICBkYXRlIGZyb20gcHJlc2NyaXB0aW9uLmF1dGhvcmVkT24sCiAgICBkYXRlIGZyb20gcHJlc2NyaXB0aW9uLmF1dGhvcmVkT24gKyBTeXN0ZW0uUXVhbnRpdHl7IHZhbHVlOiBHZXREdXJhdGlvbkluRGF5cyhwcmVzY3JpcHRpb24uZGlzcGVuc2VSZXF1ZXN0LmV4cGVjdGVkU3VwcGx5RHVyYXRpb24pLCB1bml0OiAnZGF5cycgfQogIF0KICBlbHNlIG51bGwKCi8vU3lzdGVtLkludGVnZXIKZGVmaW5lIGZ1bmN0aW9uIFRvRGFpbHkoZnJlcXVlbmN5IFN5c3RlbS5JbnRlZ2VyLCBwZXJpb2QgU3lzdGVtLlF1YW50aXR5KToKICBjYXNlIHBlcmlvZC51bml0CiAgICB3aGVuICdoJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKQogICAgd2hlbiAnbWluJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAqIDYwCiAgICB3aGVuICdzJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAqIDYwICogNjAKICAgIHdoZW4gJ2QnIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpIC8gMjQKICAgIHdoZW4gJ3drJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAvICgyNCAqIDcpCiAgICB3aGVuICdtbycgdGhlbiBmcmVxdWVuY3kgKiAoMjQuMCAvIHBlcmlvZC52YWx1ZSkgLyAoMjQgKiAzMCkgLyogYXNzdW1pbmcgMzAgZGF5cyBpbiBtb250aCAqLwogICAgd2hlbiAnYScgdGhlbiBmcmVxdWVuY3kgKiAoMjQuMCAvIHBlcmlvZC52YWx1ZSkgLyAoMjQgKiAzNjUpIC8qIGFzc3VtaW5nIDM2NSBkYXlzIGluIHllYXIgKi8KICAgIHdoZW4gJ2hvdXInIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpCiAgICB3aGVuICdtaW51dGUnIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpICogNjAKICAgIHdoZW4gJ3NlY29uZCcgdGhlbiBmcmVxdWVuY3kgKiAoMjQuMCAvIHBlcmlvZC52YWx1ZSkgKiA2MCAqIDYwCiAgICB3aGVuICdkYXknIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpIC8gMjQKICAgIHdoZW4gJ3dlZWsnIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpIC8gKDI0ICogNykKICAgIHdoZW4gJ21vbnRoJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAvICgyNCAqIDMwKSAvKiBhc3N1bWluZyAzMCBkYXlzIGluIG1vbnRoICovCiAgICB3aGVuICd5ZWFyJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAvICgyNCAqIDM2NSkgLyogYXNzdW1pbmcgMzY1IGRheXMgaW4geWVhciAqLwogICAgd2hlbiAnaG91cnMnIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpCiAgICB3aGVuICdtaW51dGVzJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAqIDYwCiAgICB3aGVuICdzZWNvbmRzJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAqIDYwICogNjAKICAgIHdoZW4gJ2RheXMnIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpIC8gMjQKICAgIHdoZW4gJ3dlZWtzJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAvICgyNCAqIDcpCiAgICB3aGVuICdtb250aHMnIHRoZW4gZnJlcXVlbmN5ICogKDI0LjAgLyBwZXJpb2QudmFsdWUpIC8gKDI0ICogMzApIC8qIGFzc3VtaW5nIDMwIGRheXMgaW4gbW9udGggKi8KICAgIHdoZW4gJ3llYXJzJyB0aGVuIGZyZXF1ZW5jeSAqICgyNC4wIC8gcGVyaW9kLnZhbHVlKSAvICgyNCAqIDM2NSkgLyogYXNzdW1pbmcgMzY1IGRheXMgaW4geWVhciAqLwogICAgZWxzZSBudWxsCiAgZW5kCgogIGRlZmluZSBmdW5jdGlvbiAiSGFzRW5kIihwZXJpb2QgSW50ZXJ2YWw8RGF0ZVRpbWU+ICk6CiAgbm90IChlbmQgb2YgcGVyaW9kIGlzIG51bGwKICAgIG9yIGVuZCBvZiBwZXJpb2QgPSBtYXhpbXVtIERhdGVUaW1lCikKCiAgZGVmaW5lIGZsdWVudCBmdW5jdGlvbiBNZWRpY2F0aW9uUmVxdWVzdFBlcmlvZChSZXF1ZXN0IE1lZGljYXRpb25SZXF1ZXN0KToKICBSZXF1ZXN0IFIKICAgIGxldAogICAgICBkb3NhZ2U6IHNpbmdsZXRvbiBmcm9tIFIuZG9zYWdlSW5zdHJ1Y3Rpb24sCiAgICAgIGRvc2VBbmRSYXRlOiBzaW5nbGV0b24gZnJvbSBkb3NhZ2UuZG9zZUFuZFJhdGUsCiAgICAgIGRvc2VSYW5nZTogZG9zZUFuZFJhdGUuZG9zZSBhcyBSYW5nZSwKICAgICAgZG9zZVF1YW50aXR5OiBkb3NlQW5kUmF0ZS5kb3NlIGFzIFNpbXBsZVF1YW50aXR5LAogICAgICBkb3NlOiBDb2FsZXNjZShlbmQgb2YgZG9zZVJhbmdlLCBkb3NlUXVhbnRpdHkpLAogICAgICB0aW1pbmc6IGRvc2FnZS50aW1pbmcsCiAgICAgIGZyZXF1ZW5jeTogQ29hbGVzY2UodGltaW5nLnJlcGVhdC5mcmVxdWVuY3lNYXgsIHRpbWluZy5yZXBlYXQuZnJlcXVlbmN5KSwKICAgICAgcGVyaW9kOiBTeXN0ZW0uUXVhbnRpdHkgeyB2YWx1ZTogdGltaW5nLnJlcGVhdC5wZXJpb2QsIHVuaXQ6IHRpbWluZy5yZXBlYXQucGVyaW9kVW5pdC52YWx1ZSB9LAogICAgICBkb3Nlc1BlckRheTogQ29hbGVzY2UoVG9EYWlseShGSElSSGVscGVycy5Ub0ludGVnZXIoZnJlcXVlbmN5KSwgcGVyaW9kKSwgQ291bnQodGltaW5nLnJlcGVhdC50aW1lT2ZEYXkpLCAxLjApLAogICAgICBib3VuZHNQZXJpb2Q6IHRpbWluZy5yZXBlYXQuYm91bmRzIGFzIFBlcmlvZCwKICAgICAgZGF5c1N1cHBseTogUi5kaXNwZW5zZVJlcXVlc3QuZXhwZWN0ZWRTdXBwbHlEdXJhdGlvbiwKICAgICAgcXVhbnRpdHk6IFIuZGlzcGVuc2VSZXF1ZXN0LnF1YW50aXR5LAogICAgICByZWZpbGxzOiBDb2FsZXNjZShSLmRpc3BlbnNlUmVxdWVzdC5udW1iZXJPZlJlcGVhdHNBbGxvd2VkLCAwKSwKICAgICAgc3RhcnREYXRlOgogICAgICAgIENvYWxlc2NlKAogICAgICAgICAgc3RhcnQgb2YgYm91bmRzUGVyaW9kLAogICAgICAgICAgc3RhcnQgb2YgUi5kaXNwZW5zZVJlcXVlc3QudmFsaWRpdHlQZXJpb2QsCiAgICAgICAgICBSLmF1dGhvcmVkT24KICAgICAgICApCiAgICByZXR1cm4KICAgICAgaWYgSGFzRW5kKGJvdW5kc1BlcmlvZCkgdGhlbgogICAgICAgIEludGVydmFsW3N0YXJ0RGF0ZSwgZW5kIG9mIGJvdW5kc1BlcmlvZF0KICAgICAgZWxzZQogICAgICAgICgKICAgICAgICAgIENvYWxlc2NlKGRheXNTdXBwbHksIHF1YW50aXR5IC8gKGRvc2UgKiBkb3Nlc1BlckRheSkpCiAgICAgICAgICAgICogKDEgKyByZWZpbGxzKQogICAgICAgICkgZHVyYXRpb25JbkRheXMKICAgICAgICAgIHJldHVybiBJbnRlcnZhbFtzdGFydERhdGUsIHN0YXJ0RGF0ZSArIGR1cmF0aW9uSW5EYXlzXQoKCmRlZmluZSBmdW5jdGlvbiAiRG9zZXNQZXJEYXkiKGZyZXF1ZW5jeSBDb2RlKToKCS8qQ2FsY3VsYXRlcyB0aGUgY3VtdWxhdGl2ZSBkb3NlIHBlciBkYXkgZm9yIGVhY2ggcHJlc2NyaXB0aW9uKi8KCWNhc2UKCQl3aGVuIGZyZXF1ZW5jeSB+IEN1c3RvbUNvbmNlcHRzLiJPbmNlIGRhaWx5IChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDEuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIlR3aWNlIGEgZGF5IChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDIuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIlRocmVlIHRpbWVzIGRhaWx5IChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDMuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkZvdXIgdGltZXMgZGFpbHkgKHF1YWxpZmllciB2YWx1ZSkiIHRoZW4gNC4wCgkJd2hlbiBmcmVxdWVuY3kgfiBDdXN0b21Db25jZXB0cy4iRXZlcnkgdHdlbnR5IGZvdXIgaG91cnMgKHF1YWxpZmllciB2YWx1ZSkiIHRoZW4gMS4wCgkJd2hlbiBmcmVxdWVuY3kgfiBDdXN0b21Db25jZXB0cy4iRXZlcnkgdHdlbHZlIGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDIuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkV2ZXJ5IHRoaXJ0eSBzaXggaG91cnMgKHF1YWxpZmllciB2YWx1ZSkiIHRoZW4gMC42NwoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkV2ZXJ5IGVpZ2h0IGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDMuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkV2ZXJ5IGZvdXIgaG91cnMgKHF1YWxpZmllciB2YWx1ZSkiIHRoZW4gNi4wCgkJd2hlbiBmcmVxdWVuY3kgfiBDdXN0b21Db25jZXB0cy4iRXZlcnkgc2l4IGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDQuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkV2ZXJ5IHNldmVudHkgdHdvIGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDAuMzQKCQl3aGVuIGZyZXF1ZW5jeSB+IEN1c3RvbUNvbmNlcHRzLiJFdmVyeSBmb3J0eSBlaWdodCBob3VycyAocXVhbGlmaWVyIHZhbHVlKSIgdGhlbiAwLjUKCQl3aGVuIGZyZXF1ZW5jeSB+IEN1c3RvbUNvbmNlcHRzLiJFdmVyeSBlaWdodCB0byB0d2VsdmUgaG91cnMgKHF1YWxpZmllciB2YWx1ZSkiIHRoZW4gMi4wCgkJd2hlbiBmcmVxdWVuY3kgfiBDdXN0b21Db25jZXB0cy4iRXZlcnkgc2l4IHRvIGVpZ2h0IGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDMuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkV2ZXJ5IHRocmVlIHRvIGZvdXIgaG91cnMgKHF1YWxpZmllciB2YWx1ZSkiIHRoZW4gNi4wCgkJd2hlbiBmcmVxdWVuY3kgfiBDdXN0b21Db25jZXB0cy4iRXZlcnkgdGhyZWUgdG8gc2l4IGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDQuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIkV2ZXJ5IHR3byB0byBmb3VyIGhvdXJzIChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDYuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIk9uZSB0byBmb3VyIHRpbWVzIGEgZGF5IChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDQuMAoJCXdoZW4gZnJlcXVlbmN5IH4gQ3VzdG9tQ29uY2VwdHMuIk9uZSB0byB0aHJlZSB0aW1lcyBhIGRheSAocXVhbGlmaWVyIHZhbHVlKSIgdGhlbiAzLjAKCQl3aGVuIGZyZXF1ZW5jeSB+IEN1c3RvbUNvbmNlcHRzLiJPbmUgdG8gdHdvIHRpbWVzIGEgZGF5IChxdWFsaWZpZXIgdmFsdWUpIiB0aGVuIDIuMAoJCWVsc2UgbnVsbCAKCWVuZAoKICAvL2RlZmluZSBmdW5jdGlvbiAiR2V0TWVkaWNhdGlvbkRhaWx5RG9zZSIoZG9zYWdlIFF1YW50aXR5LCBkb3Nlc1BlckRheSBEZWNpbWFsKToKICAvL2Rvc2FnZSAqIFF1YW50aXR5IHsgdmFsdWU6IGRvc2VzUGVyRGF5LCB1bml0OiAnL2QnIH0KCgpkZWZpbmUgZmx1ZW50IGZ1bmN0aW9uIGRhaWx5RG9zZShSZXF1ZXN0ICJNZWRpY2F0aW9uUmVxdWVzdCIpOgogIFJlcXVlc3QgUgogICAgbGV0CiAgICAgIGRvc2FnZTogc2luZ2xldG9uIGZyb20gUi5kb3NhZ2VJbnN0cnVjdGlvbiwKICAgICAgZG9zZUFuZFJhdGU6IHNpbmdsZXRvbiBmcm9tIGRvc2FnZS5kb3NlQW5kUmF0ZSwKICAgICAgdGltaW5nOiBkb3NhZ2UudGltaW5nLAogICAgICBmcmVxdWVuY3k6IENvYWxlc2NlKHRpbWluZy5yZXBlYXQuZnJlcXVlbmN5TWF4LCB0aW1pbmcucmVwZWF0LmZyZXF1ZW5jeSksCiAgICAgIHBlcmlvZDogU3lzdGVtLlF1YW50aXR5IHsgdmFsdWU6IHRpbWluZy5yZXBlYXQucGVyaW9kLCB1bml0OiB0aW1pbmcucmVwZWF0LnBlcmlvZFVuaXQudmFsdWUgfSwKICAgICAgZG9zZVJhbmdlOiBkb3NlQW5kUmF0ZS5kb3NlIGFzIFJhbmdlLAogICAgICBkb3NlUXVhbnRpdHk6IGRvc2VBbmRSYXRlLmRvc2UgYXMgU2ltcGxlUXVhbnRpdHksCiAgICAgIGRvc2U6IENvYWxlc2NlKGRvc2VSYW5nZS5oaWdoLCBkb3NlUXVhbnRpdHkpLAogICAgICBkb3Nlc1BlckRheTogQ29hbGVzY2UoVG9EYWlseShmcmVxdWVuY3ksIHBlcmlvZCksIENvdW50KHRpbWluZy5yZXBlYXQudGltZU9mRGF5KSwgMS4wKSwKICAgICAgcXVhbnRpdHk6IFIuZGlzcGVuc2VSZXF1ZXN0LnF1YW50aXR5CiAgICByZXR1cm4KICAgICAgcXVhbnRpdHkgLyAoZG9zZSAqIGRvc2VzUGVyRGF5KQoKZGVmaW5lIGZsdWVudCBmdW5jdGlvbiBkYWlseURvc2UoRGlzcGVuc2UgIk1lZGljYXRpb25EaXNwZW5zZSIpOgogIERpc3BlbnNlIEQKICAgIGxldAogICAgICBkb3NhZ2U6IHNpbmdsZXRvbiBmcm9tIEQuZG9zYWdlSW5zdHJ1Y3Rpb24sCiAgICAgIGRvc2VBbmRSYXRlOiBzaW5nbGV0b24gZnJvbSBkb3NhZ2UuZG9zZUFuZFJhdGUsCiAgICAgIHRpbWluZzogZG9zYWdlLnRpbWluZywKICAgICAgZnJlcXVlbmN5OiBDb2FsZXNjZSh0aW1pbmcucmVwZWF0LmZyZXF1ZW5jeU1heCwgdGltaW5nLnJlcGVhdC5mcmVxdWVuY3kpLAogICAgICBwZXJpb2Q6IFN5c3RlbS5RdWFudGl0eSB7IHZhbHVlOiB0aW1pbmcucmVwZWF0LnBlcmlvZCwgdW5pdDogdGltaW5nLnJlcGVhdC5wZXJpb2RVbml0LnZhbHVlIH0sCiAgICAgIGRvc2VSYW5nZTogZG9zZUFuZFJhdGUuZG9zZSBhcyBSYW5nZSwKICAgICAgZG9zZVF1YW50aXR5OiBkb3NlQW5kUmF0ZS5kb3NlIGFzIFNpbXBsZVF1YW50aXR5LAogICAgICBkb3NlOiBDb2FsZXNjZShkb3NlUmFuZ2UuaGlnaCwgZG9zZVF1YW50aXR5KSwKICAgICAgZG9zZXNQZXJEYXk6IENvYWxlc2NlKFRvRGFpbHkoZnJlcXVlbmN5LCBwZXJpb2QpLCBDb3VudCh0aW1pbmcucmVwZWF0LnRpbWVPZkRheSksIDEuMCkKICAgIHJldHVybgogICAgICBELnF1YW50aXR5IC8gKGRvc2UgKiBkb3Nlc1BlckRheSkKCgoKCgoKCiAgCiAgCgoKLy9uZWVkIHRvIGRlZmluZQogIGRlZmluZSBTVElfdGVzdGluZzoKICAgIFtQcm9jZWR1cmVdIFAKICB3aGVyZSBQLnN0YXR1cyA9ICdjb21wbGV0ZWQnCiAgYW5kIFAuY29kZSB+IENvbmNlcHRzLiJTVEkgdGVzdGluZyBhbmQgdHJlYXRtZW50IHNlcnZpY2VzIiAKCgovKioKICogQGRlc2NyaXB0aW9uIFRha2VzIGEgY2hvaWNlIGJldHdlZW4gYSBNZWRpY2F0aW9uIGFuZCBhIENvZGVhYmxlQ29uY2VwdCBhbmQgcmV0dXJucyBqdXN0IHRoZSBjb2RlIG9mIHRoZSBtZWRpY2F0aW9uCiAqLwpkZWZpbmUgZnVuY3Rpb24gRXh0cmFjdE1lZGljYXRpb25Db2RlKGNob2ljZSBDaG9pY2U8RkhJUi5Db2RlYWJsZUNvbmNlcHQsIEZISVIuUmVmZXJlbmNlPik6CiAgY2FzZQoJICB3aGVuIGNob2ljZSBpcyBGSElSLkNvZGVhYmxlQ29uY2VwdCB0aGVuCiAgICAJY2hvaWNlIGFzIEZISVIuQ29kZWFibGVDb25jZXB0CiAgICB3aGVuIGNob2ljZSBpcyBGSElSLlJlZmVyZW5jZSB0aGVuCiAgICAgIEZpcnN0KFtNZWRpY2F0aW9uXSBNIAogICAgICAgIHdoZXJlIE0uaWQgPSBMYXN0KFNwbGl0KGNob2ljZS5yZWZlcmVuY2UsICcvJykpCiAgICAgICAgcmV0dXJuIE0uY29kZSBhcyBGSElSLkNvZGVhYmxlQ29uY2VwdCkKICAgIGVsc2UKICAgICAgTWVzc2FnZShudWxsIGFzIEZISVIuQ29kZWFibGVDb25jZXB0LCB0cnVlLCAnMScsICdFcnJvcicsICdDYW5ub3QgY29tcHV0ZSBhIG1lZGljYXRpb24gY29kZScpIC8vIFRPRE86IEknbSBzdXJlIHRoYXQgdGhpcyBpcyBzdXBwb3J0ZWQgc29tZWhvdz8KICBlbmQKCi8qKgogKiBAZGVzY3JpcHRpb24gUmV0dXJucyB0aGUgY29kZSBvZiBhbiBPYnNlcnZhdGlvbiBDb2RlYWJsZUNvbmNlcHQKICovCmRlZmluZSBmbHVlbnQgZnVuY3Rpb24gZ2V0T2JzZXJ2YXRpb25Db2RlKG9ic2VydmF0aW9uIEZISVIuT2JzZXJ2YXRpb24pOgogIGNhc2UgCiAgICB3aGVuIG9ic2VydmF0aW9uLmNvZGUgaXMgRkhJUi5Db2RlYWJsZUNvbmNlcHQgdGhlbiAob2JzZXJ2YXRpb24udmFsdWUgYXMgQ29kZWFibGVDb25jZXB0KS5jb2RpbmcuY29kZQogICAgZWxzZSBudWxsCiAgZW5kCiAgCi8qKgogKiBAZGVzY3JpcHRpb24gUmV0dXJucyBhIGxpc3Qgb2YgY29kZXMgb2YgYW4gYSBsaXN0IG9mIE9ic2VydmF0aW9ucwogKi8KZGVmaW5lIGZsdWVudCBmdW5jdGlvbiBnZXRPYnNlcnZhdGlvbkNvZGVzKG9ic2xpc3QgTGlzdDxGSElSLk9ic2VydmF0aW9uPik6CiAgb2JzbGlzdCBvYnMgcmV0dXJuIG9icy5nZXRPYnNlcnZhdGlvbkNvZGUoKQoKCg=="
    }
  ]
}