From b0d44fe02cd2765c51d23febc61a2927988704b9 Mon Sep 17 00:00:00 2001 From: Tom King Date: Sat, 26 Sep 2026 21:35:57 -0500 Subject: [PATCH 1/2] feat: shorter bookmarklet URLs (4.3.0) Leave `:=,/;$@+?` unescaped in bookmarklet URLs. They are legal in URL fragments and inert in HTML attributes and Markdown link destinations. Total dist size drops 11,895 -> 10,749 bytes (-9.6%); UtmStrip -534. - Add encodeBookmarklet/validateEncodedBookmarklet to scripts/utils.js (keeps leading "/" encoded, encodes parens if unbalanced or >32 deep, self-validates with a WHATWG URL round trip) - Use a function replacer in update-readme.js so `$` in code can't be treated as a replacement pattern - Add scripts/test-encoding.js and run it from `npm test` - Patch-bump all 21 bookmarklets; bump project to 4.3.0 - Bump @types/node to ~26.6.3 Co-Authored-By: Claude Sonnet 5 --- README.md | 177 +++++++++++++------------ bookmarklets.json | 42 +++--- dist/delighter.bookmarklet | 2 +- dist/fyi.bookmarklet | 2 +- dist/isitaws.bookmarklet | 2 +- dist/killStickyHeaders.bookmarklet | 2 +- dist/linklighter.bookmarklet | 2 +- dist/openinbrave.bookmarklet | 2 +- dist/openinchrome.bookmarklet | 2 +- dist/openinddg.bookmarklet | 2 +- dist/openinedge.bookmarklet | 2 +- dist/openinfirefox-focus.bookmarklet | 2 +- dist/openinfirefox-private.bookmarklet | 2 +- dist/openinfirefox.bookmarklet | 2 +- dist/openingoodreader.bookmarklet | 2 +- dist/openinopera.bookmarklet | 2 +- dist/openinorion.bookmarklet | 2 +- dist/openintextastic.bookmarklet | 2 +- dist/openinworkingcopy.bookmarklet | 2 +- dist/openurlparam.bookmarklet | 2 +- dist/unskim.bookmarklet | 2 +- dist/utmstrip.bookmarklet | 2 +- dist/x-man.bookmarklet | 2 +- package-lock.json | 4 +- package.json | 6 +- scripts/build-bookmarklet.js | 10 +- scripts/test-encoding.js | 114 ++++++++++++++++ scripts/update-readme.js | 3 +- scripts/utils.js | 106 ++++++++++++++- 29 files changed, 364 insertions(+), 140 deletions(-) create mode 100755 scripts/test-encoding.js diff --git a/README.md b/README.md index ab566e5..dc49bcd 100644 --- a/README.md +++ b/README.md @@ -28,24 +28,24 @@ GitHub infrastructure prevents "drag & drop" install directly from the README.md preview. Use the [OpenInlets page] to drag & drop the bookmarklet links below on your desktop browser's favorites bar. -+ __[deLighter] v1.3.1__: Effectively de-highlights any highlighted text ++ __[deLighter] v1.3.2__: Effectively de-highlights any highlighted text fragment on the current page. Uses `document.location.reload()` to reload the page to de-highlight it. (It's a cross-platform companion to the __Linklighter__ bookmarklet, below.) -+ __[FYI] v3.3.0__: Select text on a web page and fire off an email that ++ __[FYI] v3.3.1__: Select text on a web page and fire off an email that quotes the selection and includes the page title and URL. "FYI" opens a new email with the page title in the subject line, the page title repeated again in the body, along with the selected text (if any text was selected), and the URL of the original page. -+ __[IsItAws] v1.3.5__: Check the current page host to determine if it runs on ++ __[IsItAws] v1.3.6__: Check the current page host to determine if it runs on AWS. This bookmarklet works with most browsers on most platforms. -+ __[KillStickyHeaders] v2.1.0__: Find & delete all fixed position elements of ++ __[KillStickyHeaders] v2.1.1__: Find & delete all fixed position elements of HTML body element. Cross-platform. -+ __[Linklighter] v2.1.0__: Use the current text selection on the active web ++ __[Linklighter] v2.1.1__: Use the current text selection on the active web page to generate a URL that will highlight the selected text when opened in a modern browser. If a new URL is generated, Linklighter ask to open it in a new window to preview the highlight, and copy the new URL to the clipboard. (See @@ -53,61 +53,61 @@ deLighter above, as a companion bookmarklet that un-highlights the newly opened window.) Linklighter works with recent releases of Safari on iPhone, iPad, and Mac, and also works with Google Chrome on desktops. -+ __[OpenInBrave] v1.1.2__: Open the current web page in the Brave app on iOS. ++ __[OpenInBrave] v1.1.3__: Open the current web page in the Brave app on iOS. -+ __[OpenInChrome] v1.0.0__: Open the current web page in the Google Chrome app ++ __[OpenInChrome] v1.0.1__: Open the current web page in the Google Chrome app on iOS. -+ __[OpenInDDG] v1.0.0__: Open the current web page in the DuckDuckGo browser ++ __[OpenInDDG] v1.0.1__: Open the current web page in the DuckDuckGo browser app on iOS. -+ __[OpenInEdge] v1.0.0__: Open the current web page in the Microsoft Edge app ++ __[OpenInEdge] v1.0.1__: Open the current web page in the Microsoft Edge app on iOS. -+ __[OpenInFirefox] v1.6.2__: Open the current web page in the Firefox app for ++ __[OpenInFirefox] v1.6.3__: Open the current web page in the Firefox app for iOS. -+ __[OpenInFirefox-Focus] v1.1.2__: Open the current web page in the Firefox ++ __[OpenInFirefox-Focus] v1.1.3__: Open the current web page in the Firefox Focus app for iOS. -+ __[OpenInFirefox-Private] v1.1.2__: Open the current web page in private ++ __[OpenInFirefox-Private] v1.1.3__: Open the current web page in private mode of the Firefox app for iOS. -+ __[OpenInGoodReader] v1.5.2__: When viewing a PDF in Mobile Safari, open or ++ __[OpenInGoodReader] v1.5.3__: When viewing a PDF in Mobile Safari, open or download the same PDF in GoodReader. -+ __[OpenInOpera] v1.0.0__: Open the current web page in the Opera app on iOS. ++ __[OpenInOpera] v1.0.1__: Open the current web page in the Opera app on iOS. -+ __[OpenInOrion] v1.0.0__: Open the current web page in the Opera app on iOS. ++ __[OpenInOrion] v1.0.1__: Open the current web page in the Opera app on iOS. -+ __[OpenInTextastic] v1.1.2__: Open the current web page in the Textastic app ++ __[OpenInTextastic] v1.1.3__: Open the current web page in the Textastic app on iOS. Download the server response of the current HTTP URL, save it in the root directory of the local (Textastic) file system, and then open it in the editor. Handy to view the source code of a web page or download a raw file. -+ __[OpenInWorkingCopy] v1.6.2__: When viewing a BitBucket _or_ Github ++ __[OpenInWorkingCopy] v1.6.3__: When viewing a BitBucket _or_ Github repository in Mobile Safari, show the same repo in the Working Copy iOS app (cloning the repo locally if necessary). -+ __[OpenURLParam] v1.2.1__: Work-around for blocked navigation from certain ++ __[OpenURLParam] v1.2.2__: Work-around for blocked navigation from certain ad or tracking blockers. If the current URL contains a parameter in the form of `url=...` this bookmarklet will parse the `url` parameter and navigate to that URL. -+ __[UtmStrip] v2.3.2__: Strips off the UTM query string elements of the ++ __[UtmStrip] v2.3.3__: Strips off the UTM query string elements of the current URL to remove common "urchin" tracking information from youtube, etc. Also removes Google `/amp/` suffix from URL path. Asks to copy the new URL to the clipboard. Finally, replaces history & reloads the page. Now works to remove host-specific trackers for common online retailers and Google Search. _NOTE:_ This bookmarklet also works with Safari and Firefox on macOS. -+ __[unskim] v2.1.1__: Bypass redirect and affiliate link wrappers by ++ __[unskim] v2.1.2__: Bypass redirect and affiliate link wrappers by detecting common URL parameters (like `url=`, `destination=`, `redirect=`, etc.) and navigating directly to the target URL. Also handles Safari DNS error pages when a redirect service is blocked, extracting the intended destination from the error message. -+ __[x-man] v1.3.1__: Using the selected text in browser, create a ++ __[x-man] v1.3.2__: Using the selected text in browser, create a `x-man-page://` link to the corresponding man page and offer to place that link on the clipboard. When using Safari on Mac, the bookmarklet will use Safari to open the corresponding man page with yellow highlighting in @@ -128,27 +128,27 @@ and Safari (Mac, iPhone, & iPad). Tap a link below. Follow the instructions on the resulting page to turn the followed link into a bookmark for JavaScript bookmarklet. -+ __Mobile Safari setup link__ -- [Setup deLighter] v1.3.1 -+ __Mobile Safari setup link__ -- [Setup FYI] v3.3.0 -+ __Mobile Safari setup link__ -- [Setup IsItAws] v1.3.5 -+ __Mobile Safari setup link__ -- [Setup KillStickyHeaders] v2.1.0 -+ __Mobile Safari setup link__ -- [Setup Linklighter] v2.1.0 -+ __Mobile Safari setup link__ -- [Setup OpenInBrave] v1.1.2 -+ __Mobile Safari setup link__ -- [Setup OpenInChrome] v1.0.0 -+ __Mobile Safari setup link__ -- [Setup OpenInDDG] v1.0.0 -+ __Mobile Safari setup link__ -- [Setup OpenInEdge] v1.0.0 -+ __Mobile Safari setup link__ -- [Setup OpenInFirefox] v1.6.2 -+ __Mobile Safari setup link__ -- [Setup OpenInFirefox-Focus] v1.1.2 -+ __Mobile Safari setup link__ -- [Setup OpenInFirefox-Private] v1.1.2 -+ __Mobile Safari setup link__ -- [Setup OpenInOpera] v1.0.0 -+ __Mobile Safari setup link__ -- [Setup OpenInOrion] v1.0.0 -+ __Mobile Safari setup link__ -- [Setup OpenInGoodReader] v1.5.2 -+ __Mobile Safari setup link__ -- [Setup OpenInTextastic] v1.1.2 -+ __Mobile Safari setup link__ -- [Setup OpenInWorkingCopy] v1.6.2 -+ __Mobile Safari setup link__ -- [Setup OpenURLParam] v1.2.1 -+ __Mobile Safari setup link__ -- [Setup UtmStrip] v2.3.2 -+ __Mobile Safari setup link__ -- [Setup unskim] v2.1.1 -+ __Mobile Safari setup link__ -- [Setup x-man] v1.3.1 ++ __Mobile Safari setup link__ -- [Setup deLighter] v1.3.2 ++ __Mobile Safari setup link__ -- [Setup FYI] v3.3.1 ++ __Mobile Safari setup link__ -- [Setup IsItAws] v1.3.6 ++ __Mobile Safari setup link__ -- [Setup KillStickyHeaders] v2.1.1 ++ __Mobile Safari setup link__ -- [Setup Linklighter] v2.1.1 ++ __Mobile Safari setup link__ -- [Setup OpenInBrave] v1.1.3 ++ __Mobile Safari setup link__ -- [Setup OpenInChrome] v1.0.1 ++ __Mobile Safari setup link__ -- [Setup OpenInDDG] v1.0.1 ++ __Mobile Safari setup link__ -- [Setup OpenInEdge] v1.0.1 ++ __Mobile Safari setup link__ -- [Setup OpenInFirefox] v1.6.3 ++ __Mobile Safari setup link__ -- [Setup OpenInFirefox-Focus] v1.1.3 ++ __Mobile Safari setup link__ -- [Setup OpenInFirefox-Private] v1.1.3 ++ __Mobile Safari setup link__ -- [Setup OpenInOpera] v1.0.1 ++ __Mobile Safari setup link__ -- [Setup OpenInOrion] v1.0.1 ++ __Mobile Safari setup link__ -- [Setup OpenInGoodReader] v1.5.3 ++ __Mobile Safari setup link__ -- [Setup OpenInTextastic] v1.1.3 ++ __Mobile Safari setup link__ -- [Setup OpenInWorkingCopy] v1.6.3 ++ __Mobile Safari setup link__ -- [Setup OpenURLParam] v1.2.2 ++ __Mobile Safari setup link__ -- [Setup UtmStrip] v2.3.3 ++ __Mobile Safari setup link__ -- [Setup unskim] v2.1.2 ++ __Mobile Safari setup link__ -- [Setup x-man] v1.3.2 ## Requirements @@ -177,6 +177,11 @@ the end the bookmarklet URL code serves two purposes. 2. It is a convenient place to embed a string indicating the `semver` version of the bookmark. +The `dist/` URLs are percent-encoded with `encodeURIComponent`, then +`:=,/;$@+?` are left literal (safe in URL fragments, HTML attributes and +Markdown link destinations) to keep them short. `*` and `_` are forced to be +encoded (`%2A`, `%5F`) to avoid Markdown emphasis. + ## Build Clone the repository. If `node` is not installed go get it from @@ -266,6 +271,10 @@ using a URL protocol scheme. ## Version Notes +4.3.0 Shorter bookmarklet URLs: leave `:=,/;$@+?` unescaped (~10% smaller +overall, 11,895 → 10,749 bytes; UtmStrip −534 bytes); patch bump for every +rebuilt bookmarklet + 4.2.4 Update engines (node >=26.0, npm >=11.13) and dependencies 4.2.3 Fix unskim regex issue, update dependency integrate a "clean" into compile @@ -381,51 +390,51 @@ repos I had; doesn't build yet -[deLighter]: javascript:document.location.reload()%3Bvoid'1.3.1' "deLighter" -[FYI]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20e=encodeURIComponent(document.title)%2Ct='%250A'%2Cn=window.getSelection()%2Co=n%26%26'Range'===n.type%26%26n.rangeCount%3E0%3Fn.getRangeAt(0).toString():''%3Blocation.href=%60mailto:%3Fsubject=fyi:%24%7Be%7D%26body=%24%7Be%7D%24%7Bt%7D%24%7BencodeURIComponent(document.URL)%7D%24%7Bt%7D---%24%7Bt%7D%24%7BencodeURIComponent(o)%7D%24%7Bt%7D%24%7Bt%7D%60%7D)()%3Bvoid'3.3.0' "FYI" -[IsItAws]: javascript:location.href='https:%2F%2Fisitonaws.com%2Fdiscover%3Fname='%2Blocation.host%3Bvoid'1.3.5' "IsItAws" -[KillStickyHeaders]: javascript:Array.from(document.querySelectorAll('body%20%2A')).filter(e=%3E%5B'fixed'%2C'sticky'%5D.includes(getComputedStyle(e).position)).forEach(e=%3Ee.remove())%3Bvoid'2.1.0' "KillStickyHeaders" -[Linklighter]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=encodeURIComponent%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20n=e.toString()%2Co=n.length%2Ci=document.URL%2Cs=i.indexOf('%23')%3Blet%20r=i%2Cc=''%2Cl=''%2Ca=''%3Bif(e.rangeCount%3E0%26%26n%26%26(document.body.textContent%7C%7C'').split(n).length-1%3E1)%7Bconst%20t=e.getRangeAt(0)%2Cn=t.commonAncestorContainer.textContent%7C%7C''%2C%7BstartOffset:o%2CendOffset:i%7D=t%2Cs=Math.max(0%2Co-20)%3Bif(l=n.substring(s%2Co).trim()%2Cs%3E0%26%26'%20'!==n.charAt(s-1))%7Bconst%20t=l.indexOf('%20')%3Bt%3E0%26%26(l=l.substring(t%2B1))%7Dconst%20r=Math.min(n.length%2Ci%2B20)%3Bif(a=n.substring(i%2Cr).trim()%2Cr%3Cn.length%26%26'%20'!==n.charAt(r))%7Bconst%20t=a.lastIndexOf('%20')%3Bt%3E0%26%26(a=a.substring(0%2Ct))%7D%7Dif(e.removeAllRanges()%2Cn%26%26''!==n)%7Bs%3E-1%26%26(r=r.substring(0%2Cs))%3Blet%20e=''%3Bif(l%26%26(e=t(l)%2B'-%2C')%2C80%3Eo)c=n%2Ce%2B=t(n)%3Belse%7Blet%20i=~~(o%2F2-2)%3Bo%3E150%3Fi=48:o%3E100%26%26(i=~~(o%2F3))%3Blet%20s=n.substring(0%2Ci)%2Cr=n.slice(o-i)%3Bconst%20l=s.lastIndexOf('%20')%3Bl%3Ei%2F2%26%26(s=s.substring(0%2Cl))%3Bconst%20a=r.indexOf('%20')%3Ba%3E-1%26%26i%2F2%3Ea%26%26(r=r.substring(a%2B1))%2Cc=s%2B'%E2%80%A6'%2Ce%2B=%60%24%7Bt(s)%7D%2C%24%7Bt(r)%7D%60%7Da%26%26(e%2B='%2C-'%2Bt(a))%2Cr%2B='%23:~:text='%2Be%2Cr=r.replace(%2F(%250A%7C%250D%7C%2509%7C%2520)%2B%24%2F%2C'')%2Cr=r.replace(%2F(%2520)%7B2%2C%7D%2Fg%2C'%2520')%2Cr=r.replace(%2F%23%23%2B:~:text=%2F%2C'%23:~:text=')%7Dif(r!==i%26%26confirm(%60Open%20URL%20with%20highlight%20on%20%22%24%7Bc%7D%22%20and%20copy%20URL%20to%20clipboard%3F%60))%7Bnavigator.clipboard.writeText(r).catch(()=%3E%7Balert('Could%20not%20copy%20to%20clipboard.%20URL%20is%20in%20the%20new%20tab.')%7D)%3Bconst%20t=window.open(r%2C'%5Fblank')%3Bt%3Ft.opener=null:alert('Popup%20blocked.%20URL%20copied%20to%20clipboard.')%7D%7D)()%3Bvoid'2.1.0' "Linklighter" -[OpenInBrave]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='brave:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.1.2' "OpenInBrave" -[OpenInChrome]: javascript:'use%20strict'%3Bif(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))%7Bconst%20o=%60googlechrome%24%7B'https:'===location.protocol%3F's':''%7D:%2F%2F%60%3Blocation.href=%60%24%7Bo%7D%24%7Blocation.host%7D%24%7Blocation.pathname%7D%24%7Blocation.search%7D%24%7Blocation.hash%7D%60%7Dvoid'1.0.0' "OpenInChrome" -[OpenInDDG]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60ddgQuickLink:%2F%2F%24%7Blocation.host%7D%24%7Blocation.pathname%7D%24%7Blocation.search%7D%24%7Blocation.hash%7D%60%3Bvoid'1.0.0' "OpenInDDG" -[OpenInEdge]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='microsoft-edge-'%2Blocation.href%3Bvoid'1.0.0' "OpenInEdge" -[OpenInFirefox]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='firefox:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.6.2' "OpenInFirefox" -[OpenInFirefox-Focus]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60firefox-focus:%2F%2Fopen-url%3Furl=%24%7BencodeURIComponent(location.href)%7D%26private=true%60%3Bvoid'1.1.2' "OpenInFirefox-Focus" -[OpenInFirefox-Private]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60firefox:%2F%2Fopen-url%3Furl=%24%7BencodeURIComponent(location.href)%7D%26private=true%60%3Bvoid'1.1.2' "OpenInFirefox-Private" -[OpenInOpera]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='touch-'%2Blocation.href%3Bvoid'1.0.0' "OpenInOpera" -[OpenInOrion]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='orion:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.0.0' "OpenInOrion" -[OpenInGoodReader]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26%2F%5C.pdf(%24%7C%5C%3F)%2F.test(location.href))location.href='gr'%2Blocation.href%3Bvoid'1.5.2' "OpenInGoodReader" -[OpenInTextastic]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=location.href.replace(%2F%5Ehttps%3F%2F%2C'textastic')%3Bvoid'1.1.2' "OpenInTextastic" -[OpenInWorkingCopy]: javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy:%2F%2Fshow%3Fremote=%24%7BencodeURIComponent(location.href.split('%2F').slice(0%2C5).join('%2F'))%7D.git%60%3Bvoid'1.6.2' "OpenInWorkingCopy" -[OpenURLParam]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=new%20URL(document.location.href)%3Bif('https:'!==t.protocol%7C%7C13%3Et.search.length)return%3Bconst%20e=new%20URLSearchParams(t.search)%2Cn=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t)%3Breturn%20n%3FdecodeURIComponent(n):''%7D).find(t=%3Et.match(%2F%5Ehttps:%2F))%3Bn%26%26window.location.replace(new%20URL(n))%7D)()%3Bvoid'1.2.1' "OpenURLParam" -[UtmStrip]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=location.pathname%2Ce=location.search%3Bif(3%3Ee.length%26%26!t.includes('%2Famp'))return%3Bconst%20i=location.hostname%2Cs=new%20URLSearchParams(e)%2C%5F=%5B'assetType'%2C'elqTrack'%2C'mkt%5Ftok'%2C'originalReferer'%2C'referrer'%2C'terminal%5Fid'%2C'trk'%2C'trkCampaign'%2C'trkInfo'%2C'anid'%2C'assetid'%2C'campaignid'%2C'eid'%2C'gclid'%2C'recipientid'%2C'siteid'%2C'sib%5Fcuid'%2C'sib%5Fsid'%2C'%5Fbta%5Ftid'%2C'%5Fbta%5Fc'%2C'%5F%5Fs'%2C'fbclid'%2C'hrc'%2C'igsh'%2C'igshid'%2C'refsrc'%2C'%5Fgl'%2C'gclsrc'%2C'gs%5Fl'%2C'srsltid'%2C'%5Fhsenc'%2C'%5Fhsmi'%2C'%5F%5Fhsfp'%2C'%5F%5Fhssc'%2C'%5F%5Fhstc'%2C'cm%5Fmmc'%2C'cm%5Fre'%2C'cm%5Fsp'%2C'manual%5Fcm%5Fmmc'%2C'%5Fke'%2C'%5Fkx'%2C'trk%5Fcontact'%2C'trk%5Fmsg'%2C'trk%5Fmodule'%2C'trk%5Fsid'%2C'mc%5Fcid'%2C'mc%5Feid'%2C'iesrc'%2C'msclkid'%2C'dclid'%2C'twclid'%2C'ttclid'%2C'oly%5Fenc%5Fid'%2C'oly%5Fanon%5Fid'%2C'epik'%2C'vero%5Fid'%2C'rdt%5Fcid'%2C'ScCid'%2C'qclid'%2C'tblci'%2C'cjevent'%2C'ef%5Fid'%2C'outbrain%5Fcid'%5D%2Ca=%5B'fb%5F'%2C'action%5F'%2C'ga%5F'%2C'utm%5F'%2C'hmb%5F'%2C'hsa%5F'%2C'mtm%5F'%2C'pk%5F'%2C'oly%5F'%2C'stm%5F'%5D%3B%2F%5C.aliexpress%5C.%5Ba-z%5D%7B2%2C3%7D%24%2F.test(i)%3F(%5F.push('algo%5Fevid'%2C'algo%5Fpvid'%2C'btsid'%2C'spm'%2C'scm'%2C'ws%5Fab%5Ftest')%2Ca.push('aff%5F')):%2F(%7C%5C.)amazon%5C.com%24%2F.test(i)%3F%5F.push('%5Fencoding'%2C'asc%5Fcampaign'%2C'asc%5Frefurl'%2C'asc%5Fsource'%2C'ascsubtag'%2C'content-id'%2C'crid'%2C'cv%5Fct%5Fcx'%2C'dib%5Ftag'%2C'dib'%2C'ie'%2C'language'%2C'linkCode'%2C'linkId'%2C'pd%5Frd%5Fi'%2C'pd%5Frd%5Fr'%2C'pd%5Frd%5Fw'%2C'pd%5Frd%5Fwg'%2C'pf%5Frd%5Fi'%2C'pf%5Frd%5Fm'%2C'pf%5Frd%5Fp'%2C'pf%5Frd%5Fr'%2C'pf%5Frd%5Fs'%2C'pf%5Frd%5Ft'%2C'pf'%2C'psc'%2C'qid'%2C'ref%5F'%2C'sprefix'%2C'sr'%2C'tag'%2C'th'):i.endsWith('.ebay.com')%7C%7C%2F%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D%24%2F.test(i)%3F%5F.push('mkevt'%2C'mkcid'%2C'mkrid'%2C'campid'%2C'toolid'%2C'customid'%2C'norover'%2C'itm'%2C'amdata'):%2F(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom%3F%5C.%5Ba-z%5D%7B2%7D)%24%2F.test(i)%26%26t.startsWith('%2Fsearch')%3F%5F.push('aqs'%2C'ei'%2C'gs%5Flp'%2C'gs%5Fssp'%2C'iflsig'%2C'sca%5Fesv'%2C'ved'%2C'oq'%2C'sa'%2C'uact'%2C'rlz'%2C'sxsrf'%2C'bih'%2C'biw'%2C'client'%2C'prmd'%2C'sclient'%2C'source'%2C'sourceid'%2C'ie'%2C'oe'):i.endsWith('.linkedin.com')%3F%5F.push('li%5Ffat%5Fid'%2C'licu'%2C'lipi'%2C'midSig'%2C'midToken'%2C'refId'):i.endsWith('.target.com')%3F%5F.push('afid'%2C'clkid'%2C'lnm'%2C'preselect'%2C'tref'):i.endsWith('.temu.com')%3F(%5F.push('%5Fbg%5Ffs'%2C'%5Fp%5Fjump%5Fid'%2C'%5Fp%5Frfs'%2C'refer%5Fpage%5Fid'%2C'refer%5Fpage%5Fname'%2C'refer%5Fpage%5Fsn')%2Ca.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i%3F%5F.push('%5Fd'%2C'%5Fr'%2C'%5Ft'%2C'is%5Ffrom%5Fwebapp'%2C'preview%5Fpb'%2C'share%5Fapp%5Fname'%2C'share%5Fitem%5Fid'%2C'tt4d%5Ft'%2C'timestamp'%2C'u%5Fcode'%2C'user%5Fid'):%2F%5C.(twitter%7Cx)%5C.com%24%2F.test(i)%7C%7C%2F%5E(twitter%7Cx)%5C.com%24%2F.test(i)%3F%5F.push('cn'%2C'ref%5Fsrc'%2C'ref%5Furl'%2C's'%2C't'):i.endsWith('.walmart.com')%3F%5F.push('adsredirect'%2C'affiliates%5Fad%5Fid'%2C'athcpid'%2C'athpgid'%2C'athcgid'%2C'athmtid'%2C'athstid'%2C'athznid'%2C'athiession'%2C'athancid'%2C'athposb'%2C'athena'%2C'campaign%5Fid'%2C'wmlspartner'%2C'wt%5Fmc'):(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26%5F.push('ac'%2C'annotation%5Fid'%2C'app'%2C'feature'%2C'gclid'%2C'kw'%2C'src%5Fvid')%3Bconst%20c=new%20Set(%5F.map(t=%3Et.toLowerCase()))%2Cr=t=%3E%7Bconst%20e=t.toLowerCase()%3Breturn%20c.has(e)%7C%7Ca.some(t=%3Ee.startsWith(t))%7C%7C%2F%5Ecm%5Fmmca%5Cd%2B%24%2Fi.test(t)%7D%3Bfor(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t)%3Blet%20d=s.toString()%3Bd=d%3F'%3F'%2Bd:''%3Bconst%20o=t.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%2Cn=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bo%7D%24%7Bd%7D%24%7Blocation.hash%7D%60%3Bif(confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F')%26%26(navigator.clipboard.writeText(n)%2Ce!==d%7C%7Ct!==o))%7Bhistory.replaceState(null%2C''%2Cn)%3Bconst%20t=window.open(n%2C'%5Fself'%2C'noreferrer')%3Bt%26%26(t.opener=null)%7D%7D)()%3Bvoid'2.3.2' "UtmStrip" -[unskim]: javascript:'use%20strict'%3B(()=%3E%7Blet%20e=new%20URL(document.location.href)%3Bif('safari-resource:%2FErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')%3F.textContent%3F.match(%2FSafari%20can%5B'%5Cu2019%5Dt%20open%20the%20page%20%5B%22%5Cu201C%5D(https%3F:%5B%5E%22%5Cu201D%5D%2B)%5B%22%5Cu201D%5D%2F)%3F.%5B1%5D%3Bt%26%26(e=new%20URL(t))%7Dif(13%3Ee.search.length)return%3Bconst%20t=new%20URLSearchParams(e.search)%2Cr=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e)%3Breturn%20r%3FdecodeURIComponent(r):''%7D).find(e=%3Ee.match(%2F%5Ehttps%3F:%2F))%3Bif(r)%7Bconst%20e=new%20URL(r)%3Bif(e.searchParams.size%3E0)%7Bconst%20t=new%20URLSearchParams(e.search)%3Bfor(const%20e%20of%5B...t.keys()%5D)%7Bconst%20r=e.toLowerCase()%3B(r.startsWith('utm%5F')%7C%7Cr.startsWith('fb%5F')%7C%7C%5B'fbclid'%2C'gclid'%2C'msclkid'%2C'ref'%2C'referrer'%2C'ttclid'%2C'twclid'%5D.includes(r))%26%26t.delete(e)%7De.search=t.toString()%7Dwindow.location.replace(e)%7D%7D)()%3Bvoid'2.1.1' "unskim" -[x-man]: javascript:'use%20strict'%3B(()=%3E%7Bconst%20i=navigator.userAgent%2Cn=i.includes('Chrome%2F')%7C%7Ci.includes('Firefox%2F')%7C%7Ci.includes('Brave%2F')%7C%7Ci.includes('Edg%2F')%2Co=i.includes('Safari%2F')%2Ct=!n%26%26!o%2Ca=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20l=e.toString().split('%5Cn')%5B0%5D.trim()%3Blet%20r='x-man-page:%2F%2F'%3Bconst%20c=l.match(%2F%5E(.%2A%3F)%5C((%5Cd)%5C)%24%2F)%3Bif(r%2B=c%3F'1'===c%5B2%5D%3Fc%5B1%5D:%60%24%7Bc%5B2%5D%7D%2F%24%7Bc%5B1%5D%7D%60:l%2Cl)%7Bif(confirm(%60Link%20for%20%22%24%7Bl%7D%22%20is:%20%24%7Br%7D%5Cn%5CnCopy%20to%20clipboard%3F%60))%7Blet%20i=''%3Bif(navigator.clipboard%3Fnavigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22%24%7Br%7D%22%20to%20clipboard.%60%2Cr='')%2Ca%26%26''!==r)%7Blet%20n=null%3Btry%7Bn=window.open(r)%2Cn%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22%24%7Br%7D%22%60%7Dfinally%7Bwindow.focus()%2Cnull!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D%2C3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22%24%7Br%7D%22%60)%3B''!==i%26%26alert(i)%7De.empty()%7D%7D)()%3Bvoid'1.3.1' "x-man" +[deLighter]: javascript:document.location.reload();void'1.3.2' "deLighter" +[FYI]: javascript:'use%20strict';(()=%3E%7Bconst%20e=encodeURIComponent(document.title),t='%250A',n=window.getSelection(),o=n%26%26'Range'===n.type%26%26n.rangeCount%3E0?n.getRangeAt(0).toString():'';location.href=%60mailto:?subject=fyi:$%7Be%7D%26body=$%7Be%7D$%7Bt%7D$%7BencodeURIComponent(document.URL)%7D$%7Bt%7D---$%7Bt%7D$%7BencodeURIComponent(o)%7D$%7Bt%7D$%7Bt%7D%60%7D)();void'3.3.1' "FYI" +[IsItAws]: javascript:location.href='https://isitonaws.com/discover?name='+location.host;void'1.3.6' "IsItAws" +[KillStickyHeaders]: javascript:Array.from(document.querySelectorAll('body%20%2A')).filter(e=%3E%5B'fixed','sticky'%5D.includes(getComputedStyle(e).position)).forEach(e=%3Ee.remove());void'2.1.1' "KillStickyHeaders" +[Linklighter]: javascript:'use%20strict';(()=%3E%7Bconst%20t=encodeURIComponent,e=window.getSelection();if(!e)return;const%20n=e.toString(),o=n.length,i=document.URL,s=i.indexOf('%23');let%20r=i,c='',l='',a='';if(e.rangeCount%3E0%26%26n%26%26(document.body.textContent%7C%7C'').split(n).length-1%3E1)%7Bconst%20t=e.getRangeAt(0),n=t.commonAncestorContainer.textContent%7C%7C'',%7BstartOffset:o,endOffset:i%7D=t,s=Math.max(0,o-20);if(l=n.substring(s,o).trim(),s%3E0%26%26'%20'!==n.charAt(s-1))%7Bconst%20t=l.indexOf('%20');t%3E0%26%26(l=l.substring(t+1))%7Dconst%20r=Math.min(n.length,i+20);if(a=n.substring(i,r).trim(),r%3Cn.length%26%26'%20'!==n.charAt(r))%7Bconst%20t=a.lastIndexOf('%20');t%3E0%26%26(a=a.substring(0,t))%7D%7Dif(e.removeAllRanges(),n%26%26''!==n)%7Bs%3E-1%26%26(r=r.substring(0,s));let%20e='';if(l%26%26(e=t(l)+'-,'),80%3Eo)c=n,e+=t(n);else%7Blet%20i=~~(o/2-2);o%3E150?i=48:o%3E100%26%26(i=~~(o/3));let%20s=n.substring(0,i),r=n.slice(o-i);const%20l=s.lastIndexOf('%20');l%3Ei/2%26%26(s=s.substring(0,l));const%20a=r.indexOf('%20');a%3E-1%26%26i/2%3Ea%26%26(r=r.substring(a+1)),c=s+'%E2%80%A6',e+=%60$%7Bt(s)%7D,$%7Bt(r)%7D%60%7Da%26%26(e+=',-'+t(a)),r+='%23:~:text='+e,r=r.replace(/(%250A%7C%250D%7C%2509%7C%2520)+$/,''),r=r.replace(/(%2520)%7B2,%7D/g,'%2520'),r=r.replace(/%23%23+:~:text=/,'%23:~:text=')%7Dif(r!==i%26%26confirm(%60Open%20URL%20with%20highlight%20on%20%22$%7Bc%7D%22%20and%20copy%20URL%20to%20clipboard?%60))%7Bnavigator.clipboard.writeText(r).catch(()=%3E%7Balert('Could%20not%20copy%20to%20clipboard.%20URL%20is%20in%20the%20new%20tab.')%7D);const%20t=window.open(r,'%5Fblank');t?t.opener=null:alert('Popup%20blocked.%20URL%20copied%20to%20clipboard.')%7D%7D)();void'2.1.1' "Linklighter" +[OpenInBrave]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='brave://open-url?url='+encodeURIComponent(location.href);void'1.1.3' "OpenInBrave" +[OpenInChrome]: javascript:'use%20strict';if(/iP(ad%7Chone)/.test(navigator.userAgent))%7Bconst%20o=%60googlechrome$%7B'https:'===location.protocol?'s':''%7D://%60;location.href=%60$%7Bo%7D$%7Blocation.host%7D$%7Blocation.pathname%7D$%7Blocation.search%7D$%7Blocation.hash%7D%60%7Dvoid'1.0.1' "OpenInChrome" +[OpenInDDG]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60ddgQuickLink://$%7Blocation.host%7D$%7Blocation.pathname%7D$%7Blocation.search%7D$%7Blocation.hash%7D%60;void'1.0.1' "OpenInDDG" +[OpenInEdge]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='microsoft-edge-'+location.href;void'1.0.1' "OpenInEdge" +[OpenInFirefox]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='firefox://open-url?url='+encodeURIComponent(location.href);void'1.6.3' "OpenInFirefox" +[OpenInFirefox-Focus]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60firefox-focus://open-url?url=$%7BencodeURIComponent(location.href)%7D%26private=true%60;void'1.1.3' "OpenInFirefox-Focus" +[OpenInFirefox-Private]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60firefox://open-url?url=$%7BencodeURIComponent(location.href)%7D%26private=true%60;void'1.1.3' "OpenInFirefox-Private" +[OpenInOpera]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='touch-'+location.href;void'1.0.1' "OpenInOpera" +[OpenInOrion]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='orion://open-url?url='+encodeURIComponent(location.href);void'1.0.1' "OpenInOrion" +[OpenInGoodReader]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent)%26%26/%5C.pdf($%7C%5C?)/.test(location.href))location.href='gr'+location.href;void'1.5.3' "OpenInGoodReader" +[OpenInTextastic]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=location.href.replace(/%5Ehttps?/,'textastic');void'1.1.3' "OpenInTextastic" +[OpenInWorkingCopy]: javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy://show?remote=$%7BencodeURIComponent(location.href.split('/').slice(0,5).join('/'))%7D.git%60;void'1.6.3' "OpenInWorkingCopy" +[OpenURLParam]: javascript:'use%20strict';(()=%3E%7Bconst%20t=new%20URL(document.location.href);if('https:'!==t.protocol%7C%7C13%3Et.search.length)return;const%20e=new%20URLSearchParams(t.search),n=%5B'url','destination','redirect','target','goto','u','dest','link','out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t);return%20n?decodeURIComponent(n):''%7D).find(t=%3Et.match(/%5Ehttps:/));n%26%26window.location.replace(new%20URL(n))%7D)();void'1.2.2' "OpenURLParam" +[UtmStrip]: javascript:'use%20strict';(()=%3E%7Bconst%20t=location.pathname,e=location.search;if(3%3Ee.length%26%26!t.includes('/amp'))return;const%20i=location.hostname,s=new%20URLSearchParams(e),%5F=%5B'assetType','elqTrack','mkt%5Ftok','originalReferer','referrer','terminal%5Fid','trk','trkCampaign','trkInfo','anid','assetid','campaignid','eid','gclid','recipientid','siteid','sib%5Fcuid','sib%5Fsid','%5Fbta%5Ftid','%5Fbta%5Fc','%5F%5Fs','fbclid','hrc','igsh','igshid','refsrc','%5Fgl','gclsrc','gs%5Fl','srsltid','%5Fhsenc','%5Fhsmi','%5F%5Fhsfp','%5F%5Fhssc','%5F%5Fhstc','cm%5Fmmc','cm%5Fre','cm%5Fsp','manual%5Fcm%5Fmmc','%5Fke','%5Fkx','trk%5Fcontact','trk%5Fmsg','trk%5Fmodule','trk%5Fsid','mc%5Fcid','mc%5Feid','iesrc','msclkid','dclid','twclid','ttclid','oly%5Fenc%5Fid','oly%5Fanon%5Fid','epik','vero%5Fid','rdt%5Fcid','ScCid','qclid','tblci','cjevent','ef%5Fid','outbrain%5Fcid'%5D,a=%5B'fb%5F','action%5F','ga%5F','utm%5F','hmb%5F','hsa%5F','mtm%5F','pk%5F','oly%5F','stm%5F'%5D;/%5C.aliexpress%5C.%5Ba-z%5D%7B2,3%7D$/.test(i)?(%5F.push('algo%5Fevid','algo%5Fpvid','btsid','spm','scm','ws%5Fab%5Ftest'),a.push('aff%5F')):/(%7C%5C.)amazon%5C.com$/.test(i)?%5F.push('%5Fencoding','asc%5Fcampaign','asc%5Frefurl','asc%5Fsource','ascsubtag','content-id','crid','cv%5Fct%5Fcx','dib%5Ftag','dib','ie','language','linkCode','linkId','pd%5Frd%5Fi','pd%5Frd%5Fr','pd%5Frd%5Fw','pd%5Frd%5Fwg','pf%5Frd%5Fi','pf%5Frd%5Fm','pf%5Frd%5Fp','pf%5Frd%5Fr','pf%5Frd%5Fs','pf%5Frd%5Ft','pf','psc','qid','ref%5F','sprefix','sr','tag','th'):i.endsWith('.ebay.com')%7C%7C/%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D$/.test(i)?%5F.push('mkevt','mkcid','mkrid','campid','toolid','customid','norover','itm','amdata'):/(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom?%5C.%5Ba-z%5D%7B2%7D)$/.test(i)%26%26t.startsWith('/search')?%5F.push('aqs','ei','gs%5Flp','gs%5Fssp','iflsig','sca%5Fesv','ved','oq','sa','uact','rlz','sxsrf','bih','biw','client','prmd','sclient','source','sourceid','ie','oe'):i.endsWith('.linkedin.com')?%5F.push('li%5Ffat%5Fid','licu','lipi','midSig','midToken','refId'):i.endsWith('.target.com')?%5F.push('afid','clkid','lnm','preselect','tref'):i.endsWith('.temu.com')?(%5F.push('%5Fbg%5Ffs','%5Fp%5Fjump%5Fid','%5Fp%5Frfs','refer%5Fpage%5Fid','refer%5Fpage%5Fname','refer%5Fpage%5Fsn'),a.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i?%5F.push('%5Fd','%5Fr','%5Ft','is%5Ffrom%5Fwebapp','preview%5Fpb','share%5Fapp%5Fname','share%5Fitem%5Fid','tt4d%5Ft','timestamp','u%5Fcode','user%5Fid'):/%5C.(twitter%7Cx)%5C.com$/.test(i)%7C%7C/%5E(twitter%7Cx)%5C.com$/.test(i)?%5F.push('cn','ref%5Fsrc','ref%5Furl','s','t'):i.endsWith('.walmart.com')?%5F.push('adsredirect','affiliates%5Fad%5Fid','athcpid','athpgid','athcgid','athmtid','athstid','athznid','athiession','athancid','athposb','athena','campaign%5Fid','wmlspartner','wt%5Fmc'):(/(m%7Cwww)%5C.youtube%5C.com$/.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26%5F.push('ac','annotation%5Fid','app','feature','gclid','kw','src%5Fvid');const%20c=new%20Set(%5F.map(t=%3Et.toLowerCase())),r=t=%3E%7Bconst%20e=t.toLowerCase();return%20c.has(e)%7C%7Ca.some(t=%3Ee.startsWith(t))%7C%7C/%5Ecm%5Fmmca%5Cd+$/i.test(t)%7D;for(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t);let%20d=s.toString();d=d?'?'+d:'';const%20o=t.replace(/%5C/amp%5C/?$/,''),n=%60$%7Blocation.protocol%7D//$%7Blocation.host%7D$%7Bo%7D$%7Bd%7D$%7Blocation.hash%7D%60;if(confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard?')%26%26(navigator.clipboard.writeText(n),e!==d%7C%7Ct!==o))%7Bhistory.replaceState(null,'',n);const%20t=window.open(n,'%5Fself','noreferrer');t%26%26(t.opener=null)%7D%7D)();void'2.3.3' "UtmStrip" +[unskim]: javascript:'use%20strict';(()=%3E%7Blet%20e=new%20URL(document.location.href);if('safari-resource:/ErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')?.textContent?.match(/Safari%20can%5B'%5Cu2019%5Dt%20open%20the%20page%20%5B%22%5Cu201C%5D(https?:%5B%5E%22%5Cu201D%5D+)%5B%22%5Cu201D%5D/)?.%5B1%5D;t%26%26(e=new%20URL(t))%7Dif(13%3Ee.search.length)return;const%20t=new%20URLSearchParams(e.search),r=%5B'url','destination','redirect','target','goto','u','dest','link','out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e);return%20r?decodeURIComponent(r):''%7D).find(e=%3Ee.match(/%5Ehttps?:/));if(r)%7Bconst%20e=new%20URL(r);if(e.searchParams.size%3E0)%7Bconst%20t=new%20URLSearchParams(e.search);for(const%20e%20of%5B...t.keys()%5D)%7Bconst%20r=e.toLowerCase();(r.startsWith('utm%5F')%7C%7Cr.startsWith('fb%5F')%7C%7C%5B'fbclid','gclid','msclkid','ref','referrer','ttclid','twclid'%5D.includes(r))%26%26t.delete(e)%7De.search=t.toString()%7Dwindow.location.replace(e)%7D%7D)();void'2.1.2' "unskim" +[x-man]: javascript:'use%20strict';(()=%3E%7Bconst%20i=navigator.userAgent,n=i.includes('Chrome/')%7C%7Ci.includes('Firefox/')%7C%7Ci.includes('Brave/')%7C%7Ci.includes('Edg/'),o=i.includes('Safari/'),t=!n%26%26!o,a=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints,e=window.getSelection();if(!e)return;const%20l=e.toString().split('%5Cn')%5B0%5D.trim();let%20r='x-man-page://';const%20c=l.match(/%5E(.%2A?)%5C((%5Cd)%5C)$/);if(r+=c?'1'===c%5B2%5D?c%5B1%5D:%60$%7Bc%5B2%5D%7D/$%7Bc%5B1%5D%7D%60:l,l)%7Bif(confirm(%60Link%20for%20%22$%7Bl%7D%22%20is:%20$%7Br%7D%5Cn%5CnCopy%20to%20clipboard?%60))%7Blet%20i='';if(navigator.clipboard?navigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22$%7Br%7D%22%20to%20clipboard.%60,r=''),a%26%26''!==r)%7Blet%20n=null;try%7Bn=window.open(r),n%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22$%7Br%7D%22%60%7Dfinally%7Bwindow.focus(),null!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D,3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22$%7Br%7D%22%60);''!==i%26%26alert(i)%7De.empty()%7D%7D)();void'1.3.2' "x-man" -[Setup deLighter]: https://mobilemind.github.io/OpenInlets/x/#javascript:document.location.reload()%3Bvoid'1.3.1' "Setup deLighter" -[Setup FYI]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20e=encodeURIComponent(document.title)%2Ct='%250A'%2Cn=window.getSelection()%2Co=n%26%26'Range'===n.type%26%26n.rangeCount%3E0%3Fn.getRangeAt(0).toString():''%3Blocation.href=%60mailto:%3Fsubject=fyi:%24%7Be%7D%26body=%24%7Be%7D%24%7Bt%7D%24%7BencodeURIComponent(document.URL)%7D%24%7Bt%7D---%24%7Bt%7D%24%7BencodeURIComponent(o)%7D%24%7Bt%7D%24%7Bt%7D%60%7D)()%3Bvoid'3.3.0' "Setup FYI" -[Setup IsItAws]: https://mobilemind.github.io/OpenInlets/x/#javascript:location.href='https:%2F%2Fisitonaws.com%2Fdiscover%3Fname='%2Blocation.host%3Bvoid'1.3.5' "Setup IsItAws" -[Setup KillStickyHeaders]: https://mobilemind.github.io/OpenInlets/x/#javascript:Array.from(document.querySelectorAll('body%20%2A')).filter(e=%3E%5B'fixed'%2C'sticky'%5D.includes(getComputedStyle(e).position)).forEach(e=%3Ee.remove())%3Bvoid'2.1.0' "Setup KillStickyHeaders" -[Setup Linklighter]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=encodeURIComponent%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20n=e.toString()%2Co=n.length%2Ci=document.URL%2Cs=i.indexOf('%23')%3Blet%20r=i%2Cc=''%2Cl=''%2Ca=''%3Bif(e.rangeCount%3E0%26%26n%26%26(document.body.textContent%7C%7C'').split(n).length-1%3E1)%7Bconst%20t=e.getRangeAt(0)%2Cn=t.commonAncestorContainer.textContent%7C%7C''%2C%7BstartOffset:o%2CendOffset:i%7D=t%2Cs=Math.max(0%2Co-20)%3Bif(l=n.substring(s%2Co).trim()%2Cs%3E0%26%26'%20'!==n.charAt(s-1))%7Bconst%20t=l.indexOf('%20')%3Bt%3E0%26%26(l=l.substring(t%2B1))%7Dconst%20r=Math.min(n.length%2Ci%2B20)%3Bif(a=n.substring(i%2Cr).trim()%2Cr%3Cn.length%26%26'%20'!==n.charAt(r))%7Bconst%20t=a.lastIndexOf('%20')%3Bt%3E0%26%26(a=a.substring(0%2Ct))%7D%7Dif(e.removeAllRanges()%2Cn%26%26''!==n)%7Bs%3E-1%26%26(r=r.substring(0%2Cs))%3Blet%20e=''%3Bif(l%26%26(e=t(l)%2B'-%2C')%2C80%3Eo)c=n%2Ce%2B=t(n)%3Belse%7Blet%20i=~~(o%2F2-2)%3Bo%3E150%3Fi=48:o%3E100%26%26(i=~~(o%2F3))%3Blet%20s=n.substring(0%2Ci)%2Cr=n.slice(o-i)%3Bconst%20l=s.lastIndexOf('%20')%3Bl%3Ei%2F2%26%26(s=s.substring(0%2Cl))%3Bconst%20a=r.indexOf('%20')%3Ba%3E-1%26%26i%2F2%3Ea%26%26(r=r.substring(a%2B1))%2Cc=s%2B'%E2%80%A6'%2Ce%2B=%60%24%7Bt(s)%7D%2C%24%7Bt(r)%7D%60%7Da%26%26(e%2B='%2C-'%2Bt(a))%2Cr%2B='%23:~:text='%2Be%2Cr=r.replace(%2F(%250A%7C%250D%7C%2509%7C%2520)%2B%24%2F%2C'')%2Cr=r.replace(%2F(%2520)%7B2%2C%7D%2Fg%2C'%2520')%2Cr=r.replace(%2F%23%23%2B:~:text=%2F%2C'%23:~:text=')%7Dif(r!==i%26%26confirm(%60Open%20URL%20with%20highlight%20on%20%22%24%7Bc%7D%22%20and%20copy%20URL%20to%20clipboard%3F%60))%7Bnavigator.clipboard.writeText(r).catch(()=%3E%7Balert('Could%20not%20copy%20to%20clipboard.%20URL%20is%20in%20the%20new%20tab.')%7D)%3Bconst%20t=window.open(r%2C'%5Fblank')%3Bt%3Ft.opener=null:alert('Popup%20blocked.%20URL%20copied%20to%20clipboard.')%7D%7D)()%3Bvoid'2.1.0' "Setup Linklighter" -[Setup OpenInBrave]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='brave:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.1.2' "Setup OpenInBrave" -[Setup OpenInChrome]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3Bif(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))%7Bconst%20o=%60googlechrome%24%7B'https:'===location.protocol%3F's':''%7D:%2F%2F%60%3Blocation.href=%60%24%7Bo%7D%24%7Blocation.host%7D%24%7Blocation.pathname%7D%24%7Blocation.search%7D%24%7Blocation.hash%7D%60%7Dvoid'1.0.0' "Setup OpenInChrome" -[Setup OpenInDDG]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60ddgQuickLink:%2F%2F%24%7Blocation.host%7D%24%7Blocation.pathname%7D%24%7Blocation.search%7D%24%7Blocation.hash%7D%60%3Bvoid'1.0.0' "Setup OpenInDDG" -[Setup OpenInEdge]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='microsoft-edge-'%2Blocation.href%3Bvoid'1.0.0' "Setup OpenInEdge" -[Setup OpenInFirefox]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='firefox:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.6.2' "Setup OpenInFirefox" -[Setup OpenInFirefox-Focus]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60firefox-focus:%2F%2Fopen-url%3Furl=%24%7BencodeURIComponent(location.href)%7D%26private=true%60%3Bvoid'1.1.2' "Setup OpenInFirefox-Focus" -[Setup OpenInFirefox-Private]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60firefox:%2F%2Fopen-url%3Furl=%24%7BencodeURIComponent(location.href)%7D%26private=true%60%3Bvoid'1.1.2' "Setup OpenInFirefox-Private" -[Setup OpenInGoodReader]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26%2F%5C.pdf(%24%7C%5C%3F)%2F.test(location.href))location.href='gr'%2Blocation.href%3Bvoid'1.5.2' "Setup OpenInGoodReader" -[Setup OpenInOpera]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='touch-'%2Blocation.href%3Bvoid'1.0.0' "Setup OpenInOpera" -[Setup OpenInOrion]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='orion:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.0.0' "Setup OpenInOrion" -[Setup OpenInTextastic]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=location.href.replace(%2F%5Ehttps%3F%2F%2C'textastic')%3Bvoid'1.1.2' "Setup OpenInTextastic" -[Setup OpenInWorkingCopy]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy:%2F%2Fshow%3Fremote=%24%7BencodeURIComponent(location.href.split('%2F').slice(0%2C5).join('%2F'))%7D.git%60%3Bvoid'1.6.2' "Setup OpenInWorkingCopy" -[Setup OpenURLParam]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=new%20URL(document.location.href)%3Bif('https:'!==t.protocol%7C%7C13%3Et.search.length)return%3Bconst%20e=new%20URLSearchParams(t.search)%2Cn=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t)%3Breturn%20n%3FdecodeURIComponent(n):''%7D).find(t=%3Et.match(%2F%5Ehttps:%2F))%3Bn%26%26window.location.replace(new%20URL(n))%7D)()%3Bvoid'1.2.1' "Setup OpenURLParam" -[Setup UtmStrip]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=location.pathname%2Ce=location.search%3Bif(3%3Ee.length%26%26!t.includes('%2Famp'))return%3Bconst%20i=location.hostname%2Cs=new%20URLSearchParams(e)%2C%5F=%5B'assetType'%2C'elqTrack'%2C'mkt%5Ftok'%2C'originalReferer'%2C'referrer'%2C'terminal%5Fid'%2C'trk'%2C'trkCampaign'%2C'trkInfo'%2C'anid'%2C'assetid'%2C'campaignid'%2C'eid'%2C'gclid'%2C'recipientid'%2C'siteid'%2C'sib%5Fcuid'%2C'sib%5Fsid'%2C'%5Fbta%5Ftid'%2C'%5Fbta%5Fc'%2C'%5F%5Fs'%2C'fbclid'%2C'hrc'%2C'igsh'%2C'igshid'%2C'refsrc'%2C'%5Fgl'%2C'gclsrc'%2C'gs%5Fl'%2C'srsltid'%2C'%5Fhsenc'%2C'%5Fhsmi'%2C'%5F%5Fhsfp'%2C'%5F%5Fhssc'%2C'%5F%5Fhstc'%2C'cm%5Fmmc'%2C'cm%5Fre'%2C'cm%5Fsp'%2C'manual%5Fcm%5Fmmc'%2C'%5Fke'%2C'%5Fkx'%2C'trk%5Fcontact'%2C'trk%5Fmsg'%2C'trk%5Fmodule'%2C'trk%5Fsid'%2C'mc%5Fcid'%2C'mc%5Feid'%2C'iesrc'%2C'msclkid'%2C'dclid'%2C'twclid'%2C'ttclid'%2C'oly%5Fenc%5Fid'%2C'oly%5Fanon%5Fid'%2C'epik'%2C'vero%5Fid'%2C'rdt%5Fcid'%2C'ScCid'%2C'qclid'%2C'tblci'%2C'cjevent'%2C'ef%5Fid'%2C'outbrain%5Fcid'%5D%2Ca=%5B'fb%5F'%2C'action%5F'%2C'ga%5F'%2C'utm%5F'%2C'hmb%5F'%2C'hsa%5F'%2C'mtm%5F'%2C'pk%5F'%2C'oly%5F'%2C'stm%5F'%5D%3B%2F%5C.aliexpress%5C.%5Ba-z%5D%7B2%2C3%7D%24%2F.test(i)%3F(%5F.push('algo%5Fevid'%2C'algo%5Fpvid'%2C'btsid'%2C'spm'%2C'scm'%2C'ws%5Fab%5Ftest')%2Ca.push('aff%5F')):%2F(%7C%5C.)amazon%5C.com%24%2F.test(i)%3F%5F.push('%5Fencoding'%2C'asc%5Fcampaign'%2C'asc%5Frefurl'%2C'asc%5Fsource'%2C'ascsubtag'%2C'content-id'%2C'crid'%2C'cv%5Fct%5Fcx'%2C'dib%5Ftag'%2C'dib'%2C'ie'%2C'language'%2C'linkCode'%2C'linkId'%2C'pd%5Frd%5Fi'%2C'pd%5Frd%5Fr'%2C'pd%5Frd%5Fw'%2C'pd%5Frd%5Fwg'%2C'pf%5Frd%5Fi'%2C'pf%5Frd%5Fm'%2C'pf%5Frd%5Fp'%2C'pf%5Frd%5Fr'%2C'pf%5Frd%5Fs'%2C'pf%5Frd%5Ft'%2C'pf'%2C'psc'%2C'qid'%2C'ref%5F'%2C'sprefix'%2C'sr'%2C'tag'%2C'th'):i.endsWith('.ebay.com')%7C%7C%2F%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D%24%2F.test(i)%3F%5F.push('mkevt'%2C'mkcid'%2C'mkrid'%2C'campid'%2C'toolid'%2C'customid'%2C'norover'%2C'itm'%2C'amdata'):%2F(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom%3F%5C.%5Ba-z%5D%7B2%7D)%24%2F.test(i)%26%26t.startsWith('%2Fsearch')%3F%5F.push('aqs'%2C'ei'%2C'gs%5Flp'%2C'gs%5Fssp'%2C'iflsig'%2C'sca%5Fesv'%2C'ved'%2C'oq'%2C'sa'%2C'uact'%2C'rlz'%2C'sxsrf'%2C'bih'%2C'biw'%2C'client'%2C'prmd'%2C'sclient'%2C'source'%2C'sourceid'%2C'ie'%2C'oe'):i.endsWith('.linkedin.com')%3F%5F.push('li%5Ffat%5Fid'%2C'licu'%2C'lipi'%2C'midSig'%2C'midToken'%2C'refId'):i.endsWith('.target.com')%3F%5F.push('afid'%2C'clkid'%2C'lnm'%2C'preselect'%2C'tref'):i.endsWith('.temu.com')%3F(%5F.push('%5Fbg%5Ffs'%2C'%5Fp%5Fjump%5Fid'%2C'%5Fp%5Frfs'%2C'refer%5Fpage%5Fid'%2C'refer%5Fpage%5Fname'%2C'refer%5Fpage%5Fsn')%2Ca.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i%3F%5F.push('%5Fd'%2C'%5Fr'%2C'%5Ft'%2C'is%5Ffrom%5Fwebapp'%2C'preview%5Fpb'%2C'share%5Fapp%5Fname'%2C'share%5Fitem%5Fid'%2C'tt4d%5Ft'%2C'timestamp'%2C'u%5Fcode'%2C'user%5Fid'):%2F%5C.(twitter%7Cx)%5C.com%24%2F.test(i)%7C%7C%2F%5E(twitter%7Cx)%5C.com%24%2F.test(i)%3F%5F.push('cn'%2C'ref%5Fsrc'%2C'ref%5Furl'%2C's'%2C't'):i.endsWith('.walmart.com')%3F%5F.push('adsredirect'%2C'affiliates%5Fad%5Fid'%2C'athcpid'%2C'athpgid'%2C'athcgid'%2C'athmtid'%2C'athstid'%2C'athznid'%2C'athiession'%2C'athancid'%2C'athposb'%2C'athena'%2C'campaign%5Fid'%2C'wmlspartner'%2C'wt%5Fmc'):(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26%5F.push('ac'%2C'annotation%5Fid'%2C'app'%2C'feature'%2C'gclid'%2C'kw'%2C'src%5Fvid')%3Bconst%20c=new%20Set(%5F.map(t=%3Et.toLowerCase()))%2Cr=t=%3E%7Bconst%20e=t.toLowerCase()%3Breturn%20c.has(e)%7C%7Ca.some(t=%3Ee.startsWith(t))%7C%7C%2F%5Ecm%5Fmmca%5Cd%2B%24%2Fi.test(t)%7D%3Bfor(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t)%3Blet%20d=s.toString()%3Bd=d%3F'%3F'%2Bd:''%3Bconst%20o=t.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%2Cn=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bo%7D%24%7Bd%7D%24%7Blocation.hash%7D%60%3Bif(confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F')%26%26(navigator.clipboard.writeText(n)%2Ce!==d%7C%7Ct!==o))%7Bhistory.replaceState(null%2C''%2Cn)%3Bconst%20t=window.open(n%2C'%5Fself'%2C'noreferrer')%3Bt%26%26(t.opener=null)%7D%7D)()%3Bvoid'2.3.2' "Setup UtmStrip" -[Setup unskim]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Blet%20e=new%20URL(document.location.href)%3Bif('safari-resource:%2FErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')%3F.textContent%3F.match(%2FSafari%20can%5B'%5Cu2019%5Dt%20open%20the%20page%20%5B%22%5Cu201C%5D(https%3F:%5B%5E%22%5Cu201D%5D%2B)%5B%22%5Cu201D%5D%2F)%3F.%5B1%5D%3Bt%26%26(e=new%20URL(t))%7Dif(13%3Ee.search.length)return%3Bconst%20t=new%20URLSearchParams(e.search)%2Cr=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e)%3Breturn%20r%3FdecodeURIComponent(r):''%7D).find(e=%3Ee.match(%2F%5Ehttps%3F:%2F))%3Bif(r)%7Bconst%20e=new%20URL(r)%3Bif(e.searchParams.size%3E0)%7Bconst%20t=new%20URLSearchParams(e.search)%3Bfor(const%20e%20of%5B...t.keys()%5D)%7Bconst%20r=e.toLowerCase()%3B(r.startsWith('utm%5F')%7C%7Cr.startsWith('fb%5F')%7C%7C%5B'fbclid'%2C'gclid'%2C'msclkid'%2C'ref'%2C'referrer'%2C'ttclid'%2C'twclid'%5D.includes(r))%26%26t.delete(e)%7De.search=t.toString()%7Dwindow.location.replace(e)%7D%7D)()%3Bvoid'2.1.1' "Setup unskim" -[Setup x-man]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict'%3B(()=%3E%7Bconst%20i=navigator.userAgent%2Cn=i.includes('Chrome%2F')%7C%7Ci.includes('Firefox%2F')%7C%7Ci.includes('Brave%2F')%7C%7Ci.includes('Edg%2F')%2Co=i.includes('Safari%2F')%2Ct=!n%26%26!o%2Ca=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20l=e.toString().split('%5Cn')%5B0%5D.trim()%3Blet%20r='x-man-page:%2F%2F'%3Bconst%20c=l.match(%2F%5E(.%2A%3F)%5C((%5Cd)%5C)%24%2F)%3Bif(r%2B=c%3F'1'===c%5B2%5D%3Fc%5B1%5D:%60%24%7Bc%5B2%5D%7D%2F%24%7Bc%5B1%5D%7D%60:l%2Cl)%7Bif(confirm(%60Link%20for%20%22%24%7Bl%7D%22%20is:%20%24%7Br%7D%5Cn%5CnCopy%20to%20clipboard%3F%60))%7Blet%20i=''%3Bif(navigator.clipboard%3Fnavigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22%24%7Br%7D%22%20to%20clipboard.%60%2Cr='')%2Ca%26%26''!==r)%7Blet%20n=null%3Btry%7Bn=window.open(r)%2Cn%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22%24%7Br%7D%22%60%7Dfinally%7Bwindow.focus()%2Cnull!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D%2C3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22%24%7Br%7D%22%60)%3B''!==i%26%26alert(i)%7De.empty()%7D%7D)()%3Bvoid'1.3.1' "Setup x-man" +[Setup deLighter]: https://mobilemind.github.io/OpenInlets/x/#javascript:document.location.reload();void'1.3.2' "Setup deLighter" +[Setup FYI]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';(()=%3E%7Bconst%20e=encodeURIComponent(document.title),t='%250A',n=window.getSelection(),o=n%26%26'Range'===n.type%26%26n.rangeCount%3E0?n.getRangeAt(0).toString():'';location.href=%60mailto:?subject=fyi:$%7Be%7D%26body=$%7Be%7D$%7Bt%7D$%7BencodeURIComponent(document.URL)%7D$%7Bt%7D---$%7Bt%7D$%7BencodeURIComponent(o)%7D$%7Bt%7D$%7Bt%7D%60%7D)();void'3.3.1' "Setup FYI" +[Setup IsItAws]: https://mobilemind.github.io/OpenInlets/x/#javascript:location.href='https://isitonaws.com/discover?name='+location.host;void'1.3.6' "Setup IsItAws" +[Setup KillStickyHeaders]: https://mobilemind.github.io/OpenInlets/x/#javascript:Array.from(document.querySelectorAll('body%20%2A')).filter(e=%3E%5B'fixed','sticky'%5D.includes(getComputedStyle(e).position)).forEach(e=%3Ee.remove());void'2.1.1' "Setup KillStickyHeaders" +[Setup Linklighter]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';(()=%3E%7Bconst%20t=encodeURIComponent,e=window.getSelection();if(!e)return;const%20n=e.toString(),o=n.length,i=document.URL,s=i.indexOf('%23');let%20r=i,c='',l='',a='';if(e.rangeCount%3E0%26%26n%26%26(document.body.textContent%7C%7C'').split(n).length-1%3E1)%7Bconst%20t=e.getRangeAt(0),n=t.commonAncestorContainer.textContent%7C%7C'',%7BstartOffset:o,endOffset:i%7D=t,s=Math.max(0,o-20);if(l=n.substring(s,o).trim(),s%3E0%26%26'%20'!==n.charAt(s-1))%7Bconst%20t=l.indexOf('%20');t%3E0%26%26(l=l.substring(t+1))%7Dconst%20r=Math.min(n.length,i+20);if(a=n.substring(i,r).trim(),r%3Cn.length%26%26'%20'!==n.charAt(r))%7Bconst%20t=a.lastIndexOf('%20');t%3E0%26%26(a=a.substring(0,t))%7D%7Dif(e.removeAllRanges(),n%26%26''!==n)%7Bs%3E-1%26%26(r=r.substring(0,s));let%20e='';if(l%26%26(e=t(l)+'-,'),80%3Eo)c=n,e+=t(n);else%7Blet%20i=~~(o/2-2);o%3E150?i=48:o%3E100%26%26(i=~~(o/3));let%20s=n.substring(0,i),r=n.slice(o-i);const%20l=s.lastIndexOf('%20');l%3Ei/2%26%26(s=s.substring(0,l));const%20a=r.indexOf('%20');a%3E-1%26%26i/2%3Ea%26%26(r=r.substring(a+1)),c=s+'%E2%80%A6',e+=%60$%7Bt(s)%7D,$%7Bt(r)%7D%60%7Da%26%26(e+=',-'+t(a)),r+='%23:~:text='+e,r=r.replace(/(%250A%7C%250D%7C%2509%7C%2520)+$/,''),r=r.replace(/(%2520)%7B2,%7D/g,'%2520'),r=r.replace(/%23%23+:~:text=/,'%23:~:text=')%7Dif(r!==i%26%26confirm(%60Open%20URL%20with%20highlight%20on%20%22$%7Bc%7D%22%20and%20copy%20URL%20to%20clipboard?%60))%7Bnavigator.clipboard.writeText(r).catch(()=%3E%7Balert('Could%20not%20copy%20to%20clipboard.%20URL%20is%20in%20the%20new%20tab.')%7D);const%20t=window.open(r,'%5Fblank');t?t.opener=null:alert('Popup%20blocked.%20URL%20copied%20to%20clipboard.')%7D%7D)();void'2.1.1' "Setup Linklighter" +[Setup OpenInBrave]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='brave://open-url?url='+encodeURIComponent(location.href);void'1.1.3' "Setup OpenInBrave" +[Setup OpenInChrome]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';if(/iP(ad%7Chone)/.test(navigator.userAgent))%7Bconst%20o=%60googlechrome$%7B'https:'===location.protocol?'s':''%7D://%60;location.href=%60$%7Bo%7D$%7Blocation.host%7D$%7Blocation.pathname%7D$%7Blocation.search%7D$%7Blocation.hash%7D%60%7Dvoid'1.0.1' "Setup OpenInChrome" +[Setup OpenInDDG]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60ddgQuickLink://$%7Blocation.host%7D$%7Blocation.pathname%7D$%7Blocation.search%7D$%7Blocation.hash%7D%60;void'1.0.1' "Setup OpenInDDG" +[Setup OpenInEdge]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='microsoft-edge-'+location.href;void'1.0.1' "Setup OpenInEdge" +[Setup OpenInFirefox]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='firefox://open-url?url='+encodeURIComponent(location.href);void'1.6.3' "Setup OpenInFirefox" +[Setup OpenInFirefox-Focus]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60firefox-focus://open-url?url=$%7BencodeURIComponent(location.href)%7D%26private=true%60;void'1.1.3' "Setup OpenInFirefox-Focus" +[Setup OpenInFirefox-Private]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60firefox://open-url?url=$%7BencodeURIComponent(location.href)%7D%26private=true%60;void'1.1.3' "Setup OpenInFirefox-Private" +[Setup OpenInGoodReader]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent)%26%26/%5C.pdf($%7C%5C?)/.test(location.href))location.href='gr'+location.href;void'1.5.3' "Setup OpenInGoodReader" +[Setup OpenInOpera]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='touch-'+location.href;void'1.0.1' "Setup OpenInOpera" +[Setup OpenInOrion]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='orion://open-url?url='+encodeURIComponent(location.href);void'1.0.1' "Setup OpenInOrion" +[Setup OpenInTextastic]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=location.href.replace(/%5Ehttps?/,'textastic');void'1.1.3' "Setup OpenInTextastic" +[Setup OpenInWorkingCopy]: https://mobilemind.github.io/OpenInlets/x/#javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy://show?remote=$%7BencodeURIComponent(location.href.split('/').slice(0,5).join('/'))%7D.git%60;void'1.6.3' "Setup OpenInWorkingCopy" +[Setup OpenURLParam]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';(()=%3E%7Bconst%20t=new%20URL(document.location.href);if('https:'!==t.protocol%7C%7C13%3Et.search.length)return;const%20e=new%20URLSearchParams(t.search),n=%5B'url','destination','redirect','target','goto','u','dest','link','out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t);return%20n?decodeURIComponent(n):''%7D).find(t=%3Et.match(/%5Ehttps:/));n%26%26window.location.replace(new%20URL(n))%7D)();void'1.2.2' "Setup OpenURLParam" +[Setup UtmStrip]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';(()=%3E%7Bconst%20t=location.pathname,e=location.search;if(3%3Ee.length%26%26!t.includes('/amp'))return;const%20i=location.hostname,s=new%20URLSearchParams(e),%5F=%5B'assetType','elqTrack','mkt%5Ftok','originalReferer','referrer','terminal%5Fid','trk','trkCampaign','trkInfo','anid','assetid','campaignid','eid','gclid','recipientid','siteid','sib%5Fcuid','sib%5Fsid','%5Fbta%5Ftid','%5Fbta%5Fc','%5F%5Fs','fbclid','hrc','igsh','igshid','refsrc','%5Fgl','gclsrc','gs%5Fl','srsltid','%5Fhsenc','%5Fhsmi','%5F%5Fhsfp','%5F%5Fhssc','%5F%5Fhstc','cm%5Fmmc','cm%5Fre','cm%5Fsp','manual%5Fcm%5Fmmc','%5Fke','%5Fkx','trk%5Fcontact','trk%5Fmsg','trk%5Fmodule','trk%5Fsid','mc%5Fcid','mc%5Feid','iesrc','msclkid','dclid','twclid','ttclid','oly%5Fenc%5Fid','oly%5Fanon%5Fid','epik','vero%5Fid','rdt%5Fcid','ScCid','qclid','tblci','cjevent','ef%5Fid','outbrain%5Fcid'%5D,a=%5B'fb%5F','action%5F','ga%5F','utm%5F','hmb%5F','hsa%5F','mtm%5F','pk%5F','oly%5F','stm%5F'%5D;/%5C.aliexpress%5C.%5Ba-z%5D%7B2,3%7D$/.test(i)?(%5F.push('algo%5Fevid','algo%5Fpvid','btsid','spm','scm','ws%5Fab%5Ftest'),a.push('aff%5F')):/(%7C%5C.)amazon%5C.com$/.test(i)?%5F.push('%5Fencoding','asc%5Fcampaign','asc%5Frefurl','asc%5Fsource','ascsubtag','content-id','crid','cv%5Fct%5Fcx','dib%5Ftag','dib','ie','language','linkCode','linkId','pd%5Frd%5Fi','pd%5Frd%5Fr','pd%5Frd%5Fw','pd%5Frd%5Fwg','pf%5Frd%5Fi','pf%5Frd%5Fm','pf%5Frd%5Fp','pf%5Frd%5Fr','pf%5Frd%5Fs','pf%5Frd%5Ft','pf','psc','qid','ref%5F','sprefix','sr','tag','th'):i.endsWith('.ebay.com')%7C%7C/%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D$/.test(i)?%5F.push('mkevt','mkcid','mkrid','campid','toolid','customid','norover','itm','amdata'):/(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom?%5C.%5Ba-z%5D%7B2%7D)$/.test(i)%26%26t.startsWith('/search')?%5F.push('aqs','ei','gs%5Flp','gs%5Fssp','iflsig','sca%5Fesv','ved','oq','sa','uact','rlz','sxsrf','bih','biw','client','prmd','sclient','source','sourceid','ie','oe'):i.endsWith('.linkedin.com')?%5F.push('li%5Ffat%5Fid','licu','lipi','midSig','midToken','refId'):i.endsWith('.target.com')?%5F.push('afid','clkid','lnm','preselect','tref'):i.endsWith('.temu.com')?(%5F.push('%5Fbg%5Ffs','%5Fp%5Fjump%5Fid','%5Fp%5Frfs','refer%5Fpage%5Fid','refer%5Fpage%5Fname','refer%5Fpage%5Fsn'),a.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i?%5F.push('%5Fd','%5Fr','%5Ft','is%5Ffrom%5Fwebapp','preview%5Fpb','share%5Fapp%5Fname','share%5Fitem%5Fid','tt4d%5Ft','timestamp','u%5Fcode','user%5Fid'):/%5C.(twitter%7Cx)%5C.com$/.test(i)%7C%7C/%5E(twitter%7Cx)%5C.com$/.test(i)?%5F.push('cn','ref%5Fsrc','ref%5Furl','s','t'):i.endsWith('.walmart.com')?%5F.push('adsredirect','affiliates%5Fad%5Fid','athcpid','athpgid','athcgid','athmtid','athstid','athznid','athiession','athancid','athposb','athena','campaign%5Fid','wmlspartner','wt%5Fmc'):(/(m%7Cwww)%5C.youtube%5C.com$/.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26%5F.push('ac','annotation%5Fid','app','feature','gclid','kw','src%5Fvid');const%20c=new%20Set(%5F.map(t=%3Et.toLowerCase())),r=t=%3E%7Bconst%20e=t.toLowerCase();return%20c.has(e)%7C%7Ca.some(t=%3Ee.startsWith(t))%7C%7C/%5Ecm%5Fmmca%5Cd+$/i.test(t)%7D;for(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t);let%20d=s.toString();d=d?'?'+d:'';const%20o=t.replace(/%5C/amp%5C/?$/,''),n=%60$%7Blocation.protocol%7D//$%7Blocation.host%7D$%7Bo%7D$%7Bd%7D$%7Blocation.hash%7D%60;if(confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard?')%26%26(navigator.clipboard.writeText(n),e!==d%7C%7Ct!==o))%7Bhistory.replaceState(null,'',n);const%20t=window.open(n,'%5Fself','noreferrer');t%26%26(t.opener=null)%7D%7D)();void'2.3.3' "Setup UtmStrip" +[Setup unskim]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';(()=%3E%7Blet%20e=new%20URL(document.location.href);if('safari-resource:/ErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')?.textContent?.match(/Safari%20can%5B'%5Cu2019%5Dt%20open%20the%20page%20%5B%22%5Cu201C%5D(https?:%5B%5E%22%5Cu201D%5D+)%5B%22%5Cu201D%5D/)?.%5B1%5D;t%26%26(e=new%20URL(t))%7Dif(13%3Ee.search.length)return;const%20t=new%20URLSearchParams(e.search),r=%5B'url','destination','redirect','target','goto','u','dest','link','out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e);return%20r?decodeURIComponent(r):''%7D).find(e=%3Ee.match(/%5Ehttps?:/));if(r)%7Bconst%20e=new%20URL(r);if(e.searchParams.size%3E0)%7Bconst%20t=new%20URLSearchParams(e.search);for(const%20e%20of%5B...t.keys()%5D)%7Bconst%20r=e.toLowerCase();(r.startsWith('utm%5F')%7C%7Cr.startsWith('fb%5F')%7C%7C%5B'fbclid','gclid','msclkid','ref','referrer','ttclid','twclid'%5D.includes(r))%26%26t.delete(e)%7De.search=t.toString()%7Dwindow.location.replace(e)%7D%7D)();void'2.1.2' "Setup unskim" +[Setup x-man]: https://mobilemind.github.io/OpenInlets/x/#javascript:'use%20strict';(()=%3E%7Bconst%20i=navigator.userAgent,n=i.includes('Chrome/')%7C%7Ci.includes('Firefox/')%7C%7Ci.includes('Brave/')%7C%7Ci.includes('Edg/'),o=i.includes('Safari/'),t=!n%26%26!o,a=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints,e=window.getSelection();if(!e)return;const%20l=e.toString().split('%5Cn')%5B0%5D.trim();let%20r='x-man-page://';const%20c=l.match(/%5E(.%2A?)%5C((%5Cd)%5C)$/);if(r+=c?'1'===c%5B2%5D?c%5B1%5D:%60$%7Bc%5B2%5D%7D/$%7Bc%5B1%5D%7D%60:l,l)%7Bif(confirm(%60Link%20for%20%22$%7Bl%7D%22%20is:%20$%7Br%7D%5Cn%5CnCopy%20to%20clipboard?%60))%7Blet%20i='';if(navigator.clipboard?navigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22$%7Br%7D%22%20to%20clipboard.%60,r=''),a%26%26''!==r)%7Blet%20n=null;try%7Bn=window.open(r),n%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22$%7Br%7D%22%60%7Dfinally%7Bwindow.focus(),null!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D,3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22$%7Br%7D%22%60);''!==i%26%26alert(i)%7De.empty()%7D%7D)();void'1.3.2' "Setup x-man" diff --git a/bookmarklets.json b/bookmarklets.json index 1c775b7..3a72be4 100644 --- a/bookmarklets.json +++ b/bookmarklets.json @@ -3,107 +3,107 @@ { "name": "FYI", "file": "fyi.bookmarklet", - "version": "3.3.0" + "version": "3.3.1" }, { "name": "IsItAws", "file": "isitaws.bookmarklet", - "version": "1.3.5" + "version": "1.3.6" }, { "name": "KillStickyHeaders", "file": "killStickyHeaders.bookmarklet", - "version": "2.1.0" + "version": "2.1.1" }, { "name": "Linklighter", "file": "linklighter.bookmarklet", - "version": "2.1.0" + "version": "2.1.1" }, { "name": "OpenInBrave", "file": "openinbrave.bookmarklet", - "version": "1.1.2" + "version": "1.1.3" }, { "name": "OpenInChrome", "file": "openinchrome.bookmarklet", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "OpenInDDG", "file": "openinddg.bookmarklet", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "OpenInEdge", "file": "openinedge.bookmarklet", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "OpenInFirefox", "file": "openinfirefox.bookmarklet", - "version": "1.6.2" + "version": "1.6.3" }, { "name": "OpenInFirefox-Focus", "file": "openinfirefox-focus.bookmarklet", - "version": "1.1.2" + "version": "1.1.3" }, { "name": "OpenInFirefox-Private", "file": "openinfirefox-private.bookmarklet", - "version": "1.1.2" + "version": "1.1.3" }, { "name": "OpenInGoodReader", "file": "openingoodreader.bookmarklet", - "version": "1.5.2" + "version": "1.5.3" }, { "name": "OpenInOpera", "file": "openinopera.bookmarklet", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "OpenInOrion", "file": "openinorion.bookmarklet", - "version": "1.0.0" + "version": "1.0.1" }, { "name": "OpenInTextastic", "file": "openintextastic.bookmarklet", - "version": "1.1.2" + "version": "1.1.3" }, { "name": "OpenInWorkingCopy", "file": "openinworkingcopy.bookmarklet", - "version": "1.6.2" + "version": "1.6.3" }, { "name": "OpenURLParam", "file": "openurlparam.bookmarklet", - "version": "1.2.1" + "version": "1.2.2" }, { "name": "UtmStrip", "file": "utmstrip.bookmarklet", - "version": "2.3.2" + "version": "2.3.3" }, { "name": "deLighter", "file": "delighter.bookmarklet", - "version": "1.3.1" + "version": "1.3.2" }, { "name": "unskim", "file": "unskim.bookmarklet", - "version": "2.1.1" + "version": "2.1.2" }, { "name": "x-man", "file": "x-man.bookmarklet", - "version": "1.3.1" + "version": "1.3.2" } ] } diff --git a/dist/delighter.bookmarklet b/dist/delighter.bookmarklet index f208770..3e97888 100644 --- a/dist/delighter.bookmarklet +++ b/dist/delighter.bookmarklet @@ -1 +1 @@ -javascript:document.location.reload()%3Bvoid'1.3.1' \ No newline at end of file +javascript:document.location.reload();void'1.3.2' \ No newline at end of file diff --git a/dist/fyi.bookmarklet b/dist/fyi.bookmarklet index 73e5fad..b3ca225 100644 --- a/dist/fyi.bookmarklet +++ b/dist/fyi.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Bconst%20e=encodeURIComponent(document.title)%2Ct='%250A'%2Cn=window.getSelection()%2Co=n%26%26'Range'===n.type%26%26n.rangeCount%3E0%3Fn.getRangeAt(0).toString():''%3Blocation.href=%60mailto:%3Fsubject=fyi:%24%7Be%7D%26body=%24%7Be%7D%24%7Bt%7D%24%7BencodeURIComponent(document.URL)%7D%24%7Bt%7D---%24%7Bt%7D%24%7BencodeURIComponent(o)%7D%24%7Bt%7D%24%7Bt%7D%60%7D)()%3Bvoid'3.3.0' \ No newline at end of file +javascript:'use%20strict';(()=%3E%7Bconst%20e=encodeURIComponent(document.title),t='%250A',n=window.getSelection(),o=n%26%26'Range'===n.type%26%26n.rangeCount%3E0?n.getRangeAt(0).toString():'';location.href=%60mailto:?subject=fyi:$%7Be%7D%26body=$%7Be%7D$%7Bt%7D$%7BencodeURIComponent(document.URL)%7D$%7Bt%7D---$%7Bt%7D$%7BencodeURIComponent(o)%7D$%7Bt%7D$%7Bt%7D%60%7D)();void'3.3.1' \ No newline at end of file diff --git a/dist/isitaws.bookmarklet b/dist/isitaws.bookmarklet index 9891339..43dbc0d 100644 --- a/dist/isitaws.bookmarklet +++ b/dist/isitaws.bookmarklet @@ -1 +1 @@ -javascript:location.href='https:%2F%2Fisitonaws.com%2Fdiscover%3Fname='%2Blocation.host%3Bvoid'1.3.5' \ No newline at end of file +javascript:location.href='https://isitonaws.com/discover?name='+location.host;void'1.3.6' \ No newline at end of file diff --git a/dist/killStickyHeaders.bookmarklet b/dist/killStickyHeaders.bookmarklet index 9a2a3ba..e67eff9 100644 --- a/dist/killStickyHeaders.bookmarklet +++ b/dist/killStickyHeaders.bookmarklet @@ -1 +1 @@ -javascript:Array.from(document.querySelectorAll('body%20%2A')).filter(e=%3E%5B'fixed'%2C'sticky'%5D.includes(getComputedStyle(e).position)).forEach(e=%3Ee.remove())%3Bvoid'2.1.0' \ No newline at end of file +javascript:Array.from(document.querySelectorAll('body%20%2A')).filter(e=%3E%5B'fixed','sticky'%5D.includes(getComputedStyle(e).position)).forEach(e=%3Ee.remove());void'2.1.1' \ No newline at end of file diff --git a/dist/linklighter.bookmarklet b/dist/linklighter.bookmarklet index c1a503a..3e63318 100644 --- a/dist/linklighter.bookmarklet +++ b/dist/linklighter.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=encodeURIComponent%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20n=e.toString()%2Co=n.length%2Ci=document.URL%2Cs=i.indexOf('%23')%3Blet%20r=i%2Cc=''%2Cl=''%2Ca=''%3Bif(e.rangeCount%3E0%26%26n%26%26(document.body.textContent%7C%7C'').split(n).length-1%3E1)%7Bconst%20t=e.getRangeAt(0)%2Cn=t.commonAncestorContainer.textContent%7C%7C''%2C%7BstartOffset:o%2CendOffset:i%7D=t%2Cs=Math.max(0%2Co-20)%3Bif(l=n.substring(s%2Co).trim()%2Cs%3E0%26%26'%20'!==n.charAt(s-1))%7Bconst%20t=l.indexOf('%20')%3Bt%3E0%26%26(l=l.substring(t%2B1))%7Dconst%20r=Math.min(n.length%2Ci%2B20)%3Bif(a=n.substring(i%2Cr).trim()%2Cr%3Cn.length%26%26'%20'!==n.charAt(r))%7Bconst%20t=a.lastIndexOf('%20')%3Bt%3E0%26%26(a=a.substring(0%2Ct))%7D%7Dif(e.removeAllRanges()%2Cn%26%26''!==n)%7Bs%3E-1%26%26(r=r.substring(0%2Cs))%3Blet%20e=''%3Bif(l%26%26(e=t(l)%2B'-%2C')%2C80%3Eo)c=n%2Ce%2B=t(n)%3Belse%7Blet%20i=~~(o%2F2-2)%3Bo%3E150%3Fi=48:o%3E100%26%26(i=~~(o%2F3))%3Blet%20s=n.substring(0%2Ci)%2Cr=n.slice(o-i)%3Bconst%20l=s.lastIndexOf('%20')%3Bl%3Ei%2F2%26%26(s=s.substring(0%2Cl))%3Bconst%20a=r.indexOf('%20')%3Ba%3E-1%26%26i%2F2%3Ea%26%26(r=r.substring(a%2B1))%2Cc=s%2B'%E2%80%A6'%2Ce%2B=%60%24%7Bt(s)%7D%2C%24%7Bt(r)%7D%60%7Da%26%26(e%2B='%2C-'%2Bt(a))%2Cr%2B='%23:~:text='%2Be%2Cr=r.replace(%2F(%250A%7C%250D%7C%2509%7C%2520)%2B%24%2F%2C'')%2Cr=r.replace(%2F(%2520)%7B2%2C%7D%2Fg%2C'%2520')%2Cr=r.replace(%2F%23%23%2B:~:text=%2F%2C'%23:~:text=')%7Dif(r!==i%26%26confirm(%60Open%20URL%20with%20highlight%20on%20%22%24%7Bc%7D%22%20and%20copy%20URL%20to%20clipboard%3F%60))%7Bnavigator.clipboard.writeText(r).catch(()=%3E%7Balert('Could%20not%20copy%20to%20clipboard.%20URL%20is%20in%20the%20new%20tab.')%7D)%3Bconst%20t=window.open(r%2C'%5Fblank')%3Bt%3Ft.opener=null:alert('Popup%20blocked.%20URL%20copied%20to%20clipboard.')%7D%7D)()%3Bvoid'2.1.0' \ No newline at end of file +javascript:'use%20strict';(()=%3E%7Bconst%20t=encodeURIComponent,e=window.getSelection();if(!e)return;const%20n=e.toString(),o=n.length,i=document.URL,s=i.indexOf('%23');let%20r=i,c='',l='',a='';if(e.rangeCount%3E0%26%26n%26%26(document.body.textContent%7C%7C'').split(n).length-1%3E1)%7Bconst%20t=e.getRangeAt(0),n=t.commonAncestorContainer.textContent%7C%7C'',%7BstartOffset:o,endOffset:i%7D=t,s=Math.max(0,o-20);if(l=n.substring(s,o).trim(),s%3E0%26%26'%20'!==n.charAt(s-1))%7Bconst%20t=l.indexOf('%20');t%3E0%26%26(l=l.substring(t+1))%7Dconst%20r=Math.min(n.length,i+20);if(a=n.substring(i,r).trim(),r%3Cn.length%26%26'%20'!==n.charAt(r))%7Bconst%20t=a.lastIndexOf('%20');t%3E0%26%26(a=a.substring(0,t))%7D%7Dif(e.removeAllRanges(),n%26%26''!==n)%7Bs%3E-1%26%26(r=r.substring(0,s));let%20e='';if(l%26%26(e=t(l)+'-,'),80%3Eo)c=n,e+=t(n);else%7Blet%20i=~~(o/2-2);o%3E150?i=48:o%3E100%26%26(i=~~(o/3));let%20s=n.substring(0,i),r=n.slice(o-i);const%20l=s.lastIndexOf('%20');l%3Ei/2%26%26(s=s.substring(0,l));const%20a=r.indexOf('%20');a%3E-1%26%26i/2%3Ea%26%26(r=r.substring(a+1)),c=s+'%E2%80%A6',e+=%60$%7Bt(s)%7D,$%7Bt(r)%7D%60%7Da%26%26(e+=',-'+t(a)),r+='%23:~:text='+e,r=r.replace(/(%250A%7C%250D%7C%2509%7C%2520)+$/,''),r=r.replace(/(%2520)%7B2,%7D/g,'%2520'),r=r.replace(/%23%23+:~:text=/,'%23:~:text=')%7Dif(r!==i%26%26confirm(%60Open%20URL%20with%20highlight%20on%20%22$%7Bc%7D%22%20and%20copy%20URL%20to%20clipboard?%60))%7Bnavigator.clipboard.writeText(r).catch(()=%3E%7Balert('Could%20not%20copy%20to%20clipboard.%20URL%20is%20in%20the%20new%20tab.')%7D);const%20t=window.open(r,'%5Fblank');t?t.opener=null:alert('Popup%20blocked.%20URL%20copied%20to%20clipboard.')%7D%7D)();void'2.1.1' \ No newline at end of file diff --git a/dist/openinbrave.bookmarklet b/dist/openinbrave.bookmarklet index 4c6e7cc..56c20b5 100644 --- a/dist/openinbrave.bookmarklet +++ b/dist/openinbrave.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='brave:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.1.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='brave://open-url?url='+encodeURIComponent(location.href);void'1.1.3' \ No newline at end of file diff --git a/dist/openinchrome.bookmarklet b/dist/openinchrome.bookmarklet index 16f4c53..8913ef0 100644 --- a/dist/openinchrome.bookmarklet +++ b/dist/openinchrome.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3Bif(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))%7Bconst%20o=%60googlechrome%24%7B'https:'===location.protocol%3F's':''%7D:%2F%2F%60%3Blocation.href=%60%24%7Bo%7D%24%7Blocation.host%7D%24%7Blocation.pathname%7D%24%7Blocation.search%7D%24%7Blocation.hash%7D%60%7Dvoid'1.0.0' \ No newline at end of file +javascript:'use%20strict';if(/iP(ad%7Chone)/.test(navigator.userAgent))%7Bconst%20o=%60googlechrome$%7B'https:'===location.protocol?'s':''%7D://%60;location.href=%60$%7Bo%7D$%7Blocation.host%7D$%7Blocation.pathname%7D$%7Blocation.search%7D$%7Blocation.hash%7D%60%7Dvoid'1.0.1' \ No newline at end of file diff --git a/dist/openinddg.bookmarklet b/dist/openinddg.bookmarklet index eb6e6ba..fb1882f 100644 --- a/dist/openinddg.bookmarklet +++ b/dist/openinddg.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60ddgQuickLink:%2F%2F%24%7Blocation.host%7D%24%7Blocation.pathname%7D%24%7Blocation.search%7D%24%7Blocation.hash%7D%60%3Bvoid'1.0.0' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60ddgQuickLink://$%7Blocation.host%7D$%7Blocation.pathname%7D$%7Blocation.search%7D$%7Blocation.hash%7D%60;void'1.0.1' \ No newline at end of file diff --git a/dist/openinedge.bookmarklet b/dist/openinedge.bookmarklet index a0cde22..83d97e3 100644 --- a/dist/openinedge.bookmarklet +++ b/dist/openinedge.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='microsoft-edge-'%2Blocation.href%3Bvoid'1.0.0' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='microsoft-edge-'+location.href;void'1.0.1' \ No newline at end of file diff --git a/dist/openinfirefox-focus.bookmarklet b/dist/openinfirefox-focus.bookmarklet index 20ab4a2..06ffa55 100644 --- a/dist/openinfirefox-focus.bookmarklet +++ b/dist/openinfirefox-focus.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60firefox-focus:%2F%2Fopen-url%3Furl=%24%7BencodeURIComponent(location.href)%7D%26private=true%60%3Bvoid'1.1.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60firefox-focus://open-url?url=$%7BencodeURIComponent(location.href)%7D%26private=true%60;void'1.1.3' \ No newline at end of file diff --git a/dist/openinfirefox-private.bookmarklet b/dist/openinfirefox-private.bookmarklet index f6b39d7..58c97d7 100644 --- a/dist/openinfirefox-private.bookmarklet +++ b/dist/openinfirefox-private.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=%60firefox:%2F%2Fopen-url%3Furl=%24%7BencodeURIComponent(location.href)%7D%26private=true%60%3Bvoid'1.1.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=%60firefox://open-url?url=$%7BencodeURIComponent(location.href)%7D%26private=true%60;void'1.1.3' \ No newline at end of file diff --git a/dist/openinfirefox.bookmarklet b/dist/openinfirefox.bookmarklet index f12db2f..344f175 100644 --- a/dist/openinfirefox.bookmarklet +++ b/dist/openinfirefox.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='firefox:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.6.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='firefox://open-url?url='+encodeURIComponent(location.href);void'1.6.3' \ No newline at end of file diff --git a/dist/openingoodreader.bookmarklet b/dist/openingoodreader.bookmarklet index 0ced424..b047b7a 100644 --- a/dist/openingoodreader.bookmarklet +++ b/dist/openingoodreader.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26%2F%5C.pdf(%24%7C%5C%3F)%2F.test(location.href))location.href='gr'%2Blocation.href%3Bvoid'1.5.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent)%26%26/%5C.pdf($%7C%5C?)/.test(location.href))location.href='gr'+location.href;void'1.5.3' \ No newline at end of file diff --git a/dist/openinopera.bookmarklet b/dist/openinopera.bookmarklet index c16822e..4587293 100644 --- a/dist/openinopera.bookmarklet +++ b/dist/openinopera.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='touch-'%2Blocation.href%3Bvoid'1.0.0' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='touch-'+location.href;void'1.0.1' \ No newline at end of file diff --git a/dist/openinorion.bookmarklet b/dist/openinorion.bookmarklet index 0c252a1..9091cd4 100644 --- a/dist/openinorion.bookmarklet +++ b/dist/openinorion.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href='orion:%2F%2Fopen-url%3Furl='%2BencodeURIComponent(location.href)%3Bvoid'1.0.0' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href='orion://open-url?url='+encodeURIComponent(location.href);void'1.0.1' \ No newline at end of file diff --git a/dist/openintextastic.bookmarklet b/dist/openintextastic.bookmarklet index ae92b1d..74a601e 100644 --- a/dist/openintextastic.bookmarklet +++ b/dist/openintextastic.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent))location.href=location.href.replace(%2F%5Ehttps%3F%2F%2C'textastic')%3Bvoid'1.1.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent))location.href=location.href.replace(/%5Ehttps?/,'textastic');void'1.1.3' \ No newline at end of file diff --git a/dist/openinworkingcopy.bookmarklet b/dist/openinworkingcopy.bookmarklet index 5ee25f1..921bbd4 100644 --- a/dist/openinworkingcopy.bookmarklet +++ b/dist/openinworkingcopy.bookmarklet @@ -1 +1 @@ -javascript:if(%2FiP(ad%7Chone)%2F.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy:%2F%2Fshow%3Fremote=%24%7BencodeURIComponent(location.href.split('%2F').slice(0%2C5).join('%2F'))%7D.git%60%3Bvoid'1.6.2' \ No newline at end of file +javascript:if(/iP(ad%7Chone)/.test(navigator.userAgent)%26%26('bitbucket.org'===location.host%7C%7C'github.com'===location.host))location.href=%60working-copy://show?remote=$%7BencodeURIComponent(location.href.split('/').slice(0,5).join('/'))%7D.git%60;void'1.6.3' \ No newline at end of file diff --git a/dist/openurlparam.bookmarklet b/dist/openurlparam.bookmarklet index 23544b1..473fb39 100644 --- a/dist/openurlparam.bookmarklet +++ b/dist/openurlparam.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=new%20URL(document.location.href)%3Bif('https:'!==t.protocol%7C%7C13%3Et.search.length)return%3Bconst%20e=new%20URLSearchParams(t.search)%2Cn=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t)%3Breturn%20n%3FdecodeURIComponent(n):''%7D).find(t=%3Et.match(%2F%5Ehttps:%2F))%3Bn%26%26window.location.replace(new%20URL(n))%7D)()%3Bvoid'1.2.1' \ No newline at end of file +javascript:'use%20strict';(()=%3E%7Bconst%20t=new%20URL(document.location.href);if('https:'!==t.protocol%7C%7C13%3Et.search.length)return;const%20e=new%20URLSearchParams(t.search),n=%5B'url','destination','redirect','target','goto','u','dest','link','out'%5D.filter(t=%3Ee.has(t)).map(t=%3E%7Bconst%20n=e.get(t);return%20n?decodeURIComponent(n):''%7D).find(t=%3Et.match(/%5Ehttps:/));n%26%26window.location.replace(new%20URL(n))%7D)();void'1.2.2' \ No newline at end of file diff --git a/dist/unskim.bookmarklet b/dist/unskim.bookmarklet index 3084649..f9c4ff7 100644 --- a/dist/unskim.bookmarklet +++ b/dist/unskim.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Blet%20e=new%20URL(document.location.href)%3Bif('safari-resource:%2FErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')%3F.textContent%3F.match(%2FSafari%20can%5B'%5Cu2019%5Dt%20open%20the%20page%20%5B%22%5Cu201C%5D(https%3F:%5B%5E%22%5Cu201D%5D%2B)%5B%22%5Cu201D%5D%2F)%3F.%5B1%5D%3Bt%26%26(e=new%20URL(t))%7Dif(13%3Ee.search.length)return%3Bconst%20t=new%20URLSearchParams(e.search)%2Cr=%5B'url'%2C'destination'%2C'redirect'%2C'target'%2C'goto'%2C'u'%2C'dest'%2C'link'%2C'out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e)%3Breturn%20r%3FdecodeURIComponent(r):''%7D).find(e=%3Ee.match(%2F%5Ehttps%3F:%2F))%3Bif(r)%7Bconst%20e=new%20URL(r)%3Bif(e.searchParams.size%3E0)%7Bconst%20t=new%20URLSearchParams(e.search)%3Bfor(const%20e%20of%5B...t.keys()%5D)%7Bconst%20r=e.toLowerCase()%3B(r.startsWith('utm%5F')%7C%7Cr.startsWith('fb%5F')%7C%7C%5B'fbclid'%2C'gclid'%2C'msclkid'%2C'ref'%2C'referrer'%2C'ttclid'%2C'twclid'%5D.includes(r))%26%26t.delete(e)%7De.search=t.toString()%7Dwindow.location.replace(e)%7D%7D)()%3Bvoid'2.1.1' \ No newline at end of file +javascript:'use%20strict';(()=%3E%7Blet%20e=new%20URL(document.location.href);if('safari-resource:/ErrorPage.html'===e.href)%7Bconst%20t=document.querySelector('p.error-message')?.textContent?.match(/Safari%20can%5B'%5Cu2019%5Dt%20open%20the%20page%20%5B%22%5Cu201C%5D(https?:%5B%5E%22%5Cu201D%5D+)%5B%22%5Cu201D%5D/)?.%5B1%5D;t%26%26(e=new%20URL(t))%7Dif(13%3Ee.search.length)return;const%20t=new%20URLSearchParams(e.search),r=%5B'url','destination','redirect','target','goto','u','dest','link','out'%5D.filter(e=%3Et.has(e)).map(e=%3E%7Bconst%20r=t.get(e);return%20r?decodeURIComponent(r):''%7D).find(e=%3Ee.match(/%5Ehttps?:/));if(r)%7Bconst%20e=new%20URL(r);if(e.searchParams.size%3E0)%7Bconst%20t=new%20URLSearchParams(e.search);for(const%20e%20of%5B...t.keys()%5D)%7Bconst%20r=e.toLowerCase();(r.startsWith('utm%5F')%7C%7Cr.startsWith('fb%5F')%7C%7C%5B'fbclid','gclid','msclkid','ref','referrer','ttclid','twclid'%5D.includes(r))%26%26t.delete(e)%7De.search=t.toString()%7Dwindow.location.replace(e)%7D%7D)();void'2.1.2' \ No newline at end of file diff --git a/dist/utmstrip.bookmarklet b/dist/utmstrip.bookmarklet index 18942fd..c3b7184 100644 --- a/dist/utmstrip.bookmarklet +++ b/dist/utmstrip.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Bconst%20t=location.pathname%2Ce=location.search%3Bif(3%3Ee.length%26%26!t.includes('%2Famp'))return%3Bconst%20i=location.hostname%2Cs=new%20URLSearchParams(e)%2C%5F=%5B'assetType'%2C'elqTrack'%2C'mkt%5Ftok'%2C'originalReferer'%2C'referrer'%2C'terminal%5Fid'%2C'trk'%2C'trkCampaign'%2C'trkInfo'%2C'anid'%2C'assetid'%2C'campaignid'%2C'eid'%2C'gclid'%2C'recipientid'%2C'siteid'%2C'sib%5Fcuid'%2C'sib%5Fsid'%2C'%5Fbta%5Ftid'%2C'%5Fbta%5Fc'%2C'%5F%5Fs'%2C'fbclid'%2C'hrc'%2C'igsh'%2C'igshid'%2C'refsrc'%2C'%5Fgl'%2C'gclsrc'%2C'gs%5Fl'%2C'srsltid'%2C'%5Fhsenc'%2C'%5Fhsmi'%2C'%5F%5Fhsfp'%2C'%5F%5Fhssc'%2C'%5F%5Fhstc'%2C'cm%5Fmmc'%2C'cm%5Fre'%2C'cm%5Fsp'%2C'manual%5Fcm%5Fmmc'%2C'%5Fke'%2C'%5Fkx'%2C'trk%5Fcontact'%2C'trk%5Fmsg'%2C'trk%5Fmodule'%2C'trk%5Fsid'%2C'mc%5Fcid'%2C'mc%5Feid'%2C'iesrc'%2C'msclkid'%2C'dclid'%2C'twclid'%2C'ttclid'%2C'oly%5Fenc%5Fid'%2C'oly%5Fanon%5Fid'%2C'epik'%2C'vero%5Fid'%2C'rdt%5Fcid'%2C'ScCid'%2C'qclid'%2C'tblci'%2C'cjevent'%2C'ef%5Fid'%2C'outbrain%5Fcid'%5D%2Ca=%5B'fb%5F'%2C'action%5F'%2C'ga%5F'%2C'utm%5F'%2C'hmb%5F'%2C'hsa%5F'%2C'mtm%5F'%2C'pk%5F'%2C'oly%5F'%2C'stm%5F'%5D%3B%2F%5C.aliexpress%5C.%5Ba-z%5D%7B2%2C3%7D%24%2F.test(i)%3F(%5F.push('algo%5Fevid'%2C'algo%5Fpvid'%2C'btsid'%2C'spm'%2C'scm'%2C'ws%5Fab%5Ftest')%2Ca.push('aff%5F')):%2F(%7C%5C.)amazon%5C.com%24%2F.test(i)%3F%5F.push('%5Fencoding'%2C'asc%5Fcampaign'%2C'asc%5Frefurl'%2C'asc%5Fsource'%2C'ascsubtag'%2C'content-id'%2C'crid'%2C'cv%5Fct%5Fcx'%2C'dib%5Ftag'%2C'dib'%2C'ie'%2C'language'%2C'linkCode'%2C'linkId'%2C'pd%5Frd%5Fi'%2C'pd%5Frd%5Fr'%2C'pd%5Frd%5Fw'%2C'pd%5Frd%5Fwg'%2C'pf%5Frd%5Fi'%2C'pf%5Frd%5Fm'%2C'pf%5Frd%5Fp'%2C'pf%5Frd%5Fr'%2C'pf%5Frd%5Fs'%2C'pf%5Frd%5Ft'%2C'pf'%2C'psc'%2C'qid'%2C'ref%5F'%2C'sprefix'%2C'sr'%2C'tag'%2C'th'):i.endsWith('.ebay.com')%7C%7C%2F%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D%24%2F.test(i)%3F%5F.push('mkevt'%2C'mkcid'%2C'mkrid'%2C'campid'%2C'toolid'%2C'customid'%2C'norover'%2C'itm'%2C'amdata'):%2F(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom%3F%5C.%5Ba-z%5D%7B2%7D)%24%2F.test(i)%26%26t.startsWith('%2Fsearch')%3F%5F.push('aqs'%2C'ei'%2C'gs%5Flp'%2C'gs%5Fssp'%2C'iflsig'%2C'sca%5Fesv'%2C'ved'%2C'oq'%2C'sa'%2C'uact'%2C'rlz'%2C'sxsrf'%2C'bih'%2C'biw'%2C'client'%2C'prmd'%2C'sclient'%2C'source'%2C'sourceid'%2C'ie'%2C'oe'):i.endsWith('.linkedin.com')%3F%5F.push('li%5Ffat%5Fid'%2C'licu'%2C'lipi'%2C'midSig'%2C'midToken'%2C'refId'):i.endsWith('.target.com')%3F%5F.push('afid'%2C'clkid'%2C'lnm'%2C'preselect'%2C'tref'):i.endsWith('.temu.com')%3F(%5F.push('%5Fbg%5Ffs'%2C'%5Fp%5Fjump%5Fid'%2C'%5Fp%5Frfs'%2C'refer%5Fpage%5Fid'%2C'refer%5Fpage%5Fname'%2C'refer%5Fpage%5Fsn')%2Ca.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i%3F%5F.push('%5Fd'%2C'%5Fr'%2C'%5Ft'%2C'is%5Ffrom%5Fwebapp'%2C'preview%5Fpb'%2C'share%5Fapp%5Fname'%2C'share%5Fitem%5Fid'%2C'tt4d%5Ft'%2C'timestamp'%2C'u%5Fcode'%2C'user%5Fid'):%2F%5C.(twitter%7Cx)%5C.com%24%2F.test(i)%7C%7C%2F%5E(twitter%7Cx)%5C.com%24%2F.test(i)%3F%5F.push('cn'%2C'ref%5Fsrc'%2C'ref%5Furl'%2C's'%2C't'):i.endsWith('.walmart.com')%3F%5F.push('adsredirect'%2C'affiliates%5Fad%5Fid'%2C'athcpid'%2C'athpgid'%2C'athcgid'%2C'athmtid'%2C'athstid'%2C'athznid'%2C'athiession'%2C'athancid'%2C'athposb'%2C'athena'%2C'campaign%5Fid'%2C'wmlspartner'%2C'wt%5Fmc'):(%2F(m%7Cwww)%5C.youtube%5C.com%24%2F.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26%5F.push('ac'%2C'annotation%5Fid'%2C'app'%2C'feature'%2C'gclid'%2C'kw'%2C'src%5Fvid')%3Bconst%20c=new%20Set(%5F.map(t=%3Et.toLowerCase()))%2Cr=t=%3E%7Bconst%20e=t.toLowerCase()%3Breturn%20c.has(e)%7C%7Ca.some(t=%3Ee.startsWith(t))%7C%7C%2F%5Ecm%5Fmmca%5Cd%2B%24%2Fi.test(t)%7D%3Bfor(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t)%3Blet%20d=s.toString()%3Bd=d%3F'%3F'%2Bd:''%3Bconst%20o=t.replace(%2F%5C%2Famp%5C%2F%3F%24%2F%2C'')%2Cn=%60%24%7Blocation.protocol%7D%2F%2F%24%7Blocation.host%7D%24%7Bo%7D%24%7Bd%7D%24%7Blocation.hash%7D%60%3Bif(confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard%3F')%26%26(navigator.clipboard.writeText(n)%2Ce!==d%7C%7Ct!==o))%7Bhistory.replaceState(null%2C''%2Cn)%3Bconst%20t=window.open(n%2C'%5Fself'%2C'noreferrer')%3Bt%26%26(t.opener=null)%7D%7D)()%3Bvoid'2.3.2' \ No newline at end of file +javascript:'use%20strict';(()=%3E%7Bconst%20t=location.pathname,e=location.search;if(3%3Ee.length%26%26!t.includes('/amp'))return;const%20i=location.hostname,s=new%20URLSearchParams(e),%5F=%5B'assetType','elqTrack','mkt%5Ftok','originalReferer','referrer','terminal%5Fid','trk','trkCampaign','trkInfo','anid','assetid','campaignid','eid','gclid','recipientid','siteid','sib%5Fcuid','sib%5Fsid','%5Fbta%5Ftid','%5Fbta%5Fc','%5F%5Fs','fbclid','hrc','igsh','igshid','refsrc','%5Fgl','gclsrc','gs%5Fl','srsltid','%5Fhsenc','%5Fhsmi','%5F%5Fhsfp','%5F%5Fhssc','%5F%5Fhstc','cm%5Fmmc','cm%5Fre','cm%5Fsp','manual%5Fcm%5Fmmc','%5Fke','%5Fkx','trk%5Fcontact','trk%5Fmsg','trk%5Fmodule','trk%5Fsid','mc%5Fcid','mc%5Feid','iesrc','msclkid','dclid','twclid','ttclid','oly%5Fenc%5Fid','oly%5Fanon%5Fid','epik','vero%5Fid','rdt%5Fcid','ScCid','qclid','tblci','cjevent','ef%5Fid','outbrain%5Fcid'%5D,a=%5B'fb%5F','action%5F','ga%5F','utm%5F','hmb%5F','hsa%5F','mtm%5F','pk%5F','oly%5F','stm%5F'%5D;/%5C.aliexpress%5C.%5Ba-z%5D%7B2,3%7D$/.test(i)?(%5F.push('algo%5Fevid','algo%5Fpvid','btsid','spm','scm','ws%5Fab%5Ftest'),a.push('aff%5F')):/(%7C%5C.)amazon%5C.com$/.test(i)?%5F.push('%5Fencoding','asc%5Fcampaign','asc%5Frefurl','asc%5Fsource','ascsubtag','content-id','crid','cv%5Fct%5Fcx','dib%5Ftag','dib','ie','language','linkCode','linkId','pd%5Frd%5Fi','pd%5Frd%5Fr','pd%5Frd%5Fw','pd%5Frd%5Fwg','pf%5Frd%5Fi','pf%5Frd%5Fm','pf%5Frd%5Fp','pf%5Frd%5Fr','pf%5Frd%5Fs','pf%5Frd%5Ft','pf','psc','qid','ref%5F','sprefix','sr','tag','th'):i.endsWith('.ebay.com')%7C%7C/%5C.ebay%5C.co%5C.%5Ba-z%5D%7B2%7D$/.test(i)?%5F.push('mkevt','mkcid','mkrid','campid','toolid','customid','norover','itm','amdata'):/(%5E%7C%5C.)google%5C.(com%7C%5Ba-z%5D%7B2%7D%7Ccom?%5C.%5Ba-z%5D%7B2%7D)$/.test(i)%26%26t.startsWith('/search')?%5F.push('aqs','ei','gs%5Flp','gs%5Fssp','iflsig','sca%5Fesv','ved','oq','sa','uact','rlz','sxsrf','bih','biw','client','prmd','sclient','source','sourceid','ie','oe'):i.endsWith('.linkedin.com')?%5F.push('li%5Ffat%5Fid','licu','lipi','midSig','midToken','refId'):i.endsWith('.target.com')?%5F.push('afid','clkid','lnm','preselect','tref'):i.endsWith('.temu.com')?(%5F.push('%5Fbg%5Ffs','%5Fp%5Fjump%5Fid','%5Fp%5Frfs','refer%5Fpage%5Fid','refer%5Fpage%5Fname','refer%5Fpage%5Fsn'),a.push('%5Fx%5F')):i.endsWith('.tiktok.com')%7C%7C'tiktok.com'===i?%5F.push('%5Fd','%5Fr','%5Ft','is%5Ffrom%5Fwebapp','preview%5Fpb','share%5Fapp%5Fname','share%5Fitem%5Fid','tt4d%5Ft','timestamp','u%5Fcode','user%5Fid'):/%5C.(twitter%7Cx)%5C.com$/.test(i)%7C%7C/%5E(twitter%7Cx)%5C.com$/.test(i)?%5F.push('cn','ref%5Fsrc','ref%5Furl','s','t'):i.endsWith('.walmart.com')?%5F.push('adsredirect','affiliates%5Fad%5Fid','athcpid','athpgid','athcgid','athmtid','athstid','athznid','athiession','athancid','athposb','athena','campaign%5Fid','wmlspartner','wt%5Fmc'):(/(m%7Cwww)%5C.youtube%5C.com$/.test(i)%7C%7C'youtu.be'===i%7C%7C'www.youtube-nocookie.com'===i)%26%26%5F.push('ac','annotation%5Fid','app','feature','gclid','kw','src%5Fvid');const%20c=new%20Set(%5F.map(t=%3Et.toLowerCase())),r=t=%3E%7Bconst%20e=t.toLowerCase();return%20c.has(e)%7C%7Ca.some(t=%3Ee.startsWith(t))%7C%7C/%5Ecm%5Fmmca%5Cd+$/i.test(t)%7D;for(const%20t%20of%5B...s.keys()%5D)r(t)%26%26s.delete(t);let%20d=s.toString();d=d?'?'+d:'';const%20o=t.replace(/%5C/amp%5C/?$/,''),n=%60$%7Blocation.protocol%7D//$%7Blocation.host%7D$%7Bo%7D$%7Bd%7D$%7Blocation.hash%7D%60;if(confirm('Update%20history%20and%20copy%20cleaned%20URL%20to%20clipboard?')%26%26(navigator.clipboard.writeText(n),e!==d%7C%7Ct!==o))%7Bhistory.replaceState(null,'',n);const%20t=window.open(n,'%5Fself','noreferrer');t%26%26(t.opener=null)%7D%7D)();void'2.3.3' \ No newline at end of file diff --git a/dist/x-man.bookmarklet b/dist/x-man.bookmarklet index e794e2a..84b96e6 100644 --- a/dist/x-man.bookmarklet +++ b/dist/x-man.bookmarklet @@ -1 +1 @@ -javascript:'use%20strict'%3B(()=%3E%7Bconst%20i=navigator.userAgent%2Cn=i.includes('Chrome%2F')%7C%7Ci.includes('Firefox%2F')%7C%7Ci.includes('Brave%2F')%7C%7Ci.includes('Edg%2F')%2Co=i.includes('Safari%2F')%2Ct=!n%26%26!o%2Ca=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints%2Ce=window.getSelection()%3Bif(!e)return%3Bconst%20l=e.toString().split('%5Cn')%5B0%5D.trim()%3Blet%20r='x-man-page:%2F%2F'%3Bconst%20c=l.match(%2F%5E(.%2A%3F)%5C((%5Cd)%5C)%24%2F)%3Bif(r%2B=c%3F'1'===c%5B2%5D%3Fc%5B1%5D:%60%24%7Bc%5B2%5D%7D%2F%24%7Bc%5B1%5D%7D%60:l%2Cl)%7Bif(confirm(%60Link%20for%20%22%24%7Bl%7D%22%20is:%20%24%7Br%7D%5Cn%5CnCopy%20to%20clipboard%3F%60))%7Blet%20i=''%3Bif(navigator.clipboard%3Fnavigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22%24%7Br%7D%22%20to%20clipboard.%60%2Cr='')%2Ca%26%26''!==r)%7Blet%20n=null%3Btry%7Bn=window.open(r)%2Cn%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22%24%7Br%7D%22%60%7Dfinally%7Bwindow.focus()%2Cnull!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D%2C3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22%24%7Br%7D%22%60)%3B''!==i%26%26alert(i)%7De.empty()%7D%7D)()%3Bvoid'1.3.1' \ No newline at end of file +javascript:'use%20strict';(()=%3E%7Bconst%20i=navigator.userAgent,n=i.includes('Chrome/')%7C%7Ci.includes('Firefox/')%7C%7Ci.includes('Brave/')%7C%7Ci.includes('Edg/'),o=i.includes('Safari/'),t=!n%26%26!o,a=navigator.platform.startsWith('Mac')%26%26o%26%26!n%26%26!t%26%26!navigator.maxTouchPoints%26%262%3Enavigator.maxTouchPoints,e=window.getSelection();if(!e)return;const%20l=e.toString().split('%5Cn')%5B0%5D.trim();let%20r='x-man-page://';const%20c=l.match(/%5E(.%2A?)%5C((%5Cd)%5C)$/);if(r+=c?'1'===c%5B2%5D?c%5B1%5D:%60$%7Bc%5B2%5D%7D/$%7Bc%5B1%5D%7D%60:l,l)%7Bif(confirm(%60Link%20for%20%22$%7Bl%7D%22%20is:%20$%7Br%7D%5Cn%5CnCopy%20to%20clipboard?%60))%7Blet%20i='';if(navigator.clipboard?navigator.clipboard.writeText(r):(i=%60Unable%20to%20copy%20%22$%7Br%7D%22%20to%20clipboard.%60,r=''),a%26%26''!==r)%7Blet%20n=null;try%7Bn=window.open(r),n%26%26(n.opener=null)%7Dcatch(n)%7Bi=%60Popup%20window%20blocked.%20Clipboard%20contains%20%22$%7Br%7D%22%60%7Dfinally%7Bwindow.focus(),null!==n%26%26setTimeout(()=%3E%7Bn%26%26n.close()%7D,3333)%7D%7Delse''!==r%26%26(i=%60Unable%20to%20open%20new%20link%20with%20Terminal.%20Clipboard%20contains%20%22$%7Br%7D%22%60);''!==i%26%26alert(i)%7De.empty()%7D%7D)();void'1.3.2' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 600065f..22d294c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "OpenInlets", - "version": "4.2.4", + "version": "4.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "OpenInlets", - "version": "4.2.4", + "version": "4.3.0", "license": "MIT", "devDependencies": { "@eslint/js": "10.0.1", diff --git a/package.json b/package.json index 95c9857..1f03e78 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "description": "Project that makes Safari bookmarklets to automagically jump to the corresponding app and more.", "devDependencies": { "@eslint/js": "10.0.1", - "@types/node": "~26.6.2", + "@types/node": "~26.6.3", "@typescript-eslint/eslint-plugin": "~8.70.1", "@typescript-eslint/parser": "~8.70.1", "eslint": "10.11.0", @@ -59,8 +59,8 @@ "deploy": "npm run build && npm run build:readme", "lint:md": "markdownlint-cli2 '**/*.md' '#node_modules' '#dist' '#.claude' '#CLAUDE.md'", "lint:sh": "if command -v shellcheck >/dev/null 2>&1; then shellcheck -s sh -o add-default-case -o avoid-nullary-conditions -o check-unassigned-uppercase -o deprecate-which pre-push; else echo 'shellcheck not installed, skipping'; fi", - "test": "npm run build && node scripts/test-utmstrip.js && npm run verify-build", + "test": "npm run build && node scripts/test-utmstrip.js && node scripts/test-encoding.js && npm run verify-build", "verify-build": "node scripts/verify-build.js" }, - "version": "4.2.4" + "version": "4.3.0" } diff --git a/scripts/build-bookmarklet.js b/scripts/build-bookmarklet.js index 9023f6d..8e31eed 100755 --- a/scripts/build-bookmarklet.js +++ b/scripts/build-bookmarklet.js @@ -6,7 +6,7 @@ const fs = require('fs'); const path = require('path'); -const {readFileOrFail, validateBookmarklet} = require('./utils'); +const {readFileOrFail, validateBookmarklet, encodeBookmarklet} = require('./utils'); function buildBookmarklet(bookmarklet) { // Source file in .temp/ is always .js (TypeScript compiler output) @@ -29,12 +29,8 @@ function buildBookmarklet(bookmarklet) { // Append version string theCode = `${theCode}void'${bookmarklet.version}'`; - // URL encoding for javascript: URL avoids RegEx & HTML issues - // with things like: "$&*+/<>?[]\^; also force encode '*'–>%2A, '_'–>%5F for regex & Markdown - theCode = `javascript:${encodeURIComponent(theCode).replace(/\*/g, '%2A').replace(/_/g, '%5F')}`; - - // Un-encode a couple of generally safe chars for URLs to reduce size - theCode = theCode.replace(/%3A/g, ':').replace(/%3D/g, '='); + // URL encode for javascript: URL; see encodeBookmarklet() in utils.js for the rules + theCode = encodeBookmarklet(theCode); // Write the bookmarklet back to dist/ directory fs.writeFileSync(distPath, theCode, 'utf8'); diff --git a/scripts/test-encoding.js b/scripts/test-encoding.js new file mode 100755 index 0000000..064713d --- /dev/null +++ b/scripts/test-encoding.js @@ -0,0 +1,114 @@ +#!/usr/bin/env node +/** + * Test bookmarklet URL encoding and validate every dist/ bookmarklet + * Run: node scripts/test-encoding.js + */ +const assert = require('node:assert'); +const fs = require('fs'); +const path = require('path'); +const {encodeBookmarklet, validateEncodedBookmarklet} = require('./utils'); + +const PREFIX = 'javascript:'; +let passed = 0; + +function bodyOf(code) { + const url = encodeBookmarklet(code); + assert.ok(url.startsWith(PREFIX), `missing prefix for ${code}`); + const body = url.slice(PREFIX.length); + assert.strictEqual(decodeURIComponent(body), code, `round trip failed for ${code}`); + return body; +} + +function test(name, fn) { + try { + fn(); + passed += 1; + } catch (error) { + console.error(`FAIL: ${name}\n${error.message}`); + process.exit(1); + } +} + +test('restored characters are literal', () => { + for (const ch of ':=,/;$@+?') { + assert.strictEqual(bodyOf(`a${ch}b`), `a${ch}b`, `'${ch}' should be literal`); + } +}); + +test('unreserved characters and * _ handling', () => { + assert.strictEqual(bodyOf("-_.!~*'()"), "-%5F.!~%2A'()"); +}); + +test('characters that must stay encoded', () => { + const expected = { + ' ': '%20', '\\': '%5C', '&': '%26', '<': '%3C', '>': '%3E', '"': '%22', + '#': '%23', '%': '%25', '`': '%60', '{': '%7B', '}': '%7D', '[': '%5B', + ']': '%5D', '|': '%7C', '^': '%5E' + }; + for (const [ch, enc] of Object.entries(expected)) { + assert.strictEqual(bodyOf(`a${ch}b`), `a${enc}b`, `'${ch}' should be ${enc}`); + } +}); + +test('literal %2F in source is not restored', () => { + assert.strictEqual(bodyOf('a%2Fb'), 'a%252Fb'); +}); + +test('README-style replace keeps $ sequences intact', () => { + for (const code of ["x='$'+y", 'a$&b', 'a$$b', 'a$1b', "a$'b", 'a$`b']) { + const url = encodeBookmarklet(code); + const result = 'X'.replace(/X/, () => url); + assert.strictEqual(result, url, `replacement corrupted ${code}`); + } +}); + +test('leading slash stays encoded', () => { + const body = bodyOf('/a\\/..\\/b/.test(x)'); + assert.ok(body.startsWith('%2F'), `body should start with %2F: ${body}`); +}); + +test('unbalanced parentheses are all encoded', () => { + const originalWarn = console.warn; + console.warn = () => 0; + try { + const body = bodyOf("x=')'"); + assert.ok(!/[()]/.test(body), `parens should be encoded: ${body}`); + assert.ok(body.includes('%29')); + } finally { + console.warn = originalWarn; + } +}); + +test('excessively nested parentheses are all encoded', () => { + const originalWarn = console.warn; + console.warn = () => 0; + try { + const body = bodyOf(`${'('.repeat(33)}${')'.repeat(33)}`); + assert.ok(!/[()]/.test(body)); + } finally { + console.warn = originalWarn; + } +}); + +test('non-ASCII is percent-encoded', () => { + assert.strictEqual(bodyOf("'…'"), "'%E2%80%A6'"); +}); + +test('validator rejects bad input', () => { + assert.throws(() => validateEncodedBookmarklet('http://x'), /javascript:/); + assert.throws(() => validateEncodedBookmarklet('javascript:a b'), /percent-encoded/); + assert.throws(() => validateEncodedBookmarklet('javascript:/a'), /starts with/); + assert.throws(() => validateEncodedBookmarklet('javascript:(a'), /parentheses/); +}); + +// Validate every dist/ bookmarklet +const configPath = path.join(__dirname, '..', 'bookmarklets.json'); +const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); +for (const bookmarklet of config.bookmarklets) { + test(`dist/${bookmarklet.file}`, () => { + const url = fs.readFileSync(path.join(__dirname, '..', 'dist', bookmarklet.file), 'utf8'); + validateEncodedBookmarklet(url); + }); +} + +console.log(`Encoding tests passed: ${passed}`); diff --git a/scripts/update-readme.js b/scripts/update-readme.js index a10cf74..7832d43 100755 --- a/scripts/update-readme.js +++ b/scripts/update-readme.js @@ -12,7 +12,8 @@ const {readFileOrFail, validateBookmarklet} = require('./utils'); // eslint-disable-next-line consistent-return function replaceReadme(readMeString, regexPattern, newStr, bookmarkletName) { if (readMeString.match(regexPattern)) { - return readMeString.replace(regexPattern, newStr); + // Function replacer: stops `$'`, `$&`, `$1` in the code being treated as replacement patterns + return readMeString.replace(regexPattern, () => newStr); } // Fail if there's no match diff --git a/scripts/utils.js b/scripts/utils.js index 2bd4259..de84c20 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -50,7 +50,111 @@ function validateBookmarklet(bookmarklet, index) { } } +/** + * Percent-encoded triplets that are restored to literal characters in bookmarklet URLs. + * + * Each encoded URL is used as (1) a raw `javascript:` URL and the fragment of the Setup + * link, (2) an HTML `href` attribute value, and (3) a Markdown reference-link destination. + * These characters are legal in an RFC 3986 fragment, inert in a double-quoted HTML + * attribute and inert in a CommonMark link destination, so leaving them literal saves bytes. + * + * Characters that stay encoded: `\` (Markdown escape), `&` (entity), `<` `>` (tags), + * `"` (ends attribute/title), `#` (fragment delimiter), `%` (decoding ambiguity), + * `` ` `` (WHATWG fragment encode set), and `*` `_` (Markdown emphasis, forced to + * `%2A`/`%5F`). `{}[]|^` are left encoded for now. + */ +const RESTORED_TRIPLETS = new Map([ + ['%3A', ':'], ['%3D', '='], ['%2C', ','], ['%2F', '/'], ['%3B', ';'], + ['%24', '$'], ['%40', '@'], ['%2B', '+'], ['%3F', '?'] +]); + +const MAX_PAREN_DEPTH = 32; + +/** + * Check that parentheses are balanced and not nested deeper than MAX_PAREN_DEPTH + * @param {string} body - Encoded URL body + * @returns {string|null} Reason the parens are unusable, or null if they are fine + */ +function parenProblem(body) { + let depth = 0; + for (const ch of body) { + if (ch === '(') { + depth += 1; + if (depth > MAX_PAREN_DEPTH) { + return `parentheses nest deeper than ${MAX_PAREN_DEPTH}`; + } + } else if (ch === ')') { + depth -= 1; + if (depth < 0) { + return 'unbalanced parentheses'; + } + } + } + return depth === 0 ? null : 'unbalanced parentheses'; +} + +/** + * Validate an encoded bookmarklet URL; throws a descriptive Error on any failure + * @param {string} url - Full `javascript:...` URL + */ +function validateEncodedBookmarklet(url) { + const prefix = 'javascript:'; + if (!url.startsWith(prefix)) { + throw new Error(`URL does not start with '${prefix}'`); + } + const body = url.slice(prefix.length); + if (!/^(?:[A-Za-z0-9\-.!~'():=,/;$@+?]|%[0-9A-F]{2})*$/.test(body)) { + throw new Error('URL body contains characters that must be percent-encoded'); + } + if (body.startsWith('/')) { + throw new Error("URL body starts with '/', which changes URL parsing"); + } + const problem = parenProblem(body); + if (problem) { + throw new Error(`URL body has ${problem}`); + } + if (new URL(url).href !== url) { + throw new Error('URL does not survive a WHATWG URL round trip'); + } + const asFragment = `https://example.com/x/#${url}`; + if (new URL(asFragment).href !== asFragment) { + throw new Error('URL does not survive a WHATWG URL round trip as a fragment'); + } +} + +/** + * Encode bookmarklet code as a compact, validated `javascript:` URL + * @param {string} code - Minified bookmarklet code + * @returns {string} Full `javascript:...` URL + */ +function encodeBookmarklet(code) { + let body = encodeURIComponent(code) + .replace(/\*/g, '%2A') + .replace(/_/g, '%5F') + .replace(/%(?:3A|3D|2C|2F|3B|24|40|2B|3F)/g, (triplet) => RESTORED_TRIPLETS.get(triplet)); + + // A leading '/' would give the URL a hierarchical path and dot-segment resolution + if (body.startsWith('/')) { + body = `%2F${body.slice(1)}`; + } + + const problem = parenProblem(body); + if (problem) { + console.warn(`Warning: ${problem}; encoding all parentheses`); + body = body.replace(/\(/g, '%28').replace(/\)/g, '%29'); + } + + if (decodeURIComponent(body) !== code) { + throw new Error('Encoded bookmarklet does not decode back to the original code'); + } + const url = `javascript:${body}`; + validateEncodedBookmarklet(url); + return url; +} + module.exports = { readFileOrFail, - validateBookmarklet + validateBookmarklet, + encodeBookmarklet, + validateEncodedBookmarklet }; From 4523749e4c4ddbcc981737d90ad7eb4da74340e3 Mon Sep 17 00:00:00 2001 From: Tom King Date: Sat, 26 Sep 2026 22:04:39 -0500 Subject: [PATCH 2/2] fix: sync package-lock.json with @types/node ~26.6.3 npm ci failed in CI because the lockfile still pinned @types/node 26.6.2. Co-Authored-By: Claude Sonnet 5 --- package-lock.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 22d294c..fafdc35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "devDependencies": { "@eslint/js": "10.0.1", - "@types/node": "~26.6.2", + "@types/node": "~26.6.3", "@typescript-eslint/eslint-plugin": "~8.70.1", "@typescript-eslint/parser": "~8.70.1", "eslint": "10.11.0", @@ -401,9 +401,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", - "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", + "version": "26.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.3.tgz", + "integrity": "sha512-dsqMQQoeTLqu9wynDD00q573mNzso3IdQOAfHRJqLCcmCFPoGo9A1bDpUcv/9tnKpErQWv9uKeGfl37EIS02Yg==", "dev": true, "license": "MIT", "dependencies": {