WHO Clinical Care in Crisis Implementation Guide for Children
0.1.0 - ci-build

WHO Clinical Care in Crisis Implementation Guide for Children - Local Development build (v0.1.0). See the Directory of published versions

: CHEBase - JSON Representation

Active as of 2023-10-04

Raw json | Download


{
  "resourceType" : "Library",
  "id" : "chebase",
  "text" : {
    "status" : "generated",
    "div" : "<div xmlns=\"http://www.w3.org/1999/xhtml\"><h2>Related Artifacts</h2><table class=\"grid\"><tr><td>depends-on</td><td><code>http://fhir.org/guides/who/anc-cds/Library/FHIRHelpers</code></td></tr></table><h2>Parameters</h2><table class=\"grid\"><tr><td>encounterid</td><td>in</td><td/><td/><td>string</td></tr></table><h2>Data Requirements</h2><table class=\"grid\"><tr><td colspan=\"2\"><b>Type</b>: <a href=\"http://hl7.org/fhir/R4/patient.html\">Patient</a> (<a href=\"http://hl7.org/fhir/R4/patient.html\">Patient</a>)</td></tr></table><table class=\"grid\"><tr><td colspan=\"2\"><b>Type</b>: <a href=\"http://hl7.org/fhir/R4/encounter.html\">Encounter</a> (<a href=\"http://hl7.org/fhir/R4/encounter.html\">Encounter</a>)</td></tr></table><h2>Contents</h2><p><code>text/cql</code></p><pre><code class=\"language-sql\">/*nter&quot;\n@author: Patrick Delcroix\n@description: This library is part of the project CHE Project, its allows standardisation for the observation processing\n*/\n\nlibrary chebase version '1.0.313+build.456'\n\nusing FHIR version '4.0.1'\n\ninclude FHIRHelpers version '4.0.1'\n\nparameter &quot;encounterid&quot; String\n//parameter &quot;Encounter&quot; Encounter$\ncodesystem &quot;RoleCodeSystem&quot; : 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/emcare-custom-codes'\ncode &quot;Mother&quot;: 'MTH' from &quot;RoleCodeSystem&quot;\n\ncontext Patient\n\n//define encounterid:\n//  &quot;Encounter&quot;.id\n\n\n\n\ndefine &quot;Yes&quot;:\n  true\n\ndefine &quot;No&quot;:\n  false \n\n\ndefine function IsInEncounter(ref FHIR.Reference):\n    case\n    when encounterid = ref.id then true\n    when encounterid = Last(Split(ref.reference, '/')) then true\n   // when ref.identifier is not null and id = ref.identifier.id then true\n    else false\nend\n\ndefine getEncounters:\n    [Encounter] E \n      where E.id = &quot;encounterid&quot;\n        return E\n\ndefine getEncounter:\n    singleton from getEncounters\n\ndefine function CHEExtensions(element Patient, id String):\n  element.extension E\n      where E.url = ('https://fhir.dk.swisstph-mis.ch/matchbox/fhir/StructureDefinition/' + id)\n      return E\n\ndefine function CHEExtension(element Patient, id String):\n  singleton from CHEExtensions(element, id)\n\ndefine function CHEExtensions(element Encounter, id String):\n  element.extension E\n      where E.url = ('https://fhir.dk.swisstph-mis.ch/matchbox/fhir/StructureDefinition/' + id)\n      return E\n\n\ndefine function postcordinationExtension(element Condition, postcordination List&lt;String&gt;):\n  element.extension E\n      where E.url = ('https://fhir.dk.swisstph-mis.ch/matchbox/fhir/StructureDefinition/postcordination')\n      and E.value in postcordination\n\n\ndefine function CHEExtension(element Encounter, id String):\n  singleton from CHEExtensions(element, id)\n\ndefine getPrimaryCareGiverReference:\n  CHEExtension(Patient, 'primarycaregiver').value\n\ndefine getPrimaryCareGiver:\n  [RelatedPerson] RP where RP.id = Last(Split(getPrimaryCareGiverReference.reference, '/'))\n    return RP\n\ndefine isMotherPrimaryCareGiver:\n  getPrimaryCareGiver is not null and Exists(getPrimaryCareGiver.relationship r where r ~ &quot;Mother&quot;)\n\ndefine &quot;Biological Mother Vital Status&quot;:\n  CHEExtension(Patient, 'motherVitalStatus').value\n  \ndefine &quot;Biological Father Vital Status&quot;:\n  CHEExtension(Patient, 'fatherVitalStatus').value\n// person accompanying the child is a participant with a null type\ndefine getRelatedPersonReferenceAccompanyingTheChild:\n  Coalesce(First(getEncounter.participant P where not exists(P.type) ).individual, getPrimaryCareGiverReference)\n\ndefine getRelatedPersonsAccompanyingTheChild:\n  [RelatedPerson] RP where RP.id = Last(Split(getRelatedPersonReferenceAccompanyingTheChild.reference, '/'))\n    return RP\n\n\ndefine getRelatedPersonAccompanyingTheChild:\n  singleton from getRelatedPersonsAccompanyingTheChild\n\n\ndefine &quot;Person accompanying child today's Relationship to Client&quot;:\n//WORKARROUND   getRelatedPersonAccompanyingTheChild.relationship\n  CHEExtension(getEncounter, 'motherpresent').value\n\n\n\n\n\ndefine function getValue(O Observation):\n  case  \n      when  O is null then null\n      when O.value is CodeableConcept then Coalesce(First(O.value.coding C where C.system  = 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes'), First(O.value.coding))\n      else O.value\n  end\n\n\ndefine function assesObservation(O Observation):\n  case  \n      when  O is null then null\n      when  O.status in  {'cancelled'} then false\n      when O.value is null then  true\n      else O.value\n  end\n/*      \ndefine function GetObservationDuringEncounter(idlist List&lt;System.Code&gt;):\n  if GetObservationDuringEncounterDone(idlist ) is null then \n      GetObservationDuringEncounterDone(idlist )\n  else\n    GetObservationDuringEncounterNotFound(idlist )\n*/\n\ndefine function GetObservationDuringEncounter(id System.Code):\n      First([Observation: id ] O\n        where   IsInEncounter(O.encounter) \n        and O.status in { 'final', 'amended', 'corrected','cancelled'} \n        sort by issued.value desc) \n\n  /*\n  this is commented for performance improvement, even if it hides a valid observation if there is an more recent unvalid one\n  Coalesce(GetObservationDuringEncounterDone(id ), GetObservationDuringEncounterNotFound(id ))\n  */\n/*\ndefine function GetObservationDuringEncounterDone(idlist List&lt;System.Code&gt;):\n      Last([Observation: idlist ] O\n        where   IsInEncounter(O.encounter) \n        and O.status in { 'final', 'amended', 'corrected'})\n*/\ndefine function GetObservationDuringEncounterDone(id System.Code):\n      First([Observation: id ] O\n        where   IsInEncounter(O.encounter) \n        and O.status in { 'final', 'amended', 'corrected'} \n        sort by issued.value desc) \n\n\ndefine function HasObservationCodeDuringEncounterDone(id System.Code, valueCode System.Code):\n    \n    Exists([Observation: id ] O\n        where   IsInEncounter(O.encounter) \n        and O.status in { 'final', 'amended', 'corrected'}\n        and O.value is FHIR.CodeableConcept\n        and O.value ~ valueCode)\n\n//Exists([Observation] O where O.status in { 'final', 'amended', 'corrected'} and O.value is FHIR.CodeableConcept   and Exists( O.value.coding C where C is FHIR.Coding and C.code = FHIR.code {value: 'CHE.B20S2.DE04'}) )&quot;\n\n/*\ndefine function GetObservationDuringEncounterNotFound(idlist List&lt;System.Code&gt;):\n      Last([Observation: idlist] O\n       where  IsInEncounter(O.encounter) \n          and O.status in {'cancelled'})\n          */\ndefine function GetObservationDuringEncounterNotFound(id System.Code):\n      First([Observation: id] O\n       where  IsInEncounter(O.encounter) \n          and O.status in {'cancelled'}\n          sort by issued.value desc)\n/*\n\ndefine function GetNumberObservationDuringEncounter(idlist List&lt;System.Code&gt;):\n  Count(\n    [Observation: idlist] O\n        where  IsInEncounter( O.encounter) \n        and O.status in { 'final', 'amended', 'corrected'})\n*/\ndefine function GetNumberObservationDuringEncounter(id System.Code):\n  Count(\n    [Observation: id] O\n        where  IsInEncounter( O.encounter) \n        and O.status in { 'final', 'amended', 'corrected'})\n\n// ************************   GetObsValue ************************/\n/*\ndefine function GetObsValue(idlist List&lt;System.Code&gt;):\n    getValue(GetObservationDuringEncounter(idlist))\n\ndefine function GetObsValue(id System.Code):\n    getValue(GetObservationDuringEncounter({id}))\n*/\n\ndefine function GetObsValue(id System.Code):\n    getValue(GetObservationDuringEncounter(id))\n\ndefine function GetObsValue(id System.String, codesystem System.String):\n    getValue(GetObservationDuringEncounter(coding(id, codesystem)))\n\ndefine function GetObsValue(id System.String):\n    getValue(GetObservationDuringEncounter(coding(id, 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes')))\n\ndefine function HasObsValueCode(id System.String, value System.Code):\n   HasObservationCodeDuringEncounterDone(coding(id, 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes') , value )\n  \ndefine function HasObsValueCode(id System.String, value System.String):\n   HasObservationCodeDuringEncounterDone(coding(id, 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes') , coding(value, 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes') )\n\ndefine function HasObsValueCode(id System.Code, value System.String):\n   HasObservationCodeDuringEncounterDone(id , coding(value, 'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes') )\n\n// ************************   HasObs ************************/\n/*\ndefine function HasObs(idlist List&lt;System.Code&gt;):\n    assesObservation(GetObservationDuringEncounter(idlist))\n\ndefine function HasObs(id System.Code):\n    assesObservation(GetObservationDuringEncounter({id}))\n*/\ndefine function HasObs(id System.Code):\n    assesObservation(GetObservationDuringEncounter(id))\n\ndefine function HasObs(id System.String, codesystem System.String):\n    assesObservation(GetObservationDuringEncounter(coding(id, codesystem)))\n\ndefine function HasObs(id System.String):\n    assesObservation(GetObservationDuringEncounter(coding(id)))\n\ndefine function HasObs(id FHIR.code, codesystem System.String):\n    assesObservation(GetObservationDuringEncounter(coding(id, codesystem)))\n/*\ndefine function GetHistoricObservation(idlist List&lt;System.Code&gt;, nbdays Integer):\n  if GetHistoricObservationNotfound(idlist , codesystem , nbdays ) is null then \n      GetHistoricObservationNotfound(idlist , codesystem , nbdays )\n  else\n    GetHistoricObservationNotfound(idlist , codesystem , nbdays )\n*/\n\ndefine function GetHistoricObservation(id System.Code, nbdays Integer):\n      First([Observation: id ] O\n        where O.status in { 'final', 'amended', 'corrected','cancelled'} \n        and (difference in days between O.issued and Today()) &lt; nbdays \n        sort by issued.value desc )\n\n  //Coalesce(GetHistoricObservationDone(id ,  nbdays ),  GetHistoricObservationNotfound(id  , nbdays ))\n/*\ndefine function GetHistoricObservationDone(idlist List&lt;System.Code&gt;, nbdays Integer):\n      Last([Observation: idlist ] O\n        where  O.status in { 'final', 'amended', 'corrected'}\n        and (difference in days between O.issued and Today()) &lt; nbdays)\n*/\ndefine function GetHistoricObservationDone(id System.Code, nbdays Integer):\n      First([Observation: id ] O\n        where  O.status in { 'final', 'amended', 'corrected'}\n        and (difference in days between O.issued and Today()) &lt; nbdays \n        sort by issued.value desc )\n\n/*\ndefine function GetHistoricObservationNotfound(idlist List&lt;System.Code&gt;, nbdays Integer):\n      Last([Observation: idlist] O\n        where  O.status in {'cancelled'}\n*/\ndefine function GetHistoricObservationNotfound(id System.Code, nbdays Integer):\n      First([Observation: id] O\n        where  O.status in {'cancelled'}\n          and (difference in days between O.issued and Today()) &lt; nbdays \n        sort by issued.value desc)\n// ************************   HasObsHistory ************************/\n\n/*\ndefine function HasObsHistory(idlist List&lt;System.Code&gt;,  nbdays Integer):\n  assesObservation(GetHistoricObservation(idlist, nbdays))\n\n\n define function HasObsHistory(id System.Code, cnbdays Integer):\n  assesObservation(GetHistoricObservation({id}, nbdays))\n*/\ndefine function HasObsHistory(id System.Code, nbdays Integer):\n  assesObservation(GetHistoricObservation(id, nbdays))\n\ndefine function HasObsHistory(id System.String, codesystem System.String, nbdays Integer):\n  assesObservation(GetHistoricObservation(coding(id, codesystem), nbdays))\n\n\ndefine function HasObsHistory(id System.String, nbdays Integer):\n  assesObservation(GetHistoricObservation(coding(id), nbdays))\n\ndefine function c(s System.String):\n  FHIR.code { value: s }\n\n\ndefine function coding(s System.String, url System.String):\n  System.Code {\n                code:  s ,\n                system:  url \n            }\n\ndefine function coding(s FHIR.code, url System.String):\n  System.Code {\n                code:  s.value ,\n                system:  url \n            }\n\ndefine function coding(s System.String):\n  System.Code {\n                code:  s ,\n                system:  'https://fhir.dk.swisstph-mis.ch/matchbox/fhir/CodeSystem/che-custom-codes'\n            }\n\n\ndefine function ToUrl(s System.String):\n  url {value:s}\n\ndefine function ToIntC(b System.Boolean):\n  case\n  when b is null then 0\n  when b = true then 1\n  else 0\n  end\n\n\n// ************************   GetCond ************************/\n\ndefine function GetConditions(id System.Code):\n      [Condition: id] O\n        where  IsInEncounter( O.encounter) \n        and exists(O.verificationStatus.coding C where C.code in {'unconfirmed', 'provisional', 'differential', 'confirmed'} \n        and C.system = 'http://terminology.hl7.org/CodeSystem/condition-ver-status')\n        sort by recordedDate desc\n\n\n\n\ndefine function GetStemCode(id System.String):\n  coding(Split( id, '&amp;')[0])\n\ndefine function GetPostcoordinationCode(id System.String):\n  Tail(Split(id, '&amp;'))\n\ndefine function GetCondition(id System.Code):\n      First(GetConditions(id))\n\n\n   \ndefine function GetCondition(id System.Code, postcordination List&lt;System.String&gt;):\n    First(\n      [Condition: id] C\n        where  IsInEncounter( C.encounter) \n        and exists(C.verificationStatus.coding cc where cc.code in {'unconfirmed', 'provisional', 'differential', 'confirmed'} \n        and cc.system = 'http://terminology.hl7.org/CodeSystem/condition-ver-status')\n        and  postcordination is null or  Count(postcordinationExtension(C,postcordination)) &gt;= Count(postcordination)\n        sort by recordedDate desc\n    )\n\n\ndefine function assesCondition(O Condition):\n  if O is null then \n    false\n  else\n    true\n\ndefine function GetCond(id System.Code):\n  (GetCondition(id))\n\ndefine function GetCond(id System.String, codesystem System.String):\n  (GetCondition(coding(id, codesystem)))\n\ndefine function GetCond(id System.String):\n  (GetCondition(GetStemCode(id),GetPostcoordinationCode(id)))\n\n// ************************   HasCond ************************/\n/*\ndefine function HasCond(idlist List&lt;System.Code&gt;):\n  assesCondition(GetCondition(idlist))\n\n\n3518GetCondition(id))\n*/\ndefine function HasCond(id System.String, codesystem System.String):\n  assesCondition(GetCondition(coding(id, codesystem)))\n\ndefine function HasCond(id System.String):\n  assesCondition(GetCondition(coding(id)))\n\ndefine function HasCond(id System.Code):\n  assesCondition(GetCondition(id))\n\n// ************************   PatientHasHistoryOfCondition ************************/\n/*\ndefine function GetHistoricCondition(idlist List&lt;System.Code&gt;,  nbdays Integer):\n      Last([Condition: idlist] O\n        where  (difference in days between O.recordedDate and Today()) &lt; nbdays\n        and exists(O.verificationStatus.coding C where C.code in {'unconfirmed', 'provisional', 'differential', 'confirmed'} \n        and C.system = 'http://terminology.hl7.org/CodeSystem/condition-ver-status'))\n*/\n\ndefine function GetHistoricCondition(id System.Code,  nbdays Integer):\n      First([Condition: id] O\n        where  (difference in days between O.recordedDate and Today()) &lt; nbdays\n        and exists(O.verificationStatus.coding C where C.code in {'unconfirmed', 'provisional', 'differential', 'confirmed'} \n        and C.system = 'http://terminology.hl7.org/CodeSystem/condition-ver-status') \n        sort by recordedDate desc)\n\n\n\n\n/*\ndefine function HasCondHistory(idlist List&lt;System.Code&gt;,  nbdays Integer):\n  assesCondition(GetHistoricCondition(idlist,  nbdays))\n\n\ndefine function HasCondHistory(id System.Code,  nbdays Integer):\n  assesCondition(GetHistoricCondition({id}, nbdays))\n*/\ndefine function HasCondHistory(id System.Code, nbdays Integer):\n  assesCondition(GetHistoricCondition(id,  nbdays))\n\ndefine function HasCondHistory(id System.String, codesystem System.String, nbdays Integer):\n  assesCondition(GetHistoricCondition(coding(id,codesystem),nbdays))\n\n\ndefine function HasCondHistory(id System.String, nbdays Integer):\n  assesCondition(GetHistoricCondition(coding(id),  nbdays))\n\n\n\n//define function PatientHasConditionDuringEncounter(id String, codesystem url, duration Integer)):\n\n//define function PatientHasConditionFromValueSetDuringEncounter(id String, codesystem url, duration Integer)):\n\n//define function PatientHasHsistoryCondition(id String,codesystem url , duration Integer):\n//define function PatientHasHsistoryConditionFromValueSet(id String,codesystem url , duration Integer):\n\n\n// PatientHasSymptom(&quot;symptom name&quot;): symptom in the encounter\n\n\n// PatientLastMeasureOf(&quot;measure name&quot;): measure in the encounter\n\n// PatientLastHistoricMeasureOf(&quot;measure name&quot;, duration): measure in the patient history during duration\n\n// PatientHasDiagnostic(&quot;Diagnostic name&quot; ): Diagnostic in the encounter\n\n// PatientHasHistoryOfDiagnostic(&quot;Diagnostic name&quot;, duration ): Diagnostic in the patient history during duration\n\n// PatientHasProposedorConfirmedDianostic(&quot;Diagnostic name&quot; ): Diagnostic in the encounter\n\n// PatientHasHistoryOfProposedorConfirmedDianostic(&quot;Diagnostic name&quot;, duration ): Diagnostic in the patient history during duration\n\n// PatientZScoreWfA(wieght, age)\n\n// PatientWeightFromWfA(age, Muac)\n</code></pre></div>"
  },
  "url" : "https://fhir.dk.swisstph-mis.ch/matchbox/fhir//Library/chebase",
  "version" : "0.1.0",
  "name" : "chebase",
  "title" : "CHEBase",
  "status" : "active",
  "type" : {
    "coding" : [
      {
        "system" : "http://hl7.org/fhir/ValueSet/library-type",
        "code" : "logic-library"
      }
    ]
  },
  "date" : "2023-10-04T12:32:21+00:00",
  "publisher" : "WHO",
  "contact" : [
    {
      "name" : "WHO",
      "telecom" : [
        {
          "system" : "url",
          "value" : "http://who.int"
        }
      ]
    }
  ],
  "relatedArtifact" : [
    {
      "type" : "depends-on",
      "resource" : "http://fhir.org/guides/who/anc-cds/Library/FHIRHelpers"
    }
  ],
  "parameter" : [
    {
      "name" : "encounterid",
      "use" : "in",
      "type" : "string"
    }
  ],
  "dataRequirement" : [
    {
      "type" : "Patient",
      "profile" : [
        "http://hl7.org/fhir/StructureDefinition/Patient"
      ]
    },
    {
      "type" : "Encounter",
      "profile" : [
        "http://hl7.org/fhir/StructureDefinition/Encounter"
      ]
    }
  ],
  "content" : [
    {
      "id" : "ig-loader-chebase.cql",
      "contentType" : "text/cql",
      "data" : "LypudGVyIgpAYXV0aG9yOiBQYXRyaWNrIERlbGNyb2l4CkBkZXNjcmlwdGlvbjogVGhpcyBsaWJyYXJ5IGlzIHBhcnQgb2YgdGhlIHByb2plY3QgQ0hFIFByb2plY3QsIGl0cyBhbGxvd3Mgc3RhbmRhcmRpc2F0aW9uIGZvciB0aGUgb2JzZXJ2YXRpb24gcHJvY2Vzc2luZwoqLwoKbGlicmFyeSBjaGViYXNlIHZlcnNpb24gJzEuMC4zMTMrYnVpbGQuNDU2JwoKdXNpbmcgRkhJUiB2ZXJzaW9uICc0LjAuMScKCmluY2x1ZGUgRkhJUkhlbHBlcnMgdmVyc2lvbiAnNC4wLjEnCgpwYXJhbWV0ZXIgImVuY291bnRlcmlkIiBTdHJpbmcKLy9wYXJhbWV0ZXIgIkVuY291bnRlciIgRW5jb3VudGVyJApjb2Rlc3lzdGVtICJSb2xlQ29kZVN5c3RlbSIgOiAnaHR0cHM6Ly9maGlyLmRrLnN3aXNzdHBoLW1pcy5jaC9tYXRjaGJveC9maGlyL0NvZGVTeXN0ZW0vZW1jYXJlLWN1c3RvbS1jb2RlcycKY29kZSAiTW90aGVyIjogJ01USCcgZnJvbSAiUm9sZUNvZGVTeXN0ZW0iCgpjb250ZXh0IFBhdGllbnQKCi8vZGVmaW5lIGVuY291bnRlcmlkOgovLyAgIkVuY291bnRlciIuaWQKCgoKCmRlZmluZSAiWWVzIjoKICB0cnVlCgpkZWZpbmUgIk5vIjoKICBmYWxzZSAKCgpkZWZpbmUgZnVuY3Rpb24gSXNJbkVuY291bnRlcihyZWYgRkhJUi5SZWZlcmVuY2UpOgogICAgY2FzZQogICAgd2hlbiBlbmNvdW50ZXJpZCA9IHJlZi5pZCB0aGVuIHRydWUKICAgIHdoZW4gZW5jb3VudGVyaWQgPSBMYXN0KFNwbGl0KHJlZi5yZWZlcmVuY2UsICcvJykpIHRoZW4gdHJ1ZQogICAvLyB3aGVuIHJlZi5pZGVudGlmaWVyIGlzIG5vdCBudWxsIGFuZCBpZCA9IHJlZi5pZGVudGlmaWVyLmlkIHRoZW4gdHJ1ZQogICAgZWxzZSBmYWxzZQplbmQKCmRlZmluZSBnZXRFbmNvdW50ZXJzOgogICAgW0VuY291bnRlcl0gRSAKICAgICAgd2hlcmUgRS5pZCA9ICJlbmNvdW50ZXJpZCIKICAgICAgICByZXR1cm4gRQoKZGVmaW5lIGdldEVuY291bnRlcjoKICAgIHNpbmdsZXRvbiBmcm9tIGdldEVuY291bnRlcnMKCmRlZmluZSBmdW5jdGlvbiBDSEVFeHRlbnNpb25zKGVsZW1lbnQgUGF0aWVudCwgaWQgU3RyaW5nKToKICBlbGVtZW50LmV4dGVuc2lvbiBFCiAgICAgIHdoZXJlIEUudXJsID0gKCdodHRwczovL2ZoaXIuZGsuc3dpc3N0cGgtbWlzLmNoL21hdGNoYm94L2ZoaXIvU3RydWN0dXJlRGVmaW5pdGlvbi8nICsgaWQpCiAgICAgIHJldHVybiBFCgpkZWZpbmUgZnVuY3Rpb24gQ0hFRXh0ZW5zaW9uKGVsZW1lbnQgUGF0aWVudCwgaWQgU3RyaW5nKToKICBzaW5nbGV0b24gZnJvbSBDSEVFeHRlbnNpb25zKGVsZW1lbnQsIGlkKQoKZGVmaW5lIGZ1bmN0aW9uIENIRUV4dGVuc2lvbnMoZWxlbWVudCBFbmNvdW50ZXIsIGlkIFN0cmluZyk6CiAgZWxlbWVudC5leHRlbnNpb24gRQogICAgICB3aGVyZSBFLnVybCA9ICgnaHR0cHM6Ly9maGlyLmRrLnN3aXNzdHBoLW1pcy5jaC9tYXRjaGJveC9maGlyL1N0cnVjdHVyZURlZmluaXRpb24vJyArIGlkKQogICAgICByZXR1cm4gRQoKCmRlZmluZSBmdW5jdGlvbiBwb3N0Y29yZGluYXRpb25FeHRlbnNpb24oZWxlbWVudCBDb25kaXRpb24sIHBvc3Rjb3JkaW5hdGlvbiBMaXN0PFN0cmluZz4pOgogIGVsZW1lbnQuZXh0ZW5zaW9uIEUKICAgICAgd2hlcmUgRS51cmwgPSAoJ2h0dHBzOi8vZmhpci5kay5zd2lzc3RwaC1taXMuY2gvbWF0Y2hib3gvZmhpci9TdHJ1Y3R1cmVEZWZpbml0aW9uL3Bvc3Rjb3JkaW5hdGlvbicpCiAgICAgIGFuZCBFLnZhbHVlIGluIHBvc3Rjb3JkaW5hdGlvbgoKCmRlZmluZSBmdW5jdGlvbiBDSEVFeHRlbnNpb24oZWxlbWVudCBFbmNvdW50ZXIsIGlkIFN0cmluZyk6CiAgc2luZ2xldG9uIGZyb20gQ0hFRXh0ZW5zaW9ucyhlbGVtZW50LCBpZCkKCmRlZmluZSBnZXRQcmltYXJ5Q2FyZUdpdmVyUmVmZXJlbmNlOgogIENIRUV4dGVuc2lvbihQYXRpZW50LCAncHJpbWFyeWNhcmVnaXZlcicpLnZhbHVlCgpkZWZpbmUgZ2V0UHJpbWFyeUNhcmVHaXZlcjoKICBbUmVsYXRlZFBlcnNvbl0gUlAgd2hlcmUgUlAuaWQgPSBMYXN0KFNwbGl0KGdldFByaW1hcnlDYXJlR2l2ZXJSZWZlcmVuY2UucmVmZXJlbmNlLCAnLycpKQogICAgcmV0dXJuIFJQCgpkZWZpbmUgaXNNb3RoZXJQcmltYXJ5Q2FyZUdpdmVyOgogIGdldFByaW1hcnlDYXJlR2l2ZXIgaXMgbm90IG51bGwgYW5kIEV4aXN0cyhnZXRQcmltYXJ5Q2FyZUdpdmVyLnJlbGF0aW9uc2hpcCByIHdoZXJlIHIgfiAiTW90aGVyIikKCmRlZmluZSAiQmlvbG9naWNhbCBNb3RoZXIgVml0YWwgU3RhdHVzIjoKICBDSEVFeHRlbnNpb24oUGF0aWVudCwgJ21vdGhlclZpdGFsU3RhdHVzJykudmFsdWUKICAKZGVmaW5lICJCaW9sb2dpY2FsIEZhdGhlciBWaXRhbCBTdGF0dXMiOgogIENIRUV4dGVuc2lvbihQYXRpZW50LCAnZmF0aGVyVml0YWxTdGF0dXMnKS52YWx1ZQovLyBwZXJzb24gYWNjb21wYW55aW5nIHRoZSBjaGlsZCBpcyBhIHBhcnRpY2lwYW50IHdpdGggYSBudWxsIHR5cGUKZGVmaW5lIGdldFJlbGF0ZWRQZXJzb25SZWZlcmVuY2VBY2NvbXBhbnlpbmdUaGVDaGlsZDoKICBDb2FsZXNjZShGaXJzdChnZXRFbmNvdW50ZXIucGFydGljaXBhbnQgUCB3aGVyZSBub3QgZXhpc3RzKFAudHlwZSkgKS5pbmRpdmlkdWFsLCBnZXRQcmltYXJ5Q2FyZUdpdmVyUmVmZXJlbmNlKQoKZGVmaW5lIGdldFJlbGF0ZWRQZXJzb25zQWNjb21wYW55aW5nVGhlQ2hpbGQ6CiAgW1JlbGF0ZWRQZXJzb25dIFJQIHdoZXJlIFJQLmlkID0gTGFzdChTcGxpdChnZXRSZWxhdGVkUGVyc29uUmVmZXJlbmNlQWNjb21wYW55aW5nVGhlQ2hpbGQucmVmZXJlbmNlLCAnLycpKQogICAgcmV0dXJuIFJQCgoKZGVmaW5lIGdldFJlbGF0ZWRQZXJzb25BY2NvbXBhbnlpbmdUaGVDaGlsZDoKICBzaW5nbGV0b24gZnJvbSBnZXRSZWxhdGVkUGVyc29uc0FjY29tcGFueWluZ1RoZUNoaWxkCgoKZGVmaW5lICJQZXJzb24gYWNjb21wYW55aW5nIGNoaWxkIHRvZGF5J3MgUmVsYXRpb25zaGlwIHRvIENsaWVudCI6Ci8vV09SS0FSUk9VTkQgICBnZXRSZWxhdGVkUGVyc29uQWNjb21wYW55aW5nVGhlQ2hpbGQucmVsYXRpb25zaGlwCiAgQ0hFRXh0ZW5zaW9uKGdldEVuY291bnRlciwgJ21vdGhlcnByZXNlbnQnKS52YWx1ZQoKCgoKCmRlZmluZSBmdW5jdGlvbiBnZXRWYWx1ZShPIE9ic2VydmF0aW9uKToKICBjYXNlICAKICAgICAgd2hlbiAgTyBpcyBudWxsIHRoZW4gbnVsbAogICAgICB3aGVuIE8udmFsdWUgaXMgQ29kZWFibGVDb25jZXB0IHRoZW4gQ29hbGVzY2UoRmlyc3QoTy52YWx1ZS5jb2RpbmcgQyB3aGVyZSBDLnN5c3RlbSAgPSAnaHR0cHM6Ly9maGlyLmRrLnN3aXNzdHBoLW1pcy5jaC9tYXRjaGJveC9maGlyL0NvZGVTeXN0ZW0vY2hlLWN1c3RvbS1jb2RlcycpLCBGaXJzdChPLnZhbHVlLmNvZGluZykpCiAgICAgIGVsc2UgTy52YWx1ZQogIGVuZAoKCmRlZmluZSBmdW5jdGlvbiBhc3Nlc09ic2VydmF0aW9uKE8gT2JzZXJ2YXRpb24pOgogIGNhc2UgIAogICAgICB3aGVuICBPIGlzIG51bGwgdGhlbiBudWxsCiAgICAgIHdoZW4gIE8uc3RhdHVzIGluICB7J2NhbmNlbGxlZCd9IHRoZW4gZmFsc2UKICAgICAgd2hlbiBPLnZhbHVlIGlzIG51bGwgdGhlbiAgdHJ1ZQogICAgICBlbHNlIE8udmFsdWUKICBlbmQKLyogICAgICAKZGVmaW5lIGZ1bmN0aW9uIEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyKGlkbGlzdCBMaXN0PFN5c3RlbS5Db2RlPik6CiAgaWYgR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXJEb25lKGlkbGlzdCApIGlzIG51bGwgdGhlbiAKICAgICAgR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXJEb25lKGlkbGlzdCApCiAgZWxzZQogICAgR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXJOb3RGb3VuZChpZGxpc3QgKQoqLwoKZGVmaW5lIGZ1bmN0aW9uIEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyKGlkIFN5c3RlbS5Db2RlKToKICAgICAgRmlyc3QoW09ic2VydmF0aW9uOiBpZCBdIE8KICAgICAgICB3aGVyZSAgIElzSW5FbmNvdW50ZXIoTy5lbmNvdW50ZXIpIAogICAgICAgIGFuZCBPLnN0YXR1cyBpbiB7ICdmaW5hbCcsICdhbWVuZGVkJywgJ2NvcnJlY3RlZCcsJ2NhbmNlbGxlZCd9IAogICAgICAgIHNvcnQgYnkgaXNzdWVkLnZhbHVlIGRlc2MpIAoKICAvKgogIHRoaXMgaXMgY29tbWVudGVkIGZvciBwZXJmb3JtYW5jZSBpbXByb3ZlbWVudCwgZXZlbiBpZiBpdCBoaWRlcyBhIHZhbGlkIG9ic2VydmF0aW9uIGlmIHRoZXJlIGlzIGFuIG1vcmUgcmVjZW50IHVudmFsaWQgb25lCiAgQ29hbGVzY2UoR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXJEb25lKGlkICksIEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyTm90Rm91bmQoaWQgKSkKICAqLwovKgpkZWZpbmUgZnVuY3Rpb24gR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXJEb25lKGlkbGlzdCBMaXN0PFN5c3RlbS5Db2RlPik6CiAgICAgIExhc3QoW09ic2VydmF0aW9uOiBpZGxpc3QgXSBPCiAgICAgICAgd2hlcmUgICBJc0luRW5jb3VudGVyKE8uZW5jb3VudGVyKSAKICAgICAgICBhbmQgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfSkKKi8KZGVmaW5lIGZ1bmN0aW9uIEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyRG9uZShpZCBTeXN0ZW0uQ29kZSk6CiAgICAgIEZpcnN0KFtPYnNlcnZhdGlvbjogaWQgXSBPCiAgICAgICAgd2hlcmUgICBJc0luRW5jb3VudGVyKE8uZW5jb3VudGVyKSAKICAgICAgICBhbmQgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfSAKICAgICAgICBzb3J0IGJ5IGlzc3VlZC52YWx1ZSBkZXNjKSAKCgpkZWZpbmUgZnVuY3Rpb24gSGFzT2JzZXJ2YXRpb25Db2RlRHVyaW5nRW5jb3VudGVyRG9uZShpZCBTeXN0ZW0uQ29kZSwgdmFsdWVDb2RlIFN5c3RlbS5Db2RlKToKICAgIAogICAgRXhpc3RzKFtPYnNlcnZhdGlvbjogaWQgXSBPCiAgICAgICAgd2hlcmUgICBJc0luRW5jb3VudGVyKE8uZW5jb3VudGVyKSAKICAgICAgICBhbmQgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfQogICAgICAgIGFuZCBPLnZhbHVlIGlzIEZISVIuQ29kZWFibGVDb25jZXB0CiAgICAgICAgYW5kIE8udmFsdWUgfiB2YWx1ZUNvZGUpCgovL0V4aXN0cyhbT2JzZXJ2YXRpb25dIE8gd2hlcmUgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfSBhbmQgTy52YWx1ZSBpcyBGSElSLkNvZGVhYmxlQ29uY2VwdCAgIGFuZCBFeGlzdHMoIE8udmFsdWUuY29kaW5nIEMgd2hlcmUgQyBpcyBGSElSLkNvZGluZyBhbmQgQy5jb2RlID0gRkhJUi5jb2RlIHt2YWx1ZTogJ0NIRS5CMjBTMi5ERTA0J30pICkiCgovKgpkZWZpbmUgZnVuY3Rpb24gR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXJOb3RGb3VuZChpZGxpc3QgTGlzdDxTeXN0ZW0uQ29kZT4pOgogICAgICBMYXN0KFtPYnNlcnZhdGlvbjogaWRsaXN0XSBPCiAgICAgICB3aGVyZSAgSXNJbkVuY291bnRlcihPLmVuY291bnRlcikgCiAgICAgICAgICBhbmQgTy5zdGF0dXMgaW4geydjYW5jZWxsZWQnfSkKICAgICAgICAgICovCmRlZmluZSBmdW5jdGlvbiBHZXRPYnNlcnZhdGlvbkR1cmluZ0VuY291bnRlck5vdEZvdW5kKGlkIFN5c3RlbS5Db2RlKToKICAgICAgRmlyc3QoW09ic2VydmF0aW9uOiBpZF0gTwogICAgICAgd2hlcmUgIElzSW5FbmNvdW50ZXIoTy5lbmNvdW50ZXIpIAogICAgICAgICAgYW5kIE8uc3RhdHVzIGluIHsnY2FuY2VsbGVkJ30KICAgICAgICAgIHNvcnQgYnkgaXNzdWVkLnZhbHVlIGRlc2MpCi8qCgpkZWZpbmUgZnVuY3Rpb24gR2V0TnVtYmVyT2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXIoaWRsaXN0IExpc3Q8U3lzdGVtLkNvZGU+KToKICBDb3VudCgKICAgIFtPYnNlcnZhdGlvbjogaWRsaXN0XSBPCiAgICAgICAgd2hlcmUgIElzSW5FbmNvdW50ZXIoIE8uZW5jb3VudGVyKSAKICAgICAgICBhbmQgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfSkKKi8KZGVmaW5lIGZ1bmN0aW9uIEdldE51bWJlck9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyKGlkIFN5c3RlbS5Db2RlKToKICBDb3VudCgKICAgIFtPYnNlcnZhdGlvbjogaWRdIE8KICAgICAgICB3aGVyZSAgSXNJbkVuY291bnRlciggTy5lbmNvdW50ZXIpIAogICAgICAgIGFuZCBPLnN0YXR1cyBpbiB7ICdmaW5hbCcsICdhbWVuZGVkJywgJ2NvcnJlY3RlZCd9KQoKLy8gKioqKioqKioqKioqKioqKioqKioqKioqICAgR2V0T2JzVmFsdWUgKioqKioqKioqKioqKioqKioqKioqKioqLwovKgpkZWZpbmUgZnVuY3Rpb24gR2V0T2JzVmFsdWUoaWRsaXN0IExpc3Q8U3lzdGVtLkNvZGU+KToKICAgIGdldFZhbHVlKEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyKGlkbGlzdCkpCgpkZWZpbmUgZnVuY3Rpb24gR2V0T2JzVmFsdWUoaWQgU3lzdGVtLkNvZGUpOgogICAgZ2V0VmFsdWUoR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXIoe2lkfSkpCiovCgpkZWZpbmUgZnVuY3Rpb24gR2V0T2JzVmFsdWUoaWQgU3lzdGVtLkNvZGUpOgogICAgZ2V0VmFsdWUoR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXIoaWQpKQoKZGVmaW5lIGZ1bmN0aW9uIEdldE9ic1ZhbHVlKGlkIFN5c3RlbS5TdHJpbmcsIGNvZGVzeXN0ZW0gU3lzdGVtLlN0cmluZyk6CiAgICBnZXRWYWx1ZShHZXRPYnNlcnZhdGlvbkR1cmluZ0VuY291bnRlcihjb2RpbmcoaWQsIGNvZGVzeXN0ZW0pKSkKCmRlZmluZSBmdW5jdGlvbiBHZXRPYnNWYWx1ZShpZCBTeXN0ZW0uU3RyaW5nKToKICAgIGdldFZhbHVlKEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyKGNvZGluZyhpZCwgJ2h0dHBzOi8vZmhpci5kay5zd2lzc3RwaC1taXMuY2gvbWF0Y2hib3gvZmhpci9Db2RlU3lzdGVtL2NoZS1jdXN0b20tY29kZXMnKSkpCgpkZWZpbmUgZnVuY3Rpb24gSGFzT2JzVmFsdWVDb2RlKGlkIFN5c3RlbS5TdHJpbmcsIHZhbHVlIFN5c3RlbS5Db2RlKToKICAgSGFzT2JzZXJ2YXRpb25Db2RlRHVyaW5nRW5jb3VudGVyRG9uZShjb2RpbmcoaWQsICdodHRwczovL2ZoaXIuZGsuc3dpc3N0cGgtbWlzLmNoL21hdGNoYm94L2ZoaXIvQ29kZVN5c3RlbS9jaGUtY3VzdG9tLWNvZGVzJykgLCB2YWx1ZSApCiAgCmRlZmluZSBmdW5jdGlvbiBIYXNPYnNWYWx1ZUNvZGUoaWQgU3lzdGVtLlN0cmluZywgdmFsdWUgU3lzdGVtLlN0cmluZyk6CiAgIEhhc09ic2VydmF0aW9uQ29kZUR1cmluZ0VuY291bnRlckRvbmUoY29kaW5nKGlkLCAnaHR0cHM6Ly9maGlyLmRrLnN3aXNzdHBoLW1pcy5jaC9tYXRjaGJveC9maGlyL0NvZGVTeXN0ZW0vY2hlLWN1c3RvbS1jb2RlcycpICwgY29kaW5nKHZhbHVlLCAnaHR0cHM6Ly9maGlyLmRrLnN3aXNzdHBoLW1pcy5jaC9tYXRjaGJveC9maGlyL0NvZGVTeXN0ZW0vY2hlLWN1c3RvbS1jb2RlcycpICkKCmRlZmluZSBmdW5jdGlvbiBIYXNPYnNWYWx1ZUNvZGUoaWQgU3lzdGVtLkNvZGUsIHZhbHVlIFN5c3RlbS5TdHJpbmcpOgogICBIYXNPYnNlcnZhdGlvbkNvZGVEdXJpbmdFbmNvdW50ZXJEb25lKGlkICwgY29kaW5nKHZhbHVlLCAnaHR0cHM6Ly9maGlyLmRrLnN3aXNzdHBoLW1pcy5jaC9tYXRjaGJveC9maGlyL0NvZGVTeXN0ZW0vY2hlLWN1c3RvbS1jb2RlcycpICkKCi8vICoqKioqKioqKioqKioqKioqKioqKioqKiAgIEhhc09icyAqKioqKioqKioqKioqKioqKioqKioqKiovCi8qCmRlZmluZSBmdW5jdGlvbiBIYXNPYnMoaWRsaXN0IExpc3Q8U3lzdGVtLkNvZGU+KToKICAgIGFzc2VzT2JzZXJ2YXRpb24oR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXIoaWRsaXN0KSkKCmRlZmluZSBmdW5jdGlvbiBIYXNPYnMoaWQgU3lzdGVtLkNvZGUpOgogICAgYXNzZXNPYnNlcnZhdGlvbihHZXRPYnNlcnZhdGlvbkR1cmluZ0VuY291bnRlcih7aWR9KSkKKi8KZGVmaW5lIGZ1bmN0aW9uIEhhc09icyhpZCBTeXN0ZW0uQ29kZSk6CiAgICBhc3Nlc09ic2VydmF0aW9uKEdldE9ic2VydmF0aW9uRHVyaW5nRW5jb3VudGVyKGlkKSkKCmRlZmluZSBmdW5jdGlvbiBIYXNPYnMoaWQgU3lzdGVtLlN0cmluZywgY29kZXN5c3RlbSBTeXN0ZW0uU3RyaW5nKToKICAgIGFzc2VzT2JzZXJ2YXRpb24oR2V0T2JzZXJ2YXRpb25EdXJpbmdFbmNvdW50ZXIoY29kaW5nKGlkLCBjb2Rlc3lzdGVtKSkpCgpkZWZpbmUgZnVuY3Rpb24gSGFzT2JzKGlkIFN5c3RlbS5TdHJpbmcpOgogICAgYXNzZXNPYnNlcnZhdGlvbihHZXRPYnNlcnZhdGlvbkR1cmluZ0VuY291bnRlcihjb2RpbmcoaWQpKSkKCmRlZmluZSBmdW5jdGlvbiBIYXNPYnMoaWQgRkhJUi5jb2RlLCBjb2Rlc3lzdGVtIFN5c3RlbS5TdHJpbmcpOgogICAgYXNzZXNPYnNlcnZhdGlvbihHZXRPYnNlcnZhdGlvbkR1cmluZ0VuY291bnRlcihjb2RpbmcoaWQsIGNvZGVzeXN0ZW0pKSkKLyoKZGVmaW5lIGZ1bmN0aW9uIEdldEhpc3RvcmljT2JzZXJ2YXRpb24oaWRsaXN0IExpc3Q8U3lzdGVtLkNvZGU+LCBuYmRheXMgSW50ZWdlcik6CiAgaWYgR2V0SGlzdG9yaWNPYnNlcnZhdGlvbk5vdGZvdW5kKGlkbGlzdCAsIGNvZGVzeXN0ZW0gLCBuYmRheXMgKSBpcyBudWxsIHRoZW4gCiAgICAgIEdldEhpc3RvcmljT2JzZXJ2YXRpb25Ob3Rmb3VuZChpZGxpc3QgLCBjb2Rlc3lzdGVtICwgbmJkYXlzICkKICBlbHNlCiAgICBHZXRIaXN0b3JpY09ic2VydmF0aW9uTm90Zm91bmQoaWRsaXN0ICwgY29kZXN5c3RlbSAsIG5iZGF5cyApCiovCgpkZWZpbmUgZnVuY3Rpb24gR2V0SGlzdG9yaWNPYnNlcnZhdGlvbihpZCBTeXN0ZW0uQ29kZSwgbmJkYXlzIEludGVnZXIpOgogICAgICBGaXJzdChbT2JzZXJ2YXRpb246IGlkIF0gTwogICAgICAgIHdoZXJlIE8uc3RhdHVzIGluIHsgJ2ZpbmFsJywgJ2FtZW5kZWQnLCAnY29ycmVjdGVkJywnY2FuY2VsbGVkJ30gCiAgICAgICAgYW5kIChkaWZmZXJlbmNlIGluIGRheXMgYmV0d2VlbiBPLmlzc3VlZCBhbmQgVG9kYXkoKSkgPCBuYmRheXMgCiAgICAgICAgc29ydCBieSBpc3N1ZWQudmFsdWUgZGVzYyApCgogIC8vQ29hbGVzY2UoR2V0SGlzdG9yaWNPYnNlcnZhdGlvbkRvbmUoaWQgLCAgbmJkYXlzICksICBHZXRIaXN0b3JpY09ic2VydmF0aW9uTm90Zm91bmQoaWQgICwgbmJkYXlzICkpCi8qCmRlZmluZSBmdW5jdGlvbiBHZXRIaXN0b3JpY09ic2VydmF0aW9uRG9uZShpZGxpc3QgTGlzdDxTeXN0ZW0uQ29kZT4sIG5iZGF5cyBJbnRlZ2VyKToKICAgICAgTGFzdChbT2JzZXJ2YXRpb246IGlkbGlzdCBdIE8KICAgICAgICB3aGVyZSAgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfQogICAgICAgIGFuZCAoZGlmZmVyZW5jZSBpbiBkYXlzIGJldHdlZW4gTy5pc3N1ZWQgYW5kIFRvZGF5KCkpIDwgbmJkYXlzKQoqLwpkZWZpbmUgZnVuY3Rpb24gR2V0SGlzdG9yaWNPYnNlcnZhdGlvbkRvbmUoaWQgU3lzdGVtLkNvZGUsIG5iZGF5cyBJbnRlZ2VyKToKICAgICAgRmlyc3QoW09ic2VydmF0aW9uOiBpZCBdIE8KICAgICAgICB3aGVyZSAgTy5zdGF0dXMgaW4geyAnZmluYWwnLCAnYW1lbmRlZCcsICdjb3JyZWN0ZWQnfQogICAgICAgIGFuZCAoZGlmZmVyZW5jZSBpbiBkYXlzIGJldHdlZW4gTy5pc3N1ZWQgYW5kIFRvZGF5KCkpIDwgbmJkYXlzIAogICAgICAgIHNvcnQgYnkgaXNzdWVkLnZhbHVlIGRlc2MgKQoKLyoKZGVmaW5lIGZ1bmN0aW9uIEdldEhpc3RvcmljT2JzZXJ2YXRpb25Ob3Rmb3VuZChpZGxpc3QgTGlzdDxTeXN0ZW0uQ29kZT4sIG5iZGF5cyBJbnRlZ2VyKToKICAgICAgTGFzdChbT2JzZXJ2YXRpb246IGlkbGlzdF0gTwogICAgICAgIHdoZXJlICBPLnN0YXR1cyBpbiB7J2NhbmNlbGxlZCd9CiovCmRlZmluZSBmdW5jdGlvbiBHZXRIaXN0b3JpY09ic2VydmF0aW9uTm90Zm91bmQoaWQgU3lzdGVtLkNvZGUsIG5iZGF5cyBJbnRlZ2VyKToKICAgICAgRmlyc3QoW09ic2VydmF0aW9uOiBpZF0gTwogICAgICAgIHdoZXJlICBPLnN0YXR1cyBpbiB7J2NhbmNlbGxlZCd9CiAgICAgICAgICBhbmQgKGRpZmZlcmVuY2UgaW4gZGF5cyBiZXR3ZWVuIE8uaXNzdWVkIGFuZCBUb2RheSgpKSA8IG5iZGF5cyAKICAgICAgICBzb3J0IGJ5IGlzc3VlZC52YWx1ZSBkZXNjKQovLyAqKioqKioqKioqKioqKioqKioqKioqKiogICBIYXNPYnNIaXN0b3J5ICoqKioqKioqKioqKioqKioqKioqKioqKi8KCi8qCmRlZmluZSBmdW5jdGlvbiBIYXNPYnNIaXN0b3J5KGlkbGlzdCBMaXN0PFN5c3RlbS5Db2RlPiwgIG5iZGF5cyBJbnRlZ2VyKToKICBhc3Nlc09ic2VydmF0aW9uKEdldEhpc3RvcmljT2JzZXJ2YXRpb24oaWRsaXN0LCBuYmRheXMpKQoKCiBkZWZpbmUgZnVuY3Rpb24gSGFzT2JzSGlzdG9yeShpZCBTeXN0ZW0uQ29kZSwgY25iZGF5cyBJbnRlZ2VyKToKICBhc3Nlc09ic2VydmF0aW9uKEdldEhpc3RvcmljT2JzZXJ2YXRpb24oe2lkfSwgbmJkYXlzKSkKKi8KZGVmaW5lIGZ1bmN0aW9uIEhhc09ic0hpc3RvcnkoaWQgU3lzdGVtLkNvZGUsIG5iZGF5cyBJbnRlZ2VyKToKICBhc3Nlc09ic2VydmF0aW9uKEdldEhpc3RvcmljT2JzZXJ2YXRpb24oaWQsIG5iZGF5cykpCgpkZWZpbmUgZnVuY3Rpb24gSGFzT2JzSGlzdG9yeShpZCBTeXN0ZW0uU3RyaW5nLCBjb2Rlc3lzdGVtIFN5c3RlbS5TdHJpbmcsIG5iZGF5cyBJbnRlZ2VyKToKICBhc3Nlc09ic2VydmF0aW9uKEdldEhpc3RvcmljT2JzZXJ2YXRpb24oY29kaW5nKGlkLCBjb2Rlc3lzdGVtKSwgbmJkYXlzKSkKCgpkZWZpbmUgZnVuY3Rpb24gSGFzT2JzSGlzdG9yeShpZCBTeXN0ZW0uU3RyaW5nLCBuYmRheXMgSW50ZWdlcik6CiAgYXNzZXNPYnNlcnZhdGlvbihHZXRIaXN0b3JpY09ic2VydmF0aW9uKGNvZGluZyhpZCksIG5iZGF5cykpCgpkZWZpbmUgZnVuY3Rpb24gYyhzIFN5c3RlbS5TdHJpbmcpOgogIEZISVIuY29kZSB7IHZhbHVlOiBzIH0KCgpkZWZpbmUgZnVuY3Rpb24gY29kaW5nKHMgU3lzdGVtLlN0cmluZywgdXJsIFN5c3RlbS5TdHJpbmcpOgogIFN5c3RlbS5Db2RlIHsKICAgICAgICAgICAgICAgIGNvZGU6ICBzICwKICAgICAgICAgICAgICAgIHN5c3RlbTogIHVybCAKICAgICAgICAgICAgfQoKZGVmaW5lIGZ1bmN0aW9uIGNvZGluZyhzIEZISVIuY29kZSwgdXJsIFN5c3RlbS5TdHJpbmcpOgogIFN5c3RlbS5Db2RlIHsKICAgICAgICAgICAgICAgIGNvZGU6ICBzLnZhbHVlICwKICAgICAgICAgICAgICAgIHN5c3RlbTogIHVybCAKICAgICAgICAgICAgfQoKZGVmaW5lIGZ1bmN0aW9uIGNvZGluZyhzIFN5c3RlbS5TdHJpbmcpOgogIFN5c3RlbS5Db2RlIHsKICAgICAgICAgICAgICAgIGNvZGU6ICBzICwKICAgICAgICAgICAgICAgIHN5c3RlbTogICdodHRwczovL2ZoaXIuZGsuc3dpc3N0cGgtbWlzLmNoL21hdGNoYm94L2ZoaXIvQ29kZVN5c3RlbS9jaGUtY3VzdG9tLWNvZGVzJwogICAgICAgICAgICB9CgoKZGVmaW5lIGZ1bmN0aW9uIFRvVXJsKHMgU3lzdGVtLlN0cmluZyk6CiAgdXJsIHt2YWx1ZTpzfQoKZGVmaW5lIGZ1bmN0aW9uIFRvSW50QyhiIFN5c3RlbS5Cb29sZWFuKToKICBjYXNlCiAgd2hlbiBiIGlzIG51bGwgdGhlbiAwCiAgd2hlbiBiID0gdHJ1ZSB0aGVuIDEKICBlbHNlIDAKICBlbmQKCgovLyAqKioqKioqKioqKioqKioqKioqKioqKiogICBHZXRDb25kICoqKioqKioqKioqKioqKioqKioqKioqKi8KCmRlZmluZSBmdW5jdGlvbiBHZXRDb25kaXRpb25zKGlkIFN5c3RlbS5Db2RlKToKICAgICAgW0NvbmRpdGlvbjogaWRdIE8KICAgICAgICB3aGVyZSAgSXNJbkVuY291bnRlciggTy5lbmNvdW50ZXIpIAogICAgICAgIGFuZCBleGlzdHMoTy52ZXJpZmljYXRpb25TdGF0dXMuY29kaW5nIEMgd2hlcmUgQy5jb2RlIGluIHsndW5jb25maXJtZWQnLCAncHJvdmlzaW9uYWwnLCAnZGlmZmVyZW50aWFsJywgJ2NvbmZpcm1lZCd9IAogICAgICAgIGFuZCBDLnN5c3RlbSA9ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2NvbmRpdGlvbi12ZXItc3RhdHVzJykKICAgICAgICBzb3J0IGJ5IHJlY29yZGVkRGF0ZSBkZXNjCgoKCgpkZWZpbmUgZnVuY3Rpb24gR2V0U3RlbUNvZGUoaWQgU3lzdGVtLlN0cmluZyk6CiAgY29kaW5nKFNwbGl0KCBpZCwgJyYnKVswXSkKCmRlZmluZSBmdW5jdGlvbiBHZXRQb3N0Y29vcmRpbmF0aW9uQ29kZShpZCBTeXN0ZW0uU3RyaW5nKToKICBUYWlsKFNwbGl0KGlkLCAnJicpKQoKZGVmaW5lIGZ1bmN0aW9uIEdldENvbmRpdGlvbihpZCBTeXN0ZW0uQ29kZSk6CiAgICAgIEZpcnN0KEdldENvbmRpdGlvbnMoaWQpKQoKCiAgIApkZWZpbmUgZnVuY3Rpb24gR2V0Q29uZGl0aW9uKGlkIFN5c3RlbS5Db2RlLCBwb3N0Y29yZGluYXRpb24gTGlzdDxTeXN0ZW0uU3RyaW5nPik6CiAgICBGaXJzdCgKICAgICAgW0NvbmRpdGlvbjogaWRdIEMKICAgICAgICB3aGVyZSAgSXNJbkVuY291bnRlciggQy5lbmNvdW50ZXIpIAogICAgICAgIGFuZCBleGlzdHMoQy52ZXJpZmljYXRpb25TdGF0dXMuY29kaW5nIGNjIHdoZXJlIGNjLmNvZGUgaW4geyd1bmNvbmZpcm1lZCcsICdwcm92aXNpb25hbCcsICdkaWZmZXJlbnRpYWwnLCAnY29uZmlybWVkJ30gCiAgICAgICAgYW5kIGNjLnN5c3RlbSA9ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2NvbmRpdGlvbi12ZXItc3RhdHVzJykKICAgICAgICBhbmQgIHBvc3Rjb3JkaW5hdGlvbiBpcyBudWxsIG9yICBDb3VudChwb3N0Y29yZGluYXRpb25FeHRlbnNpb24oQyxwb3N0Y29yZGluYXRpb24pKSA+PSBDb3VudChwb3N0Y29yZGluYXRpb24pCiAgICAgICAgc29ydCBieSByZWNvcmRlZERhdGUgZGVzYwogICAgKQoKCmRlZmluZSBmdW5jdGlvbiBhc3Nlc0NvbmRpdGlvbihPIENvbmRpdGlvbik6CiAgaWYgTyBpcyBudWxsIHRoZW4gCiAgICBmYWxzZQogIGVsc2UKICAgIHRydWUKCmRlZmluZSBmdW5jdGlvbiBHZXRDb25kKGlkIFN5c3RlbS5Db2RlKToKICAoR2V0Q29uZGl0aW9uKGlkKSkKCmRlZmluZSBmdW5jdGlvbiBHZXRDb25kKGlkIFN5c3RlbS5TdHJpbmcsIGNvZGVzeXN0ZW0gU3lzdGVtLlN0cmluZyk6CiAgKEdldENvbmRpdGlvbihjb2RpbmcoaWQsIGNvZGVzeXN0ZW0pKSkKCmRlZmluZSBmdW5jdGlvbiBHZXRDb25kKGlkIFN5c3RlbS5TdHJpbmcpOgogIChHZXRDb25kaXRpb24oR2V0U3RlbUNvZGUoaWQpLEdldFBvc3Rjb29yZGluYXRpb25Db2RlKGlkKSkpCgovLyAqKioqKioqKioqKioqKioqKioqKioqKiogICBIYXNDb25kICoqKioqKioqKioqKioqKioqKioqKioqKi8KLyoKZGVmaW5lIGZ1bmN0aW9uIEhhc0NvbmQoaWRsaXN0IExpc3Q8U3lzdGVtLkNvZGU+KToKICBhc3Nlc0NvbmRpdGlvbihHZXRDb25kaXRpb24oaWRsaXN0KSkKCgozNTE4R2V0Q29uZGl0aW9uKGlkKSkKKi8KZGVmaW5lIGZ1bmN0aW9uIEhhc0NvbmQoaWQgU3lzdGVtLlN0cmluZywgY29kZXN5c3RlbSBTeXN0ZW0uU3RyaW5nKToKICBhc3Nlc0NvbmRpdGlvbihHZXRDb25kaXRpb24oY29kaW5nKGlkLCBjb2Rlc3lzdGVtKSkpCgpkZWZpbmUgZnVuY3Rpb24gSGFzQ29uZChpZCBTeXN0ZW0uU3RyaW5nKToKICBhc3Nlc0NvbmRpdGlvbihHZXRDb25kaXRpb24oY29kaW5nKGlkKSkpCgpkZWZpbmUgZnVuY3Rpb24gSGFzQ29uZChpZCBTeXN0ZW0uQ29kZSk6CiAgYXNzZXNDb25kaXRpb24oR2V0Q29uZGl0aW9uKGlkKSkKCi8vICoqKioqKioqKioqKioqKioqKioqKioqKiAgIFBhdGllbnRIYXNIaXN0b3J5T2ZDb25kaXRpb24gKioqKioqKioqKioqKioqKioqKioqKioqLwovKgpkZWZpbmUgZnVuY3Rpb24gR2V0SGlzdG9yaWNDb25kaXRpb24oaWRsaXN0IExpc3Q8U3lzdGVtLkNvZGU+LCAgbmJkYXlzIEludGVnZXIpOgogICAgICBMYXN0KFtDb25kaXRpb246IGlkbGlzdF0gTwogICAgICAgIHdoZXJlICAoZGlmZmVyZW5jZSBpbiBkYXlzIGJldHdlZW4gTy5yZWNvcmRlZERhdGUgYW5kIFRvZGF5KCkpIDwgbmJkYXlzCiAgICAgICAgYW5kIGV4aXN0cyhPLnZlcmlmaWNhdGlvblN0YXR1cy5jb2RpbmcgQyB3aGVyZSBDLmNvZGUgaW4geyd1bmNvbmZpcm1lZCcsICdwcm92aXNpb25hbCcsICdkaWZmZXJlbnRpYWwnLCAnY29uZmlybWVkJ30gCiAgICAgICAgYW5kIEMuc3lzdGVtID0gJ2h0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLXZlci1zdGF0dXMnKSkKKi8KCmRlZmluZSBmdW5jdGlvbiBHZXRIaXN0b3JpY0NvbmRpdGlvbihpZCBTeXN0ZW0uQ29kZSwgIG5iZGF5cyBJbnRlZ2VyKToKICAgICAgRmlyc3QoW0NvbmRpdGlvbjogaWRdIE8KICAgICAgICB3aGVyZSAgKGRpZmZlcmVuY2UgaW4gZGF5cyBiZXR3ZWVuIE8ucmVjb3JkZWREYXRlIGFuZCBUb2RheSgpKSA8IG5iZGF5cwogICAgICAgIGFuZCBleGlzdHMoTy52ZXJpZmljYXRpb25TdGF0dXMuY29kaW5nIEMgd2hlcmUgQy5jb2RlIGluIHsndW5jb25maXJtZWQnLCAncHJvdmlzaW9uYWwnLCAnZGlmZmVyZW50aWFsJywgJ2NvbmZpcm1lZCd9IAogICAgICAgIGFuZCBDLnN5c3RlbSA9ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2NvbmRpdGlvbi12ZXItc3RhdHVzJykgCiAgICAgICAgc29ydCBieSByZWNvcmRlZERhdGUgZGVzYykKCgoKCi8qCmRlZmluZSBmdW5jdGlvbiBIYXNDb25kSGlzdG9yeShpZGxpc3QgTGlzdDxTeXN0ZW0uQ29kZT4sICBuYmRheXMgSW50ZWdlcik6CiAgYXNzZXNDb25kaXRpb24oR2V0SGlzdG9yaWNDb25kaXRpb24oaWRsaXN0LCAgbmJkYXlzKSkKCgpkZWZpbmUgZnVuY3Rpb24gSGFzQ29uZEhpc3RvcnkoaWQgU3lzdGVtLkNvZGUsICBuYmRheXMgSW50ZWdlcik6CiAgYXNzZXNDb25kaXRpb24oR2V0SGlzdG9yaWNDb25kaXRpb24oe2lkfSwgbmJkYXlzKSkKKi8KZGVmaW5lIGZ1bmN0aW9uIEhhc0NvbmRIaXN0b3J5KGlkIFN5c3RlbS5Db2RlLCBuYmRheXMgSW50ZWdlcik6CiAgYXNzZXNDb25kaXRpb24oR2V0SGlzdG9yaWNDb25kaXRpb24oaWQsICBuYmRheXMpKQoKZGVmaW5lIGZ1bmN0aW9uIEhhc0NvbmRIaXN0b3J5KGlkIFN5c3RlbS5TdHJpbmcsIGNvZGVzeXN0ZW0gU3lzdGVtLlN0cmluZywgbmJkYXlzIEludGVnZXIpOgogIGFzc2VzQ29uZGl0aW9uKEdldEhpc3RvcmljQ29uZGl0aW9uKGNvZGluZyhpZCxjb2Rlc3lzdGVtKSxuYmRheXMpKQoKCmRlZmluZSBmdW5jdGlvbiBIYXNDb25kSGlzdG9yeShpZCBTeXN0ZW0uU3RyaW5nLCBuYmRheXMgSW50ZWdlcik6CiAgYXNzZXNDb25kaXRpb24oR2V0SGlzdG9yaWNDb25kaXRpb24oY29kaW5nKGlkKSwgIG5iZGF5cykpCgoKCi8vZGVmaW5lIGZ1bmN0aW9uIFBhdGllbnRIYXNDb25kaXRpb25EdXJpbmdFbmNvdW50ZXIoaWQgU3RyaW5nLCBjb2Rlc3lzdGVtIHVybCwgZHVyYXRpb24gSW50ZWdlcikpOgoKLy9kZWZpbmUgZnVuY3Rpb24gUGF0aWVudEhhc0NvbmRpdGlvbkZyb21WYWx1ZVNldER1cmluZ0VuY291bnRlcihpZCBTdHJpbmcsIGNvZGVzeXN0ZW0gdXJsLCBkdXJhdGlvbiBJbnRlZ2VyKSk6CgovL2RlZmluZSBmdW5jdGlvbiBQYXRpZW50SGFzSHNpc3RvcnlDb25kaXRpb24oaWQgU3RyaW5nLGNvZGVzeXN0ZW0gdXJsICwgZHVyYXRpb24gSW50ZWdlcik6Ci8vZGVmaW5lIGZ1bmN0aW9uIFBhdGllbnRIYXNIc2lzdG9yeUNvbmRpdGlvbkZyb21WYWx1ZVNldChpZCBTdHJpbmcsY29kZXN5c3RlbSB1cmwgLCBkdXJhdGlvbiBJbnRlZ2VyKToKCgovLyBQYXRpZW50SGFzU3ltcHRvbSgic3ltcHRvbSBuYW1lIik6IHN5bXB0b20gaW4gdGhlIGVuY291bnRlcgoKCi8vIFBhdGllbnRMYXN0TWVhc3VyZU9mKCJtZWFzdXJlIG5hbWUiKTogbWVhc3VyZSBpbiB0aGUgZW5jb3VudGVyCgovLyBQYXRpZW50TGFzdEhpc3RvcmljTWVhc3VyZU9mKCJtZWFzdXJlIG5hbWUiLCBkdXJhdGlvbik6IG1lYXN1cmUgaW4gdGhlIHBhdGllbnQgaGlzdG9yeSBkdXJpbmcgZHVyYXRpb24KCi8vIFBhdGllbnRIYXNEaWFnbm9zdGljKCJEaWFnbm9zdGljIG5hbWUiICk6IERpYWdub3N0aWMgaW4gdGhlIGVuY291bnRlcgoKLy8gUGF0aWVudEhhc0hpc3RvcnlPZkRpYWdub3N0aWMoIkRpYWdub3N0aWMgbmFtZSIsIGR1cmF0aW9uICk6IERpYWdub3N0aWMgaW4gdGhlIHBhdGllbnQgaGlzdG9yeSBkdXJpbmcgZHVyYXRpb24KCi8vIFBhdGllbnRIYXNQcm9wb3NlZG9yQ29uZmlybWVkRGlhbm9zdGljKCJEaWFnbm9zdGljIG5hbWUiICk6IERpYWdub3N0aWMgaW4gdGhlIGVuY291bnRlcgoKLy8gUGF0aWVudEhhc0hpc3RvcnlPZlByb3Bvc2Vkb3JDb25maXJtZWREaWFub3N0aWMoIkRpYWdub3N0aWMgbmFtZSIsIGR1cmF0aW9uICk6IERpYWdub3N0aWMgaW4gdGhlIHBhdGllbnQgaGlzdG9yeSBkdXJpbmcgZHVyYXRpb24KCi8vIFBhdGllbnRaU2NvcmVXZkEod2llZ2h0LCBhZ2UpCgovLyBQYXRpZW50V2VpZ2h0RnJvbVdmQShhZ2UsIE11YWMpCg=="
    }
  ]
}