CMS FHIR Prototype Measure Calculation Tool IG
0.1.0 - CI Build United States of America flag

CMS FHIR Prototype Measure Calculation Tool IG, published by HL7 International - [Some] Work Group. This guide is not an authorized publication; it is the continuous build for version 0.1.0 built by the FHIR (HL7® FHIR® Standard) CI Build. This version is based on the current content of https://github.com/cqframework/mct-ig/ and changes regularly. See the Directory of published versions

: QiCore Common - TTL Representation

Draft as of 2026-02-27

Raw ttl | Download

@prefix fhir: <http://hl7.org/fhir/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

# - resource -------------------------------------------------------------------

 a fhir:Library ;
  fhir:nodeRole fhir:treeRoot ;
  fhir:id [ fhir:v "QICoreCommon"] ; # 
  fhir:text [
fhir:status [ fhir:v "extensions" ] ;
fhir:div [ fhir:v "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n    <table class=\"grid dict\">\n        \n        <tr>\n            <th scope=\"row\"><b>Id: </b></th>\n            <td style=\"padding-left: 4px;\">QICoreCommon</td>\n        </tr>\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Url: </b></th>\n            <td style=\"padding-left: 4px;\"><a href=\"Library-QICoreCommon.html\">QiCore Common</a></td>\n        </tr>\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Version: </b></th>\n            <td style=\"padding-left: 4px;\">0.1.0</td>\n        </tr>\n        \n        \n        \n        <tr>\n            <th scope=\"row\"><b>Name: </b></th>\n            <td style=\"padding-left: 4px;\">QICoreCommon</td>\n        </tr>\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Title: </b></th>\n            <td style=\"padding-left: 4px;\">QiCore Common</td>\n        </tr>\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>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/7.0.1/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        <tr>\n            <th scope=\"row\"><b>Date: </b></th>\n            <td style=\"padding-left: 4px;\">2026-02-27 18:11:00+0000</td>\n        </tr>\n        \n        \n        <tr>\n            <th scope=\"row\"><b>Publisher: </b></th>\n            <td style=\"padding-left: 4px;\">HL7 International - [Some] Work Group</td>\n        </tr>\n        \n        \n        \n        \n        \n        \n        <tr>\n            <th scope=\"row\"><b>Jurisdiction: </b></th>\n            <td style=\"padding-left: 4px;\">US</td>\n        </tr>\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\">/*#xD;\n@author: Stan Rankins#xD;\n@description: Common terminologies and functions used in QI-Core-based CQL artifacts#xD;\n@update: Fashioned after FHIRCommon Version 4.0.012 for use in ecqm-content-qicore-2022 repos#xD;\n*/#xD;\nlibrary QICoreCommon version '1.0.000'#xD;\n#xD;\nusing QICore version '4.1.1'#xD;\n#xD;\ninclude FHIRHelpers version '4.0.013'#xD;\n#xD;\ncodesystem &amp;quot;LOINC&amp;quot;: 'http://loinc.org'#xD;\ncodesystem &amp;quot;SNOMEDCT&amp;quot;: 'http://snomed.info/sct'#xD;\ncodesystem &amp;quot;ICD10CM&amp;quot;: 'http://hl7.org/fhir/sid/icd-10-cm'#xD;\ncodesystem &amp;quot;RoleCode&amp;quot;: 'http://terminology.hl7.org/CodeSystem/v3-RoleCode'#xD;\ncodesystem &amp;quot;Diagnosis Role&amp;quot;: 'http://terminology.hl7.org/CodeSystem/diagnosis-role'#xD;\ncodesystem &amp;quot;RequestIntent&amp;quot;: 'http://terminology.hl7.org/CodeSystem/request-intent'#xD;\ncodesystem &amp;quot;MedicationRequestCategory&amp;quot;: 'http://terminology.hl7.org/CodeSystem/medicationrequest-category'#xD;\ncodesystem &amp;quot;ConditionClinicalStatusCodes&amp;quot;: 'http://terminology.hl7.org/CodeSystem/condition-clinical'#xD;\ncodesystem &amp;quot;ConditionVerificationStatusCodes&amp;quot;: 'http://terminology.hl7.org/CodeSystem/condition-ver-status'#xD;\ncodesystem &amp;quot;AllergyIntoleranceClinicalStatusCodes&amp;quot;: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical'#xD;\ncodesystem &amp;quot;AllergyIntoleranceVerificationStatusCodes&amp;quot;: 'http://terminology.hl7.org/CodeSystem/allergyintolerance-verification'#xD;\ncodesystem &amp;quot;ConditionCategoryCodes&amp;quot;: 'http://terminology.hl7.org/CodeSystem/condition-category'#xD;\ncodesystem &amp;quot;ObservationCategoryCodes&amp;quot;: 'http://terminology.hl7.org/CodeSystem/observation-category'#xD;\n#xD;\nvalueset &amp;quot;Active Condition&amp;quot;: 'http://fhir.org/guides/cqf/common/ValueSet/active-condition'#xD;\nvalueset &amp;quot;Inactive Condition&amp;quot;: 'http://fhir.org/guides/cqf/common/ValueSet/inactive-condition'#xD;\n#xD;\ncode &amp;quot;Birthdate&amp;quot;: '21112-8' from &amp;quot;LOINC&amp;quot; display 'Birth date'#xD;\ncode &amp;quot;Dead&amp;quot;: '419099009' from &amp;quot;SNOMEDCT&amp;quot; display 'Dead'#xD;\ncode &amp;quot;ER&amp;quot;: 'ER' from &amp;quot;RoleCode&amp;quot; display 'Emergency room'#xD;\ncode &amp;quot;ICU&amp;quot;: 'ICU' from &amp;quot;RoleCode&amp;quot; display 'Intensive care unit'#xD;\ncode &amp;quot;Billing&amp;quot;: 'billing' from &amp;quot;Diagnosis Role&amp;quot; display 'Billing'#xD;\n#xD;\n// Condition Clinical Status Codes - Consider value sets for these#xD;\ncode &amp;quot;active&amp;quot;: 'active' from &amp;quot;ConditionClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;recurrence&amp;quot;: 'recurrence' from &amp;quot;ConditionClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;relapse&amp;quot;: 'relapse' from &amp;quot;ConditionClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;inactive&amp;quot;: 'inactive' from &amp;quot;ConditionClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;remission&amp;quot;: 'remission' from &amp;quot;ConditionClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;resolved&amp;quot;: 'resolved' from &amp;quot;ConditionClinicalStatusCodes&amp;quot;#xD;\n#xD;\n// Condition Verification Status Codes - Consider value sets for these#xD;\ncode &amp;quot;unconfirmed&amp;quot;: 'unconfirmed' from ConditionVerificationStatusCodes#xD;\ncode &amp;quot;provisional&amp;quot;: 'provisional' from ConditionVerificationStatusCodes#xD;\ncode &amp;quot;differential&amp;quot;: 'differential' from ConditionVerificationStatusCodes#xD;\ncode &amp;quot;confirmed&amp;quot;: 'confirmed' from ConditionVerificationStatusCodes#xD;\ncode &amp;quot;refuted&amp;quot;: 'refuted' from ConditionVerificationStatusCodes#xD;\ncode &amp;quot;entered-in-error&amp;quot;: 'entered-in-error' from ConditionVerificationStatusCodes#xD;\n#xD;\ncode &amp;quot;allergy-active&amp;quot;: 'active' from &amp;quot;AllergyIntoleranceClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;allergy-inactive&amp;quot;: 'inactive' from &amp;quot;AllergyIntoleranceClinicalStatusCodes&amp;quot;#xD;\ncode &amp;quot;allergy-resolved&amp;quot;: 'resolved' from &amp;quot;AllergyIntoleranceClinicalStatusCodes&amp;quot;#xD;\n#xD;\n// Allergy/Intolerance Verification Status Codes - Consider value sets for these#xD;\ncode &amp;quot;allergy-unconfirmed&amp;quot;: 'unconfirmed' from AllergyIntoleranceVerificationStatusCodes#xD;\ncode &amp;quot;allergy-confirmed&amp;quot;: 'confirmed' from AllergyIntoleranceVerificationStatusCodes#xD;\ncode &amp;quot;allergy-refuted&amp;quot;: 'refuted' from AllergyIntoleranceVerificationStatusCodes#xD;\n#xD;\n// MedicationRequest Category Codes#xD;\ncode &amp;quot;Community&amp;quot;: 'community' from &amp;quot;MedicationRequestCategory&amp;quot; display 'Community'#xD;\ncode &amp;quot;Discharge&amp;quot;: 'discharge' from &amp;quot;MedicationRequestCategory&amp;quot; display 'Discharge'#xD;\n#xD;\n// Diagnosis Role Codes#xD;\ncode &amp;quot;AD&amp;quot;: 'AD' from &amp;quot;Diagnosis Role&amp;quot; display 'Admission diagnosis'#xD;\ncode &amp;quot;DD&amp;quot;: 'DD' from &amp;quot;Diagnosis Role&amp;quot; display 'Discharge diagnosis'#xD;\ncode &amp;quot;CC&amp;quot;: 'CC' from &amp;quot;Diagnosis Role&amp;quot; display 'Chief complaint'#xD;\ncode &amp;quot;CM&amp;quot;: 'CM' from &amp;quot;Diagnosis Role&amp;quot; display 'Comorbidity diagnosis'#xD;\ncode &amp;quot;pre-op&amp;quot;: 'pre-op' from &amp;quot;Diagnosis Role&amp;quot; display 'pre-op diagnosis'#xD;\ncode &amp;quot;post-op&amp;quot;: 'post-op' from &amp;quot;Diagnosis Role&amp;quot; display 'post-op diagnosis'#xD;\ncode &amp;quot;billing&amp;quot;: 'billing' from &amp;quot;Diagnosis Role&amp;quot; display 'billing diagnosis'#xD;\n#xD;\n// Observation Category Codes#xD;\ncode &amp;quot;social-history&amp;quot;: 'social-history' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Social History'#xD;\ncode &amp;quot;vital-signs&amp;quot;: 'vital-signs' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Vital Signs'#xD;\ncode &amp;quot;imaging&amp;quot;: 'imaging' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Imaging'#xD;\ncode &amp;quot;laboratory&amp;quot;: 'laboratory' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Laboratory'#xD;\ncode &amp;quot;procedure&amp;quot;: 'procedure' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Procedure'#xD;\ncode &amp;quot;survey&amp;quot;: 'survey' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Survey'#xD;\ncode &amp;quot;exam&amp;quot;: 'exam' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Exam'#xD;\ncode &amp;quot;therapy&amp;quot;: 'therapy' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Therapy'#xD;\ncode &amp;quot;activity&amp;quot;: 'activity' from &amp;quot;ObservationCategoryCodes&amp;quot; display 'Activity'#xD;\n#xD;\n// Condition Category Codes#xD;\ncode &amp;quot;problem-list-item&amp;quot;: 'problem-list-item' from &amp;quot;ConditionCategoryCodes&amp;quot; display 'Problem List Item'#xD;\ncode &amp;quot;encounter-diagnosis&amp;quot;: 'encounter-diagnosis' from &amp;quot;ConditionCategoryCodes&amp;quot; display 'Encounter Diagnosis'#xD;\n#xD;\ncontext Patient#xD;\n#xD;\n/*#xD;\n@description: Normalizes a value that is a choice of timing-valued types to an equivalent interval#xD;\n@comment: Normalizes a choice type of DateTime, Quanitty, Interval&amp;lt;DateTime&amp;gt;, or Interval&amp;lt;Quantity&amp;gt; types#xD;\nto an equivalent interval. This selection of choice types is a superset of the majority of choice types that are used as possible#xD;\nrepresentations for timing-valued elements in QICore, allowing this function to be used across any resource.#xD;\n#xD;\nThe input can be provided as a DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt; or Interval&amp;lt;Quantity&amp;gt;.#xD;\nThe intent of this function is to provide a clear and concise mechanism to treat single#xD;\nelements that have multiple possible representations as intervals so that logic doesn't have to account#xD;\nfor the variability. More complex calculations (such as medication request period or dispense period#xD;\ncalculation) need specific guidance and consideration. That guidance may make use of this function, but#xD;\nthe focus of this function is on single element calculations where the semantics are unambiguous.#xD;\nIf the input is a DateTime, the result a DateTime Interval beginning and ending on that DateTime.#xD;\nIf the input is a Quantity, the quantity is expected to be a calendar-duration interpreted as an Age, #xD;\nand the result is a DateTime Interval beginning on the Date the patient turned that age and ending immediately before one year later.#xD;\nIf the input is a DateTime Interval, the result is the input.#xD;\nIf the input is a Quantity Interval, the quantities are expected to be calendar-durations interpreted as an Age, and the result#xD;\nis a DateTime Interval beginning on the date the patient turned the age given as the start of the quantity interval, and ending #xD;\nimmediately before one year later than the date the patient turned the age given as the end of the quantity interval.#xD;\nAny other input will reslt in a null DateTime Interval#xD;\n*/#xD;\ndefine function ToInterval(choice Choice&amp;lt;DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt;, Interval&amp;lt;Quantity&amp;gt;&amp;gt;):#xD;\n  case#xD;\n	  when choice is DateTime then#xD;\n    	Interval[choice as DateTime, choice as DateTime]#xD;\n		when choice is Interval&amp;lt;DateTime&amp;gt; then#xD;\n  		choice as Interval&amp;lt;DateTime&amp;gt;#xD;\n		when choice is Quantity then#xD;\n		  Interval[Patient.birthDate + (choice as Quantity),#xD;\n			  Patient.birthDate + (choice as Quantity) + 1 year)#xD;\n		when choice is Interval&amp;lt;Quantity&amp;gt; then#xD;\n		  Interval[Patient.birthDate + (choice.low as Quantity),#xD;\n			  Patient.birthDate + (choice.high as Quantity) + 1 year)#xD;\n		else#xD;\n			null as Interval&amp;lt;DateTime&amp;gt;#xD;\n	end#xD;\n#xD;\n/*#xD;\n@description: Normalizes a value that is a choice of timing-valued types to an equivalent interval#xD;\n@comment: Normalizes a choice type of DateTime, Quanitty, Interval&amp;lt;DateTime&amp;gt;, or Interval&amp;lt;Quantity&amp;gt; types#xD;\nto an equivalent interval. This selection of choice types is a superset of the majority of choice types that are used as possible#xD;\nrepresentations for timing-valued elements in QICore, allowing this function to be used across any resource.#xD;\n#xD;\nThe input can be provided as a DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt; or Interval&amp;lt;Quantity&amp;gt;.#xD;\nThe intent of this function is to provide a clear and concise mechanism to treat single#xD;\nelements that have multiple possible representations as intervals so that logic doesn't have to account#xD;\nfor the variability. More complex calculations (such as medication request period or dispense period#xD;\ncalculation) need specific guidance and consideration. That guidance may make use of this function, but#xD;\nthe focus of this function is on single element calculations where the semantics are unambiguous.#xD;\nIf the input is a DateTime, the result a DateTime Interval beginning and ending on that DateTime.#xD;\nIf the input is a Quantity, the quantity is expected to be a calendar-duration interpreted as an Age, #xD;\nand the result is a DateTime Interval beginning on the Date the patient turned that age and ending immediately before one year later.#xD;\nIf the input is a DateTime Interval, the result is the input.#xD;\nIf the input is a Quantity Interval, the quantities are expected to be calendar-durations interpreted as an Age, and the result#xD;\nis a DateTime Interval beginning on the date the patient turned the age given as the start of the quantity interval, and ending #xD;\nimmediately before one year later than the date the patient turned the age given as the end of the quantity interval.#xD;\nAny other input will reslt in a null DateTime Interval#xD;\n*/#xD;\ndefine fluent function toInterval(choice Choice&amp;lt;DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt;, Interval&amp;lt;Quantity&amp;gt;&amp;gt;):#xD;\n  case#xD;\n	  when choice is DateTime then#xD;\n    	Interval[choice as DateTime, choice as DateTime]#xD;\n		when choice is Interval&amp;lt;DateTime&amp;gt; then#xD;\n  		choice as Interval&amp;lt;DateTime&amp;gt;#xD;\n		when choice is Quantity then#xD;\n		  Interval[Patient.birthDate + (choice as Quantity),#xD;\n			  Patient.birthDate + (choice as Quantity) + 1 year)#xD;\n		when choice is Interval&amp;lt;Quantity&amp;gt; then#xD;\n		  Interval[Patient.birthDate + (choice.low as Quantity),#xD;\n			  Patient.birthDate + (choice.high as Quantity) + 1 year)#xD;\n		else#xD;\n			null as Interval&amp;lt;DateTime&amp;gt;#xD;\n	end#xD;\n#xD;\n/*#xD;\n@description: Returns an interval representing the normalized abatement of a given Condition.#xD;\n@comment: If the abatement element of the Condition is represented as a DateTime, the result#xD;\nis an interval beginning and ending on that DateTime.#xD;\nIf the abatement is represented as a Quantity, the quantity is expected to be a calendar-duration and is interpreted as the age of the patient. The#xD;\nresult is an interval from the date the patient turned that age to immediately before one year later.#xD;\nIf the abatement is represented as a Quantity Interval, the quantities are expected to be calendar-durations and are interpreted as an age range during#xD;\nwhich the abatement occurred. The result is an interval from the date the patient turned the starting age of the quantity interval, and ending immediately#xD;\nbefore one year later than the date the patient turned the ending age of the quantity interval.#xD;\n*/#xD;\ndefine function ToAbatementInterval(condition Condition):#xD;\n	if condition.abatement is DateTime then#xD;\n	  Interval[condition.abatement as DateTime, condition.abatement as DateTime]#xD;\n	else if condition.abatement is Quantity then#xD;\n		Interval[Patient.birthDate + (condition.abatement as Quantity),#xD;\n			Patient.birthDate + (condition.abatement as Quantity) + 1 year)#xD;\n	else if condition.abatement is Interval&amp;lt;Quantity&amp;gt; then#xD;\n	  Interval[Patient.birthDate + (condition.abatement.low as Quantity),#xD;\n		  Patient.birthDate + (condition.abatement.high as Quantity) + 1 year)#xD;\n	else if condition.abatement is Interval&amp;lt;DateTime&amp;gt; then#xD;\n	  Interval[condition.abatement.low, condition.abatement.high)#xD;\n	else null as Interval&amp;lt;DateTime&amp;gt;#xD;\n#xD;\n/*#xD;\n@description: Returns an interval representing the normalized abatement of a given Condition.#xD;\n@comment: If the abatement element of the Condition is represented as a DateTime, the result#xD;\nis an interval beginning and ending on that DateTime.#xD;\nIf the abatement is represented as a Quantity, the quantity is expected to be a calendar-duration and is interpreted as the age of the patient. The#xD;\nresult is an interval from the date the patient turned that age to immediately before one year later.#xD;\nIf the abatement is represented as a Quantity Interval, the quantities are expected to be calendar-durations and are interpreted as an age range during#xD;\nwhich the abatement occurred. The result is an interval from the date the patient turned the starting age of the quantity interval, and ending immediately#xD;\nbefore one year later than the date the patient turned the ending age of the quantity interval.#xD;\n*/#xD;\ndefine fluent function toAbatementInterval(condition Condition):#xD;\n	if condition.abatement is DateTime then#xD;\n	  Interval[condition.abatement as DateTime, condition.abatement as DateTime]#xD;\n	else if condition.abatement is Quantity then#xD;\n		Interval[Patient.birthDate + (condition.abatement as Quantity),#xD;\n			Patient.birthDate + (condition.abatement as Quantity) + 1 year)#xD;\n	else if condition.abatement is Interval&amp;lt;Quantity&amp;gt; then#xD;\n	  Interval[Patient.birthDate + (condition.abatement.low as Quantity),#xD;\n		  Patient.birthDate + (condition.abatement.high as Quantity) + 1 year)#xD;\n	else if condition.abatement is Interval&amp;lt;DateTime&amp;gt; then#xD;\n	  Interval[condition.abatement.low, condition.abatement.high)#xD;\n	else null as Interval&amp;lt;DateTime&amp;gt;#xD;\n#xD;\n/*#xD;\n@description: Returns an interval representing the normalized prevalence period of a given Condition.#xD;\n@comment: Uses the ToInterval and ToAbatementInterval functions to determine the widest potential interval from#xD;\nonset to abatement as specified in the given Condition. If the condition is active, the resulting interval will have#xD;\na closed ending boundary. If the condition is not active, the resulting interval will have an open ending boundary.#xD;\n*/#xD;\ndefine function ToPrevalenceInterval(condition Condition):#xD;\nif condition.clinicalStatus ~ &amp;quot;active&amp;quot;#xD;\n  or condition.clinicalStatus ~ &amp;quot;recurrence&amp;quot;#xD;\n  or condition.clinicalStatus ~ &amp;quot;relapse&amp;quot; then#xD;\n  Interval[start of ToInterval(condition.onset), end of ToAbatementInterval(condition)]#xD;\nelse#xD;\n  Interval[start of ToInterval(condition.onset), end of ToAbatementInterval(condition))#xD;\n#xD;\n/*#xD;\n@description: Returns an interval representing the normalized prevalence period of a given Condition.#xD;\n@comment: Uses the ToInterval and ToAbatementInterval functions to determine the widest potential interval from#xD;\nonset to abatement as specified in the given Condition. If the condition is active, the resulting interval will have#xD;\na closed ending boundary. If the condition is not active, the resulting interval will have an open ending boundary.#xD;\n*/#xD;\ndefine fluent function toPrevalenceInterval(condition Condition):#xD;\nif condition.clinicalStatus ~ &amp;quot;active&amp;quot;#xD;\n  or condition.clinicalStatus ~ &amp;quot;recurrence&amp;quot;#xD;\n  or condition.clinicalStatus ~ &amp;quot;relapse&amp;quot; then#xD;\n  Interval[start of ToInterval(condition.onset), end of ToAbatementInterval(condition)]#xD;\nelse#xD;\n  Interval[start of ToInterval(condition.onset), end of ToAbatementInterval(condition))#xD;\n#xD;\n/*#xD;\n@description: Returns the tail of the given uri (i.e. everything after the last slash in the URI).#xD;\n@comment: This function can be used to determine the logical id of a given resource. It can be used in#xD;\na single-server environment to trace references. However, this function does not attempt to resolve#xD;\nor distinguish the base of the given url, and so cannot be used safely in multi-server environments.#xD;\n*/#xD;\ndefine function GetId(uri String ):#xD;\n  Last(Split(uri, '/'))#xD;\n#xD;\n/*#xD;\n@description: Returns the tail of the given uri (i.e. everything after the last slash in the URI).#xD;\n@comment: This function can be used to determine the logical id of a given resource. It can be used in#xD;\na single-server environment to trace references. However, this function does not attempt to resolve#xD;\nor distinguish the base of the given url, and so cannot be used safely in multi-server environments.#xD;\n*/#xD;\ndefine fluent function getId(uri String):#xD;\n  Last(Split(uri, '/'))#xD;\n#xD;\n/*#xD;\n@description: Given an interval, return true if the interval has a starting boundary specified #xD;\n(i.e. the start of the interval is not null and not the minimum DateTime value)#xD;\n*/#xD;\ndefine function &amp;quot;HasStart&amp;quot;(period Interval&amp;lt;DateTime&amp;gt; ):#xD;\n  not ( start of period is null#xD;\n      or start of period = minimum DateTime#xD;\n  )#xD;\n#xD;\n/*#xD;\n@description: Given an interval, return true if the interval has a starting boundary specified #xD;\n(i.e. the start of the interval is not null and not the minimum DateTime value)#xD;\n*/#xD;\ndefine fluent function hasStart(period Interval&amp;lt;DateTime&amp;gt; ):#xD;\n  not ( start of period is null#xD;\n      or start of period = minimum DateTime#xD;\n  )#xD;\n#xD;\n/*#xD;\n@description: Given an interval, returns true if the interval has an ending boundary specified #xD;\n(i.e. the end of the interval is not null and not the maximum DateTime value)#xD;\n*/#xD;\ndefine function &amp;quot;HasEnd&amp;quot;(period Interval&amp;lt;DateTime&amp;gt; ):#xD;\n  not (#xD;\n    end of period is null#xD;\n      or end of period = maximum DateTime#xD;\n  )#xD;\n#xD;\n/*#xD;\n@description: Given an interval, returns true if the interval has an ending boundary specified #xD;\n(i.e. the end of the interval is not null and not the maximum DateTime value)#xD;\n*/#xD;\ndefine fluent function hasEnd(period Interval&amp;lt;DateTime&amp;gt; ):#xD;\n  not (#xD;\n    end of period is null#xD;\n      or end of period = maximum DateTime#xD;\n  )#xD;\n#xD;\n/*#xD;\n@description: Given an interval, returns the ending point if the interval has an ending boundary specified, #xD;\notherwise, returns the starting point#xD;\n*/#xD;\ndefine function &amp;quot;Latest&amp;quot;(choice Choice&amp;lt;DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt;, Interval&amp;lt;Quantity&amp;gt;&amp;gt; ):#xD;\n  (choice.toInterval()) period#xD;\n    return#xD;\n      if (HasEnd(period)) then end of period#xD;\n      else start of period#xD;\n#xD;\n/*#xD;\n@description: Given an interval, returns the ending point if the interval has an ending boundary specified, #xD;\notherwise, returns the starting point#xD;\n*/#xD;\ndefine fluent function latest(choice Choice&amp;lt;DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt;, Interval&amp;lt;Quantity&amp;gt;&amp;gt; ):#xD;\n  (choice.toInterval()) period#xD;\n    return#xD;\n      if (HasEnd(period)) then end of period#xD;\n      else start of period#xD;\n#xD;\n/*#xD;\n@description: Given an interval, return the starting point if the interval has a starting boundary specified, #xD;\notherwise, return the ending point#xD;\n*/#xD;\ndefine function &amp;quot;Earliest&amp;quot;(choice Choice&amp;lt;DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt;, Interval&amp;lt;Quantity&amp;gt;&amp;gt; ):#xD;\n  (choice.toInterval()) period#xD;\n    return#xD;\n      if (HasStart(period)) then start of period#xD;\n      else end of period#xD;\n#xD;\n/*#xD;\n@description: Given an interval, return the starting point if the interval has a starting boundary specified, #xD;\notherwise, return the ending point#xD;\n*/#xD;\ndefine fluent function earliest(choice Choice&amp;lt;DateTime, Quantity, Interval&amp;lt;DateTime&amp;gt;, Interval&amp;lt;Quantity&amp;gt;&amp;gt; ):#xD;\n  (choice.toInterval()) period#xD;\n    return#xD;\n      if (HasStart(period)) then start of period#xD;\n      else end of period#xD;\n#xD;\n/*#xD;\n@description: Creates a list of integers from 1 to how many days are in the interval. Note, this wont create an index for#xD;\nthe final day if it is less than 24 hours. This also includes the first 24 hour period.#xD;\n*/#xD;\ndefine function &amp;quot;Interval To Day Numbers&amp;quot;(Period Interval&amp;lt;DateTime&amp;gt;):#xD;\n  ( expand { Interval[1, duration in days between start of Period and end of Period]} ) DayNumber#xD;\n    return end of DayNumber#xD;\n#xD;\n/*#xD;\n@description: Creates a list of integers from 1 to how many days are in the interval. Note, this wont create an index for#xD;\nthe final day if it is less than 24 hours. This also includes the first 24 hour period.#xD;\n*/#xD;\ndefine fluent function toDayNumbers(Period Interval&amp;lt;DateTime&amp;gt;):#xD;\n  ( expand { Interval[1, duration in days between start of Period and end of Period]} ) DayNumber#xD;\n    return end of DayNumber#xD;\n#xD;\n/*#xD;\n@description: Creates a list of 24 hour long intervals in an interval paired with the index (1 indexed) to which 24 hour interval it is.#xD;\nNote that the result will include intervals that are closed at the beginning and open at the end#xD;\n*/#xD;\ndefine function &amp;quot;Days In Period&amp;quot;(Period Interval&amp;lt;DateTime&amp;gt;):#xD;\n  ( &amp;quot;Interval To Day Numbers&amp;quot;(Period)) DayIndex#xD;\n    let startPeriod: start of Period + (24 hours * (DayIndex - 1)),#xD;\n    endPeriod: if (hours between startPeriod and end of Period &amp;lt; 24) then startPeriod#xD;\n      else start of Period + (24 hours * DayIndex)#xD;\n    return Tuple {#xD;\n      dayIndex: DayIndex,#xD;\n      dayPeriod: Interval[startPeriod, endPeriod)#xD;\n    }#xD;\n#xD;\n/*#xD;\n@description: Creates a list of 24 hour long intervals in an interval paired with the index (1 indexed) to which 24 hour interval it is.#xD;\nNote that the result will include intervals that are closed at the beginning and open at the end#xD;\n*/#xD;\ndefine fluent function daysInPeriod(Period Interval&amp;lt;DateTime&amp;gt;):#xD;\n  ( &amp;quot;Interval To Day Numbers&amp;quot;(Period)) DayIndex#xD;\n    let startPeriod: start of Period + (24 hours * (DayIndex - 1)),#xD;\n    endPeriod: if (hours between startPeriod and end of Period &amp;lt; 24) then startPeriod#xD;\n      else start of Period + (24 hours * DayIndex)#xD;\n    return Tuple {#xD;\n      dayIndex: DayIndex,#xD;\n      dayPeriod: Interval[startPeriod, endPeriod)#xD;\n    }</code></pre></td></tr>\n            </table>\n          </td>\n        </tr>\n        \n        \n        \n    </table>\n</div>"^^rdf:XMLLiteral ]
  ] ; # 
  fhir:extension ( [
fhir:url [
fhir:v "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-softwaresystem"^^xsd:anyURI ;
fhir:l <http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-softwaresystem>     ] ;
fhir:value [
a fhir:Reference ;
fhir:l fhir:Device/cqf-tooling ;
fhir:reference [ fhir:v "Device/cqf-tooling" ]     ]
  ] ) ; # 
  fhir:url [
fhir:v "http://cms.gov/fhir/mct/Library/QICoreCommon"^^xsd:anyURI ;
fhir:l <http://cms.gov/fhir/mct/Library/QICoreCommon>
  ] ; # 
  fhir:version [ fhir:v "0.1.0"] ; # 
  fhir:name [ fhir:v "QICoreCommon"] ; # 
  fhir:title [ fhir:v "QiCore Common"] ; # 
  fhir:status [ fhir:v "draft"] ; # 
  fhir:type [
    ( fhir:coding [
fhir:system [
fhir:v "http://terminology.hl7.org/CodeSystem/library-type"^^xsd:anyURI ;
fhir:l <http://terminology.hl7.org/CodeSystem/library-type>       ] ;
fhir:code [ fhir:v "logic-library" ]     ] )
  ] ; # 
  fhir:date [ fhir:v "2026-02-27T18:11:00+00:00"^^xsd:dateTime] ; # 
  fhir:publisher [ fhir:v "HL7 International - [Some] Work Group"] ; # 
  fhir:contact ( [
    ( fhir:telecom [
fhir:system [ fhir:v "url" ] ;
fhir:value [ fhir:v "http://hl7.org/Special/committees/[something]" ]     ] )
  ] ) ; # 
  fhir:jurisdiction ( [
    ( fhir:coding [
fhir:system [
fhir:v "urn:iso:std:iso:3166"^^xsd:anyURI ;
fhir:l <urn:iso:std:iso:3166>       ] ;
fhir:code [ fhir:v "US" ]     ] )
  ] ) ; # 
  fhir:content ( [
fhir:contentType [ fhir:v "text/cql" ] ;
fhir:data [ fhir:v "LyoNCkBhdXRob3I6IFN0YW4gUmFua2lucw0KQGRlc2NyaXB0aW9uOiBDb21tb24gdGVybWlub2xvZ2llcyBhbmQgZnVuY3Rpb25zIHVzZWQgaW4gUUktQ29yZS1iYXNlZCBDUUwgYXJ0aWZhY3RzDQpAdXBkYXRlOiBGYXNoaW9uZWQgYWZ0ZXIgRkhJUkNvbW1vbiBWZXJzaW9uIDQuMC4wMTIgZm9yIHVzZSBpbiBlY3FtLWNvbnRlbnQtcWljb3JlLTIwMjIgcmVwb3MNCiovDQpsaWJyYXJ5IFFJQ29yZUNvbW1vbiB2ZXJzaW9uICcxLjAuMDAwJw0KDQp1c2luZyBRSUNvcmUgdmVyc2lvbiAnNC4xLjEnDQoNCmluY2x1ZGUgRkhJUkhlbHBlcnMgdmVyc2lvbiAnNC4wLjAxMycNCg0KY29kZXN5c3RlbSAiTE9JTkMiOiAnaHR0cDovL2xvaW5jLm9yZycNCmNvZGVzeXN0ZW0gIlNOT01FRENUIjogJ2h0dHA6Ly9zbm9tZWQuaW5mby9zY3QnDQpjb2Rlc3lzdGVtICJJQ0QxMENNIjogJ2h0dHA6Ly9obDcub3JnL2ZoaXIvc2lkL2ljZC0xMC1jbScNCmNvZGVzeXN0ZW0gIlJvbGVDb2RlIjogJ2h0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vdjMtUm9sZUNvZGUnDQpjb2Rlc3lzdGVtICJEaWFnbm9zaXMgUm9sZSI6ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2RpYWdub3Npcy1yb2xlJw0KY29kZXN5c3RlbSAiUmVxdWVzdEludGVudCI6ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL3JlcXVlc3QtaW50ZW50Jw0KY29kZXN5c3RlbSAiTWVkaWNhdGlvblJlcXVlc3RDYXRlZ29yeSI6ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL21lZGljYXRpb25yZXF1ZXN0LWNhdGVnb3J5Jw0KY29kZXN5c3RlbSAiQ29uZGl0aW9uQ2xpbmljYWxTdGF0dXNDb2RlcyI6ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2NvbmRpdGlvbi1jbGluaWNhbCcNCmNvZGVzeXN0ZW0gIkNvbmRpdGlvblZlcmlmaWNhdGlvblN0YXR1c0NvZGVzIjogJ2h0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLXZlci1zdGF0dXMnDQpjb2Rlc3lzdGVtICJBbGxlcmd5SW50b2xlcmFuY2VDbGluaWNhbFN0YXR1c0NvZGVzIjogJ2h0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vYWxsZXJneWludG9sZXJhbmNlLWNsaW5pY2FsJw0KY29kZXN5c3RlbSAiQWxsZXJneUludG9sZXJhbmNlVmVyaWZpY2F0aW9uU3RhdHVzQ29kZXMiOiAnaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9hbGxlcmd5aW50b2xlcmFuY2UtdmVyaWZpY2F0aW9uJw0KY29kZXN5c3RlbSAiQ29uZGl0aW9uQ2F0ZWdvcnlDb2RlcyI6ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL2NvbmRpdGlvbi1jYXRlZ29yeScNCmNvZGVzeXN0ZW0gIk9ic2VydmF0aW9uQ2F0ZWdvcnlDb2RlcyI6ICdodHRwOi8vdGVybWlub2xvZ3kuaGw3Lm9yZy9Db2RlU3lzdGVtL29ic2VydmF0aW9uLWNhdGVnb3J5Jw0KDQp2YWx1ZXNldCAiQWN0aXZlIENvbmRpdGlvbiI6ICdodHRwOi8vZmhpci5vcmcvZ3VpZGVzL2NxZi9jb21tb24vVmFsdWVTZXQvYWN0aXZlLWNvbmRpdGlvbicNCnZhbHVlc2V0ICJJbmFjdGl2ZSBDb25kaXRpb24iOiAnaHR0cDovL2ZoaXIub3JnL2d1aWRlcy9jcWYvY29tbW9uL1ZhbHVlU2V0L2luYWN0aXZlLWNvbmRpdGlvbicNCg0KY29kZSAiQmlydGhkYXRlIjogJzIxMTEyLTgnIGZyb20gIkxPSU5DIiBkaXNwbGF5ICdCaXJ0aCBkYXRlJw0KY29kZSAiRGVhZCI6ICc0MTkwOTkwMDknIGZyb20gIlNOT01FRENUIiBkaXNwbGF5ICdEZWFkJw0KY29kZSAiRVIiOiAnRVInIGZyb20gIlJvbGVDb2RlIiBkaXNwbGF5ICdFbWVyZ2VuY3kgcm9vbScNCmNvZGUgIklDVSI6ICdJQ1UnIGZyb20gIlJvbGVDb2RlIiBkaXNwbGF5ICdJbnRlbnNpdmUgY2FyZSB1bml0Jw0KY29kZSAiQmlsbGluZyI6ICdiaWxsaW5nJyBmcm9tICJEaWFnbm9zaXMgUm9sZSIgZGlzcGxheSAnQmlsbGluZycNCg0KLy8gQ29uZGl0aW9uIENsaW5pY2FsIFN0YXR1cyBDb2RlcyAtIENvbnNpZGVyIHZhbHVlIHNldHMgZm9yIHRoZXNlDQpjb2RlICJhY3RpdmUiOiAnYWN0aXZlJyBmcm9tICJDb25kaXRpb25DbGluaWNhbFN0YXR1c0NvZGVzIg0KY29kZSAicmVjdXJyZW5jZSI6ICdyZWN1cnJlbmNlJyBmcm9tICJDb25kaXRpb25DbGluaWNhbFN0YXR1c0NvZGVzIg0KY29kZSAicmVsYXBzZSI6ICdyZWxhcHNlJyBmcm9tICJDb25kaXRpb25DbGluaWNhbFN0YXR1c0NvZGVzIg0KY29kZSAiaW5hY3RpdmUiOiAnaW5hY3RpdmUnIGZyb20gIkNvbmRpdGlvbkNsaW5pY2FsU3RhdHVzQ29kZXMiDQpjb2RlICJyZW1pc3Npb24iOiAncmVtaXNzaW9uJyBmcm9tICJDb25kaXRpb25DbGluaWNhbFN0YXR1c0NvZGVzIg0KY29kZSAicmVzb2x2ZWQiOiAncmVzb2x2ZWQnIGZyb20gIkNvbmRpdGlvbkNsaW5pY2FsU3RhdHVzQ29kZXMiDQoNCi8vIENvbmRpdGlvbiBWZXJpZmljYXRpb24gU3RhdHVzIENvZGVzIC0gQ29uc2lkZXIgdmFsdWUgc2V0cyBmb3IgdGhlc2UNCmNvZGUgInVuY29uZmlybWVkIjogJ3VuY29uZmlybWVkJyBmcm9tIENvbmRpdGlvblZlcmlmaWNhdGlvblN0YXR1c0NvZGVzDQpjb2RlICJwcm92aXNpb25hbCI6ICdwcm92aXNpb25hbCcgZnJvbSBDb25kaXRpb25WZXJpZmljYXRpb25TdGF0dXNDb2Rlcw0KY29kZSAiZGlmZmVyZW50aWFsIjogJ2RpZmZlcmVudGlhbCcgZnJvbSBDb25kaXRpb25WZXJpZmljYXRpb25TdGF0dXNDb2Rlcw0KY29kZSAiY29uZmlybWVkIjogJ2NvbmZpcm1lZCcgZnJvbSBDb25kaXRpb25WZXJpZmljYXRpb25TdGF0dXNDb2Rlcw0KY29kZSAicmVmdXRlZCI6ICdyZWZ1dGVkJyBmcm9tIENvbmRpdGlvblZlcmlmaWNhdGlvblN0YXR1c0NvZGVzDQpjb2RlICJlbnRlcmVkLWluLWVycm9yIjogJ2VudGVyZWQtaW4tZXJyb3InIGZyb20gQ29uZGl0aW9uVmVyaWZpY2F0aW9uU3RhdHVzQ29kZXMNCg0KY29kZSAiYWxsZXJneS1hY3RpdmUiOiAnYWN0aXZlJyBmcm9tICJBbGxlcmd5SW50b2xlcmFuY2VDbGluaWNhbFN0YXR1c0NvZGVzIg0KY29kZSAiYWxsZXJneS1pbmFjdGl2ZSI6ICdpbmFjdGl2ZScgZnJvbSAiQWxsZXJneUludG9sZXJhbmNlQ2xpbmljYWxTdGF0dXNDb2RlcyINCmNvZGUgImFsbGVyZ3ktcmVzb2x2ZWQiOiAncmVzb2x2ZWQnIGZyb20gIkFsbGVyZ3lJbnRvbGVyYW5jZUNsaW5pY2FsU3RhdHVzQ29kZXMiDQoNCi8vIEFsbGVyZ3kvSW50b2xlcmFuY2UgVmVyaWZpY2F0aW9uIFN0YXR1cyBDb2RlcyAtIENvbnNpZGVyIHZhbHVlIHNldHMgZm9yIHRoZXNlDQpjb2RlICJhbGxlcmd5LXVuY29uZmlybWVkIjogJ3VuY29uZmlybWVkJyBmcm9tIEFsbGVyZ3lJbnRvbGVyYW5jZVZlcmlmaWNhdGlvblN0YXR1c0NvZGVzDQpjb2RlICJhbGxlcmd5LWNvbmZpcm1lZCI6ICdjb25maXJtZWQnIGZyb20gQWxsZXJneUludG9sZXJhbmNlVmVyaWZpY2F0aW9uU3RhdHVzQ29kZXMNCmNvZGUgImFsbGVyZ3ktcmVmdXRlZCI6ICdyZWZ1dGVkJyBmcm9tIEFsbGVyZ3lJbnRvbGVyYW5jZVZlcmlmaWNhdGlvblN0YXR1c0NvZGVzDQoNCi8vIE1lZGljYXRpb25SZXF1ZXN0IENhdGVnb3J5IENvZGVzDQpjb2RlICJDb21tdW5pdHkiOiAnY29tbXVuaXR5JyBmcm9tICJNZWRpY2F0aW9uUmVxdWVzdENhdGVnb3J5IiBkaXNwbGF5ICdDb21tdW5pdHknDQpjb2RlICJEaXNjaGFyZ2UiOiAnZGlzY2hhcmdlJyBmcm9tICJNZWRpY2F0aW9uUmVxdWVzdENhdGVnb3J5IiBkaXNwbGF5ICdEaXNjaGFyZ2UnDQoNCi8vIERpYWdub3NpcyBSb2xlIENvZGVzDQpjb2RlICJBRCI6ICdBRCcgZnJvbSAiRGlhZ25vc2lzIFJvbGUiIGRpc3BsYXkgJ0FkbWlzc2lvbiBkaWFnbm9zaXMnDQpjb2RlICJERCI6ICdERCcgZnJvbSAiRGlhZ25vc2lzIFJvbGUiIGRpc3BsYXkgJ0Rpc2NoYXJnZSBkaWFnbm9zaXMnDQpjb2RlICJDQyI6ICdDQycgZnJvbSAiRGlhZ25vc2lzIFJvbGUiIGRpc3BsYXkgJ0NoaWVmIGNvbXBsYWludCcNCmNvZGUgIkNNIjogJ0NNJyBmcm9tICJEaWFnbm9zaXMgUm9sZSIgZGlzcGxheSAnQ29tb3JiaWRpdHkgZGlhZ25vc2lzJw0KY29kZSAicHJlLW9wIjogJ3ByZS1vcCcgZnJvbSAiRGlhZ25vc2lzIFJvbGUiIGRpc3BsYXkgJ3ByZS1vcCBkaWFnbm9zaXMnDQpjb2RlICJwb3N0LW9wIjogJ3Bvc3Qtb3AnIGZyb20gIkRpYWdub3NpcyBSb2xlIiBkaXNwbGF5ICdwb3N0LW9wIGRpYWdub3NpcycNCmNvZGUgImJpbGxpbmciOiAnYmlsbGluZycgZnJvbSAiRGlhZ25vc2lzIFJvbGUiIGRpc3BsYXkgJ2JpbGxpbmcgZGlhZ25vc2lzJw0KDQovLyBPYnNlcnZhdGlvbiBDYXRlZ29yeSBDb2Rlcw0KY29kZSAic29jaWFsLWhpc3RvcnkiOiAnc29jaWFsLWhpc3RvcnknIGZyb20gIk9ic2VydmF0aW9uQ2F0ZWdvcnlDb2RlcyIgZGlzcGxheSAnU29jaWFsIEhpc3RvcnknDQpjb2RlICJ2aXRhbC1zaWducyI6ICd2aXRhbC1zaWducycgZnJvbSAiT2JzZXJ2YXRpb25DYXRlZ29yeUNvZGVzIiBkaXNwbGF5ICdWaXRhbCBTaWducycNCmNvZGUgImltYWdpbmciOiAnaW1hZ2luZycgZnJvbSAiT2JzZXJ2YXRpb25DYXRlZ29yeUNvZGVzIiBkaXNwbGF5ICdJbWFnaW5nJw0KY29kZSAibGFib3JhdG9yeSI6ICdsYWJvcmF0b3J5JyBmcm9tICJPYnNlcnZhdGlvbkNhdGVnb3J5Q29kZXMiIGRpc3BsYXkgJ0xhYm9yYXRvcnknDQpjb2RlICJwcm9jZWR1cmUiOiAncHJvY2VkdXJlJyBmcm9tICJPYnNlcnZhdGlvbkNhdGVnb3J5Q29kZXMiIGRpc3BsYXkgJ1Byb2NlZHVyZScNCmNvZGUgInN1cnZleSI6ICdzdXJ2ZXknIGZyb20gIk9ic2VydmF0aW9uQ2F0ZWdvcnlDb2RlcyIgZGlzcGxheSAnU3VydmV5Jw0KY29kZSAiZXhhbSI6ICdleGFtJyBmcm9tICJPYnNlcnZhdGlvbkNhdGVnb3J5Q29kZXMiIGRpc3BsYXkgJ0V4YW0nDQpjb2RlICJ0aGVyYXB5IjogJ3RoZXJhcHknIGZyb20gIk9ic2VydmF0aW9uQ2F0ZWdvcnlDb2RlcyIgZGlzcGxheSAnVGhlcmFweScNCmNvZGUgImFjdGl2aXR5IjogJ2FjdGl2aXR5JyBmcm9tICJPYnNlcnZhdGlvbkNhdGVnb3J5Q29kZXMiIGRpc3BsYXkgJ0FjdGl2aXR5Jw0KDQovLyBDb25kaXRpb24gQ2F0ZWdvcnkgQ29kZXMNCmNvZGUgInByb2JsZW0tbGlzdC1pdGVtIjogJ3Byb2JsZW0tbGlzdC1pdGVtJyBmcm9tICJDb25kaXRpb25DYXRlZ29yeUNvZGVzIiBkaXNwbGF5ICdQcm9ibGVtIExpc3QgSXRlbScNCmNvZGUgImVuY291bnRlci1kaWFnbm9zaXMiOiAnZW5jb3VudGVyLWRpYWdub3NpcycgZnJvbSAiQ29uZGl0aW9uQ2F0ZWdvcnlDb2RlcyIgZGlzcGxheSAnRW5jb3VudGVyIERpYWdub3NpcycNCg0KY29udGV4dCBQYXRpZW50DQoNCi8qDQpAZGVzY3JpcHRpb246IE5vcm1hbGl6ZXMgYSB2YWx1ZSB0aGF0IGlzIGEgY2hvaWNlIG9mIHRpbWluZy12YWx1ZWQgdHlwZXMgdG8gYW4gZXF1aXZhbGVudCBpbnRlcnZhbA0KQGNvbW1lbnQ6IE5vcm1hbGl6ZXMgYSBjaG9pY2UgdHlwZSBvZiBEYXRlVGltZSwgUXVhbml0dHksIEludGVydmFsPERhdGVUaW1lPiwgb3IgSW50ZXJ2YWw8UXVhbnRpdHk+IHR5cGVzDQp0byBhbiBlcXVpdmFsZW50IGludGVydmFsLiBUaGlzIHNlbGVjdGlvbiBvZiBjaG9pY2UgdHlwZXMgaXMgYSBzdXBlcnNldCBvZiB0aGUgbWFqb3JpdHkgb2YgY2hvaWNlIHR5cGVzIHRoYXQgYXJlIHVzZWQgYXMgcG9zc2libGUNCnJlcHJlc2VudGF0aW9ucyBmb3IgdGltaW5nLXZhbHVlZCBlbGVtZW50cyBpbiBRSUNvcmUsIGFsbG93aW5nIHRoaXMgZnVuY3Rpb24gdG8gYmUgdXNlZCBhY3Jvc3MgYW55IHJlc291cmNlLg0KDQpUaGUgaW5wdXQgY2FuIGJlIHByb3ZpZGVkIGFzIGEgRGF0ZVRpbWUsIFF1YW50aXR5LCBJbnRlcnZhbDxEYXRlVGltZT4gb3IgSW50ZXJ2YWw8UXVhbnRpdHk+Lg0KVGhlIGludGVudCBvZiB0aGlzIGZ1bmN0aW9uIGlzIHRvIHByb3ZpZGUgYSBjbGVhciBhbmQgY29uY2lzZSBtZWNoYW5pc20gdG8gdHJlYXQgc2luZ2xlDQplbGVtZW50cyB0aGF0IGhhdmUgbXVsdGlwbGUgcG9zc2libGUgcmVwcmVzZW50YXRpb25zIGFzIGludGVydmFscyBzbyB0aGF0IGxvZ2ljIGRvZXNuJ3QgaGF2ZSB0byBhY2NvdW50DQpmb3IgdGhlIHZhcmlhYmlsaXR5LiBNb3JlIGNvbXBsZXggY2FsY3VsYXRpb25zIChzdWNoIGFzIG1lZGljYXRpb24gcmVxdWVzdCBwZXJpb2Qgb3IgZGlzcGVuc2UgcGVyaW9kDQpjYWxjdWxhdGlvbikgbmVlZCBzcGVjaWZpYyBndWlkYW5jZSBhbmQgY29uc2lkZXJhdGlvbi4gVGhhdCBndWlkYW5jZSBtYXkgbWFrZSB1c2Ugb2YgdGhpcyBmdW5jdGlvbiwgYnV0DQp0aGUgZm9jdXMgb2YgdGhpcyBmdW5jdGlvbiBpcyBvbiBzaW5nbGUgZWxlbWVudCBjYWxjdWxhdGlvbnMgd2hlcmUgdGhlIHNlbWFudGljcyBhcmUgdW5hbWJpZ3VvdXMuDQpJZiB0aGUgaW5wdXQgaXMgYSBEYXRlVGltZSwgdGhlIHJlc3VsdCBhIERhdGVUaW1lIEludGVydmFsIGJlZ2lubmluZyBhbmQgZW5kaW5nIG9uIHRoYXQgRGF0ZVRpbWUuDQpJZiB0aGUgaW5wdXQgaXMgYSBRdWFudGl0eSwgdGhlIHF1YW50aXR5IGlzIGV4cGVjdGVkIHRvIGJlIGEgY2FsZW5kYXItZHVyYXRpb24gaW50ZXJwcmV0ZWQgYXMgYW4gQWdlLCANCmFuZCB0aGUgcmVzdWx0IGlzIGEgRGF0ZVRpbWUgSW50ZXJ2YWwgYmVnaW5uaW5nIG9uIHRoZSBEYXRlIHRoZSBwYXRpZW50IHR1cm5lZCB0aGF0IGFnZSBhbmQgZW5kaW5nIGltbWVkaWF0ZWx5IGJlZm9yZSBvbmUgeWVhciBsYXRlci4NCklmIHRoZSBpbnB1dCBpcyBhIERhdGVUaW1lIEludGVydmFsLCB0aGUgcmVzdWx0IGlzIHRoZSBpbnB1dC4NCklmIHRoZSBpbnB1dCBpcyBhIFF1YW50aXR5IEludGVydmFsLCB0aGUgcXVhbnRpdGllcyBhcmUgZXhwZWN0ZWQgdG8gYmUgY2FsZW5kYXItZHVyYXRpb25zIGludGVycHJldGVkIGFzIGFuIEFnZSwgYW5kIHRoZSByZXN1bHQNCmlzIGEgRGF0ZVRpbWUgSW50ZXJ2YWwgYmVnaW5uaW5nIG9uIHRoZSBkYXRlIHRoZSBwYXRpZW50IHR1cm5lZCB0aGUgYWdlIGdpdmVuIGFzIHRoZSBzdGFydCBvZiB0aGUgcXVhbnRpdHkgaW50ZXJ2YWwsIGFuZCBlbmRpbmcgDQppbW1lZGlhdGVseSBiZWZvcmUgb25lIHllYXIgbGF0ZXIgdGhhbiB0aGUgZGF0ZSB0aGUgcGF0aWVudCB0dXJuZWQgdGhlIGFnZSBnaXZlbiBhcyB0aGUgZW5kIG9mIHRoZSBxdWFudGl0eSBpbnRlcnZhbC4NCkFueSBvdGhlciBpbnB1dCB3aWxsIHJlc2x0IGluIGEgbnVsbCBEYXRlVGltZSBJbnRlcnZhbA0KKi8NCmRlZmluZSBmdW5jdGlvbiBUb0ludGVydmFsKGNob2ljZSBDaG9pY2U8RGF0ZVRpbWUsIFF1YW50aXR5LCBJbnRlcnZhbDxEYXRlVGltZT4sIEludGVydmFsPFF1YW50aXR5Pj4pOg0KICBjYXNlDQoJICB3aGVuIGNob2ljZSBpcyBEYXRlVGltZSB0aGVuDQogICAgCUludGVydmFsW2Nob2ljZSBhcyBEYXRlVGltZSwgY2hvaWNlIGFzIERhdGVUaW1lXQ0KCQl3aGVuIGNob2ljZSBpcyBJbnRlcnZhbDxEYXRlVGltZT4gdGhlbg0KICAJCWNob2ljZSBhcyBJbnRlcnZhbDxEYXRlVGltZT4NCgkJd2hlbiBjaG9pY2UgaXMgUXVhbnRpdHkgdGhlbg0KCQkgIEludGVydmFsW1BhdGllbnQuYmlydGhEYXRlICsgKGNob2ljZSBhcyBRdWFudGl0eSksDQoJCQkgIFBhdGllbnQuYmlydGhEYXRlICsgKGNob2ljZSBhcyBRdWFudGl0eSkgKyAxIHllYXIpDQoJCXdoZW4gY2hvaWNlIGlzIEludGVydmFsPFF1YW50aXR5PiB0aGVuDQoJCSAgSW50ZXJ2YWxbUGF0aWVudC5iaXJ0aERhdGUgKyAoY2hvaWNlLmxvdyBhcyBRdWFudGl0eSksDQoJCQkgIFBhdGllbnQuYmlydGhEYXRlICsgKGNob2ljZS5oaWdoIGFzIFF1YW50aXR5KSArIDEgeWVhcikNCgkJZWxzZQ0KCQkJbnVsbCBhcyBJbnRlcnZhbDxEYXRlVGltZT4NCgllbmQNCg0KLyoNCkBkZXNjcmlwdGlvbjogTm9ybWFsaXplcyBhIHZhbHVlIHRoYXQgaXMgYSBjaG9pY2Ugb2YgdGltaW5nLXZhbHVlZCB0eXBlcyB0byBhbiBlcXVpdmFsZW50IGludGVydmFsDQpAY29tbWVudDogTm9ybWFsaXplcyBhIGNob2ljZSB0eXBlIG9mIERhdGVUaW1lLCBRdWFuaXR0eSwgSW50ZXJ2YWw8RGF0ZVRpbWU+LCBvciBJbnRlcnZhbDxRdWFudGl0eT4gdHlwZXMNCnRvIGFuIGVxdWl2YWxlbnQgaW50ZXJ2YWwuIFRoaXMgc2VsZWN0aW9uIG9mIGNob2ljZSB0eXBlcyBpcyBhIHN1cGVyc2V0IG9mIHRoZSBtYWpvcml0eSBvZiBjaG9pY2UgdHlwZXMgdGhhdCBhcmUgdXNlZCBhcyBwb3NzaWJsZQ0KcmVwcmVzZW50YXRpb25zIGZvciB0aW1pbmctdmFsdWVkIGVsZW1lbnRzIGluIFFJQ29yZSwgYWxsb3dpbmcgdGhpcyBmdW5jdGlvbiB0byBiZSB1c2VkIGFjcm9zcyBhbnkgcmVzb3VyY2UuDQoNClRoZSBpbnB1dCBjYW4gYmUgcHJvdmlkZWQgYXMgYSBEYXRlVGltZSwgUXVhbnRpdHksIEludGVydmFsPERhdGVUaW1lPiBvciBJbnRlcnZhbDxRdWFudGl0eT4uDQpUaGUgaW50ZW50IG9mIHRoaXMgZnVuY3Rpb24gaXMgdG8gcHJvdmlkZSBhIGNsZWFyIGFuZCBjb25jaXNlIG1lY2hhbmlzbSB0byB0cmVhdCBzaW5nbGUNCmVsZW1lbnRzIHRoYXQgaGF2ZSBtdWx0aXBsZSBwb3NzaWJsZSByZXByZXNlbnRhdGlvbnMgYXMgaW50ZXJ2YWxzIHNvIHRoYXQgbG9naWMgZG9lc24ndCBoYXZlIHRvIGFjY291bnQNCmZvciB0aGUgdmFyaWFiaWxpdHkuIE1vcmUgY29tcGxleCBjYWxjdWxhdGlvbnMgKHN1Y2ggYXMgbWVkaWNhdGlvbiByZXF1ZXN0IHBlcmlvZCBvciBkaXNwZW5zZSBwZXJpb2QNCmNhbGN1bGF0aW9uKSBuZWVkIHNwZWNpZmljIGd1aWRhbmNlIGFuZCBjb25zaWRlcmF0aW9uLiBUaGF0IGd1aWRhbmNlIG1heSBtYWtlIHVzZSBvZiB0aGlzIGZ1bmN0aW9uLCBidXQNCnRoZSBmb2N1cyBvZiB0aGlzIGZ1bmN0aW9uIGlzIG9uIHNpbmdsZSBlbGVtZW50IGNhbGN1bGF0aW9ucyB3aGVyZSB0aGUgc2VtYW50aWNzIGFyZSB1bmFtYmlndW91cy4NCklmIHRoZSBpbnB1dCBpcyBhIERhdGVUaW1lLCB0aGUgcmVzdWx0IGEgRGF0ZVRpbWUgSW50ZXJ2YWwgYmVnaW5uaW5nIGFuZCBlbmRpbmcgb24gdGhhdCBEYXRlVGltZS4NCklmIHRoZSBpbnB1dCBpcyBhIFF1YW50aXR5LCB0aGUgcXVhbnRpdHkgaXMgZXhwZWN0ZWQgdG8gYmUgYSBjYWxlbmRhci1kdXJhdGlvbiBpbnRlcnByZXRlZCBhcyBhbiBBZ2UsIA0KYW5kIHRoZSByZXN1bHQgaXMgYSBEYXRlVGltZSBJbnRlcnZhbCBiZWdpbm5pbmcgb24gdGhlIERhdGUgdGhlIHBhdGllbnQgdHVybmVkIHRoYXQgYWdlIGFuZCBlbmRpbmcgaW1tZWRpYXRlbHkgYmVmb3JlIG9uZSB5ZWFyIGxhdGVyLg0KSWYgdGhlIGlucHV0IGlzIGEgRGF0ZVRpbWUgSW50ZXJ2YWwsIHRoZSByZXN1bHQgaXMgdGhlIGlucHV0Lg0KSWYgdGhlIGlucHV0IGlzIGEgUXVhbnRpdHkgSW50ZXJ2YWwsIHRoZSBxdWFudGl0aWVzIGFyZSBleHBlY3RlZCB0byBiZSBjYWxlbmRhci1kdXJhdGlvbnMgaW50ZXJwcmV0ZWQgYXMgYW4gQWdlLCBhbmQgdGhlIHJlc3VsdA0KaXMgYSBEYXRlVGltZSBJbnRlcnZhbCBiZWdpbm5pbmcgb24gdGhlIGRhdGUgdGhlIHBhdGllbnQgdHVybmVkIHRoZSBhZ2UgZ2l2ZW4gYXMgdGhlIHN0YXJ0IG9mIHRoZSBxdWFudGl0eSBpbnRlcnZhbCwgYW5kIGVuZGluZyANCmltbWVkaWF0ZWx5IGJlZm9yZSBvbmUgeWVhciBsYXRlciB0aGFuIHRoZSBkYXRlIHRoZSBwYXRpZW50IHR1cm5lZCB0aGUgYWdlIGdpdmVuIGFzIHRoZSBlbmQgb2YgdGhlIHF1YW50aXR5IGludGVydmFsLg0KQW55IG90aGVyIGlucHV0IHdpbGwgcmVzbHQgaW4gYSBudWxsIERhdGVUaW1lIEludGVydmFsDQoqLw0KZGVmaW5lIGZsdWVudCBmdW5jdGlvbiB0b0ludGVydmFsKGNob2ljZSBDaG9pY2U8RGF0ZVRpbWUsIFF1YW50aXR5LCBJbnRlcnZhbDxEYXRlVGltZT4sIEludGVydmFsPFF1YW50aXR5Pj4pOg0KICBjYXNlDQoJICB3aGVuIGNob2ljZSBpcyBEYXRlVGltZSB0aGVuDQogICAgCUludGVydmFsW2Nob2ljZSBhcyBEYXRlVGltZSwgY2hvaWNlIGFzIERhdGVUaW1lXQ0KCQl3aGVuIGNob2ljZSBpcyBJbnRlcnZhbDxEYXRlVGltZT4gdGhlbg0KICAJCWNob2ljZSBhcyBJbnRlcnZhbDxEYXRlVGltZT4NCgkJd2hlbiBjaG9pY2UgaXMgUXVhbnRpdHkgdGhlbg0KCQkgIEludGVydmFsW1BhdGllbnQuYmlydGhEYXRlICsgKGNob2ljZSBhcyBRdWFudGl0eSksDQoJCQkgIFBhdGllbnQuYmlydGhEYXRlICsgKGNob2ljZSBhcyBRdWFudGl0eSkgKyAxIHllYXIpDQoJCXdoZW4gY2hvaWNlIGlzIEludGVydmFsPFF1YW50aXR5PiB0aGVuDQoJCSAgSW50ZXJ2YWxbUGF0aWVudC5iaXJ0aERhdGUgKyAoY2hvaWNlLmxvdyBhcyBRdWFudGl0eSksDQoJCQkgIFBhdGllbnQuYmlydGhEYXRlICsgKGNob2ljZS5oaWdoIGFzIFF1YW50aXR5KSArIDEgeWVhcikNCgkJZWxzZQ0KCQkJbnVsbCBhcyBJbnRlcnZhbDxEYXRlVGltZT4NCgllbmQNCg0KLyoNCkBkZXNjcmlwdGlvbjogUmV0dXJucyBhbiBpbnRlcnZhbCByZXByZXNlbnRpbmcgdGhlIG5vcm1hbGl6ZWQgYWJhdGVtZW50IG9mIGEgZ2l2ZW4gQ29uZGl0aW9uLg0KQGNvbW1lbnQ6IElmIHRoZSBhYmF0ZW1lbnQgZWxlbWVudCBvZiB0aGUgQ29uZGl0aW9uIGlzIHJlcHJlc2VudGVkIGFzIGEgRGF0ZVRpbWUsIHRoZSByZXN1bHQNCmlzIGFuIGludGVydmFsIGJlZ2lubmluZyBhbmQgZW5kaW5nIG9uIHRoYXQgRGF0ZVRpbWUuDQpJZiB0aGUgYWJhdGVtZW50IGlzIHJlcHJlc2VudGVkIGFzIGEgUXVhbnRpdHksIHRoZSBxdWFudGl0eSBpcyBleHBlY3RlZCB0byBiZSBhIGNhbGVuZGFyLWR1cmF0aW9uIGFuZCBpcyBpbnRlcnByZXRlZCBhcyB0aGUgYWdlIG9mIHRoZSBwYXRpZW50LiBUaGUNCnJlc3VsdCBpcyBhbiBpbnRlcnZhbCBmcm9tIHRoZSBkYXRlIHRoZSBwYXRpZW50IHR1cm5lZCB0aGF0IGFnZSB0byBpbW1lZGlhdGVseSBiZWZvcmUgb25lIHllYXIgbGF0ZXIuDQpJZiB0aGUgYWJhdGVtZW50IGlzIHJlcHJlc2VudGVkIGFzIGEgUXVhbnRpdHkgSW50ZXJ2YWwsIHRoZSBxdWFudGl0aWVzIGFyZSBleHBlY3RlZCB0byBiZSBjYWxlbmRhci1kdXJhdGlvbnMgYW5kIGFyZSBpbnRlcnByZXRlZCBhcyBhbiBhZ2UgcmFuZ2UgZHVyaW5nDQp3aGljaCB0aGUgYWJhdGVtZW50IG9jY3VycmVkLiBUaGUgcmVzdWx0IGlzIGFuIGludGVydmFsIGZyb20gdGhlIGRhdGUgdGhlIHBhdGllbnQgdHVybmVkIHRoZSBzdGFydGluZyBhZ2Ugb2YgdGhlIHF1YW50aXR5IGludGVydmFsLCBhbmQgZW5kaW5nIGltbWVkaWF0ZWx5DQpiZWZvcmUgb25lIHllYXIgbGF0ZXIgdGhhbiB0aGUgZGF0ZSB0aGUgcGF0aWVudCB0dXJuZWQgdGhlIGVuZGluZyBhZ2Ugb2YgdGhlIHF1YW50aXR5IGludGVydmFsLg0KKi8NCmRlZmluZSBmdW5jdGlvbiBUb0FiYXRlbWVudEludGVydmFsKGNvbmRpdGlvbiBDb25kaXRpb24pOg0KCWlmIGNvbmRpdGlvbi5hYmF0ZW1lbnQgaXMgRGF0ZVRpbWUgdGhlbg0KCSAgSW50ZXJ2YWxbY29uZGl0aW9uLmFiYXRlbWVudCBhcyBEYXRlVGltZSwgY29uZGl0aW9uLmFiYXRlbWVudCBhcyBEYXRlVGltZV0NCgllbHNlIGlmIGNvbmRpdGlvbi5hYmF0ZW1lbnQgaXMgUXVhbnRpdHkgdGhlbg0KCQlJbnRlcnZhbFtQYXRpZW50LmJpcnRoRGF0ZSArIChjb25kaXRpb24uYWJhdGVtZW50IGFzIFF1YW50aXR5KSwNCgkJCVBhdGllbnQuYmlydGhEYXRlICsgKGNvbmRpdGlvbi5hYmF0ZW1lbnQgYXMgUXVhbnRpdHkpICsgMSB5ZWFyKQ0KCWVsc2UgaWYgY29uZGl0aW9uLmFiYXRlbWVudCBpcyBJbnRlcnZhbDxRdWFudGl0eT4gdGhlbg0KCSAgSW50ZXJ2YWxbUGF0aWVudC5iaXJ0aERhdGUgKyAoY29uZGl0aW9uLmFiYXRlbWVudC5sb3cgYXMgUXVhbnRpdHkpLA0KCQkgIFBhdGllbnQuYmlydGhEYXRlICsgKGNvbmRpdGlvbi5hYmF0ZW1lbnQuaGlnaCBhcyBRdWFudGl0eSkgKyAxIHllYXIpDQoJZWxzZSBpZiBjb25kaXRpb24uYWJhdGVtZW50IGlzIEludGVydmFsPERhdGVUaW1lPiB0aGVuDQoJICBJbnRlcnZhbFtjb25kaXRpb24uYWJhdGVtZW50LmxvdywgY29uZGl0aW9uLmFiYXRlbWVudC5oaWdoKQ0KCWVsc2UgbnVsbCBhcyBJbnRlcnZhbDxEYXRlVGltZT4NCg0KLyoNCkBkZXNjcmlwdGlvbjogUmV0dXJucyBhbiBpbnRlcnZhbCByZXByZXNlbnRpbmcgdGhlIG5vcm1hbGl6ZWQgYWJhdGVtZW50IG9mIGEgZ2l2ZW4gQ29uZGl0aW9uLg0KQGNvbW1lbnQ6IElmIHRoZSBhYmF0ZW1lbnQgZWxlbWVudCBvZiB0aGUgQ29uZGl0aW9uIGlzIHJlcHJlc2VudGVkIGFzIGEgRGF0ZVRpbWUsIHRoZSByZXN1bHQNCmlzIGFuIGludGVydmFsIGJlZ2lubmluZyBhbmQgZW5kaW5nIG9uIHRoYXQgRGF0ZVRpbWUuDQpJZiB0aGUgYWJhdGVtZW50IGlzIHJlcHJlc2VudGVkIGFzIGEgUXVhbnRpdHksIHRoZSBxdWFudGl0eSBpcyBleHBlY3RlZCB0byBiZSBhIGNhbGVuZGFyLWR1cmF0aW9uIGFuZCBpcyBpbnRlcnByZXRlZCBhcyB0aGUgYWdlIG9mIHRoZSBwYXRpZW50LiBUaGUNCnJlc3VsdCBpcyBhbiBpbnRlcnZhbCBmcm9tIHRoZSBkYXRlIHRoZSBwYXRpZW50IHR1cm5lZCB0aGF0IGFnZSB0byBpbW1lZGlhdGVseSBiZWZvcmUgb25lIHllYXIgbGF0ZXIuDQpJZiB0aGUgYWJhdGVtZW50IGlzIHJlcHJlc2VudGVkIGFzIGEgUXVhbnRpdHkgSW50ZXJ2YWwsIHRoZSBxdWFudGl0aWVzIGFyZSBleHBlY3RlZCB0byBiZSBjYWxlbmRhci1kdXJhdGlvbnMgYW5kIGFyZSBpbnRlcnByZXRlZCBhcyBhbiBhZ2UgcmFuZ2UgZHVyaW5nDQp3aGljaCB0aGUgYWJhdGVtZW50IG9jY3VycmVkLiBUaGUgcmVzdWx0IGlzIGFuIGludGVydmFsIGZyb20gdGhlIGRhdGUgdGhlIHBhdGllbnQgdHVybmVkIHRoZSBzdGFydGluZyBhZ2Ugb2YgdGhlIHF1YW50aXR5IGludGVydmFsLCBhbmQgZW5kaW5nIGltbWVkaWF0ZWx5DQpiZWZvcmUgb25lIHllYXIgbGF0ZXIgdGhhbiB0aGUgZGF0ZSB0aGUgcGF0aWVudCB0dXJuZWQgdGhlIGVuZGluZyBhZ2Ugb2YgdGhlIHF1YW50aXR5IGludGVydmFsLg0KKi8NCmRlZmluZSBmbHVlbnQgZnVuY3Rpb24gdG9BYmF0ZW1lbnRJbnRlcnZhbChjb25kaXRpb24gQ29uZGl0aW9uKToNCglpZiBjb25kaXRpb24uYWJhdGVtZW50IGlzIERhdGVUaW1lIHRoZW4NCgkgIEludGVydmFsW2NvbmRpdGlvbi5hYmF0ZW1lbnQgYXMgRGF0ZVRpbWUsIGNvbmRpdGlvbi5hYmF0ZW1lbnQgYXMgRGF0ZVRpbWVdDQoJZWxzZSBpZiBjb25kaXRpb24uYWJhdGVtZW50IGlzIFF1YW50aXR5IHRoZW4NCgkJSW50ZXJ2YWxbUGF0aWVudC5iaXJ0aERhdGUgKyAoY29uZGl0aW9uLmFiYXRlbWVudCBhcyBRdWFudGl0eSksDQoJCQlQYXRpZW50LmJpcnRoRGF0ZSArIChjb25kaXRpb24uYWJhdGVtZW50IGFzIFF1YW50aXR5KSArIDEgeWVhcikNCgllbHNlIGlmIGNvbmRpdGlvbi5hYmF0ZW1lbnQgaXMgSW50ZXJ2YWw8UXVhbnRpdHk+IHRoZW4NCgkgIEludGVydmFsW1BhdGllbnQuYmlydGhEYXRlICsgKGNvbmRpdGlvbi5hYmF0ZW1lbnQubG93IGFzIFF1YW50aXR5KSwNCgkJICBQYXRpZW50LmJpcnRoRGF0ZSArIChjb25kaXRpb24uYWJhdGVtZW50LmhpZ2ggYXMgUXVhbnRpdHkpICsgMSB5ZWFyKQ0KCWVsc2UgaWYgY29uZGl0aW9uLmFiYXRlbWVudCBpcyBJbnRlcnZhbDxEYXRlVGltZT4gdGhlbg0KCSAgSW50ZXJ2YWxbY29uZGl0aW9uLmFiYXRlbWVudC5sb3csIGNvbmRpdGlvbi5hYmF0ZW1lbnQuaGlnaCkNCgllbHNlIG51bGwgYXMgSW50ZXJ2YWw8RGF0ZVRpbWU+DQoNCi8qDQpAZGVzY3JpcHRpb246IFJldHVybnMgYW4gaW50ZXJ2YWwgcmVwcmVzZW50aW5nIHRoZSBub3JtYWxpemVkIHByZXZhbGVuY2UgcGVyaW9kIG9mIGEgZ2l2ZW4gQ29uZGl0aW9uLg0KQGNvbW1lbnQ6IFVzZXMgdGhlIFRvSW50ZXJ2YWwgYW5kIFRvQWJhdGVtZW50SW50ZXJ2YWwgZnVuY3Rpb25zIHRvIGRldGVybWluZSB0aGUgd2lkZXN0IHBvdGVudGlhbCBpbnRlcnZhbCBmcm9tDQpvbnNldCB0byBhYmF0ZW1lbnQgYXMgc3BlY2lmaWVkIGluIHRoZSBnaXZlbiBDb25kaXRpb24uIElmIHRoZSBjb25kaXRpb24gaXMgYWN0aXZlLCB0aGUgcmVzdWx0aW5nIGludGVydmFsIHdpbGwgaGF2ZQ0KYSBjbG9zZWQgZW5kaW5nIGJvdW5kYXJ5LiBJZiB0aGUgY29uZGl0aW9uIGlzIG5vdCBhY3RpdmUsIHRoZSByZXN1bHRpbmcgaW50ZXJ2YWwgd2lsbCBoYXZlIGFuIG9wZW4gZW5kaW5nIGJvdW5kYXJ5Lg0KKi8NCmRlZmluZSBmdW5jdGlvbiBUb1ByZXZhbGVuY2VJbnRlcnZhbChjb25kaXRpb24gQ29uZGl0aW9uKToNCmlmIGNvbmRpdGlvbi5jbGluaWNhbFN0YXR1cyB+ICJhY3RpdmUiDQogIG9yIGNvbmRpdGlvbi5jbGluaWNhbFN0YXR1cyB+ICJyZWN1cnJlbmNlIg0KICBvciBjb25kaXRpb24uY2xpbmljYWxTdGF0dXMgfiAicmVsYXBzZSIgdGhlbg0KICBJbnRlcnZhbFtzdGFydCBvZiBUb0ludGVydmFsKGNvbmRpdGlvbi5vbnNldCksIGVuZCBvZiBUb0FiYXRlbWVudEludGVydmFsKGNvbmRpdGlvbildDQplbHNlDQogIEludGVydmFsW3N0YXJ0IG9mIFRvSW50ZXJ2YWwoY29uZGl0aW9uLm9uc2V0KSwgZW5kIG9mIFRvQWJhdGVtZW50SW50ZXJ2YWwoY29uZGl0aW9uKSkNCg0KLyoNCkBkZXNjcmlwdGlvbjogUmV0dXJucyBhbiBpbnRlcnZhbCByZXByZXNlbnRpbmcgdGhlIG5vcm1hbGl6ZWQgcHJldmFsZW5jZSBwZXJpb2Qgb2YgYSBnaXZlbiBDb25kaXRpb24uDQpAY29tbWVudDogVXNlcyB0aGUgVG9JbnRlcnZhbCBhbmQgVG9BYmF0ZW1lbnRJbnRlcnZhbCBmdW5jdGlvbnMgdG8gZGV0ZXJtaW5lIHRoZSB3aWRlc3QgcG90ZW50aWFsIGludGVydmFsIGZyb20NCm9uc2V0IHRvIGFiYXRlbWVudCBhcyBzcGVjaWZpZWQgaW4gdGhlIGdpdmVuIENvbmRpdGlvbi4gSWYgdGhlIGNvbmRpdGlvbiBpcyBhY3RpdmUsIHRoZSByZXN1bHRpbmcgaW50ZXJ2YWwgd2lsbCBoYXZlDQphIGNsb3NlZCBlbmRpbmcgYm91bmRhcnkuIElmIHRoZSBjb25kaXRpb24gaXMgbm90IGFjdGl2ZSwgdGhlIHJlc3VsdGluZyBpbnRlcnZhbCB3aWxsIGhhdmUgYW4gb3BlbiBlbmRpbmcgYm91bmRhcnkuDQoqLw0KZGVmaW5lIGZsdWVudCBmdW5jdGlvbiB0b1ByZXZhbGVuY2VJbnRlcnZhbChjb25kaXRpb24gQ29uZGl0aW9uKToNCmlmIGNvbmRpdGlvbi5jbGluaWNhbFN0YXR1cyB+ICJhY3RpdmUiDQogIG9yIGNvbmRpdGlvbi5jbGluaWNhbFN0YXR1cyB+ICJyZWN1cnJlbmNlIg0KICBvciBjb25kaXRpb24uY2xpbmljYWxTdGF0dXMgfiAicmVsYXBzZSIgdGhlbg0KICBJbnRlcnZhbFtzdGFydCBvZiBUb0ludGVydmFsKGNvbmRpdGlvbi5vbnNldCksIGVuZCBvZiBUb0FiYXRlbWVudEludGVydmFsKGNvbmRpdGlvbildDQplbHNlDQogIEludGVydmFsW3N0YXJ0IG9mIFRvSW50ZXJ2YWwoY29uZGl0aW9uLm9uc2V0KSwgZW5kIG9mIFRvQWJhdGVtZW50SW50ZXJ2YWwoY29uZGl0aW9uKSkNCg0KLyoNCkBkZXNjcmlwdGlvbjogUmV0dXJucyB0aGUgdGFpbCBvZiB0aGUgZ2l2ZW4gdXJpIChpLmUuIGV2ZXJ5dGhpbmcgYWZ0ZXIgdGhlIGxhc3Qgc2xhc2ggaW4gdGhlIFVSSSkuDQpAY29tbWVudDogVGhpcyBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBkZXRlcm1pbmUgdGhlIGxvZ2ljYWwgaWQgb2YgYSBnaXZlbiByZXNvdXJjZS4gSXQgY2FuIGJlIHVzZWQgaW4NCmEgc2luZ2xlLXNlcnZlciBlbnZpcm9ubWVudCB0byB0cmFjZSByZWZlcmVuY2VzLiBIb3dldmVyLCB0aGlzIGZ1bmN0aW9uIGRvZXMgbm90IGF0dGVtcHQgdG8gcmVzb2x2ZQ0Kb3IgZGlzdGluZ3Vpc2ggdGhlIGJhc2Ugb2YgdGhlIGdpdmVuIHVybCwgYW5kIHNvIGNhbm5vdCBiZSB1c2VkIHNhZmVseSBpbiBtdWx0aS1zZXJ2ZXIgZW52aXJvbm1lbnRzLg0KKi8NCmRlZmluZSBmdW5jdGlvbiBHZXRJZCh1cmkgU3RyaW5nICk6DQogIExhc3QoU3BsaXQodXJpLCAnLycpKQ0KDQovKg0KQGRlc2NyaXB0aW9uOiBSZXR1cm5zIHRoZSB0YWlsIG9mIHRoZSBnaXZlbiB1cmkgKGkuZS4gZXZlcnl0aGluZyBhZnRlciB0aGUgbGFzdCBzbGFzaCBpbiB0aGUgVVJJKS4NCkBjb21tZW50OiBUaGlzIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIHRvIGRldGVybWluZSB0aGUgbG9naWNhbCBpZCBvZiBhIGdpdmVuIHJlc291cmNlLiBJdCBjYW4gYmUgdXNlZCBpbg0KYSBzaW5nbGUtc2VydmVyIGVudmlyb25tZW50IHRvIHRyYWNlIHJlZmVyZW5jZXMuIEhvd2V2ZXIsIHRoaXMgZnVuY3Rpb24gZG9lcyBub3QgYXR0ZW1wdCB0byByZXNvbHZlDQpvciBkaXN0aW5ndWlzaCB0aGUgYmFzZSBvZiB0aGUgZ2l2ZW4gdXJsLCBhbmQgc28gY2Fubm90IGJlIHVzZWQgc2FmZWx5IGluIG11bHRpLXNlcnZlciBlbnZpcm9ubWVudHMuDQoqLw0KZGVmaW5lIGZsdWVudCBmdW5jdGlvbiBnZXRJZCh1cmkgU3RyaW5nKToNCiAgTGFzdChTcGxpdCh1cmksICcvJykpDQoNCi8qDQpAZGVzY3JpcHRpb246IEdpdmVuIGFuIGludGVydmFsLCByZXR1cm4gdHJ1ZSBpZiB0aGUgaW50ZXJ2YWwgaGFzIGEgc3RhcnRpbmcgYm91bmRhcnkgc3BlY2lmaWVkIA0KKGkuZS4gdGhlIHN0YXJ0IG9mIHRoZSBpbnRlcnZhbCBpcyBub3QgbnVsbCBhbmQgbm90IHRoZSBtaW5pbXVtIERhdGVUaW1lIHZhbHVlKQ0KKi8NCmRlZmluZSBmdW5jdGlvbiAiSGFzU3RhcnQiKHBlcmlvZCBJbnRlcnZhbDxEYXRlVGltZT4gKToNCiAgbm90ICggc3RhcnQgb2YgcGVyaW9kIGlzIG51bGwNCiAgICAgIG9yIHN0YXJ0IG9mIHBlcmlvZCA9IG1pbmltdW0gRGF0ZVRpbWUNCiAgKQ0KDQovKg0KQGRlc2NyaXB0aW9uOiBHaXZlbiBhbiBpbnRlcnZhbCwgcmV0dXJuIHRydWUgaWYgdGhlIGludGVydmFsIGhhcyBhIHN0YXJ0aW5nIGJvdW5kYXJ5IHNwZWNpZmllZCANCihpLmUuIHRoZSBzdGFydCBvZiB0aGUgaW50ZXJ2YWwgaXMgbm90IG51bGwgYW5kIG5vdCB0aGUgbWluaW11bSBEYXRlVGltZSB2YWx1ZSkNCiovDQpkZWZpbmUgZmx1ZW50IGZ1bmN0aW9uIGhhc1N0YXJ0KHBlcmlvZCBJbnRlcnZhbDxEYXRlVGltZT4gKToNCiAgbm90ICggc3RhcnQgb2YgcGVyaW9kIGlzIG51bGwNCiAgICAgIG9yIHN0YXJ0IG9mIHBlcmlvZCA9IG1pbmltdW0gRGF0ZVRpbWUNCiAgKQ0KDQovKg0KQGRlc2NyaXB0aW9uOiBHaXZlbiBhbiBpbnRlcnZhbCwgcmV0dXJucyB0cnVlIGlmIHRoZSBpbnRlcnZhbCBoYXMgYW4gZW5kaW5nIGJvdW5kYXJ5IHNwZWNpZmllZCANCihpLmUuIHRoZSBlbmQgb2YgdGhlIGludGVydmFsIGlzIG5vdCBudWxsIGFuZCBub3QgdGhlIG1heGltdW0gRGF0ZVRpbWUgdmFsdWUpDQoqLw0KZGVmaW5lIGZ1bmN0aW9uICJIYXNFbmQiKHBlcmlvZCBJbnRlcnZhbDxEYXRlVGltZT4gKToNCiAgbm90ICgNCiAgICBlbmQgb2YgcGVyaW9kIGlzIG51bGwNCiAgICAgIG9yIGVuZCBvZiBwZXJpb2QgPSBtYXhpbXVtIERhdGVUaW1lDQogICkNCg0KLyoNCkBkZXNjcmlwdGlvbjogR2l2ZW4gYW4gaW50ZXJ2YWwsIHJldHVybnMgdHJ1ZSBpZiB0aGUgaW50ZXJ2YWwgaGFzIGFuIGVuZGluZyBib3VuZGFyeSBzcGVjaWZpZWQgDQooaS5lLiB0aGUgZW5kIG9mIHRoZSBpbnRlcnZhbCBpcyBub3QgbnVsbCBhbmQgbm90IHRoZSBtYXhpbXVtIERhdGVUaW1lIHZhbHVlKQ0KKi8NCmRlZmluZSBmbHVlbnQgZnVuY3Rpb24gaGFzRW5kKHBlcmlvZCBJbnRlcnZhbDxEYXRlVGltZT4gKToNCiAgbm90ICgNCiAgICBlbmQgb2YgcGVyaW9kIGlzIG51bGwNCiAgICAgIG9yIGVuZCBvZiBwZXJpb2QgPSBtYXhpbXVtIERhdGVUaW1lDQogICkNCg0KLyoNCkBkZXNjcmlwdGlvbjogR2l2ZW4gYW4gaW50ZXJ2YWwsIHJldHVybnMgdGhlIGVuZGluZyBwb2ludCBpZiB0aGUgaW50ZXJ2YWwgaGFzIGFuIGVuZGluZyBib3VuZGFyeSBzcGVjaWZpZWQsIA0Kb3RoZXJ3aXNlLCByZXR1cm5zIHRoZSBzdGFydGluZyBwb2ludA0KKi8NCmRlZmluZSBmdW5jdGlvbiAiTGF0ZXN0IihjaG9pY2UgQ2hvaWNlPERhdGVUaW1lLCBRdWFudGl0eSwgSW50ZXJ2YWw8RGF0ZVRpbWU+LCBJbnRlcnZhbDxRdWFudGl0eT4+ICk6DQogIChjaG9pY2UudG9JbnRlcnZhbCgpKSBwZXJpb2QNCiAgICByZXR1cm4NCiAgICAgIGlmIChIYXNFbmQocGVyaW9kKSkgdGhlbiBlbmQgb2YgcGVyaW9kDQogICAgICBlbHNlIHN0YXJ0IG9mIHBlcmlvZA0KDQovKg0KQGRlc2NyaXB0aW9uOiBHaXZlbiBhbiBpbnRlcnZhbCwgcmV0dXJucyB0aGUgZW5kaW5nIHBvaW50IGlmIHRoZSBpbnRlcnZhbCBoYXMgYW4gZW5kaW5nIGJvdW5kYXJ5IHNwZWNpZmllZCwgDQpvdGhlcndpc2UsIHJldHVybnMgdGhlIHN0YXJ0aW5nIHBvaW50DQoqLw0KZGVmaW5lIGZsdWVudCBmdW5jdGlvbiBsYXRlc3QoY2hvaWNlIENob2ljZTxEYXRlVGltZSwgUXVhbnRpdHksIEludGVydmFsPERhdGVUaW1lPiwgSW50ZXJ2YWw8UXVhbnRpdHk+PiApOg0KICAoY2hvaWNlLnRvSW50ZXJ2YWwoKSkgcGVyaW9kDQogICAgcmV0dXJuDQogICAgICBpZiAoSGFzRW5kKHBlcmlvZCkpIHRoZW4gZW5kIG9mIHBlcmlvZA0KICAgICAgZWxzZSBzdGFydCBvZiBwZXJpb2QNCg0KLyoNCkBkZXNjcmlwdGlvbjogR2l2ZW4gYW4gaW50ZXJ2YWwsIHJldHVybiB0aGUgc3RhcnRpbmcgcG9pbnQgaWYgdGhlIGludGVydmFsIGhhcyBhIHN0YXJ0aW5nIGJvdW5kYXJ5IHNwZWNpZmllZCwgDQpvdGhlcndpc2UsIHJldHVybiB0aGUgZW5kaW5nIHBvaW50DQoqLw0KZGVmaW5lIGZ1bmN0aW9uICJFYXJsaWVzdCIoY2hvaWNlIENob2ljZTxEYXRlVGltZSwgUXVhbnRpdHksIEludGVydmFsPERhdGVUaW1lPiwgSW50ZXJ2YWw8UXVhbnRpdHk+PiApOg0KICAoY2hvaWNlLnRvSW50ZXJ2YWwoKSkgcGVyaW9kDQogICAgcmV0dXJuDQogICAgICBpZiAoSGFzU3RhcnQocGVyaW9kKSkgdGhlbiBzdGFydCBvZiBwZXJpb2QNCiAgICAgIGVsc2UgZW5kIG9mIHBlcmlvZA0KDQovKg0KQGRlc2NyaXB0aW9uOiBHaXZlbiBhbiBpbnRlcnZhbCwgcmV0dXJuIHRoZSBzdGFydGluZyBwb2ludCBpZiB0aGUgaW50ZXJ2YWwgaGFzIGEgc3RhcnRpbmcgYm91bmRhcnkgc3BlY2lmaWVkLCANCm90aGVyd2lzZSwgcmV0dXJuIHRoZSBlbmRpbmcgcG9pbnQNCiovDQpkZWZpbmUgZmx1ZW50IGZ1bmN0aW9uIGVhcmxpZXN0KGNob2ljZSBDaG9pY2U8RGF0ZVRpbWUsIFF1YW50aXR5LCBJbnRlcnZhbDxEYXRlVGltZT4sIEludGVydmFsPFF1YW50aXR5Pj4gKToNCiAgKGNob2ljZS50b0ludGVydmFsKCkpIHBlcmlvZA0KICAgIHJldHVybg0KICAgICAgaWYgKEhhc1N0YXJ0KHBlcmlvZCkpIHRoZW4gc3RhcnQgb2YgcGVyaW9kDQogICAgICBlbHNlIGVuZCBvZiBwZXJpb2QNCg0KLyoNCkBkZXNjcmlwdGlvbjogQ3JlYXRlcyBhIGxpc3Qgb2YgaW50ZWdlcnMgZnJvbSAxIHRvIGhvdyBtYW55IGRheXMgYXJlIGluIHRoZSBpbnRlcnZhbC4gTm90ZSwgdGhpcyB3b250IGNyZWF0ZSBhbiBpbmRleCBmb3INCnRoZSBmaW5hbCBkYXkgaWYgaXQgaXMgbGVzcyB0aGFuIDI0IGhvdXJzLiBUaGlzIGFsc28gaW5jbHVkZXMgdGhlIGZpcnN0IDI0IGhvdXIgcGVyaW9kLg0KKi8NCmRlZmluZSBmdW5jdGlvbiAiSW50ZXJ2YWwgVG8gRGF5IE51bWJlcnMiKFBlcmlvZCBJbnRlcnZhbDxEYXRlVGltZT4pOg0KICAoIGV4cGFuZCB7IEludGVydmFsWzEsIGR1cmF0aW9uIGluIGRheXMgYmV0d2VlbiBzdGFydCBvZiBQZXJpb2QgYW5kIGVuZCBvZiBQZXJpb2RdfSApIERheU51bWJlcg0KICAgIHJldHVybiBlbmQgb2YgRGF5TnVtYmVyDQoNCi8qDQpAZGVzY3JpcHRpb246IENyZWF0ZXMgYSBsaXN0IG9mIGludGVnZXJzIGZyb20gMSB0byBob3cgbWFueSBkYXlzIGFyZSBpbiB0aGUgaW50ZXJ2YWwuIE5vdGUsIHRoaXMgd29udCBjcmVhdGUgYW4gaW5kZXggZm9yDQp0aGUgZmluYWwgZGF5IGlmIGl0IGlzIGxlc3MgdGhhbiAyNCBob3Vycy4gVGhpcyBhbHNvIGluY2x1ZGVzIHRoZSBmaXJzdCAyNCBob3VyIHBlcmlvZC4NCiovDQpkZWZpbmUgZmx1ZW50IGZ1bmN0aW9uIHRvRGF5TnVtYmVycyhQZXJpb2QgSW50ZXJ2YWw8RGF0ZVRpbWU+KToNCiAgKCBleHBhbmQgeyBJbnRlcnZhbFsxLCBkdXJhdGlvbiBpbiBkYXlzIGJldHdlZW4gc3RhcnQgb2YgUGVyaW9kIGFuZCBlbmQgb2YgUGVyaW9kXX0gKSBEYXlOdW1iZXINCiAgICByZXR1cm4gZW5kIG9mIERheU51bWJlcg0KDQovKg0KQGRlc2NyaXB0aW9uOiBDcmVhdGVzIGEgbGlzdCBvZiAyNCBob3VyIGxvbmcgaW50ZXJ2YWxzIGluIGFuIGludGVydmFsIHBhaXJlZCB3aXRoIHRoZSBpbmRleCAoMSBpbmRleGVkKSB0byB3aGljaCAyNCBob3VyIGludGVydmFsIGl0IGlzLg0KTm90ZSB0aGF0IHRoZSByZXN1bHQgd2lsbCBpbmNsdWRlIGludGVydmFscyB0aGF0IGFyZSBjbG9zZWQgYXQgdGhlIGJlZ2lubmluZyBhbmQgb3BlbiBhdCB0aGUgZW5kDQoqLw0KZGVmaW5lIGZ1bmN0aW9uICJEYXlzIEluIFBlcmlvZCIoUGVyaW9kIEludGVydmFsPERhdGVUaW1lPik6DQogICggIkludGVydmFsIFRvIERheSBOdW1iZXJzIihQZXJpb2QpKSBEYXlJbmRleA0KICAgIGxldCBzdGFydFBlcmlvZDogc3RhcnQgb2YgUGVyaW9kICsgKDI0IGhvdXJzICogKERheUluZGV4IC0gMSkpLA0KICAgIGVuZFBlcmlvZDogaWYgKGhvdXJzIGJldHdlZW4gc3RhcnRQZXJpb2QgYW5kIGVuZCBvZiBQZXJpb2QgPCAyNCkgdGhlbiBzdGFydFBlcmlvZA0KICAgICAgZWxzZSBzdGFydCBvZiBQZXJpb2QgKyAoMjQgaG91cnMgKiBEYXlJbmRleCkNCiAgICByZXR1cm4gVHVwbGUgew0KICAgICAgZGF5SW5kZXg6IERheUluZGV4LA0KICAgICAgZGF5UGVyaW9kOiBJbnRlcnZhbFtzdGFydFBlcmlvZCwgZW5kUGVyaW9kKQ0KICAgIH0NCg0KLyoNCkBkZXNjcmlwdGlvbjogQ3JlYXRlcyBhIGxpc3Qgb2YgMjQgaG91ciBsb25nIGludGVydmFscyBpbiBhbiBpbnRlcnZhbCBwYWlyZWQgd2l0aCB0aGUgaW5kZXggKDEgaW5kZXhlZCkgdG8gd2hpY2ggMjQgaG91ciBpbnRlcnZhbCBpdCBpcy4NCk5vdGUgdGhhdCB0aGUgcmVzdWx0IHdpbGwgaW5jbHVkZSBpbnRlcnZhbHMgdGhhdCBhcmUgY2xvc2VkIGF0IHRoZSBiZWdpbm5pbmcgYW5kIG9wZW4gYXQgdGhlIGVuZA0KKi8NCmRlZmluZSBmbHVlbnQgZnVuY3Rpb24gZGF5c0luUGVyaW9kKFBlcmlvZCBJbnRlcnZhbDxEYXRlVGltZT4pOg0KICAoICJJbnRlcnZhbCBUbyBEYXkgTnVtYmVycyIoUGVyaW9kKSkgRGF5SW5kZXgNCiAgICBsZXQgc3RhcnRQZXJpb2Q6IHN0YXJ0IG9mIFBlcmlvZCArICgyNCBob3VycyAqIChEYXlJbmRleCAtIDEpKSwNCiAgICBlbmRQZXJpb2Q6IGlmIChob3VycyBiZXR3ZWVuIHN0YXJ0UGVyaW9kIGFuZCBlbmQgb2YgUGVyaW9kIDwgMjQpIHRoZW4gc3RhcnRQZXJpb2QNCiAgICAgIGVsc2Ugc3RhcnQgb2YgUGVyaW9kICsgKDI0IGhvdXJzICogRGF5SW5kZXgpDQogICAgcmV0dXJuIFR1cGxlIHsNCiAgICAgIGRheUluZGV4OiBEYXlJbmRleCwNCiAgICAgIGRheVBlcmlvZDogSW50ZXJ2YWxbc3RhcnRQZXJpb2QsIGVuZFBlcmlvZCkNCiAgICB9"^^xsd:base64Binary ]
  ] ) . #