File size: 43,525 Bytes
7c58acb
7d51779
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7c58acb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Dependency end of support Dates — check dependency support dates</title>
<meta name="description" content="This free tool checks package manifests for listed framework and library versions that are past or near their published end-of-support dates.">
<style>
:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}
.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}
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}
.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}
input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}
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}
.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}
.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}
</style>
<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>
<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/dependency-checker-eol-dates"></head>
<body>
<div class="wrap">
<h1>Dependency end of support Dates — check dependency support dates</h1>
<p class="lede">Dependency checker for package.json, composer.json and requirements.txt: flags Angular, Express 4, ESLint 8, Vue 2, Laravel and Django versions past or near their published end-of-support date. Runs entirely in your browser — nothing is uploaded.</p>
<textarea id="src" spellcheck="false">{
  "name": "client-portal",
  "version": "3.4.0",
  "private": true,
  "scripts": {
    "start": "ng serve",
    "api": "node server/index.js",
    "lint": "eslint ."
  },
  "dependencies": {
    "@angular/common": "^19.2.0",
    "@angular/core": "^19.2.0",
    "@angular/upgrade": "^19.2.0",
    "angular": "1.8.3",
    "bootstrap": "^4.6.2",
    "express": "^4.21.2",
    "request": "^2.88.2",
    "rxjs": "~7.8.0",
    "zone.js": "~0.15.0"
  },
  "devDependencies": {
    "eslint": "^8.57.0",
    "typescript": "~5.6.3"
  }
}</textarea>
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
<div id="out" aria-live="polite"></div>
<div id="paid"><strong>Free here:</strong> Checks the open manifest and lists every pinned framework major that is past or within 120 days of its end-of-support date, with the date and the upgrade target. <strong>In the editor:</strong> Scans every package.json, composer.json and requirements file in the workspace at once and exports one dated EOL report (CSV + Markdown) for a client or audit. — that part asks for a licence key. <a href="https://getreadystack.com/api/buy/cl/polar_cl_Zm5aHGvUSteeXkwq8xhpNGDo1hwHYtpcqfNSa21xZvj">Get the full version — workspace scan + dated EOL report, $29</a> · $29 once · one licence key per person or team seat. Snyk Team is listed at $25 per contributing developer per month.</div>
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
</div>
<script>var DEOL_RULES = [
 {"id":"angularjs-eol","eco":"npm","pkg":"angular","min":"0.0","max":"1.999","eol":"2021-12-31","warn_days":120,"what":"AngularJS 1.x","fix":"migrate to @angular/core ^21","src":"angularjs.org (end of long-term support 2021-12-31)"},
 {"id":"angular-16-eol","eco":"npm","pkg":"@angular/core","min":"2.0","max":"16.999","eol":"2024-11-08","warn_days":120,"what":"Angular 16 or older","fix":"^21","src":"angular.dev/reference/releases"},
 {"id":"angular-17-eol","eco":"npm","pkg":"@angular/core","min":"17.0","max":"17.999","eol":"2025-05-15","warn_days":120,"what":"Angular 17","fix":"^21","src":"angular.dev/reference/releases"},
 {"id":"angular-18-eol","eco":"npm","pkg":"@angular/core","min":"18.0","max":"18.999","eol":"2025-11-21","warn_days":120,"what":"Angular 18","fix":"^21","src":"angular.dev/reference/releases"},
 {"id":"angular-19-eol","eco":"npm","pkg":"@angular/core","min":"19.0","max":"19.999","eol":"2026-05-19","warn_days":120,"what":"Angular 19","fix":"^21","src":"angular.dev/reference/releases"},
 {"id":"angular-20-eol","eco":"npm","pkg":"@angular/core","min":"20.0","max":"20.999","eol":"2026-11-21","warn_days":120,"what":"Angular 20 LTS","fix":"^21","src":"angular.dev/reference/releases (LTS ends November 2026)"},
 {"id":"vue-2-eol","eco":"npm","pkg":"vue","min":"0.0","max":"2.999","eol":"2023-12-31","warn_days":120,"what":"Vue 2","fix":"^3.5","src":"v2.vuejs.org/eol"},
 {"id":"nuxt-2-eol","eco":"npm","pkg":"nuxt","min":"0.0","max":"2.999","eol":"2024-06-30","warn_days":120,"what":"Nuxt 2","fix":"^4","src":"nuxt.com (Nuxt 2 end of life 2024-06-30)"},
 {"id":"bootstrap-4-eol","eco":"npm","pkg":"bootstrap","min":"0.0","max":"4.999","eol":"2023-01-01","warn_days":120,"what":"Bootstrap 4 or older","fix":"^5.3","src":"getbootstrap.com release schedule"},
 {"id":"express-4-eol","eco":"npm","pkg":"express","min":"4.0","max":"4.999","eol":"2026-10-01","warn_days":120,"what":"Express 4 (maintenance)","label":"2026-10-01 (target, no sooner than)","fix":"^5.1","src":"expressjs.com/en/support"},
 {"id":"eslint-8-eol","eco":"npm","pkg":"eslint","min":"0.0","max":"8.999","eol":"2024-10-05","warn_days":120,"what":"ESLint 8 or older","fix":"^9 (flat config)","src":"eslint.org/version-support"},
 {"id":"request-deprecated","eco":"npm","pkg":"request","min":"0.0","max":"999.0","eol":"2020-02-11","warn_days":120,"what":"request (deprecated package)","fix":"native fetch or undici","src":"github.com/request/request#deprecated"},
 {"id":"react-scripts-deprecated","eco":"npm","pkg":"react-scripts","min":"0.0","max":"999.0","eol":"2025-02-14","warn_days":120,"what":"Create React App (react-scripts)","fix":"Vite or a React framework","src":"react.dev/blog/2025/02/14/sunsetting-create-react-app"},
 {"id":"django-3-eol","eco":"pypi","pkg":"django","min":"0.0","max":"3.999","eol":"2024-04-01","warn_days":120,"what":"Django 3.2 or older","label":"April 2024","fix":"Django 5.2 LTS","src":"djangoproject.com/download (supported versions)"},
 {"id":"django-4-eol","eco":"pypi","pkg":"django","min":"4.0","max":"4.999","eol":"2026-04-01","warn_days":120,"what":"Django 4.x (4.2 LTS)","label":"April 2026","fix":"Django 5.2 LTS","src":"djangoproject.com/download (supported versions)"},
 {"id":"django-51-eol","eco":"pypi","pkg":"django","min":"5.0","max":"5.1","eol":"2025-12-01","warn_days":120,"what":"Django 5.0 / 5.1","label":"December 2025","fix":"Django 5.2 LTS","src":"djangoproject.com/download (supported versions)"},
 {"id":"laravel-9-eol","eco":"composer","pkg":"laravel/framework","min":"0.0","max":"9.999","eol":"2024-02-06","warn_days":120,"what":"Laravel 9 or older","fix":"^12","src":"laravel.com/docs/releases (support policy)"},
 {"id":"laravel-10-eol","eco":"composer","pkg":"laravel/framework","min":"10.0","max":"10.999","eol":"2025-02-04","warn_days":120,"what":"Laravel 10","fix":"^12","src":"laravel.com/docs/releases (support policy)"},
 {"id":"laravel-11-eol","eco":"composer","pkg":"laravel/framework","min":"11.0","max":"11.999","eol":"2026-03-12","warn_days":120,"what":"Laravel 11","fix":"^12","src":"laravel.com/docs/releases (support policy)"}
]
;</script>
<script>// Dependency Checker — EOL Dates · one brain for the VS Code extension and the free web page.
(function () {
  var RULES = (typeof module !== 'undefined') ? require('./rules.json') : window.DEOL_RULES;
  var DAY = 86400000;
  var SECTIONS = /"(dependencies|devDependencies|peerDependencies|optionalDependencies|require|require-dev)"\s*:\s*\{/;

  function num(v) {
    var m = String(v).match(/(\d+)(?:\.(\d+))?/);
    if (!m) return null;
    return parseInt(m[1], 10) * 1000 + (m[2] ? parseInt(m[2], 10) : 0);
  }
  function specNum(spec) {
    var s = String(spec).trim();
    if (!/^[\^~><=v\s]*\d/.test(s)) return null;   // skip "*", "latest", git urls, workspace:
    return num(s);
  }
  function toDay(s) {
    var t = Date.parse(String(s || '').slice(0, 10) + 'T00:00:00Z');
    return isNaN(t) ? null : t;
  }
  function norm(eco, name) {
    return eco === 'pypi' ? name.toLowerCase().replace(/[_.]+/g, '-') : name.toLowerCase();
  }

  // → [{eco, name, spec, line}]
  function parseDeps(text) {
    var lines = String(text).replace(/\r/g, '').split('\n');
    var out = [];
    var isJson = /^\s*\{/.test(text);
    if (isJson) {
      var composer = /"require(-dev)?"\s*:/.test(text) && !/"dependencies"\s*:/.test(text);
      var depth = 0, inSec = false;
      lines.forEach(function (ln, i) {
        if (!inSec && SECTIONS.test(ln)) { inSec = true; depth = 0; }
        if (inSec) {
          var m = ln.match(/^\s*"([^"]+)"\s*:\s*"([^"]*)"/);
          if (m && depth === 1) out.push({ eco: composer ? 'composer' : 'npm', name: m[1], spec: m[2], line: i + 1 });
          depth += (ln.match(/\{/g) || []).length - (ln.match(/\}/g) || []).length;
          if (depth <= 0) inSec = false;
        }
      });
    } else {
      lines.forEach(function (ln, i) {
        var s = ln.replace(/#.*/, '').trim();
        if (!s || s[0] === '-') return;
        var m = s.match(/^([A-Za-z0-9][A-Za-z0-9._-]*)(?:\[[^\]]*\])?\s*(==|~=|>=|===|<=|<|>|!=)?\s*([^;,\s]*)/);
        if (m && m[2] && m[3]) out.push({ eco: 'pypi', name: m[1], spec: m[3], line: i + 1 });
      });
    }
    return out;
  }

  function check(text, opts) {
    opts = opts || {};
    var today = toDay(opts.today) || toDay(new Date().toISOString());
    var findings = [];
    parseDeps(text).forEach(function (d) {
      var v = specNum(d.spec);
      if (v === null) return;
      RULES.forEach(function (r) {
        if (r.eco !== d.eco || norm(r.eco, r.pkg) !== norm(d.eco, d.name)) return;
        if (v < num(r.min) || v > num(r.max)) return;
        var eol = toDay(r.eol);
        var days = Math.round((eol - today) / DAY);
        var when = r.label || r.eol;
        var pin = d.name + ' ' + d.spec;
        if (days < 0) {
          findings.push({ check: r.id, sev: 'error', line: d.line,
            msg: r.what + ' (' + pin + ') is past end of support since ' + when + ' — ' + (-days) + ' days without security fixes. Upgrade: ' + r.fix + '. Source: ' + r.src });
        } else if (days <= r.warn_days) {
          findings.push({ check: r.id, sev: 'warning', line: d.line,
            msg: r.what + ' (' + pin + ') reaches end of support on ' + when + ' — in ' + days + ' days. Upgrade: ' + r.fix + '. Source: ' + r.src });
        }
      });
    });
    findings.sort(function (a, b) { return a.line - b.line; });
    return { findings: findings };
  }

  var api = { engine: { check: check, parseDeps: parseDeps }, RULES: RULES, RULE_COUNT: RULES.length };
  if (typeof window !== 'undefined') window.DEOL_ENGINE = api;
  if (typeof module !== 'undefined') module.exports = api;
})();
</script>
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
'use strict';
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }
function summaryLine(res) {
  const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
  return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
}
function toText(res, label) {
  const f = (res && res.findings) || [];
  const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
  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 || '')); });
  return lines.join('\n');
}
function toHtml(res) {
  const f = (res && res.findings) || [];
  if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
  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('');
  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>';
}
var DEOL_REPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
if (typeof module !== 'undefined' && module.exports) module.exports = DEOL_REPORT;
else window.DEOL_REPORT = DEOL_REPORT;
</script>
<script>
(function(){
  var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
  today.value=new Date().toISOString().slice(0,10);
  function run(){ try { var res=window.DEOL_ENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.DEOL_REPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
  go.onclick=run; if (src.value.trim()) run();
})();
</script>


<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/dependency-checker-eol-dates" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'dependency-checker-eol-dates',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/dependency-checker-eol-dates" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'dependency-checker-eol-dates',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/dependency-checker-eol-dates" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'dependency-checker-eol-dates',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/dependency-checker-eol-dates &lt;file&gt;
docker run --rm -v &quot;$PWD:/w&quot; getreadystack/dependency-checker-eol-dates /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/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>
<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 Dependency Checker — EOL Dates 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:"dependency-checker-eol-dates",lang:"en",source:"rule_alert"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).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><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section>

<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">Dependency checker for package.json, composer.json and requirements.txt. On the sample package.json (Angular 19 + Express API, _fixtures/dirty.json) checked on 2026-09-28 it finds six depend</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">Snyk Team is listed at $25 per contributing developer per month ($300 a year each); this is $29 once.</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_Zm5aHGvUSteeXkwq8xhpNGDo1hwHYtpcqfNSa21xZvj" 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>
<!--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>
<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>

<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><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 {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[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><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><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-28">Updated 2026-09-28</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-28","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku358482_result_card.jpg" alt="Dependency Checker — EOL Dates" loading="lazy" style="max-width:100%;border-radius:6px"></p>
<p>Dependency checker result: six dependencies in a sample Angular and Express package.json are past or near end of support. Five are already past their published end date, and Express 4 reaches its end-of-support target on 2026-10-01. If you are an agency or freelance web developer maintaining client apps in the US, the UK or the EU, this is the list your client&#x27;s security reviewer will ask for.</p>
<h3>The file</h3>
<p>The sample is an ordinary Angular 19 app with an Express API and an AngularJS module still running through ngUpgrade. It builds, it deploys and every test passes. Here is what the dependency checker printed on 2026-09-28:</p>
<table><thead><tr><th>Pinned line</th><th>Support end and fix</th></tr></thead><tbody><tr><td>&quot;express&quot;: &quot;^4.21.2&quot;</td><td>EOL target 2026-10-01 (no sooner than) → ^5.1</td></tr><tr><td>&quot;@angular/core&quot;: &quot;^19.2.0&quot;</td><td>ended 2026-05-19 → ^21</td></tr><tr><td>&quot;eslint&quot;: &quot;^8.57.0&quot;</td><td>ended 2024-10-05 → ^9</td></tr><tr><td>&quot;bootstrap&quot;: &quot;^4.6.2&quot;</td><td>ended 2023-01-01 → ^5.3</td></tr><tr><td>&quot;angular&quot;: &quot;1.8.3&quot;</td><td>ended 2021-12-31 → @angular/core ^21</td></tr><tr><td>&quot;request&quot;: &quot;^2.88.2&quot;</td><td>deprecated 2020-02-11 → native fetch</td></tr></tbody></table>
<p>Five errors, one warning. The upgraded version of the same file returns zero findings.</p>
<h3>Why npm outdated did not catch it</h3>
<p>npm outdated compares your pin with the newest release. It will tell you that 21 is newer than 19. It will not tell you that 19 stopped getting security patches on 2026-05-19, or that Express marks 2026-10-01 as the earliest end of life for version 4. pip list --outdated and composer outdated work the same way. Nothing breaks on the end date, so nothing in your pipeline goes red.</p>
<p>The dates live on a different page for every project: angular.dev, expressjs.com/en/support, eslint.org/version-support, djangoproject.com, laravel.com/docs/releases. Code assistants make it worse in one specific way: they suggest the majors they saw most in training, so a project scaffolded this year can start on a line that is already out of support.</p>
<h3>What the checker does</h3>
<p>The extension stores 19 rules. Each one is a package, a version range, an end date and the page the date came from:</p>
<ul><li>npm: AngularJS 1.x, Angular 16 and older, 17, 18, 19 and 20, Vue 2, Nuxt 2, Bootstrap 4 and older, Express 4, ESLint 8 and older, request, react-scripts</li><li>pip: Django 3.2 and older, Django 4.x, Django 5.0 and 5.1</li><li>Composer: Laravel 9 and older, Laravel 10, Laravel 11</li></ul>
<p>It reads the first version number of each range, compares it with today&#x27;s date and reports past dates as errors and dates within 120 days as warnings. Change the date and the answer changes: the same package.json checked on 2026-05-01 shows Express 4 as clear and Angular 19 as a warning, because the end dates are now 153 and 18 days away.</p>
<pre><code>WARN L16 express-4-eol  Express 4 (express ^4.21.2) reaches end of support on 2026-10-01 (target, no sooner than)
ERRO L12 angular-19-eol Angular 19 (@angular/core ^19.2.0) is past end of support since 2026-05-19</code></pre>
<h3>Free and full</h3>
<p>The free extension and the free web page check the manifest you open and show every finding, every date and every upgrade target. Nothing is uploaded. The full version scans every package.json, composer.json and requirements file in a workspace in one run and exports a single dated report as CSV and Markdown, the file you hand to a client or an auditor. For comparison, Snyk Team is listed at $25 per contributing developer per month; it focuses on known vulnerabilities rather than end-of-support dates.</p>
<p>Open your own package.json before 2026-10-01 and look for the Express line first.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku358482_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku358482_short.mp4" type="video/mp4"></video><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 the Dependency Checker — EOL Dates extension do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads package.json, composer.json and requirements.txt, takes the version you pinned for Angular, AngularJS, Vue, Nuxt, Bootstrap, Express, ESLint, request, react-scripts, Django and Laravel, and compares it with 19 published end-of-support dates. Past dates become errors, dates within 120 days become warnings, and each finding names the date, its source and the version to upgrade to.</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 dependency checker for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Agency and freelance web developers who maintain client apps built on Angular, Express, Django or Laravel, and the tech leads who must answer &#x27;is anything we ship out of support?&#x27; before a security review, a renewal or a handover. It also suits anyone reviewing a project an AI assistant scaffolded, because generated manifests often pin older majors.</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 not just use npm outdated or Dependabot?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">npm outdated, pip list --outdated and composer outdated compare your pin with the newest release; they never print the date your current major stops receiving security fixes. Angular 19 still builds after its 2026-05-19 end date, so nothing fails. This extension stores each end date and source, so the finding says exactly when support ended or will end.</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 does the full version add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free, with no key: checking the open manifest in VS Code or on the web page, with every finding, date and upgrade target shown. The full version, $29 once with one licence key per person or team seat, scans every manifest in the workspace in one run and exports a single dated EOL report as CSV and Markdown for a client or an 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 the alternative cost?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Snyk Team is listed at $25 per contributing developer per month, which is $300 a year for each developer; it focuses on known vulnerabilities rather than end-of-support dates. Checking by hand means opening angular.dev, expressjs.com, eslint.org, djangoproject.com and laravel.com for every project. The full version of this extension is a one-time $29 licence.</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 not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Dependency Checker — EOL Dates checks the file you open against 19 rules from a rule set dated 2026-09-28, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does the Dependency Checker — EOL Dates extension do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads package.json, composer.json and requirements.txt, takes the version you pinned for Angular, AngularJS, Vue, Nuxt, Bootstrap, Express, ESLint, request, react-scripts, Django and Laravel, and compares it with 19 published end-of-support dates. Past dates become errors, dates within 120 days become warnings, and each finding names the date, its source and the version to upgrade to."}}, {"@type": "Question", "name": "Who is this dependency checker for?", "acceptedAnswer": {"@type": "Answer", "text": "Agency and freelance web developers who maintain client apps built on Angular, Express, Django or Laravel, and the tech leads who must answer 'is anything we ship out of support?' before a security review, a renewal or a handover. It also suits anyone reviewing a project an AI assistant scaffolded, because generated manifests often pin older majors."}}, {"@type": "Question", "name": "Why not just use npm outdated or Dependabot?", "acceptedAnswer": {"@type": "Answer", "text": "npm outdated, pip list --outdated and composer outdated compare your pin with the newest release; they never print the date your current major stops receiving security fixes. Angular 19 still builds after its 2026-05-19 end date, so nothing fails. This extension stores each end date and source, so the finding says exactly when support ended or will end."}}, {"@type": "Question", "name": "What is free and what does the full version add?", "acceptedAnswer": {"@type": "Answer", "text": "Free, with no key: checking the open manifest in VS Code or on the web page, with every finding, date and upgrade target shown. The full version, $29 once with one licence key per person or team seat, scans every manifest in the workspace in one run and exports a single dated EOL report as CSV and Markdown for a client or an audit."}}, {"@type": "Question", "name": "What does the alternative cost?", "acceptedAnswer": {"@type": "Answer", "text": "Snyk Team is listed at $25 per contributing developer per month, which is $300 a year for each developer; it focuses on known vulnerabilities rather than end-of-support dates. Checking by hand means opening angular.dev, expressjs.com, eslint.org, djangoproject.com and laravel.com for every project. The full version of this extension is a one-time $29 licence."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. Dependency Checker — EOL Dates checks the file you open against 19 rules from a rule set dated 2026-09-28, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files."}}]}</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:358482,slug:"dependency-checker-eol-dates",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.</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/angular-removed-api-lint"><span class="yj-rel-t">Angular Removed-API Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/dotnet-eol-support-gate"><span class="yj-rel-t">.NET EOL &amp; CRA Support Window Gate</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/base-image-eol-lint"><span class="yj-rel-t">Base Image EOL Lint - Dockerfile and CI end-of-life check</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/actions-deprecation-lint-2026"><span class="yj-rel-t">GitHub Actions Deprecation Lint: the 2026 runner and action EOL dates</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/play-release-blocker-lint"><span class="yj-rel-t">Google Play Release Blocker Lint - target API 36, Billing 8, 16 KB</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/spdx-license-field-lint"><span class="yj-rel-t">SPDX License Field Lint for package.json, pyproject.toml and Cargo.toml</span><span class="yj-rel-p">$29</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></body>
</html>