Upload index.html with huggingface_hub
Browse files- index.html +313 -17
index.html
CHANGED
|
@@ -1,19 +1,315 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 6 |
+
<title>US Core Profile Gap Check (USCDI v3) — free online check</title>
|
| 7 |
+
<style>
|
| 8 |
+
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
|
| 9 |
+
.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}
|
| 10 |
+
textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}
|
| 11 |
+
.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}
|
| 12 |
+
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
|
| 13 |
+
table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}
|
| 14 |
+
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
|
| 15 |
+
.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}
|
| 16 |
+
</style>
|
| 17 |
+
<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>
|
| 18 |
+
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/uscore-profile-gap-lint"></head>
|
| 19 |
+
<body>
|
| 20 |
+
<div class="wrap">
|
| 21 |
+
<h1>US Core Profile Gap Check (USCDI v3)</h1>
|
| 22 |
+
<p class="lede">Finds FHIR R4 resource files still pinned to US Core 3.1.1 or 5.0.1, and the USCDI v3 patient elements they miss. 10 rules, offline, no PHI leaves your machine. Runs entirely in your browser — nothing is uploaded.</p>
|
| 23 |
+
<textarea id="src" spellcheck="false">{
|
| 24 |
+
"resourceType": "Bundle",
|
| 25 |
+
"id": "legacy-export-set",
|
| 26 |
+
"type": "collection",
|
| 27 |
+
"meta": {
|
| 28 |
+
"versionId": "3"
|
| 29 |
+
},
|
| 30 |
+
"entry": [
|
| 31 |
+
{
|
| 32 |
+
"resource": {
|
| 33 |
+
"resourceType": "Patient",
|
| 34 |
+
"id": "pt-9001",
|
| 35 |
+
"meta": {
|
| 36 |
+
"profile": [
|
| 37 |
+
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient|3.1.1"
|
| 38 |
+
]
|
| 39 |
+
},
|
| 40 |
+
"identifier": [
|
| 41 |
+
{
|
| 42 |
+
"type": {
|
| 43 |
+
"coding": [
|
| 44 |
+
{
|
| 45 |
+
"system": "http://hl7.org/fhir/v2/0203",
|
| 46 |
+
"code": "MR"
|
| 47 |
+
}
|
| 48 |
+
]
|
| 49 |
+
},
|
| 50 |
+
"system": "http://hospital.example.org/mrn",
|
| 51 |
+
"value": "9001"
|
| 52 |
+
}
|
| 53 |
+
],
|
| 54 |
+
"name": [{ "family": "Nowak", "given": ["Piotr"] }],
|
| 55 |
+
"gender": "male",
|
| 56 |
+
"birthDate": "1965-11-02"
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"resource": {
|
| 61 |
+
"resourceType": "Condition",
|
| 62 |
+
"id": "cond-9001-a",
|
| 63 |
+
"meta": {
|
| 64 |
+
"profile": [
|
| 65 |
+
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition|5.0.1"
|
| 66 |
+
]
|
| 67 |
+
},
|
| 68 |
+
"subject": { "reference": "Patient/pt-9001" }
|
| 69 |
+
}
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"resource": {
|
| 73 |
+
"resourceType": "Observation",
|
| 74 |
+
"id": "obs-9001-a",
|
| 75 |
+
"meta": {
|
| 76 |
+
"profile": [
|
| 77 |
+
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab"
|
| 78 |
+
]
|
| 79 |
+
},
|
| 80 |
+
"status": "final",
|
| 81 |
+
"subject": { "reference": "Patient/pt-9001" }
|
| 82 |
+
}
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"resource": {
|
| 86 |
+
"resourceType": "CapabilityStatement",
|
| 87 |
+
"id": "cap-legacy",
|
| 88 |
+
"status": "active",
|
| 89 |
+
"kind": "instance",
|
| 90 |
+
"fhirVersion": "3.0.2",
|
| 91 |
+
"format": ["json"],
|
| 92 |
+
"instantiates": [
|
| 93 |
+
"http://hl7.org/fhir/STU3/capabilitystatement.html"
|
| 94 |
+
]
|
| 95 |
+
}
|
| 96 |
+
}
|
| 97 |
+
]
|
| 98 |
+
}</textarea>
|
| 99 |
+
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
|
| 100 |
+
<div id="out" aria-live="polite"></div>
|
| 101 |
+
<div id="paid"><strong>Free here:</strong> Scan every FHIR JSON resource in the workspace and see each US Core profile gap on its own line, with the USCDI version that pin actually meets. <strong>In the editor:</strong> Export the whole workspace as one conformance report file - every resource, its profile pin and the USCDI v3 element it misses - to attach to a certification or customer audit. — that part asks for a licence key.</div>
|
| 102 |
+
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
|
| 103 |
+
</div>
|
| 104 |
+
<script>var USCORE_RULES = [
|
| 105 |
+
{"id": "uscore_v1_pin", "sev": "error", "msg": "Profile pinned to US Core 3.1.1 - that is the USCDI v1 element set. Certified health IT has had to carry USCDI v3 since 2026-01-01."},
|
| 106 |
+
{"id": "uscore_v2_pin", "sev": "error", "msg": "Profile pinned to US Core 5.0.1 - that is the USCDI v2 element set. USCDI v3 needs US Core 6.1.0 or above."},
|
| 107 |
+
{"id": "unpinned_profile", "sev": "warn", "msg": "US Core profile claimed with no |version. Nothing in this file proves which USCDI version you meet at test time."},
|
| 108 |
+
{"id": "no_meta_profile", "sev": "error", "msg": "US Core resource type with no us-core profile in meta.profile. An unlabelled resource is not a conformance claim."},
|
| 109 |
+
{"id": "pre_r4_url", "sev": "error", "msg": "DSTU2 or STU3 artefact in an R4 resource set. US Core 6.1.0 is FHIR R4 (4.0.1) only."},
|
| 110 |
+
{"id": "legacy_terminology_url", "sev": "warn", "msg": "Legacy hl7.org/fhir/v2 or /v3 code system URL. R4 moved these to terminology.hl7.org/CodeSystem."},
|
| 111 |
+
{"id": "missing_race_ethnicity", "sev": "error", "msg": "Patient carries no us-core-race and us-core-ethnicity extension. Race and ethnicity are required USCDI Patient Demographics elements."},
|
| 112 |
+
{"id": "missing_sogi", "sev": "error", "msg": "Patient carries no us-core-genderIdentity extension. Gender identity is one of the elements USCDI v3 added over v2."},
|
| 113 |
+
{"id": "capability_fhir_version", "sev": "error", "msg": "CapabilityStatement.fhirVersion is not 4.0.1, so the server advertises a version US Core 6.1.0 does not profile."},
|
| 114 |
+
{"id": "no_last_updated", "sev": "warn", "msg": "meta block with no lastUpdated. Surveyors cannot date the resource against the 2026-01-01 USCDI v3 line."}
|
| 115 |
+
]
|
| 116 |
+
;</script>
|
| 117 |
+
<script>// US Core Profile Gap Check - one brain, used by the extension and by the web page.
|
| 118 |
+
const RULES = (typeof module !== 'undefined' && module.exports)
|
| 119 |
+
? require('./rules.json')
|
| 120 |
+
: window.USCORE_RULES;
|
| 121 |
+
|
| 122 |
+
const RULE_COUNT = RULES.length;
|
| 123 |
+
|
| 124 |
+
// Resource types US Core 6.1.0 profiles and USCDI v3 expects to be labelled.
|
| 125 |
+
const US_CORE_TYPES = [
|
| 126 |
+
'Patient', 'Encounter', 'Condition', 'Observation', 'AllergyIntolerance',
|
| 127 |
+
'MedicationRequest', 'Immunization', 'Procedure', 'DiagnosticReport',
|
| 128 |
+
'DocumentReference', 'CarePlan', 'CareTeam', 'Goal', 'Location',
|
| 129 |
+
'Organization', 'Practitioner', 'Device', 'Coverage', 'ServiceRequest',
|
| 130 |
+
'QuestionnaireResponse', 'RelatedPerson', 'Specimen', 'Provenance'
|
| 131 |
+
];
|
| 132 |
+
|
| 133 |
+
const USCDI_V3_FLOOR = '6.1.0';
|
| 134 |
+
const DEADLINE = '2026-01-01';
|
| 135 |
+
|
| 136 |
+
function msgOf(id) {
|
| 137 |
+
const r = RULES.find(function (x) { return x.id === id; });
|
| 138 |
+
return r ? r.msg : id;
|
| 139 |
+
}
|
| 140 |
+
function sevOf(id) {
|
| 141 |
+
const r = RULES.find(function (x) { return x.id === id; });
|
| 142 |
+
return r ? r.sev : 'warn';
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
function daysSince(from, today) {
|
| 146 |
+
if (!today) return null;
|
| 147 |
+
const a = Date.parse(from + 'T00:00:00Z');
|
| 148 |
+
const b = Date.parse(today + 'T00:00:00Z');
|
| 149 |
+
if (isNaN(a) || isNaN(b)) return null;
|
| 150 |
+
return Math.round((b - a) / 86400000);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
function check(text, opts) {
|
| 154 |
+
opts = opts || {};
|
| 155 |
+
const src = String(text == null ? '' : text);
|
| 156 |
+
const lines = src.split(/\r?\n/);
|
| 157 |
+
// Flattened copy: JSON is hard-wrapped by every formatter, so every
|
| 158 |
+
// whole-document test runs against one space-normalised string.
|
| 159 |
+
const flat = src.replace(/\s+/g, ' ');
|
| 160 |
+
const findings = [];
|
| 161 |
+
|
| 162 |
+
function lineOf(re) {
|
| 163 |
+
for (let i = 0; i < lines.length; i++) {
|
| 164 |
+
if (re.test(lines[i])) return i + 1;
|
| 165 |
+
}
|
| 166 |
+
return 1;
|
| 167 |
+
}
|
| 168 |
+
function push(id, line, extra) {
|
| 169 |
+
findings.push({
|
| 170 |
+
check: id,
|
| 171 |
+
sev: sevOf(id),
|
| 172 |
+
msg: extra ? msgOf(id) + ' ' + extra : msgOf(id),
|
| 173 |
+
line: line || 1
|
| 174 |
+
});
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
// 1 + 2 + 3: what version does each us-core profile claim actually pin?
|
| 178 |
+
// Only meta.profile is a conformance claim - the same StructureDefinition URL
|
| 179 |
+
// under an extension "url" is a definition reference and carries no version.
|
| 180 |
+
const claimRe = /"profile"\s*:\s*(\[[\s\S]*?\]|"[^"]*")/g;
|
| 181 |
+
const profileRe = /https?:\/\/hl7\.org\/fhir\/us\/core\/StructureDefinition\/([A-Za-z0-9-]+)(\|([0-9][0-9A-Za-z.\-]*))?/g;
|
| 182 |
+
let m, sawProfile = false;
|
| 183 |
+
while ((m = claimRe.exec(src)) !== null) {
|
| 184 |
+
const block = m[1];
|
| 185 |
+
const base = m.index + m[0].indexOf(block);
|
| 186 |
+
let p;
|
| 187 |
+
profileRe.lastIndex = 0;
|
| 188 |
+
while ((p = profileRe.exec(block)) !== null) {
|
| 189 |
+
sawProfile = true;
|
| 190 |
+
const name = p[1];
|
| 191 |
+
const ver = p[3];
|
| 192 |
+
const at = src.slice(0, base + p.index).split(/\r?\n/).length;
|
| 193 |
+
if (!ver) {
|
| 194 |
+
push('unpinned_profile', at, '(' + name + ')');
|
| 195 |
+
} else if (/^3\./.test(ver)) {
|
| 196 |
+
push('uscore_v1_pin', at, '(' + name + '|' + ver + ' -> needs ' + USCDI_V3_FLOOR + ')');
|
| 197 |
+
} else if (/^[45]\./.test(ver)) {
|
| 198 |
+
push('uscore_v2_pin', at, '(' + name + '|' + ver + ' -> needs ' + USCDI_V3_FLOOR + ')');
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
// 4: a US Core resource type that never claims a us-core profile at all.
|
| 204 |
+
const typeRe = /"resourceType"\s*:\s*"([A-Za-z]+)"/g;
|
| 205 |
+
const seenTypes = [];
|
| 206 |
+
while ((m = typeRe.exec(src)) !== null) {
|
| 207 |
+
if (US_CORE_TYPES.indexOf(m[1]) !== -1 && seenTypes.indexOf(m[1]) === -1) {
|
| 208 |
+
seenTypes.push(m[1]);
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
if (seenTypes.length && !sawProfile) {
|
| 212 |
+
push('no_meta_profile', lineOf(/"resourceType"/), '(' + seenTypes.join(', ') + ')');
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
// 5: pre-R4 artefacts.
|
| 216 |
+
if (/hl7\.org\/fhir\/(STU3|DSTU2)\//.test(flat) || /"fhirVersion"\s*:\s*"[123]\./.test(flat)) {
|
| 217 |
+
push('pre_r4_url', lineOf(/(STU3|DSTU2)|"fhirVersion"\s*:\s*"[123]\./));
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
// 6: terminology URLs R4 retired.
|
| 221 |
+
if (/hl7\.org\/fhir\/v[23]\//.test(flat)) {
|
| 222 |
+
push('legacy_terminology_url', lineOf(/hl7\.org\/fhir\/v[23]\//));
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
// 7 + 8: USCDI Patient Demographics, including the elements v3 added over v2.
|
| 226 |
+
const hasPatient = /"resourceType"\s*:\s*"Patient"/.test(flat);
|
| 227 |
+
if (hasPatient) {
|
| 228 |
+
if (!/us-core-race/.test(flat) || !/us-core-ethnicity/.test(flat)) {
|
| 229 |
+
push('missing_race_ethnicity', lineOf(/"resourceType"\s*:\s*"Patient"/));
|
| 230 |
+
}
|
| 231 |
+
if (!/us-core-genderIdentity/.test(flat)) {
|
| 232 |
+
push('missing_sogi', lineOf(/"resourceType"\s*:\s*"Patient"/));
|
| 233 |
+
}
|
| 234 |
+
}
|
| 235 |
+
|
| 236 |
+
// 9: the version the server advertises.
|
| 237 |
+
if (/"resourceType"\s*:\s*"CapabilityStatement"/.test(flat)) {
|
| 238 |
+
const fv = flat.match(/"fhirVersion"\s*:\s*"([^"]+)"/);
|
| 239 |
+
if (!fv || fv[1] !== '4.0.1') {
|
| 240 |
+
push('capability_fhir_version', lineOf(/"fhirVersion"/), '(found ' + (fv ? fv[1] : 'nothing') + ')');
|
| 241 |
+
}
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
// 10: can a surveyor date this resource against the line?
|
| 245 |
+
if (/"meta"\s*:/.test(flat) && !/"lastUpdated"\s*:/.test(flat)) {
|
| 246 |
+
push('no_last_updated', lineOf(/"meta"\s*:/));
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
const since = daysSince(DEADLINE, opts.today);
|
| 250 |
+
if (since !== null && findings.length) {
|
| 251 |
+
findings.forEach(function (f) {
|
| 252 |
+
if (f.sev === 'error' && !/day/.test(f.msg)) {
|
| 253 |
+
f.msg = f.msg + ' USCDI v3 line passed ' + since + ' days ago.';
|
| 254 |
+
}
|
| 255 |
+
});
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
return { findings: findings };
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
const engine = { check: check };
|
| 262 |
+
|
| 263 |
+
if (typeof module !== 'undefined' && module.exports) {
|
| 264 |
+
module.exports = { engine: engine, RULES: RULES, RULE_COUNT: RULE_COUNT };
|
| 265 |
+
}
|
| 266 |
+
if (typeof window !== 'undefined') {
|
| 267 |
+
window.USCOREENGINE = { engine: engine, RULES: RULES, RULE_COUNT: RULE_COUNT };
|
| 268 |
+
}
|
| 269 |
+
</script>
|
| 270 |
+
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
|
| 271 |
+
'use strict';
|
| 272 |
+
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
|
| 273 |
+
function summaryLine(res) {
|
| 274 |
+
const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
|
| 275 |
+
return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
|
| 276 |
+
}
|
| 277 |
+
function toText(res, label) {
|
| 278 |
+
const f = (res && res.findings) || [];
|
| 279 |
+
const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
|
| 280 |
+
f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); });
|
| 281 |
+
return lines.join('\n');
|
| 282 |
+
}
|
| 283 |
+
function toHtml(res) {
|
| 284 |
+
const f = (res && res.findings) || [];
|
| 285 |
+
if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
|
| 286 |
+
const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');
|
| 287 |
+
return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';
|
| 288 |
+
}
|
| 289 |
+
var USCOREREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
|
| 290 |
+
if (typeof module !== 'undefined' && module.exports) module.exports = USCOREREPORT;
|
| 291 |
+
else window.USCOREREPORT = USCOREREPORT;
|
| 292 |
+
</script>
|
| 293 |
+
<script>
|
| 294 |
+
(function(){
|
| 295 |
+
var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
|
| 296 |
+
today.value=new Date().toISOString().slice(0,10);
|
| 297 |
+
function run(){ try { var res=window.USCOREENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.USCOREREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
|
| 298 |
+
go.onclick=run; if (src.value.trim()) run();
|
| 299 |
+
})();
|
| 300 |
+
</script>
|
| 301 |
+
|
| 302 |
+
<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind US Core Profile Gap Check (USCDI v3) every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"uscore-profile-gap-lint",lang:"en",source:"rule_alert"})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script></section>
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/uscore-profile-gap-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'uscore-profile-gap-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/uscore-profile-gap-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'uscore-profile-gap-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/uscore-profile-gap-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'uscore-profile-gap-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/uscore-profile-gap-lint <file>
|
| 306 |
+
docker run --rm -v "$PWD:/w" getreadystack/uscore-profile-gap-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>
|
| 307 |
+
<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Finds the FHIR R4 resources still pinned to US Core 3.1.1 or 5.0.1, and the USCDI v3 Patient elements they never carried.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A US FHIR consultant averages $49.72/hour (ZipRecruiter, 31 July 2026); reading a resource set by hand takes hours.</p><a href="https://buy.polar.sh/polar_cl_hiGlxcgqsijQYOSCbWd96m5roAeXS4jd5pGkt0elCAc" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>
|
| 308 |
+
<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does US Core Profile Gap Check actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads the FHIR R4 JSON files in your workspace and applies 10 rules. It flags meta.profile pins on US Core 3.1.1 (USCDI v1) and 5.0.1 (USCDI v2), profiles claimed with no version at all, pre-R4 STU3 and DSTU2 artefacts, retired v2 and v3 terminology URLs, Patient resources missing race, ethnicity or gender identity, and a CapabilityStatement whose fhirVersion is not 4.0.1.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Health IT developers and FHIR integration engineers at US EHR vendors, payers and digital health companies. If your product carries an ONC certification, or you are preparing a Health IT Module for testing, you are the reader. It recognises 23 US Core resource types, so it fits a working repository rather than a single sample file.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why will a free FHIR validator not catch this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">The official HL7 validator checks a resource against whichever profile you hand it. Pin us-core-patient 3.1.1 and it will happily tell you the resource is valid, because it is valid against USCDI v1. Nothing in that run says the version you pinned stopped being the certification floor on 2026-01-01.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs the full version?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free finishes the job on screen: every gap in every resource, on its own line, with the USCDI version that pin meets. On the dirty sample shipped with the extension that is 9 findings, 6 of them errors. The full version exports the same scan as one conformance report file you can attach to a certification or a customer audit.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does it cost to do this by hand?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A US FHIR consultant averages $49.72 an hour and most earn between $24.28 and $62.50, according to ZipRecruiter figures published on 31 July 2026. Opening each resource, reading the profile pin and checking it against the US Core 6.1.0 element list is an afternoon on any real repository. The full version is $29 once.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does US Core Profile Gap Check actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads the FHIR R4 JSON files in your workspace and applies 10 rules. It flags meta.profile pins on US Core 3.1.1 (USCDI v1) and 5.0.1 (USCDI v2), profiles claimed with no version at all, pre-R4 STU3 and DSTU2 artefacts, retired v2 and v3 terminology URLs, Patient resources missing race, ethnicity or gender identity, and a CapabilityStatement whose fhirVersion is not 4.0.1."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Health IT developers and FHIR integration engineers at US EHR vendors, payers and digital health companies. If your product carries an ONC certification, or you are preparing a Health IT Module for testing, you are the reader. It recognises 23 US Core resource types, so it fits a working repository rather than a single sample file."}}, {"@type": "Question", "name": "Why will a free FHIR validator not catch this?", "acceptedAnswer": {"@type": "Answer", "text": "The official HL7 validator checks a resource against whichever profile you hand it. Pin us-core-patient 3.1.1 and it will happily tell you the resource is valid, because it is valid against USCDI v1. Nothing in that run says the version you pinned stopped being the certification floor on 2026-01-01."}}, {"@type": "Question", "name": "What is free and what needs the full version?", "acceptedAnswer": {"@type": "Answer", "text": "Free finishes the job on screen: every gap in every resource, on its own line, with the USCDI version that pin meets. On the dirty sample shipped with the extension that is 9 findings, 6 of them errors. The full version exports the same scan as one conformance report file you can attach to a certification or a customer audit."}}, {"@type": "Question", "name": "What does it cost to do this by hand?", "acceptedAnswer": {"@type": "Answer", "text": "A US FHIR consultant averages $49.72 an hour and most earn between $24.28 and $62.50, according to ZipRecruiter figures published on 31 July 2026. Opening each resource, reading the profile pin and checking it against the US Core 6.1.0 element list is an afternoon on any real repository. The full version is $29 once."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:0,slug:"uscore-profile-gap-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence, 7-day refund.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/dsa-terms-lint"><span class="yj-rel-t">DSA Terms Lint - EU Digital Services Act</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/hmrc-fraud-prevention-header-lint"><span class="yj-rel-t">HMRC Fraud Prevention Header Lint for Making Tax Digital (VAT and Income Tax)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/crypto-1099da-basis-gap"><span class="yj-rel-t">1099-DA Basis Gap Checker (2026)</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/agency-website-template"><span class="yj-rel-t">Agency Website Template — 7-Page Digital Marketing Agency Site (Plain HTML, No</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/canada-payroll-2026-gap-check"><span class="yj-rel-t">Canada Payroll 2026 Gap Check (CPP2 & EI)</span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/companies-house-idv-deadline-2026"><span class="yj-rel-t">Companies House ID Verification Deadline Checker (UK, 2026)</span><span class="yj-rel-p">$60</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script>
|
| 309 |
+
|
| 310 |
+
<div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>
|
| 311 |
+
<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script>
|
| 312 |
+
|
| 313 |
+
<script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script>
|
| 314 |
+
</body>
|
| 315 |
</html>
|