Spaces:
Running
Running
Upload index.html with huggingface_hub
Browse files- index.html +342 -17
index.html
CHANGED
|
@@ -1,19 +1,344 @@
|
|
| 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>DSA Terms Lint - EU Digital Services Act — 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/dsa-terms-lint"></head>
|
| 19 |
+
<body>
|
| 20 |
+
<div class="wrap">
|
| 21 |
+
<h1>DSA Terms Lint - EU Digital Services Act</h1>
|
| 22 |
+
<p class="lede">Reads your terms-of-service markdown and names every Digital Services Act duty it is missing, by article number. Runs entirely in your browser — nothing is uploaded.</p>
|
| 23 |
+
<textarea id="src" spellcheck="false"># Terms of Service - Loomcast
|
| 24 |
+
|
| 25 |
+
Last updated: 2023-11-02
|
| 26 |
+
|
| 27 |
+
Welcome to Loomcast, where anyone can publish a clip and follow other creators. By using Loomcast
|
| 28 |
+
you agree to these terms. We have tried to keep them short.
|
| 29 |
+
|
| 30 |
+
## 1. Your account
|
| 31 |
+
|
| 32 |
+
You must be able to form a binding contract to open an account. You are responsible for everything
|
| 33 |
+
posted from your account. Keep your password to yourself.
|
| 34 |
+
|
| 35 |
+
## 2. Your content
|
| 36 |
+
|
| 37 |
+
You keep ownership of what you upload and you give us a worldwide licence to host and show it.
|
| 38 |
+
Do not upload anything unlawful, hateful, or that you do not have the rights to.
|
| 39 |
+
|
| 40 |
+
## 3. Content moderation
|
| 41 |
+
|
| 42 |
+
We run content moderation across the service. We use automated tools to detect spam and copyright
|
| 43 |
+
matches, and flagged clips are reviewed by a person before we act. We may remove anything that
|
| 44 |
+
breaks these terms at our discretion.
|
| 45 |
+
|
| 46 |
+
## 4. Getting in touch
|
| 47 |
+
|
| 48 |
+
Questions about these terms go to support@loomcast.example and we answer as quickly as we can.
|
| 49 |
+
|
| 50 |
+
## 5. If we remove something
|
| 51 |
+
|
| 52 |
+
If we take a clip down, you may appeal our decision by email within six months of being notified,
|
| 53 |
+
and we will look at it again free of charge.
|
| 54 |
+
|
| 55 |
+
## 6. Payments
|
| 56 |
+
|
| 57 |
+
Paid plans renew monthly until cancelled. Refunds are handled under our refund policy.
|
| 58 |
+
|
| 59 |
+
## 7. Liability
|
| 60 |
+
|
| 61 |
+
Loomcast is provided as is. To the maximum extent permitted by law we are not liable for indirect
|
| 62 |
+
or consequential loss.
|
| 63 |
+
|
| 64 |
+
## 8. Changes to these terms
|
| 65 |
+
|
| 66 |
+
We will notify you by email before material changes to these terms take effect.
|
| 67 |
+
|
| 68 |
+
## 9. Governing law
|
| 69 |
+
|
| 70 |
+
These terms are governed by the laws of the State of Delaware, United States, and the courts of
|
| 71 |
+
Wilmington shall have exclusive jurisdiction.</textarea>
|
| 72 |
+
<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>
|
| 73 |
+
<div id="out" aria-live="polite"></div>
|
| 74 |
+
<div id="paid"><strong>Free here:</strong> Names every Digital Services Act duty missing from the terms file you have open, with the article number and the sentence that is absent.. <strong>In the editor:</strong> Scans every legal page and every language version in the workspace at once and exports a dated DSA gap report you can hand to counsel. — that part asks for a licence key.</div>
|
| 75 |
+
<p class="note">Same engine as the VS Code extension, byte for byte.</p>
|
| 76 |
+
</div>
|
| 77 |
+
<script>var DSA_RULES = [
|
| 78 |
+
{
|
| 79 |
+
"check": "art11_authority_contact",
|
| 80 |
+
"sev": "err",
|
| 81 |
+
"msg": "Art. 11 DSA: no single point of contact for Member State authorities, the Commission and the Board. Publish one electronic contact (email or form) and say it is for authorities.",
|
| 82 |
+
"need": ["single point of contact[^.]{0,120}(authorit|commission|board|digital services coordinator)", "point of contact for (member state )?authorit", "authorities may contact us (at|by|via)"]
|
| 83 |
+
},
|
| 84 |
+
{
|
| 85 |
+
"check": "art11_contact_languages",
|
| 86 |
+
"sev": "warn",
|
| 87 |
+
"msg": "Art. 11(3) DSA: the languages used for communication with authorities are not stated. Name them, and one must be an official language of your Member State of main establishment.",
|
| 88 |
+
"need": ["languages? (used |available )?for communicat", "we communicate with authorities in", "official language"]
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"check": "art12_recipient_contact",
|
| 92 |
+
"sev": "err",
|
| 93 |
+
"msg": "Art. 12 DSA: no single point of contact for users. Publish a direct contact for recipients of the service, separate from the authority contact.",
|
| 94 |
+
"need": ["point of contact for (users|recipients|customers)", "contact us[^.]{0,80}(support@|legal@|help@|privacy@|@)", "you can (reach|contact) us (at|by|via)[^.]{0,60}@"]
|
| 95 |
+
},
|
| 96 |
+
{
|
| 97 |
+
"check": "art12_human_channel",
|
| 98 |
+
"sev": "err",
|
| 99 |
+
"msg": "Art. 12(1) DSA: users must be able to reach you by a means that is not solely automated. Say in the terms that a human answers, not only a chatbot or ticket robot.",
|
| 100 |
+
"need": ["not (solely|only|exclusively) (automated|an automated)", "a (human|person|member of our team) (will |does )?(reply|respond|review|answer)", "human review of (your |every )?(message|request|enquiry)", "without (relying )?(solely|only) on automated"]
|
| 101 |
+
},
|
| 102 |
+
{
|
| 103 |
+
"check": "art13_legal_representative",
|
| 104 |
+
"sev": "err",
|
| 105 |
+
"msg": "Art. 13 DSA: providers without an establishment in the Union must name a legal representative in a Member State where they offer the service. State your EU establishment or name the representative.",
|
| 106 |
+
"need": ["legal representative", "established in (the )?(european union|eu)\\b", "our (place of )?establishment (is )?in (the )?(european union|eu|ireland|germany|france|netherlands|spain|italy|poland|sweden|belgium)"]
|
| 107 |
+
},
|
| 108 |
+
{
|
| 109 |
+
"check": "art14_moderation_policy",
|
| 110 |
+
"sev": "err",
|
| 111 |
+
"msg": "Art. 14(1) DSA: the terms must describe the policies, procedures, measures and tools used for content moderation. Describe what you remove and how you find it.",
|
| 112 |
+
"need": ["content moderation", "moderation (policy|policies|procedures?|measures|tools)", "how we (review|moderate) (content|posts|uploads)"]
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
"check": "art14_algorithmic_human_review",
|
| 116 |
+
"sev": "err",
|
| 117 |
+
"msg": "Art. 14(1) DSA: the terms must say whether moderation uses algorithmic decision-making and whether a human reviews it. Name both.",
|
| 118 |
+
"need": ["algorithmic decision[- ]?making", "automated (tools|systems|detection)[^.]{0,120}(human review|reviewed by (a )?(human|person|staff))", "human review[^.]{0,120}(automated|algorithm)"]
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"check": "art14_plain_language",
|
| 122 |
+
"sev": "warn",
|
| 123 |
+
"msg": "Art. 14(1) DSA: the terms must be in clear, plain, intelligible, user-friendly and unambiguous language, and Art. 14(3) requires a version minors can understand where the service targets them. Say which you have done.",
|
| 124 |
+
"need": ["plain (and )?(intelligible )?language", "clear,? (plain|simple) (and )?(intelligible|understandable)", "written in plain (english|language)", "plain-language summary"]
|
| 125 |
+
},
|
| 126 |
+
{
|
| 127 |
+
"check": "art14_change_notice",
|
| 128 |
+
"sev": "warn",
|
| 129 |
+
"msg": "Art. 14(2) DSA: significant changes to the terms must be notified to users. State the channel and the notice period.",
|
| 130 |
+
"need": ["(notify|inform|tell) (you|users|recipients)[^.]{0,120}(chang|amend|updat)", "(significant|material) chang[^.]{0,120}(notice|notify|inform)", "we will give[^.]{0,60}days'? notice"]
|
| 131 |
+
},
|
| 132 |
+
{
|
| 133 |
+
"check": "art16_notice_action",
|
| 134 |
+
"sev": "err",
|
| 135 |
+
"msg": "Art. 16 DSA: hosting services must offer an electronic notice-and-action mechanism for reporting illegal content, easy to access and user-friendly. Link it from the terms.",
|
| 136 |
+
"need": ["notice[- ]and[- ]action", "report illegal content", "(report|flag) (allegedly )?illegal (content|material|items)", "illegal content (report|notice) (form|mechanism|channel)"]
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
"check": "art16_receipt_confirmation",
|
| 140 |
+
"sev": "warn",
|
| 141 |
+
"msg": "Art. 16(4) DSA: you must confirm receipt of a notice to the notifier without undue delay. Say that a confirmation is sent.",
|
| 142 |
+
"need": ["confirm(ation)? of receipt", "we (will )?(send|issue) (you )?(a )?confirmation", "acknowledge receipt", "confirm receipt of (your |the )?(notice|report)"]
|
| 143 |
+
},
|
| 144 |
+
{
|
| 145 |
+
"check": "art17_statement_of_reasons",
|
| 146 |
+
"sev": "err",
|
| 147 |
+
"msg": "Art. 17 DSA: every restriction (removal, demotion, suspension, demonetisation) needs a clear and specific statement of reasons to the affected user. Promise it in the terms.",
|
| 148 |
+
"need": ["statement of reasons", "we (will )?(tell|explain to) you why[^.]{0,80}(remov|restrict|suspend|disabl)", "reasons for (the )?(removal|restriction|suspension) (will be|are) (given|provided)"]
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"check": "art20_internal_complaints",
|
| 152 |
+
"sev": "err",
|
| 153 |
+
"msg": "Art. 20 DSA: hosting services must run a free internal complaint-handling system open for at least six months after the decision. State that it is free and state the six-month window.",
|
| 154 |
+
"need": ["internal complaint[- ]handling", "appeal (a|the|our) (decision|removal)[^.]{0,120}(six months|6 months|180 days)", "complaint[- ]handling system[^.]{0,120}(free|no charge)"]
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"check": "art21_out_of_court",
|
| 158 |
+
"sev": "err",
|
| 159 |
+
"msg": "Art. 21 DSA: users must be told they may take a dispute to a certified out-of-court dispute settlement body. Name the right and where to find the certified bodies.",
|
| 160 |
+
"need": ["out[- ]of[- ]court dispute settlement", "certified dispute settlement body", "alternative dispute resolution body certified"]
|
| 161 |
+
},
|
| 162 |
+
{
|
| 163 |
+
"check": "art23_misuse_suspension",
|
| 164 |
+
"sev": "warn",
|
| 165 |
+
"msg": "Art. 23 DSA: state the policy for suspending accounts that frequently post manifestly illegal content, and notifiers who frequently file unfounded notices, after a prior warning.",
|
| 166 |
+
"need": ["prior warning", "manifestly (illegal|unfounded)", "repeated(ly)? (unfounded|abusive) (notices|reports)", "frequently (post|submit)[^.]{0,80}(illegal|unfounded)"]
|
| 167 |
+
},
|
| 168 |
+
{
|
| 169 |
+
"check": "art26_ad_transparency",
|
| 170 |
+
"sev": "err",
|
| 171 |
+
"msg": "Art. 26 DSA: this service shows advertising, so each ad must be marked as an ad, name who paid for it, and explain the main parameters used to target it. Say so in the terms.",
|
| 172 |
+
"when": "advertis|sponsored (post|content|listing)|promoted (post|content)",
|
| 173 |
+
"need": ["(marked|labelled|labeled|identified) as (an )?(ad|advertis)", "on whose behalf (the )?(ad|advertis)", "main parameters used to determine"]
|
| 174 |
+
},
|
| 175 |
+
{
|
| 176 |
+
"check": "art28_minor_profiling_ads",
|
| 177 |
+
"sev": "err",
|
| 178 |
+
"msg": "Art. 28(2) DSA: where the service is accessible to minors you may not show advertising based on profiling of their personal data. State the ban in the terms.",
|
| 179 |
+
"when": "minor|under 18|under-18|child(ren)?|teen",
|
| 180 |
+
"need": ["no (advertis|ads)[^.]{0,120}profil", "profiling[^.]{0,120}(minors?|children)[^.]{0,60}(not|never|prohibited)", "we do not (show|serve) (profil|targeted) (ads|advertis)[^.]{0,80}(minor|child)"]
|
| 181 |
+
},
|
| 182 |
+
{
|
| 183 |
+
"check": "terms_dated_before_dsa",
|
| 184 |
+
"sev": "err",
|
| 185 |
+
"kind": "date",
|
| 186 |
+
"msg": "The DSA has applied to every intermediary service since 17 February 2024. Terms that carry no version date, or a date before it, were not written against these duties."
|
| 187 |
+
}
|
| 188 |
+
]
|
| 189 |
+
;</script>
|
| 190 |
+
<script>/* dsa-terms-lint engine - EU Digital Services Act (Regulation (EU) 2022/2065)
|
| 191 |
+
Same file runs in Node (VS Code extension) and in the browser (free web page). */
|
| 192 |
+
(function () {
|
| 193 |
+
'use strict';
|
| 194 |
+
|
| 195 |
+
var RULES = (typeof module !== 'undefined') ? require('./rules.json') : window.DSA_RULES;
|
| 196 |
+
|
| 197 |
+
/* The DSA has applied to all providers of intermediary services since this date. */
|
| 198 |
+
var DSA_APPLIES = '2024-02-17';
|
| 199 |
+
var STALE_MONTHS = 18;
|
| 200 |
+
|
| 201 |
+
var DATE_RE = /(last\s+updated|last\s+revised|effective\s+(?:date|from)|version\s+date|in\s+force\s+from)\s*[:–—-]*\s*(\d{4}-\d{2}-\d{2})/i;
|
| 202 |
+
|
| 203 |
+
function rx(pattern) {
|
| 204 |
+
return new RegExp(pattern, 'i');
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
function lineOfMatch(text, pattern) {
|
| 208 |
+
if (!pattern) return 1;
|
| 209 |
+
var re = new RegExp(pattern, 'i');
|
| 210 |
+
var lines = text.split(/\r?\n/);
|
| 211 |
+
for (var i = 0; i < lines.length; i++) {
|
| 212 |
+
if (re.test(lines[i])) return i + 1;
|
| 213 |
+
}
|
| 214 |
+
return 1;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
function monthsBetween(fromISO, toISO) {
|
| 218 |
+
var a = fromISO.split('-').map(Number);
|
| 219 |
+
var b = toISO.split('-').map(Number);
|
| 220 |
+
return (b[0] - a[0]) * 12 + (b[1] - a[1]) - (b[2] < a[2] ? 1 : 0);
|
| 221 |
+
}
|
| 222 |
+
|
| 223 |
+
function dateFindings(rule, text, today) {
|
| 224 |
+
var out = [];
|
| 225 |
+
var m = text.replace(/\s+/g, ' ').match(DATE_RE);
|
| 226 |
+
if (!m) {
|
| 227 |
+
out.push({
|
| 228 |
+
check: rule.check,
|
| 229 |
+
sev: 'err',
|
| 230 |
+
msg: 'No version date found. ' + rule.msg + ' Add a "Last updated: YYYY-MM-DD" line.',
|
| 231 |
+
line: 1
|
| 232 |
+
});
|
| 233 |
+
return out;
|
| 234 |
+
}
|
| 235 |
+
var found = m[2];
|
| 236 |
+
var line = lineOfMatch(text, m[0].replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
| 237 |
+
if (found < DSA_APPLIES) {
|
| 238 |
+
out.push({
|
| 239 |
+
check: rule.check,
|
| 240 |
+
sev: 'err',
|
| 241 |
+
msg: 'Version date ' + found + ' is before ' + DSA_APPLIES + '. ' + rule.msg,
|
| 242 |
+
line: line
|
| 243 |
+
});
|
| 244 |
+
} else if (monthsBetween(found, today) >= STALE_MONTHS) {
|
| 245 |
+
out.push({
|
| 246 |
+
check: rule.check,
|
| 247 |
+
sev: 'warn',
|
| 248 |
+
msg: 'Version date ' + found + ' is ' + monthsBetween(found, today) + ' months old as of ' + today +
|
| 249 |
+
'. Art. 14(2) DSA expects the published terms to match what you actually do.',
|
| 250 |
+
line: line
|
| 251 |
+
});
|
| 252 |
+
}
|
| 253 |
+
return out;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
function check(text, opts) {
|
| 257 |
+
text = String(text == null ? '' : text);
|
| 258 |
+
opts = opts || {};
|
| 259 |
+
var today = opts.today || '2026-09-18';
|
| 260 |
+
var findings = [];
|
| 261 |
+
|
| 262 |
+
/* Real terms files are hard-wrapped, so a clause routinely straddles two lines.
|
| 263 |
+
Rules are matched against a whitespace-flattened copy; line numbers stay on the original. */
|
| 264 |
+
var flat = text.replace(/\s+/g, ' ');
|
| 265 |
+
|
| 266 |
+
for (var i = 0; i < RULES.length; i++) {
|
| 267 |
+
var rule = RULES[i];
|
| 268 |
+
if (rule.when && !rx(rule.when).test(flat)) continue;
|
| 269 |
+
|
| 270 |
+
if (rule.kind === 'date') {
|
| 271 |
+
findings = findings.concat(dateFindings(rule, text, today));
|
| 272 |
+
continue;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
var satisfied = false;
|
| 276 |
+
var need = rule.need || [];
|
| 277 |
+
for (var j = 0; j < need.length; j++) {
|
| 278 |
+
if (rx(need[j]).test(flat)) { satisfied = true; break; }
|
| 279 |
+
}
|
| 280 |
+
if (!satisfied) {
|
| 281 |
+
findings.push({
|
| 282 |
+
check: rule.check,
|
| 283 |
+
sev: rule.sev || 'warn',
|
| 284 |
+
msg: rule.msg,
|
| 285 |
+
line: lineOfMatch(text, rule.anchor)
|
| 286 |
+
});
|
| 287 |
+
}
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
findings.sort(function (a, b) { return a.line - b.line; });
|
| 291 |
+
return { findings: findings };
|
| 292 |
+
}
|
| 293 |
+
|
| 294 |
+
var api = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };
|
| 295 |
+
if (typeof module !== 'undefined') module.exports = api;
|
| 296 |
+
if (typeof window !== 'undefined') window.DSAENGINE = api;
|
| 297 |
+
})();
|
| 298 |
+
</script>
|
| 299 |
+
<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.
|
| 300 |
+
'use strict';
|
| 301 |
+
function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); }
|
| 302 |
+
function summaryLine(res) {
|
| 303 |
+
const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;
|
| 304 |
+
return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';
|
| 305 |
+
}
|
| 306 |
+
function toText(res, label) {
|
| 307 |
+
const f = (res && res.findings) || [];
|
| 308 |
+
const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];
|
| 309 |
+
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 || '')); });
|
| 310 |
+
return lines.join('\n');
|
| 311 |
+
}
|
| 312 |
+
function toHtml(res) {
|
| 313 |
+
const f = (res && res.findings) || [];
|
| 314 |
+
if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';
|
| 315 |
+
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('');
|
| 316 |
+
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>';
|
| 317 |
+
}
|
| 318 |
+
var DSAREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };
|
| 319 |
+
if (typeof module !== 'undefined' && module.exports) module.exports = DSAREPORT;
|
| 320 |
+
else window.DSAREPORT = DSAREPORT;
|
| 321 |
+
</script>
|
| 322 |
+
<script>
|
| 323 |
+
(function(){
|
| 324 |
+
var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');
|
| 325 |
+
today.value=new Date().toISOString().slice(0,10);
|
| 326 |
+
function run(){ try { var res=window.DSAENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.DSAREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }
|
| 327 |
+
go.onclick=run; if (src.value.trim()) run();
|
| 328 |
+
})();
|
| 329 |
+
</script>
|
| 330 |
+
|
| 331 |
+
<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 DSA Terms Lint - EU Digital Services Act 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:"dsa-terms-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>
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
<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/dsa-terms-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'dsa-terms-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/dsa-terms-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'dsa-terms-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/dsa-terms-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'dsa-terms-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/dsa-terms-lint <file>
|
| 335 |
+
docker run --rm -v "$PWD:/w" getreadystack/dsa-terms-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>
|
| 336 |
+
<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">Reads your terms-of-service markdown and names every DSA duty it is missing, by article number.</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">EU technology counsel bills roughly $250-$500 an hour to read the same six pages of terms.</p><a href="https://buy.polar.sh/polar_cl_cvvpOHUl0trDgV1H4FITDdGO0eTfT4jX9Olem3MhKMp" 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>
|
| 337 |
+
<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 DSA Terms Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads a terms-of-service markdown file and reports which EU Digital Services Act duties the text does not express. Eighteen rules cover Articles 11, 12, 13, 14, 16, 17, 20, 21, 23, 26 and 28, plus the version date. Each finding names the article and the sentence that is missing, in the VS Code Problems panel.</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">Developers and founders who host user content and wrote their own terms: a two-person SaaS with comments, a forum, a marketplace, a mobile app with profiles. The Digital Services Act has applied to every provider of intermediary services offering them in the EU since 17 February 2024, not only to very large platforms.</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 tool or a chatbot not do this?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A language model will happily draft fluent terms and never tell you that Article 16 is absent, because absence is what it cannot see. Generic markdown linters check style, not statute. This tool reports the missing clause by article number, and its conditional rules stay quiet on advertising and minors unless your own text raises them.</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 is in the full version?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free gives the complete gap list for the file you have open: all eighteen rules, every article number, no watermark and no cut-off. The full version works across scope instead: it scans every legal page and every language version in the workspace at once and exports a dated report with article citations for counsel.</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 would this cost without the tool?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">EU technology counsel bills roughly $250 to $500 an hour to read the same six pages, and a fixed-fee terms review runs into four figures. Enforcement runs the other way: Digital Services Act fines reach 6% of worldwide annual turnover, and national coordinators can act on a single user complaint.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does DSA Terms Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads a terms-of-service markdown file and reports which EU Digital Services Act duties the text does not express. Eighteen rules cover Articles 11, 12, 13, 14, 16, 17, 20, 21, 23, 26 and 28, plus the version date. Each finding names the article and the sentence that is missing, in the VS Code Problems panel."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Developers and founders who host user content and wrote their own terms: a two-person SaaS with comments, a forum, a marketplace, a mobile app with profiles. The Digital Services Act has applied to every provider of intermediary services offering them in the EU since 17 February 2024, not only to very large platforms."}}, {"@type": "Question", "name": "Why will a free tool or a chatbot not do this?", "acceptedAnswer": {"@type": "Answer", "text": "A language model will happily draft fluent terms and never tell you that Article 16 is absent, because absence is what it cannot see. Generic markdown linters check style, not statute. This tool reports the missing clause by article number, and its conditional rules stay quiet on advertising and minors unless your own text raises them."}}, {"@type": "Question", "name": "What is free and what is in the full version?", "acceptedAnswer": {"@type": "Answer", "text": "Free gives the complete gap list for the file you have open: all eighteen rules, every article number, no watermark and no cut-off. The full version works across scope instead: it scans every legal page and every language version in the workspace at once and exports a dated report with article citations for counsel."}}, {"@type": "Question", "name": "What would this cost without the tool?", "acceptedAnswer": {"@type": "Answer", "text": "EU technology counsel bills roughly $250 to $500 an hour to read the same six pages, and a fixed-fee terms review runs into four figures. Enforcement runs the other way: Digital Services Act fines reach 6% of worldwide annual turnover, and national coordinators can act on a single user complaint."}}]}</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:"dsa-terms-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/en301549-lint"><span class="yj-rel-t">EN 301 549 Lint — European Accessibility Act rules, with the clause number, in</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-act-article-50-audit"><span class="yj-rel-t">EU AI Act Article 50 Transparency Audit for Your Codebase</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/webflow-restaurant-template"><span class="yj-rel-t">Webflow Restaurant Template — delivered as self-contained HTML you own: 26 pag</span><span class="yj-rel-p">$49</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/age-gate-lint"><span class="yj-rel-t">Age Gate Lint — UK Online Safety Act</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cra-24-72-14-reporting-lint"><span class="yj-rel-t">CRA 24/72/14 Reporting Lint (Article 14)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/cra-annex-ii-docs-lint"><span class="yj-rel-t">CRA Annex II User Docs Lint</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><!--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>
|
| 338 |
+
|
| 339 |
+
<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>
|
| 340 |
+
<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>
|
| 341 |
+
|
| 342 |
+
<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>
|
| 343 |
+
</body>
|
| 344 |
</html>
|