<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns="http://purl.org/rss/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel rdf:about="https://let.hatelabo.jp/unarist/rss">
    <link>https://let.hatelabo.jp/unarist/rss</link>
    <description></description>
    <title>Bookmarklets from unarist</title>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJmdtaLojaxI"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJmfm9iE84hA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/i-6fpfbEgcAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/i8220fXEgMAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/g5G0hv-GgegT"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHW-9ex3N5o"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHVrPWvl-hw"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHUr_HeiJB3"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJmcxa3yjMtI"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHUxenf0KpN"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHUo4by_bpo"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJmf2ODn7pR1"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHXhPGQ34I6"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJmfvMai6uQe"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHWv4uKv-of"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJme8ZD-2_Z7"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hLHW_4WUwZoq"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJme-9yZ3b0r"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJme9rWRv4gj"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/unarist/let/hJme7oSg94MD"/>
      </rdf:Seq>
    </items>
  </channel>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJmdtaLojaxI">
    <link>https://let.hatelabo.jp/unarist/let/hJmdtaLojaxI</link>
    <dc:date>2023-10-14T19:44:39Z</dc:date>
    <description>event catpture の活躍の場</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Disable contextmenu blocking</title>
    <content:encoded>&lt;a href="javascript:%5B%27contextmenu%27%2C%27selectstart%27%2C%27copy%27%2C%27mousedown%27%5D.forEach%28%28ev%3D%3Ewindow.addEventListener%28ev%2C%28e%3D%3Ee.stopImmediatePropagation%28%29%29%2Ctrue%29%29%29%3Bdocument.head.appendChild%28document.createElement%28%27style%27%29%29.textContent%3D%27%2A%20%7B%20user-select%3A%20initial%20%21important%20%7D%27%3Bvoid%200%3B"&gt;Disable contextmenu blocking&lt;/a&gt;&lt;pre&gt;/*
 * @title Disable contextmenu blocking
 * @description event catpture の活躍の場
 * @include http://*
 * @license CC0 https://creativecommons.org/publicdomain/zero/1.0/
 * @javascript_url
 */

['contextmenu', 'selectstart', 'copy', 'mousedown'].forEach(ev =&amp;gt; window.addEventListener(ev, e =&amp;gt; e.stopImmediatePropagation(), true));
document.head.appendChild(document.createElement('style')).textContent = '* { user-select: initial !important }';
void(0); // prevent redirection (thanks: http://let.hatelabo.jp/Lhankor_Mhy/let/iuzX89CqgKAA)&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJmfm9iE84hA">
    <link>https://let.hatelabo.jp/unarist/let/hJmfm9iE84hA</link>
    <dc:date>2022-12-06T15:28:34Z</dc:date>
    <description>w/ "{title} {url}" format. easy copyable title/url box; click to copy, double-click outer to close</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] T/U box</title>
    <content:encoded>&lt;a href="javascript:%28%28%29%3D%3E%7B%27use%20strict%27%3Bconst%20tag%3D%28name%2Cprops%3D%7B%7D%2Cchildren%3D%5B%5D%29%3D%3E%7Bconst%20e%3DObject.assign%28document.createElement%28name%29%2Cprops%29%3Bif%28typeof%20props.style%3D%3D%3D%22object%22%29Object.assign%28e.style%2Cprops.style%29%3B%28children.forEach%3Fchildren%3A%5Bchildren%5D%29.forEach%28%28c%3D%3Ee.appendChild%28c%29%29%29%3Breturn%20e%7D%3Bconst%20canonical%3D%28%28%29%3D%3E%7Bconst%20canonical_base%3D%28document.querySelector%28%27head%20meta%5Bproperty%3D%22og%3Aurl%22%5D%5Bcontent%5D%27%29%7C%7C%7B%7D%29.content%7C%7C%28document.querySelector%28%27head%20link%5Brel%3D%22canonical%22%5D%5Bhref%5D%27%29%7C%7C%7B%7D%29.href%7C%7C%27%27%3Bif%28%21canonical_base%29return%20null%3Bconst%20prefix%3Dcanonical_base.startsWith%28%27%2F%27%29%26%26location.origin%7C%7C%21canonical_base.match%28%2F%5E%5Ba-z%5D%2B%3A%2F%29%26%26location.protocol%2B%27%2F%2F%27%7C%7C%27%27%3Bconst%20urlobj%3Dnew%20URL%28prefix%2Bcanonical_base%29%3Burlobj.hash%3Dlocation.hash%3Breturn%20urlobj.href%7D%29%28%29%3Bconst%20title%3Ddocument.title%3Bconst%20canonical_whitelist%3D%2F%5C.amazon%5C.%2F%3Bconst%20canonical_blacklist%3D%2F%5B%5C.%5C%2F%5Dgithub%5C.com%7Cyoutube%5C.com%2F%3Blet%20url%3D%21canonical%26%26location.href%7C%7Ccanonical_whitelist.test%28location.href%29%26%26canonical%7C%7Ccanonical_blacklist.test%28location.href%29%26%26location.href%7C%7Cnew%20URL%28canonical%29.pathname%3D%3D%3Dlocation.pathname%26%26canonical%7C%7Cconfirm%28%60%E6%AC%A1%E3%81%AEURL%E3%81%8Cmeta%E3%82%BF%E3%82%B0%E3%81%8B%E3%82%89%E8%A6%8B%E3%81%A4%E3%81%8B%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F%E3%81%8C%E3%80%81%E7%8F%BE%E5%9C%A8%E3%81%AEpath%E3%81%A8%E7%95%B0%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82%5Cn%E3%82%AD%E3%83%A3%E3%83%B3%E3%82%BB%E3%83%AB%E3%82%92%E6%8A%BC%E3%81%99%E3%81%A8location.href%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%5Cn%24%7Bcanonical%7D%60%29%26%26canonical%7C%7Clocation.href%3Bconst%20filters%3D%7B%5B%2Fwww%5C.google%5C.%5Ba-z%5C.%5D%2B%5C%2Fsearch%2F%5D%3A%7Ballowed_params%3A%2F%5E%28q%7Ctbm%7Ctbs%7Cstart%29%24%2F%7D%2C%5B%2F%28amazon%5C.%5Ba-z%5C.%5D%2B%29%5C%2F%28%5B%5E%5C%2F%5D%2B%5C%2F%29%3Fdp%2F%5D%3A%7Breplace%3A%27%241%2Fdp%27%2Callowed_params%3A%2F%5E%24%2F%7D%2C%5B%2F%28amazon%5C.%5Ba-z%5C.%5D%2B%29%5C%2F%28%5B%5E%5C%2F%5D%2B%3F%5C%2F%29%3F%28s%7Cgp%5C%2Fsearch%29%28%5C%2F%5B%5E%5C%3F%5D%2A%29%3F%5C%3F%2F%5D%3A%7Breplace%3A%27%241%2Fs%3F%27%2Callowed_params%3A%2F%5E%28url%7Csearch-alias%7Cfield-.%2B%7Crh%7Csort%7Cpage%29%24%2F%7D%2C%5B%2Fwww%5C.youtube%5C.com%5C%2Fwatch.%2A%5B%5C%3F%26%5Dv%3D%28%5B%5E%26%23%3F%5D%2B%29%26%3F%2F%5D%3A%7Breplace%3A%27youtu.be%2F%241%3F%27%2Callowed_params%3A%2F%5Et%24%2F%7D%7D%3Bfor%28const%5Bname%2Caction%5Dof%20Object.entries%28filters%29%29%7Bconst%20regex%3Dnew%20RegExp%28name.substr%281%2Cname.length-2%29%29%3Bif%28%21regex.test%28url%29%29continue%3Bif%28action.replace%29url%3Durl.replace%28regex%2Caction.replace%29%3Bconst%20urlobj%3Dnew%20URL%28url%29%3Bif%28action.allowed_params%29%7B%5B...urlobj.searchParams.keys%28%29%5D.filter%28%28k%3D%3E%21action.allowed_params.test%28k%29%29%29.forEach%28%28k%3D%3Eurlobj.searchParams.delete%28k%29%29%29%7Durl%3Durlobj.toString%28%29%7Durl%3Durl.replace%28%2F%5C%3F%3F%23%3F%24%2F%2C%27%27%29%3Bconst%20box%3Ddocument.body.appendChild%28tag%28%27div%27%2C%7Bid%3A%27copy-buttons%27%2Cstyle%3A%60%5Cnborder%3A%201em%20solid%20white%3B%5Cnoutline%3A%201px%20solid%20silver%3B%5Cnpadding%3A%200.2em%200.5em%3B%5Cnbackground%3A%20silver%3B%5Cnposition%3A%20fixed%3B%5Cntop%3A%200%3B%5Cnleft%3A%200%3B%5Cnz-index%3A%20%24%7BNumber.MAX_SAFE_INTEGER%7C%7CNumber.MAX_VALUE%7D%3B%5Cn%60%7D%29%29%3Bconst%20onClose%3De%3D%3E%7Bbox.parentNode.removeChild%28box%29%3Bdocument.removeEventListener%28%27click%27%2ConClose%29%3Be.stopPropagation%28%29%7D%3Bbox.addEventListener%28%27click%27%2C%28e%3D%3Ee.stopPropagation%28%29%29%29%3Bbox.addEventListener%28%27dblclick%27%2ConClose%29%3Bdocument.addEventListener%28%27click%27%2ConClose%29%3B%5B%7Blabel%3A%27URL%27%2Cvalue%3Aurl%7D%2C%7Blabel%3A%27Title%27%2Cvalue%3Atitle%7D%2C%7Blabel%3A%27Title%20%2B%20URL%27%2Cvalue%3Atitle%2B%27%20%27%2Burl%7D%2C%7Blabel%3A%27Hatena%27%2Cvalue%3A%60%5B%24%7Burl%7D%3Atitle%3D%24%7Btitle%7D%5D%60%7D%2C%7Blabel%3A%27Markdown%27%2Cvalue%3A%60%5B%24%7Btitle%7D%5D%28%24%7Burl%7D%29%60%7D%2C%7Blabel%3A%27Markdown%2Btitle%27%2Cvalue%3A%60%27%5B%24%7Burl%7D%5D%28%24%7Burl%7D%20%22%24%7Btitle%7D%22%29%27%60.slice%281%2C-1%29%7D%2Cnavigator.share%26%26%7Blabel%3A%27Web%20Share%27%2Cvalue%3A%60Share%21%60%2Conclick%3A%28%29%3D%3Enavigator.share%28%7Btitle%3Atitle%2Curl%3Aurl%7D%29%7D%5D.filter%28%28x%3D%3Ex%29%29.forEach%28%28%28%7Blabel%3Alabel%2Cvalue%3Avalue%2Conclick%3Aonclick%7D%29%3D%3E%7Bbox.appendChild%28tag%28%27label%27%2C%7Bstyle%3A%60display%3A%20block%3B%20color%3A%20black%3B%20text-align%3A%20left%3B%60%7D%2C%5Btag%28%27span%27%2C%7Bstyle%3A%60display%3A%20inline-block%3B%20width%3A%208em%3B%60%2CtextContent%3A%60%24%7Blabel%7D%3A%20%60%7D%29%2C%21onclick%3Ftag%28%27input%27%2C%7Bstyle%3A%60%5Cncolor%3A%20black%3B%5Cnbackground-color%3A%20%23ddd%3B%5Cnborder%3A%20none%3B%5Cnborder-bottom%3A%201px%20solid%20gray%3B%5Cnpadding%3A%200.2em%3B%5Cnmargin%3A%200.3em%200%3B%5Cnwidth%3A%2015em%3B%60%2Cvalue%3Avalue%2Ctitle%3Avalue%2Conclick%3Ae%3D%3E%7Be.target.select%28%29%3Bdocument.execCommand%28%27copy%27%29%3Be.stopPropagation%28%29%7D%7D%29%3Atag%28%27input%27%2C%7Btype%3A%27button%27%2Cstyle%3A%60margin%3A%200.3em%200%3B%20%60%2Conclick%3Aonclick%2Cvalue%3Avalue%7D%29%5D%29%29%7D%29%29%7D%29%28%29%3B"&gt;T/U box&lt;/a&gt;&lt;pre&gt;/*
 * @title T/U box
 * @description w/ &amp;quot;{title} {url}&amp;quot; format. easy copyable title/url box; click to copy, double-click outer to close
 * @include http://*
 * @include https://*
 * @contributor	pacochi	http://let.hatelabo.jp/pacochi/let/hJme3OvVzN41
 * @contributor noromanba http://let.hatelabo.jp/noromanba/let/hJme3Pyylqos
 * @license MIT License	https://opensource.org/licenses/MIT
 * @javascript_url
 */

/* modifications

* Show confirm dialog for doubtful URL
 (location.pushState/replace will cause mismatch between meta URLs and current URL)
* URL cleanup for some sites
* Fix copy format
* Hover cursor on inputs to show preview (i.e. title attribute)
* Add Title+URL, Markdown+title format
* Append location.hash
* Avoid to use array for querySelector (for cloudflare rocket.js)
* Close on click anywhere
* Add support of og:url with absolute path and protocol-less URL
* Add support of Web Share API (Chromium and &amp;quot;Experimental Web Platform features&amp;quot; flag may be required. only on https page)
* More styles

*/

(() =&amp;gt; {
  'use strict';
  
  const tag = (name, props = {}, children = []) =&amp;gt; {
    const e = Object.assign(document.createElement(name), props);
    if (typeof props.style === &amp;quot;object&amp;quot;) Object.assign(e.style, props.style);
    (children.forEach ? children : [children]).forEach(c =&amp;gt; e.appendChild(c));
    return e;
  };

  // SPAの普及と雑metaタグの多さで、canonical参照微妙かもなあという気持ちが少しある
  const canonical = (() =&amp;gt; {
    const canonical_base = 
          (document.querySelector('head meta[property=&amp;quot;og:url&amp;quot;][content]') || {}).content ||
          (document.querySelector('head link[rel=&amp;quot;canonical&amp;quot;][href]') || {}).href ||
          '';
    
    if (!canonical_base) return null;
    
    const prefix = 
          (canonical_base.startsWith('/') &amp;amp;&amp;amp; location.origin) ||
          (!canonical_base.match(/^[a-z]+:/) &amp;amp;&amp;amp; location.protocol + '//') || /* :/ */
          '';
    
    const urlobj = new URL(prefix + canonical_base);
    urlobj.hash = location.hash;
    
    return urlobj.href;
  })();
  
  const title = document.title;

  const canonical_whitelist = /\.amazon\./;
  const canonical_blacklist = /[\.\/]github\.com|youtube\.com/;
  
  let url =
        (!canonical &amp;amp;&amp;amp; location.href) ||
        (canonical_whitelist.test(location.href) &amp;amp;&amp;amp; canonical) ||
        (canonical_blacklist.test(location.href) &amp;amp;&amp;amp; location.href) ||
        (new URL(canonical).pathname === location.pathname &amp;amp;&amp;amp; canonical) ||
        (confirm(`次のURLがmetaタグから見つかりましたが、現在のpathと異なります。\nキャンセルを押すとlocation.hrefを使用します。\n${canonical}`) &amp;amp;&amp;amp; canonical) ||
        location.href;
  
  const filters = {
    // tbm: mode, tbs: options
    [/www\.google\.[a-z\.]+\/search/]: { allowed_params: /^(q|tbm|tbs|start)$/ },
    [/(amazon\.[a-z\.]+)\/([^\/]+\/)?dp/]: { replace: '$1/dp', allowed_params: /^$/ },
    // 単純な検索は search-alias, field-.+ で、そこから設定していくと rh になるっぽい。
    // url は search-alias 等を含んでいることがあり、展開してしまってもよさそうではあるが…。
    // あとcanonicalだとrhに正規化されてる気がする。
    [/(amazon\.[a-z\.]+)\/([^\/]+?\/)?(s|gp\/search)(\/[^\?]*)?\?/]: { replace: '$1/s?', allowed_params: /^(url|search-alias|field-.+|rh|sort|page)$/ },
    [/www\.youtube\.com\/watch.*[\?&amp;amp;]v=([^&amp;amp;#?]+)&amp;amp;?/]: { replace: 'youtu.be/$1?', allowed_params: /^t$/ },
  };

  for (const [name, action] of Object.entries(filters)) {
      const regex = new RegExp(name.substr(1, name.length - 2));
      if (!regex.test(url)) continue;

      if (action.replace)
        url = url.replace(regex, action.replace);

      const urlobj = new URL(url);
      if (action.allowed_params) {
        [...urlobj.searchParams.keys()]
        .filter(k =&amp;gt; !action.allowed_params.test(k))
        .forEach(k =&amp;gt; urlobj.searchParams.delete(k));
      }
      url = urlobj.toString();
  }
  
  url = url.replace(/\??#?$/, '');

  const box = document.body.appendChild(tag('div', {
    id: 'copy-buttons',
    style: `
border: 1em solid white;
outline: 1px solid silver;
padding: 0.2em 0.5em;
background: silver;
position: fixed;
top: 0;
left: 0;
z-index: ${Number.MAX_SAFE_INTEGER || Number.MAX_VALUE};
`,
  }));
  const onClose = e =&amp;gt; {
    box.parentNode.removeChild(box);
    document.removeEventListener('click', onClose);
    e.stopPropagation();
  };
  
  box.addEventListener('click', e =&amp;gt; e.stopPropagation());
  box.addEventListener('dblclick', onClose);
  document.addEventListener('click', onClose);
  
  [
    { label: 'URL', value: url },
    { label: 'Title', value: title },
    { label: 'Title + URL', value: title + ' ' + url },
    { label: 'Hatena', value: `[${url}:title=${title}]` },
    { label: 'Markdown', value: `[${title}](${url})` },
    { label: 'Markdown+title', value: `'[${url}](${url} &amp;quot;${title}&amp;quot;)'`.slice(1, -1) },
    navigator.share &amp;amp;&amp;amp; { label: 'Web Share', value: `Share!`, onclick: () =&amp;gt; navigator.share({ title, url }) },
  ].filter(x =&amp;gt; x).forEach(({label, value, onclick}) =&amp;gt; {
    box.appendChild(tag('label', {
      style: `display: block; color: black; text-align: left;`,
    }, [
      tag('span', {
        style: `display: inline-block; width: 8em;`,
        textContent: `${label}: `
      }),
      !onclick ?
      tag('input', {
        style: `
color: black;
background-color: #ddd;
border: none;
border-bottom: 1px solid gray;
padding: 0.2em;
margin: 0.3em 0;
width: 15em;`,
        value,
        title: value,
        onclick: e =&amp;gt; {
          e.target.select();
          document.execCommand('copy');
          e.stopPropagation();
        }
      }) :
      tag('input', {
        type: 'button',
        style: `margin: 0.3em 0; `,
        onclick,
        value
      })
    ]));
  });
})();
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/i-6fpfbEgcAA">
    <link>https://let.hatelabo.jp/unarist/let/i-6fpfbEgcAA</link>
    <dc:date>2021-06-16T13:29:28Z</dc:date>
    <description>Simple Key Logger (w/o modifiers, composition)</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] KeyLogger</title>
    <content:encoded>&lt;a href="javascript:%28%28%29%3D%3E%7Bif%28window.__KeyLogger_finish%29%7Bwindow.__KeyLogger_finish%28%29%3Breturn%7Dlet%20events%3D%5B%27timestamp%20%28Asia%2FTokyo%29%5Ctkey%5Ctcode%5CtkeyCode%5Cttarget%27%5D%3Bconst%20dtFormat%3Dnew%20Intl.DateTimeFormat%28%27ja-JP%27%2C%7BtimeZone%3A%27Asia%2FTokyo%27%2Chour12%3Afalse%2Cyear%3A%27numeric%27%2Cmonth%3A%272-digit%27%2Cday%3A%272-digit%27%2Chour%3A%272-digit%27%2Cminute%3A%272-digit%27%2Csecond%3A%272-digit%27%7D%29%3Bconst%20listener%3De%3D%3E%7Bif%28e.isComposing%7C%7Ce.repeat%7C%7C%5B%27Control%27%2C%27Shift%27%2C%27Alt%27%2C%27Meta%27%5D.includes%28e.key%29%29return%3Bconst%20ts%3DdtFormat.format%28new%20Date%29%3Bconst%20shortStr%3D%5Be.ctrlKey%26%26%27Ctrl%27%2Ce.shiftKey%26%26%27Shift%27%2Ce.altKey%26%26%27Alt%27%2Ce.metaKey%26%26%27Meta%27%2Ce.key%5D.filter%28%28x%3D%3Ex%29%29.join%28%27%2B%27%29%3Bevents.push%28%5Bts%2CshortStr%2Ce.code%2Ce.keyCode%2Ce.target.localName%5D.join%28%27%5Ct%27%29%29%7D%3Bwindow.addEventListener%28%27keydown%27%2Clistener%2C%7Bcapture%3Atrue%7D%29%3Bwindow.__KeyLogger_finish%3D%28%29%3D%3E%7Bwindow.removeEventListener%28%27keydown%27%2Clistener%2C%7Bcapture%3Atrue%7D%29%3Bconst%20resultdoc%3Dwindow.open%28%27about%3Ablank%27%2C%27_blank%27%29.document%3Bresultdoc.title%3D%60%E3%82%AD%E3%83%BC%E6%93%8D%E4%BD%9C%E3%81%AE%E8%A8%98%E9%8C%B2%20-%20%24%7BdtFormat.format%28new%20Date%29%7D%60%3Bresultdoc.body.appendChild%28Object.assign%28resultdoc.createElement%28%27textarea%27%29%2C%7BreadOnly%3Atrue%2Cstyle%3A%27position%3A%20fixed%3B%20width%3A%20100%25%3B%20height%3A%20100%25%3B%20top%3A%200%3B%20left%3A%200%3B%27%2CtextContent%3A%60----%20%E6%8A%BC%E3%81%95%E3%82%8C%E3%81%9F%E3%82%AD%E3%83%BC%20----%5Cn%24%7Bevents.join%28%27%5Cn%27%29%7D%5Cn----%20%E7%92%B0%E5%A2%83%E6%83%85%E5%A0%B1%20----%5CnURL%3A%20%24%7Blocation.href%7D%5Cn%E7%92%B0%E5%A2%83%3A%20%24%7Bnavigator.userAgent%7D%60%7D%29%29%3Bdelete%20window.__KeyLogger_finish%7D%3Balert%28%27%E3%81%93%E3%81%AE%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%A7%E6%8A%BC%E3%81%95%E3%82%8C%E3%81%9F%E3%82%AD%E3%83%BC%E3%81%AE%E8%A8%98%E9%8C%B2%E3%82%92%E9%96%8B%E5%A7%8B%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82%E8%A8%98%E9%8C%B2%E7%B5%90%E6%9E%9C%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%82%82%E3%81%86%E4%B8%80%E5%BA%A6%E3%81%93%E3%81%AE%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%AC%E3%83%83%E3%83%88%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82%27%29%7D%29%28%29%3B"&gt;KeyLogger&lt;/a&gt;&lt;pre&gt;/*
 * @title KeyLogger
 * @description Simple Key Logger (w/o modifiers, composition)
 * @include http://*
 * @license MIT License
 * @javascript_url 
 */

(() =&amp;gt; {
  if (window.__KeyLogger_finish) {
    window.__KeyLogger_finish();
    return;
  }
  let events = ['timestamp (Asia/Tokyo)\tkey\tcode\tkeyCode\ttarget'];
  const dtFormat = new Intl.DateTimeFormat('ja-JP', { timeZone: 'Asia/Tokyo', hour12: false, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' });
  const listener = e =&amp;gt; {
    if (e.isComposing || e.repeat || ['Control','Shift','Alt','Meta'].includes(e.key)) return;
    const ts = dtFormat.format(new Date());
    const shortStr = [e.ctrlKey &amp;amp;&amp;amp; 'Ctrl', e.shiftKey &amp;amp;&amp;amp; 'Shift', e.altKey &amp;amp;&amp;amp; 'Alt', e.metaKey &amp;amp;&amp;amp; 'Meta', e.key].filter(x =&amp;gt; x).join('+');
    events.push([ts, shortStr, e.code, e.keyCode, e.target.localName].join('\t'));
  };
  window.addEventListener('keydown', listener, { capture: true });
  window.__KeyLogger_finish = () =&amp;gt; {
    window.removeEventListener('keydown', listener, { capture: true });
    // dataURIにしてnoopenerにしてもいいな
    const resultdoc = window.open('about:blank', '_blank').document;
    resultdoc.title = `キー操作の記録 - ${dtFormat.format(new Date())}`;
    resultdoc.body.appendChild(Object.assign(resultdoc.createElement('textarea'), {
      readOnly: true,
      style: 'position: fixed; width: 100%; height: 100%; top: 0; left: 0;',
      textContent: `---- 押されたキー ----\n${events.join('\n')}\n---- 環境情報 ----\nURL: ${location.href}\n環境: ${navigator.userAgent}`
    }));
    delete window.__KeyLogger_finish;
  };
  alert('このページで押されたキーの記録を開始しました。記録結果を表示するにはもう一度このブックマークレットを実行してください。');
})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/i8220fXEgMAA">
    <link>https://let.hatelabo.jp/unarist/let/i8220fXEgMAA</link>
    <dc:date>2021-04-26T13:05:19Z</dc:date>
    <description></description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Slackの箇条書きを普通のul入れ子にする</title>
    <content:encoded>&lt;a href="javascript:%28%28%29%3D%3E%7Bdocument.querySelectorAll%28%27.p-rich_text_list%27%29.forEach%28%28x%3D%3Ex.classList.remove%28%27p-rich_text_list%27%2C%27p-rich_text_list__bullet%27%29%29%29%3B%5B...document.querySelectorAll%28%27.p-rich_text_block%27%29%5D.map%28%28x%3D%3Ex.querySelectorAll%28%27ul%5Bdata-indent%5D%27%29%29%29.forEach%28%28%28%5Bx%2C...xs%5D%29%3D%3Exs.reduce%28%28%28stack%2Cc%29%3D%3E%7Bconst%20p%3Dstack%5Bstack.length-1%5D%3Bif%28p.dataset.indent%3Cc.dataset.indent%29%7Bif%28c.dataset.indent-p.dataset.indent%3E1%29%7Balert%28%272%E6%AE%B5%E4%BB%A5%E4%B8%8A%E4%B8%80%E6%B0%97%E3%81%AB%E3%82%A4%E3%83%B3%E3%83%87%E3%83%B3%E3%83%88%E3%81%99%E3%82%8B%E3%81%AE%E3%81%AF%E9%9D%9E%E5%AF%BE%E5%BF%9C%27%29%3Bthrow%20new%20Error%7Dp.append%28c%29%3Breturn%20stack.concat%28c%29%7Delse%7Bstack%5Bc.dataset.indent%5D.append%28...c.children%29%3Breturn%20stack.slice%280%2Cc.dataset.indent%2B1%29%7D%7D%29%2C%5Bx%5D%29%29%29%7D%29%28%29%3B"&gt;Slackの箇条書きを普通のul入れ子にする&lt;/a&gt;&lt;pre&gt;/*
 * @title Slackの箇条書きを普通のul入れ子にする
 * @include https://app.slack.com/client/*
 * @license MIT License
 * @javascript_url 
 */

/*
 ## これはなに
 Slackの箇条書きをコピペするとインデントや●が消えるやつをなんとかしよう
 
 ## 使い方
 1. Slackのブラウザ版で変換したい箇条書きのある投稿を表示する
 2. これを実行する
 3. DOMツリー上の全ての箇条書きが変換されているので、コピペしたりする
*/

(() =&amp;gt; {
  document.querySelectorAll('.p-rich_text_list').forEach(x =&amp;gt; x.classList.remove('p-rich_text_list', 'p-rich_text_list__bullet'));
  [...document.querySelectorAll('.p-rich_text_block')]
    .map(x =&amp;gt; x.querySelectorAll('ul[data-indent]'))
    .forEach(([x, ...xs]) =&amp;gt; xs.reduce((stack,c) =&amp;gt; {
      const p = stack[stack.length - 1];
      if (p.dataset.indent &amp;lt; c.dataset.indent) {
        if (c.dataset.indent - p.dataset.indent &amp;gt; 1) {
          alert('2段以上一気にインデントするのは非対応');
          throw new Error();
        }
        p.append(c);
        return stack.concat(c);
      } else {
        stack[c.dataset.indent].append(...c.children);
        return stack.slice(0, c.dataset.indent + 1);
      }
  }, [x]));
})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/g5G0hv-GgegT">
    <link>https://let.hatelabo.jp/unarist/let/g5G0hv-GgegT</link>
    <dc:date>2020-02-12T06:52:31Z</dc:date>
    <description>画面をwebmで録画するやつ</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] 録画</title>
    <content:encoded>&lt;a href="javascript:%28function%28%29%7B%27use%20strict%27%3Bif%28%21navigator.mediaDevices%29%7Balert%28location.protocol%3D%3D%3D%27http%3A%27%3F%27https%E3%81%A7%E3%81%AA%E3%81%84%E3%82%B5%E3%82%A4%E3%83%88%E3%81%A7%E3%81%AF%E4%BD%BF%E3%81%88%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82%27%3A%27%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E3%81%99%27%29%3Breturn%7Dconst%20tag%3D%28name%2Cprops%3D%7B%7D%2Cchildren%3D%5B%5D%29%3D%3E%7Bconst%20e%3DObject.assign%28document.createElement%28name%29%2Cprops%29%3Bif%28typeof%20props.style%3D%3D%3D%22object%22%29Object.assign%28e.style%2Cprops.style%29%3B%28children.forEach%3Fchildren%3A%5Bchildren%5D%29.forEach%28%28c%3D%3Ee.appendChild%28c%29%29%29%3Breturn%20e%7D%3Bconst%20modal%3D%28%28%29%3D%3E%7Blet%20refs%3D%7B%7D%3Brefs.container%3Dtag%28%27div%27%2C%7Bstyle%3A%27position%3A%20fixed%3B%20top%3A%200%3B%20left%3A%200%3B%20width%3A%20100%25%3B%20height%3A%20100%25%3B%20background%3A%20rgba%280%2C%200%2C%200%2C%200.8%29%3B%20z-index%3A%202147483647%27%7D%2C%5Brefs.content%3Dtag%28%27div%27%2C%7Bstyle%3A%60%5Cnposition%3A%20absolute%3B%20width%3A%20320px%3B%20height%3A%20160px%3B%20left%3A%200%3B%20right%3A%200%3B%20top%3A%200%3B%20bottom%3A%200%3B%20margin%3A%20auto%3B%20padding%3A%201em%3B%5Cnbackground%3A%20white%3B%20border-radius%3A%205px%3B%5Cndisplay%3A%20flex%3B%20flex-direction%3A%20column%3B%20align-items%3A%20center%3B%20justify-content%3A%20space-evenly%3B%60%7D%2C%5Btag%28%27p%27%2C%7Bstyle%3A%27font-size%3A%201.4em%3B%20font-weight%3A%20bold%27%2CtextContent%3A%27%E9%8C%B2%E7%94%BB%E4%B8%AD...%27%7D%29%2Ctag%28%27p%27%2C%7BtextContent%3A%27%E4%B8%8B%E3%81%AE%E3%80%8C%E9%8C%B2%E7%94%BB%E7%B5%82%E4%BA%86%E3%80%8D%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E3%81%8B%E3%80%81%E7%94%BB%E9%9D%A2%E5%85%B1%E6%9C%89%E3%82%92%E5%81%9C%E6%AD%A2%E3%81%99%E3%82%8B%E3%81%A8%E3%80%81%E9%8C%B2%E7%94%BB%E3%82%92%E7%B5%82%E4%BA%86%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%27%7D%29%2Crefs.stopButton%3Dtag%28%27button%27%2C%7BtextContent%3A%27%E9%8C%B2%E7%94%BB%E7%B5%82%E4%BA%86%27%7D%29%5D%29%5D%29%3Breturn%7Bshow%28%7BonStop%3AonStop%7D%29%7Bdocument.body.appendChild%28refs.container%29%3Brefs.stopButton.onclick%3DonStop%7D%2Chide%28%29%7Brefs.container.remove%28%29%7D%7D%7D%29%28%29%3Bfunction%20saveFile%28filename%2Cblob%29%7Bconst%20url%3DURL.createObjectURL%28blob%29%3Bconst%20link%3Dtag%28%27a%27%2C%7Bstyle%3A%27display%3A%20none%27%2Chref%3Aurl%2Cdownload%3Afilename%7D%29%3Bdocument.body.appendChild%28link%29%3Blink.click%28%29%3BURL.revokeObjectURL%28url%29%3Blink.remove%28%29%7Dfunction%20getDefaultFilename%28%29%7Bconst%20dateStr%3D%28new%20Date%29.toLocaleString%28%27ja-JP%27%2C%7Bhour12%3Afalse%2Cyear%3A%27numeric%27%2Cmonth%3A%272-digit%27%2Cday%3A%272-digit%27%2Chour%3A%272-digit%27%2Cminute%3A%272-digit%27%2Csecond%3A%272-digit%27%7D%29%3Breturn%20dateStr.replace%28%2F%5B%5C%2F%3A%5D%2Fg%2C%27%27%29.replace%28%2F%20%2F%2C%27-%27%29%7Dnavigator.mediaDevices.getDisplayMedia%28%29.then%28%28stream%3D%3E%7Blet%20chunks%3D%5B%5D%3Bconst%20recorder%3Dnew%20MediaRecorder%28stream%2C%7BmimeType%3AMediaRecorder.isTypeSupported%28%27video%2Fwebm%3Bcodecs%3Dvp9%27%29%3F%27video%2Fwebm%3Bcodecs%3Dvp9%27%3A%27video%2Fwebm%3Bcodecs%3Dvp8%27%2CvideoBitsPerSecond%3A800%2A1e3%7D%29%3Brecorder.ondataavailable%3De%3D%3Echunks.push%28e.data%29%3Bconst%20recordingPromise%3Dnew%20Promise%28%28%28resolve%2Creject%29%3D%3E%7Brecorder.onstop%3D%28%29%3D%3Eresolve%28new%20Blob%28chunks%2C%7Btype%3Arecorder.mimeType%7D%29%29%3Brecorder.onerror%3De%3D%3Ereject%28e.error%29%7D%29%29.finally%28%28%28%29%3D%3E%7Bstream.getTracks%28%29.forEach%28%28track%3D%3Etrack.stop%28%29%29%29%3Bmodal.hide%28%29%7D%29%29%3Bstream.getTracks%28%29.forEach%28%28x%3D%3Ex.addEventListener%28%27ended%27%2C%28%28%29%3D%3Erecorder.stop%28%29%29%29%29%29%3Bmodal.show%28%7BonStop%3A%28%29%3D%3Erecorder.stop%28%29%7D%29%3Brecorder.start%28%29%3Breturn%20recordingPromise%7D%29%29.then%28%28blob%3D%3E%7Bconst%20name%3Dprompt%28%27%E9%8C%B2%E7%94%BB%E3%81%8C%E5%AE%8C%E4%BA%86%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%82%92%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82%27%2CgetDefaultFilename%28%29%29%3Bif%28%21name%29return%3BsaveFile%28name%2B%27.webm%27%2Cblob%29%7D%29%29.catch%28%28e%3D%3E%7Bconst%20hint%3De.message.includes%28%27user%20gesture%27%29%3F%27%E4%B8%80%E5%BA%A6%E3%83%9A%E3%83%BC%E3%82%B8%E3%81%AE%E3%81%A9%E3%81%93%E3%81%8B%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89%E5%86%8D%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E3%81%BF%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82%27%3Ae.name%3D%3D%3D%27NotAllowedError%27%3F%27%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3%E3%81%8C%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%82%88%E3%81%86%E3%81%A7%E3%81%99%E3%80%82%5Cn%E3%83%BB%E5%85%B1%E6%9C%89%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0%E3%81%A7%E3%80%8C%E6%8B%92%E5%90%A6%E3%80%8D%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%BE%E3%81%9B%E3%82%93%E3%81%A7%E3%81%97%E3%81%9F%E3%81%8B%EF%BC%9F%5Cn%E3%83%BB%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%81%A7%E3%82%AB%E3%83%A1%E3%83%A9%E3%81%AE%E4%BD%BF%E7%94%A8%E3%81%AA%E3%81%A9%E3%82%92%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%9B%E3%82%93%E3%81%8B%EF%BC%9F%27%3Anull%3Bconst%20msg%3De.message%7C%7Ce.name%7C%7Ce%3Balert%28%27%E9%8C%B2%E7%94%BB%E3%81%AB%E5%A4%B1%E6%95%97%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82%5Cn%27%2B%28hint%3Fhint%2B%27%5Cn%5Cn%27%3A%27%27%29%2B%27%E3%82%A8%E3%83%A9%E3%83%BC%E8%A9%B3%E7%B4%B0%3A%20%27%2Be%29%7D%29%29%7D%29%28%29%3B"&gt;録画&lt;/a&gt;&lt;pre&gt;/*
 * @title 録画
 * @description 画面をwebmで録画するやつ
 * @include http://*
 * @include https://*
 * @license MIT License
 * @javascript_url
 */

(function() {
    'use strict';
  
    if (!navigator.mediaDevices) {
      alert(location.protocol === 'http:' ? 'httpsでないサイトでは使えません。' : '対応していないブラウザです');
      return;
    }

    const tag = (name, props = {}, children = []) =&amp;gt; {
        const e = Object.assign(document.createElement(name), props);
        if (typeof props.style === &amp;quot;object&amp;quot;) Object.assign(e.style, props.style);
        (children.forEach ? children : [children]).forEach(c =&amp;gt; e.appendChild(c));
        return e;
    };

    const modal = (() =&amp;gt; {
        let refs = {};
        refs.container = tag('div', {
            style: 'position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 2147483647'
        }, [
            refs.content = tag('div', {
                style: `
position: absolute; width: 320px; height: 160px; left: 0; right: 0; top: 0; bottom: 0; margin: auto; padding: 1em;
background: white; border-radius: 5px;
display: flex; flex-direction: column; align-items: center; justify-content: space-evenly;`
            }, [
                tag('p', { style: 'font-size: 1.4em; font-weight: bold', textContent: '録画中...' }),
                tag('p', { textContent: '下の「録画終了」ボタンをクリックするか、画面共有を停止すると、録画を終了します。' }),
                refs.stopButton = tag('button', { textContent: '録画終了' })
            ])
        ]);
        return {
            show({onStop}) {
                document.body.appendChild(refs.container);
                refs.stopButton.onclick = onStop;
            },
            hide() {
                refs.container.remove();
            }
        };
    })();

    function saveFile(filename, blob) {
        const url = URL.createObjectURL(blob);
        const link = tag('a', { style: 'display: none', href: url, download: filename });
        document.body.appendChild(link);
        link.click();
        URL.revokeObjectURL(url);
        link.remove();
    }

    function getDefaultFilename() {
        const dateStr = new Date().toLocaleString('ja-JP', {
            hour12: false,
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit'
        });
      return dateStr.replace(/[\/:]/g, '').replace(/ /, '-');
    }

    navigator.mediaDevices.getDisplayMedia(/* w,h,audio */)
    .then(stream =&amp;gt; {
        let chunks = [];
        const recorder = new MediaRecorder(stream, {
            mimeType: MediaRecorder.isTypeSupported('video/webm;codecs=vp9') ? 'video/webm;codecs=vp9' : 'video/webm;codecs=vp8',
            videoBitsPerSecond: 800 * 1000
        });
        recorder.ondataavailable = e =&amp;gt; chunks.push(e.data);
        const recordingPromise = new Promise((resolve, reject) =&amp;gt; {
            recorder.onstop = () =&amp;gt; resolve(new Blob(chunks, { type: recorder.mimeType }));
            recorder.onerror = e =&amp;gt; reject(e.error);
        })
        .finally(() =&amp;gt; {
            // 録画を終了したら元ストリームも閉じる（共有を停止する）
            stream.getTracks().forEach(track =&amp;gt; track.stop());
            modal.hide();
        });
        // 82canaryだとなくても共有終了で閉じてくれたけど、80stableでは必要っぽい？
        stream.getTracks().forEach(x =&amp;gt; x.addEventListener('ended', () =&amp;gt; recorder.stop()));
        modal.show({ onStop: () =&amp;gt; recorder.stop() });
        recorder.start();
        return recordingPromise;
    })
    .then(blob =&amp;gt; {
        const name = prompt('録画が完了しました。ファイル名を入力してください。', getDefaultFilename());
        if (!name) return;
        saveFile(name + '.webm', blob);
    })
    .catch(e =&amp;gt; {
      const hint =
        e.message.includes('user gesture') ? '一度ページのどこかをクリックしてから再実行してみてください。' :
        e.name === 'NotAllowedError' ? 'キャプチャがブロックされているようです。\n・共有ダイアログで「拒否」を選択しませんでしたか？\n・ブラウザの設定でカメラの使用などをブロックしていませんか？' :
        null;
      const msg = e.message || e.name || e;
      alert('録画に失敗しました。\n' + (hint ? hint + '\n\n' : '') + 'エラー詳細: ' + e);
    });
})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHW-9ex3N5o">
    <link>https://let.hatelabo.jp/unarist/let/hLHW-9ex3N5o</link>
    <dc:date>2018-10-04T13:51:19Z</dc:date>
    <description>CWを自動で開きます。まる。</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Mastodon - Auto CW opener</title>
    <content:encoded>&lt;a href="javascript:%28%28target%2Cproc%29%3D%3E%28new%20MutationObserver%28%28m%3D%3Em.forEach%28%28r%3D%3Eproc%28r.addedNodes%29%29%29%29%29.observe%28target%2C%7BchildList%3A1%2Csubtree%3A1%7D%29%2Cproc%28%5Btarget%5D%29%29%29%28document.querySelector%28%27.columns-area%27%29%2C%28nodes%3D%3E%7BArray.from%28nodes%29.filter%28%28n%3D%3En.nodeType%3D%3D%3DNode.ELEMENT_NODE%29%29.reduce%28%28%28p%2Cc%29%3D%3Ep.concat%28Array.from%28c.querySelectorAll%28%27.status__content%27%29%29%29%29%2C%5B%5D%29.forEach%28%28n%3D%3E%7Bif%28n.lastElementChild.matches%28%27.status__content__text%3Anot%28.status__content__text--visible%27%29%29n.querySelector%28%27.status__content__spoiler-link%20span%27%29.click%28%29%7D%29%29%7D%29%29%3B"&gt;Mastodon - Auto CW opener&lt;/a&gt;&lt;pre&gt;/*
 * @title Mastodon - Auto CW opener
 * @description CWを自動で開きます。まる。
 * @license MIT License
 * @javascript_url
 */

// jQuery依存がなくなるようなのでjQueryなしで書き直し。

/*
  .status-listをtargetとして複数降ってくることが多いので、targetをそのまま反復するのは無駄が多い。
  addedNodesを見る or mutationRecordsは無視して監視対象のコンテナからquerySelector、するのがよさそう。
*/
((target, proc) =&amp;gt; (new MutationObserver(m =&amp;gt; m.forEach(r =&amp;gt; proc(r.addedNodes))).observe(target, { childList: 1, subtree: 1　}), proc([target])))(
  document.querySelector('.columns-area'),
  nodes =&amp;gt; {
    Array.from(nodes)
      .filter(n =&amp;gt; n.nodeType === Node.ELEMENT_NODE)
      .reduce((p, c) =&amp;gt; p.concat(Array.from(c.querySelectorAll('.status__content'))), [])
      .forEach(n =&amp;gt; {
        // open CW
        if (n.lastElementChild.matches('.status__content__text:not(.status__content__text--visible'))
          n.querySelector('.status__content__spoiler-link span').click();
        
        // open media spoiler
        // (n.closest('.status').querySelector('.media-spoiler')||{click(){}}).click();
      });
  });

/* でも前のがES2016活用(?)していておもしろかったので残しとく

((target, proc) =&amp;gt; (new MutationObserver(m=&amp;gt;m.forEach(proc)).observe(target, {childList:1, subtree:1}), proc({target})))(
    document.querySelector('.columns-area'),
    ({target}) =&amp;gt; {
        // open CW
        $(target).find('.status__content:has(&amp;gt; :nth-child(3)) .status__content__spoiler-link span').click();
        // open media spoiler
        // $(target).find('.media-spoiler').click();
    });

*/&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHVrPWvl-hw">
    <link>https://let.hatelabo.jp/unarist/let/hLHVrPWvl-hw</link>
    <dc:date>2018-08-23T15:23:20Z</dc:date>
    <description>翻訳してしまっている場合でも原文からコピーしてきて修復</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] MDN - Restore heading ids</title>
    <content:encoded>&lt;a href="javascript:%28%28%29%3D%3E%7Bconst%20execAll%3Dfunction%2A%28re%2Cstr%2Cm%3Dnull%29%7Bwhile%28%28m%3Dre.exec%28str%29%29%21%3D%3Dnull%29yield%20m%7D%3Bconst%20src_str%3Ddocument.querySelector%28%27.translate-source%20%3E%20textarea%27%29.textContent%3Bconst%20editor%3DCKEDITOR.instances%5BObject.keys%28CKEDITOR.instances%29%5B0%5D%5D%3Bconst%20dest_str%3Deditor.getData%28%29%3Bconst%20heading_re%3D%2F%3Ch%28%5Cd%29%20%28%5B%5E%20%3E%5D%2A%20%2B%29%3Fid%3D%22%28%5B%5E%22%5D%2B%29%22%28%3F%3A%20name%3D%22%5B%5E%22%5D%2B%22%29%3F%3E%2Fg%3Bconst%20untranslated_re%3D%2F%5E%5BA-Za-z0-9_%5C-%E2%80%93%3B%27%5C.%5C%28%5C%29%26%5D%2B%24%2F%3Bconst%20src_headings%3D%5B...execAll%28heading_re%2Csrc_str%29%5D%3Bconst%20dest_headings%3D%5B...execAll%28heading_re%2Cdest_str%29%5D%3Bconst%20isSameHeading%3D%28src%2Cdest%29%3D%3Esrc%5B1%5D%3D%3D%3Ddest%5B1%5D%26%26%28%21untranslated_re.test%28dest%5B3%5D%29%7C%7Csrc%5B3%5D%3D%3D%3Ddest%5B3%5D%29%3Bif%28src_headings.length%21%3D%3Ddest_headings.length%7C%7Csrc_headings.some%28%28%28src%2Ci%29%3D%3E%21isSameHeading%28src%2Cdest_headings%5Bi%5D%29%29%29%29%7Balert%28%27%E8%A6%8B%E5%87%BA%E3%81%97%E3%81%AE%E6%A7%8B%E9%80%A0%E3%81%8C%E4%B8%80%E8%87%B4%E3%81%97%E3%81%AA%E3%81%84%E3%81%9F%E3%82%81%E4%B8%AD%E6%AD%A2%E3%81%97%E3%81%BE%E3%81%99%E3%80%82%27%29%3Breturn%7Dif%28src_headings.every%28%28%28src%2Ci%29%3D%3Esrc%5B3%5D%3D%3D%3Ddest_headings%5Bi%5D%5B3%5D%29%29%29%7Balert%28%27%E5%85%A8%E3%81%A6%E3%81%AE%E8%A6%8B%E5%87%BA%E3%81%97%E3%81%A7%E5%8E%9F%E6%96%87%E3%81%A8%E5%90%8C%E3%81%98id%E3%81%8C%E6%8C%87%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82%5Cn%E4%BF%AE%E6%AD%A3%E3%81%AE%E5%BF%85%E8%A6%81%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82%27%29%3Breturn%7Dlet%20i%3D0%3Bconst%20out_str%3Ddest_str.replace%28heading_re%2C%28%28src%2Clv%2Cother%2Cid%29%3D%3E%7Bconst%20orig_heading%3Dsrc_headings%5Bi%2B%2B%5D%5B3%5D%3Bconsole.log%28id%2B%27%20-%3E%20%27%2Borig_heading%29%3Breturn%60%27%3Ch%24%7Blv%7D%20%24%7Bother%7C%7C%27%27%7Did%3D%22%24%7Borig_heading%7D%22%20name%3D%22%24%7Borig_heading%7D%22%3E%27%60.slice%281%2C-1%29%7D%29%29%3Beditor.setData%28out_str%29%3Balert%28%27%E8%A6%8B%E5%87%BA%E3%81%97%E3%81%AEid%2Fname%E5%B1%9E%E6%80%A7%E3%82%92%E4%BF%AE%E6%AD%A3%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82%5Cn%E8%A9%B3%E7%B4%B0%E3%81%AF%E3%82%B3%E3%83%B3%E3%82%BD%E3%83%BC%E3%83%AB%E3%82%92%E7%A2%BA%E8%AA%8D%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%82%27%29%7D%29%28%29%3B"&gt;MDN - Restore heading ids&lt;/a&gt;&lt;pre&gt;/*
 * @title MDN - Restore heading ids
 * @description 翻訳してしまっている場合でも原文からコピーしてきて修復
 * @include https://developer.mozilla.org/ja/docs/*
 * @license MIT License
 * @javascript_url
 */

// MDNの記事でheadingタグのidはtextContentから自動生成されているが、
// 日本語版では見出しそのものは翻訳しつつもidは変えたくないのでname属性を足す
// （name属性をつけておけばそっちがid属性にも反映される仕様）
// c.f. https://github.com/mozilla-japan/translation/blob/master/MDN/TranslationHelper.user.js

// で、見出しタグの数と並びがあっていれば一対一で対応する、と雑な処理をしてみるテスト。

(() =&amp;gt; {
  const execAll = function*(re, str, m = null) { while ((m = re.exec(str)) !== null) yield m; };
  const src_str = document.querySelector('.translate-source &amp;gt; textarea').textContent;
  const editor = CKEDITOR.instances[Object.keys(CKEDITOR.instances)[0]];
  const dest_str = editor.getData();

  const heading_re = /&amp;lt;h(\d) ([^ &amp;gt;]* +)?id=&amp;quot;([^&amp;quot;]+)&amp;quot;(?: name=&amp;quot;[^&amp;quot;]+&amp;quot;)?&amp;gt;/g;
  const untranslated_re = /^[A-Za-z0-9_\-–;'\.\(\)&amp;amp;]+$/;
  const src_headings = [...execAll(heading_re, src_str)];
  const dest_headings = [...execAll(heading_re, dest_str)];

  const isSameHeading = (src, dest) =&amp;gt; src[1] === dest[1] &amp;amp;&amp;amp; (!untranslated_re.test(dest[3]) || src[3] === dest[3]);

  if (src_headings.length !== dest_headings.length ||
      src_headings.some((src, i) =&amp;gt; !isSameHeading(src, dest_headings[i]))) {
    alert('見出しの構造が一致しないため中止します。');
    return;
  }
  if (src_headings.every((src, i) =&amp;gt; src[3] === dest_headings[i][3])) {
    alert('全ての見出しで原文と同じidが指定されています。\n修正の必要はありません。');
    return;
  }

  let i = 0;
  const out_str = dest_str.replace(heading_re, (src, lv, other, id) =&amp;gt; {
    const orig_heading = src_headings[i++][3];
    console.log(id + ' -&amp;gt; ' + orig_heading);
    // `'...'`.slice(1, -1) はHatena::Letのpacker対策
    return `'&amp;lt;h${lv} ${other || ''}id=&amp;quot;${orig_heading}&amp;quot; name=&amp;quot;${orig_heading}&amp;quot;&amp;gt;'`.slice(1, -1);
  });

  editor.setData(out_str);
  alert('見出しのid/name属性を修正しました。\n詳細はコンソールを確認してください。');
})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHUr_HeiJB3">
    <link>https://let.hatelabo.jp/unarist/let/hLHUr_HeiJB3</link>
    <dc:date>2018-06-07T10:04:14Z</dc:date>
    <description>eh, too wide paragraphs... :/</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Set &lt;body&gt; max-width</title>
    <content:encoded>&lt;a href="javascript:%28function%28%29%7BObject.assign%28document.body.style%2C%7BmaxWidth%3Aprompt%28%27body%20width%27%2C%2722cm%27%29%2B%27%21important%27%2CmarginLeft%3A%27auto%20%21important%27%2CmarginRight%3A%27auto%20%21important%27%7D%29%3Bif%28confirm%28%27darken%20background%20%28and%20etc.%29%3F%27%29%29%7BObject.assign%28document.documentElement.style%2C%7Bbackground%3A%27%23555%27%7D%29%3BObject.assign%28document.body.style%2C%7Bbackground%3A%27%23fafafa%27%2Ccolor%3A%27%23333%27%2Cpadding%3A%271em%203em%27%7D%29%7D%7D%29%28%29%3B"&gt;Set &amp;lt;body&amp;gt; max-width&lt;/a&gt;&lt;pre&gt;/*
 * @title Set &amp;lt;body&amp;gt; max-width
 * @description eh, too wide paragraphs... :/
 * @include *
 * @license MIT License
 * @javascript_url 
 */

(function(){
  Object.assign(document.body.style, {
    maxWidth: prompt('body width', '22cm') + '!important',
    marginLeft: 'auto !important',
    marginRight: 'auto !important'
  });
  if (confirm('darken background (and etc.)?')) {
    Object.assign(document.documentElement.style, {
      background: '#555'
    });
    Object.assign(document.body.style, {
      background: '#fafafa',
      color: '#333',
      padding: '1em 3em'
    });
  }
})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJmcxa3yjMtI">
    <link>https://let.hatelabo.jp/unarist/let/hJmcxa3yjMtI</link>
    <dc:date>2018-04-14T06:56:50Z</dc:date>
    <description>動くといいね。masterではもう動かないよ。</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] :don: - TLジャンプしようとしてたやつ</title>
    <content:encoded>&lt;a href="javascript:%28%28%29%3D%3E%7Bconst%20store%3D%28%28%29%3D%3E%7Blet%20current_node%3Ddocument.querySelector%28%27%23mastodon%27%29._reactRootContainer.current.child%3Bwhile%28%27function%27%3D%3D%3Dtypeof%20current_node.type%29%7Bconst%20store%3Dcurrent_node.memoizedProps.store%3Bif%28store%29return%20store%3Bcurrent_node%3Dcurrent_node.child%7D%7D%29%28%29%3Bconst%20target%3D%28%28%29%3D%3E%7Bconst%20path_segments%3Dlocation.pathname.split%28%27%2F%27%29.slice%282%29%3Bif%28path_segments%5B0%5D%3D%3D%3D%27accounts%27%29%7Bconst%5B%2Cid%2Ctype%5D%3Dpath_segments%3Bconst%20build%3D%28label%3D%27%27%2Cappend_key%3D%27%27%2Cappend_path%3D%27%27%29%3D%3E%28%7Blabel%3Alabel%7C%7C%60account%20timeline%60%2Ckey%3A%60account%3A%24%7Bid%7D%24%7Bappend_key%7D%60%2Cpath%3A%60accounts%2F%24%7Bid%7D%2Fstatuses%24%7Bappend_path%7D%60%7D%29%3Bswitch%28type%29%7Bcase%27media%27%3Areturn%20build%28%27account%20media%20timeline%27%2C%27%3Amedia%27%2C%27%3Fonly_media%3Dtrue%27%29%3Bcase%27with_replies%27%3Areturn%20build%28%27account%20timeline%20%28w%2F%20replies%29%27%2C%27%3Awith_replies%27%2C%27%3Fexclude_replies%3Dfalse%27%29%3Bdefault%3Areturn%20build%28%27account%20timeline%27%2C%27%27%2C%27%3Fexclude_replies%3Dtrue%27%29%7D%7Delse%20if%28path_segments%5B0%5D%3D%3D%3D%27timelines%27%29%7Bconst%5B%2Ctype%2Cid%5D%3Dpath_segments%3Bswitch%28type%29%7Bcase%27local%27%3Areturn%7Blabel%3A%27local%27%2Ckey%3A%27community%27%2Cpath%3A%27timelines%2Fpublic%3Flocal%3Dtrue%27%7D%3Bcase%27public%27%3Areturn%7Blabel%3A%27federated%27%2Ckey%3A%27public%27%2Cpath%3A%27timelines%2Fpublic%27%7D%3Bcase%27tag%27%3Areturn%7Blabel%3A%60%23%24%7Bid%7D%60%2Ckey%3A%60hashtag%3A%24%7Bid%7D%60%2Cpath%3A%27timelines%2Ftag%2F%24%7Bid%7D%27%7D%7D%7Dif%28document.querySelector%28%27.fa-users.column-header__icon%27%29%29%7Breturn%7Blabel%3A%27local%27%2Ckey%3A%27community%27%2Cpath%3A%27timelines%2Fpublic%3Flocal%3Dtrue%27%7D%7D%7D%29%28%29%3Bif%28%21target%29%7Balert%28%27No%20supported%20timeline%20detected.%5CnThis%20script%20finds%3A%5Cn-%20account%2Flocal%20timeline%20on%20right-most%20column%5Cn-%20pinned%20local%20timeline%27%29%3Breturn%7Dconst%20query%3Dprompt%28%60Load%20statuses%20to%20%24%7Btarget.label%7D%20timeline.%5Cn%5CnEnter%20%3Cmax_id%3E%20%7C%20%5B%5Byyyy%2F%5Dmm%2Fdd%20%5Dhh%3Amm%5Cnor%20leave%20empty%20to%20load%20latest%20timeline.%60%29%3Bif%28query%3D%3D%3Dnull%29return%3Bconst%20parseDateQuery%3Ds%3D%3E%7Bconst%20now_array%3D%28%28d%3Dnew%20Date%29%3D%3E%5B0%2Cd.getFullYear%28%29%2Cd.getMonth%28%29%2B1%2Cd.getDate%28%29%2Cd.getHours%28%29%2Cd.getMinutes%28%29%5D%29%28%29%3Bconst%20query_date%3D%28s.match%28%2F%28%3F%3A%28%3F%3A%28%5Cd%7B4%7D%29%5CD%2B%29%3F%28%5Cd%2B%29%5CD%2B%28%5Cd%2B%29%5CD%2B%29%3F%28%5Cd%2B%29%3A%28%5Cd%2B%29%2F%29%7C%7C%5B%5D%29.map%28%28%28e%2Ci%29%3D%3Ee%7C%7Cnow_array%5Bi%5D%29%29%3Breturn%20query_date.length%26%26new%20Date%28query_date%5B1%5D%2Cquery_date%5B2%5D-1%2Cquery_date%5B3%5D%2Cquery_date%5B4%5D%2Cquery_date%5B5%5D%2C0%29.getTime%28%29%2A2%2A%2A16%7D%3Bconst%20parseMaxIdQuery%3Ds%3D%3E%28s.match%28%2F%5E%5Cd%2B%24%2F%29%7C%7C%7B%7D%29%5B0%5D%3Bconst%20max_id%3DparseDateQuery%28query%29%7C%7CparseMaxIdQuery%28query%29%3Bif%28%21max_id%29%7Balert%28%27Invalid%20query%3A%20%27%2Bquery%29%3Breturn%7Dconsole.log%28target%29%3Bfetch%28%60%2Fapi%2Fv1%2F%24%7Btarget.path%7D%24%7Btarget.path.includes%28%27%3F%27%29%3F%27%26%27%3A%27%3F%27%7Dlimit%3D40%60%2B%28max_id%3F%60%26max_id%3D%24%7Bmax_id%7D%60%3A%27%27%29%2C%7Bheaders%3A%7BAuthorization%3A%27Bearer%20%27%2Bstore.getState%28%29.getIn%28%5B%27meta%27%2C%27access_token%27%5D%29%7D%7D%29.then%28%28x%3D%3Ex.json%28%29%29%29.then%28%28statuses%3D%3E%7Bconst%20scrollTop%3Dstore.getState%28%29.getIn%28%5B%27timelines%27%2Ctarget.key%2C%27top%27%5D%29%3Bstore.dispatch%28%7Btype%3A%27TIMELINE_SCROLL_TOP%27%2Ctimeline%3Atarget.key%2Ctop%3Atrue%7D%29%3Bstore.dispatch%28%7Btype%3A%27TIMELINE_REFRESH_SUCCESS%27%2Ctimeline%3Atarget.key%2Cstatuses%3Astatuses.slice%281%29%2Cpartial%3Afalse%7D%29%3Bstore.dispatch%28%7Btype%3A%27TIMELINE_UPDATE%27%2Ctimeline%3Atarget.key%2Cstatus%3Astatuses%5B0%5D%2Creferences%3A%5B%5D%7D%29%3Bstore.dispatch%28%7Btype%3A%27TIMELINE_SCROLL_TOP%27%2Ctimeline%3Atarget.key%2Ctop%3AscrollTop%7D%29%7D%29%29%7D%29%28%29%3B"&gt;:don: - TLジャンプしようとしてたやつ&lt;/a&gt;&lt;pre&gt;/*
 * @title :don: - TLジャンプしようとしてたやつ
 * @description 動くといいね。masterではもう動かないよ。
 * @include http://*
 * @license MIT License
 * @javascript_url
 */

// BUG: TIMELINE_REFRESH_SUCCESS always *concat* to cached timeline...

(() =&amp;gt; {
  const store = (() =&amp;gt; {
    // &amp;gt;= v16: to descendant
    let current_node = document.querySelector('#mastodon')._reactRootContainer.current.child;
    while ('function' === typeof current_node.type) {
      const store = current_node.memoizedProps.store;
      if (store) return store;
      current_node = current_node.child;
    }
  })();
  
  const target = (() =&amp;gt; {
    // path match
    const path_segments = location.pathname.split('/').slice(2);
    if (path_segments[0] === 'accounts') {
      const [, id, type] = path_segments;
      const build = (label = '', append_key = '', append_path = '') =&amp;gt;
        ({ label: label || `account timeline`, key: `account:${id}${append_key}`, path: `accounts/${id}/statuses${append_path}` });
      switch (type) {
        case 'media': return build('account media timeline', ':media', '?only_media=true');
        case 'with_replies': return build('account timeline (w/ replies)', ':with_replies', '?exclude_replies=false');
        default: return build('account timeline', '', '?exclude_replies=true');
      }
    } else if (path_segments[0] === 'timelines') {
      const [, type, id] = path_segments;
      switch (type) {
        case 'local': return { label: 'local', key: 'community', path: 'timelines/public?local=true'};
        case 'public': return { label: 'federated', key: 'public', path: 'timelines/public'};
        case 'tag': return { label: `#${id}`, key: `hashtag:${id}`, path: 'timelines/tag/${id}'};
      }
    }
    // use pinned columns
    if (document.querySelector('.fa-users.column-header__icon')) {
      return { label: 'local', key: 'community', path: 'timelines/public?local=true'};
    }
  })();
  
  if (!target) {
    alert('No supported timeline detected.\nThis script finds:\n- account/local timeline on right-most column\n- pinned local timeline');
    return;
  }
  
  const query = prompt(`Load statuses to ${target.label} timeline.\n\nEnter &amp;lt;max_id&amp;gt; | [[yyyy/]mm/dd ]hh:mm\nor leave empty to load latest timeline.`);
  if (query === null) return;
  
  const parseDateQuery = s =&amp;gt; {
    const now_array = ((d = new Date()) =&amp;gt; [0, d.getFullYear(), d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes()])();
    const query_date = (s.match(/(?:(?:(\d{4})\D+)?(\d+)\D+(\d+)\D+)?(\d+):(\d+)/)||[]).map((e, i) =&amp;gt; e || now_array[i]);
    return query_date.length &amp;amp;&amp;amp; new Date(query_date[1], query_date[2] - 1, query_date[3], query_date[4], query_date[5], 0).getTime() * 2 ** 16;
  }
  const parseMaxIdQuery = s =&amp;gt; (s.match(/^\d+$/) || {})[0];
  
  const max_id = parseDateQuery(query) || parseMaxIdQuery(query);
  
  if (!max_id) {
    alert('Invalid query: ' + query);
    return;
  }
  console.log(target);
  

 fetch(`/api/v1/${target.path}${target.path.includes('?') ? '&amp;amp;' : '?'}limit=40` + (max_id ? `&amp;amp;max_id=${max_id}` : ''),
      { headers: {Authorization: 'Bearer ' + store.getState().getIn(['meta', 'access_token'])}})
 .then(x =&amp;gt; x.json())
 .then(statuses =&amp;gt; {
   // TIMELINE_UPDATE trims timeline if the timeline has 40 statuses already
   const scrollTop = store.getState().getIn(['timelines', target.key, 'top']);
   store.dispatch({
     type: 'TIMELINE_SCROLL_TOP',
     timeline: target.key,
     top: true
   });
   store.dispatch({
    type: 'TIMELINE_REFRESH_SUCCESS',
    timeline: target.key,
    statuses: statuses.slice(1),
    partial: false
   });
   store.dispatch({
     type: 'TIMELINE_UPDATE',
     timeline: target.key,
     status: statuses[0],
     references: []
   });
   store.dispatch({
     type: 'TIMELINE_SCROLL_TOP',
     timeline: target.key,
     top: scrollTop
   });
 });
})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHUxenf0KpN">
    <link>https://let.hatelabo.jp/unarist/let/hLHUxenf0KpN</link>
    <dc:date>2018-03-16T11:39:55Z</dc:date>
    <description></description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] ピクトセンスで入力欄の補完を切る</title>
    <content:encoded>&lt;a href="javascript:void%28document.getElementById%28%27chatText%27%29.autocomplete%3D%22off%22%29%3B"&gt;ピクトセンスで入力欄の補完を切る&lt;/a&gt;&lt;pre&gt;/*
 * @title ピクトセンスで入力欄の補完を切る
 * @description 
 * @include http://pictsense.com/*
 * @license MIT License
 * @javascript_url
 */

void(document.getElementById('chatText').autocomplete = &amp;quot;off&amp;quot;);&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHUo4by_bpo">
    <link>https://let.hatelabo.jp/unarist/let/hLHUo4by_bpo</link>
    <dc:date>2018-01-21T11:17:09Z</dc:date>
    <description>outputs to console.log</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] List up IDs/classes used in stylesheets</title>
    <content:encoded>&lt;a href="javascript:console.log%28%5B...new%20Set%28%5B...document.styleSheets%5D.reduce%28%28%28m%2Cs%29%3D%3E%7Btry%7Breturn%20Array.prototype.concat.apply%28m%2C%5B...s.cssRules%5D.map%28%28r%3D%3E%28r.selectorText%7C%7C%27%27%29.match%28%2F%5B%23%5C.%5D%5B-_a-z%5D%2B%2Fgi%29%29%29%29%7Dcatch%28x%29%7Breturn%20m.concat%28%27--%20cannot%20read%20cssRules%20for%20%27%2Bs.href%29%7D%7D%29%2C%5B%5D%29%29%5D.filter%28%28x%3D%3Ex%26%26%21x.startsWith%28%27.fa-%27%29%29%29.sort%28%29.join%28%27%5Cn%27%29%29%3B"&gt;List up IDs/classes used in stylesheets&lt;/a&gt;&lt;pre&gt;// @title List up IDs/classes used in stylesheets
// @description outputs to console.log
// @license MIT License
// @javascript_url https://opensource.org/licenses/MIT

console.log(
  [...new Set(
    [...document.styleSheets]
    .reduce((m,s) =&amp;gt; {
      try{
        return Array.prototype.concat.apply(m, [...s.cssRules].map(r =&amp;gt; (r.selectorText || '').match(/[#\.][-_a-z]+/gi)));
      } catch(x) {
        // &amp;gt; In some browsers, if a stylesheet is loaded from a different domain, calling cssRules results in SecurityError.
        // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet#Notes
        return m.concat('-- cannot read cssRules for ' + s.href);
      }
    }, []))
  ]
  .filter(x=&amp;gt;x &amp;amp;&amp;amp; !x.startsWith('.fa-')) /* fontawesome */
  .sort()
  .join('\n')
);&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJmf2ODn7pR1">
    <link>https://let.hatelabo.jp/unarist/let/hJmf2ODn7pR1</link>
    <dc:date>2017-09-28T01:14:53Z</dc:date>
    <description>ツイート中の3文字以上の英字列をnumeronymに変換します。</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Twitter - n7m</title>
    <content:encoded>&lt;a href="javascript:%28%28target%2Cp%29%3D%3E%28new%20MutationObserver%28%28m%3D%3Em.forEach%28%28r%3D%3Ep%28r.addedNodes%29%29%29%29%29.observe%28target%2C%7BchildList%3A1%2Csubtree%3A1%7D%29%2Cp%28%5Btarget%5D%29%29%29%28document.querySelector%28%27.stream-items%27%29%2C%28ns%3D%3EArray.from%28ns%29.reduce%28%28%28p%2Cc%29%3D%3Ep.concat%28c.querySelectorAll%3FArray.from%28c.querySelectorAll%28%27.tweet-text%27%29%29%3A%5B%5D%29%29%2C%5B%5D%29.forEach%28%28e%3D%3EArray.from%28e.childNodes%2C%28n%3D%3En.nodeType%3D%3D%3DNode.TEXT_NODE%26%26%28n.textContent%3Dn.textContent.replace%28%2F%5Ba-z%5D%7B4%2C%7D%2Fgi%2C%28s%3D%3E%60%24%7Bs%5B0%5D%7D%24%7Bs.length-2%7D%24%7Bs%5Bs.length-1%5D%7D%60%29%29%29%29%29%29%29%29%29%3B"&gt;Twitter - n7m&lt;/a&gt;&lt;pre&gt;// @title Twitter - n7m
// @description ツイート中の3文字以上の英字列をnumeronymに変換します。
// @include https://twitter.com/*
// @license MIT License
// @javascript_url

// https://github.com/timrwood/n7m
// for Mastodon http://let.hatelabo.jp/unarist/let/hLHXhPGQ34I6

((target, p) =&amp;gt; (new MutationObserver(m =&amp;gt; m.forEach(r =&amp;gt; p(r.addedNodes))).observe(target, {childList: 1, subtree: 1}), p([target])))(
  document.querySelector('.stream-items'),
  ns=&amp;gt;
  Array.from(ns)
  .reduce((p, c) =&amp;gt; p.concat(c.querySelectorAll ? Array.from(c.querySelectorAll('.tweet-text')) : []), [])
  .forEach(e=&amp;gt;
    Array.from(e.childNodes, n=&amp;gt; n.nodeType === Node.TEXT_NODE &amp;amp;&amp;amp; (n.textContent= n.textContent.replace(/[a-z]{4,}/gi, s =&amp;gt; `${s[0]}${s.length-2}${s[s.length-1]}`))))
);&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHXhPGQ34I6">
    <link>https://let.hatelabo.jp/unarist/let/hLHXhPGQ34I6</link>
    <dc:date>2017-09-28T01:02:12Z</dc:date>
    <description>トゥート中の3文字以上の英字列をnumeronymに変換します。</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Mastodon - n7m</title>
    <content:encoded>&lt;a href="javascript:%28%28target%2Cp%29%3D%3E%28new%20MutationObserver%28%28m%3D%3Em.forEach%28%28r%3D%3Ep%28r.addedNodes%29%29%29%29%29.observe%28target%2C%7BchildList%3A1%2Csubtree%3A1%7D%29%2Cp%28%5Btarget%5D%29%29%29%28document.querySelector%28%27.columns-area%27%29%2C%28ns%3D%3EArray.from%28ns%29.reduce%28%28%28p%2Cc%29%3D%3Ep.concat%28c.querySelectorAll%3FArray.from%28c.querySelectorAll%28%27.status__content%2C%20.status__content%20p%2C%20p%3Espan%27%29%29%3A%5B%5D%29%29%2C%5B%5D%29.forEach%28%28e%3D%3EArray.from%28e.childNodes%2C%28n%3D%3En.nodeType%3D%3D%3DNode.TEXT_NODE%26%26%28n.textContent%3Dn.textContent.replace%28%2F%5Ba-z%5D%7B4%2C%7D%2Fgi%2C%28s%3D%3E%60%24%7Bs%5B0%5D%7D%24%7Bs.length-2%7D%24%7Bs%5Bs.length-1%5D%7D%60%29%29%29%29%29%29%29%29%29%3B"&gt;Mastodon - n7m&lt;/a&gt;&lt;pre&gt;// @title Mastodon - n7m
// @description トゥート中の3文字以上の英字列をnumeronymに変換します。
// @include https://*/web/*
// @license MIT License
// @javascript_url

// https://github.com/timrwood/n7m

((target, p) =&amp;gt; (new MutationObserver(m =&amp;gt; m.forEach(r =&amp;gt; p(r.addedNodes))).observe(target, {childList: 1, subtree: 1}), p([target])))(
  document.querySelector('.columns-area'),
  ns=&amp;gt;
  Array.from(ns)
  .reduce((p, c) =&amp;gt; p.concat(c.querySelectorAll ? Array.from(c.querySelectorAll('.status__content, .status__content p, p&amp;gt;span')) : []), [])
  .forEach(e=&amp;gt;
    Array.from(e.childNodes, n=&amp;gt; n.nodeType === Node.TEXT_NODE &amp;amp;&amp;amp; (n.textContent= n.textContent.replace(/[a-z]{4,}/gi, s =&amp;gt; `${s[0]}${s.length-2}${s[s.length-1]}`))))
);&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJmfvMai6uQe">
    <link>https://let.hatelabo.jp/unarist/let/hJmfvMai6uQe</link>
    <dc:date>2017-08-15T05:36:08Z</dc:date>
    <description>個人的な好みで前後に : が入ってます</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] gemojiのemoji.jsonをSKK辞書に変換する</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2Funarist%2Flet%2FhJmfvMai6uQe.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;gemojiのemoji.jsonをSKK辞書に変換する&lt;/a&gt;&lt;pre&gt;/*
 * @title gemojiのemoji.jsonをSKK辞書に変換する
 * @description 個人的な好みで前後に : が入ってます
 * @include https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json
 * @license MIT License
 */

// 使用例: https://gist.github.com/unarist/95575f50dcaaf6c95a361acd4c342681

// スペースが消えないように \x20 で代用
[].concat(
  ...JSON.parse(document.querySelector('pre').textContent)
  .filter(({emoji}) =&amp;gt; emoji) // Unicode表現のないやつは除外
  .map(({emoji, aliases}) =&amp;gt; aliases.map(alias =&amp;gt; `:${alias}:\x20/${emoji}/`))
).sort().join('\n');&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHWv4uKv-of">
    <link>https://let.hatelabo.jp/unarist/let/hLHWv4uKv-of</link>
    <dc:date>2017-05-28T00:24:34Z</dc:date>
    <description>charsetの指定がアレなサイトをMobileSafariで見たい時に</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] 現在のドキュメントを文字コード自動判定で読み直す</title>
    <content:encoded>&lt;a href="javascript:%28window.length%3FArray.from%28window%29%3A%5Bwindow%5D%29.forEach%28%28function%28w%29%7Bconst%20xhr%3Dnew%20XMLHttpRequest%3Bxhr.open%28%22GET%22%2Cw.location.href%29%3Bxhr.responseType%3D%22blob%22%3Bxhr.onload%3Dfunction%28%29%7Bconst%20reader%3Dnew%20FileReader%3Breader.onload%3Dfunction%28%29%7Bconst%20enc%3Dfunction%28bytes%29%7Bvar%20cnt%3D0%3Bfor%28var%20i%3D0%3Bi%3Cbytes.length-1%26%26cnt%3C50%3B%2B%2Bi%29%7Bconst%20b%3Dbytes%5Bi%5D%3Bif%28b%3D%3D27%29return%22iso-2022-jp%22%3Bif%28b%3C129%29continue%3B%2B%2Bcnt%3Bif%28b%3C160%29%7Bif%28%28b%3D%3D142%7C%7Cb%3D%3D143%29%26%26bytes%5Bi%2B1%5D%3E%3D161%29%7B%2B%2Bi%7Delse%7Breturn%22shift-jis%22%7D%7Delse%20if%28b%3E%3D224%29%7B%2B%2Bi%7D%7Dreturn%22euc-jp%22%7D%28new%20Uint8Array%28reader.result%29%29%3Breader.onload%3Dfunction%28%29%7Bw.document.documentElement.innerHTML%3Dreader.result%7D%3Breader.readAsText%28xhr.response%2Cenc%29%7D%3Breader.readAsArrayBuffer%28xhr.response%29%7D%3Bxhr.send%28%29%7D%29%29%3B"&gt;現在のドキュメントを文字コード自動判定で読み直す&lt;/a&gt;&lt;pre&gt;/*
 * @title 現在のドキュメントを文字コード自動判定で読み直す
 * @description charsetの指定がアレなサイトをMobileSafariで見たい時に
 * @include http://*
 * @license MIT License
 * @javascript_url
 */

// === History ===
// 17-05-28: フレーム対応(えっ

(window.length ? Array.from(window) : [window])
.forEach(function(w){
const xhr = new XMLHttpRequest();
xhr.open(&amp;quot;GET&amp;quot;, w.location.href);
xhr.responseType = &amp;quot;blob&amp;quot;;
xhr.onload = function() {
  const reader = new FileReader();
  reader.onload = function() {
    
    // 簡易文字コード検出(このbookmarkletの用途的にUTF-8は考慮してない)
    // http://unarist.hatenablog.com/entry/2017/02/28/205401
    const enc = (function(bytes) {
      // let-&amp;gt;var はiOS9対策
      /*let*/var cnt = 0;
      for (/*let*/var i = 0; i &amp;lt; bytes.length - 1 &amp;amp;&amp;amp; cnt &amp;lt; 50; ++i) {
        const b = bytes[i];
        
        if (b == 0x1B) return &amp;quot;iso-2022-jp&amp;quot;;
        if (b &amp;lt; 0x81) continue;
        
        ++cnt;
        if (b &amp;lt; 0xA0) {
          if ((b == 0x8E || b == 0x8F) &amp;amp;&amp;amp; bytes[i + 1] &amp;gt;= 0xA1) {
            ++i;
          } else {
            return &amp;quot;shift-jis&amp;quot;;
          }
        } else if (b &amp;gt;= 0xE0) {
          ++i;
        }
      }
      return &amp;quot;euc-jp&amp;quot;;
    })(new Uint8Array(reader.result));
    
    // TextDecoder使いたいですね... http://caniuse.com/#feat=textencoder
    reader.onload = function() {
      // document.writeだと(iOS9のSafariでは)タイトルが更新されなかった
      w.document.documentElement.innerHTML = reader.result;
    };
    reader.readAsText(xhr.response, enc);
  };
  reader.readAsArrayBuffer(xhr.response);
};
xhr.send();
})&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJme8ZD-2_Z7">
    <link>https://let.hatelabo.jp/unarist/let/hJme8ZD-2_Z7</link>
    <dc:date>2017-05-21T02:15:26Z</dc:date>
    <description>ログインした状態で実行してね</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Mastodonのチュートリアル既読フラグをリセットするやつ</title>
    <content:encoded>&lt;a href="javascript:%28function%28%29%7Bvar%20settings%3DJSON.parse%28document.querySelector%28%27%23initial-state%27%29.textContent%29.settings%3Bsettings.onboarded%3Dfalse%3Bfetch%28%27%2Fapi%2Fweb%2Fsettings%27%2C%7Bmethod%3A%27put%27%2Cheaders%3A%7B%27Content-Type%27%3A%27application%2Fjson%27%7D%2Cbody%3AJSON.stringify%28settings%29%2Ccredentials%3A%27same-origin%27%7D%29.then%28%28%28%29%3D%3Ealert%28%27%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E6%97%A2%E8%AA%AD%E3%83%95%E3%83%A9%E3%82%B0%E3%82%92%E3%83%AA%E3%82%BB%E3%83%83%E3%83%88%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82%E3%83%9A%E3%83%BC%E3%82%B8%E3%82%92%E5%86%8D%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF%E3%81%97%E3%81%A6%E3%81%AD%E3%80%82%27%29%29%29%7D%29%28%29%3B"&gt;Mastodonのチュートリアル既読フラグをリセットするやつ&lt;/a&gt;&lt;pre&gt;/*
 * @title Mastodonのチュートリアル既読フラグをリセットするやつ
 * @description ログインした状態で実行してね
 * @license MIT License
 * @javascript_url
 */

// iOS9対応するならXHRに書き直さないとだけど...。

(function(){
  var settings = JSON.parse(document.querySelector('#initial-state').textContent).settings;
  settings.onboarded = false;
  
  fetch('/api/web/settings',{
    method:'put',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(settings),
    credentials: 'same-origin'
  })
  .then(() =&amp;gt; alert('チュートリアル既読フラグをリセットしました。ページを再読み込みしてね。'));
})()&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hLHW_4WUwZoq">
    <link>https://let.hatelabo.jp/unarist/let/hLHW_4WUwZoq</link>
    <dc:date>2017-05-11T16:29:31Z</dc:date>
    <description>適当</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Mastodon - 読み上げ</title>
    <content:encoded>&lt;a href="javascript:%28function%20sayNext%28%7Btarget%3Ac%7D%2Ctarget%3Dnew%20SpeechSynthesisUtterance%28%28%28document.querySelector%28%27.mastodon-column-container%5Baria-hidden%3D%22false%22%5D%20.status__content%27%29%7C%7C%7B%7D%29.textContent%7C%7C%22%22%29.replace%28%2F%28http%7C%23%29%5B%5E%5Cs%5D%2B%2F%2C%27%27%29%29%29%7Bif%28%28c%7C%7C%7B%7D%29.text%21%3Dtarget.text%29setTimeout%28%28%28%29%3D%3EspeechSynthesis.speak%28Object.assign%28target%2C%7Brate%3AMath.max%28Math.pow%28target.text.length%2F50%2C1.3%29%2C2%29%2Conend%3AsayNext%7D%29%29%29%2C0%29%3Belse%20setTimeout%28%28%28%29%3D%3EsayNext%28%7Btarget%3Atarget%7D%29%29%2C500%29%7D%29%28%7B%7D%29%3B"&gt;Mastodon - 読み上げ&lt;/a&gt;&lt;pre&gt;/*
 * @title Mastodon - 読み上げ
 * @description 適当
 * @license MIT License
 * @javascript_url
 */

// BUG: なんか途中で止まることがある（setTimeout経由で呼ぶのもその対策だけど、それでも止まることがある）

(function sayNext({target:c},target=new SpeechSynthesisUtterance(((document.querySelector('.mastodon-column-container[aria-hidden=&amp;quot;false&amp;quot;] .status__content')||{}).textContent||&amp;quot;&amp;quot;).replace(/(http|#)[^\s]+/,''))){if((c||{}).text!=target.text)setTimeout(()=&amp;gt;speechSynthesis.speak(Object.assign(target,{rate:Math.max(Math.pow(target.text.length/50,1.3),2),onend:sayNext})),0);else setTimeout(()=&amp;gt;sayNext({target}),500)})({})&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJme-9yZ3b0r">
    <link>https://let.hatelabo.jp/unarist/let/hJme-9yZ3b0r</link>
    <dc:date>2017-05-06T14:27:36Z</dc:date>
    <description>my bookmarklet</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] javascript_urlの実験</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2Funarist%2Flet%2FhJme-9yZ3b0r.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;javascript_urlの実験&lt;/a&gt;&lt;pre&gt;/*
 * @title javascript_urlの実験
 * @description my bookmarklet
 * @include http://*/web/*
 * @license MIT License
 * @private
 * @javascript_url
 */

void();
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJme9rWRv4gj">
    <link>https://let.hatelabo.jp/unarist/let/hJme9rWRv4gj</link>
    <dc:date>2017-04-28T06:54:20Z</dc:date>
    <description></description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Inject js/css</title>
    <content:encoded>&lt;a href="javascript:%28function%28%29%7Bvar%20url%3Dprompt%28%22Enter%20.js%20or%20.css%20URL%3A%22%29%3Bdocument.head.appendChild%28url.match%28%2F%5C.js%24%2F%29%3FObject.assign%28document.createElement%28%27script%27%29%2C%7Bsrc%3Aurl%7D%29%3AObject.assign%28document.createElement%28%27link%27%29%2C%7Brel%3A%22stylesheet%22%2Csrc%3Aurl%7D%29%29%7D%29%28%29%3B"&gt;Inject js/css&lt;/a&gt;&lt;pre&gt;/*
 * @title Inject js/css
 * @include http://*
 * @license MIT License
 * @javascript_url
 */

(function() {
  var url = prompt(&amp;quot;Enter .js or .css URL:&amp;quot;);
  document.head.appendChild(
    url.match(/\.js$/) ?
    Object.assign(document.createElement('script'), { src: url }) :
    Object.assign(document.createElement('link'), { rel: &amp;quot;stylesheet&amp;quot;, src: url }));
})()&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/unarist/let/hJme7oSg94MD">
    <link>https://let.hatelabo.jp/unarist/let/hJme7oSg94MD</link>
    <dc:date>2017-04-16T02:39:13Z</dc:date>
    <description>割といける。</description>
    <dc:creator>unarist</dc:creator>
    <title>[Let] Base64 デコード（charset判定総当たり版）</title>
    <content:encoded>&lt;a href="javascript:%28%28r%3Dwindow.getSelection%28%29%2Cs%3DString%28r%29%2Cp%3Dr.anchorNode%2Ce%3D%27%27%2Ca%2Ct%29%3D%3E%7Bif%28p.nodeType%3D%3D3%29p%3Dp.parentNode%3Bs%3Datob%28s.replace%28%2F%5E%5B%5Ea-zA-Z0-9%3D%5C%2B%5C%2F%5D%2B%2F%2C%27%27%29.split%28%2F%5B%5Ea-zA-Z0-9%3D%5C%2B%5C%2F%5Cs%5Cr%5Cn%5D%2F%29%5B0%5D.replace%28%2F%5B%5Cs%5Cr%5Cn%5D%2Fg%2C%27%27%29%29%3Bif%28%21p%7C%7C%21s%29return%3Ba%3DUint8Array.from%28s%2C%28c%3D%3Ec.charCodeAt%280%29%29%29%3Bfor%28let%20charset%20of%5B%22iso-2022-jp%22%2C%22euc-jp%22%2C%22utf-8%22%2C%22sjis%22%2C%22utf-16%22%5D%29%7Btry%7Bs%3Dnew%20TextDecoder%28charset%2C%7Bfatal%3Atrue%7D%29.decode%28a%29%3Bbreak%7Dcatch%28e%29%7B%7D%7Dp.appendChild%28Object.assign%28document.createElement%28%27span%27%29%2C%7BtextContent%3As%2Cstyle%3A%27display%3A%20block%3B%20margin%3A%201em%3B%20white-space%3A%20pre-wrap%3B%27%7D%29%29%7D%29%28%29%3B"&gt;Base64 デコード（charset判定総当たり版）&lt;/a&gt;&lt;pre&gt;/*
 * @title Base64 デコード（charset判定総当たり版）
 * @description 割といける。
 * @include *
 * @javascript_url
 */

((r = window.getSelection(), s = String(r), p = r.anchorNode, e = '', a, t) =&amp;gt; {

	if (p.nodeType == 3) p = p.parentNode;
	s = atob(s.replace(/^[^a-zA-Z0-9=\+\/]+/, '').split(/[^a-zA-Z0-9=\+\/\s\r\n]/)[0].replace(/[\s\r\n]/g, ''));
	if (!p || !s) return;

	a = Uint8Array.from(s, c =&amp;gt; c.charCodeAt(0));

	// ダメな例：
	// u8のサロゲートペアがu16として通る
	// u16のサロゲートペアがsjisとして通る
	// sjisがu16として通る
	for (let charset of [&amp;quot;iso-2022-jp&amp;quot;, &amp;quot;euc-jp&amp;quot;, &amp;quot;utf-8&amp;quot;, &amp;quot;sjis&amp;quot;, &amp;quot;utf-16&amp;quot;]) {
		try {
			s = new TextDecoder(charset, {fatal: true}).decode(a);
			break;
		} catch(e){}
	}

	p.appendChild(Object.assign(document.createElement('span'), {
	 textContent: s,
	 style: 'display: block; margin: 1em; white-space: pre-wrap;'
	}));

})();

/*

少なくともfork元で例示されていた、下記ページに載ってるものは全てデコードできた。
http://q.hatena.ne.jp/1289780783
http://d.hatena.ne.jp/kuro-yo/20101115/1289825621
http://yurume.hatenadiary.jp/entry/20101116/QmFzZTY0


テスト用文字列の方は微妙。サロゲートペアが鬼門っぽい？
どこがどう被るのか詳しくは確認してないです。

iso-2022-jp
GyRCJWElbSU5JE83Y0VcJDckPyEjGyhC
GyhJUltdGyRCJE83YyQmJF4kQCRDJD8hIxsoQg==

sjis
g4GDjYNYgs2Mg5N7grWCvYFC
0tvdgs2Mg4KkgtyCvoLBgr2BQg==

euc-jp
peGl7aW5pM+348XcpLekv6Gj
jtKO247dpM+346SmpN6kwKTDpL+how==

utf-8
44Oh44Ot44K544Gv5r+A5oCS44GX44Gf44CC
776S776b776d44Gv5r+A44GG44G+44Gg44Gj44Gf44CC
8J+NiPCfmIvwn5KX

utf-16
4TDtMLkwbzDAbxJgVzBfMAIw
kv+b/53/bzDAb0YwfjBgMGMwXzACMA==
PNhI3z3YC9492Jfc
*/
&lt;/pre&gt;</content:encoded>
  </item>
</rdf:RDF>
