Greasy Fork

Greasy Fork is available in English.

ヤフオクで非表示とメモ

q:非表示 w:アンドゥ b:NGワード Shift+Q:NG編集 12:メモを追加 34:自由メモ 56:定型文をメモ Shift+!:メモを編集 Shift+":自動メモのみ全削除 Shift+#:メモを一時非表示 Shift+56:定型文を設定 .:上限価格 t:半透明モード

当前为 2023-03-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name ヤフオクで非表示とメモ
// @description q:非表示 w:アンドゥ b:NGワード Shift+Q:NG編集 12:メモを追加 34:自由メモ 56:定型文をメモ Shift+!:メモを編集 Shift+":自動メモのみ全削除 Shift+#:メモを一時非表示 Shift+56:定型文を設定 .:上限価格 t:半透明モード
// @match *://auctions.yahoo.co.jp/search/*
// @match *://page.auctions.yahoo.co.jp/jp/auction/*
// @match *://auctions.yahoo.co.jp/seller/*
// @match *://auctions.yahoo.co.jp/category/list/*
// @match *://cpu.userbenchmark.com/*
// @match *://webcomics.jp/*
// @match *://www.amazon.co.jp/*
// @exclude *://www.amazon.co.jp/*/cart/*
// @exclude *://www.amazon.co.jp/*/buy/*
// @exclude *://www.amazon.co.jp/*/huc/*
// @exclude *://www.amazon.co.jp/*/css/*
// @exclude *://www.amazon.co.jp/ap/*
// @exclude *://www.amazon.co.jp/gp/*
// @exclude *://www.amazon.co.jp/auto-deliveries*
// @match *://booklive.jp/index/no-charge*
// @match *://ebookjapan.yahoo.co.jp/free*
// @match *://ebookjapan.yahoo.co.jp/ranking/free/*
// @match *://ebookjapan.yahoo.co.jp/ranking/details/free/*
// @match *://ebookjapan.yahoo.co.jp/viewer*
// @match *://sokuyomi.jp/*
// @match *://csbs.shogakukan.co.jp/free*
// @match *://www.rtings.com/*/tools/table*
// @match *://www.rtings.com/*/reviews/*
// @match *://www.nicovideo.jp/search/*
// @match *://www.nicovideo.jp/tag/*
// @match *://www.nicovideo.jp/user/*
// @match *://www.nicovideo.jp/series/*
// @match *://www.nicovideo.jp/my/*
// @match *://www.nicovideo.jp/ranking/*
// @match *://www.nicovideo.jp/watch/*
// @match *://*.5ch.net/*
// @match *://www.ebay.com/sch/*
// @match *://www.ebay.com/itm/*
// @match *://jmty.jp/*
// @match *://greasyfork.org/*/scripts*
// @match *://*.aliexpress.com/af/*
// @match *://*.aliexpress.com/item/*
// @match *://*.aliexpress.com/wholesale*
// @match *://www.cmoa.jp/freecontents*
// @match *://piccoma.com/*
// @match *://www.mangaz.com/*
// @match *://www.sukima.me/*
// @match *://*.userbenchmark.com/*
// @match *://www.hellowork.mhlw.go.jp/kensaku/*
// @match *://kakaku.com/*
// @match *://seiga.nicovideo.jp/*
// @match *://tsugimanga.jp/*
// @match *://www.yodobashi.com/*
// @match *://www.youtube.com/*
// @match *://*.iherb.com/*
// @match *://www.suruga-ya.jp/*
// @match *://twitter.com/*
// @match *://www.nicovideo.me/*
// @match *://www.nicochart.jp/*
// @match *://pubmed.ncbi.nlm.nih.gov/?term=*
// @match *://pubmed.ncbi.nlm.nih.gov/?linkname=*
// @match *://pubmed.ncbi.nlm.nih.gov/*
// @match *://a-timesale.com/*
// @match *://rrws.info/*
// @match *://commons.nicovideo.jp/*
// @match *://scholar.google.tld/*
// @match *://hibiki-radio.jp/*
// @match *://www.onsen.ag/
// @match *://www.freem.ne.jp/*
// @match *://shopping.yahoo.co.jp/search*
// @match *://360life.shinyusha.co.jp/*
// @match *://omocoro.jp/*
// @match *://minsoku.net/*
// @match https://refind2ch.org/search*
// @match *://chiebukuro.yahoo.co.jp/*
// @match *://www.msdmanuals.com/*
// @match *://ff5ch.syoboi.jp/?q=*
// @match *://todo-ran.com/*
// @match *://booth.pm/*
// @match *://sakura-checker.jp/category/*
// @match https://chrome.google.com/webstore/search/*
// @match https://chrome.google.com/webstore/detail/*
// @match *://twicomi.com/*
// @match *://twiman.net/*
// @match *://free.arinco.org/*
// @match *://workman.jp/shop/*
// @match *://www.uniqlo.com/*
// @match *://*.shitaraba.net/bbs/read.cgi/*
// @match *://*.shitaraba.net/bbs/read_archive.cgi/*
// @match *://*.ftbucket.info/*
// @match *://kuzure.but.jp/*
// @match *://*.2chan.net/*
// @match *://anige.horigiri.net/*
// @match *://futapo.futakuro.com/*
// @match *://kako.futakuro.com/futa/*
// @match https://kakaku.com/pc/note-pc/itemlist.aspx
// @match https://kakaku.com/pc/desktop-pc/itemlist.aspx
// @match *://btopc-minikan.com/*
// @match *://pcfreebook.com/*
// @match *://search.bilibili.com/*
// @version     0.5.71
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_deleteValue
// @grant       GM_addStyle
// @grant       GM.addStyle
// @grant       GM.setClipboard
// @grant       GM.openInTab
// @run-at      document-idle
// @namespace http://greasyfork.icu/users/181558
// @require https://code.jquery.com/jquery-3.6.1.min.js
// @require https://code.jquery.com/ui/1.13.2/jquery-ui.min.js
// ==/UserScript==

(function() {

  const FUTAPO_AUTO_FIRST = 0; // 1:futapoで最初に無操作自動更新ON 2:1+下まで読み込む
  const FUTAPO_CRAM_TITLE = 1; // 1:futapoでboxの横幅が狭いときでもタイトルを詰め込む
  const FUTABA_RELOAD_INTERVAL = 0; // 1~:ふたばでレスを自動リロードする間隔(分) ※新着がなく無操作だと自動的に10分まで伸びる 0:無効
  const FUTABA_FLOAT_RELOAD_BUTTON = 1; // 1:ふたばでリロードボタンを浮遊させる
  const FUTABA_HOVER_POPUP_REPLACE = 1; // 1:ふたばで>引用ポップアップを置き換える
  const FUTABA_HOVER_POPUP_DELAY = 1; // ふたばで>引用の上に静止してn/60秒間後にポップアップを表示する -1:瞬間&低負荷(mousemove) 1:瞬間(interval) 2~:n/60秒(interval)
  const FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY = 1; // 1:ふたばで>no.○○や>○○.jpgや>fu○○.jpgといった引用にも本文の引用を追加する(要「5chサムネイル表示他」併用)
  const FUTABA_EXPERIMENTAL_DISPLAY_CHAINED = 0; // 1:ふたばでレス右下の□に引用連鎖数を書き入れていく ※現状重い処理
  const FUTABA_DEBUG = 0; // 1-2:ふたばで開発用情報を表示 1:最下行ログ 2:1+タブタイトル
  const ISCHROME = window.navigator.userAgent.toLowerCase().indexOf('chrome') != -1
  const DEBUG_CATCH = 0; // 1:catchしたエラーをalert
  const KEYCHANGE_DEBUG = "disable"; // 押す度にdebugを0~3に切り替えるキー "Shift+D","disable"等
  const ftbBGC = 0 ? "#f0e0d6" : "#ffffee"
  const ENABLE_HELP = 1; // 1:操作ガイドを表示 0:無効
  const ENABLE_AUTOMEMO = 7; // 0:自動メモを無効 1でオン 2~7:大きくするほど一時的に表示が崩れる代わりに確実
  const REPLACE_LINK_IN_YOUTUBE = 1; // 1:YouTubeで投稿者のチャンネルのホームタブへのリンクをチャンネルの動画タブへのリンクに置き換える
  const ENABLE_EXCEPT_YAJ = 1; // 1:ヤフオク以外でも有効 0:ヤフオクでのみ動作
  var debug = 0; // 1~だとデバッグモード V&&dc(text) 1:非対応ページでその旨表示など/コンソールにverbose表示 2:verboseをポップアップ(速度測定して表示 debug&&sw("項目"))&非表示にした原因に枠追加 3:Q/1/2等の対象要素を目立たせる
  const ENABLE_MEASURE_TIME_SPENT = 0; // 1で速度測定して表示 debug&&sw("項目")

  const fasttest = 1; // 1:高速モードを試用

  var futabapopupscale;
  const futabapicksizeDefault = 84
  var futabapicksizeL = futabapicksizeDefault;
  var futabapicksize = 100;
  var hovertimer = 0;
  var swb = new Date();
  var prefCache = []
  //  GM_addStyle("span.yhmMyMemo{all:initial; word-wrap:break-word;cursor:pointer; font-size:14px; font-weight:bold; margin:0px 1px; text-align:center; padding:0px 6px 0px 6px; border-radius:12px; color:white;font-family:sans-serif;}")
  GM_addStyle("span.yhmMyMemo{all:initial; word-wrap:break-word;cursor:pointer; font-size:14px; font-weight:bold; margin:0px 1px; text-align:center; padding:0px 6px 0px 6px; border-radius:12px; color:white;font-family:sans-serif;}")
  debug && sw("reset")

  String.prototype.match0 = function(re) { let tmp = this.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可
  String.prototype.nfd = function() { return SITE.nfd ? this?.normalize("NFD") : String(this) } // 文字列をNFDエンコードにまとめる
  String.prototype.sanit = function() { return this.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;') }

  function adja(place = document.body, pos, html) {
    return place ? (place.insertAdjacentHTML(pos, html), place) : null;
  }
  let addstyle = {
    added: [],
    add: function(str) {
      if (this.added.includes(str)) return
      GM.addStyle(str)
      this.added.push(str)
    },
  }

  var SITE = {}
  let inYOUTUBE = location.hostname.match0(/^www\.youtube\.com|^youtu\.be/);

  $.fn.animate2 = function(properties, duration, ease) {
    ease = ease || 'ease';
    var $this = this;
    var cssOrig = { transition: $this.css('transition') };
    return $this.queue(next => {
      properties['transition'] = 'all ' + duration + 'ms ' + ease;
      $this.css(properties);
      setTimeout(function() {
        $this.css(cssOrig);
        next();
      }, duration);
    });
  };

  if (window != parent) return;
  const WAIT = performance.now(); // ページ開始後のウエイト用 delayAutoWeightingをかける
  const COLOR1 = "#6080ff",
    COLOR2 = "#c03020",
    COLOR3 = "#808080",
    COLOR5 = "#6080ff",
    COLOR6 = "#c03020",
    COLORVIDEOTIME = "#204020",
    COLORCPUSCORE = "#a08000",
    KEYHIDE = "q",
    KEYUNDO = "w",
    KEYBW = "b",
    KEYEDIT = "Shift+Q",
    //    KEYEDIT2 = "Shift+B",
    KEYMAXP = ".",
    KEYMEMO1 = "1",
    KEYMEMO2 = "2",
    KEYMEMO1S = "3",
    KEYMEMO2S = "4",
    KEYMEMO5 = "5",
    KEYMEMO6 = "6",
    KEYMEMO5EDIT = "Shift+%",
    KEYMEMO6EDIT = "Shift+&",
    KEYTOGGLEtranslucent = "t",
    KEYRESETMEMO = "Shift+!",
    KEYRESETMEMOAUTO = "Shift+\"";
  var MEMO5WORD = "", // 5キーの定型文初期値 ""なら現在年月日
    MEMO6WORD = ""; // 6キーの定型文初期値 ""なら現在年月日

  var pauseAll = 0;
  let kaisuuU = 0;
  var GF = {}
  var memofast = false;

  // 上が優先
  const SITEINFO = [{
      id: 'search.bilibili.com',
      urlRE: '//search.bilibili.com/',
      listTitleXP: '//h3[@class="bili-video-card__info--tit"]',
      listTitleSearchXP: '//h3[@class="bili-video-card__info--tit"][**title**]/ancestor::div[contains(@class,"video-list-item")]',
      listTitleMemoSearchXP: '//h3[@class="bili-video-card__info--tit"][**title**]',
      listGen: 7,
      observe: 999,
      useText: 1,
    }, {
      id: 'pcfreebook.com',
      urlRE: '//pcfreebook.com/',
      listTitleXP: '//td[1]/a[@target="_blank" and @rel="noopener nofollow noreferrer"]',
      listTitleSearchXP: '//td[1]/a[@target="_blank" and @rel="noopener nofollow noreferrer"][+++]/ancestor::tr',
      listTitleMemoSearchXP: '//td[1]/a[@target="_blank" and @rel="noopener nofollow noreferrer"][+++]',
      listGen: 3,
      listTitleMemoSearchXPSameGen: 1,
      listTitleXPIgnoreNotExist: 1,
      observe: 2500,
    }, {
      id: 'btopc-minikan.com',
      urlRE: '//btopc-minikan.com/',
      titleProcessFunc: (title) => { return title.replace(/\n|\s/gmi, " ").trim() },
      listTitleXP: '//span[@class="itemname"]',
      listTitleSearchXP: '//span[@class="itemname"][++title++]/ancestor::tr',
      listTitleMemoSearchXP: '//span[@class="itemname"][++title++]',
      listTitleMemoSearchXPSameGen: 1,
      useTitle: 1,
      listGen: 4,
      func: () => {
        elegeta('//td[1]/div[@class="notranslate"]|.//td[@class="CPUgrease-GraphCell-Maker"]').forEach(e => e.insertAdjacentHTML("beforeend", `<span class="itemname" title="${e.textContent.replace(/\n|\s/gmi," ").trim()}"> </span>`))
      },
      listTitleXPIgnoreNotExist: 1,
      observe: 2500,
    }, {
      urlRE: /^https:\/\/kakaku.com\/pc\/note-pc\/itemlist\.aspx|https:\/\/kakaku\.com\/pc\/desktop-pc\/itemlist.aspx|\/\/kakaku.com\/pc\/gaming-pc\/itemlist.aspx|\/\/kakaku.com\/pc\/gaming-note\/itemlist.aspx/,
      WhateverFirstAndEveryAPFunc: () => {
        if (!elegeta('//th[@class="sub thHeader" and contains(text(),"CPUスコア ")]')[0]) return
        popup3("A:CPUスコア単価で絞り込み", 4)
        //$(".cps").remove()
        //        let arr = lh("gaming") ? elegeta('//table/tbody/tr[@class="tr-border"]/td[11]') : elegeta('//table/tbody/tr[@class="tr-border"]/td[10]')
        let arr = lh("gaming") ? elegeta('table tbody tr.tr-border td:nth-child(11):not([data-scorecost])') : elegeta('table tbody tr.tr-border td:nth-child(10):not([data-scorecost])')
        arr.forEach(e => {
          e.dataset.scorecost = 1
          //          let p = elegeta('//td[2]/ul/li[@class="pryen"]/a', e?.closest("tr"))[0]
          let p = elegeta('td:nth-child(2) ul li.pryen a', e?.closest("tr"))[0]
          let b = e.parentNode
          let cpu = parseInt(e.innerText.replace(/\D/g, ""))
          let price = parseInt(p.innerText.replace(/\D/g, ""))
          e.insertAdjacentHTML("beforeend", `<div title="Aキーでこの上限で絞り込み" class="cps" style="color:#F00;" >価格/スコア<br><span class="cputanka">${((price/cpu).toFixed(2))}</span></div>`)
        })
      },
      keyFunc: [{
        key: 'a', // a::
        func: () => {
          if (!elegeta('//th[@class="sub thHeader" and contains(text(),"CPUスコア ")]')[0]) return
          GF.base = proInput("CPUスコア単価上限を入力してください", $('#CPS').data("cps") || 10) || 0;
          autoPagerized(() => {
            $('#CPS').remove();
            $(document.body).append(`<span id="CPS" data-cps="${GF.base}" style="background-color:#"></span>`)
            //            $(elegeta('//table/tbody/tr[@class="tr-border"]')).show(100)
            $(elegeta('table tbody tr.tr-border')).show()
            if (GF.base <= 0) return
            elegeta('.cputanka').forEach(e => {
              let cps = Number(e?.innerText || 0)
              let b = e.closest("tr.tr-border")
              if (!cps || cps > GF.base) {
                $(b.previousSibling.previousSibling).add(b).hide()
              }
            })
          })
        }
      }, ],
    }, {
      urlRE: /\/\/www.ftbucket.info\/scrapshot\/ftb\/index\.php|\/\/www.ftbucket.info\/scrapshot\/ftb\/?$|\/\/www.ftbucket.info\/scrapshot\/ftb\/\?favo=/,
      id: 'FUTACHAN_CATALOG',
      listTitleXP: '//span',
      listTitleSearchXP: '//td/span[**title**]/..',
      listTitleMemoSearchXP: '//td/span[**title**]',
      listGen: 4,
      WhateverFirstAndEveryAPFunc: () => {
        popup3("Shift+F:FTBucket検索", 8, 5000)
      },
      //      WhateverFirstAndEveryAPFunc: () => { SITEINFO[SITEINFO.findIndex(c => c.id == "FUTACHAN")].WhateverFirstAndEveryAPFunc() },
      keyFunc: [{
        key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
        func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
        //        func: () => { SITEINFO[SITEINFO.findIndex(c => c.id == "FUTACHAN")].keyFunc[0].func() },
      }],
      listTitleMemoSearchXPSameGen: 1,
      delay: 333,
      func: () => {
        elegeta('//div/input[@type="search" and @id="searchword"]').forEach(e => e.style.width = "calc(100% - 4em)") // 検索フォームを大きく

        if (location.href.match0("//www.ftbucket.info/scrapshot/ftb/")) {
          setSlider(eleget0('//html/body/div[2]/a/img/..'), 4, 255, 16, "タイトル表示:***文字", "FTBTitleLength", (val) => elegeta('//td/span[@title]/div').forEach(e => e.textContent = e.parentNode.title.substr(0, val)))
          setSlider(eleget0('//html/body/div[2]/a/img/..'), 4, 30, 8, "セル幅:***em", "FTBcallWidth", (val) => elegeta('//td/span[@title]/div/../..').forEach(e => e.style.width = `${val}em`))
        }
      },
    }, {
      urlRE: "\/\/futapo.futakuro.com", // futapo::
      id: 'FUTACHAN_CATALOG',
      listTitleXP: '//div[@class="thread-text"]',
      listTitleSearchXP: '//div[@class="thread-text"][***]/../..|.//span[@class="emph"][***]/../../..',
      listTitleMemoSearchXP: '//div[@class="thread-text"][***]|.//span[@class="emph"][***]/..',
      listGen: 5,
      memoStyle: 'word-break:break-all; font-size:10px !important; line-height:130%; padding:0px 4px 0px 4px;',
      preventMemo: m => ["★", "◎", "○"].includes(m),
      QRule: "\n\n非表示化に関しては正規表現は使えませんが\nこのサイトではここで登録した内容でU/jメモの追加動作の抑制ができ、\nその抑制に関してだけは正規表現が使え、全角/半角、大文字/小文字も区別しません\n",
      listTitleXPIgnoreNotExist: 1,
      observe: 666,
      observeClass: ["box", "box ", "yhmMyMemo"], //2022年07月12日
      WhateverFirstAndEveryAPFunc: () => {
        popup3("Shift+F:FTBucket検索\nu:左上優先配置タイトルを設定\nU:左上優先配置(+通知)タイトルを設定\nj:左上優先配置(+開く)タイトルを設定\nJ:メモ削除画面\nE:更新 D:下まで読み込む", 8, 5000) // ↻
      },
      listTitleMemoSearchXPSameGen: 1,
      funcOnlyFirst: () => {
        GF.latestReload = Date.now() - 3000
        GM_addStyle('.popuptext,.popuptext-back{z-index:1000000000000;}')
        GM_addStyle(".boxpri1{animation: pulse1 5s 1; } @keyframes pulse1 { 0% { outline:5px solid #0000ffff; } 40% { outline:5px solid #0000ffff; } 100% { outline:5px solid #0000ff00; } }")
        //if (FUTAPO_CRAM_TITLE) GM_addStyle("div.thread-contents {  padding-left: 0px !important;} div.thumbnailContainer { min-width:68.4px; position:inherit !important; margin-left: 0px !important;}") // boxの横幅が狭いときでもタイトルを詰め込む
        document.querySelector(`head`).insertAdjacentHTML('beforeend', `<style>.waiting{ display: inline-block; vertical-align: middle; color: #666; line-height: 1; width: 1em; height: 1em; border: 0.12em solid currentColor; border-top-color: rgba(102, 102, 102, 0.3); border-radius: 50%; box-sizing: border-box; -webkit-animation: rotate 1s linear infinite; animation: rotate 1s linear infinite; } @-webkit-keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } @keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } }</style>`)

        if (FUTAPO_CRAM_TITLE) GM_addStyle("div.thread-contents {  padding-left: 0px !important;} div.thumbnailContainer { min-width:3em; position:inherit !important; margin-left: 0px !important;}") // boxの横幅が狭いときでもタイトルを詰め込む

        var lastope = Date.now()
        var cdID
        setTimeout(() => {
          if (eleget0('#reload') && !cdID) {
            document.body.insertAdjacentHTML("beforeend", `<tt id="cdsw" style="cursor:pointer;left:1em; bottom:2em; position:fixed;" title="左クリックで無操作時60秒毎に自動更新開始\nもう一度左クリックで停止">&#9211;無操作<br>自動更新</tt>`)
            $(document).on("click", `#cdsw`, () => {
              $('#cdsw').fadeOut(222);
              var lastope = Date.now()
              $(document).on("mousemove mousedown keydown", () => { lastope = Date.now() })
              var cdID = setInterval(() => {
                $('#cd,#cdsw').remove();
                //                document.body.insertAdjacentHTML("beforeend", `<tt id="cd" style="cursor:pointer;left:1em; bottom:2em; position:fixed;">${~~(60.9-(Date.now()-lastope)/1000)} 無操作<br>自動更新中</tt>`)//&#9213;
                document.body.insertAdjacentHTML("beforeend", `<tt id="cd" style="cursor:pointer;left:1em; bottom:2em; position:fixed;">${~~(60.9-(Date.now()-lastope)/1000)}</tt>`) //&#9213;
                if (Date.now() - lastope > 60 * 1000) {
                  lastope = Date.now();
                  eleget0('//li[1]/a[@id="reload"]')?.click()
                }
              }, 333)
              $(document).on("click", `#cd`, () => {
                clearInterval(cdID);
                $('#cd').remove() //text("停止")//.hide(999);
                document.body.insertAdjacentHTML("beforeend", `<tt id="cdsw" style="cursor:pointer;left:1em; bottom:2em; position:fixed;" title="左クリックで無操作時60秒毎に自動更新開始\nもう一度左クリックで停止">&#9211;無操作<br>自動更新</tt>`)
              })
            })
          }
        }, 500)

        let scr = (i) => {
          let last = eleget0('#kako-search')
          window.scroll({ left: 0, top: last ? 0 : 99999, behavior: i % 2 == 1 ? "instant" : "smooth" })
          if (!last && i < 99) setTimeout(() => { scr(++i) }, 100)
        }
        setTimeout(() => {
          elegeta("#reload,#logo,#cdsw").forEach(e => e.title = e?.title + "\nE:更新\nD/右クリック:更新+下まで読み込み") // ↻
          $(document).on("contextmenu", '#reload,#logo,#cdsw,#cd', () => { // d::
            let r = eleget0('//a[@id="reload"]');
            if (r) {
              if (!GF.latestReload || new Date().getTime() - GF.latestReload > 5000) {
                r.click();
                scr(0)
                GF.latestReload = new Date().getTime();
              } // 要5秒インターバル
            }
            return false
          })

          $('a#server.pulldown').attr("title", ($("a#server.pulldown").attr("title") || "") + "\n右クリック:may←→img") // ↻
          $('a#server.pulldown').on("contextmenu", () => {
            let url = location.href == 'https://futapo.futakuro.com/?server=img_b' ? 'https://futapo.futakuro.com/?server=may_b' : 'https://futapo.futakuro.com/?server=img_b'
            location.href = url;
            return false
          })
          $('a#mode.pulldown').on("contextmenu", () => {
            let url = lh(/\&mode=6_0/) ? location.href.replace("&mode=6_0", "&mode=4_0") : lh(/\&mode=4_0/) ? location.href.replace("&mode=4_0", "&mode=6_0") : `https://futapo.futakuro.com/?server=may_b&mode=4_0&search=&searchMode=0&kako=0`
            location.href = url;
            return false
          })
          if (FUTAPO_AUTO_FIRST >= 1) $("#cdsw").click()
          if (FUTAPO_AUTO_FIRST >= 2) scr(0)

        }, 500)

        GM_addStyle("div.thread-text{display:inline;} .thread-text{word-break:break-all;}") // html{line-height:1.2;}
        setTimeout(() => {
          setSlider(eleget0('//div[@id="boxArea"]'), 54, 300, 54, "box高さ:***", "boxheight", (val) => {
            eleget0('#boxheightcss')?.remove()
            end(document.head, `<style id="boxheightcss">div.thread-contents{height:${val - 2}px !important;} a.box{height:${15 + val}px !important;}</style>`)
          }, 0, 'style="width:7em;height:0.5em;"')
          setSlider(eleget0('//div[@id="boxArea"]'), 0, 10, 5, "タイトル行間:***", "lineheight", (val) => {
            eleget0('#boxlineheightcss')?.remove()
            end(document.head, `<style id="boxlineheightcss">html{line-height:${1+val/10} !important;}</style>`)
          }, 0, 'style="width:7em;height:0.5em;"')
        }, 999)
      },
      funcMemo: () => { SITE.funcFinally() },
      funcFinally: (disableHide) => {
        setTimeout(() => {
          let found = 0;

          // u::U::j:: メモが付いたものを左上に優先整列
          // ここのu/U/j動作は正規表現対応や大文字小文字全角半角非区別のために標準のメモが付く動作(正規表現非対応)や非表示動作(正規表現非対応)とは一致しない点に注意
          try {
            // メモをクリックで消す&ESC/パネル外をクリックでパネルを消す動作を登録
            if (!GF.yhmMemoDeleteButton) {
              GF.yhmMemoDeleteButton = 1
              $(document).on("keydown", e => { if (e.key === "Escape") $('#yhmMemoDeletePanel').hide(200).queue(function() { $(this).remove() }) })
              //              $(document).on("mousedown", e => { if (e?.target === document.body || e?.target?.matches("*:not(#yhmMemoDeletePanel,.yhmMemoDeleteButton,.yhmNoSelect)")) $('#yhmMemoDeletePanel').hide(200).queue(function() { $(this).remove() }) })
              $(document).on("mousedown", e => { if (!e?.target?.closest("#yhmMemoDeletePanel") || e?.target?.matches("#yhmMemoDeletePanelClose")) $('#yhmMemoDeletePanel').hide(200).queue(function() { $(this).remove() }) })
              $(document).on("click", ".yhmMemoDeleteButton,.yhmNoSelect", e => { // クリックで削除
                let ele = e.target?.closest(".yhmMemoDeleteButton")
                if (!ele) return
                var str = pref(SITE.id + ' : SearchMyMemo') || [];
                //let memo = str.find(v => v.t === unescape(ele.dataset.t) && v.m === unescape(ele.dataset.m) && v.c === unescape(ele.dataset.c))
                let memo = str.find(v => escape(v.t + v.m + v.c) === ele.id)
                if (memo) {
                  $(ele).hide(200).queue(function() { $(this).remove() }); // これは削除パネル用の動作
                  elegeta('.yhmMyMemo').filter(e => e.id === escape(memo.t + memo.m + memo.c)).forEach(e => { $(e).hide(200).queue(function() { $(this).remove() }) })
                  adja(document.body, "afterbegin", "<yhmmymemoremoved></yhmmymemoremoved>");
                  eleget0('yhmmymemoremoved')?.remove(); // 学園祭用に消去を告知
                  GM.setClipboard(memo.t)
                  pref(SITE.id + ' : SearchMyMemo', (pref(SITE.id + ' : SearchMyMemo') || []).filter(n => JS(n) !== JS(memo)))
                }
                e.preventDefault()
                return false
              })
            }

            let memoa = pref(SITE.id + ' : SearchMyMemo') || [];
            //          memoa = memoa.map(v => {
            memoa = memoa.filter(v => SITE?.preventMemo(v.m)).map(v => {
              v.than = han(v.t);
              if (isValidRE(v.t)) v.re = new RegExp(v.t, "mi");
              return v
            }) // 重いので計算を1回で済ます
            let hide = disableHide ? [] : pref(SITE.id + ' : SearchHideTitle') || []
            hide = hide.map(v => { return { word: v, re: isValidRE(v) ? new RegExp(v, "mi") : null } }) // 重いので計算を1回で済ます

            var hit = []
            for (let e of elegeta('.box:not([relocatedByMemo])')) {
              let tt = eleget0('.thread-text', e)?.textContent
              for (let v of memoa) {
                if (v.re && v.re.test(han(tt)) ||
                  tt?.indexOf(v.t) !== -1) { // u/U/jメモ登録ワードが正規表現として有効なら正規表現としてチェック、また単純文字列としてヒットしてもヒットとする
                  if (!hit.includes(e)) hit.push(e)
                  e.dataset.vip = Math.max("○◎★".indexOf(v.m), e.dataset?.vip || 0) // j>U>uの順で強い結果を残す
                  e.title = `${e.title?e.title+" ":""}${v.m}${v.t}`
                  e.dataset.hitwords = `${e.dataset.hitwords?e.dataset.hitwords+" ":""}${v.m}${v.t}`;
                  if (v?.t?.length > 3) { if (!eleget0(`*[id="${escape(v.t+v.m+v.c)}"]`, e)) after(eleget0('.thread-text', e), `<span class="ignoreMe yhmMyMemo yhmMemoDeleteButton" id="${escape(v.t+v.m+v.c)}" title="『${sani(v.t)}』についたメモ\nクリックで削除&クリップボードにコピー" style="${MEMOSTYLE} cursor:pointer; background-color:${v.c}; border-radius:1em; color:#fff;">${sani(v.m)}${sani(v.t)?.substr(0,25)+(v?.t?.length>25?"…":"")}</span>`) } else {
                    if (!eleget0(`*[id="${escape(v.t+v.m+v.c)}"]`, e)) after(eleget0('.thread-text', e), `<ruby class="ignoreMe yhmMyMemo yhmMemoDeleteButton" id="${escape(v.t+v.m+v.c)}" title="『${sani(v.t)}』についたメモ\nクリックで削除&クリップボードにコピー"><span class="ignoreMe yhmMyMemo" style="${MEMOSTYLE} cursor:pointer; background-color:${v.c}; border-radius:1em; color:#fff;">${sani(v.m)}${sani(v.t)?.substr(0,25)+(v?.t?.length>25?"…":"")}</span></ruby>`)
                  }
                }
              }
              eleget0('.thumbnail', e)?.setAttribute("title", `${tt}\n${e.title}`)
            }
            GF.opened = GF.opened || []
            GF.opened1 = GF.opened1 || []
            GF.opened2 = GF.opened2 || []

            while (1) {
              var b = elegeta('.box:not([relocatedByMemo])')
              var e = b.find(v => hit.find(w => w === v))
              if (!e) break;
              GF.opened.push(e.href)

              let vip = Number(e.dataset.vip)
              e.setAttribute("relocatedByMemo", "")
              let memoEle = e
              let firstBox = elegeta('.box:not(.boxpri,.boxpri2)').filter(e => e.style.backgroundColor !== "rgb(255, 255, 0)")[0]
              if (vip == 1) {
                firstBox = elegeta('.box:not(.boxpri2,.boxpri3)').filter(e => e.style.backgroundColor !== "rgb(255, 255, 0)")[0]
                eleget0('.thread-text', memoEle).style.color = "#12e";
                memoEle.style.boxShadow = "4px 4px 4px 0px #0006";
                //              memoEle.style.boxShadow = "2px 2px 4px 2px #0006";
                memoEle.style.zIndex = 2;
                memoEle.style.fontWeight = "bold"
                memoEle.classList.add("boxpri2")
              } else if (vip == 2) {
                firstBox = elegeta('.box:not(.boxpri3)').filter(e => e.style.backgroundColor !== "rgb(255, 255, 0)")[0]
                eleget0('.thread-text', memoEle).style.color = "#12e";
                memoEle.style.boxShadow = "4px 4px 4px 0px #0006";
                //memoEle.style.boxShadow = "2px 2px 4px 2px #0006";
                memoEle.style.zIndex = 3;
                memoEle.style.fontWeight = "bold"
                memoEle.classList.add("boxpri3")
              } else {
                memoEle.style.boxShadow = "4px 4px 4px #0006";
                memoEle.style.zIndex = 1;
              }
              memoEle.classList.add("boxpri")

              firstBox.parentNode.insertBefore(memoEle, firstBox)

              // Qの非表示にヒットしたものは除外、正規表現対応・全角半角非区別・大文字小文字非区別
              let tt = eleget0('.thread-text', e)?.textContent;
              if (disableHide || !hide.some(q => {
                  return (q.re && q.re.test(han(tt))) || tt?.indexOf(q.word) !== -1
                })) { // Q非表示登録ワードが正規表現として有効なら正規表現としてもチェック、また単純文字列としてヒットしてもヒットとする

                if (vip == 1 && e.offsetHeight && !GF.opened1.includes(e.href)) {
                  GF.opened1.push(e.href)
                  found = memoEle.cloneNode(true);
                  notifyMe(eleget0(".thread-text", found)?.innerText, e.dataset.hitwords, () => { window.open(memoEle.href) })
                }
                if (vip == 2 && e.offsetHeight && !GF.opened2.includes(e.href)) {
                  GF.opened2.push(e.href)
                  GF.open = GF.open || []
                  found = memoEle.cloneNode(true);
                  memoEle.classList.add('blinkingOL')
                  addstyle.add('@keyframes outline { 0% { outline: 2px solid #f0f; } 100% { outline: 2px solid #c8f; } } .blinkingOL{ animation: outline 1s ease infinite alternate; }')

                  function opentab(href) {
                    if (Date.now() - (GF.latest || 0) > (ISCHROME ? 7000 : 5000)) {
                      GF.latest = Date.now()
                      GM.openInTab(href, true)
                      memoEle.classList.remove('blinkingOL')
                    } else {
                      setTimeout(() => { opentab(href) }, 333)
                    }
                  }
                  opentab(memoEle.href)
                  //}
                }
              }
            }
            if (found) {
              function sound(type, sec) {
                let ctx = new AudioContext();
                let osc = ctx.createOscillator();
                osc.type = type;
                osc.connect(ctx.destination);
                osc.start();
                osc.stop(sec);
              }
              sound("sine", 0.1);
            }
          } catch (e) { if (DEBUG_CATCH) alert(e) }
        }, 200)
      },
      keyFunc: [{
        key: 'd', // d::
        func: (e) => {
          let r = eleget0('//a[@id="reload"]');
          if (r) {
            //if (!GF.latestReload || new Date().getTime() - GF.latestReload > 5000) {
            //r.click();
            let scr = (i) => {
              let last = eleget0('#kako-search')
              window.scroll({ left: 0, top: last ? 0 : 99999, behavior: i % 2 == 1 ? "instant" : "smooth" })
              if (!last && i < 99) setTimeout(() => { scr(++i) }, 100)
            }
            scr(0)
            //GF.latestReload = new Date().getTime();
            //} // 要5秒インターバル
          }
        },
      }, {
        key: 'e', // e::リロード
        func: () => {
          let r = eleget0('//a[@id="reload"]');
          if (r) {
            if (!GF.latestReload || new Date().getTime() - GF.latestReload > 4000) {
              r.click();
              GF.latestReload = new Date().getTime();
            } // 要4秒インターバル
          }
        },
      }, {
        key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
        func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
      }, {
        key: /^u$|^Shift\+U$|^j$/, // u::U::j::
        func: (e) => {
          var str = pref(SITE.id + ' : SearchMyMemo') || [];
          let memostr = e == "j" ? "★" : e == "u" ? "○" : "◎"
          var newstr = str.filter(e => e.m === memostr).map(e => e.t)
          GF.sorttype = ((GF.sorttype || 0) % 3 + 1)
          var [order, finstrfunc] = [
            ["登録順", a => a.join(" ")],
            ["abc順", a => a.sort(new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare).join(" ")],
            ["長さ→abc順", a => a.sort((a, b) => a.length === b.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a, b) : a.length > b.length ? 1 : -1).join(" ")]
          ][GF.sorttype - 1]
          var target = (window.getSelection() && window.getSelection().toString().trim()) || (prompt(`${memostr}メモを付けるキーワードを入力してください\n\nこのサイトではここで設定した項目、メモが付く項目を左上に優先配置します\n(部分一致、正規表現使用可)\n\n${"◎メモではさらに音声とNotificationで通知します\n★メモでは更に自動的に新しいタブで開きます"}\n\nすでに登録されている文字列を入力するとそれを削除します\n複数の単語をスペースで区切って入力するとまとめて登録できます\n\n現在登録済み(${newstr.length}): (${order})\n${finstrfunc(newstr)}\n\n`) || "").trim();

          if (!target) return;
          var dele = 0;
          target.split(/\s| /).forEach(targetc => {
            targetc = targetc.trim()
            var str = pref(SITE.id + ' : SearchMyMemo') || [];
            var str2 = str.filter(e => { return e.t != targetc })
            if (str.length != str2.length) {
              if (confirm(`『${targetc}』(${str.find(e=>e.t==targetc)?.m})は既に存在します\n削除しますか?`)) {
                if (debug) V && dc(`『${targetc}』をメモから削除しました`)
                pref(SITE.id + ' : SearchMyMemo', JSON.stringify(str2));
                dele = 1;
                elegeta('[relocatedByMemo]').forEach(v => v.removeAttribute("relocatedByMemo"))
                $(".yhmMyMemo").remove()
                run("returned")
                //                run()
              }
            } else {
              storeMemo(targetc.trim(), memostr, COLOR1)
              //                SITE.funcMemo();
              //for (let e of elegeta('//span[contains(@class,"yhmMyMemo")]')) $(e).hide(200).queue(function() { $(this).remove() });
              //SITE.keyFunc.find(v=>v.key=="e").func()
              elegeta('[relocatedByMemo]').forEach(v => v.removeAttribute("relocatedByMemo"))
              //$(".yhmMyMemo").remove()
              run("returned")
              //SITE?.funcFinally(disableHide)
            }
          })
          if (dele) run(document.body, "returned")
          //if (dele) location.reload()
        },
      }, {
        key: /^Shift\+J$/, // Shift+J::メモ一覧一括削除画面
        func: (e) => {
          var str = pref(SITE.id + ' : SearchMyMemo') || [];
          var newstr = str
          //GF.sorttype = ((GF.sorttype || 0) % 6 + 1)
          GF.sorttype = eleget0("#yhmMemoDeletePanel") ? ((GF.sorttype) % 6 + 1) : 1
          var [order, finstrfunc] = [
            ["登録順", a => a],
            ["abc順", a => a.sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1).sort((a, b) => (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t))],
            ["長さ→abc順", a => a.sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1).sort((a, b) => a.t.length === b.t.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t) : a.t.length > b.t.length ? 1 : -1)],
            ["種別→登録順", a => a.sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1)],
            ["種別→abc順", a => a.sort((a, b) => (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t)).sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1)],
            ["種別→長さ→abc順", a => a.sort((a, b) => a.t.length === b.t.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t) : a.t.length > b.t.length ? 1 : -1).sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1)]
          ][GF.sorttype - 1]
          let words = finstrfunc(newstr)
          $("#yhmMemoDeletePanel").remove()
          end(document.body, `<div id="yhmMemoDeletePanel" style="width:85%; font-size:95%; position:absolute; top:1em; left: 50%; transform: translate(-50%, 0%); box-shadow:0px 0px 2em #0008; word-break:keep-all; z-index:${Number.MAX_SAFE_INTEGER}; padding:2em; margin:auto; background-color:#fff; line-height:1.5em;"><span id="yhmMemoDeletePanelClose" style="cursor:pointer;float:right;">×</span>Shift+J:(${order})<br>メモ(${words.length})をクリックすると削除してクリップボードにコピーします<br><div>`)
          let dup = [] // 重複しているものは暗い色にする
          words.forEach(w => {
            end(eleget0("#yhmMemoDeletePanel"), `<span class="yhmMemoDeleteButton" id="${escape(w.t+w.m+w.c)}" data-m="${escape(w.m)}" data-t="${escape(w.t)}" data-c="${escape(w.c)}" style="cursor:pointer; background-color:${w.c}; ${dup.includes(w.t)?"filter:saturate(0.66);":""} padding:1px 0.4em 1px 0.3em; margin:0; border-radius:1em; color:#fff;"><font class="yhmNoSelect" style="user-select:none; ">${sani(w.m)}</font>${sani(w.t)}</span> `) // title="クリックで削除&クリッピボードにコピー"
            //            end(eleget0('.thread-text', e), `<span class="yhmMyMemo yhmMemoDeleteButton" id="${escape(v.t+v.m+v.c)}" data-m="${escape(v.m)}" data-t="${escape(v.t)}" data-c="${escape(v.c)}" style="${MEMOSTYLE} cursor:pointer; background-color:${v.c}; border-radius:1em; color:#fff;">${sani(v.m)}</span>`)//${sani(v.t)}
            dup.push(w.t)
          })
          /*if (!GF.yhmMemoDeleteButton) {
            GF.yhmMemoDeleteButton = 1
            $(document.body).on("keydown", e => { if (e.key === "Escape") $('#yhmMemoDeletePanel').hide(200).queue(function() { $(this).remove() }) })
            $(document).on("mousedown", e => { if (e?.target === document.body || e?.target?.matches("*:not(#yhmMemoDeletePanel,.yhmMemoDeleteButton,.yhmNoSelect)")) $('#yhmMemoDeletePanel').hide(200).queue(function() { $(this).remove() }) })
            $(document.body).on("click", ".yhmMemoDeleteButton,.yhmNoSelect", e => { // クリックで削除
              let ele = e.target?.closest(".yhmMemoDeleteButton")
              if (!ele) return
              var str = pref(SITE.id + ' : SearchMyMemo') || [];
              let memo = str.find(v => v.t === unescape(ele.dataset.t) && v.m === unescape(ele.dataset.m) && v.c === unescape(ele.dataset.c))
              if (memo) {
                $(ele).hide(200).queue(function() { $(this).remove() });
                for (let e of elegeta('//span[contains(@class,"yhmMyMemo") and @id="' + escape(memo.t + memo.m + memo.c) + '"]')) $(e).hide(200).queue(function() { $(this.parentNode).remove() });
                adja(document.body, "afterbegin", "<yhmmymemoremoved></yhmmymemoremoved>");
                eleget0('yhmmymemoremoved')?.remove(); // 学園祭用に消去を告知
                GM.setClipboard(memo.t)
                pref(SITE.id + ' : SearchMyMemo', (pref(SITE.id + ' : SearchMyMemo') || []).filter(n => JS(n) !== JS(memo)))
              }
              e.preventDefault()
              return false
            })
          }*/
        },
      }, {
        key: 'a', // a::ソート
        func: () => {
          var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
          $('.yhmSortType').remove(), $(document.body).append(`<span class="yhmSortType" id="${++sorttype%4}"></span>`)
          popup2("A:ソート\n" + (["レス数", "勢い", "タイトル", "元"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
          sorttype == 1 && sortdom(elegeta('.box:not(#kako-search)'), v => Number(eleget0('.rescnt', v)?.textContent), 1)
          sorttype == 2 && sortdom(elegeta('.box:not(#kako-search)'), v => Number(0 + eleget0('.ikioi-icon', v)?.textContent) + Number((eleget0('span.red', v)?.textContent + 0 || 0)) * 10, 1)
          sorttype == 3 && sortdom(elegeta('.box:not(#kako-search)'), v => (eleget0('.thread-text', v)?.textContent))
          sorttype == 4 && sortdom(elegeta('.box:not(#kako-search)'), v => v?.dataset?.idx)
        }
      }, ],
      wholeHelp: [() => 1, " A:ソート"],
      hideSelectedWord: 1,
      selectedHelp: { help: [KEYHIDE + ":NGワードに追加", "u/U/j:左上に優先配置(U:+通知/j:+開く)"] }, //, multi: "複数行に渡る文字列は NG に入れられません" },
    },
    {
      id: 'FUTACHAN_CATALOG',
      urlRE: /\/\/anige\.horigiri\.net\/?$|\/\/anige\.horigiri\.net\/\?cat=|\/\/anige\.horigiri\.net\/\?paged=/,
      listTitleXP: '//div/h3[@class="entry-title"]/a',
      listTitleSearchXP: '//div/h3[@class="entry-title"]/a[+++]/../../../..',
      hideSelectedWord: 1,
      listTitleMemoSearchXP: '//div/h3[@class="entry-title"]/a[+++]',
      listGen: 5,
      delat: 500,
      listTitleMemoSearchXPSameGen: 1,
      WhateverFirstAndEveryAPFunc: () => { SITEINFO[SITEINFO.findIndex(c => c.id == "FUTACHAN_CATALOG")].WhateverFirstAndEveryAPFunc() },
      keyFunc: [{
        key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
        func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
      }],
    },
    {
      id: 'FUTACHAN',
      urlRE: '//kuzure.but.jp/f/$',
      WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+F:FTBucket検索`, 8, 5000) },
      keyFunc: [{
        key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
        func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
      }],
    },
    {
      id: 'FUTACHAN', // futaba::
      urlRE: '//.*.ftbucket.info/|//kuzure.but.jp/f/b/|//[^.]+.2chan.net\/|//anige.horigiri.net|//kako.futakuro.com/futa/',
      title: '.thre table .cno',
      box: '.thre table',
      disableKeyB: 0,
      //      isMemoPartialMatch:1,
      isHidePartialMatch: 1,
      memoFunc: titleEle => eleget0('.memo', titleEle.closest('tr')),
      memoPosition: "afterbegin",
      listHelpJQS: '.thre table',
      delay: 333,
      memoStyle: 'display:table;',
      detailURLRE: /$^/,
      detailTitleXP: '',
      hideSelectedWord: 1,
      selectedHelp: { help: [KEYHIDE + ":NGワードに追加"] }, //, multi: "複数行に渡る文字列は NG に入れられません" },
      detailTitleSearchXP: '',
      listTitleSearchFunc: (title) => { // q::レス中キーワードNG // todo:リロードで追加されたレスにも非表示を適用
        let resHit = [];
        if (typeof title === "string" && !/^No\.\d+$/gmi.test(title)) { // textContentでサーチする
          for (let res of elegeta('.thre table:not(.ftbpu table,#respopup_area table)')) { // レス全体(ID:~も対象)
            if (res.textContent.indexOf(title) !== -1) resHit.push(res?.closest('table'));
          }
        }
        return resHit;
      },

      WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+F:FTBucket検索\nA:そうだね順/引用順/画像順でソート${location.href.match0(/^https?:\/\/[^.]+\.2chan\.net\//)?"\nE:リロード(D:+新着までスクロール)":""}`, 6, 5000) },
      //wholeHelp:[()=>1,`\n A:ソート Shift+F:FTBucket検索 ${location.href.match0(/^https?:\/\/[^.]+\.2chan\.net\//)?" D:リロード+新着までスクロール":""}`],
      funcD: () => { // d::
        //        let r = eleget0("#contres>a,#fvw_loading");
        let r = eleget0("#contres>a,#fvw_loading,a#akahuku_reload_button");
        if (r) {
          if (!GF.latestReload || new Date().getTime() - GF.latestReload > 4000) {
            //if (!GF.latestReload || Date.now() - GF.latestReload > 4000) {
            r.click();
            //            setTimeout(() => { eleget0('.reloadline')?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }) }, 200);
            //GF.latestReload = Date.now()
            GF.latestReload = new Date().getTime();
          } // 要4秒インターバル
          setTimeout(() => { eleget0('.reloadline')?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }) }, 200);
        }
      },
      keyFunc: [{
        key: /z|Shift\+Z/, // z::ポップアップを画像として「名前を付けて保存」
        id: "z",
        func: (e) => {
          if (document.elementFromPoint(mousex, mousey)?.matches("video,img")) return
          let target = eleget0('.ftbpu') ? ".ftbpu" : eleget0('#pickbox') ? "#presentPick" : ""
          if (target == "#presentPick") {
            let p = end(document.body, `<div id="presentPick" class="ignoreMe" style="padding:5px; width:max-content; max-width:100%; background-color:#ffffeecc; "></div>`)
            if (GF.presentPick) GF.presentPick.forEach(v => p.append(v.cloneNode(true)))
            sortdom(elegeta('#presentPick table[data-rsc]'), v => v.getAttribute("data-rsc"))
          }
          if (e == "Shift+Z") {
            if (!eleget0("#contdisp font:text*=スレッドがありません")) {
              elegeta('.ftbpu a>img[src*="thumb/"]:not([data-rep-lar]),#pickbox a>img[src*="thumb/"]:not([data-rep-lar])').filter(e => e.src.match(/thumb\/\d+s\./)).forEach(img => {
                let orgHref = img?.parentNode?.href
                if (orgHref?.match(/\.(jpe?g|png|bmp|gif|webp)/)) elegeta(`a>img[src="${img?.getAttribute("src")}"]`).forEach(e => {
                  e.src = orgHref;
                  e.dataset.repLar = 1
                })
              })
            }
            setTimeout(() => z(2), Math.max(999, elegeta(`${target} img:not(.quoteSpeechBalloonImg)`)?.length * 210))
            return
          }
          z(1)

          function z(e = 1) {
            var SCALE_MIN = 1 // 保存最低倍率
            var SCALE_MAX = e || 2 // 保存最大倍率
            var D_FILENAME_MAXLENGTH = 100 // ファイル名の最大長
            if (!eleget0(target)) return

            GF?.zFunc && GF?.zFunc()

            let honbun = elegeta(`${target} blockquote`).map(e => e.innerText)?.join(" ")
            honbun = honbun?.replace(/\s*\>+[^\s]+/gm, "")?.trim() || res
            honbun = honbun?.slice(0, 100); // ?.replace(/キタ━+\(゚\∀゚\)━+\!+/gm,"")

            $(`${target} .yhmMyMemo,${target} .relallArea,${target} .adddel`).remove()
            $(`${target}`).css({ "box-shadow": "none", "transform": "scale(1)" })
            if (target == "#presentPick") {
              $(`${target} table`).css({ "margin-right": "auto", "margin-left": "0" })
              $(`${target} .sod`).css({ "font-size": "100%", "color": "#800000" }) //,"float":"right" })
              $(`${target} .revQuote`).after("<br>"); //css({ "display": "inline-block" })
              //$(`${target}`).css({ "max-height": "none", "padding": "5px", "max-width": "100%","opacity":"1" })
              $(`${target} a img`).css({ "max-height": "" }) // pickの画像縦圧縮を解放する
              //$(`#pickbox a img`).css({ "max-height": "9em" }) // pickの画像縦圧縮を解放する
            }
            var hrefName = ""
            var fn = `${signzen(document.title+" "+location.href).substr(0, D_FILENAME_MAXLENGTH-hrefName.length-1)} ${hrefName}`?.trim()
            var res = honbun
            res = res?.replace(/^\s*\>.*\s*$/gm, "")?.replace(/キタ━+\(゚\∀゚\)━+\!+/gm, "")?.trim() || res;
            if (res) fn = `${signzen(document.title+" "+location.href).substr(0, D_FILENAME_MAXLENGTH/2-hrefName.length-1)} ${signzen(res).substr(0, D_FILENAME_MAXLENGTH/2-1)} ${hrefName}`.trim()

            function signzen(str) { return str.replace(/^\s+/, "").replace(/\\|\/|\:|\;|\,|\+|\&|\=|\*|\?|\"|\'|\>|\<|\./g, c => { return String.fromCharCode(c.charCodeAt(0) + 0xFEE0) }) }

            let puele = eleget0(`${target}`)
            let scale = Math.max(1, Math.min(SCALE_MAX, SCALE_MIN + (elegeta('img:not(.quoteSpeechBalloonImg)', puele).length * 0.5)))
            popup3(`z:ポップアップ(ピックアップ)を保存\nZ:ポップアップ(ピックアップ)を保存(高画質)\nScale = ${scale}`)
            document.dispatchEvent(new CustomEvent('saveDOMAsImage', { detail: { element: puele, filename: fn, scale: scale } }))
            $('#presentPick').remove()
            if (target == "#pickbox") window.dispatchEvent(new Event('resize'))
          }
        },
      }, {
        key: 'e', // e::リロード
        func: () => {
          //let r = eleget0("#contres>a,#fvw_loading");
          let r = eleget0("#contres>a,#fvw_loading,a#akahuku_reload_button");
          if (r) {
            if (!GF.latestReload || new Date().getTime() - GF.latestReload > 4000) {
              //if (!GF.latestReload || Date.now() - GF.latestReload > 4000) {
              r.click();
              GF.latestReload = new Date().getTime();
              //GF.latestReload = Date.now()
            } // 要4秒インターバル
          }
        }
      }, {
        key: 'd', // d::
        func: (e) => {
          if (eleget0("a:hover,video:hover,img:hover")) return
          SITE.funcD()
        },
      }, {
        key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
        func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
      }, {
        key: 'a', // a::
        func: () => {
          GF.stopmoq = 1
          let isftchan = /^https?:\/\/kuzure\.but\.jp\/f\/b\//.test(location.href);
          let isanigeaki = /\/\/anige\.horigiri\.net\/\?p/.test(location.href);
          if (isanigeaki || isftchan) $(elegeta('.thre .rtd').filter(e => !e.closest("#pickbox,.ftbpu"))[0]).closest("table").before($('<div id="thre0"></div>'))
          $('.reloadline').remove();
          GF.sort = (GF?.sort || 0) % 4 + 1 //var sorttype = GF.sort||0//Number($('.yhmSortType')?.attr("id") || 0);
          let sorttype = GF.sort
          popup2("A:ソート\n" + (["そうだね", "引用", "画像", "古い順"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
          sorttype == 1 && sortdom(elegeta('.rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('.sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1000000000) + (v.querySelectorAll(".revQuote").length * 1000000) + (((v.textContent.match(/\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/gmi) || []).length * 1000) || ((v.textContent.match(/ttps?\:\/\//gmi) || []).length * 1)) }, 1) // リンクも加点
          sorttype == 2 && sortdom(elegeta('.rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('.sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1000000) + (v.querySelectorAll(".revQuote").length * 1000000000) + (((v.textContent.match(/\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/gmi) || []).length * 1000) || ((v.textContent.match(/ttps?\:\/\//gmi) || []).length * 1)) }, 1) // リンクも加点
          sorttype == 3 && sortdom(elegeta('.rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('.sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1) + (v.querySelectorAll(".revQuote").length * 1) + (((v.textContent.match(/\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/gmi) ? 1 : 0) * 1000000) || ((v.textContent.match(/ttps?\:\/\//gmi) ? 1 : 0) * 1000)) }, 1) // リンクも加点
          sorttype == 4 && sortdom(elegeta('.rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), v => v.getAttribute("rsc")) //,

          setTimeout(() => { GF.stopmoq = 0 }, 500)
        },
      }],
      funcOnlyFirst: () => {
        GF.latestReload = Date.now() - 3000
        GF.newarticle = 1000
        GF.latestInterval = FUTABA_RELOAD_INTERVAL * 60 * 1000
        let is2chan = /^https?:\/\/[^.]+\.2chan\.net\//.test(location.href);
        let isftb = /^https?:\/\/www\.ftbucket\.info\//.test(location.href);
        if (is2chan && !location.href.match0(/\.2chan\..+\/res\//)) return;
        let iskurokako = /\/\/kako\.futakuro\.com\/futa\//.test(location.href);
        let isftchan = /^https?:\/\/kuzure\.but\.jp\/f\/b\//.test(location.href);
        let isanigeaki = /\/\/anige\.horigiri\.net\/\?p/.test(location.href);
        if (isanigeaki) GM_addStyle('table, th, td{border:0;}');
        if (isftchan || isanigeaki) { document.body.innerHTML = "<div class='thre'>" + document.body.innerHTML + "</div>" }
        if (isftchan) { GM_addStyle("body{min-width:95%} .thre table{margin-right:0} #v0z{display:none;}") }
        //        if (is2chan || isftchan) GM_addStyle(".rtd{vertical-align:top}")
        if (is2chan || isftchan) GM_addStyle(".rtd{vertical-align:top} #pdm{z-index:2000000021}")
        GM_addStyle("#pickbox .yhmMyMemo{white-space: nowrap;} .quo{vertical-align:top} a:visited{color:#800080;}")
        //        FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY = FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY && (eleget0('#fivechthumbnailetc') || lh("ftbucket|kuzure")) // Math.random()>0.5?1:0; // 1:ふたばで>no.○○や>○○.jpgといった引用に本文の引用を追加する
        let fivechthumbnailetc = (!lh(/\.2chan\.net\//) || eleget0('#fivechthumbnailetc')) && 1
        GM_addStyle(".quoteSpeechBalloon{font-size:14px; position:relative; bottom:1px; color:#484; background-color:#ffffee;border-radius:1em; user-select:none; cursor:pointer;}") // qsb::
        GM_addStyle(".quoteSpeechBalloonImg{float:right; clear:right; max-height:2.8em !important; padding:4px; user-select:none; background-color:#ffffee; border-radius:6px; cursor:pointer;")
        GM_addStyle(".revQuote{cursor:pointer;color:#789922; margin:0.19em;}")
        document.querySelector(`head`).insertAdjacentHTML('beforeend', `<style>.waiting{ display: inline-block; vertical-align: middle; color: #666; line-height: 1; width: 1em; height: 1em; border: 0.12em solid currentColor; border-top-color: rgba(102, 102, 102, 0.3); border-radius: 50%; box-sizing: border-box; -webkit-animation: rotate 1s linear infinite; animation: rotate 1s linear infinite; } @-webkit-keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } @keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } }</style>`)

        let isfvw = eleget0('#fvw_menu')
        let replaceMainPopup = (FUTABA_HOVER_POPUP_REPLACE) || !is2chan
        if (is2chan && replaceMainPopup) { GM_addStyle("#slp{z-index:1001} .qtd{display:none !important;} .fvw_respop,#respopup_area{display:none;opacity:0}"); }
        $("#contres>a,#fvw_loading").attr("title", ($("#contres>a,#fvw_loading").attr("title") || "新着レスを読み込みます") + "\nE:リロード\nD/右クリック:リロード+新着にスクロール").on("contextmenu", (e) => {
          SITE.funcD();
          return false;
        })
        if (FUTABA_FLOAT_RELOAD_BUTTON) {
          $('#contres').attr("floated", "");
          GM_addStyle(`#contres{z-index:999; position:fixed; right:18em; left:auto; bottom:3px; height:auto; padding:0.1em 0.2em; border:2px solid #dddddd; background-color:#ffffff;}`)
        }
        pick2title(1)

        $(document).on("click", ".relallAreaon", e => SITE?.keyFunc?.find(v => v.id === "z")?.func(e.ctrlKey ? "Shift+Z" : "z"))

        // 自動リロード::
        if (FUTABA_RELOAD_INTERVAL >= 1) {
          var musousa = {
            last: Date.now(),
            elapsed: () => { return Date.now() - this.last },
            init: () => {
              this.last = Date.now();
              $('body').on('keydown mousedown mousemove', () => this.last = Date.now());
            },
          }
          musousa.init()
          setInterval(() => {
            if ((musousa.elapsed() < 30000 && document.activeElement.tagName.match(/textarea|input/i)) || eleget0('//span[@id="thread_down"]') || document.body.textContent.match("スレッドがありません|上限\d+レスに達しました")) return
            let r = eleget0('#contres>a,#fvw_loading')
            if (!r) return
            let inter = Math.max(60 * 1000, Math.min(Math.max(600000, (FUTABA_RELOAD_INTERVAL * 60 * 1000)), (FUTABA_RELOAD_INTERVAL * 60 * 1000) + (musousa.elapsed() >= 59000 && GF?.newarticle == 0 && GF.latestInterval / 1))) // 1分以上無操作の時リロードして新着がないと更新間隔を広げていく、最低1分最大10分
            if (!GF.latestReload || Date.now() - GF.latestReload >= inter) {
              if (FUTABA_DEBUG >= 1) end(document.body, `<div>update : ${gettime()} / 現在更新間隔:${~~(inter/1000)} / 新着:${GF?.newarticle} / リロード後経過秒:${~~((Date.now()-GF.latestReload)/1000)} / 無操作秒:${~~(musousa.elapsed()/1000)} / 前回:${GF.latestInterval/1000}</div>`)
              GF.latestReload = Date.now()
              GF.latestInterval = inter
              r?.click()
            }
            if (FUTABA_DEBUG >= 2) document.title = `${~~(inter/1000)}/${GF?.newarticle}/${~~((Date.now()-GF.latestReload)/1000)}/${~~(musousa.elapsed()/1000)} 現在更新間隔:${~~(inter/1000)} / 新着:${GF?.newarticle} / リロード後経過秒:${~~((Date.now()-GF.latestReload)/1000)} / 無操作秒:${~~(musousa.elapsed()/1000)} / 前回:${GF.latestInterval/1000}`
          }, 1000)
        }

        // c::ホバー下にそうだね
        var xTarget = []
        var cnoPushed = []
        var sodTarget = []
        var lastc = 0
        document.addEventListener('keypress', e => {
          if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true') return;
          var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
          var ele = document.elementFromPoint(mousex, mousey);
          var cno = eleget0('.cno', ele?.closest('table'))?.textContent?.replace(/\D/g, "")
          if (key == "c") $(ele?.closest('td')).effect("highlight")
          if (key == "c" && cno && !cnoPushed.includes(cno)) {
            cnoPushed.push(cno)
            xTarget.push({ key: key, cno: cno });
            xTarget = (Array.from(new Set(xTarget.map(v => JSON.stringify(v))))).map(v => JSON.parse(v)) // uniq:オブジェクトの配列→JSON文字列配列→uniq→オブジェクトの配列
            //end(eleget0('.sod', ele?.closest('td')), `<span class="waiting">+</span>`) // くるくるを表示
          }
        })
        setInterval(() => {
          if (Date.now() - lastc < 3500) return
          var a = xTarget.shift()
          if (!a) return
          let [key, cno] = [a.key, a.cno]
          let t = eleget0(`.cno:text*=${cno}`)?.closest('table')
          if (!t) return
          if (key == "c" && !t?.dataset?.soddone) {
            $('.waiting', t).remove()
            $('.sod', t).click().effect("highlight")
            lastc = Date.now()
            t.dataset.soddone = 1;
          }
        }, 200)

        // そうだねを改行しないようにする
        //document.body.addEventListener('copy', (event) => { $("#pickbox .sod:contains('x')").css({ "font-size": "125%", "float": "none" }); setTimeout(() => { $("#pickbox .sod:contains('x')").css({ "font-size": "125%", "float": "right" }) }, 1) });

        var sdset = () => { if (is2chan) elegeta('#pickbox .sod:not([onclick]),.ftbpu .sod:not([onclick])').forEach(e => { e.setAttribute("onclick", `sd(${e?.id.replace(/\D/g,"")});return(false);`) }) }
        $(document).on("click", "a.sod", (e) => { e.target.style.color = "#f00" }) //$(document).on("click","a.sod",(e)=>{e.target.style.textDecoration="underline"})

        $("#contres>a,#fvw_loading").on("click", (e => {
          GF.newarticle = 0
          let latestEle = eleget0('//*[@class="thre"]/table[last()]');
          //setTimeout(() => { document.body.dispatchEvent(new Event('2chanReloaded')) }, 1500)
          document.body.dispatchEvent(new Event('2chanReloadedNodelay'))
        })); // リロード再実行

        //new MutationObserver((e) => { let nodes = [...e.filter(v => v.addedNodes).map(v => [...v.addedNodes]).filter(v => v.length)].flat().filter(v => v.nodeType === 1).filter(v => v?.matches("table")); if (nodes.length) document.body.dispatchEvent(new Event('2chanReloaded')) })?.observe(eleget0('.thre'), { attributes: false, childList: true, subtree: false });

        //moq(eleget0('.thre:not(#pickbox .thre'), ".thre>table,.thre>div", v => { document.body.dispatchEvent(new Event('2chanReloaded')) })
        //moq(eleget0('.thre:not(#pickbox .thre'), ".thre>table,.thre>div:not(#pickbox .thre>div,#pickbox,.qtd,.slp)", v => {!GF.stopmoq && setTimeout(() => { document.body.dispatchEvent(new Event('2chanReloaded')) }, 1) })

        moq(eleget0('.thre:not(#pickbox .thre'), ".thre>table,.thre>div:not(#pickbox .thre>div,#pickbox,.qtd,.slp)", v => { // 新しいレスが追加されたら
          if (!GF?.arrival && !document.hasFocus()) {
            GF.arrival = 1;
            document.title = `■${document.title}`
          }
          if (!GF.stopmoq) {
            let newarticle = elegeta('.thre table .rtd .rsc:not([data-basec]),.thre table .res_no:not([data-basec])')
            GF.newarticle = newarticle.length || 0
            setTimeout(() => { document.body.dispatchEvent(new Event('2chanReloaded')) }, 1)
          }
        })
        document.addEventListener("focus", () => {
          if (GF?.arrival) {
            document.title = document.title.replace(/^■/, "");
            GF.arrival = 0
          }
        })

        function moq(observeNode, targetCSSSelector, cb) {
          new MutationObserver((m) => {
            let eles = [...m.filter(v => v.addedNodes).map(v => [...v.addedNodes]).filter(v => v.length)].flat().find(v => v.nodeType === 1 && v?.matches(targetCSSSelector));
            if (eles) cb(eles)
            //let eles = [...m.filter(v => v.addedNodes).map(v => [...v.addedNodes]).filter(v => v.length)].flat().filter(v => v.nodeType === 1 && v?.matches(targetCSSSelector));
            //if (eles.length) cb(eles)
          })?.observe(observeNode || document.body, { attributes: false, childList: true, subtree: false });
        }

        document.body.addEventListener('2chanReloadedNodelay', function() {
          $(`<hr class="reloadline" style="color:#aaa;">`).fadeIn("slow", function() { $(this).hide(0).fadeIn("slow") }).insertAfter($(elegeta('.thre table:not(#pickbox table,.ftbpu table,#respopup_area table,[floated] table)').pop()))
        }, false);
        $(document).on("scroll", () => {
          if (elegeta('.reloadline:not([found])').filter(e => isinscreen(e)).length) {
            $(elegeta('.reloadline')).attr("found", 1).delay(2000).hide("slow").delay(3000, function() { $(this).remove(); })
          }
        })
        /*
        document.body.addEventListener('2chanReloadedNodelay', function() {
          //    $(`<span style="font-size:0.8em;float:left;clear:both;" class="reloadline">${gettime("YYYY/MM/DD hh:mm:ss")} </span><hr class="reloadline" style="clear:both;color:#aaa;">`).fadeIn("slow", function() { $(this).hide(0).fadeIn("slow") }).insertAfter($(elegeta('.thre .reloadline,.thre table:not(#pickbox table,.ftbpu table,#respopup_area table,[floated] table)').pop()))
          //          $(`<hr class="reloadline" title="${gettime("YYYY/MM/DD hh:mm:ss")}" style="clear:right;color:#aaa;">`).fadeIn("slow", function() { $(this).hide(0).fadeIn("slow") }).insertAfter($(elegeta('.thre .reloadline,.thre table:not(#pickbox table,.ftbpu table,#respopup_area table,[floated] table)').pop()))
          $(`<hr class="reloadline" style="color:#aaa;">`).fadeIn("slow", function() { $(this).hide(0).fadeIn("slow") }).insertAfter($(elegeta('.thre .reloadline,.thre table:not(#pickbox table,.ftbpu table,#respopup_area table,[floated] table)').pop()))

        }, false);
        $(document).on("scroll", () => {
          if (elegeta('.reloadline:not([found])').filter(e => isinscreen(e)).length) {
            $(elegeta('.reloadline')).attr("found", 1).delay(2000).hide("slow").delay(3000, function() { $(this).remove(); })
          }
        })
*/

        if (location.href.match0("anige.horigiri")) GM_addStyle(`blockquote{color:#800000;line-height:1.2em;font-style:normal;`)

        $(elegeta('//table[@class="deleted"]|//tr/td[@class="rtd"]/blockquote[contains(text(),"del")]/../../../..')).attr("title", "クリックで復帰").attr("floated", "1").animate2({ "opacity": "0.3", "transform": "scale(0.8)", "transform-origin": "right", "float": "right" }, 500).one("click", function() {
          $(elegeta('//table[@class="deleted"]|//tr/td[@class="rtd"]/blockquote[contains(text(),"del")]/../../../..')).attr("title", "").animate2({ "opacity": "0.7", "transform": "scale(1)", "transform-origin": "right", "float": "none" }, 500);
          $(this)[0].scrollIntoView({ block: "nearest", behavior: "smooth" })
        }) // 隔離を薄くして右に

        $(document.body).append(`<script type="text/javascript">function scrRsc(n){let e=[...document.querySelectorAll('.rsc')].find(c=>c.textContent==n);if(e){e.closest(".rtd").style.outline="4px solid #0f0";setTimeout(()=>e.closest(".rtd").style.outline=null,1000)}e?.closest("table")?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}</script>`)
        //        $('head').append(`<script type="text/javascript">function scrRsc(n){let e=[...document.querySelectorAll('.rsc')].find(c=>c.textContent==n);if(e){e.closest(".rtd").style.outline="4px solid #0f0";setTimeout(()=>e.closest(".rtd").style.outline=null,1000)}e?.closest("table")?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}</script>`);//2022.11.30x

        //adja(document.body,"beforeend",`<script type="text/javascript">function scrRsc(n){let e=[...document.querySelectorAll('.rsc')].find(c=>c.textContent==n);if(e){e.closest(".rtd").style.outline="4px solid #0f0";setTimeout(()=>e.closest(".rtd").style.outline=null,1000)}e?.closest("table")?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}</script>`)
        ////var script = document.createElement( 'script' ); script.type = 'text/javascript'; script.innerText=`function scrRsc(n){let e=[...document.querySelectorAll('.rsc')].find(c=>c.textContent==n);if(e){e.closest(".rtd").style.outline="4px solid #0f0";setTimeout(()=>e.closest(".rtd").style.outline=null,1000)}e?.closest("table")?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}`; var firstScript = document.getElementsByTagName( 'script' )[ 0 ]; firstScript.parentNode.insertBefore( script, firstScript );

        // ニコ動埋め込み(PrivacyBadger等は要Disable)
        var embednv = () => {
          var elea = elegeta('a[href*="nicovideo"]:not([nde]),a[href*="//nico.ms/sm"]:not([nde])')
          //          for (let ele of elea.filter(e => isinscreen(e) || eleget0('.yhmMyMemo', e.closest("table")))) { // リロード回避のためpickされるものは先に読み込む
          for (let ele of elea.filter(e => eleget0('.yhmMyMemo', e.closest("table"))).concat(elea.filter(e => isinscreen(e)))) { // リロード回避のためpickされるものは先に読み込む
            let url = ele.href; //innerText.replace(/^ttp/i, "http");
            ele.setAttribute("nde", "nde");
            var nico = url.match(/h?ttps?:\/\/www.nicovideo.jp\/watch\/(.*)/i);
            if (!nico) var nico = url.match(/h?https:\/\/nico\.ms\/(.*)/i);
            if (!nico) continue
            $(ele?.closest("td,div.thre>blockquote:not([nde])")).append(`<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe class="ignoreMe" referrerpolicy="no-referrer" rel="nofollow external noopener noreferrer" allowfullscreen="allowfullscreen" allow="autoplay" src="https://embed.nicovideo.jp/watch/${nico[1]}${nico[1].match0(/\?/)?"&":"?"}persistence=1&amp;oldScript=1&amp;allowProgrammaticFullScreen=1" style="max-width: 100%;" width="312" height="176" frameborder="0"></iframe></p></blockquote>`) // 埋め込み外部プレイヤー版
            break; // 一度に1つずつしかやらない
          }
          if (elea.length) setTimeout(() => embednv(), 2000 + elea.length * 10);
        }
        autoPagerized(() => { embednv() })

        // youtube埋め込み
        var embedyt = () => {
          //          var elea = elegeta('a[href*="youtube.com"]:not([yte]),a[href*="youtu.be"]:not([yte])')
          var elea = elegeta('a[href*="youtube.com"]:not(#pickbox a,[yte]),a[href*="youtu.be"]:not(#pickbox a,[yte])')
          //          for (let ele of elea.filter(e => isinscreen(e) || eleget0('.yhmMyMemo', e.closest("table")))) { // リロード回避のためpickされるものは先に読み込む
          for (let ele of elea.filter(e => eleget0('.yhmMyMemo', e.closest("table"))).concat(elea.filter(e => isinscreen(e)))) { // リロード回避のためpickされるものは先に読み込む
            let url = ele.href //innerText;
            ele.setAttribute("yte", "yte");
            var sm = (url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11}).*[\?\&]t=(\d*).*$/i) || url.match(/h?ttps?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11}).*&t=(\d*).*$/i)) || url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.)?youtube\.com\/shorts\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11})/i);
            if (!sm) continue
            var pl = (url.match0(/[\&\?]list=([a-zA-Z0-9_\-]+)/));
            $(ele?.closest("td,div.thre>blockquote:not([yte])")).append('<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") + '" id="ytplayer" type="text/html" width=321 height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p></blockquote>');
            //            $(ele?.closest("td,div.thre>blockquote:not([yte])")).append('<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (sm[2] ? "?start=" + sm[2] : "") + '" id="ytplayer" type="text/html" width=321 height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p></blockquote>');
            break; // 一度に1つずつしかやらない
          };
          if (elea.length) setTimeout(() => embedyt(), 2000 + elea.length * 10);
        }
        autoPagerized(() => { embedyt() })

        // fu画像埋め込み
        var embedimg = () => {
          var elea = elegeta('.rtd blockquote:not([ime]),div.thre>blockquote:not([ime])')
          //          for (let ele of elea.filter(e => isinscreen(e) || eleget0('.yhmMyMemo', e.closest("table")))) { // 画面内にあるものだけが基本だけどリロード回避のためpickされるものは優先的に読み込む
          for (let ele of elea) { // 画面内にあるものだけが基本だけどリロード回避のためpickされるものは優先的に読み込む
            let txt = ele.innerText;
            ele.setAttribute("ime", "ime");
            var sm = txt.match(/^fu?\d+\.(jpg|jpeg|png|gif|bmp|webp)$/gmi);
            //            if (sm?.length) sm.forEach(v => $(ele?.closest("td,div.thre>blockquote")).append(`<blockquote style=""><p class="ignoreMe" style="margin:0 0 0px;"><img class="ignoreMe" referrerpolicy="no-referrer" style="max-height:125px;" src="https://${/^fu\d+\./.test(v)?"dec.2chan.net/up2/src/":"dec.2chan.net/up/src/"}${v}" </blockquote>`))
            if (sm?.length) {
              sm.forEach(v => $(ele?.closest("td,div.thre>blockquote")).append(`<blockquote style="margin-top:0;"><p class="ignoreMe" style="margin:0 0 0px;"><img class="ignoreMe" referrerpolicy="no-referrer" style="max-height:250px;" src="https://${/^fu\d+\./.test(v)?"dec.2chan.net/up2/src/":"dec.2chan.net/up/src/"}${v}"></p></blockquote>`))
              //ele.style.marginBottom="0"
            }
            var sm = txt.match(/^fu?\d+\.(mp4|webm)$/gmi);
            //            if (sm?.length) sm.forEach(v => $(ele?.closest("td,div.thre>blockquote")).append(`<blockquote style=""><p class="ignoreMe" style="margin:0 0 0px;"><video controls="" name="media" src="https://${/^fu\d+\./.test(v)?"dec.2chan.net/up2/src/":"dec.2chan.net/up/src/"}${v}"" style="max-height:125px;" class="ignoreMe"></video></blockquote>`)) // preload="none"
            if (sm?.length) {
              sm.forEach(v => $(ele?.closest("td,div.thre>blockquote")).append(`<blockquote style="margin-top:0;"><p class="ignoreMe" style="margin:0 0 0px;"><video controls="" name="media" src="https://${/^fu\d+\./.test(v)?"dec.2chan.net/up2/src/":"dec.2chan.net/up/src/"}${v}"" style="max-height:250px;" class="ignoreMe"></video></p></blockquote>`)) // preload="none"
              //ele.style.marginBottom="0"
            }
            //break; // 一度に1つずつしかやらない
          };
          //if (elea.length) setTimeout(() => embedimg(), 2000 + elea.length * 10);
        }
        autoPagerized(() => { embedimg() })

        var popped = []
        $(eleget0('//td/input[@value="返信する"]')).on("click", () => { setTimeout(() => shikomi(), 999) })
        // 引用ポップアップ仕込み
        var cited = [];
        var resEnum = [];

        function shikomi() {
          $(elegeta('.cnw:not([idw])').filter(v => /ID\:|IP\:/.test(v.innerText))).attr("idw", "1").css({ 'color': '#f00', 'font-weight': '800' })
          //          elegeta('.thre table .rtd .rsc,.thre table .res_no').forEach(e => {
          //GF.newarticle=newarticle.length||0
          //let newarticle=elegeta('.thre table .rtd .rsc:not([data-basec]),.thre table .res_no:not([data-basec])')
          elegeta('.thre table .rtd .rsc:not([data-basec]),.thre table .res_no:not([data-basec])').forEach(e => {
            e.dataset.basec = "1"
            e.style.cursor = "pointer"
            //            e.setAttribute("onclick", "let num=this.textContent; let e=[...document.querySelectorAll('.rtd>.rsc,.thre table .res_no')].find(c=>c.textContent==num); if(e){e?.closest('table').scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}"); //クリックで中心にスクロール
            //            e.setAttribute("onclick", "[...document.querySelectorAll('.rtd>.rsc,.thre table .res_no')].find(c=>c.textContent==this.textContent)?.closest('table')?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}"); //クリックで中心にスクロール
            e.setAttribute("onclick", `scrRsc(${Number(e.textContent)})`); //クリックで中心にスクロール
            let resno = e?.textContent
            e.closest('table').setAttribute("rsc", resno)
            e.closest('.rtd').dataset.rsc = resno
            e.closest('table').dataset.rsc = resno
          })
          //elegeta('.thre table tr').filter(e => !eleget0('.quo', e)).forEach(e => e.insertAdjacentHTML("beforeend", `<td class="quo"><span class="memo"></span></td>`))
          //          elegeta('.thre table tr:not([data-quospan])').forEach(e => { e.dataset.quospan = "1"; if (!eleget0('.quo', e)) { e.insertAdjacentHTML("beforeend", `<td class="quo"><span class="memo"></span></td>`) } })

          addstyle.add('.relallArea{position:absolute; bottom:0; text-align:center; line-height:1.5em; color:#78992280; width:1.5em; height:1.5em; }') //background-color:#eed;
          addstyle.add('.relallAreaon{outline:2px dotted #789922c0; margin:1px; cursor:pointer;}') //background-color:#eed;

          elegeta('.thre table tr:not([data-quospan])').forEach(e => {
            e.dataset.quospan = "1";
            //        e.insertAdjacentHTML("beforeend", `<td class="quo"><span class="memo"></span></td>`)
            e.insertAdjacentHTML("beforeend", `<td class="ignoreMe quo" style="position:relative;"><span class="ignoreMe memo"></span><span class="ignoreMe relallArea"> </span></td>`)
          })

          // 逆引用を追加
          var issorted = eleget0('#sortType2') || eleget0('#sortType1')
          resEnum = [];
          cited = [];
          var resa = elegeta('.thre table .rtd:not(#pickbox .rtd,.ftbpu .rtd,#respopup_area .rtd)').sort((a, b) => { return (Number(a.dataset.rsc) - Number(b.dataset.rsc)) })
          elegeta(".revQuote:not(#pickbox .revQuote,.ftbpu .revQuote)").forEach(e => e?.remove())

          //test: 5578ms - タイマー終了 test: 5327ms - タイマー終了
          elegeta('.thre table .rtd blockquote font:not(#pickbox font,.ftbpu font,#respopup_area font),.thre table .rtd blockquote p font:not(#pickbox font,.ftbpu font,#respopup_area font)').forEach((h, i) => { //緑文字の引用行文字列
            var eWord = h.textContent.match(/^\>+(.+)$/)?.[1]; // >***の***部分 // oこれだと>>No.*への逆引用がつくのは「>No.*」と「No.*」の両方に逆引用がつく x本当にレスしている対象より前の初出のレスだけに逆引用がついてしまう
            //var eWord = h.textContent.match(/^\>(.+)$/)?.[1]; // >***の***部分 // xこれだと>>No.*への逆引用がつくのは「>No.*」だけになり「No.*」にはつかない o本当にレスしている対象より前のものだけに逆引用がついてしまう
            if (eWord) {
              //h.style.cursor="pointer" //これをやるとちょっとうるさい
              var greenResNo = h.closest('table').dataset.rsc; //緑文字列があるレスのレス番
              resa.filter(e => e.textContent.indexOf(eWord) !== -1).forEach((c, i) => { // c=***が含まれるレス
                let n = c.dataset.rsc; // ***が含まれるレスのレス番
                if (i === 0 && !(!resEnum[n] && n === greenResNo)) { // i==0つまりスレの初出のそれにしかヒットしない
                  let r = eleget0(".relallArea", h.closest('table'))?.classList.add("relallAreaon") // >>100があったらrelallOn
                  eleget0(".relallArea", c.closest('table'))?.classList.add("relallAreaon") // >あいう の対象レスが本当に存在したらrelallOn
                  if (!resEnum[n]) resEnum[n] = []
                  if (!resEnum[n].includes(greenResNo)) {
                    resEnum[n].push(greenResNo)
                    end(c.parentNode.querySelector(".quo"), `<font class="revQuote" data-resenum="${resEnum[n]}" data-rsc="${n}" onclick="scrRsc(${greenResNo})">&gt;&gt;${greenResNo}</font>`) //クリックで中心にスクロール
                  }
                }
              })
            }
          })

          // >No.○に本文の引用を追加 qsb::
          if (FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY && fivechthumbnailetc) { //} || lh("ftbucket|kuzure")) {
            var quos = elegeta('.thre table .rtd blockquote font:not([data-quoted],#pickbox font,.ftbpu font,#respopup_area font),.thre table .rtd blockquote p font:not([data-quoted],#pickbox font,.ftbpu font,#respopup_area font)').filter(v => v.innerText.match(/>+No\.|>+\d|>+fu/))
            quos.filter(e => /^\>+No\.\d+$/m.test(e?.textContent)).forEach((e, i) => { //緑文字の引用行文字列
              e.dataset.quoted = 1
              var srcTable = elegeta(".cno").find(v => v?.textContent?.replace(/\D/g, "") == e?.textContent?.replace(/\D/g, ""))?.closest("table[rsc]")
              if (srcTable && srcTable != e?.closest("table[rsc]")) {
                var origno = e?.textContent
                var lead = eleget0('blockquote', srcTable)?.innerText?.replace(/^\s*>+.*$/gm, "")?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
                if (!lead) lead = eleget0('blockquote', srcTable)?.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
                if (lead?.slice(33)?.length) lead = lead?.slice(0, 33)?.trim() + "…"
                lead = lead?.replace(/\n/gm, " ")
                //                lead && adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
                if (lead) {
                  adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
                }
                var srcImg = eleget0("img", srcTable)?.cloneNode()
                if (srcImg) {
                  srcImg.removeAttribute("width")
                  srcImg.removeAttribute("height")
                  srcImg.dataset.quoteno = origno
                  srcImg.className = "quoteSpeechBalloonImg"
                  srcImg.removeAttribute("hspace")
                  srcImg.removeAttribute("align")
                  srcImg.dataset.zoomonhover = "disable"
                  srcTable && e.appendChild(srcImg)
                } //else end(e,`<div style="float:right"></div>`) // このdivはinnerTextに改行を追加する意味がある
              }
            })
            // >>○.jpgに本文の引用を追加 qsb::
            quos.filter(e => /^\>+\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)$/m.test(e?.textContent)).forEach((e, i) => { //緑文字の引用行文字列
              e.dataset.quoted = 1
              var srcTable = elegeta(".rtd").find(v => { return v?.textContent?.match(/\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/)?.[0] == e?.textContent?.replace(/\>+/, "") })?.closest("table[rsc]")
              if (srcTable && srcTable != e?.closest("table[rsc]")) {
                var origno = e?.textContent
                var lead = eleget0('blockquote', srcTable)?.innerText?.replace(/^\s*>+.*$/gm, "")?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
                if (!lead) lead = eleget0('blockquote', srcTable)?.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
                if (lead?.slice(33)?.length) lead = lead?.slice(0, 33)?.trim() + "…"
                lead = lead?.replace(/\n/gm, " ")
                var srcImg = eleget0("img", srcTable)?.cloneNode()
                if (lead) {
                  adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
                }
                if (srcImg) {
                  srcImg.removeAttribute("width")
                  srcImg.removeAttribute("height")
                  srcImg.dataset.quoteno = origno
                  srcImg.className = "quoteSpeechBalloonImg"
                  srcImg.removeAttribute("hspace")
                  srcImg.removeAttribute("align")
                  srcImg.dataset.zoomonhover = "disable"
                  srcTable && e.appendChild(srcImg)
                } //else end(e,`<div style="float:right"></div>`) // このdivはinnerTextに改行を追加する意味がある
              }
            })
            // >fu○.jpgに本文の引用を追加 qsb::
            quos.filter(e => /^\>+fu\d+\.(jpg|jpeg|png|gif|bmp|webp)$/m.test(e?.textContent)).forEach((e, i) => { //緑文字の引用行文字列 fu*
              e.dataset.quoted = 1
              var srcTable = elegeta(".rtd").find(v => elegeta('img', v).find(w => w?.src?.indexOf(e?.textContent?.replace(/\>+/, "")) !== -1))?.closest("table[rsc]")
              if (srcTable && srcTable != e?.closest("table[rsc]")) {
                var origno = e?.textContent
                var lead = eleget0('blockquote', srcTable)?.innerText?.replace(/^\s*>*fu\S+\s*/gm, "")?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
                //if (!lead) lead = eleget0('blockquote', srcTable)?.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
                if (lead?.slice(33)?.length) lead = lead?.slice(0, 33)?.trim() + "…"
                lead = lead?.replace(/\n/gm, " ")
                var srcImg = elegeta('img', srcTable).find(w => w?.src?.indexOf(e?.textContent?.replace(/\>+/, "")) !== -1)?.cloneNode()
                if (lead) {
                  adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
                }
                if (srcImg) {
                  srcImg.dataset.quoteno = origno
                  srcImg.className = "quoteSpeechBalloonImg"
                  srcImg.dataset.zoomonhover = "disable"
                  srcTable && e.appendChild(srcImg)
                } //else end(e,`<div style="float:right"></div>`) // このdivはinnerTextに改行を追加する意味がある
              }
            })
          }
        }

        // .relAllAreaon枠に連鎖レス数を書き入れていく
        if (FUTABA_EXPERIMENTAL_DISPLAY_CHAINED) {
          GF.resChained = []
          setTimeout(() => reschain('#pickbox .relallAreaon:not([data-filled])'), 4000) // 最初はピックアップにあるものだけ最速でやる
          if (lh(".2chan.")) document.body.addEventListener('2chanReloaded', () => setTimeout(reschain, 2000), false)

          function reschain(dash = null) {
            let org
            if (!GF.resChained || !GF.resChained?.length) {
              GF.resChained = elegeta(dash ? dash : '.thre .relallAreaon:not([data-filled],.ftbpu .relallAreaon,#pickbox .relallAreaon)')
              GF.resTotal = elegeta('.thre .rtd').length
            }
            do {
              do {
                org = GF.resChained.shift()
              } while (org && org?.dataset?.filled)
              if (org) {
                let rsc = org.closest('[data-rsc]')?.dataset?.rsc
                let lists = getRelatedRsca(rsc)
                lists.forEach(v => {
                  elegeta('table[data-rsc="' + v + '"] .relallAreaon').forEach(w => {
                    w.innerText = lists?.length
                    w.dataset.filled = "1"
                    if (debug) $(w).effect("highlight"); //org.areaonEle.scrollIntoView()
                  })
                })
              }
            } while (dash && org)
            setTimeout(reschain, (org || dash) ? ((GF?.resTotal || 9) * 3 + 100) : 60000)
          }
        }

        autoPagerized(() => {
          GF.stoppick = 1;
          memofast = 1;
          run(document.body, "observed");
          GF.stoppick = 0;
          memofast = false;
        }, "not1st")
        autoPagerized(() => shikomi())
        //        autoPagerized((node) => {run()},"not1sttime")

        // onclick,html埋め込み,レス番,不安
        autoPagerized((node) => {
          //          elegeta('blockquote font,.quoteSpeechBalloon,.quoteSpeechBalloonImg', node).filter(v => !v.onclick && (v?.dataset?.quoteno || /^>+/gm.test(v.textContent))).forEach(e => {//test: 1017ms - タイマー終了
          elegeta('blockquote font:not([onclick]),.quoteSpeechBalloon:not([onclick]),.quoteSpeechBalloonImg:not([onclick])', node).filter(v => /^>./gm.test(v.textContent?.trim())).forEach(e => { //test: 832ms - タイマー終了
            //            let r = [...document.querySelectorAll(".thre table")].find(v => v.textContent.indexOf(e?.dataset?.quoteno?.match(/^>(.+)$/)?.[1].trim() || e.textContent.replace(/^>+/gm, "").trim()) != -1) || null
            //            let r = [...document.querySelectorAll(".thre table")].find(v => v.textContent.indexOf(e?.dataset?.quoteno?.match(/^>(.+)$/)?.[1].trim() || e.textContent.replace(/^>/gm, "").trim()) != -1) || null
            let etext = e?.dataset?.quoteno?.match(/^>(.+)$/)?.[1].trim() || e.textContent.replace(/^>/gm, "").trim()
            let r = [...document.querySelectorAll(".thre table")].find(v => v.textContent.indexOf(etext) !== -1) || null
            //            let no = eleget0('.rsc', r?.closest("table"))?.textContent
            e.setAttribute("onclick", `scrRsc(${eleget0('.rsc', r)?.textContent})`) //クリックで中心にスクロール
          })
        })

        // レス番rscに引用・非引用が連鎖するレスのレス番rscを全て配列で返す rsc => [rsc,rsc,rsc,...]
        function getRelatedRsca(rsc) {
          let tableRsc = elegeta('table[data-rsc]').sort((a, b) => a.dataset.rsc === b.dataset.rsc ? 0 : Number(a.dataset.rsc) > Number(b.dataset.rsc) ? 1 : -1) // レステーブル[登場順]
          let tableRscOrder = [] // レステーブル[rsc]
          elegeta(`table[data-rsc]`).forEach(v => tableRscOrder[v.dataset.rsc] = v) // 速度のためにキャッシュする
          let ress = getRelCno([rsc], tableRsc, tableRscOrder)
          while (1) {
            let r = getRelCno(ress, tableRsc, tableRscOrder)
            if (r.length <= ress.length) { ress = r; break }
            ress = r
          }
          if (ress?.length < 2) return null //lists = null
          return ress
        }

        function getRelCno(resa, tableRsc, tableRscOrder) {
          let a = resa || []
          resa.forEach(res => {
            a = a.concat(elegeta(`.quo .revQuote`, tableRscOrder[res]).map(v => v.innerText.replace(/^>>/, ""))) // test: 6137ms - タイマー終了
            let rscText = elegeta(`blockquote font[color="#789922"]`, tableRscOrder[res]).map(e => e?.innerText?.replace(/^>/, "")?.trim())
            rscText.forEach(v => a.push(tableRsc.find(w => w.innerText.indexOf(v) !== -1)?.dataset.rsc)) // 最初の1つめの>abcだけにヒット
          })
          return [...new Set(a?.flat())].filter(v => v !== undefined && v !== null).sort()
        }

        // 引用ホバー hover::
        GM_addStyle(".rtdAttract{background-color:#fed;}")
        if (location.href.match0(/ftbucket/) && !eleget0(`.csb`)) GM_addStyle(".rsc,.cnw,.cno{padding:0 0.5em 0 0;}")
        var latestHover;
        var latestlevel = 0
        var latestPU

        if (FUTABA_HOVER_POPUP_DELAY == -1) { document.addEventListener("mousemove", function(e) { hover() }, false); } else { hover_enter() }

        function hover_enter() {
          hover();
          setTimeout(hover_enter, 1 * 17);
        }

        function hover() {
          if (!replaceMainPopup) return
          hovertimer++;
          let ele = document.elementFromPoint(mousex, mousey);
          if (ele !== latestHover) latestPU = 0
          if (ele && (FUTABA_HOVER_POPUP_DELAY || (ele && latestHover != ele))) {
            var quoteDesEle = ele.matches('table FONT,table .quoteSpeechBalloon,table .quoteSpeechBalloonImg,.relallArea') ? ele : null; //ホバーしている黄土色文字の要素群
            var hoverEle = quoteDesEle; //ele.tagName === "FONT" && ele.closest("table") ? [ele] : []; //ホバーしている黄土色文字の要素群

            let level = Number(ele.closest(".ftbpu")?.dataset.level || 0);
            var lists = []
            //if (debug) V&&dc("quoteDesEle:" + quoteDesEle?.tagName)
            if ((quoteDesEle && latestPU !== ele) && ((FUTABA_HOVER_POPUP_DELAY == 0 && latestHover != quoteDesEle) || (FUTABA_HOVER_POPUP_DELAY && hovertimer >= (Math.max(hoverEle?.closest('#pickbox,.ftbpu') && FUTABA_HOVER_POPUP_DELAY != -1 ? 2 : 0, FUTABA_HOVER_POPUP_DELAY))))) { // ピックアップの中では遅延を少なくとも3にする
              //var eWord = quoteDesEle?.textContent?.match0(/^\>+(.+)$/)?.trim(); // 引用文
              var eWord = quoteDesEle?.dataset?.quoteno?.match0(/^\>+(.+)$/)?.trim() || quoteDesEle?.textContent?.match0(/^\>+(.+)$/)?.trim(); // 引用文 // >の入れ子数を無視してすべて遡る
              //var eWord = quoteDesEle?.dataset?.quoteno?.match0(/^\>(.+)$/)?.trim() || quoteDesEle?.textContent?.match0(/^\>(.+)$/)?.trim(); // 引用文 // >の入れ子数を忠実に遡る
              var resa = elegeta('.rtd').filter(e => !e.closest("#pickbox,.ftbpu,#respopup_area"))
              var hit0no = (replaceMainPopup && resa.find(a => a.textContent && a.textContent.indexOf(eWord) != -1))?.dataset?.rsc; //ヒットした最初のレス番号
              if (hit0no < 0) return;
              var motoNumber = hoverEle.closest('table').getAttribute("rsc"); // ホバーしているレスのレス番号

              var hitResNo = hoverEle.dataset.rsc; // rscがある=レスの右側に追加した>>100型逆引用である、そのレス番号
              var relAll = ele.matches(".relallArea:not(.ftbpu .relallArea)") && ele?.closest("table")?.dataset?.rsc // …:全関連レス

              if (relAll) { // relall::…:全関連レスモード
                $(".ftbpu").remove();
                lists = getRelatedRsca(relAll)
              } else

              if (hitResNo) { // >>100:逆引用モード
                var lists = []
                resa.forEach(c => { if (c.dataset.rsc == hitResNo) lists.push(c.closest("table").dataset.rsc) })
                resEnum[hitResNo].forEach(e => resa.forEach(c => { if (c.dataset.rsc == e) lists.push(c.closest("table").dataset.rsc) })); // rscがある=レスの右側に追加した逆引用である、そのレス番号
              } else {
                // レス本文内の引用
                if (motoNumber) {
                  //                  var quoteStr = quoteDesEle?.textContent?.match0(/^\>+(.+)$/)?.trim(); // 文字列
                  var quoteStr = eWord; //quoteDesEle?.textContent?.match0(/^\>+(.+)$/)?.trim(); // 文字列
                  if (quoteStr) {
                    var hitEles = resa.filter(e => e.textContent.indexOf(quoteStr) !== -1)
                    if (hitEles.length) {
                      var hoverResNo = (replaceMainPopup && hoverEle.getAttribute("rsc")) //ホバーしているレス番号
                      //hits[0].classList.add("rtdAttract")
                      var lists = hitEles.map(e => e.closest("table").dataset.rsc)
                    }
                  }
                }
              }

              // 表示
              if (hitResNo || lists) {
                latestPU = ele
                lists = lists.sort((a, b) => a - b)
                var hit0no = lists[0] //tables[0][0].getAttribute("rsc") //ヒットした最初のレス番号
                //var restable = elegeta('//td[@class="rtd"]/ancestor::table').filter(e => !e.closest("#pickbox,.ftbpu,#respopup_area"))
                var restable = elegeta('.rtd:not(#pickbox .rtd,.ftbpu .rtd,#respopup_area .rtd)').map(e => e.closest("table"))
                var tables = lists.map(c => $(restable.find(e => e.dataset.rsc == c)).clone(true, true))
                var lists2 = (hit0no == motoNumber) ? lists.slice(1) : lists
                debug && dc(`list : ${lists}\nlist2 : ${lists2}`, 0)
                debug && dc("既存:" + elegeta('.ftbpu').find(e => lists == e.dataset.list || lists2 == e.dataset.list2 || lists == e.dataset.list2)?.dataset.list)
                if (
                  !(elegeta('.ftbpu').find(e => lists == e.dataset.list || lists2 == e.dataset.list2 || lists == e.dataset.list2))
                ) { // まだ重複するポップアップがなければ
                  debug && dc(`list-sorted : ${lists}`, 0)

                  var pu = $(`<span data-anker="${hit0no}" class="ftbpu ${relAll?"relAll ":""}ignoreFilter entry-content" data-list="${lists}" data-list2="${lists2}" data-level="${1+Number(level)}" style="z-index:2000000020; padding:5px; box-shadow:2px 2px 15px #000a; border-radius:2px; background-color:${ftbBGC}; margin:0 1em 3px 3px; outline:1px solid #999; position:absolute; top:${$(quoteDesEle).offset().top+quoteDesEle.getBoundingClientRect().height-1}px;" ondblclick="this.remove();"><table style="table-layout:auto;"></table></span>`); //ヒットした全部をポップアップする版

                  if (!relAll && hit0no == motoNumber) { tables.shift() } // 1個目の引用が自分自身なら削除
                  if (tables.length) {
                    tables.forEach(e => { $(pu).append(e) });
                    $(".thre:first()").append(pu)
                    if (!relAll) $(pu).find(".quoteSpeechBalloon").remove()
                    //                reso[hoverEles[0].getAttribute("rscf") || hit0no].classList.add("rtdAttract")
                    $('.ftbpu table').fadeIn(300)

                    let xr = (mousex - 20 + $(pu).width() > window.innerWidth) ? ($(pu).css({ "right": "0px" }), 1) : ($(pu).css({ "left": `${Math.max(4,mousex-20)}px` }), 0)

                    // 少し縮小するか?
                    let eleBottomY = $(quoteDesEle).offset().top - $(window).scrollTop() + $(quoteDesEle).outerHeight() + 1;
                    let eleTopY = $(quoteDesEle).offset().top - $(window).scrollTop() // + $(quoteDesEle).outerHeight() + 1;
                    let eleHeight = $(quoteDesEle).height();
                    let puHeight = $(pu).height() + 10 // + 15;
                    let bottomMargin = Math.min(window.innerHeight, document.documentElement.clientHeight) - eleBottomY
                    let upMargin = (quoteDesEle.getBoundingClientRect().top)
                    let originx = window.innerWidth - mousex
                    // 画面の下のほうより上のほうが大きくあいていれば上に表示
                    if (puHeight > bottomMargin && upMargin > puHeight) {
                      $(pu).css({ "top": `${$(window).scrollTop()+eleTopY-puHeight}px` })
                    } else {
                      // 少し縮小する
                      if (bottomMargin / puHeight < 1) $(pu).css({ "transform-origin": xr ? `${$(pu).width()-(window.innerWidth-mousex)+40}px 0px` : "top left" }).delay(100).animate2({ "transform": `scale(${Math.max(futabapopupscale/100,bottomMargin/(puHeight+5))})`, "opacity": "1" }, 100)
                    }

                    domsort(pu[0], elegeta('//table', pu[0]), v => -v.getAttribute("rsc"))
                    sdset()

                    $(".ftbpu .relallArea").remove()
                    // z使用モード
                    GF?.zFunc && GF?.zFunc()
                  }
                }
              }
            } else {
              if (!hoverEle && eleget0('.ftbpu') && !(ele.closest(".ftbpu") || ele.closest("#slp") || ele.closest(".fvw_respop") || eleget0("#pdm"))) {
                $(".ftbpu").remove();
                $(".rtdAttract").removeClass("rtdAttract")
              }
              if (latestHover != ele && ele.closest(".ftbpu,#slp,.fvw_respop")) { // levelが低い要素に降りたら上のは消す
                elegeta(".ftbpu").forEach(e => { if (e?.dataset?.level > level) { e.remove() } })
              }
            }
          }
          latestlevel = ele?.closest(".ftbpu")?.dataset?.level || 0
          latestHover = ele; //V&&dc("latest:"+latestHover?.tagName)
        }

        // pick::メモの付いたレスを右上に列挙
        var pick_overflow;
        if (is2chan || isftb || isftchan || iskurokako) {
          var pick = (force = 0) => {
            if (GF.stoppick) return;
            if (window.getSelection() == "" && $("#pickbox:hover").length == 0 && $('#pickbox:hidden').length == 0) {
              //              var res = [...new Set($.makeArray($('.thre table:has(span.yhmMyMemo)')))].filter(e => !e.closest("#pickbox,.ftbpu")); // 埋め込み動画はロードが発生するので無視
              var res = [...new Set($.makeArray($('.thre table:has(span.yhmMyMemo)')))].filter(e => !e.closest("#pickbox,.ftbpu")); // 埋め込み動画はロードが発生するので無視
              GF.presentPick = res
              let update = (GF.res !== JSON.stringify(res.map(e => e.innerText).sort()))
              if (update || force) {
                GF.res = JSON.stringify(res.map(e => e.innerText).sort())
                if (debug) popup2("更新:" + GF.res.slice(0, 200))
                if (!pick_overflow) {
                  var p = eleget0('#pickbox:not(:hover)');
                  if (p && p?.scrollHeight > p?.offsetHeight) { pick_overflow = 1; }
                }
                $("#pickbox").remove();
                if (res.length) {
                  let threR = $('#rightadfloat:visible')[0] ? document.documentElement.clientWidth - ($(".thre").offset().left + $('.thre').outerWidth()) : 3
                  if (1 || document.documentElement.clientWidth - threR > 1300) {
                    $.makeArray($(".thre")).filter(e => !e.closest("#pickbox,.ftbpu"))[0].insertAdjacentHTML("beforeend", `<div id='pickbox' class='ignoreFilter' floated="" style='z-index:1; max-height:calc(${(100)*(100/futabapicksize)}vh - ${8*(100/futabapicksize)}em) ; overflow-y:auto; max-width:${55}%; opacity:0.9; outline:2px #8888 solid; position:fixed; top:6px; right:${threR+2}px; background-color:#ffffeecc;  transform:scale(${futabapicksize/100}); transform-origin:top right;'></div>`)
                    let pickbox = eleget0("#pickbox")
                    res.forEach(e => { pickbox.appendChild($(e).clone(true, true).css({ "display": "revert", "margin-left": "auto", "margin-right": "0" })[0]) })
                    elegeta('.quoteSpeechBalloon', pickbox).forEach(e => { if (e?.textContent?.length > 18) { e.textContent = e.textContent.slice(0, 18) + "…" } })
                    //                    elegeta('.quoteSpeechBalloon',pickbox).forEach(e=>{e.style.width="10em";e.style.textOverflow="ellipsis";})
                    $("#pickbox .sod:contains('x')").css({ "font-size": "125%", "float": "right" })
                    if (pick_overflow) {
                      $("#pickbox img").css({ "width": "auto", "max-height": Math.max(50, 125 - res.length * 5) + "px" });
                      $("#pickbox blockquote").css({ "margin": "5px 40px" })
                    }
                    $("#pickbox .relallAreaon").css({ "right": "1px" }) //,"z-index":"-1"})
                    $("#pickbox .revQuote").after("<br>"); //css({ "display": "inline-block" })
                    $("#pickbox .yhmMyMemo,.revQuote").css({ "user-select": "none" })
                    if (update) { $("#pickbox").css({ "outline": "#f00 5px solid" }).delay(100).queue(() => { $("#pickbox").css({ "outline": "2px #8888 solid" }) }) }
                    domsort(pickbox, elegeta('//table', pickbox).filter(e => e.closest("#pickbox")), v => -v.getAttribute("rsc"))
                    sdset()
                    GF?.zFunc && GF?.zFunc()
                  }
                }
                pick2title(20)
              }
            }
            setTimeout(() => pick(), 2000)
          }
          setTimeout(pick, 2000)

          setInterval(() => {
            if (futabapicksize == futabapicksizeL) return;
            var p = eleget0('#pickbox:not(:hover)')
            if (p) {
              var lr = elegeta('.rtd')?.filter(e => isinscreen(e, 1) && !e?.closest("#pickbox,.ftbpu,#respopup_area,[floated]"))?.map(e => { let r = e.getBoundingClientRect().right; return e?.closest('table')?.querySelector('.revQuote,.relallArea')?.getBoundingClientRect()?.right + 4 || r + 2 }).reduce((a, b) => a > b ? a : b, 0) || 0 //test 175 / 1sec
              var big = p.getBoundingClientRect().left - lr
              var bigabs = Math.abs(big)
              if (p.scrollHeight > p.offsetHeight) {
                futabapicksize = Math.max(futabapicksizeL, futabapicksize - (p.scrollHeight - p.offsetHeight) / 62);
                pick_overflow = 1;
                pick(1)
              } else if (big < 0) {
                //var ff = elegeta('td.rtd')?.filter(e => isinscreen(e, 1) && !e?.closest("#pickbox,.ftbpu,#respopup_area,[floated]")) // ←ffをどこで使うのか分からない 画面内に見えている左側のレスたち
                futabapicksize = Math.max(futabapicksizeL, futabapicksize - bigabs / 52);
                p.style.transform = `scale(${futabapicksize/100})`
                debug && dc("picksize:" + futabapicksize, 1)
              }
            }
          }, 52)
          //}, 60)

          window.addEventListener('resize', () => {
            futabapicksize = 100;
            pick(1)
          })
          //window.addEventListener('focus', () => { futabapicksize = 100; pick(1) }) // ややうるさい

          setTimeout(() => {
            let slider = eleget0('#pickbox') ? [eleget0('/HTML/BODY/HR[2]'), "style=' position:fixed; right:8em; bottom:0.5em; font-size:11px; transform:scale(0.9); display:block;'", "style=' position:fixed; right:20em; bottom:0.5em; font-size:11px; transform:scale(0.9); display:block;'"] : [eleget0(`//span[@id="hml"]/..`), "style='float:left; font-size:13px; transform:scale(0.9);'", "style='float:left; font-size:13px; transform:scale(0.9);'"]

            setSlider(slider[0], 30, 100, futabapicksizeDefault, "ピックアップの最小スケール:***%", "FUTABA_pickupSize", (val) => {
              futabapicksizeL = val;
              futabapicksize = Math.min(100, ++futabapicksize);
              pick(1);
              //            }, 0, slider[1])
            }, 0, slider[1])

            //            setSlider(slider[0], 50, 100, 95, "ポップアップの最小スケール:***%", "FUTABA_popupScale", (val) => { futabapopupscale = val; }, 0, slider[2]);
            setSlider(slider[0], 50, 100, 95, "ポップアップの最小スケール:***%", "FUTABA_popupScale", (val) => { futabapopupscale = val; }, 1, slider[2]);
          }, 2100)
        }

        function pick2title(len) {
          var suff = document.title.match0(/(\s-\s.*)/)
          let intro = elegeta('.thre>blockquote,#pickbox blockquote:visible')?.slice(0, len)?.map(e => e.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "").replace(/\n/gm, " "))?.join(" ")?.replace(/[ \s\u200B-\u200D\uFEFF\u2028\u2029\u200eㅤ]{1,99}/g, " ")
          if (is2chan && intro && suff) { // 0とpickのレス100文字までページタイトルにする
            if (intro) document.title = document.title = `${intro}`?.slice(0, 100) + suff
          }
        }
      },
    },
    {
      id: 'www.uniqlo.com',
      urlRE: '//www.uniqlo.com/',
      listTitleXP: '//a/div[2]/h3',
      listTitleSearchXP: '//a/div[2]/h3[+++]/../../..',
      listTitleMemoSearchXP: '//a/div[2]/h3[+++]|//h1[@data-test="product-name"][+++]',
      listGen: 6,
      redoWhenReturned: 1,
      delay: 500,
      observe: 500,
      detailURLRE: /\/www.uniqlo.com\/jp\/ja\/products\//,
      detailTitleXP: '//h1[@data-test="product-name"]',
      detailTitleSearchXP: '//h1[@data-test="product-name"][+++]/../../..',
      urlHasChangedCommonFunc: () => {
        setTimeout(() => {
          isDetail = (SITE.detailURLRE && location.href.match(SITE.detailURLRE)) ? 1 : 0;
          run(document.body)
        }, 2000);
      },
    },
    {
      id: 'workman',
      urlRE: '//workman.jp/shop/',
      listTitleXP: '//div[@class="block-thumbnail-t--goods-name"]/a|.//div[@class="_wrap"]/div[@class="_title"]/a',
      listTitleSearchXP: '//div[@class="block-thumbnail-t--goods-name"]/a[+++]/../../..|.//div[@class="_wrap"]/div[@class="_title"]/a[+++]/../../..',
      listTitleMemoSearchXP: '//div[@class="block-thumbnail-t--goods-name"]/a[+++]|//h1[@class="h1 block-goods-name--text js-enhanced-ecommerce-goods-name"][+++]|.//div[@class="_wrap"]/div[@class="_title"]/a[+++]',
      listGen: 4,
      observe: 500,
      detailURLRE: /shop\/g\//,
      detailTitleXP: '//h1[@class="h1 block-goods-name--text js-enhanced-ecommerce-goods-name"]',
      detailTitleSearchXP: '//h1[@class="h1 block-goods-name--text js-enhanced-ecommerce-goods-name"][+++]/../../../..',
    },
    {
      id: 'free.arinco.org',
      urlRE: 'http://free.arinco.org/mail/index1.html',
      listTitleXP: '//a',
      redoWhenRefocused: 1,
      useURL: 1,
      listTitleMemoSearchXPSameGen: 1,
      listGen: 4,
      listTitleSearchXP: '//a[++url++]/..',
      listTitleMemoSearchXP: '//a[++url++]',
    },
    {
      id: 'free.arinco.org',
      urlRE: '//free.arinco.org/',
      useURL: 1,
      redoWhenRefocused: 1,
      listTitleMemoSearchXPSameGen: 1,
      listGen: 4,
      listTitleXP: '//a|//h1/span[@itemprop="name"]',
      listTitleSearchXP: '//a[**url**]/..|//h1/span[@itemprop="name"][**url**]',
      listTitleMemoSearchXP: '//a[**url**]|//h1/span[@itemprop="name"][**url**]',
      detailURLRE: /\/mail\//,
      detailTitleXP: '//h1/span[@itemprop="name"]',
      detailTitleSearchXP: '//h1/span[@itemprop="name"][**url**]',
      funcOnlyFirst: function() {
        GM_addStyle('.itemlist li{height:auto; margin:0.5em;}');
        var e = location.href.replace(/^https?:\/\/free.arinco.org\/mail\/([^/]+\/)$/, "$1");
        var t = eleget0('//h1/span[@itemprop="name"]')
        if (document.body.innerText.match(/ホーム » Free Mail » /) && e && t) t.setAttribute("href", e)
      },
      automemoURLRE: /^https?:\/\/free.arinco.org\/mail\/[^/]+\/$/, // メールサービス名にホバーしないと作られない
      automemoSearchFunc: function() { return eletext(['//article[@role="main"]/section[@id="detail"]', '//div[@id="main"]/article/section[1]']); },
      automemoFunc: function() {
        //        [/(imap)/im, /(pop3)/mi, /(Tor)/m, /(e2ee)/m, /(openpgp)|(gnupgp)|(pgp)/mi].forEach(m => autoMemo(m));
        [/(imap)/im, /(pop3)/mi, /(Tor)/m, /(e2ee)/m, /(openpgp)|(gnupgp)|(gpg)|(pgp)/mi].forEach(m => autoMemo(m));
      },
      automemoForceFunc: function() { return 1; },
      /*      autoTranslucentURLRE: /^https?:\/\/free.arinco.org\/mail\/[^/]+\/$/, // urlだけでは詳細概要画面を特定できない
            detailURLRE: /^https?:\/\/free.arinco.org\/mail\/.+/,
            detailTitleXP: '//h1/span[@itemprop="name"]',
            detailTitleSearchXP: '//h1/span[@itemprop="name"][**url**]/../../../..',
            automemoURLRE: /^https?:\/\/free.arinco.org\/mail\/[^/]+\/$/,
            automemoSearchFunc: () => { return eletext(['//article[@role="main"]/section[@id="detail"]']); },
            automemoFunc: () => {
                [/(imap)/im,/(pop3)/mi,/(openpgp)|(gnupgp)|(pgp)/mi].forEach(m => autoMemo(m));
              },
      */
    },
    {
      id: 'twiman.net',
      urlRE: '//twiman.net/',
      listTitleXP: '//div[@class="v-list-item__content"]/div[2]',
      listTitleSearchXP: '//div[@class="v-list-item__content"]/div[2][***]/../../../..',
      listTitleMemoSearchXP: '//div[@class="v-list-item__content"]/div[2][***]/../..',
      listGen: 7,
      observe: 500,
      trim: 1,
    },
    {
      id: 'twicomi.com',
      urlRE: '//twicomi.com',
      trim: 1,
      title: 'div.screen-name,div.fixed-tweet>div:nth-child(3),span.screen-name,div.tweet-text',
      box: 'div.author-profile,.fixed-area,div.manga-item',
      forceTranslucentFunc: e => e.closest('div.author-profile,.fixed-area'),
      autoTranslucentURLRE: /\/\/twicomi\.com\/manga\//,
      XP2name: 'ユーザー名 ',
      listTitleXP2: 'div.screen-name,span.screen-name',
      listGen: 8,
      observe: 500,
      redoWhenReturned: 1,
      func: () => { $('.list').css({ "min-height": "0px" }) }, // AP継ぎ足し時の空白を詰める
      funcOnlyFirst: () => {
        var observeUrlHasChangedhref = location.href;
        var observeUrlHasChanged = new MutationObserver(mutations => {
          if (observeUrlHasChangedhref !== location.href) {
            pauseAll = 1;
            prefCacheClear()
            observeUrlHasChangedhref = location.href;
            elegeta('//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
            setTimeout(() => {
              pauseAll = 0;
              $(".phov2").remove();
              $('span.phov').remove();
              //              elegeta('//div[@class="fixed-area"]/div[@class="fixed-tweet"]/div[@class="text"]/..').forEach(e => e.style.opacity = "1")
              elegeta('div.author-profile,.fixed-area', ).forEach(e => e.style.opacity = "1")
              disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
              run(document.body, "returned")
            }, 100);
          }
        });
        observeUrlHasChanged.observe(document, { childList: true, subtree: true });
      },
    },
    {
      id: 'chrome.google.com/webstore/search/',
      urlRE: '//chrome.google.com/webstore/search/|//chrome.google.com/webstore/detail/',
      listTitleXP: '//div[@class="a-na-d-w" and @role="heading"]',
      listTitleSearchXP: '//div[@class="a-na-d-w" and @role="heading"][+++]/../../../../../..',
      listTitleMemoSearchXP: '//div[@class="a-na-d-w" and @role="heading"][+++]|.//div[@class="e-f-n-Va"]/div[@class="e-f-w-Va"]/h1[@class="e-f-w"][+++]',
      listGen: 7,
      delay: 2500,
      observe: 500,
      redoWhenReturned: 1,
      detailURLRE: /https:\/\/chrome.google.com\/webstore\/detail\//,
      detailTitleXP: '//div[@class="e-f-n-Va"]/div[@class="e-f-w-Va"]/h1[@class="e-f-w"]',
      detailTitleSearchXP: '//div[@class="e-f-n-Va"]/div[@class="e-f-w-Va"]/h1[@class="e-f-w"][+++]/../../../..',
      listTitleMemoSearchXPSameGen: 1,
    },
    {
      id: 'sakura-checker.jp',
      urlRE: '//sakura-checker.jp/category/',
      listTitleXP: '//div[1]/figure/a',
      listTitleSearchXP: '//div[1]/figure/a[++url++]/../../..',
      listTitleMemoSearchXP: '//div[1]/figure/a[++url++]',
      listGen: 5,
      listHelpXP: '//div[1]/figure/a/../../..',
      useURL: 1,
    },
    {
      id: 'BOOTH.PM', // 作者名でQ/1/2 出品者名でQ
      urlRE: 'https:\/\/booth\.pm\/ja\/browse/|https:\/\/booth\.pm\/ja\/items|https:\/\/booth.pm\/ja$|https:\/\/booth\.pm\/ja\/events\/|https:\/\/booth\.pm\/ja\/search\/',
      listHelpXP: '//a[@class="item-card__title-anchor nav"]/../../../..|.//a[@class="item-card__title-anchor--multiline nav"]/../../../..',
      listTitleXP: '//a[@class="item-card__title-anchor nav"]|.//a[@class="item-card__title-anchor--multiline nav"]',
      listTitleXP2: '//div[@class="item-card__shop-name"]|//div[@class="u-text-ellipsis"]|//a[@class="nav u-tpg-title2"]',
      XP2memo: 1,
      XP2name: '出品者名 ',
      listTitleSearchXP: '//a[@class="item-card__title-anchor nav"][+++]/../../../..|//div[@class="item-card__shop-name"][+++]/../../../../../..|.//a[@class="item-card__title-anchor--multiline nav"][+++]/../../../..',
      listTitleMemoSearchXP: '//a[@class="item-card__title-anchor nav"][+++]|//header/h2[@class="u-text-wrap u-tpg-title1 u-mt-0 u-mb-400"][+++]|.//a[@class="item-card__title-anchor--multiline nav"][+++]|.//div[@class="item-card__shop-name"][+++]|.//div[@class="u-text-ellipsis"][+++]|//a[@class="nav u-tpg-title2"][+++]',
      listGen: 7,
      detailURLRE: /https:\/\/booth\.pm\/ja\/items\//,
      detailTitleXP: '//header/h2[@class="u-text-wrap u-tpg-title1 u-mt-0 u-mb-400"]',
      detailTitleSearchXP: '//header/h2[@class="u-text-wrap u-tpg-title1 u-mt-0 u-mb-400"][+++]/../../../../../../../..|//div[@class="u-text-ellipsis"][+++]/../../../../../../../..',
      redoWhenReturned: 1,
      hideListEvenDetail: 1,
    },
    {
      id: 'TOODORAN',
      urlRE: '//todo-ran.com/t/soukan/',
      listTitleXP: '//td/a[1]',
      listTitleSearchXP: '//td/a[1][+++]/../..',
      listTitleMemoSearchXP: '//td/a[1][+++]',
      listGen: 3,
      listTitleMemoSearchXPSameGen: 1,
    },
    {
      id: 'FF5CH',
      urlRE: /\/\/ff5ch\.syoboi\.jp\/\?q=/,
      listTitleXP: '//a[@class="thread"]',
      listTitleSearchXP: '//a[@class="thread"][+++]/../..',
      listTitleMemoSearchXP: '//a[@class="thread"][+++]',
      listGen: 3,
    },
    {
      id: 'MSDMANUAL', // 検索結果と詳細ページでは項目名に表記ゆれがあるので合致しない
      urlRE: '//www.msdmanuals.com/',
      listTitleXP: '//div/a[@class="search__result--title"]',
      listTitleSearchXP: '//div/a[@class="search__result--title"][+++]/../../..',
      listTitleMemoSearchXP: '//div/a[@class="search__result--title"][+++]|//h1[@class="topic__header__headermodify--title topic__header__headermodify--title--animate"][+++]',
      listGen: 3,
      delay: 2000,
      observe: 500,
      detailURLRE: /^(?!.*(SearchResults)).*/,
      detailTitleXP: '//h1[@class="topic__header__headermodify--title topic__header__headermodify--title--animate"]',
      detailTitleSearchXP: '//h1[@class="topic__header__headermodify--title topic__header__headermodify--title--animate"][+++]/../../../../../..',
    },
    {
      id: 'CHIEBUKURO',
      urlRE: '//chiebukuro.yahoo.co.jp/',
      //  urlRE: /\/\/chiebukuro.yahoo.co.jp\/|\/\/detail.chiebukuro.yahoo.co.jp\//,
      listTitleXP: '//div/a/div/div/div/div/h2/../../../../..',
      listTitleSearchXP: '//article/div/a/div/div/div/div/h2/../../../../..[++url++]/../..',
      listTitleMemoSearchXP: '//article/div/a[++url++]/div/div/div/div/h2',
      listGen: 9,
      useURL: 1,
      redoWhenReturned: 1,
    },
    {
      urlRE: 'https://refind2ch.org/search',
      id: '2CHTHREADLIST',
      title: 'p.list-group-item-heading.thread_title,p.board_title span',
      box: '#search_results a.thread_url.list-group-item.entry.board_border',
      /*      listTitleXP: '//p[contains(@class,"thread_title")]',
            listTitleXP2: '//p/span[@class="board_clr_font_shitaraba"]|.//p/span[@class="board_clr_font_2chnet"]', // おーぷん板名は重複'|//p/span[@class="board_clr_font_open2chnet"]',
            XP2name: '板 ',
            listTitleSearchXP: '//p[contains(@class,"thread_title")][***]/../..|.//p/span[@class="board_clr_font_shitaraba"][***]/../../..|.//p/span[@class="board_clr_font_2chnet"][***]/../../..', //'|//p/span[@class="board_clr_font_open2chnet"][+++]/../../..',
            listTitleMemoSearchXP: '//p[contains(@class,"thread_title")][***]',
            listGen: 4,
      */
      observe: 500,
      redoWhenReturned: 1,
      XP2name: '板名 ',
      listHelpXP2: '.board_title span',
      trim: 1,
      //titleProcessFunc: (title) => { return title.replace(/\s\(したらば\)/gmi, "") },
      WhateverFirstAndEveryAPFunc: () => {
        $(".side_box").css({ "height": "100vh" });
        popup3("Shift+F:re.Find2ch検索", 8, 5000)
      },
      wholeHelp: [() => 1, " A:ソート"],
      keyFunc: [{
        key: 'a', // a::
        func: () => {
          var sorttype = GF.yhmSortType || 0
          let menu = [
            { t: "タイトル", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('p.list-group-item-heading.thread_title', v)?.textContent) } },
            { t: "板名", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('p:last-child span small', v)?.textContent + eleget0('.board_title span', v)?.textContent) } },
            { t: "新しい", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('.date_raw,.date', v)?.textContent, 1) } },
            { t: "勢い", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('.rate_cnt', v)?.textContent, 1) } },
          ]
          popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+2),0)}em;`);
          menu[sorttype].f()
          GF.yhmSortType = (++sorttype) % menu.length
          return
        }
      }, {
        key: 'Shift+F', // Shift+F::refind2chでキーワード検索
        func: () => { searchWithHistory("REFIND2CH", "re.Find2ch", 'https://refind2ch.org/search?q=***&sort=rate', " OR ") },
      }],
      func: (node = document) => { // 高密度化&https化
        elegeta('//div/div[@class="container-fluid"]').forEach(e => {
          e.style.width = "95%";
          e.style.maxWidth = "100%";
        })
        elegeta('//div[@id="content_main"]').forEach(e => {
          e.style.width = "calc(95vw - 400px)";
          e.style.maxWidth = "100%";
        })
        elegeta('//div[@class="progress rate pull-right"]').forEach((e) => { e.style.width = "5%" });
        for (let element of elegeta('//div[@class="clearfix"]|//a[contains(@class,"thread_url list-group-item entry clearfix board_border board_clr_border_2chnet") and @target="_blank" and @rel="nofollow noreferrer"]/p')) {
          element.parentNode.href = element.parentNode.href.replace(/http:\/\//, "https://");
          element.style = "display:inline;float:left; margin:0px 0.0em; padding:0px 0.5em 0px 0.5em;";
        }
        for (let element of elegeta('//a[@rel="nofollow noreferrer"]')) { element.style = "padding:0px;"; }
        elegeta('//div[@id="content_main"]/div[@id="search_results"]/a', node).forEach(e => { e.setAttribute("onclick", "") })
        elegeta('div>small.pull-right', node).forEach(e => {
          e.style = "float:none !important";
          e.parentNode.parentNode.appendChild(e);
        });
      },
    },
    {
      id: 'KAKAKUBB',
      urlRE: '//kakaku.com/bb/',
      listTitleXP: '//a[@class="planName"]',
      listTitleSearchXP: '//a[@class="planName"][+++]/../../../../..',
      listTitleMemoSearchXP: '//a[@class="planName"][+++]',
      listGen: 3,
    },
    {
      id: 'MINSOKU',
      urlRE: '//minsoku.net/',
      listTitleXP: '//div/div[@class="text-bold mt-xxs"]/a|.//div/div[@class="mt-10 text-bold"]/a|.//div[@class="mt-10 mb--xxxs text-bold"]/a',
      listTitleSearchXP: '//div/div[@class="text-bold mt-xxs"]/a[+++]/../../..|.//div/div[@class="mt-10 text-bold"]/a[+++]/../../..|.//div[@class="mt-10 mb--xxxs text-bold"]/a[+++]/../../..',
      listTitleMemoSearchXP: '//div/div[@class="text-bold mt-xxs"]/a[+++]|.//div/div[@class="mt-10 text-bold"]/a[+++]|.//div[@class="mt-10 mb--xxxs text-bold"]/a[+++]',
      listGen: 4,
    },
    {
      id: 'OMOCORO',
      urlRE: '//omocoro.jp/',
      listTitleXP: '//div[@class="details"]/div[@class="title"]/a',
      listTitleSearchXP: '//div[@class="details"]/div[@class="title"]/a[+++]/../../..',
      listTitleMemoSearchXP: '//div[@class="details"]/div[@class="title"]/a[+++]',
      listGen: 4,
    },
    {
      id: '360life.shinyusha.co.jp',
      urlRE: '//360life.shinyusha.co.jp/',
      listTitleXP: '//article/div[@class="m-article-item__info"]/h3[@class="m-article-item__title"]',
      listTitleSearchXP: '//article/div[@class="m-article-item__info"]/h3[@class="m-article-item__title"][***]/../../../..',
      listTitleMemoSearchXP: '//article/div[@class="m-article-item__info"]/h3[@class="m-article-item__title"][***]|//div[@class="article-header"]/h1[@class="article-header__title"][***]',
      listGen: 4,
      detailURLRE: /\/\/360life\.shinyusha\.co\.jp\/articles\//,
      detailTitleXP: '//div[@class="article-header"]/h1[@class="article-header__title"]',
      detailTitleSearchXP: '//div[@class="article-header"]/h1[@class="article-header__title"][***]/../../../../..',
      redoWhenReturned: 1,
      trim: 1,
    },
    {
      id: 'SHOPPING_YAHOO',
      urlRE: '//shopping.yahoo.co.jp/search',
      listTitleXP: '//div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span',
      listTitleSearchXP: '//div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span[+++]/../../../../..',
      listTitleMemoSearchXP: '//li[@class="LoopList__item"]/div/div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span[+++]',
      listGen: 6,
      func: () => { // 商品名を省略しなくする
        elegeta('//div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span/..').forEach(e => {
          e.style.display = "block";
          e.style.maxHeight = "none";
        });
      },
      observe: 1000,
    },
    {
      id: 'FREEM',
      urlRE: '//www.freem.ne.jp/',
      listTitleXP: '//a/h3[@class="pc"]',
      listTitleSearchXP: '//ul[contains(@class,"game-list game-list-wrap row")]/li/a/h3[@class="pc"][+++]/../..',
      listTitleMemoSearchXP: '//ul[contains(@class,"game-list game-list-wrap row")]/li/a/h3[@class="pc"][+++]',
      listGen: 3,
    },
    {
      id: 'ONSEN',
      urlRE: '//www.onsen.ag/',
      listTitleXP: '//h4[@class="title"]',
      listTitleSearchXP: '//h4[@class="title"][+++]/../..',
      listTitleMemoSearchXP: '//h4[@class="title"][+++]',
      listGen: 4,
      observe: 500,
    },
    {
      id: 'HIBIKI',
      urlRE: '//hibiki-radio.jp',
      listTitleXP: '//div[@class="title program-title-animate ng-binding"]',
      listTitleSearchXP: '//div[@class="title program-title-animate ng-binding"][+++]/../../..',
      listTitleMemoSearchXP: '//div[@class="title program-title-animate ng-binding"][+++]',
      listGen: 3,
      observe: 500,
    },
    {
      id: 'GOOGLE_SCHOLAR',
      urlRE: '//scholar\.google\..*/',
      listTitleXP: '//h3[@class="gs_rt"]/a',
      listTitleSearchXP: '//h3[@class="gs_rt"]/a[++url++]/../../..',
      listTitleMemoSearchXP: '//h3[@class="gs_rt"]/a[++url++]',
      listGen: 3,
      useURL: 1,
      disableKeyB: 1,
    },
    {
      id: 'NICODOUGA',
      urlRE: '//commons.nicovideo.jp/',
      listTitleXP: '//a[@class="title_link"]',
      listTitleSearchXP: '//a[@class="title_link"][+++]/..',
      listTitleMemoSearchXP: '//a[@class="title_link"][+++]', // ちゃんと動かない
      listGen: 2,
      observe: 500,
    },
    {
      id: 'RRWS',
      urlRE: '//rrws.info/',
      listTitleXP: '//h2[@class="entry-card-title card-title e-card-title"]',
      listTitleSearchXP: '//h2[@class="entry-card-title card-title e-card-title"][***]/../../..',
      listTitleMemoSearchXP: '//h2[@class="entry-card-title card-title e-card-title"][***]|//h1[@class="entry-title"][***]',
      listGen: 3,
      detailURLRE: /rrws.info\/archives\//,
      detailTitleXP: '//h1[@class="entry-title"]',
      detailTitleSearchXP: '//h1[@class="entry-title"][***]/../..',
      trim: 1,
    },
    {
      id: 'A-TIMESALE',
      urlRE: '//a-timesale.com/',
      listTitleXP: '//div[3]/div[@class="border-b pb-3 mb-4"]/a[@target="_blank"]',
      listTitleSearchXP: '//div[3]/div[@class="border-b pb-3 mb-4"]/a[@target="_blank"][+++]/../../../../..',
      listTitleMemoSearchXP: '//div[3]/div[@class="border-b pb-3 mb-4"]/a[@target="_blank"][+++]',
      listGen: 6,
      observe: 500,
    },
    {
      id: 'PUBMED',
      //      urlRE: '//pubmed.ncbi.nlm.nih.gov/.term=',
      urlRE: '//pubmed.ncbi.nlm.nih.gov/.term=|//pubmed.ncbi.nlm.nih.gov/.linkname=|//pubmed.ncbi.nlm.nih.gov/',
      listTitleXP: '//span[@class="docsum-pmid" and text()]|.//span[@class="docsum-pmid"]/font[1]/font[1]',
      listHelpXP: '//span[@class="docsum-pmid" and text()]/../../../../..|.//span[@class="docsum-pmid"]/font/font/../../../../../../..',
      listTitleSearchXP: '//span[@class="docsum-pmid"][+++]/../../../../..|.//span[@class="docsum-pmid"]/font/font[+++]/../../../../../../..',
      listTitleMemoSearchXP: '//span[@class="docsum-pmid"][+++]|.//span[@class="docsum-pmid"]/font/font[+++]|//header[@id="heading"]/div[1]/ul/li/span/strong[@class="current-id"][+++]|//strong[@class="current-id"]/font/font[+++]/../..',
      observe: 500,
      listGen: 7,
      trim: 1,
      detailURLRE: /\/\/pubmed.ncbi.nlm.nih.gov\/\d*\//,
      detailTitleXP: '//header[@id="heading"]/div[1]/ul/li/span/strong[@class="current-id"][1]|//strong[@class="current-id"][1]/font[1]/font[1]',
      detailTitleSearchXP: '//header[@id="heading"]/div[1]/ul/li/span/strong[@class="current-id"][+++]/../../../../../..|//strong[@class="current-id"][1]/font[1]/font[1][+++]/../../../../../../../..',
      useText: 1,
    },
    {
      id: 'NICOCHART',
      urlRE: '//www.nicochart.jp/',
      listTitleXP: '//li[@class="title"]/a',
      listTitleSearchXP: '//li[@class="title"]/a[+++]/../../../../..',
      listTitleMemoSearchXP: '//li[@class="title"]/a[+++]',
      listGen: 5,
      redoWhenReturned: 1,
    },
    {
      id: 'NICOCHART',
      urlRE: '//www.nicovideo.me/',
      listTitleXP: '//h3[@class="fxs mtxs"]/a',
      listTitleSearchXP: '//h3[@class="fxs mtxs"]/a[+++]/../../..',
      listTitleMemoSearchXP: '//h3[@class="fxs mtxs"]/a[+++]',
      listGen: 3,
      redoWhenReturned: 1,
    },
    {
      id: 'TWITTER',
      urlRE: '//twitter.com/',
      title: 'a div[dir="ltr"] span',
      //listTitleXP: '//a/div[@dir="ltr"]/span',
      //listTitleSearchXP: '//a/div[@dir="ltr"]/span[+++]/../../../../../../../../../../../../../../..',
      box: 'div[data-testid="cellInnerDiv"]',
      //listTitleSearchXP: '//a/div[@dir="ltr"]/span[+++]/ancestor::div[@data-testid="cellInnerDiv"]',
      //listTitleMemoSearchXP: '//a/div[@dir="ltr"]/span[+++]',
      //listGen: 14,
      observe: 500,
      disableHelpForce: 1,
    },
    {
      id: 'SURUGAYA',
      urlRE: '//www.suruga-ya.jp/',
      listTitleXP: '//p[@class="title"]/a[1]',
      listTitleSearchXP: '//p[@class="title"]/a[1][+++]/../../..',
      listTitleMemoSearchXP: '//p[@class="title"]/a[1][+++]',
      listGen: 5,
      //      titleProcessFunc: (title) => { return title.replace(/ランクB\)/gmi, "").replace(/(.*$|\(.*$/g, "").replace(/全??\d+巻セット.*$|全?\d+?~?\d+巻セット.*$/gmi, "").replace(/\s\/.*$/gmi, "").trim() },
      redoWhenReturned: 1,
      funcOnlyFirst: function() {
        if (location.href == "https://www.suruga-ya.jp/pcmypage/action_nyuka_search/list") {
          setupbutton("zaiko", "品切れの項目を非表示", () => {
            setInterval(() => { elegeta('//div[last()]/input[@value="再入荷通知する"]/../../../..').forEach(e => e.style.display = "none") }, 500);
          }, "もとに戻すにはリロード", "removeWhenClicked")
        }
        /*          $(document).keypress(k=>{
                  if(k.key=="1"){ setInterval(()=>{elegeta('//div[last()]/input[@value="再入荷通知する"]/../../../..').forEach(e=>e.style.display="none") },999);}
                  if(k.key=="2"){ elegeta('//div[last()]/input[@value="再入荷通知する"]/../../../..').forEach(e=>e.style.display="block")}
                  });
        */
      },
    },
    {
      id: 'YOUTUBE', // youtube::
      //      helpOnDNI: 1,
      //listTitleMemoSearchXPSameGen: 1,
      //delayAutoWeighting: lh("www.youtube.com/playlist") ? 1 : 0,
      urlRE: /\/\/www\.youtube\.com\/$|\/\/www\.youtube\.com\/results|\/\/www\.youtube\.com\/channel\/|\/\/www\.youtube\.com\/playlist|\/\/www\.youtube\.com\/c\/|\/\/www\.youtube\.com\/user\/|\/\/www\.youtube\.com\/watch\?|\/\/www\.youtube\.com\/@/,
      disableUrlRE: /\/\/www\.youtube\.com\/watch\?/,
      redoWhenRefocused: 1,
      //      redoWhenReturned: 1,
      listTitleXPIgnoreNotExist: 1,
      //nfd: 1,
      //title: 'ytd-channel-name.ytd-c4-tabbed-header-renderer>.ytd-channel-name>div>yt-formatted-string,div.ytd-channel-name>yt-formatted-string#text>a,h1.title.ytd-video-primary-info-renderer>yt-formatted-string,h3.title-and-badge.ytd-video-renderer>a#video-title>yt-formatted-string.ytd-video-renderer,#items #dismissible a#video-title.yt-simple-endpoint,h4.ytd-playlist-panel-video-renderer span#video-title,h3.ytd-playlist-video-renderer a#video-title,#video-title.ytd-rich-grid-media,h1 yt-formatted-string.style-scope.ytd-watch-metadata,yt-formatted-string.style-scope.ytd-channel-name.complex-string a,span#video-title,.ytd-watch-next-secondary-results-renderer yt-formatted-string.ytd-channel-name', //,h1.ytd-watch-metadata yt-formatted-string.ytd-watch-metadata
      title: 'ytd-channel-name.ytd-c4-tabbed-header-renderer>.ytd-channel-name>div>yt-formatted-string,div.ytd-channel-name>yt-formatted-string#text>a,h1.title.ytd-video-primary-info-renderer>yt-formatted-string,h3.title-and-badge.ytd-video-renderer>a#video-title>yt-formatted-string.ytd-video-renderer,#items #dismissible a#video-title.yt-simple-endpoint,h4.ytd-playlist-panel-video-renderer span#video-title,h3.ytd-playlist-video-renderer a#video-title,#video-title.ytd-rich-grid-media,h1 yt-formatted-string.style-scope.ytd-watch-metadata,yt-formatted-string.style-scope.ytd-channel-name.complex-string a,span#video-title,.ytd-watch-next-secondary-results-renderer yt-formatted-string.ytd-channel-name,#byline', //,h1.ytd-watch-metadata yt-formatted-string.ytd-watch-metadata
      //box: 'ytd-grid-video-renderer, ytd-video-renderer, div.ytd-playlist-video-list-renderer ytd-playlist-video-renderer, ytd-rich-item-renderer, h1 yt-formatted-string.ytd-watch-metadata, div#channel-header .ytd-channel-name yt-formatted-string, ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string, ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,ytd-compact-video-renderer',
      box: 'ytd-grid-video-renderer, ytd-video-renderer, div.ytd-playlist-video-list-renderer ytd-playlist-video-renderer, ytd-rich-item-renderer, h1 yt-formatted-string.ytd-watch-metadata, div#channel-header .ytd-channel-name yt-formatted-string, ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string, ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,ytd-compact-video-renderer,ytd-reel-item-renderer',
      forceTranslucentFunc: e => e.closest('#channel-container div ytd-channel-name div div yt-formatted-string.style-scope.ytd-channel-name,ytd-watch-metadata h1 yt-formatted-string.ytd-watch-metadata,ytd-watch-metadata .ytd-channel-name a,div#channel-header .ytd-channel-name yt-formatted-string,ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string,ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,#byline'),
      /*
#channel-container div ytd-channel-name div div yt-formatted-string.style-scope.ytd-channel-name
↑チャンネルホームの投稿者名
ytd-watch-metadata h1 yt-formatted-string.ytd-watch-metadata
↑新視聴画面タイトル
ytd-watch-metadata .ytd-channel-name a
↑新視聴画面投稿者名
div#channel-header .ytd-channel-name yt-formatted-string
↑旧チャンネルホーム投稿者名
ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string
↑旧視聴タイトル
ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a
↑旧視聴投稿者名
*/
      listHelpXP: '//div[@id="dismissible"]|//div[@class="style-scope ytd-playlist-video-renderer"]/h3[@class="style-scope ytd-playlist-video-renderer"]/a/../../../../..',
      listTitleXP: '//a/yt-formatted-string[@class="style-scope ytd-video-renderer"]/..|.//a[@id="video-title"]|.//h3/span[@id="video-title"]|.//a[@id="video-title-link"]/yt-formatted-string[@id="video-title"]|.//yt-formatted-string[@id="video-title" and @class="style-scope ytd-rich-grid-media"]|//div[2]/ytd-video-primary-info-renderer[@has-date-text=""]/div/h1/yt-formatted-string[@force-default-style="" and contains(@class,"style-scope ytd-video-primary-info-renderer")]|//ytd-watch-metadata[@class="style-scope ytd-watch-flexy"]/div/div[@class="style-scope ytd-watch-metadata"]/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string',
      listTitleSearchXP: '//ytd-grid-video-renderer[.//a[@id="video-title" and +++]]|//ytd-channel-name[@wrap-text=""]/div/div/yt-formatted-string[+++]/following::a|.//ytd-video-renderer[.//a[@id="video-title" and ++title++]]|.//ytd-video-renderer[.//a[contains(@class,"yt-simple-endpoint") and +++]]|.//ytd-rich-item-renderer[.//yt-formatted-string[@id="video-title" and +++]]|.//ytd-rich-item-renderer[.//a[contains(@class,"yt-simple-endpoint") and +++]]|.//ytd-playlist-video-renderer[.//a[@id="video-title" and ++title++]]',
      XP2name: '投稿者名 ',
      //XP2memo:1, // 投稿者にメモ可は重そう
      listTitleXP2: '//ytd-item-section-renderer[@class="style-scope ytd-section-list-renderer" and @use-height-hack=""]/div[3]/ytd-video-renderer[@class="style-scope ytd-item-section-renderer" and @use-prominent-thumbs=""]/div[@id="dismissible" and @class="style-scope ytd-video-renderer"]/div/div/ytd-channel-name[@id="channel-name" and @class="long-byline style-scope ytd-video-renderer" and @wrap-text="true"]/div[@id="container"]/div[@id="text-container" and @class="style-scope ytd-channel-name"]/yt-formatted-string[@id="text" and @class="style-scope ytd-channel-name"]/a|.//div[@class="byline style-scope ytd-rich-grid-media"]/ytd-video-meta-block[@rich-meta="" and @mini-mode=""]/div[@class="style-scope ytd-video-meta-block"]/div[@class="style-scope ytd-video-meta-block"]/ytd-channel-name/div[@class="style-scope ytd-channel-name"]/div[@class="style-scope ytd-channel-name"]/yt-formatted-string[@id="text" and @class="style-scope ytd-channel-name complex-string"]/a[@class="yt-simple-endpoint style-scope yt-formatted-string" and @spellcheck="false" and @dir="auto"]|//div[@id="meta" and @class="style-scope ytd-c4-tabbed-header-renderer"]/ytd-channel-name/div[@class="style-scope ytd-channel-name"]/div[@id="text-container" and @class="style-scope ytd-channel-name"]/yt-formatted-string[@id="text" and @class="style-scope ytd-channel-name"]|.//ytd-channel-name[@id="channel-name" and @class="style-scope ytd-video-meta-block"]/div[@id="container"]/div[@class="style-scope ytd-channel-name"]/yt-formatted-string[@class="style-scope ytd-channel-name complex-string" and @ellipsis-truncate=""]/a[@class="yt-simple-endpoint style-scope yt-formatted-string" and @dir="auto"]|.//ytd-channel-name[@id=\"channel-name\" and @wrap-text=\"true\"]/div[@class=\"style-scope ytd-channel-name\"]/div/yt-formatted-string/a|//div[@id="container"]/div[@class="style-scope ytd-channel-name"]/yt-formatted-string/a[@class="yt-simple-endpoint style-scope yt-formatted-string"]',
      listGen: 7,
      observe: 500,
      //      ignoreDNI: e => e.nodeType !== 1 || !["YTD-PLAYLIST-VIDEO-RENDERER", "YTD-VIDEO-RENDERER", "YTD-RICH-ITEM-RENDERER", "YTD-PLAYLIST-PANEL-VIDEO-RENDERER"].includes(e.tagName), //ytd-playlist-panel-video-renderer
      ignoreDNI: e => e.nodeType !== 1 || !e?.matches(SITE.box), //!["YTD-PLAYLIST-VIDEO-RENDERER", "YTD-VIDEO-RENDERER", "YTD-RICH-ITEM-RENDERER", "YTD-PLAYLIST-PANEL-VIDEO-RENDERER"].includes(e.tagName), //ytd-playlist-panel-video-renderer
      //observeId: "dismissible",
      disableKeyB: 1,
      funcOnlyFirst: () => {

        document.body.addEventListener('mousedown', e => {
          //動画視聴ページで再生リストタイトルを右クリックでプレイリスト詳細を開く
          if (e.button == 2 && lh(/\&list=([0-9a-zA-Z-_]+)/) && e?.target == eleget0('//yt-formatted-string[@class="title style-scope ytd-playlist-panel-renderer" and @ellipsis-truncate="" and @title="Untitled List" and text()="Untitled List"]|//div[@id="container"]/div/div[@id="header-contents" and @class="style-scope ytd-playlist-panel-renderer"]/div[1]/div[1]/h3[1]/yt-formatted-string/a')) {
            let u = location.href.match0(/\&list=([0-9a-zA-Z-_]+)/)
            if (u) window.open(`https://www.youtube.com/playlist?list=${u}`)
          }
          //動画視聴ページで再生中タイトルを右クリックでその動画を含む再生リストを検索する
          if (e.button == 2 && lh(/\/watch/) && e?.target?.matches('div#title>h1>yt-formatted-string')) {
            let u = encodeURIComponent(e?.target?.innerText?.trim())
            if (u) {
              if (confirm(`https://www.youtube.com/results?search_query="${e?.target?.innerText?.trim()}"&sp=EgIQAw%253D%253D\n\nを開きます。よろしいですか?`)) {
                elegeta('video').forEach(v => v.pause());
                window.open(`https://www.youtube.com/results?search_query=%22${u}%22&sp=EgIQAw%253D%253D`)
              }
            }
          }
        }, false);

        var observeUrlHasChangedhref = location.href;
        var observeUrlHasChanged = new MutationObserver(mutations => {
          if (observeUrlHasChangedhref !== location.href) {
            pauseAll = 1;
            prefCacheClear();
            observeUrlHasChangedhref = location.href;
            elegeta('//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
            //            elegeta(SITE.box).forEach(e => e.style, opacity = "1");
            //            elegeta(SITE.box).concat(elegeta(SITE.title)).forEach(e => e.style, opacity = "1");
            elegeta(SITE.box).forEach(e => e.style.opacity = "1");
            //elegeta('//ytd-video-renderer|//*[@id="dismissible"]|//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
            //            setTimeout(() => { elegeta('//span[contains(@class,"yhmMyMemo")]').forEach(e => e.parentNode.remove());pauseAll=0;run(document.body, "returned") }, 3500);
            setTimeout(() => {
              pauseAll = 0;
              /*let watchTitle=eleget0('//div[@id="above-the-fold" and @class="style-scope ytd-watch-metadata"]/div/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string'); if(watchTitle)watchTitle.innerText=watchTitle?.textContent?.normalize("NFC")*/
              run(document.body, "returned")
            }, 3500);
          }
        });
        observeUrlHasChanged.observe(document, { childList: true, subtree: true });
        GM_addStyle("#meta.ytd-playlist-panel-video-renderer{display:block}") // プレイリストがdisplay:flexで1行に詰め込めないので外す試用

      },
      func: function(node = document.body) {
        /*var watchtitle = eleget0('h1>yt-formatted-string.style-scope.ytd-video-primary-info-renderer');
        if (watchtitle) watchtitle.innerText = watchtitle.innerText.normalize("NFC"); //動画視聴画面のタイトルだけNFDでマッチしないので変換*/ //これやると動画遷移時タイトルが書き換わらなくなる
        //        if (location.href.indexOf("https://www.youtube.com/playlist?list=") !== -1) { elegeta('a#video-title,span#video-title').forEach(e => { e.title = e.textContent.trim();            e.innerText = e.textContent.trim(); }); } // 再生リストだけテキストにゴミスペースがある
        //if (lh(/^https:\/\/www\.youtube\.com\/playlist\?list=|^https:\/\/www\.youtube\.com\/watch/)) { elegeta('a#video-title,span#video-title').forEach(e => { e.title = e.textContent.trim();            e.innerText = e.textContent.trim(); }); } // 再生リストだけテキストにゴミスペースがある
        if (REPLACE_LINK_IN_YOUTUBE) {
          //          elegeta('//a', node).forEach(e => { if (/\/(channel|user|c)\/[^\/]+$/.test(e.href)) e.href = e.href + "/videos"; });
          elegeta('//a', node).forEach(e => { if (/\/(channel|user|c)\/[^\/]+$|youtube\.com\/@[^\/]+$/.test(e.href)) e.href = e.href + "/videos"; });
        }
      },
      //      helpOnDNI:1,
      redoWhenReturned: 1,
      keyFunc: [{
        key: 'Shift+F', // Shift+F::YouTubeでキーワード検索
        func: () => { searchWithHistory("YouTube", "YouTube", 'https://www.youtube.com/results?search_query=***', "+OR+") },
      }, {
        key: 'u', // u::チャプターメモ
        func: (e) => {
          if (lh(/https:\/\/www\.youtube\.com\/results\?search_query\=/)) { // u::uniq
            let undup = []
            let dup = []
            elegeta('h3.title-and-badge.style-scope.ytd-video-renderer>a>yt-formatted-string:visible').forEach(e => {
              if (undup.includes(e.textContent)) {
                e.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
                $(e.closest("ytd-grid-video-renderer, ytd-video-renderer, div.ytd-playlist-video-list-renderer ytd-playlist-video-renderer, ytd-rich-item-renderer, h1 yt-formatted-string.ytd-watch-metadata, div#channel-header .ytd-channel-name yt-formatted-string, ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string, ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,ytd-compact-video-renderer,ytd-reel-item-renderer")).hide(999, function() { $(this).remove() }); //e?.closest(".entry")?.remove()
                dup.push(e.textContent)
              } else { undup.push(e.textContent) }
            })
            popup2(`u:重複タイトルを隠す\n${dup.join("\n")}`, 6)
            return
          }

          chapterMemo(/watch/, () => eleget0('//div[2]/ytd-video-primary-info-renderer[@has-date-text=""]/div/h1/yt-formatted-string[@force-default-style="" and contains(@class,"style-scope ytd-video-primary-info-renderer")]|//ytd-watch-metadata[@class="style-scope ytd-watch-flexy"]/div/div[@class="style-scope ytd-watch-metadata"]/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string')?.textContent, `https://www.youtube.com/watch?v=${location.href.match0(/v\=([^?&]*)/)}&t=**time**`)
        },
      }, {
        key: 'Shift+U', // Shift+U::チャプターメモをクリップボードにコピー
        func: (e) => {
          //GF.U = (GF.U || 0) + 1
          //let list
          //chapterMemo(/watch/, () => eleget0('meta[name="title"]:visible')?.getAttribute("content") || eleget0('//div[@id="title" and @class="style-scope ytd-watch-metadata"]/h1/yt-formatted-string:visible')?.textContent?.trim(), `${(GF.U%3==1?"https://www.youtube.com/watch?v=**id**&t=**time**":"https://youtu.be/**id**?t=**time**").replace("**id**",location.href.match0(/v\=([a-zA-Z0-9_\-]{11})/))}`, 1)
          //if (lh("/watch") && GF.U % 3 == 0) { list = elegeta(SITE.box).filter(e => eleget0(".yhmMyMemo:visible", e)).map(e => { return `${eleget0(SITE.title,e?.closest(SITE.box))?.textContent?.trim()}\n${e?.dataset?.url || eleget0("a[href*='/watch?v='],a[href*='/shorts/']",e?.closest(SITE.box))?.href?.replace("https://www.youtube.com/watch?v=","https://youtu.be/").replace("https://www.youtube.com/shorts/","https://youtu.be/").replace(/&list=.*/,"")}\n` }) }
          //if (!lh(/\/watch/) && lh(/\/results\?search_query=|\/videos|\/playlist|\/shorts|\/search/)) {
          //  if (GF.U % 3 == 1 || GF.U % 3 == 2) { list = elegeta('.yhmMyMemo:visible').filter(e => e?.closest("ytd-grid-video-renderer,ytd-video-renderer,ytd-playlist-video-renderer,ytd-rich-item-renderer") && (GF.U % 3 == 1 || e?.dataset?.cm)).map(e => { return `${eleget0(SITE.title,e?.closest(SITE.box))?.textContent?.trim()} ${e?.textContent?.trim()}\n${e?.dataset?.url || eleget0("a[href*='/watch?v='],a[href*='/shorts/']",e?.closest(SITE.box))?.href?.replace("https://www.youtube.com/watch?v=","https://youtu.be/").replace("https://www.youtube.com/shorts/","https://youtu.be/").replace(/&list=.*/,"")}\n` }) } // 押すたびに 1:再生リストのすべてのメモ(詳細あり) 2:再生リストのチャプターメモのみ1つごと(詳細あり) 3:再生リストのメモがついているもののみ(詳細なし)
          //  if (GF.U % 3 == 0) { list = elegeta(SITE.box).filter(e => eleget0(".yhmMyMemo:visible", e)).map(e => { return `${eleget0(SITE.title,e?.closest(SITE.box))?.textContent?.trim()}\n${e?.dataset?.url || eleget0("a[href*='/watch?v='],a[href*='/shorts/']",e?.closest(SITE.box))?.href?.replace("https://www.youtube.com/watch?v=","https://youtu.be/").replace("https://www.youtube.com/shorts/","https://youtu.be/").replace(/&list=.*/,"")}\n` }) }
          //}
          //if (list) {
          //  GM.setClipboard(list?.join("") || "")
          //  popup2((list?.join("") || ""), -1, "", "top")
          //}

          if (lh(/watch/) && kaisuuU % 3 < 2) chapterMemo(/watch/, () => eleget0('meta[name="title"]:visible')?.getAttribute("content") || eleget0('//div[@id="title" and @class="style-scope ytd-watch-metadata"]/h1/yt-formatted-string:visible')?.textContent?.trim(), `${(kaisuuU%2?"https://www.youtube.com/watch?v=**id**&t=**time**":"https://youtu.be/**id**?t=**time**").replace("**id**",location.href.match0(/v\=([a-zA-Z0-9_\-]{11})/))}`, 1)

          //if(lh(/watch/)&&kaisuuU%3<2)chapterMemo(/watch/, () => eleget0('meta[name="title"]:visible')?.getAttribute("content") || eleget0('//div[@id="title" and @class="style-scope ytd-watch-metadata"]/h1/yt-formatted-string:visible')?.textContent?.trim(), `${("https://www.youtube.com/watch?v=**id**&t=**time**").replace("**id**",location.href.match0(/v\=([a-zA-Z0-9_\-]{11})/))}`, 1)
          if (lh(/watch/) && kaisuuU % 3 == 2) {
            let chaMemoTU = [...new Set((elegeta('div#items ytd-playlist-panel-video-renderer#playlist-items').reduce((ac, v) => {
              if (eleget0('.yhmMyMemo', v)) {
                ac.push(`${eleget0('#video-title', v)?.innerText?.trim()}\n${eleget0('a', v)?.href?.replace(/\&list=.*/, "")}\n`)
              }
              return ac
            }, [])))]
            GM.setClipboard(chaMemoTU)
            popup2(chaMemoTU, -1, "", "top")
          }

          if (!lh(/\/watch/) && lh(/\/results\?search_query=|\/videos|\/playlist|\/shorts|\/search/)) {
            let list = elegeta('.yhmMyMemo:visible').filter(e => e?.closest("ytd-grid-video-renderer,ytd-video-renderer,ytd-playlist-video-renderer,ytd-rich-item-renderer") && (!GF?.chaptermemotype || e?.dataset?.cm)).map(e => { return `${eleget0(SITE.title,e?.closest(SITE.box))?.textContent?.trim()} ${e?.textContent?.trim()}\n${e?.dataset?.url || eleget0("a[href*='/watch?v='],a[href*='/shorts/']",e?.closest(SITE.box))?.href?.replace("https://www.youtube.com/watch?v=","https://youtu.be/").replace("https://www.youtube.com/shorts/","https://youtu.be/").replace(/&list=.*/,"")}\n` })
            GF.chaptermemotype = 1 - (GF.chaptermemotype || 0) // 偶数回目に押した時はチャプターメモに絞る
            GM.setClipboard(list?.join("") || "")
            popup2((list?.join("") || ""), -1, "", "top")
          }
          kaisuuU++
        },
      }, {
        key: 'h', // a:: h::キューかプレイリストありでの視聴画面 (「YouTube検索結果「全てキューに入れて再生」ボタンを追加」用)
        func: () => {
          if (/\/\/www\.youtube\.com\/watch/.test(location.href)) {
            var sorttype = GF.yhmSortType || 0
            let menu = [
              { t: "時間長", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => Number(v?.querySelector('span.style-scope.ytd-thumbnail-overlay-time-status-renderer')?.innerText?.replace(/[^0-9]/gmi, "")), 1) } },
              { t: "時間短", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => Number(v?.querySelector('span.style-scope.ytd-thumbnail-overlay-time-status-renderer')?.innerText?.replace(/[^0-9]/gmi, ""))) } },
              { t: "メモ多", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => Number(elegeta('.yhmMyMemo', v).length), 1) } },
              { t: "タイトル", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => v?.querySelector('span#video-title')?.textContent?.trim()) } },
              { t: "投稿者名", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => v?.querySelector('span#byline')?.textContent?.trim()) } },
            ]
            popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+2),0)}em;`);
            menu[sorttype].f()
            GF.yhmSortType = (++sorttype) % menu.length
          }
        }
      }, {
        key: 'a', // a::
        func: () => {
          if (lh(/\/\/www\.youtube\.com\/playlist\?list=/)) {
            var sorttype = GF.yhmSortType || 0
            let menu = [
              { t: "時間長", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")), 1) } },
              { t: "時間短", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, ""))) } },
              { t: "メモ多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => elegeta('.yhmMyMemo', v).length, 1) } },
              { t: "タイトル", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('#video-title', v)?.textContent?.trim()) } },
              { t: "投稿者", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('div.style-scope.ytd-channel-name yt-formatted-string a', v)?.textContent?.trim() || "") } },
              { t: "再生多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) } },
              { t: "再生少", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 0) } },
              { t: "古い", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
              { t: "新しい", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 0) } },
              { t: "逆順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 1) } },
              { t: "元順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 0) } },
            ]
            popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+2),0)}em;`);
            menu[sorttype].f()
            GF.yhmSortType = (++sorttype) % menu.length
            return
          }
          if (lh(/\/\/www.youtube.com\/(?:channel\/|c\/|user\/|@)[^\/]+\/(?:videos|shorts|streams)/)) {
            var menumax = lh(/\/\/www\.youtube\.com\/playlist\?list=/) ? 4 : 8
            var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
            $('.yhmSortType').remove();
            $(document.body).append(`<span class="yhmSortType" id="${++sorttype}"></span>`)
            popup2("A:ソート\n" + (["現状を反転", "時間長", "時間短", "タイトル", "再生多", "再生少", "古い", "新しい"].slice(0, menumax).map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:8em;")
            //popup2("A:ソート\n" + (["時間長", "時間短", "タイトル", "再生多", "再生少"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
            let newUI = eleget0('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer') || eleget0('//div[@class="style-scope ytd-rich-grid-row"]')
            if (newUI) $('ytd-rich-grid-row .style-scope.ytd-rich-grid-row').unwrap(); // 表示が乱れるのでよくわからない4列化行要素を消す
            //if (newUI) GM_addStyle(`ytd-rich-grid-row #contents.ytd-rich-grid-row{display: grid;}`);
            [() => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v, i) => { return -i }) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v, i) => { return -i }, 1);
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { return -Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1);
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1);
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => v?.querySelector('#video-title')?.textContent?.trim()) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => v?.querySelector('a#video-title')?.title?.trim(), 3);
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(3)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(1)')?.textContent; return -parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1);
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(3)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(1)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1);
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(4)')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = eleget0('//div[1]/div[@id="metadata-line"]/span[2]', v)?.textContent; return -parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1)
            }, () => {
              if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(4)')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }) // 20221029UI
              if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = eleget0('//div[1]/div[@id="metadata-line"]/span[2]', v)?.textContent; return -parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 3)
            }][sorttype - 1]()
            if (sorttype == menumax) $('.yhmSortType').remove();
            return
          }
          if (/\/\/www.youtube.com\/results\?search_query=/.test(location.href)) { // 検索結果 // a::
            var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
            $('.yhmSortType').remove();
            //$('ytd-shelf-renderer,ytd-horizontal-card-list-renderer').remove() // 縦1列「○○の最新の動画をお見逃しなく」「他の人はこちらも検索」
            $(document.body).append(`<span class="yhmSortType" id="${++sorttype}"></span>`)
            popup2("A:ソート\n" + (["時間長", "時間短", "タイトル", "再生多", "再生少", "古い", "新しい", "投稿者", "動画多"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
            switch (sorttype) {
              case 1:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => Number(eleget0('span#text.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "")), 1);
                break;
              case 2:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => Number(eleget0('span#text.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "")));
                break;
              case 3:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => eleget0('//yt-formatted-string[@class="style-scope ytd-video-renderer"]', v)?.textContent?.trim()); // shortsを含めない
                break;
              case 4:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@id="metadata-line"]/span[1]', v)?.textContent || "0"; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1)
                break;
              case 5:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@id="metadata-line"]/span[1]', v)?.textContent || "0"; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) })
                break;
              case 6:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@class="style-scope ytd-video-meta-block"]/div/span[2]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1)
                break;
              case 7:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@class="style-scope ytd-video-meta-block"]/div/span[2]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) })
                break;
              case 8:
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => eleget0('//a[@class="yt-simple-endpoint style-scope yt-formatted-string"]', v)?.textContent);
                break;
              case 9:
                $('.yhmSortType').remove();
                //              sortdom(elegeta('ytd-playlist-renderer:visible'), v => -Number(eleget0('.style-scope.ytd-thumbnail-overlay-side-panel-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "")||0) ) ;
                sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer,ytd-playlist-renderer:visible'), v => Number(eleget0('.style-scope.ytd-thumbnail-overlay-side-panel-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "") || 0) * 10000000 || Number(eleget0('span#text.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "")), 1);
                $('.yhmSortType').remove();
                break;
            }
            return
          }
        },
      }],
      //WhateverFirstAndEveryAPFunc: () => {if((/\/\/www.youtube.com\/results\?search_query=/.test(location.href)) || (/\/\/www.youtube.com\/channel\/[^\/]+\/videos/.test(location.href) || /\/\/www.youtube.com\/user\/[^\/]+\/videos/.test(location.href))) popup3(`A:ソート`,8,5000)},
      //      wholeHelp: [() => (/\/\/www.youtube.com\/results\?search_query=/.test(location.href)) || (/\/\/www.youtube.com\/channel\/[^\/]+\/videos/.test(location.href) || /\/\/www.youtube.com\/user\/[^\/]+\/videos/.test(location.href)), " A:ソート"],
      wholeHelp: [() => (lh(/\/\/www\.youtube\.com\/playlist\?list=/) || /\/\/www.youtube.com\/results\?search_query=/.test(location.href) || lh(/\/\/www.youtube.com\/(?:channel\/|c\/|user\/|@)[^\/]+\/(?:videos|shorts|streams)/)), " A:ソート"],
    },
    {
      id: 'IHERB',
      urlRE: '//.*.iherb.com/',
      title: 'div.product-title,div div#name',
      box: 'div.product-cell-container',
      //listTitleXP: '//div[@class="absolute-link-wrapper"]/a',
      //listTitleSearchXP: '//div[@class="absolute-link-wrapper"]/a[++title++]/../../..',
      //listTitleMemoSearchXP: '//div[@class="absolute-link-wrapper"]/a[++title++]|.//div[@itemprop="name" and @id="name" and ***]|.//div/div[@id="name" and ***]|//section[3]/div[@id="product-summary-header"]/div[3][***]',
      //listGen: 3,
      observe: 1000,
      //runWhenUrlHasChanged:1,
      detailURLRE: /iherb.com\/pr\//,
      detailTitleXP: '//div[@itemprop="name" and @id="name"]',
      detailTitleSearchXP: '//div[@itemprop="name" and @id="name"][***]/../../../../..',
      trim: 1,
      titleProcessFunc: (title) => { return title.replace(/<br>/gmi, "")?.trim() },
      func: () => {
        elegeta('//div[@itemprop="name" and @id="name"]').forEach(e => e.textContent = e.textContent.replace(/\&/gmi, "&").replace(/\"/gmi, "”").trim()) // &はxpath/textで見逃す
        elegeta('//div[@class="absolute-link-wrapper"]/a').forEach(e => e.title = e.title.replace(/\&/gmi, "&").replace(/\"/gmi, "”").trim())
        GM_addStyle('.product-column .product { height: auto; min-height:395px; }');
      }, // 商品ブロックの縦幅固定をやめる
    },
    {
      id: 'YODOBASHI',
      urlRE: '//www.yodobashi.com/',
      listTitleXP: '//div[@class="pName fs14"]/p[2]|.//div[@class="product js_productName"]',
      listTitleSearchXP: '//div[@class="pName fs14"]/p[2][+++]/../../..|.//div[@class="product js_productName" and +++]/../../..|.//div[@class="product js_productName" and +++]/../../../../..',
      listTitleMemoSearchXP: '//div[@class="pName fs14"]/p[2][+++]|.//div[3]/h1[@id="products_maintitle"]/span[1][+++]|.//div[@class="product js_productName" and +++]|.//div[@class="product js_productName"][+++]',
      listGen: 4,
      listHelpXP: '//div[@class="pName fs14"]/p[2]/../../..',
      detailURLRE: /\/www.yodobashi.com\/product\//,
      detailTitleXP: '//div[3]/h1[@id="products_maintitle"]/span[1]',
      detailTitleSearchXP: '//div[3]/h1[@id="products_maintitle"]/span[1][+++]/../../../../..',
      hideListEvenDetail: 1,
      observe: 500,
      automemoURLRE: /^https:\/\/www.yodobashi.com\/product\//,
      automemoSearchFunc: () => { return eletext(['//div[@id="pinfo_productSummury"]', '//div[@id="productSet1Box"]', '//div[@class="specBox"]', '//h1[@class="pName js_variHeight"]/span[1]']); },
      automemoFunc: () => {
        var cat = elegeta('//div[@class="txtnav clearfix"]');
        if ((cat.some(e => /ヘルス&ビューティー/.test(e.innerText)))) {
          [/(イソプロピルメチルフェノール)/m, /(IPMP)/m, /(塩化セチルピリジニウム|塩化セシルピリジニウム|セチルピリジニウム塩化物)/m, /(CPC)/m, /(塩化ベンザルコニウム)/m, /(BKC)/m, /(ラウロイルサルコシンナトリウム|ラウロイルサルコシンNa|ラウロイルサルコシンNa)/m, /(LSS)/m, /(塩化ベンゼトニウム)/m, /(BTC)/m, /(クロルヘキシジン)/m, /(CHG)/m, /(グリチルリチン酸アンモニウム)/m, /(イプシロン.アミノカプロン酸)/m, /(ε.ACA)/m, /(トラネキサム酸)/m, /(TXA)/m, /(グリチルリチン酸ジカリウム|グリチルリチン酸二カリウム|グリチルリチン酸2K|グリチルリチン酸2K|GK2)/mi, /(1\,?450\s?ppm)/m, /(高?濃?度?フッ化ナトリウム|高?濃?度?フッ素)/m, /(ハイドロオ?キシアパタイト)/m, /(リン酸化オリゴ糖カルシウム)/m, /(POs-Ca|POs-Ca)/mi, /(カゼインホスホペプチド.非結晶性リン酸カルシウム|リカルデント)/m, /(CPP-ACP)/m, /(チモール)/m, /(サリチル酸メ?チ?ル?)/m, /(1\,8-シネオール)/m, /(トリクロサン)/m, /(トリクロカルバン)/m, /(オクトピロックス|ピロクトン.?オラミン)/m, /(Znピリチオン|ジンクピリチオン)/m, /(硫黄|イオウ)/m, /(アラントイン)/m, /(グリチルリチン酸アンモニウム)/m, /(ミコナゾール硝?酸?塩?)/m, /(クロラムフェニコール)/m, /(フラジオマイシン硫?酸?塩?)/m, /(ナイスタチン)/m, /(塩化亜鉛)/m, /(ポビドン.?ヨード)/m, /(ラウリルジアミノエチルグリシンナトリウム)/m, /(カキタンニン)/m, /(チャエキス)/m, /(ローズマリー)/m, /(カンゾウ)/m, /(クマザサ)/m, /(セージ)/m, /(シソエキス)/m, /(β?-?グリチルレチン酸?)/m, /(メントール)/m, /(ポリリン酸ナトリウム|ポリリン酸Na)/m, /(ヒノキチオール)/m, /(ティーツリー油オ?イ?ル?)/m, /(ティートゥリー油オ?イ?ル?)/m].forEach(m => autoMemo(m));
        }
        if ((cat.some(e => /浄水器/.test(e.innerText)))) {
          //          [/([0-90-9++].*?物質)/m, /(除?去?物質.{0,19}[0-90-9++]+)/m, /([0-90-9++]+?項目)/gm,/(交換.{1,19}[0-9.]+ヶ月)|(交換.{1,19}[0-9.]+年)|(取替.{1,19}[0-9.]+ヶ月)|(取替.{1,19}[0-9.]+年)/m].forEach(m => autoMemo(m)); //,/(除去物質数[\s\S]*\d+)/gm
          [/([0-90-9++].*?物質)/m, /([0-90-9++]+?項目)/gm, /(交換.{1,19}[0-9.]+ヶ月)|(交換.{1,19}[0-9.]+年)|(取替.{1,19}[0-9.]+ヶ月)|(取替.{1,19}[0-9.]+年)/m].forEach(m => autoMemo(m)); //,/(除去物質数[\s\S]*\d+)/gm
        }
        if ((cat.some(e => /電池/.test(e.innerText)))) {
          [/([\d\s\,]+mAh)/m, /([\d\s\,]+mAh)/m, /([\d\s\,]{2,9}回)/m].forEach(m => autoMemo(m));
        }
        if ((cat.some(e => /食器/.test(e.innerText)))) {
          [/(?:寸法|サイズ).*[::](.+)$/m, /容量[::](.+$)/m, /生産国[::](.+$)/m, /(深さ.*[::].+$)/m, /(\dつ穴)/m].forEach(m => autoMemo(m));
        }
        if ((cat.some(e => /シュレッダー/.test(e.innerText)))) {
          [/(細断サイズ[\s\S]{0,9}[0-9.]+×?[0-9.]*m?m?)/m, /ダストボックス(容量[\s\S]{0,9}[0-9.]+L)/m].forEach(m => autoMemo(m));
        }
        if ((cat.some(e => /食品/.test(e.innerText)))) {
          [/(食物繊維\D{0,9}[0-9.]+[gg])/m].forEach(m => autoMemo(m));
        }
        if ((cat.some(e => /圧力鍋/.test(e.innerText)))) {
          [/(低圧\D?\d+kpa)/mi, /(高圧\D?\d+kpa)/mi, /(圧力[\::]\d+kPa)/mi].forEach(m => autoMemo(m));
        }
        if ((cat.some(e => /ヘッドセット/.test(e.innerText)))) {
          [/(感度.{1,20}dB)/mi, /(\-\s*[0-90-9]+\s*dB)/mi].forEach(m => autoMemo(m));
        }
      },
      redoWhenReturned: 1,
    },
    {
      id: 'TSUGIMANGA',
      urlRE: '//tsugimanga.jp/',
      listTitleXP: '//div/div[@class="work__title"]',
      listTitleSearchXP: '//div/div[@class="work__title"][+++]/../..',
      listTitleMemoSearchXP: '//div/div[@class="work__title" and +++]',
      listGen: 5,
    },
    {
      id: 'NICOSEIGA_COMIC',
      //        urlRE: /\/\/seiga.nicovideo.jp\/comic\/|\/\/seiga.nicovideo.jp\/watch\//,
      urlRE: /\/\/seiga.nicovideo.jp\/(?:watch|comic|manga)\//,
      title: 'div.main_title>h1,div.description>div.title>a,div.inner_content>div>h1>span.episode_title,div.description_block>div>div>div.title>a,strong.mg_title>a',
      //      box: 'div.main_title,li.episode_item,article#detail.vertical,li.mg_item.item,#mg_recent_inner li,div.inner.cfix div div.title h1', //'',
      box: 'div.main_title,li.episode_item,li.mg_item.item,#mg_recent_inner li,div.inner.cfix div div.title h1', //'',
      forceTranslucentFunc: e => e.closest('div.main_title,div.inner.cfix div div.title h1'),
      trim: 1,
      /*listTitleXP: '//div[@class="title"]/a',
      listTitleSearchXP: '//div[@class="title"]/a[+++]/../../../..',
      listTitleMemoSearchXP: '//div[@class="title"]/a[+++]|//div/div/div/div[@class="title"]/h1/span[last()][+++]',*/
      //listHelpXP: '//div[@class="title"]/a/../../..',
      listHelpJQS: 'div.main_title,li.episode_item,article#detail.vertical,li.mg_item.item,#mg_recent_inner li',
      //listGen: 4,
      //listTitleMemoSearchXPSameGen: 1,
      /*detailURLRE: /\/\/seiga.nicovideo.jp\/watch\//,
      detailTitleXP: '//div/div/div/div[@class="title"]/h1/span[last()]',
      detailTitleSearchXP: '//div/div/div/div[@class="title"]/h1/span[last()][+++]/../../../../../..',*/
      redoWhenReturned: 1,
      disableHelpUrlRE: /\/watch\//,
    },
    {
      id: 'NICOSEIGA',
      urlRE: '//seiga.nicovideo.jp/illust/ranking/point/',
      listGen: 5,
      // 項目名:投稿者名
      listTitleXP: '//span[@class="rank_txt_user"]/a',
      listTitleSearchXP: '//span[@class="rank_txt_user"]/a[+++]/../../../../../..',
      listTitleMemoSearchXP: '//span[@class="rank_txt_user"]/a[+++]',
      listHelpXP: '//tr/td[contains(@class,"rank_block_right rank_no_")]',
    },
    {
      id: 'NICOSEIGA',
      urlRE: '//seiga.nicovideo.jp/tag/|//seiga.nicovideo.jp/seiga/|//seiga.nicovideo.jp/user/illust/|//seiga.nicovideo.jp/illust/|//seiga.nicovideo.jp|//seiga.nicovideo.jp/my/personalize',
      listGen: 5,
      detailURLRE: /\/\/seiga.nicovideo.jp\/seiga\/|\/\/seiga.nicovideo.jp\/user\/illust\//,
      // 項目名:投稿者名
      listTitleXP: '//li[@class="user"]|.//span[@class="rank_txt_user"]/a|.//span[@class="popular_illust_block__item__info--nickname"]|.//p[@class="info_source"]/a[@class="user_name"]',
      listTitleSearchXP: '//li[@class="user" and +++]/../../..|.//span[@class="rank_txt_user"]/a[+++]/../../../..|.//span[@class="popular_illust_block__item__info--nickname" and +++]/../../..|.//p[@class="info_source"]/a[@class="user_name" and +++]/../../..',
      hideListEvenDetail: 1,
      listTitleMemoSearchXP: '//li[@class="user" and +++]/..|//ul/li[@class="user_name"]/strong[+++]/..|.//span[@class="nickname" and +++]/..|.//span[@class="rank_txt_user"]/a[+++]|.//span[@class="popular_illust_block__item__info--nickname" and +++]|.//p[@class="info_source"]/a[@class="user_name" and +++]',
      listHelpXP: '//li[contains(@class,"list_item list_no_trim2")]/a|.//tbody/tr/td[contains(@class,"rank_list_block rank_no_")]|.//div[@class="popular_illust_block__item"]|.//ul[@class="item_list"]/li[@class="list_item  middle"]/a|.//div/ul[@class="item_list"]/li[@class="list_item middle"]/a|.//p[@class="info_source"]/a[@class="user_name"]/../../..',
      detailTitleXP: '//ul/li[@class="user_name"]/strong|//span[@class="nickname"]',
      detailTitleSearchXP: '//ul/li[@class="user_name"]/strong[+++]/../../../../../../../../../../../..|//span[@class="nickname" and +++]/../../../../../../..',
    },
    {
      id: 'KAKAKU',
      urlRE: '//kakaku.com/search_results/',
      listTitleXP: '//p[@class="p-item_name s-biggerlinkHover_underline"]',
      listTitleSearchXP: '//p[@class="p-item_name s-biggerlinkHover_underline"][+++]/../../../../..',
      listTitleMemoSearchXP: '//p[@class="p-item_name s-biggerlinkHover_underline"][+++]',
      listGen: 5,
    },
    {
      id: 'KAKAKU',
      urlRE: '//kakaku.com/specsearch|//kakaku.com/item/',
      listTitleXP: '//td[@class="textL"]/strong/a[1]',
      listTitleSearchXP: '//td[@class="textL"]/strong/a[1 and +++]/../../..',
      listTitleMemoSearchXP: '//td[@class="textL"]/strong/a[1 and +++]|//div[@class="boxL"]/h2[@itemprop="name" and +++]/..',
      listGen: 4,
      detailURLRE: /\/\/kakaku.com\/item\//,
      detailTitleXP: '//div[@class="boxL"]/h2[@itemprop="name"]',
      detailTitleSearchXP: '//div[@class="boxL"]/h2[@itemprop="name" and +++]/../../../..',
    },
    {
      id: 'HELLOWORK',
      urlRE: '//www.hellowork.mhlw.go.jp/kensaku/',
      listTitleXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div',
      listTitleSearchXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div[+++]/../../../../../../../../..|//div[@id="ID_kjNo"]',
      listTitleMemoSearchXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div[+++]/../../../..|//div[@id="ID_kjNo" and +++]/../../..',
      listHelpXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div/../../../../../../../../..',
      listGen: 8,
      detailURLRE: /Detail/i,
      detailTitleXP: '//div[@id="ID_kjNo"]',
      detailTitleSearchXP: '//div[@id="ID_kjNo" and +++]/../../../../..',
      func: () => { if (location.href.match(/detail/i)) { GM_addStyle('table.normal tr th, table.normal tr td { padding: 0.2em 1em;}') } else { GM_addStyle('table.kyujin th, table.kyujin td { padding: 0.5em 0.5em; } table.normal tr th, table.normal tr td { border-top: 1px solid #125939; padding: 0.5em 10px; text-align: left; } .mb03 { margin-bottom: 0em; }'); } },
    },
    {
      id: 'USERBENCHMARK',
      urlRE: '.*?.userbenchmark.com',
      listTitleXP: '//span/a[@class="nodec"]',
      listTitleSearchXP: '//span/a[@class="nodec" and +++]/../../../../..',
      listTitleMemoSearchXP: '//span/a[@class="nodec" and +++]|//h1[@class="pg-head-title"]/a[+++]',
      listGen: 5,
      observe: 1000,
      detailURLRE: /\/\/.*?.userbenchmark.com\/SpeedTest\/|\/\/.*?.userbenchmark.com\/.*?\/Rating\//i,
      detailTitleXP: '//h1[@class="pg-head-title"]/a',
      detailTitleSearchXP: '//h1[@class="pg-head-title"]/a[+++]/../../..',
      automemoURLRE: /\/\/.*?.userbenchmark.com\/SpeedTest\/|\/\/.*?.userbenchmark.com\/.*?\/Rating\//i,
      automemoSearchFunc: () => { return eletext('//h3[@class="pg-head-toption"]/span[@class="pg-head-toption-post"]') + "\n"; },
      automemoFunc: () => { autoMemo(/(.*)/); },
    },
    {
      urlRE: '//www.sukima.me/(?!bv|login)',
      id: 'SUKIMA',
      listTitleXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div',
      listTitleSearchXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div[***]/../../../..',
      listTitleMemoSearchXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div[***]',
      listHelpXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div/../../../..',
      listGen: 5,
      titleProcessFunc: title => { return title.replace(/\n\s*?\n\s*?|(?分冊版)?.*|【期間限定 無料お試し版】.*|[0-90-9]*?巻.*/g, "").trim() },
      observe: 1500,
      func: () => {
        /*        var observeUrlHasChangedhref = location.href;
                var observeUrlHasChanged = new MutationObserver(mutations => { if (observeUrlHasChangedhref !== location.href) location.reload() });
                observeUrlHasChanged.observe(document, { childList: true, subtree: true });
          */
        document.title = document.title.replace(/(^\[.*\])(.*)/, "$2$1");
      } // ページタイトルの「[全話無料]」等の接頭辞を末尾に移動
    },
    {
      urlRE: '//www.mangaz.com/',
      //      id: 'MANGAZ', // SUKIMAと登録内容を共通にしない
      id: 'SUKIMA', // SUKIMAと登録内容を共通にする
      title: 'div.listBoxDetail>h4>a,p.author,div.header h2,ul.seriesAuthor li a,span.sort-word' + `,ul.detailAuthor li span a`,
      box: '.itemList>li,div.seriesMain div.header,div.sort-inner' + `,ul.detailAuthor`,
      forceTranslucentFunc: e => e.closest('div.seriesMain div.header,div.sort-inner' + `,ul.detailAuthor`),
      observeFunc: e => e?.nodetype === 1 && e?.matches('.itemList>li,div.seriesMain div.header,div.sort-inner'),
      listHelpJPS: '.itemList>li,div.seriesMain div.header,div.sort-inner',
      listHelpXP2: 'p.author,ul.seriesAuthor li a',
      XP2name: '作者名 ',
      wholeHelp: [() => 1, " Shift+F:作品検索 A:ソート"],
      keyFunc: [{
        key: 'Shift+F', // Shift+F::キーワード検索
        func: () => { searchWithHistory("MANGAZ", "マンガ図書館Z", 'https://www.mangaz.com/title/index?category=&query=***&sort=&search=input', "") },
      }, {
        key: 'a', // a::ソート
        func: () => {
          var sorttype = GF.yhmSortType || 0;
          //          $('.yhmSortType').remove(), $(document.body).append(`<span class="yhmSortType" id="${++sorttype%2}"></span>`)
          GF.yhmSortType = ++sorttype % 2
          popup2("A:ソート\n" + (["タイトル", "著者名"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
          sorttype == 1 && sortdom(elegeta('.itemList>li'), v => eleget0('div.listBoxDetail>h4>a', v)?.textContent)
          sorttype == 2 && sortdom(elegeta('.itemList>li'), v => eleget0('.listBoxDetail>p', v)?.textContent)
        }
      }],
      titleProcessFunc: (title) => { return title.replace(/\s[0-90-9]+巻?$|【.*?】|全.*?巻|第\d*話/gmi, "").trim() },
      observe: 500,
      redoWhenRefocused: 1,
      func: () => {
        document.title = document.title.replace(/(^【.*】)(.*)/, "$2$1"); // ページタイトルの「[全話無料]」等の接頭辞を末尾に移動
        // 作品一覧の著者名をクリックで検索できるようにする
        elegeta('p.author:not([data-linked])').forEach((e, i, a) => {
          let author = e.textContent.trim().replace(/,/gm, " ").replace(/\s+/gm, " ")
          let url = 'https://www.mangaz.com/title/index?category=&query=***&sort=&search=input'.replace("***", encodeURI(author))
          e.dataset.linked = url
          e.style.cursor = "pointer"
          e.title = `クリックで「${author}」で作品検索をします\n${url}`
          e.addEventListener("click", v => window.open(v.target.dataset.linked))
        })
      }
    },
    {
      id: 'PICCOMA',
      urlRE: '//piccoma.com/',
      listTitleXP: '//div[@class="PCM-productCoverImage_title"]/span|.//div[@class="PCM-rankingProduct_title"]/p|.//p[@class="PCM-productCoverImage_title"]/span',
      listTitleSearchXP: '//div[@class="PCM-productCoverImage_title"]/span[+++]/ancestor::li[contains(@class,"PCM-slotProducts_list")]|.//div[@class="PCM-rankingProduct_tdata"]/div/p[+++]/ancestor::li[contains(@class,"PCM-slotProducts_list")]|.//p[@class="PCM-productCoverImage_title"]/span[+++]/ancestor::li[contains(@class,"PCM-slotProducts_list")]',
      listTitleMemoSearchXP: '//div[@class="PCM-productCoverImage_title"]/span[+++]', // 実質表示されない
      listGen: 7,
      observe: 3000,
    },
    {
      id: 'TAMESHIYOMI',
      urlRE: '//www.cmoa.jp/freecontents/',
      listTitleXP: '//p[@class="titile_name"]/a',
      listTitleSearchXP: '//p[@class="titile_name"]/a[+++]/../../../..',
      listTitleMemoSearchXP: '//p[@class="titile_name"]/a[+++]',
      listGen: 4,
      redoWhenReturned: 1,
    },
    {
      id: 'ja.aliexpress.com',
      urlRE: '//ja.aliexpress.com/',
      listTitleXP: '//h1[@class="_3eC3x"]/../../..',
      listTitleXP2: '//a[@class="ox0KZ"]',
      listHelpXP: '//h1[@class="_3eC3x"]/../../..',
      XP2name: 'セラー名 ',
      XP2memo: 1,
      listTitleSearchXP: '//a[**url**]/*/*/h1[@class="_3eC3x"]/../../..|//a[@class="ox0KZ"][+++]/../../..',
      listTitleMemoSearchXP: '//a[**url**]/*/*/h1[@class="_3eC3x"]|//a[@class="ox0KZ"][+++]',
      listGen: 3,
      useURL: 1,
      func: () => { // 商品名を全行表示する
        elegeta('//div[@class="product-container"]/div[2]/a/div[2]/div[1]/h1').forEach(e => {
          e.style.whiteSpace = "";
          e.style.height = "auto";
          e.style.whiteSpace = "normal";
          e.parentNode.style.display = "block"
        });
      },
    },
    {
      id: 'GREASYFORK',
      urlRE: '//greasyfork.org/.*?/scripts',
      listTitleXP: `//a[@class="script-link"]|.//a[@class="script-link"]/font/font`, //'//article/h2/a',
      listTitleSearchXP: `//a[@class="script-link"][+++]/ancestor::li|.//a[@class="script-link"]/font/font[+++]/ancestor::li`, //'//article/h2/a[+++]/../../..|//article/h2/a/font/font[+++]/../../../../..',
      listTitleMemoSearchXP: `//a[@class="script-link"][+++]|.//a[@class="script-link"]/font/font[+++]/../..`, //'//article/h2/a[+++]|//article/h2/a/font/font[+++]/../..',
      listGen: 7,
      // func:(n)=>{elegeta('//h2/a[@class="script-link"]',n).forEach(e=>{$(e.parentNode.parentNode.parentNode).append(' <a style="float:right;margin:0 0 0 1em;" href="'+e.href+'/stats?period=all">統計</a>').append(' <a style="float:right;margin:0 0 0 1em;" href="'+e.href+'/feedback">フィードバック</a>')})  },
    },
    {
      id: 'JMTY',
      urlRE: '//jmty.jp/',
      listTitleXP: '//div[@class="p-item-title"]/a',
      listTitleSearchXP: '//div[@class="p-item-title"]/a[++url++]/../../..',
      listTitleMemoSearchXP: '//div[@class="p-item-title"]/a[++url++]',
      listGen: 5,
      useURL: 1,
    },
    {
      id: 'EBAY',
      urlRE: 'ebay.com/',
      //title:'//a[@class="s-item__link"]/div[@class="s-item__title"]/span',
      //box:'div#srp-river-results ul li',
      listTitleXPIgnoreNotExist: 1,
      // @match *://www.ebay.com/*
      listTitleXP: '//div[@class="s-item__title"]/span[@role="heading"]/../..',
      listTitleSearchXP: '//div[@class="s-item__title"]/span[@role="heading"]/../..[**url**]/../../..',
      listTitleMemoSearchXP: '//div[@class="s-item__title"]/span[@role="heading"]/../..[**url**]|//h1[@class="x-item-title__mainTitle"]/span[1][**url**]/..',
      listGen: 5,
      //  detailURLRE:/$^/,
      detailTitleXP: '//h1[@class="x-item-title__mainTitle"]/span[1]',
      detailTitleSearchXP: '//h1[@class="x-item-title__mainTitle"]/span[1][**url**]/../../../../..',
      /*listTitleXP: '//a[@class="s-item__link"]/h3/..',
      listTitleSearchXP: '//a[@class="s-item__link"][**url**]/h3/../../../..|//div[@class="si-inner"]/div/div/div/a/span[@class="mbg-nw"][+++]',
      listTitleMemoSearchXP: '//a[@class="s-item__link"][**url**]/h3/../..|//h1[@itemprop="name" and @id="itemTitle"][**url**]/..|//div[@class="si-inner"]/div/div/div/a/span[@class="mbg-nw"][+++]/..',
      listTitleXP2: '//div[@class="si-inner"]/div/div/div/a/span[@class="mbg-nw"]',*/
      XP2memo: 1,
      XP2name: 'セラー名 ',
      listGen: 6,
      useURL: 1,
      funcOnlyFirst: () => {
        //let u=eleget0('//meta[@property="og:url"]')?.content; eleget0('//h1[@class="x-item-title__mainTitle"]/span[1]').href=u
        var e = eleget0('//link[@rel="canonical"]');
        //var t = eleget0('//h1[@itemprop="name" and @id="itemTitle"]')
        var t = eleget0('//h1[@class="x-item-title__mainTitle"]/span[1]|//h1[@itemprop="name" and @id="itemTitle"]')
        if (e && t) t.setAttribute("href", e.href)
      },
      detailURLRE: /www.ebay.com\/itm\//,
      //      detailTitleXP: '//h1[@itemprop="name" and @id="itemTitle"]',
      //    detailTitleSearchXP: '//h1[@itemprop="name" and @id="itemTitle"][**url**]/../../../../../../../..|//div[@class="si-inner"]/div/div/div/a/span[@class="mbg-nw"][+++]/../../../../../../../..',
      //titleProcessFunc: title => { return title.replace(/^NEW LISTING|^Details about\s*/i, "") },

      //listTitleXP: '//h3[contains(@class,"s-item__title")]|//h1[@id="itemTitle"]',
      //  listTitleSearchXP: '//h3[contains(@class,"s-item__title") and ***]/../../../..',
      //  listTitleMemoSearchXP: '//h3[contains(@class,"s-item__title") and ***]|//h1[@id="itemTitle" and ***]/..',
      //  listGen: 6,

      //detailURLRE: /www.ebay.com\/itm\//,
      //detailTitleXP: '//h1[@id="itemTitle"]',
      //detailTitleSearchXP: '//h1[@id="itemTitle" and ***]/../../../..',
      //titleProcessFunc: title => { return title.replace(/^NEW LISTING|^Details about\s*/i, "") },
      listHelpJQS: 'li.s-item',
      helpInBlock: 1,
      maxpriceXP: '//div/input[@aria-label="Maximum Value"]',
    },
    {

      id: '2CHTHREADLIST',
      urlRE: /\/\/.*\.5ch\.net\/\w*\/$/,
      listTitleXP: '//td/a',
      listTitleSearchXP: '//table[@id="thread-list"]/tbody/tr/td/a[+++]/../..',
      listTitleMemoSearchXP: '//tr/td/a[+++]',
      listTitleMemoSearchXPSameGen: 1,
      listGen: 6,
      delay: 1000,
      observe: 500, // 並べ替え時に必要
      redoWhenReturned: 1,
      keyFunc: [{
        key: 'Shift+F', // Shift+F::refind2chでキーワード検索
        func: () => { searchWithHistory("REFIND2CH", "re.Find2ch", 'https://refind2ch.org/search?q=***&sort=rate', " OR ") },
      }],
    },
    { // 5chスレッド内
      id: `${/shitaraba\.net/.test(location.href)?"SHITARABA":"5CH"}`, //'5CH',
      urlRE: '.5ch.net/test/read.cgi/|.shitaraba.net/bbs/read.cgi/|.shitaraba.net/bbs/read_archive.cgi/',
      listTitleXP2: '//span[@class="uid"]',
      listTitleXPIgnoreNotExist: 1,
      forceRunIffunc: () => { return /\.shitaraba\.net\/bbs\/read\.cgi\//.test(location.href) || eleget0('.thread > dd:nth-child(2)') },
      //      titleProcessFunc: (title) => { return title.replace(/\>\>.*$/, "").replace(/ |\s|:/g, "").trim() },
      //      titleProcessFunc: (title) => { return title.replace(/\>\>.*$/, "").trim() },
      //      titleProcessFunc: (title) => { return /^\d{1,4}.+\d\d\d\d\/\d\d\/\d\d\(.\)\s\d\d\:/.test(title) ? title.replace(/\>\>.*$/, "").replace(/ |\s|:/g, "").trim() : title.replace(/\>\>.*$/, "").trim() },
      hideSelectedWord: 1,
      //      selectedHelp: { help: [KEYHIDE + ":NGワードに追加"], multi: "複数行に渡る文字列は NG に入れられません" },
      selectedHelp: { help: [KEYHIDE + ":NGワードに追加"] }, //, multi: "複数行に渡る文字列は NG に入れられません" },
      //      titleProcessFunc: (title) => { return /^\d{1,4}.+\d\d\d\d\/\d\d\/\d\d\(.\)\s\d\d\:/.test(title.replace(/\n/gm, "").trim()) ? title.replace(/\>\>.*$/, "").replace(/\n| |\s|:/g, "").trim() : title.replace(/\n/gm, "").replace(/\>\>.*$/, "").trim() },
      titleProcessFunc: (title) => { return /^\d{1,4}.+\d\d\d\d\/\d\d\/\d\d\(.\)\s..\:/.test(title.replace(/\n/gm, "").trim()) ? title?.replace(/⋮/g, "").replace(/\>\>.*$/, "").replace(/\n| |\s|:/g, "").trim() : title?.replace(/⋮/g, "").replace(/\n/gm, "").replace(/\>\>.*$/, "").trim() },
      XP2name: 'ID ',
      //      id: '5CH',
      //      urlRE: '.5ch.net/test/read.cgi/',
      listTitleXP: '//div[@class="meta"]', // 項目名はレス番~IDまでの一連のdiv.meta
      listTitleSearchXP: '//div[@class="meta"][**alt**]/..|//span[@class="escaped"][***]/../..',
      listTitleMemoSearchXP: '//div[@class="meta"][**alt**]/span[@class="date"]',
      //      listHelpXP: '//div/div[@class="post"]',
      listHelpXP: '//div[@class="post"]',
      listGen: 6,
      searchAllowLength: 1,
      //      delay: 100, //delayAutoWeighting: 0.6, // 5chサムネイル表示他のhNukiURLHokan()より後でないとメモを消せなくなる
      delay: 100, //delayAutoWeighting: 0.6, // 5chサムネイル表示他のhNukiURLHokan()より後でないとメモを消せなくなる
      keyFunc: [{
        key: 'Shift+F', // Shift+F::refind2chでキーワード検索
        func: () => { searchWithHistory("REFIND2CH", "re.Find2ch", 'https://refind2ch.org/search?q=***&sort=rate', " OR ") },
      }, {
        key: 'a', // a::
        func: () => {
          var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
          $('.yhmSortType').remove();
          $(document.body).append(`<span class="yhmSortType" id="${++sorttype}"></span>`)
          popup2("A:ソート\n" + (["引用", "リンク", "古い順"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
          $(".thread>br,#thread-body>br").remove()
          switch (sorttype) {
            case 1:
              domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return -(v.querySelectorAll('.allpopup').length) }, 1)
              break;
            case 2:
              domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return Number((v?.textContent?.match(/ttps?:\/\//gmi)?.length)) && -1 - Number((v.querySelectorAll('.allpopup').length)) || 0 }, 1)
              //domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return Number((v?.textContent?.match(/ttps?:\/\//gmi)?.length)) && -Number((v?.textContent?.match(/ttps?:\/\//gmi)?.length))*1000 - Number((v.querySelectorAll('.allpopup').length)) || 0 },1)
              break;
            case 3:
              domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return (v.id) }, 1)
              $('.yhmSortType').remove();
              break;
          }
          $('.post').after("<br>")
        }
      }],
      wholeHelp: [() => 1, " A:ソート"],
      listTitleSearchFunc: (title) => { // レス中キーワードNG
        let resHit = [];
        if (typeof title === "string" && /\D/m.test(title)) { // textContentでサーチする
          //          for (let res of elegeta('//div[@class="message"]')) { // レス本文
          for (let res of elegeta('.message')) { // レス本文
            if (res.textContent.indexOf(title) !== -1) resHit.push(res.parentNode);
          }
          //          for (let res of elegeta('//span[@class="uid"]')) { // ID
          for (let res of elegeta('.uid')) { // ID
            if (res.textContent.indexOf(title) !== -1) resHit.push(res.parentNode.parentNode);
          }
        }
        return resHit;
      },
      funcQ: function() {
        setTimeout(() => {
          $('div.post:hidden').next("br").css("display", "none");
          $('div.post:visible').next("br:hidden").css("display", "block");
        }, 200);
      }, //余計な改行を詰める
      funcB: () => SITE.funcQ(),
      funcOnlyFirst: () => {
        GM_addStyle('.uid:hover{background:#ddeeffc0; border: 0px solid #ddeeffc0; color: #000000; text-shadow: 0 0 4px #ddeeffc0; box-shadow: inset 0 0 6px #ddeeffc0, 0 0 6px #ddeeffc0; }')
        // 旧表示なら対応するために加工
        if (/\.shitaraba\.net\/bbs\/read\.cgi\/|\.shitaraba\.net\/bbs\/read_archive.cgi\//.test(location.href)) $('dl.rep-comment:hidden').remove(); // したらばでは本家の>>1等のアンカーの中に見えないHTMLのコピーがありQ等がそれに反応してしまうので消す
        if (/\.5ch\.net\/test\/read\.cgi\/|\.shitaraba\.net\/bbs\/read\.cgi\/|\.shitaraba\.net\/bbs\/read_archive.cgi\//.test(location.href) && eleget0("//div/dl/dt|//body/dl/dt")) {
          if (/\.shitaraba\.net\/bbs\/read/.test(location.href) && eleget0("//div/dl/dt|//body/dl/dt")) { $('dl>br').remove() }
          elegeta('.thread dd').forEach(e => elegeta('br', e)?.pop()?.remove()) // 本文末尾の空改行をtrim
          var res1 = elegeta("//div/dl/dt|//body/dl/dt").slice(0, 1001)
          var res2 = elegeta("//div/dl/dd|//body/dl/dd").slice(0, 1001)
          if (res1.length && res1.length == res2.length) {
            GM_addStyle('div.post{border-width: 1px; display: inline-block; border-style: none solid solid none; border-color: #ddd; background-color: #efefef; margin-bottom: 8px; padding: 8px;}div.meta { margin: 0 0 0.33em; } .message { font-size: 17px; color: #333; padding: 2px 0 10px; overflow-wrap: break-word; }')
            GM_addStyle('div.post2{background-color:#efefef; display:inline-block; padding:1em; margin:0; box-shadow: 1px 1px 2px #cccccc;} div.meta{margin:0 0 0.33em;} ') // line-height:1.2em;
            var e = eleget0('//div/dl[@class="thread"]/../../../..|//div[@id="thread-body-wrapper"]/..');
            if (e) e.style.backgroundColor = "#f2f3f7";
            var e = eleget0('//body/div/span[@style="float:left;"]');
            if (e) e.style.float = "none";
            res1.forEach((e, i) => {
              var res1t = e.textContent; // innerTextは遅い
              var res2o = res2[i].outerHTML; //alert(res2o)
              while (/<br>[\s]{0,22}\<\/dd\>/.test(res2o)) res2o = res2o.replace(/<br>[\s]{0,22}\<\/dd\>/, "</dd>"); // 後ろの空改行をtrim
              e.outerHTML = `<div class="post"><div class="meta" alt="${res1t.replace(/ |\s|:/g,"").trim()}"><span class="date">${res1[i].innerHTML}</span></div><div class="message"><span class="escaped">${res2o.replace(/^<dd>/,"").replace(/<\/dd>/,"")}</span></div></div><br>`;
              res2[i].remove();
            });
          }
          elegeta('//div[@class="post"]/div[1]/span[@class="date"]').slice(0, 1001).forEach(e => { e.closest(".post").id = e.textContent.trim().match0(/^\d+/) || null; })
          //document.body.dispatchEvent(new Event('ch5changedoldstyle')) })//
          adja(document.body, "beforeend", "<span id='ch5styleoldnewmodend'><span>"); //加工終了を告げる
        }
      },

      func: () => {
        for (let e of elegeta('//div[@class="meta"][not(@alt)]').slice(0, 1001)) { // レスの特定のために1行目をまとめてtitle属性に埋める
          let id = e.innerText.replace(/>>.*/g, "").replace(/ |\s|:/g, "").trim();
          e.setAttribute("alt", id); // e.style.pointerEvents="none";
        };
        SITE.funcQ();
        /*        $('body').on('mouseup', function(e) {
                  var selectedStr;
                  if (window.getSelection) {
                    selectedStr = window.getSelection().toString();
                    if (selectedStr !== '' && selectedStr !== '\n') {
                      if (selectedStr.indexOf("\n") !== -1) popup2("複数行に渡る文字列は NG に入れられません", 1);
                      else popup2(KEYHIDE + ' キー:\n『' + selectedStr + '』\nをNGワードに追加', 1);
                    }
                  }
                });
        */
      },
      hideSelectedWord: 1,
      memoStyle: ' float:right; ',
    },
    {
      id: 'NICODOUGA',
      urlRE: '//www.nicovideo.jp/ranking',
      listTitleXP: '//div/h2[@class="MediaObjectTitle VideoMediaObject-title MediaObjectTitle_fixed2Line"]',
      listTitleSearchXP: '//div/h2[@class="MediaObjectTitle VideoMediaObject-title MediaObjectTitle_fixed2Line"][+++]/../../../../..',
      listTitleMemoSearchXP: '//div/h2[@class="MediaObjectTitle VideoMediaObject-title MediaObjectTitle_fixed2Line"][+++]',
      listGen: 6,
    },
    {
      id: 'NICODOUGA',
      urlRE: '//www.nicovideo.jp/series/',
      listTitleXP: '//div[@class="VideoMediaObject-title"]/a',
      listTitleSearchXP: '//div[@class="VideoMediaObject-title"]/a[+++]/../../../..',
      listTitleMemoSearchXP: '//div[@class="VideoMediaObject-title"]/a[+++]',
      listGen: 5,
      listTitleHelpXP: '//div[@class="VideoMediaObject-title"]/a/../../../..',
    },
    {
      id: 'NICODOUGA', // nicosea::
      urlRE: '//www.nicovideo.jp/search/|//www.nicovideo.jp/tag/|//www.nicovideo.jp/watch/',
      //title: '.list li.item p.itemTitle>a,a.nrn-contributor-link,div h1.VideoTitle',
      title: '.list li.item p.itemTitle>a,a.nrn-contributor-link,div h1.VideoTitle,.nrn-movie-tag-link',
      box: '.list li.item',
      observe: 1000,
      //      ignoreDNI: e => e?.nodeName === "#text"||e?.classList?.contains('Marquee-item'),
      //ignoreDNI: e => !e?.classList?.contains('item'),
      //listTitleXP: '//div/p[@class="itemTitle"]/a|//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]',
      //listTitleSearchXP: '//div/p[@class="itemTitle"]/a[++title++]/../../..',
      //listTitleMemoSearchXP: '//div/p[@class="itemTitle"]/a[++title++]|//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"][+++]/..',
      listGen: 7,
      detailURLRE: /\/watch\//,
      detailTitleXP: '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]',
      detailTitleSearchXP: '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"][+++]',
      wholeHelp: [() => 1, " A:ソート"],
      keyFunc: [{
        key: 'a', // a::
        func: () => {
          if (lh("/watch")) return
          var sorttype = GF.yhmSortType || 0
          let menu = [
            { t: "タイトル", f: () => { sortdom(elegeta('.videoList ul.list li.item:visible'), v => eleget0('//p[@class="itemTitle"]/a', v)?.textContent) } },
            { t: "投稿者", f: () => { sortdom(elegeta('.videoList ul.list li.item:visible'), v => eleget0('//a[@class="nrn-contributor-link"]', v)?.textContent) } },
            { t: "いいね+マイリス", f: () => { sortdom(elegeta('.videoList ul.list li.item:visible'), v => (0 + Number(eleget0('//li[4]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[3]/span[@class="value"]', v)?.textContent || 0)) || -1, 1) } },
            { t: "いいね+マイリス+コメント", f: () => { sortdom(elegeta('.videoList ul.list li.item:visible'), v => (Number(eleget0('//li[2]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[4]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[3]/span[@class="value"]', v)?.textContent || 0)) || -1, 1) } },
            { t: "いいね+マイリス+コメント+再生", f: () => { sortdom(elegeta('.videoList ul.list li.item:visible'), v => (Number(eleget0('//li[2]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[4]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[3]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('li.count.view>span', v)?.textContent?.replace(/\,/gm, "") || 0) / 1000) || -1, 1) } },
          ]
          popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+2),0)}em;`);
          menu[sorttype].f()
          GF.yhmSortType = (++sorttype) % menu.length
        }
      }, {
        key: 'u', // u::チャプターメモ
        func: (e) => {
          chapterMemo(/watch/, '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]', `https://www.nicovideo.jp/watch/${(location.href.match0(/\/watch\/([^/?]+)/))}?from=**time**`)
        },
      }, {
        key: 'Shift+U', // Shift+U::チャプターメモをクリップボードにコピー
        func: (e) => {
          chapterMemo(/watch/, '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]', `https://www.nicovideo.jp/watch/${(location.href.match0(/\/watch\/([^/?]+)/))}?from=**time**`, 1)
        },
      }],
      funcOnlyFirst: () => {
        document.addEventListener('fullscreenchange', (event) => { if (document.fullscreenElement && $('video')[0] && $('video')[0].paused == false) { $("#yafuokuhelp").hide(200) } else { $("#yafuokuhelp").show(300) } })
        var observeUrlHasChangedhref = location.href;
        var observeUrlHasChanged = new MutationObserver(mutations => {
          if (observeUrlHasChangedhref !== location.href) {
            pauseAll = 1;
            prefCacheClear();
            observeUrlHasChangedhref = location.href;
            elegeta('//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
            setTimeout(() => {
              pauseAll = 0;
              run(document.body, "returned")
            }, 3500);
          }
        });
        observeUrlHasChanged.observe(document, { childList: true, subtree: true });
      },
      //      func: function(node) { for (let ele of elegeta('//div/p[@class="itemTitle"]/a', node)) ele.textContent = ele.title; }, // 長いタイトルが...で省略されているとヒットしないのでtitleプロパティから取り出す
      //    }, {
      //      id: 'NICODOUGA', // URLをキーにする
      //      urlRE: '//www.nicovideo.jp/user/.*/video',
      //      listTitleXP: '//a[@class="VideoMediaObject-linkArea"]',
      //      listTitleSearchXP: '//a[@class="VideoMediaObject-linkArea"][++url++]/..',
      //      listTitleMemoSearchXP: '//a[@class="VideoMediaObject-linkArea"][++url++]/div[2]/span',
      //      listGen: 6,
      //      useURL: 1,
      //      observe: 500,
      //      //func: function(node) { for (let ele of elegeta('//div/p[@class="itemTitle"]/a', node)) ele.textContent = ele.title; }, // 長いタイトルが...で省略されているとヒットしないのでtitleプロパティから取り出す
    },
    {
      id: 'NICODOUGA', // タイトルをキーにする
      urlRE: '//www.nicovideo.jp/user/.*/video',
      listTitleXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2',
      listTitleSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]/../../../../..',
      listTitleMemoSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]',
      listGen: 5,
      observe: 500,
      //                    {
      //      id: 'NICODOUGA', // タイトルをキーにする
      //      urlRE: '//www.nicovideo.jp/user/.*/video',
      //      listTitleXP: '//div[@class="VideoMediaObject-body"]/span',
      //      listTitleSearchXP: '//div[@class="VideoMediaObject-body"]/span[+++]/../../../..',
      //      listTitleMemoSearchXP: '//div[@class="VideoMediaObject-body"]/span[+++]',
      //      listGen: 5,
      //      observe: 500,
      //      func: function(node) { for (let ele of elegeta('//div/p[@class="itemTitle"]/a', node)) ele.textContent = ele.title; }, // 長いタイトルが...で省略されているとヒットしないのでtitleプロパティから取り出す
      // }, {
      //       id: 'NICODOUGA', // 旧(-2020年07月26日)
      //       urlRE: '//www.nicovideo.jp/user/.*/video',
      //       listTitleXP: '//div[@class="section VideoItem-videoDetail"]/h5/a',
      //       listTitleSearchXP: '//div[@class="section VideoItem-videoDetail"]/h5/a[+++]/../../..',
      //       listTitleMemoSearchXP: '//div[@class="section VideoItem-videoDetail"]/h5/a[+++]',
      //       listGen: 5,
      //       //      func: function(node) { for (let ele of elegeta('//div/p[@class="itemTitle"]/a', node)) ele.textContent = ele.title; }, // 長いタイトルが...で省略されているとヒットしないのでtitleプロパティから取り出す
    },
    {
      id: 'NICODOUGA', // タイトルをキーにする
      urlRE: '//www.nicovideo.jp/user/.*?/mylist/', // バグらなくなった
      listTitleXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2',
      listTitleSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]/../../../../..',
      listTitleMemoSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]',
      listGen: 6,
      observe: 500,
      listTitleXPIgnoreNotExist: 1,
      //    reloadWhenUrlHasChanged:1,
    },
    {
      id: 'NICODOUGA',
      urlRE: '//www.nicovideo.jp/my/mylist|www.nicovideo.jp/my/watchlater',
      listTitleXP: '//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"]',
      listTitleSearchXP: '//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"][+++]/../../../../../..',
      listTitleMemoSearchXP: '//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"][+++]',
      delay: 2000,
      listGen: 5,
      listTitleXPIgnoreNotExist: 1,
      //    reloadWhenUrlHasChanged:1,
      wholeHelp: [() => 1, " A:ソート"],
      keyFunc: [{
        key: 'a', // a::
        func: () => {
          if (lh("https://www.nicovideo.jp/my/watchlater|https://www.nicovideo.jp/my/mylist/")) {
            var sorttype = GF.yhmSortType || 0
            let menu = [
              //              { t: "時間長", f: () => { sortdom(elegeta('//section[@class="WatchLaterContainer"]/div[last()]/div'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")), 1) } },
              //            { t: "時間短", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, ""))) } },
              { t: "メモ多", f: () => { sortdom(elegeta('//div[@class="VideoMediaObjectList"]/div'), v => elegeta('.yhmMyMemo', v).length, 1) } },
              //          { t: "タイトル", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('#video-title', v)?.textContent?.trim()) } },
              //        { t: "投稿者", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('div.style-scope.ytd-channel-name yt-formatted-string a', v)?.textContent?.trim() || "") } },
              //      { t: "再生多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) } },
              //    { t: "再生少", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 0) } },
              //  { t: "古い", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
              //{ t: "新しい", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 0) } },
              //  { t: "逆順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 1) } },
              //  { t: "元順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 0) } },
            ]
            popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+2),0)}em;`);
            menu[sorttype].f()
            GF.yhmSortType = (++sorttype) % menu.length
            return
          }
        }
      }],
    },
    {
      id: 'RTINGS',
      urlRE: 'www.rtings.com/.*?/tools/table|//www.rtings.com/.*?/reviews/',
      listTitleXP: '//div/div[@class="table_cell_product-name"]',
      listTitleSearchXP: '//div/div[@class="table_cell_product-name"][***]/../../../../..',
      listTitleMemoSearchXP: '//div/div[@class="table_cell_product-name"][***]/..|//span[@class="e-page_title-primary"][***]',
      listGen: 3,
      listTitleXPIgnoreNotExist: 1,
      delay: 3000,
      observe: 1000,
      detailURLRE: /\/\/www.rtings.com\/.*?\/reviews\//,
      detailTitleXP: '//span[@class="e-page_title-primary"]',
      detailTitleSearchXP: '//span[@class="e-page_title-primary"][***]/../../../../..',
    },
    {
      id: 'TAMESHIYOMI',
      urlRE: 'csbs.shogakukan.co.jp',
      listTitleXP: '//div[1]/img[@class="is-item-cover loaded"]',
      listTitleSearchXP: '//div[1]/img[@class="is-item-cover loaded" and ++alt++]/../../..',
      listTitleMemoSearchXP: '//div[1]/img[@class="is-item-cover loaded" and ++alt++]',
      listGen: 3,
      listTitleXPIgnoreNotExist: 1,
      delay: 1000,
      observe: 1500,
      redoWhenReturned: 1,
    },
    {
      id: 'TAMESHIYOMI',
      urlRE: '//sokuyomi.jp/free_',
      listTitleXP: '//p[@class="title"]/a|//h1[@class="title"]',
      listTitleSearchXP: '//p[@class="title"]/a[++title++]/../..',
      listTitleMemoSearchXP: '//p[@class="title"]/a[++title++]', // 多分表示されない
      listGen: 3,
      observe: 900,
      listHelpXP: '//div[@id="content"]/div/ul/li',
      redoWhenReturned: 1,
    },
    {
      id: 'TAMESHIYOMI',
      urlRE: '//sokuyomi.jp/free\.',
      listTitleXP: '//img[@class="waku"]',
      listTitleSearchXP: '//img[@class="waku" and ++alt++]/../..',
      listTitleMemoSearchXP: '//img[@class="waku" and ++alt++]',
      listHelpXP: '//div[@id="content"]/div/ul/li',
      listGen: 3,
      observe: 600,
      redoWhenReturned: 1,
    },
    {
      urlRE: '//ebookjapan.yahoo.co.jp/viewer',
      func: () => {
        //$().ready(() => { setTimeout(() => { document.title = (eleget0('//div[@class="header__title"]').innerText || "") + " " + document.title; }, 2000); });
      },
    },
    {
      id: 'TAMESHIYOMI',
      urlRE: '//ebookjapan.yahoo.co.jp/free|//ebookjapan.yahoo.co.jp/ranking/details/free/',
      listTitleXP: '//p[@class="book-item__title"]',
      listTitleSearchXP: '//p[@class="book-item__title"][***]/../..',
      listTitleMemoSearchXP: '//p[@class="book-item__title"][***]',
      //listTitleXP: '//div[2]/p[@class="book-caption__title"]|.//p[@class="book-item__title"]',
      //listTitleSearchXP: '//div[2]/p[@class="book-caption__title" and ***]/../..|.//p[@class="book-item__title"][***]/../../..',
      //listTitleMemoSearchXP: '//div[2]/p[@class="book-caption__title" and ***]|.//p[@class="book-item__title"][***]',

      listGen: 3,
      titleProcessFunc: (title) => { return title.replace(/\s[0-90-9]+巻?$/gmi, "").replace(/[(\(][0-90-9]+巻?[)\)]$/gmi, "").replace(/【期間限定.*?】|【フルカラー】/g, "").replace(/\s\d+冊/gmi, "").replace(/\.\.\./gmi, "").trim() },
      observe: 1000,
      redoWhenReturned: 1,
    },
    {
      id: 'TAMESHIYOMI',
      urlRE: 'booklive.jp/index/no-charge',
      listTitleXP: '//p[@class="p-no-charge-book-item__title"]/a',
      listTitleSearchXP: '//p[@class="p-no-charge-book-item__title"]/a[***]/../../..',
      listTitleMemoSearchXP: '//p[@class="p-no-charge-book-item__title"]/a[***]',
      listGen: 5,
      titleProcessFunc: (title) => { return title.replace(/\s[0-90-9]+巻?$/gmi, "").replace(/[(\(][0-90-9]+巻?[)\)]/gmi, "").replace(/【.*?】|(.*?)|分冊版[\s::]*|合冊版[\s::]*/g, "").replace(/第?[0-90-9]+話?$/gmi, "").trim() },
      listTitleXPIgnoreNotExist: 1,
      observe: 1000,
      redoWhenReturned: 1,
    },
    {
      id: 'WCA',
      urlRE: 'webcomics\.jp',
      //      listTitleXP: '//div[@class="entry-title"]/a[1]|//div[@class="comic-title"]/h2/a[1]',
      //      listTitleSearchXP: '//div[@class="entry-title"]/a[+++]/../..|//div[@class="comic-title"]/h2/a[1][+++]/../../../../../..', // 完全一致のキーワードのみヒット+漫画サイト名にはヒットしない(高速)
      //      listTitleMemoSearchXP: '//div[@class="entry-title"]/a[+++]|//div[@class="comic-title"]/h2/a[1][+++]/..',
      title: '.entry-title>a:first-child,.entry-site>a',
      box: ".entry",
      //listTitleXP2: '//div[@class="entry-site"]/a[1]', // サイト名でQ/1/2可…重いので
      XP2name: 'サイト名 ',
      XP2memo: 1,
      //listTitleXP: '//div[@class="entry-title"]/a[1]|//div[@class="comic-title"]/h2/a[1]',
      //listTitleSearchXP: '//div[@class="entry-title"]/a[+++]/../..|//div[@class="comic-title"]/h2/a[1][+++]/../../../../../..|.//div[@class="entry-site"]/a[1][+++]/../..', // 完全一致のキーワードのみヒット+サイト名にヒット(低速)
      //listTitleMemoSearchXP: '//div[@class="entry-title"]/a[+++]|//div[@class="comic-title"]/h2/a[1][+++]/..|.//div[@class="entry-site"]/a[1][+++]',
      //listGen: 5,
      listHelpJQS: 'div.entry',
      helpInBlock: 1,
      redoWhenReturned: 1,
      func: function(node) { // width 880-600→1180-900
        if (node === document.body && document.documentElement.clientWidth > 1200 && ($("#page").css("width")) == "880px") {
          $("#main-container").css("width", "900px");
          $("#page").css("width", "1180px");
        }
        //if (WCA_HIDE_SOME_SITES) { for (let name of SITES_TO_BE_HIDDEN) { hideByTitle(name, document, '//div[@class="entry-site"]/a[+++]/../..') } }
        //if (eleget0('//div[@class="comic-author"]') && /^https:\/\/webcomics\.jp\/[^/]+\/[^/]+$/.test(location.href)) autoMemo(/作者: (.*)/m) //autoMemo(/作者: (.*)/m,'//div[@class="comic-author"]',)
      },
      //funcOnTOn: () => { for (let name of SITES_TO_BE_HIDDEN) { showByTitle(name, 0, '//div[@class="entry-site"]/a[+++]/../..') } },
      autoTranslucentURLRE: /mylist|bookmark|https:\/\/webcomics\.jp\/[^\/]+\/\d+$/,
      //automemoURLRE: /https:\/\/webcomics\.jp\/[^/]+\/\d+$/,
      //automemoSearchFunc: () => { return eletext('//div[@class="comic-author"]'); },
      wholeHelp: [() => 1, ` u:重複作品を隠す h:ソート`],
      keyFunc: [{
        key: 'u', // u::uniq
        func: () => {
          //domsort("", elegeta('.entry'), (v) => { return eleget0('//div[@class="entry-site"]/a', v).innerText.match0(/walker|ヤンマガ/gmi) || "" }, 1) // サイトでソート
          //          domsort("", elegeta('.entry'), (v) => { return eleget0('//div[@class="entry-site"]/a', v).innerText.match0(/walker|ヤンマガ/gmi)?1:-1 },2) // サイトでソート
          let undup = [],
            dup = []
          //          elegeta('//div[@class="entry"]/div[@class="entry-title"]/a[1]:visible').forEach(e => {
          //          elegeta('//div[@class="entry"]/div[@class="entry-title"]/a[1]:visible').reverse().forEach(e => {
          elegeta('//div[@class="entry"]/div[@class="entry-title"]/a[1]:visible').reverse().sort((a, b) => eleget0('//div[@class="entry-site"]/a', a.closest(".entry")).innerText.match0(/ComicWalker|ヤンマガWeb/gmi) ? 1 : -1).forEach(e => {
            if (undup.includes(e.textContent)) {
              e.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
              $(e.closest(".entry")).hide(999, function() { $(this).remove() }); //e?.closest(".entry")?.remove()
              dup.push(e.textContent)
            } else { undup.push(e.textContent) }
          })
          popup2(`u:重複タイトルを隠す\n${dup.join("\n")}`, 6)
        }
      }, {
        key: 'h', // h::
        func: () => {
          var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
          $('.yhmSortType').remove();
          $(document.body).append(`<span class="yhmSortType" id="${++sorttype}"></span>`)
          popup2("H:ソート\n" + (["名前順", "作者順", "サイト順"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
          switch (sorttype) {
            case 1:
              domsort("", elegeta('.entry'), (v) => { return ((v.querySelector('div.entry-title>a')).innerText) || "" }, 3)
              break;
            case 2:
              domsort("", elegeta('.entry'), (v) => { return eleget0('//a[@class="autele aut autname"]', v)?.innerText || "" }, 3)
              break;
            case 3:
              domsort("", elegeta('.entry'), (v) => { return eleget0('//div[@class="entry-site"]/a', v).innerText || "" }, 3)
              $('.yhmSortType').remove();
              break;
          }
        },
      }],
    },
    {
      id: 'YAJ2', // yafuoku::
      urlRE: '://auctions.yahoo.co.jp/search/|://page.auctions.yahoo.co.jp/jp/auction/|://auctions.yahoo.co.jp/category/list/',
      title: 'h3.Product__title>a,h1.ProductTitle__text,div.Product__sellerArea>a,div>p.Seller__name>a,div p.Seller__name>a',
      titleSubstr: true,
      box: 'li.Product,div.l-contentsBody',
      forceTranslucentFunc: e => e?.closest('div.l-contentsBody') && lh("/auction/"),
      //forceTranslucentFunc: 'div.l-contentsBody:not(:has(.Result__header))',
      trim: 1,
      redoWhenRefocused: 1,
      /*
      listTitleXP: '//div[@class="Product__infoTable"]/div/h3[@class="Product__title"]/a',
      listTitleSearchXP: '//div[@class="Product__infoTable"]/div/h3[@class="Product__title"]/a[***]/../../../../..|.//div[@class="Product__sellerArea"]/a[+++]/../../../../..|//span[@class="Seller__name"]/a[1][+++]',
      listTitleMemoSearchXP: '//div[@class="Product__infoTable"]/div/h3[@class="Product__title"]/a[***]|//h1[@class="ProductTitle__text" and ***]|.//div[@class="Product__sellerArea"]/a[+++]|.//span[@class="Seller__name"]/a[1][+++]',*/
      listTitleXP2: '//div[@class="Product__sellerArea"]/a|//span[@class="Seller__name"]/a[1]|//p[@class="Seller__name"]/a',
      XP2name: '出品者名 ',
      XP2memo: 1,
      listGen: 6,
      listHelpXP: '//li[@class="Product"]',
      //helpInBlock: 1,
      wholeHelp: [() => 1, " " + KEYMAXP + ":価格上限"],
      detailURLRE: /:\/\/page.auctions.yahoo.co.jp\/jp\/auction\//, // automemoのために必要
      detailTitleXP: '//h1[@class="ProductTitle__text"]', // automemoのために必要
      detailTitleSearchXP: '//h1[@class="ProductTitle__text" and ***]/../../../..|//span[@class="Seller__name"]/a[+++]/../../../../../../../../../../..|.//span[@class="Seller__name"]/a[1][+++]|//p[@class="Seller__name"]/a[+++]/ancestor::div[@class="l-containerInner"]',
      func: () => { elegeta(SITE.title).forEach(e => e.innerText = e.innerText?.trim()) },

      maxpriceXP: '//input[@class="InputText__input" and @name="max"]',
      automemoForceFunc: () => lh("://page.auctions.yahoo.co.jp/jp/auction/"),
      automemoURLRE: "://page.auctions.yahoo.co.jp/jp/auction/",
      automemoSearchFunc: () => { return eletext('//div[@class="ProductExplanation__commentArea"]') + "\n" + eletext('//div[@id="ProductProcedures"]') + "\n" + eletext('//h1[@class="ProductTitle__text"]') + '\n' + eletext('//ul[@class="ProductInformation__items"]/li[2]') + '\n' + eletext('//div/div[@class="ProductDetail"]') + '\n' + eletext('//ul/li[@class="ProductInformation__item"]/section[@class="Section"]'); },
      automemoFunc: () => {
        for (let am of CUSTOMAUTOMEMORE) { autoMemo(am); }
        autoMemo(/(レターパック[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(クリックポスト[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(ゆうメール[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(ゆうパケット[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(ゆうパック[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(定形外[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(メール便[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/送料.*(全国一律\s*[0-9,0-9,]*.*円[-~]?)/m);
        autoMemo(/送料\s*[::]?(.*[都道府県]は[0-9,0-9,]*円[-~]?)/m);
        autoMemo(/(Pentium.*?GHz)|(Celeron.*?GHz)|(Atom.*?GHz)|(Core\s?i\d.*?GHz)|(AMD.*APU)/mi) ? 0 :
          autoMemo(/(CPU[\s\S]{1,30}?GHz)/mi) ? 0 :
          autoMemo(/^(.*GHz)/gmi) ? 0 :
          autoMemo(/(Pentium[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)|(Celeron[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)|(Atom\s[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)|(Core\s?i\d.[0-9A-Za-z\-_.]*)|(Ryzen\s?\d[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)/mi);
        autoMemo(/([0-90-9]{2,4}年製)/m) ? 0 :
          autoMemo(/([0-90-9]{2,4}年)/m) ? 0 :
          autoMemo(/([0-90-9]{2,4}年製)/m) ? 0 :
          autoMemo(/([0-90-9]{2,4}年)/m);
        autoMemo(/発送元:(.{1,4}[都道府県])/m);
        autoMemo(/(認証制限[\s\S]{1,3}あり)/m);
      },
      showFunc: () => { run(document.body, "returned") },
    },
    {
      id: 'YAJ2',
      urlRE: '://auctions.yahoo.co.jp/seller/',
      listTitleXP: '//a[@class="Product__titleLink"]|.//a[@class="Product__titleLink u-textBold"]|.//div[@class="a1wrp"]/h3/a',
      listTitleXP2: '//div/div[@class="seller__subInfo"]/span[@class="seller__yid"]',
      XP2name: '出品者名 ',
      XP2memo: 1,
      listGen: 4,
      listHelpJQS: "div.a1,#list01 table tbody tr td",
      listTitleSearchXP: '//div[@class="a1wrp"]/h3/a[***]/../../../..|.//div[@class="a1wrp"]/h3/a/em[***]/../../../../..|//div/div[@class="seller__subInfo"]/span[@class="seller__yid"][+++]',
      listTitleMemoSearchXP: '//div[@class="a1wrp"]/h3/a[***]|.//div[@class="a1wrp"]/h3/a/em[***]/..|//div/div[@class="seller__subInfo"]/span[@class="seller__yid"][+++]',
      redoWhenReturned: 1,
    },
    {
      id: 'YAJ2',
      urlRE: 'userbenchmark',
    },
    {
      id: 'AMAZON', //amazon::
      listTitleXPIgnoreNotExist: 1,
      urlRE: /www\.amazon\.co\.jp\/s\?k\=|www\.amazon\.co\.jp.*\/dp\/.*/,
      //title: 'a.a-link-normal.s-underline-text.s-underline-link-text.s-link-style.a-text-normal>span,div#title_feature_div.celwidget[data-feature-name="title"]>div#titleSection.a-section.a-spacing-none>h1#title>span#productTitle',
      title: 'a.a-link-normal.s-underline-text.s-underline-link-text.s-link-style.a-text-normal>span,div#title_feature_div.celwidget[data-feature-name="title"]>div#titleSection.a-section.a-spacing-none>h1#title>span#productTitle,h1#title span',
      //      box:'div[data-asin]',
      box: 'div.s-asin,div#dp-container',
      //      memoFunc: e => { return e.parentNode.parentNode },

      //delay:1600,observe:1600, // 非表示の前にヨドバシ量単価を先に処理させるため1500以上にしたほうがいい

      memoFunc: e => e.parentNode.parentNode,
      forceTranslucentFunc: e => e.closest('div#dp-container'),
      //listTitleXP: '//span[@class="a-size-base-plus a-color-base a-text-normal"]|.//h1[@id="title"]/span[@id="productTitle"]|.//h2/a/span[contains(@class,"a-size-base a-color-base a-text-normal")]|.//span[contains(@class,"a-size-medium a-color-base a-text-normal")]',
      //listTitleSearchXP: '//div[@data-asin and .//span[@class="a-size-base a-color-base a-text-normal" and ***]]|.//div[@data-asin and .//span[contains(@class,"a-size-medium a-color-base a-text-normal") and ***]]',
      //  listTitleSearchXP: '//div[@data-asin and .//span[@class="a-size-base-plus a-color-base a-text-normal" and ***]]|.//div[@data-asin and .//span[contains(@class,"a-size-medium a-color-base a-text-normal") and ***]]',
      //      listTitleMemoSearchXP: '//div[contains(@class,"s-title-instructions-style")]/h2/a/span[***]/..|.//h1[@class="a-size-large a-spacing-none"]/span[@id="productTitle"][***]/..',
      //      listTitleMemoSearchXP: '//div[contains(@class,"s-title-instructions-style")]/h2/a/span[***]/..|.//h1[@class="a-size-large a-spacing-none"]/span[@id="productTitle"][***]/..',
      //listTitleMemoSearchXP: '//a[@class="a-link-normal s-underline-text s-underline-link-text s-link-style a-text-normal"]/span[***]/..|//span[@id="productTitle"][***]',
      detailTitleSearchXP: '//span[@id="productTitle" and ***]/../../../../../..|//h1/a[@class="a-link-normal" and ***]/../../../../../../../../../../../../..|//div[@class="p13n-sc-truncate-desktop-type2  p13n-sc-truncated"][***]/../../../../..',
      listGen: 12,
      listHelpXP: '//div[@data-asin][.//span[@class="a-size-base a-color-base a-text-normal"]]|.//div[@data-asin][.//span[contains(@class,"a-size-medium a-color-base a-text-normal")]]',
      trim: true,
      func: () => {
        //elegeta('//*[@class="s-line-clamp-2"]|.//*[@class="s-line-clamp-3"]').forEach(e => e.style.maxHeight = "auto");
        //elegeta('//div[@class="a-section a-spacing-none"]/div[1]/h2/a[@class="a-link-normal a-text-normal"]/span').forEach(e => e.style.display = "inline-block") // 商品名を広く表示する
      },
      //observe: 200,
      //observeClassNameNot: ["a-declarative", "nav-span", "autopagerize-icon", "vsc-controller", "DAsis"],
      observeTagName: "DIV",
      //      listHelpJQS: 'div[data-asin]',
      detailURLRE: /\/dp\/|\/product-reviews\//,
      detailTitleXP: '//h1[@id="title"]/span[@id="productTitle"]',
      hideListEvenDetail: 1,

      automemoURLRE: /https:\/\/www.amazon.co.jp.*\/dp\//,
      automemoSearchFunc: () => { return eletext(['//div[@id="ppd"]/div[4]', '//div/div[@data-template-name="productDescription" and @id="productDescription_feature_div"]', '//div[@data-template-name="productDescription"]', '//div[@id="important-information"]', '//div[@id="prodDetails"]']); },
      automemoFunc: () => {
        if (eleget0('//div[@id="nav-subnav" and @data-category="beauty"]|//div[@id="nav-subnav" and @data-category="hpc"]|//div[@id="nav-subnav" and @class="spacious subnav-untied"]')) {
          [/(イソプロピルメチルフェノール)/m, /(IPMP)/m, /(塩化セチルピリジニウム|塩化セシルピリジニウム|セチルピリジニウム塩化物)/m, /(CPC)/m, /(塩化ベンザルコニウム)/m, /(BKC)/m, /(ラウロイルサルコシンナトリウム|ラウロイルサルコシンNa|ラウロイルサルコシンNa)/m, /(LSS)/m, /(塩化ベンゼトニウム)/m, /(BTC)/m, /(クロルヘキシジン)/m, /(CHG)/m, /(グリチルリチン酸アンモニウム)/m, /(イプシロン.アミノカプロン酸)/m, /(ε.ACA)/m, /(トラネキサム酸)/m, /(TXA)/m, /(グリチルリチン酸ジカリウム|グリチルリチン酸二カリウム|グリチルリチン酸2K|グリチルリチン酸2K|GK2)/mi, /(1\,?450\s?ppm)/m, /(高?濃?度?フッ化ナトリウム|高?濃?度?フッ素)/m, /(ハイドロオ?キシアパタイト)/m, /(リン酸化オリゴ糖カルシウム)/m, /(POs-Ca|POs-Ca)/mi, /(カゼインホスホペプチド.非結晶性リン酸カルシウム|リカルデント)/m, /(CPP-ACP)/m, /(チモール)/m, /(サリチル酸メ?チ?ル?)/m, /(1\,8-シネオール)/m, /(トリクロサン)/m, /(トリクロカルバン)/m, /(オクトピロックス|ピロクトン.?オラミン)/m, /(Znピリチオン|ジンクピリチオン)/m, /(硫黄|イオウ)/m, /(アラントイン)/m, /(グリチルリチン酸アンモニウム)/m, /(ミコナゾール硝?酸?塩?)/m, /(クロラムフェニコール)/m, /(フラジオマイシン硫?酸?塩?)/m, /(ナイスタチン)/m, /(塩化亜鉛)/m, /(ポビドン.?ヨード)/m, /(ラウリルジアミノエチルグリシンナトリウム)/m, /(カキタンニン)/m, /(チャエキス)/m, /(ローズマリー)/m, /(カンゾウ)/m, /(クマザサ)/m, /(セージ)/m, /(シソエキス)/m, /(β?-?グリチルレチン酸?)/m, /(メントール)/m, /(ポリリン酸ナトリウム|ポリリン酸Na)/m, /(ヒノキチオール)/m, /(ティーツリー油オ?イ?ル?)/m, /(ティートゥリー油オ?イ?ル?)/m].forEach(m => autoMemo(m));
        }
        if (eleget0('//div/div[@id="nav-subnav" and @data-category="electronics"]|//div/div[@data-category="musical-instruments"]/a[1]')) {
          [/([\d\s\,]+mAh)/m, /([\d\s\,]+mAh)/m, /([\d\s\,]{2,9}回)/m, /(感度.{1,20}dB)/mi].forEach(m => autoMemo(m));
          //          [/([\d\s\,]+mAh)/m, /([\d\s\,]+mAh)/m, /([\d\s\,]{2,9}回)/m].forEach(m => autoMemo(m));
        }
        if (eleget0('//div[@id="nav-subnav" and @data-category="kitchen"]|//div[@id="nav-subnav" and @data-category="home"]')) {
          [/([0-90-9++]+?物質)/m, /([0-90-9++]+?項目)/m, /(交換.{1,19}[0-9.]+ヶ月)|(交換.{1,19}[0-9.]+年)|(取替.{1,19}[0-9.]+ヶ月)|(取替.{1,19}[0-9.]+年)/m].forEach(m => autoMemo(m));
          [/(低圧\D?\d+kpa)/mi, /(高圧\D?\d+kpa)/mi, /(圧力[\::]\d+kPa)/mi].forEach(m => autoMemo(m));
        }
        if (eleget0('//div[@id="nav-subnav" and @data-category="food-beverage"]')) {
          [/(食物繊維\D{0,9}[0-9.]+[gg])/m].forEach(m => autoMemo(m));
        }
        if (eleget0('//div/a/span/img[@alt="AMAZON FASHION"]|//span[@class="nav-a-content" and contains(text(),"産業・研究開発用品")]')) {
          [/(ハイパーV)|(Hyper.?V)|(.?先芯.{0,3})/mi].forEach(m => autoMemo(m));
        }
      },
      funcOnlyFirst: () => {
        var observeUrlHasChangedhref = location.href;
        var observeUrlHasChanged = new MutationObserver(mutations => {
          if (observeUrlHasChangedhref !== location.href) {
            prefCacheClear();
            observeUrlHasChangedhref = location.href;
            elegeta('//span[contains(@class,"yhmMyMemo")]').forEach(e => e.parentNode.remove());
            setTimeout(() => { run(document.body, "returned") }, 2500);
          }
        });
        observeUrlHasChanged.observe(document, { childList: true, subtree: true });
      },
    },
    /*    { // doc::
          id: '', // GM_setValueで保存するグループ名 同じグループは設定が共通になる
          urlRE: '', // 動作するサイトのURLの一部(正規表現)
          necessaryToWorkFunc: null, // この関数がありfalseなら動作を停止する urlREだけでは非対応ページを絞り込めない時に使用
          listTitleXP: '', // 項目一覧ページの項目名を特定できる要素のXPath title>text>altの順にあるものから利用される
          listTitleXP2: '', // 項目一覧ページの項目名の第2候補を指すXPath これにホバーしていればQキーでこれのinnerTextでもNG登録できる
          XP2name: '', // XP2にホバーした時のガイドに表示する文字列
          XP2memo: 0, // 1だとXP2でも1-6キーのメモを許可
          listTitleSearchXP: '', // 項目一覧ページの項目を消すブロック要素をサーチするXPath 通常listTitleXPにサーチ用マクロを付け/..をいくつかつけたもの
          listTitleSearchFunc: null, // 項目一覧ページの項目を消すブロック要素をサーチする関数 5chのレス本文キーワードNGなどで使用
          listTitleMemoSearchXP: '', // 項目一覧ページと詳細ページのメモを付ける要素をサーチするXPath(一覧と詳細の両方を|でOR記述) 通常listTitleXPやdetailTitleXPにサーチ用マクロを付け/..をいくつかつけたもの
          listTitleMemoSearchXPSameGen: 0, // 1だとメモをタイトルと同じ世代の要素として付ける 0だと1つ親世代
            // サーチ用マクロ; ***:textをcontainsで検索 +++:textを=で検索 ++alt++:altを=で検索 ++title++:titleを=で検索 **url**:hrefをcontainsで検索(要useURL) ++url++:hrefを=で検索(要useURL)
          listGen: 3, // Q12を押した場所の要素からいくつ上まで遡った要素までを当たり判定にするか 必要最小限にする
          listHelpJQS: '', // 項目一覧ページで操作ガイドを表示する要素のJQueryセレクタ ↓でも良い 両方を省略するとlistTitleXPの2つ親の要素で代用 当たり判定とは関係ない
          listHelpXP: '', // 項目一覧ページで操作ガイドを表示する要素のXpath ↑でも良い 両方を省略するとlistTitleXPの2つ親の要素で代用 当たり判定とは関係ない
          helpInBlock: 0, // 1だと操作ガイドを要素のブロック内に表示する
          detailURLRE: //, // URLにmatchする正規表現、matchすると個別詳細画面だと判断する
          detailTitleXP: '', // 詳細画面で項目名を指すXPath
          detailTitleSearchXP: '', // 詳細画面で非表示化時に表示を薄くする要素をサーチするXPath
          func: null, // 処理時にそのサイトでのみ実行したい関数があれば書く
          funcQ: null, // Qキー処理時にそのサイトでのみ実行したい関数があれば書く
          funcMemo: null, // 5/6などメモ関係処理時にそのサイトでのみ実行したい関数があれば書く
          funcFinally: null, // そのサイトで非表示やメモの処理が終わった後に実行したい関数があれば書く
          funcOnlyFirst: null, // ページ開始時に1回だけ実行したい関数 通常通りのDelayが効く
          funcOnlyFirstWithoutDelay: null, // ページ開始時に1回だけ実行したい関数 Delayなしで最速で実行する
          titleProcessFunc: null, // 項目名を保存する前に加工したければ関数を書く
          autoTranslucentURLRE: //, // 強制的に半透明モードにするURLの正規表現 Web漫画アンテナのマイリスト等
          listTitleXPIgnoreNotExist: 0, // 通常listTitleXPにヒットする要素が1つもなくobserveも0なら動作を停止するがこれがtrueだと停止をしない 項目が動的に追加されるページなどで使用
          forceRunIffunc: null, // これがありtrueを返したらlistTitleXPIgnoreNotExist=1と同様に動作の停止をしない 項目が動的に追加されるページ、先に加工を要するページ(旧5ch)などで使用
          delay: 0, // ミリ秒 ページ読み込み後処理を開始するまでの遅延
          delayAutoWeighting: 0, // 0以外ならページ開始時から処理開始までの遅延の係数(省略可) delayと排他利用
          observe: 0, // ミリ秒 1以上だと要素追加ごとにこのミリ秒の遅延を置いて再処理する(とても遅い) 項目が動的に追加されるページなどで使用
          observeFunc:null, // これがあると追加された要素ごとにtrueを返した要素のみが処理対象になる判定関数 (addedElement)=>{return addedElement==~})
          observeId: "", // これがあるとobserve有効時にこのIDの要素でないものは無視する YouTubeなどの高速化に重要
          observeClass: [], // これがあるとobserve有効時にこれに含まれるClassNameでない要素は無視する futapoなどの高速化に重要
          observeClassNameNot:[], // これがあるとobserve有効時にこのclassNameの要素は処理しない
          observeTagName:"", // これがあるとobserve有効時にこのtagNameの要素は処理しない
          trim: 0, // 1だと項目名をtrimしてから保存 Amazonでは項目名が一覧と詳細で揺れるため1にする
          automemoURLRE: null, // 自動メモを収集するURL
          automemoSearchFunc: null, // 自動メモの対象要素のテキストを収集する関数
          automemoFunc: null, // 自動メモを実行する関数
          redoWhenReturned: 0, // これが1かdetailTitleXPが存在すれば他ウインドウや他タブから戻ってきた時に全体を再処理する disableUrlREを見る
          redoWhenRefocused: 0, // これが1なら他タブから戻ってきた時に全体を再処理する disableUrlREを無視
          showFunc: null, // QWで項目を再表示した時に実行したい関数があれば書く
          hideListEvenDetail: 0, // 1なら詳細画面でも一覧画面用の非表示を実行する ニコニコ静画(イラスト)などで使用
          detailRangeFunc: null, // 詳細画面で項目対象が2つ以上ある場合に指した要素から遡る等の処理があれば書く関数
          //useURL: 0, // 1なら項目名としてAタグのhrefを取り込み、使う ジモティ等、完全に同名の項目名が付けられやすいサイトで使用
          useURL: 0, // 1なら項目名としてAタグのhrefを取り込み、使う(?以降は無視) ジモティ等、完全に同名の項目名が付けられやすいサイトで使用
          useText: 0, // 1なら項目名としてtextContentを取り込み、使う Pubmed等IDではない@titleが設定されているためテキストを優先したいサイトで使用
          hideSelectedWord: 1, // 1ならQキーを押した時に文字列選択中ならその文字列を非表示リストに入れる 5chのレス本文キーワードNGなどで使用
          disableHelpForce: 0, // 1ならENABLE_HELP_CONCLUSIONを常に0にしヘルプやガイドを一切表示しない
          disableHelpUrlRE: '', // 正規表現 URLにマッチすると全体ヘルプを抑制する
          disableKeyB: 0, // 1ならBキーは効かなくする youtubeなどで使用
          searchAllowLength: 0, // 1ならQ12キーの当たり判定をゆるくする(説明しづらい) 5chで使用
          reloadWhenUrlHasChanged:0, // 1ならURLが変わった時にリロードする SPAサイトなどで使用
          helpOnDNI: 0, // 1ならdniでの継ぎ足し時非表示にしたレポートを逐一表示する
          disableUrlRE: "", // URLにマッチしたらキー操作を無効にする正規表現 YouTubeなどSPAサイトで動画視聴ページでキー操作の機能を無効にするために使用
          urlHasChangedCommonFunc: null, // urlが変わったら実行する関数 uniqlo等シングルページアプリケーションで一覧と詳細を行き来するサイト等で使用
          WhateverFirstAndEveryAPFunc: null, // 対象要素がなくてもurlREにマッチしたページならとにかく最初とAutoPagerize時に実行する関数
          memoStyle:"", // メモのstyle=""指定に特別に追加する文字列
          ignoreDNI:null, // これがあるとDOMNodeInsertedイベントでe.targetを受け取りtrueを返したらそのノードは無視する判定関数 ニコ動watch画面等で使用 (e)=>{if(e==無視すべきノード)return false} などと使う
          // 新方式(titleとboxで1セット、listTitle~を代替)
          title: '', // 項目名を指すXPath/CSS これとboxだけで要素を特定する新フォーマット title→textContentの順に優先して同一判定する 現在===判定のみ
          box: '', // titleを包含し項目全体の枠になる先祖要素(枠)を指すXPath/CSS boxの中にtitleがある
          titleSubstr: false, // これがtrueだとメモがtitleに対して部分一致でヒットするようになる ヤフオクでCPUスコアの自動メモを表示するために使用
          memoFunc: null, // メモを付ける位置は通常はtitleのafterendだがこれがあるとtitle要素から辿って変更できる デフォルトは(titleEle)=>{return titleEle}
          memoPosition: '', // メモを付ける位置は通常はtitleのafterendだがこれがあると変更できる afterbegin等
          nfd: 0, // 1:項目のタイトルをすべてNFDエンコードにしてから一致判定する 壮絶に遅い タイトルのエンコードが一定でないサイトで使用 YouTubeの新仕様で必要になるかも
          forceTranslucentFunc:null, // これがあると非表示にした要素eがtrueを返すときは半透明に消す判定関数 e=>e.closest("***") のように使う
          //isMemoPartialMatch: 0, // 全体ヘルプの表示だけメモを部分一致にする
          isHidePartialMatch: 0, // 全体ヘルプの表示だけ非表示を部分一致にする=Bキーのガイドを出す 5ch/ふたばなどの特殊本文NGができるサイトでBキーのヘルプを出すためだけに使用
          preventMemo: null,  // (memo内容)=>return true だと通常のメモの内容表示を抑制する判定関数 futapoで使用
          },
    */
  ];

  var siteinfo = Object.assign(SITEINFO, pref("MY_SITEINFO") || []); //alert(siteinfo);return;
  // thissiteを決定
  var thissite = null;
  for (var i = 0; i < siteinfo.length; i++) {
    if (siteinfo[i].urlRE == "") break;
    if (location.href.match(siteinfo[i].urlRE)) {
      thissite = i;
      var SITE = Object.create(siteinfo[thissite]);
      //if ((SITE.detailTitleSearchXP || "").indexOf("***") == -1 && (SITE.listTitleSearchXP || "").indexOf("***") == -1 && (SITE.listTitleMemoSearchXP || "").indexOf("***") == -1) SITE.disableKeyB = 1;
      if (SITE.disableKeyB === undefined && (!(/\*\*\*|\*\*title\*\*|\*\*alt\*\*/.test(SITE.detailTitleSearchXP || "") || /\*\*\*|\*\*title\*\*|\*\*alt\*\*/.test((SITE.listTitleSearchXP || "") || /\*\*\*|\*\*title\*\*|\*\*alt\*\*/.test(SITE.listlTitleMemoSearchXP || ""))))) SITE.disableKeyB = 1;
      break;
    }
  }
  if (thissite === null || (!ENABLE_EXCEPT_YAJ && SITE.id != "YAJ2")) return;

  let ENABLE_HELP_CONCLUSION = lh(SITE?.disableHelpUrlRE || /$^/) ? 0 : SITE.disableHelpForce ? 0 : ENABLE_HELP;

  //  GM_addStyle("span.yhmMyMemo{all:initial; pointer-events:none; word-wrap:break-word;cursor:pointer; font-size:14px; font-weight:bold; margin:0px 1px; text-align:center; padding:0px 6px 0px 6px; border-radius:12px; color:white;font-family:sans-serif;}")
  //  GM_addStyle("span.yhmMyMemo{pointer-events:none; word-wrap:break-word;cursor:pointer; font-size:14px; font-weight:bold; margin:0px 1px; text-align:center; padding:0px 6px 0px 6px; border-radius:12px; color:white;font-family:sans-serif;}")
  const MEMOSTYLE = SITE.memoStyle ? SITE.memoStyle : "";
  const CUSTOMAUTOMEMORE = [/(Windows.*bit)/gmi, /((?:HDD|HDD|SSD|SSD|ハードディスク|ストレージ).*?(?:GB|TB|GB|TB|無し|なし|無|欠品|欠))/mi, /((?:10|テン)(?:key|キー))/mi, /(768.{1,3}576)|(800.{1,3}600)|(832.{1,3}624)|(1024.{1,3}768)|(1152.{1,3}864)|(1,?280.{1,3}960)|(1400.{1,3}1050)|(1440.{1,3}1080)|(1600.{1,3}1200)|(2048.{1,3}1536)|(2304.{1,3}1728)|(3200.{1,3}2400)|(854.{1,3}480)|(1024.{1,3}576)|(1136.{1,3}640)|(1280.{1,3}720)|(1,?36\d?.{1,3}768)|(1,?920.{1,3}1,?080)|(2048.{1,3}1152)|(2,?560.{1,3}1,?440)|(3200.{1,3}1800)|(3,?840.{1,3}2,?160)|(7680.{1,3}4320)|(640.{1,3}400)|(1280.{1,3}800)|(1,?440.{1,3}900)|(1680.{1,3}1050)|(1,?920.{1,3}1,?200)|(2560.{1,3}1600)|(2880.{1,3}1800)|(3840.{1,3}2400)|(480.{1,3}320)|(960.{1,3}640)|(176.{1,3}144)|(400.{1,3}240)|(352.{1,3}288)|(640.{1,3}350)|(720.{1,3}480)|(800.{1,3}480)|(864.{1,3}480)|(1024.{1,3}480)|(1024.{1,3}600)|(1280.{1,3}600)|(1120.{1,3}750)|(1280.{1,3}768)|(1152.{1,3}870)|(1280.{1,3}1024)|(1,?600.{1,3}900)|(1,?600.{1,3}1024)|(2048.{1,3}1080)|(4096.{1,3}2160)|(8192.{1,3}4320)/m, /(非光沢|ノングレア|ノーグレア|アンチグレア|光沢|グレア)/m, /((?:30|40)\s?(?:pin|ピン))/mi, /(LVDS.*$|eDP)/mi, /^(.*リカバリ.*)$/mi, /(仕事率[^0-90-9\n]*[0-9,0-9,]*\s*[wW])/mi, /(\[?\s?関東[^0-9,0-9,\n]*[0-9,0-9,]*\s*円[-~]?)/m, /(\[?\s?本州[^0-9,0-9,\n]*[0-9,0-9,]*\s*円[-~]?)/m, /(HDMI.{0,10}入力.{2,3}|入力.{0,20}HDMI.{2,3})/mi, /(電源入り.{2,10})/mi, /(\d\d鍵)/m];
  //const CUSTOMAUTOMEMORE = [/$()^/]; // 無指定
  // ,/(フルHD|Full\s?HD|FHD|WXGA|FWXGA|QVGA|WXGA\+|SXGA|SXGA\+|HD\+|WXGA\+\+|WSXGA|WSXGA\+|UXGA|FHD|2K|WUXGA|FHD\+|UltraWideFHD|QXGA|WQHD|WQXGA|UltraWideQHD\+|QUXGA|QFHD|UHD4K|DCI4K|8KFUHD)/m
  const alsoClearBenchMemoWhenClearAutoMemo = 0; // 1:Shift+"で自動メモのみ削除する時CPUスコアのメモも削除する 0:CPUスコアのメモは残す

  const LogMatch = 0;

  debug && sw("start")
  var mousex = 0;
  var mousey = 0;
  //var maey = 0;

  // userbenchmarkでの動作
  if (location.href.match(/cpu.userbenchmark.com\/.*\/Rating\/|cpu.userbenchmark.com\/SpeedTest\//i)) { //userbenchmark
    setTimeout(() => {
      let cpuscore = $(eleget0('//td[@class="mcs-hl-col" and contains(text(),"64-Core")]/span')).css("border", "4px dotted blue").text();
      let cpuscore1t = "1C:" + $(eleget0('//td[@class="mcs-hl-col" and contains(text(),"1-Core")]/span')).css("border", "4px dotted blue").text();
      cpuscore = cpuscore.replace(/(.*\%).*/, "$1").trim();
      let ubmodel = eleget0('//h1[@class="pg-head-title"]/a[@class="stealthlink"]').innerText.trim();
      let lasttitle = pref("lastItemName") || "";
      let modelno = (ubmodel.replace(/^core i\d-?(\S?\s?\d{3,5}.*$)/gi, "$1").replace(/^Core2 Duo (.?\d{3,5}.*$)/gi, "$1").trim());
      for (let title of (lasttitle ? lasttitle.indexOf(modelno) != -1 ? [modelno] : [lasttitle, modelno] : [modelno])) {
        //for (let memo of [
        [document?.body?.innerText?.match(/(TDP\s*\d+\s*W)/mi)?.[1]?.replace(/\s/gm, " ") || "",
          cpuscore, cpuscore1t,
        ].forEach((memo, i) => {
          //]) {
          var tmp = pref('YAJ2 : SearchMyMemo') || [];
          var isExist = tmp.filter(e => e.t == title && e.m == memo);
          popup3(title + "\n" + memo, i * 3);
          if (isExist.length == 0) {
            if (title && memo) {
              let tmp = pref('YAJ2 : SearchMyMemo') || [];
              tmp.push({ t: title, m: memo, c: COLORCPUSCORE })
              pref('YAJ2 : SearchMyMemo', tmp)
            }
          }
        })
      }
      pref("lastItemName", "");
      //popup3("Task completed");
    }, 500);
    //return;
  }
  if (location.href.indexOf("userbenchmark.com") != -1) {} else {
    pref("lastItemName") ? (pref("lastItemName", ""), popup3("UBM Task has been cleared")) : 0;
  }

  // GM_設定を前バージョンから引き継ぐ
  /*  if (pref(SITE.id + 'SearchHideTitle') && !pref(SITE.id + ' : SearchHideTitle')) {
      pref(SITE.id + ' : SearchHideTitle', pref(SITE.id + 'SearchHideTitle'));
      pref(SITE.id + 'SearchHideTitle', "");
    }
    if (pref(SITE.id + 'SearchMyMemo') && !pref(SITE.id + ' : SearchMyMemo')) {
      pref(SITE.id + ' : SearchMyMemo', pref(SITE.id + 'SearchMyMemo'));
      pref(SITE.id + 'SearchMyMemo', "");
    }
    if (pref(SITE.id + 'SearchHideTitle') && pref(SITE.id + ' : SearchHideTitle')) {
      pref(SITE.id + 'SearchHideTitle', "");
    }
    if (pref(SITE.id + 'SearchMyMemo') && pref(SITE.id + ' : SearchMyMemo')) {
      pref(SITE.id + 'SearchMyMemo', "");
    }
  */

  if (SITE.id == "5CH") {
    var oldmemo = pref(SITE.id + ' : SearchMyMemo') || []
    var newmemo = JSON.parse(JSON.stringify(oldmemo)) || []
    newmemo.forEach(c => {
      c.t = c.t.replace(document.title, "").replace(/ |\s|:/g, "").trim()
    })
    //prompt("",JSON.stringify(oldmemo) );prompt("", JSON.stringify(newmemo))
    if (JSON.stringify(oldmemo) != JSON.stringify(newmemo)) {
      pref(SITE.id + ' : SearchMyMemo', newmemo)
      alert("前バージョンからのメモの変換に成功しました") //JSON.stringify(newmemo))
    }
  }

  //  if (SITE.funcOnlyFirst) SITE.funcOnlyFirst();
  //  if (SITE.WhateverFirstAndEveryAPFunc) {
  //    SITE.WhateverFirstAndEveryAPFunc();
  if (SITE.funcOnlyFirstWithoutDelay) SITE.funcOnlyFirstWithoutDelay();
  if (SITE.funcOnlyFirst) setTimeout(() => { SITE.funcOnlyFirst(); }, (SITE.delayAutoWeighting || 0) * WAIT || (SITE.delay || 0));
  if (SITE.WhateverFirstAndEveryAPFunc) {
    setTimeout(() => { SITE.WhateverFirstAndEveryAPFunc(); }, (SITE.delayAutoWeighting || 0) * WAIT || (SITE.delay || 0));
    document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { SITE.WhateverFirstAndEveryAPFunc(evt.target); }, false);
  }

  if (SITE.keyFunc) { // SITEINFOにあるkeyFunc
    document.addEventListener('keydown', e => {
      //      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true' || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;

      var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
      //if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA' && e.target.getAttribute('contenteditable') != 'true') {
      //if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true' || (inYOUTUBE && (document.activeElement.closest('#chat-messages') || document.activeElement.closest('ytd-comments-header-renderer')))) return;
      SITE.keyFunc.forEach(c => {
        //        if (key == c.key) { c.func(key) }
        //        if (key.match0(c.key)) { c.func(key) }
        if (typeof c.key === "string" ? key === c.key : key.match0(c.key)) { c.func(key) }
      })
      //}
    }, false)
  }

  if (SITE.reloadWhenUrlHasChanged) {
    var observeUrlHasChangedhref = location.href;
    var observeUrlHasChanged = new MutationObserver(mutations => { if (observeUrlHasChangedhref !== location.href) location.reload() });
    observeUrlHasChanged.observe(document, { childList: true, subtree: true });
  }
  if (SITE.runWhenUrlHasChanged) {
    var observeUrlHasChangedhrefRun = location.href;
    var observeUrlHasChangedRun = new MutationObserver(mutations => {
      if (observeUrlHasChangedhrefRun !== location.href) {
        prefCacheClear();
        setTimeout(() => { run(document.body, "returned") }, 2500);
      }
    });
    observeUrlHasChangedRun.observe(document, { childList: true, subtree: true });
  }

  // 詳細画面?
  var isDetail = (SITE.detailURLRE && location.href.match(SITE.detailURLRE)) ? 1 : 0;
  debug && dc("isDetail : " + isDetail)

  var isHidePartialMatch = SITE.isHidePartialMatch || (SITE.listTitleSearchXP && SITE.listTitleSearchXP.indexOf("**") != -1) ? 1 : 0;
  var isMemoPartialMatch = SITE.isMemoPartialMatch || (SITE.listTitleMemoSearchXP && SITE.listTitleMemoSearchXP.indexOf("**") != -1) ? 1 : 0;

  // ヤフオク上限価格はIME offにする
  if (SITE.id == "YAJ2") $(eleget0('//input[@class="InputText__input" and @name="max"]')).css('ime-mode', 'inactive');

  // ヤフオクは「画像を大きく」モードでは効かない
  /*if (SITE.id == "YAJ2" && !isDetail && eleget0('//span[@class="Option__mode Option__mode--gridCurrent"]|//span[@class="Option__mode Option__mode--immersiveCurrent"]')) {
    popup2("「ヤフオクで非表示とメモ」は「タイトルと画像」表示でのみ働きます\n「画像を大きく」と「クイックビュー表示」には対応していません");
    return;
  }*/

  // 自動的に半透明モードにするページ
  var disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");

  // 非対応ページ
  if (!isDetail && ((SITE.listTitleXP && !eleget0(SITE.listTitleXP)) || (SITE.title && !elegeta(SITE.title)))) {
    //    if (!(SITE.listTitleXPIgnoreNotExist) && !(SITE.observe) && !(SITE.forceRunIffunc && SITE.forceRunIffunc())) {
    if ((SITE.listTitleXPIgnoreNotExist) || (SITE.observe) || (SITE.forceRunIffunc && SITE.forceRunIffunc())) {} else {
      //      if (debug) popup3("対象要素がないのでこのページでは働きません");
      if (debug) popup3("対象要素がないのでこのページでは働きません");
      return;
    }
  }
  if (SITE.necessaryToWork && (document.body.innerText.match(SITE.necessaryToWork)) == null) { //prompt(document.body.innerText,document.body.innerText.match(SITE.necessaryToWork))
    if (debug) popup3("非対応ページなのでこのページでは働きません");
    return;
  }

  if (SITE.selectedHelp) {
    $('body').on('mouseup', function(e) {
      var selectedStr;
      if (window.getSelection) {
        selectedStr = window.getSelection().toString();
        if (selectedStr !== '' && selectedStr !== '\n') {
          if (selectedStr.indexOf("\n") !== -1) SITE.selectedHelp.multi ? popup3(SITE.selectedHelp.multi, 12, 5000) : 0;
          else SITE.selectedHelp.help ? popup3(`『${selectedStr}』を\n` + SITE.selectedHelp.help.join("\n"), 12, 5000) : 0;
        }
      }
    });
  }

  String.prototype.replaceTitle = function(title) {
    if (title && SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
    if (!title) title = "空の文字列";
    return this.replace(/\*\*\*/g, "contains(text(),\"" + title + "\")").replace(/\+\+\+/g, "text()=\"" + title + "\"").replace(/\+\+alt\+\+/g, "@alt=\"" + title + "\"").replace(/\*\*alt\*\*/g, "contains(@alt,\"" + title + "\")").replace(/\*\*title\*\*/g, "contains(@title,\"" + title + "\")").replace(/\+\+title\+\+/g, "@title=\"" + title + "\"").replace(/\+\+url\+\+/g, "@href=\"" + title + "\"").replace(/\*\*url\*\*/g, "contains(@href,\"" + title + "\")");
  };

  var keyListen = function(e) {
    //    if (SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) { var one = document.elementFromPoint(mousex, mousey); if (!SITE.listTitleXP || !elegeta(SITE.listTitleXP).concat(elegeta(SITE.listTitleXP2)).find(v => v == one)) { return; } } //youtube視聴画面では反応する項目にホバーしているとき以外はキーを無効にする
    if (SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) {
      var one = document.elementFromPoint(mousex, mousey);
      if (!SITE.listTitleXP || !elegeta(SITE.listTitleXP).concat(elegeta(SITE.listTitleXP2)).concat(elegeta(SITE.title)).find(v => v == one)) { return; }
    } //youtube視聴画面では反応する項目にホバーしているとき以外はキーを無効にする
    //if (SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) { var one = document.elementFromPoint(mousex, mousey); if (!SITE.listTitleXP || !elegeta(SITE.listTitleXP).find(v => v == one)) { return; } } //youtube視聴画面でタイトルにホバーしているときだけキーを効かせる
    //    if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true' || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;
    if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;

    //if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true' || (inYOUTUBE && (document.activeElement.closest('#chat-messages') || document.activeElement.closest('ytd-comments-header-renderer')))) return;
    var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
    if (key === KEYCHANGE_DEBUG) { // D::change debug mode
      debug = (debug + 1) % 4;
      popup3("debug mode : " + debug)
    }
    if (key === KEYHIDE) { // Q::hide
      e.preventDefault();
      if (SITE.hideSelectedWord) { // 選択された文字列をNG / 5ch等
        let sel = String(window.getSelection());
        if (sel) {
          if (sel.indexOf("\n") !== -1) { popup2("複数行の選択は NG に入れられません", 1); } else { addNG(sel); }
          if (SITE.funcB) SITE.funcB();
          return false;
        }
      }
      if (SITE.title) { // 直接ホバーしている要素が非表示対象ならそれで非表示登録(1つのbox内に複数の対象(作品名に対する作者名など)がある時にどちらで登録するかを選べるための処理)
        var ele = document.elementFromPoint(mousex, mousey);
        if (elegeta(SITE.title).find(e => e == ele)) {
          debug && dc(`Direct element Q : 『${ele?.textContent?.trim()||ele?.title?.trim() }』\nbox : ${e2sel(ele)}`)
          //          addNG(ele?.title || ele?.textContent)
          addNG(ele?.textContent?.trim() || ele?.title?.trim())
          //blockElement(ele);
          //          hideByTitle(ele.innerText);
          //        addNG(ele.innerText);
          if (SITE.funcQ) SITE.funcQ();
          return false;
        }
      }
      if (SITE.listTitleXP2) { // 2つ目の項目名がありそこにホバーしていればそれで非表示登録
        var ele = document.elementFromPoint(mousex, mousey);
        if (elegeta(SITE.listTitleXP2).indexOf(ele) != -1) {
          //          hideByTitle(ele.innerText, SITE.listTitleXP2);
          blockElement(ele); //hideByTitle(ele.innerText);
          //addNG(ele.innerText);
          if (SITE.funcQ) SITE.funcQ();
          return false;
        }
      }
      var ele = (SITE.detailTitleXP && isDetail) ? (eleget0(SITE.detailTitleXP, (SITE.detailRangeFunc ? SITE.detailRangeFunc(document.elementFromPoint(mousex, mousey)) : document.elementFromPoint(mousex, mousey))) || eleget0(SITE.detailTitleXP)) : document.elementFromPoint(mousex, mousey);
      debug && dc("Q start element : " + ele.tagName);
      blockElement(ele);
      if (SITE.funcQ) SITE.funcQ();
      return false;
    }
    if (key == KEYUNDO) { // W::undo
      e.preventDefault();
      let resist = pref(SITE.id + ' : SearchHideTitle') || [];
      let title = resist.pop();
      let title2 = resist.slice(-1)[0] || "";
      title2 = title2 ? ("。次のアンドゥ対象は\n『" + title2 + "』") : ""
      pref(SITE.id + ' : SearchHideTitle', resist) || [];
      showByTitle(title);
      if (isDetail && SITE.showFunc) SITE.showFunc();
      if (title) popup2("『" + title + "』\nを非表示登録から削除しました" + title2, 1);
      else popup2("登録された非表示項目はありません", 1);
      //        }
      if (SITE.funcQ) SITE.funcQ();
      return false;
    }
    if (key == KEYBW && !SITE.disableKeyB) { // B::NGword
      e.preventDefault();
      addNGWord();
      if (SITE.funcB) SITE.funcB();
      return false;
    }
    if (key == KEYTOGGLEtranslucent) { // T:: 半透明
      e.preventDefault();
      if (pref("translucent") == "on") restoreHidden();
      pref("translucent", pref("translucent") == "on" ? "off" : "on");;
      popup2(KEYTOGGLEtranslucent + ": 半透明モードを" + pref("translucent") + "にします");
      disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
      if (pref("translucent") == "on") {
        restoreTranslucent();
        run(document.body, "returned");
      }
      // location.reload();
      //        else restoreHidden();
      return false;
    }

    if (key === KEYEDIT) { // shift+Q:: edit NGs
      e.preventDefault();
      prefRestrict(SITE.id + ' : SearchHideTitle', "array");
      let sht = (JSON.stringify(pref(SITE.id + ' : SearchHideTitle') || ""));
      if (sht === '""') sht = "";
      //      let tmp = prompt(SITE.id + "\n\n" + KEYEDIT + ":\n非表示にするタイトル(現在" + (pref(SITE.id + ' : SearchHideTitle') || []).length + ")をJSON形式で編集してください\n正規表現ではありません\n空欄を入力すれば全削除できます\n先頭の[の前に+を付けると現在のデータに追加(マージ)します\n\n" + sht, sht);
      let tmp = prompt(`${SITE.id}\n\n${ KEYEDIT }:\n非表示にするタイトル(現在${ (pref(SITE.id + ' : SearchHideTitle') || []).length })をJSON形式で編集してください${SITE.QRule||"\n正規表現ではありません"}\n空欄を入力すれば全削除できます\n先頭の[の前に+を付けると現在のデータに追加(マージ)します\n\n${ sht}`, sht);
      if (tmp !== null) { // ESCで抜けたのでなければ
        try {
          if (tmp.match(/^\+|^+/)) {
            tmp = tmp.replace(/^\+|^+/, "")
            var tmp2 = pref(SITE.id + ' : SearchHideTitle') || []
            tmp = JSON.parse(tmp || "") || []
            var tmp3 = tmp.concat(tmp2)
            tmp = JSON.stringify(tmp3)
          }
          tmp = tmp ? JSON.parse(tmp) : []
          pref(SITE.id + ' : SearchHideTitle', tmp)
          prefRestrict(SITE.id + ' : SearchHideTitle', "array");
          var a = pref(SITE.id + ' : SearchHideTitle')
          var b = [...new Set(a)]; // uniq
          pref(SITE.id + ' : SearchHideTitle', b || []);
          //    document.body.remove();
          location.reload();
        } catch (e) {
          alert(e + "\n入力された文字列がうまくparseできなかったので設定を変更しません\n正しいJSON書式になっているか確認してください");
          return false
        }
        return false
      }
    }
    if (key == KEYMEMO5EDIT || key == KEYMEMO6EDIT) { // Shift+5::5memo設定 Shift+6::6memo設定
      e.preventDefault();
      var date = new Date();
      var memo = window.getSelection().toString().trim() || prompt((key == KEYMEMO5EDIT ? KEYMEMO5 : KEYMEMO6) + "キーのメモ内容を設定してください", (key == KEYMEMO5EDIT ? MEMO5WORD : MEMO6WORD) || date.getFullYear() + "." + ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + " (" + ["日", "月", "火", "水", "木", "金", "土"][date.getDay()] + ")")
      if (key == KEYMEMO5EDIT) {
        MEMO5WORD = memo;
        key = KEYMEMO5
      } else {
        MEMO6WORD = memo;
        key = KEYMEMO6
      }
      if (SITE.funcMemo) SITE.funcMemo();
      if (memo == false) return false;
    }
    if (key == KEYMEMO5 || key == KEYMEMO6) { // 5::5memo 6::6memo
      e.preventDefault();
      if (SITE.title) { // 直接ホバーしている要素が対象ならそれで登録(1つのbox内に複数の対象(作品名と作者名など)がある時にどちらで登録するかを選べるための処理)
        var ele = document.elementFromPoint(mousex, mousey);
        if (elegeta(SITE.title).find(e => e == ele)) {
          var date = new Date();
          var dateStr = (key == KEYMEMO5 ? MEMO5WORD : MEMO6WORD) || date.getFullYear() + "." + ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + " (" + ["日", "月", "火", "水", "木", "金", "土"][date.getDay()] + ")";
          //          memoElement(ele.innerText, document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
          memoElement(ele.textContent?.trim(), document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
          if (SITE.funcMemo) SITE.funcMemo();
          return false;
        }
      }

      if (SITE.listTitleXP2 && SITE.XP2memo) { // 2つ目の項目名がありそこにホバーしていればそれで56
        var ele = document.elementFromPoint(mousex, mousey);
        if (elegeta(SITE.listTitleXP2).indexOf(ele) != -1) {
          var date = new Date();
          var dateStr = (key == KEYMEMO5 ? MEMO5WORD : MEMO6WORD) || date.getFullYear() + "." + ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + " (" + ["日", "月", "火", "水", "木", "金", "土"][date.getDay()] + ")";
          memoElement(ele.innerText, document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
          if (SITE.funcMemo) SITE.funcMemo();
          return false;
        }
      }

      var ele = (SITE.detailTitleXP && isDetail) ? (eleget0(SITE.detailTitleXP, (SITE.detailRangeFunc ? SITE.detailRangeFunc(document.elementFromPoint(mousex, mousey)) : document.elementFromPoint(mousex, mousey))) || eleget0(SITE.detailTitleXP)) : document.elementFromPoint(mousex, mousey);
      var date = new Date();
      var dateStr = (key == KEYMEMO5 ? MEMO5WORD : MEMO6WORD) || date.getFullYear() + "." + ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + " (" + ["日", "月", "火", "水", "木", "金", "土"][date.getDay()] + ")";
      memoElement(ele, document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
      if (SITE.funcMemo) SITE.funcMemo();
      return false;
    }
    if (key == KEYMEMO1 || key == KEYMEMO2) { // 1::1memo 2::2memo
      e.preventDefault();
      var ele = document.elementFromPoint(mousex, mousey);
      if (SITE.listTitleXP2 && SITE.XP2memo) { // 2つ目の項目名がありそこにホバーしていればそれで12
        //      var ele = document.elementFromPoint(mousex, mousey);
        if (elegeta(SITE.listTitleXP2).indexOf(ele) != -1) {
          memoElement(ele.innerText, document, key == KEYMEMO2 ? COLOR2 : COLOR1);
          if (SITE.funcMemo) SITE.funcMemo();
          return false;
        }
      }
      if (SITE.title) { // 直接ホバーしている要素が対象ならそれで登録(1つのbox内に複数の対象(作品名と作者名など)がある時にどちらで登録するかを選べるための処理)
        //        var ele = document.elementFromPoint(mousex, mousey);
        if (elegeta(SITE.title).find(e => e == ele)) {
          memoElement(ele.innerText?.trim(), document, key == KEYMEMO2 ? COLOR2 : COLOR1) //, window.getSelection().toString().trim() || dateStr);
          if (SITE.funcMemo) SITE.funcMemo();
          return false;
        }
      }
      //        var ele = eleget0(SITE.detailTitleXP) ? eleget0(SITE.detailTitleXP) : document.elementFromPoint(mousex, mousey);
      var ele = (SITE.detailTitleXP && isDetail) ? (eleget0(SITE.detailTitleXP, (SITE.detailRangeFunc ? SITE.detailRangeFunc(document.elementFromPoint(mousex, mousey)) : document.elementFromPoint(mousex, mousey))) || eleget0(SITE.detailTitleXP)) : document.elementFromPoint(mousex, mousey);
      memoElement(ele, document, key == KEYMEMO2 ? COLOR2 : COLOR1);
      if (SITE.funcMemo) SITE.funcMemo();
      return false;
    }
    if ((key == KEYMEMO1S || key == KEYMEMO2S)) { // 3:: 4:: free memo
      e.preventDefault();
      var target = (prompt(`メモを付けたい項目のタイトルが含むキーワードを入力してください\nこのページでは${SITE?.listTitleMemoSearchXP?.indexOf("**")!=-1?"部分一致です":"全体一致です"}\n\n`) || "")?.trim();
      if (!target) return;
      var memo = (prompt("『" + target + "』\nに付けるメモを書いてください") || "").trim();
      if (!memo) return;
      storeMemo(target.trim(), memo, key == KEYMEMO1S ? COLOR1 : COLOR2)
      if (SITE.funcMemo) SITE.funcMemo();
      return false;
    }
    if (key == KEYRESETMEMO) { // !::reset memo
      e.preventDefault();
      prefRestrict(SITE.id + 'SearchMyMemo', "array");
      let smm = JSON.stringify(pref(SITE.id + ' : SearchMyMemo') || []);
      if (smm === '[]') smm = "";
      var tmp = prompt(SITE.id + "\n\n" + KEYRESETMEMO + ":\nメモ(現在" + (pref(SITE.id + ' : SearchMyMemo') || []).length + ")をJSON形式で編集してください\n重複は自動的に削除されます\n空欄を入力すれば全削除されます\n先頭の[の前に+を付けると現在のデータに追加(マージ)します\n\n" + smm, smm);

      if (tmp === smm) return false;
      if (tmp !== null) { // ESCで抜けたのでなければ
        //pref(SITE.id + ' : SearchMyMemo', tmp.trim() || []);
        try {
          var mergemode = tmp?.trim()?.match(/^\+|^+/)
          if (mergemode) {
            tmp = tmp?.trim()?.replace(/^\+|^+/, "")?.trim()
            var tmp2 = pref(SITE.id + ' : SearchMyMemo') || []
            tmp = JSON.parse(tmp || "") || []
            var tmp3 = tmp.concat(tmp2)
            tmp = JSON.stringify(tmp3)
          }
          tmp = tmp ? JSON.parse(tmp) : []
          pref(SITE.id + ' : SearchMyMemo', tmp);
          prefRestrict(SITE.id + 'SearchMyMemo', "array");
          var a = pref(SITE.id + ' : SearchMyMemo')
          var b = (Array.from(new Set(a.map(v => JSON.stringify(v))))).map(v => JSON.parse(v)) // uniq:オブジェクトの配列→JSON文字列配列→uniq→オブジェクトの配列//var b = a.reduce((a, v) => { if (!a.some((e) => (e.t === v.t && e.m === v.m && e.c === v.c))) { a.push(v); } return a; }, []); // uniq

          var found = 0; // 同一タイトルに5/6キーの日時メモが日時違いで重複していたら削除
          var dups = []
          var c = [...b]
          if (mergemode) {
            do {
              found = 0
              for (let v of b) {
                if (v.m.match(/^\d\d\d\d\.\d\d\.\d\d\s\(.\)$/)) {
                  var e2 = b.find(v2 => v.t == v2.t && v.c == v2.c && v2.m.match(/^\d\d\d\d\.\d\d\.\d\d\s\(.\)$/) && v2 != v)
                  if (e2) {
                    //console.table({orig:v,dup:e2})
                    var ea = [v, e2].sort((a, b) => a.m > b.m ? 1 : -1)
                    //console.table(ea)
                    var dup = b.find(v3 => JS(v3) == JS(ea[1]))
                    //console.log("%c"+JS(dup),"color:#F00;")
                    dups.push(dup);
                    b = b.filter(f => f != dup)
                    found = 1
                    break
                  }
                }
              }
            } while (found)
          }
          if (mergemode && dups.length) {
            if (confirm(`同一のタイトルに5/6キーの日時メモが複数付いているものが${dups.length}個ありました\nこれを重複とみなし最も古い日時のメモ以外を削除することもできますが\nそうしますか?\n\n削除する項目:\n${JS(dups).replace(/\},{\"t\"\:/g,'},\n{"t":')}`)) {
              c = b
            }
          }
          pref(SITE.id + ' : SearchMyMemo', c || []);
          /*
      if (tmp !== null) { // ESCで抜けたのでなければ
        //pref(SITE.id + ' : SearchMyMemo', tmp.trim() || []);
        try {
          if (tmp.match(/^\+/)) {
            tmp = tmp.replace(/^\+/, "")
            var tmp2 = pref(SITE.id + ' : SearchMyMemo') || []
            tmp = JSON.parse(tmp || "") || []
            var tmp3 = tmp.concat(tmp2)
            tmp = JSON.stringify(tmp3)
          }
          tmp = tmp ? JSON.parse(tmp) : []
          pref(SITE.id + ' : SearchMyMemo', tmp);
          prefRestrict(SITE.id + 'SearchMyMemo', "array");
          var a = pref(SITE.id + ' : SearchMyMemo')
          var b = (Array.from(new Set(a.map(v => JSON.stringify(v))))).map(v => JSON.parse(v)) // uniq:オブジェクトの配列→JSON文字列配列→uniq→オブジェクトの配列//var b = a.reduce((a, v) => { if (!a.some((e) => (e.t === v.t && e.m === v.m && e.c === v.c))) { a.push(v); } return a; }, []); // uniq
          pref(SITE.id + ' : SearchMyMemo', b || []);
          */
          //document.body.remove();
          setTimeout(() => {
            location.reload();
          }, 1000)
          return false
        } catch (e) {
          alert(e + "\n入力された文字列がうまくparseできなかったので設定を変更しません\n正しいJSON書式になっているか確認してください");
          return false
        }
      }
    }
    if (key == KEYRESETMEMOAUTO) { // Shift+2::reset automemo
      e.preventDefault();
      var str = pref(SITE.id + ' : SearchMyMemo') || [];
      if (alsoClearBenchMemoWhenClearAutoMemo) {
        var newstr = str.filter(e => !(e.c == COLOR3 || e.c == COLORCPUSCORE)); // CPUスコアもリセット
        var newstr2 = str.filter(e => (e.c == COLOR3 || e.c == COLORCPUSCORE)); // CPUスコアもリセット
      } else {
        var newstr = str.filter(e => !(e.c == COLOR3));
        var newstr2 = str.filter(e => (e.c == COLOR3));
      }
      if (confirm(SITE.id + "\n\n" + KEYRESETMEMOAUTO + ":\n自動メモ(" + newstr2.length + ")のみ全て削除します。良いですか?\n\n消すもの:\n" + JSON.stringify(newstr2))) {
        pref(SITE.id + ' : SearchMyMemo', JSON.stringify(newstr));
        popup2("自動メモをクリアしました", 1);
        document.body.remove();
        location.reload();
      }
      return false;
    }
    if (key == "Shift+#") { // Shift+3::#::hide/show memo
      e.preventDefault();
      if ($('#pickbox:visible,.setSlider:visible,[floated]:visible').length) { $('#pickbox:visible,.setSlider:visible,[floated]:visible').hide(); } else if ($(`.yhmMyMemo:visible,.ignoreMe.shibo:visible,#shiboButton:visible,#5chVerticalThreadTitle:visible,.setSlider:visible,#ftxa:visible,.quoteSpeechBalloon:visible,.quoteSpeechBalloonImg:visible`).length) {
        $(`.yhmMyMemo:visible,.ignoreMe.shibo:visible,#shiboButton:visible,#5chVerticalThreadTitle:visible,.setSlider:visible,#ftxa:visible,.quoteSpeechBalloon:visible,.quoteSpeechBalloonImg:visible`).hide()
      } else {
        $(`.yhmMyMemo:hidden,.ignoreMe.shibo:hidden,#shiboButton:hidden,#5chVerticalThreadTitle:hidden,.setSlider:hidden,#ftxa:hidden,.quoteSpeechBalloon:hidden,.quoteSpeechBalloonImg:hidden`).show()
        $('#pickbox:hidden,.setSlider:hidden,[floated]:hidden').show()
      }
      if (SITE.funcMemo) SITE.funcMemo();
      return false;
    }
    if (SITE.maxpriceXP && !isDetail) {
      if (key == KEYMAXP) { // maxpriceXP
        e.preventDefault();
        let ele = eleget0(SITE.maxpriceXP);
        if (ele) {
          ele.focus();
          ele.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
          ele.select();
          popup2("上限価格にフォーカス", 1);
        }
      }
      return false;
      //}
    }
  }
  //  document.addEventListener('keydown', keyListen, false)
  document.addEventListener('keydown', keyListen, true) // youtube/watchで先取りするためにtrue

  document.addEventListener("mousemove", e => ((mousex = e.clientX), (mousey = e.clientY), (hovertimer = 0), undefined), false)
  //document.addEventListener("mousemove", function(e) { mousex = e.clientX; mousey = e.clientY; hovertimer = 0; }, false);

  // AP継ぎ足しを監視
  setTimeout(() => { run() }, (SITE.delayAutoWeighting || 0) * WAIT || (SITE.delay || 0));
  document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { run(evt.target, "APed"); }, false);

  // DOM追加を監視
  var DNIDelay = null;
  //  if (!isDetail && SITE.observe) {
  if (SITE.observe) {
    debug && dc("observe DNI");
    document.body.addEventListener('DOMNodeInserted', dnifunc, false);
    //document.body.addEventListener('transitionend', dnifunc, false); // テスト

    function dnifunc(e) {
      let ele = e.target;
      /*if (SITE.observeFunc)
        if (!SITE.observeFunc(ele)) { return } else { debug && console.log(`dnifunc observed, to do:`, ele);
          run(document.body, "observed", ele) }*/
      if (DNIDelay) return;
      if (ele?.classList?.contains("ignoreMe")) return;
      if (SITE.observeId && (ele.id !== SITE.observeId)) return;
      if (SITE.observeClass && !SITE.observeClass.includes(e.target.className)) return;
      //      if (ele.classList && ele.classList.contains("ignoreMe")) return;
      if (SITE.observeTagName && SITE.observeTagName !== ele.tagName) return;
      if (SITE.ignoreDNI && SITE.ignoreDNI(ele)) return;
      if (ele.className && SITE.observeClassNameNot && SITE.observeClassNameNot.includes(ele.className)) return;
      //debug&&console.log(`accept dni:`,ele)
      DNIDelay = setTimeout(
        //        ((ele)=>{return ()=>{
        (function(ele) {
          return function() {
            run(document.body, "observed", ele); // ここで run(ele.parentNode.parentNode, "observed"); などとすると速くなるが~searchXPが何世代まで親を参照するか分からないので全サイトの動作確認が必要
            //            run(SITE.observeFunc?ele.parentNode:document.body, "observed", ele); // ここで run(ele.parentNode.parentNode, "observed"); などとすると速くなるが~searchXPが何世代まで親を参照するか分からないので全サイトの動作確認が必要
            DNIDelay = null;
          }
        })(ele)
        //        () => {
        //        run(document.body, "observed",ele); // ここで run(ele.parentNode.parentNode, "observed"); などとすると速くなるが~searchXPが何世代まで親を参照するか分からないので全サイトの動作確認が必要
        //        DNIDelay = null;
        //      }
        , SITE.observe || 0);

    }
  }

  // タブにフォーカスが戻ったら再実行
  //  if (SITE.redoWhenRefocused) window.addEventListener("focus", () => { restoreHidden() })
  if (SITE.redoWhenRefocused) window.addEventListener("focus", () => {
    //    if (JS(prefCache[SITE.id + ' : SearchMyMemo'] || []) !== JS(pref(SITE.id + ' : SearchMyMemo') || []) || JS(prefCache[SITE.id + ' : SearchHideTitle'] || []) !== JS(pref(SITE.id + ' : SearchHideTitle') || [])) {
    if (!prefCacheEqual(SITE.id + ' : SearchMyMemo') || !prefCacheEqual(SITE.id + ' : SearchHideTitle')) {
      restoreHidden()
    } // prefCache:キャッシュと保存されたデータが同一だったら再実行しない
  })

  // 詳細画面に対応しているサイトかredoWhenReturnedが1ならタブにフォーカスが戻ったら再実行する
  if (SITE.detailTitleXP || SITE.redoWhenReturned) {
    var hidden, visibilityChange;
    if (typeof document.hidden !== "undefined") {
      hidden = "hidden";
      visibilityChange = "visibilitychange";
    } else if (typeof document.msHidden !== "undefined") {
      hidden = "msHidden";
      visibilityChange = "msvisibilitychange";
    } else if (typeof document.webkitHidden !== "undefined") {
      hidden = "webkitHidden";
      visibilityChange = "webkitvisibilitychange";
    }
    document.addEventListener(visibilityChange, handleVisibilityChange, false);

    function handleVisibilityChange() {
      if (SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) { return; }
      if (document[hidden]) {} else {

        if (!(JS(prefCache[SITE.id + ' : SearchMyMemo'] || []) !== JS(pref(SITE.id + ' : SearchMyMemo') || []) || JS(prefCache[SITE.id + ' : SearchHideTitle'] || []) !== JS(pref(SITE.id + ' : SearchHideTitle') || []))) { return }

        let prefHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
        if (prefHide !== disableHide) {
          disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
          restoreTranslucent();
        }
        restoreHidden();
      }
    }
  }

  // タブにフォーカスが戻った時等用 隠していた要素のうち非表示登録から外されたものを再表示
  function restoreHidden() {
    if (isDetail) {
      //      showByTitle(eleget0(SITE.detailTitleXP).textContent.replaceTitle());
      //      var dtitle = eleget0(SITE.detailTitleXP).textContent.replaceTitle();
      var d = eleget0(SITE.detailTitleXP)
      if (d && !(/\"/.test(d.textContent.replaceTitle()))) showByTitle(d.textContent.replaceTitle());
    }
    if (!isDetail || SITE.hideListEvenDetail) {
      let resist = pref(SITE.id + ' : SearchHideTitle') || [];
      debug && sw("")
      for (let ele of elegeta('//*[@data-hidden="1" or @data-hidden="2"]')) {
        //let title = getTitleFromParent(ele, 1); // これだとXP2はヒットしないので再表示されない:保留
        let title = ele.dataset.yhmkey;
        if (SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
        let i = resist.indexOf(title); // ここは常に全体一致判定なのでcontains判定のサイトでは少し余計に再表示してしまう(でもまたすぐ隠す)
        if (i === -1) {
          showByTitle(title);
          //if(debug)V&&dc(title + "は再表示")
        }
      }
      debug && sw("show by returned")

    }
    setTimeout(() => { run(document.body, "returned"); }, 0);
    if (SITE.funcQ) SITE.funcQ();
  }

  // ヤフオク キーワードの検索対象を切り替えるボタン
  if (SITE.id == "YAJ2") {
    if (location.href.indexOf("://page.auctions.yahoo.co.jp/jp/auction/") == -1) {
      for (let kw of [{ t: "タイトルからのみ検索する", s: "&f=0x2" }, { t: "タイトルと商品説明から検索する", s: "&f=0x4" }]) {
        var ele = eleget0('//div[@class="ptsOption"]/a/../../..');
        if (ele && !(location.href.match(kw.s))) {
          var ele2 = ele.parentNode.insertBefore(document.createElement("a"), ele.nextSibling);
          ele2.innerHTML = kw.t + " ";
          ele2.href = location.href.replace(/\&f\=.*(\&|$)/, "") + kw.s;
        }
      }
    }
  }

  // URL変化を監視、変化したら再実行
  if (SITE.urlHasChangedCommonFunc && !observeUrlHasChangedCommon) {
    var observeUrlHasChangedhrefCommon = location.href;
    var observeUrlHasChangedCommon = new MutationObserver(function(mutations) {
      if (observeUrlHasChangedhrefCommon !== location.href) {
        prefCacheClear();
        observeUrlHasChangedhrefCommon = location.href;
        SITE.urlHasChangedCommonFunc();
      }
    });
    observeUrlHasChangedCommon.observe(document, { childList: true, subtree: true });
  }

  function run(node = document.body, runmode = "1st", ele = null) { // 1st observed returned
    //    if(debug)V&&dc("runmode : " + runmode + " / node tag: " + node?.tagName + " / ele.tag : " + ele?.tagName + " / ele.class : " + ele?.className + " ele.id : " + ele?.id); // beautify
    debug && dc("runmode : " + runmode + " / node tag: " + (node.tagName ? node.tagName : "-") + (ele ? (" / ele.tag : " + (ele.tagName ? ele.tagName : "-") + " | ele.class : " + (ele.className ? ele.className : "-") + " | ele.id : " + (ele.id ? ele.id : "-")) : ""));
    debug && sw("reset");
    if (pauseAll) return;
    debug && sw("run");

    //    if (debug>=3) { elegeta(SITE.listTitleXP).forEach(e => debugEle(e, "force"));elegeta(SITE.listTitleXP2).forEach(e => debugEle(e, "force")) }
    if (debug >= 3 && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE)))) {
      elegeta(SITE.listTitleXP).concat(elegeta(SITE.listTitleXP2)).forEach(e => {
        debugEle(e, "force autoRemove");
        //setTimeout(()=>{debugEle(e,"remove");},2000);
      });
    }
    // サイトごとの個別処理
    if (SITE.func) { SITE.func(node); }

    //if (SITE.disableUrlRE && (SITE.disableUrlRE.test(location.href))) { return; }

    // ホバー時の操作案内のポップアップを登録
    //    if (ENABLE_HELP_CONCLUSION) {
    if ((debug >= 1 || ENABLE_HELP_CONCLUSION) && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE)))) {
      //      var lh = (!isDetail && SITE.helpInBlock) ? $("<span class='ignoreMe phov' id='yafuokuhelp' style='cursor:pointer; color:#505050; font-size:15px; background:#ffffffb0; padding:0px 4px 0px 4px; border-radius:9px;border:#505050 1px solid; position: absolute; bottom:2px; right: 20em;' title='クリックでこのガイドを一時的に消す'>Q:非表示 W:アンドゥ 1:○メモ 2:×メモ</span>") : $("<span class='ignoreMe phov' id='yafuokuhelp' style='all:initial; cursor:pointer; z-index:100; color:#505050; font-size:15px; background:#ffffffc0; padding:3px; border-radius:9px;border:#505050 1px solid; position:fixed; bottom:1em; right: 1em;' title='クリックでこのガイドを一時的に消す'>Q:非表示 W:アンドゥ 1:○メモ 2:×メモ</span>");
      var lh = (!isDetail && SITE.helpInBlock) ? $("<span class='ignoreMe phov' id='yafuokuhelp' style='cursor:pointer; color:#505050; font-size:15px; background:#ffffffb0; padding:0px 4px 0px 4px; border-radius:9px;border:#505050 1px solid; position: absolute; bottom:2px; right: 20em;' title='クリックでこのガイドを一時的に消す'>Q:非表示 W:アンドゥ 1:○メモ 2:×メモ</span>") : $("<span class='ignoreMe phov' id='yafuokuhelp' style='all:initial; cursor:pointer; z-index:1000; color:#505050; font-size:15px; background:#ffffffc0; padding:3px; border-radius:9px;border:#505050 1px solid; position:fixed; bottom:1em; right: 1em;' title='クリックでこのガイドを一時的に消す'>Q:非表示 W:アンドゥ 1:○メモ 2:×メモ</span>");
      var lh2 = $(`<span class='ignoreMe phov2' id='yafuokuhelp' style='all:initial; cursor:pointer; z-index:2147483647; color:#505050; font-size:15px; background:#ddeeffc0; padding:3px; border-radius:9px;border:#304050 1px solid; position:fixed; bottom:1em; right: 1em;' title='クリックでこのガイドを一時的に消す'>${SITE.XP2name||""}Q:非表示 W:アンドゥ${ SITE.XP2memo?" 1:○メモ 2:×メモ":""}</span>`);
      // 画面全体で1つだけ=詳細画面の方
      if (SITE.detailURLRE && location.href.match(SITE.detailURLRE)) {
        $('span.phov').remove();
        lh.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
        debug && sw("zentai help");
        //SITE.listTitleXP2 + "" → SITE.listTitleXP2 + "/../.."
        $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
          $('span.phov').fadeTo(0, 0);
          lh2.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
        }, function() {
          $(".phov2").remove();
          $('span.phov').fadeTo(0, 1);
        }); // test
      } else {
        // 一画面に複数ある=検索結果&セラー画面の方
        if (runmode !== "observed") { // 初処理+追記部分のみ=重複しない処理
          //          $(node).find(SITE.listHelpJQS || elegeta(SITE.listHelpXP || (SITE.listTitleXP ? SITE.listTitleXP + "/../.." : undefined))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
          //          $(node).find(SITE?.box || SITE.listHelpJQS || elegeta(SITE.listHelpXP || (SITE.listTitleXP ? SITE.listTitleXP + "/../.." : undefined))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
          //          console.log(elegeta(SITE?.box, node).concat(elegeta(SITE?.listHelpJQS, node)).concat(elegeta(SITE?.listHelpXP, node)).concat(SITE?.listTitleXP ? elegeta(SITE?.listTitleXP + "/../..", node):[]))
          //          console.log(elegeta(SITE?.box, node),(elegeta(SITE?.listHelpJQS, node)),(elegeta(SITE?.listHelpXP, node)),(SITE?.listTitleXP ? elegeta(SITE?.listTitleXP + "/../..", node):[]))

          //          $(elegeta(SITE?.box, node).concat(elegeta(SITE.listHelpJQS, node)).concat(elegeta(SITE.listHelpXP, node)).concat(elegeta(SITE.listTitleXP ? SITE.listTitleXP + "/../.." : "", node))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
          $(elegeta(SITE?.box, node).concat(elegeta(SITE.listHelpJQS, node)).concat(elegeta(SITE.listHelpXP, node)) || (elegeta(SITE.listTitleXP ? SITE.listTitleXP + "/../.." : "", node))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });

          $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
            $('span.phov').fadeTo(0, 0);
            lh2.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
          }, function() {
            $(".phov2").remove();
            $('span.phov').fadeTo(0, 1);
          }); // test
        } else { // 重複ありの処理
          /*          $(node).find(SITE.listHelpJQS || elegeta(SITE.listHelpXP || (SITE.listTitleXP ? SITE.listTitleXP + "/../.." : undefined))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
                    $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
          */

          //$(node).find(SITE?.box || SITE.listHelpJQS || elegeta(SITE.listHelpXP || (SITE.listTitleXP ? SITE.listTitleXP + "/../.." : undefined))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
          //          $(elegeta(SITE?.box, node).concat(elegeta(SITE.listHelpJQS, node)).concat(elegeta(SITE.listHelpXP, node)).concat(elegeta(SITE.listTitleXP ? SITE.listTitleXP + "/../.." : "", node))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
          $(elegeta(SITE?.box, node).concat(elegeta(SITE.listHelpJQS, node)).concat(elegeta(SITE.listHelpXP, node)) || (elegeta(SITE.listTitleXP ? SITE.listTitleXP + "/../.." : "", node))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
          $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
            $('span.phov').fadeTo(0, 0);
            lh2.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
          }, function() {
            $(".phov2").remove();
            $('span.phov').fadeTo(100, 1);
          }); // test
        }
        debug && sw("1gyou help");
      }
    }

    // 高速化のためにtitleXP/2の要素のtextContentに含まれるメモ・NGだけの集合を作る>documemtのtextContent>documemtのinnerHTML の順
    //    let fastmode = !fasttest ? null : !(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc;
    let fastmode = !fasttest ? null : SITE.listTitleSearchFunc ? null : SITE.title || (!(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc);
    //let fastmode = !fasttest ? null : !(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP));
    //    let fasttext = !fasttest ? null : fastmode ? node.textContent?.nfd() || "" : node.innerHTML?.nfd() || "";

    //    let fasttext = !fasttest ? null : fastmode ? ele?.textContent || node.textContent || "" : ele?.textContent || node.innerHTML || "";
    let fasttext = !fasttest ? null : fastmode ? node.textContent || "" : node.innerHTML || "";
    //let fasttext = !fasttest ? null : node.textContent +" "+ node.innerHTML // こうしてしまう手もある
    //console.log(fastmode,fasttext)
    if (fasttext > "") fasttext = fasttext.replace(/\\u0026|&amp;/gm, "&"); //prompt(fasttext,fasttext) // node.innerText中の&がunicodeエスケープされているのでもとに戻す youtubeで必要
    var fastMatch = !fasttest ? null : fastmode ? (SITE.title ? elegeta(SITE.title, node) : []).concat(SITE.listTitleXP ? elegeta(SITE.listTitleXP, node) : []).concat((SITE.listTitleXP2 ? elegeta(SITE.listTitleXP2, node) : [])).concat((SITE.detailTitleXP ? elegeta(SITE.detailTitleXP, node) : [])) : null;
    debug && sw(fastmode ? "use fast test" : "NOT fast mode")
    if (fasttest && fastmode) { debug && sw("draft by fastMatch") } else { debug && sw("draft by innerHTML") }
    //prompt(fasttext,fasttext)

    // メモ貼りを実行 memo::
    if (runmode === "observed" || runmode === "returned") {
      debug && sw("reset");
      $('span[data-mbt="1"]').remove();
      debug && sw("removing memo");
    }
    var isnotChrome = (window.navigator.userAgent.toLowerCase().indexOf('chrome') == -1);

    if (pref(SITE.id + ' : SearchMyMemo')) {
      var i = 0;
      var hitTitle = [];
      var titles = pref(SITE.id + ' : SearchMyMemo')
      if (fasttest) {
        if (fastMatch) {
          //          for (let ele of fastMatch) { hitTitle = hitTitle.concat(titles.filter(t => { return ele.textContent?.nfd().indexOf(t.t?.nfd()) !== -1 })); } debug&&sw("mymemo draft-test");
          for (let ele of fastMatch) { hitTitle = hitTitle.concat(titles.filter(t => { return ele.textContent.indexOf(t.t) !== -1 })); } debug && sw("mymemo draft-test");
          debug && sw("memo/fastMatch")
        } else { // document.innerHTMLにタイトルが含まれるメモに絞り込む
          //          hitTitle = hitTitle.concat(titles.filter(t => { return fasttext.indexOf(t.t) !== -1 }));
          //          hitTitle = hitTitle.concat(titles.filter(t => fasttext.indexOf(t.t?.nfd()) !== -1)); //453,463
          hitTitle = hitTitle.concat(titles.filter(t => fasttext.indexOf(t.t) !== -1)); //453,463
          debug && sw(`memo/indexOf ${hitTitle.length}`)
        }
        hitTitle = [...new Set(hitTitle)];
        for (let a of hitTitle.sort(function(a, b) { return isnotChrome ? (a.c == COLORCPUSCORE && b.c !== COLORCPUSCORE ? 1 : 0) : (a.c != COLORCPUSCORE && b.c == COLORCPUSCORE ? -1 : 0); })) {
          memoByTitle(a.t, a.m, node, a.c || COLOR1, a.u);
        }
        debug && sw("memo/fastTest")
      } else {
        for (let a of pref(SITE.id + ' : SearchMyMemo').sort(function(a, b) { return isnotChrome ? (a.c == COLORCPUSCORE && b.c !== COLORCPUSCORE ? 1 : 0) : (a.c != COLORCPUSCORE && b.c == COLORCPUSCORE ? -1 : 0); })) {
          memoByTitle(a.t, a.m, node, a.c || COLOR1, a.u);
        }
        debug && sw("memo/slow")
      }
    }
    debug && sw("mymemo ( draft-matched : " + ((hitTitle || []).length) + " )"); //JSON.stringify(hitTitle)

    // 非表示を実行 hide::
    //    var help = (KEYHIDE + ":非表示 " + KEYUNDO + ":アンドゥ " + (isHidePartialMatch ? (SITE.disableKeyB==1 ? "" : KEYBW + ":NGワード ") : "") + KEYEDIT + ":NG編集 " + KEYMEMO1 + KEYMEMO2 + ":メモを追加 " + KEYMEMO1S + KEYMEMO2S + ":自由メモ " + KEYMEMO5 + KEYMEMO6 + ":定型メモ " + KEYRESETMEMO + ":メモを編集 " + (SITE.automemoURLRE ? KEYRESETMEMOAUTO + ":自動メモのみ全削除 " : "") + KEYTOGGLEtranslucent + ":半透明") + ((SITE.wholeHelp && SITE.wholeHelp[0]() && SITE.wholeHelp[1]) || "");
    var help = (KEYHIDE + ":非表示 " + KEYUNDO + ":アンドゥ " + (isHidePartialMatch ? (SITE.disableKeyB ? "" : KEYBW + ":NGワード ") : "") + KEYEDIT + ":NG編集 " + KEYMEMO1 + KEYMEMO2 + ":メモを追加 " + KEYMEMO1S + KEYMEMO2S + ":自由メモ " + KEYMEMO5 + KEYMEMO6 + ":定型メモ " + KEYRESETMEMO + ":メモを編集 " + (SITE.automemoURLRE ? KEYRESETMEMOAUTO + ":自動メモのみ全削除 " : "") + KEYTOGGLEtranslucent + ":半透明") + ((SITE.wholeHelp && SITE.wholeHelp[0]() && SITE.wholeHelp[1]) || "");
    if (pref(SITE.id + ' : SearchHideTitle')) {
      var i = 0;
      var hitTitle = [];
      var titles = pref(SITE.id + ' : SearchHideTitle') //.map(q=>q?.nfd())
      if (fasttest) {
        if (fastMatch) {
          for (let ele of fastMatch) {
            var a = titles.filter(t => ele.textContent.indexOf(t) !== -1);
            if (a) hitTitle = hitTitle.concat(a);
          } //console.log(hitTitle)
        } else { // document.innerHTMLにタイトルが含まれるメモに絞り込む
          hitTitle = titles.filter(t => { return fasttext.indexOf(t) !== -1 });
        }
        hitTitle = [...new Set(hitTitle)];
        debug && sw("block draft-test");
        for (let title of hitTitle || []) { i += hideByTitle(title, node); }
        debug && sw("block ( actually : " + i + " / draft-matched : " + ((hitTitle || []).length) + (fastMatch ? " / target : " + fastMatch.length : "") + " )");
      } else {
        for (let title of pref(SITE.id + ' : SearchHideTitle') || []) { i += hideByTitle(title, node); }
        debug && sw("block ( actually : " + i + "  )");
      }
      if (i) { help = i + "個を非表示にしました\n" + help + (debug && fasttest ? " \n\nドラフトでマッチ:" + (JSON.stringify(hitTitle.slice(0, 9))) : ""); }
    }
    // 全体ヘルプを表示
    //    if (debug || (ENABLE_HELP_CONCLUSION && (SITE.helpOnDNI || (runmode === "1st" && SITE.listTitleXP)) && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))))) popup2(help, 1);
    if (debug || (ENABLE_HELP_CONCLUSION && (SITE.helpOnDNI || (runmode === "1st" && (SITE.title || SITE.listTitleXP))) && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))))) popup2(help, 1.5);

    // 自動メモを探索&製作
    /*    if (isDetail || (SITE.automemoForceFunc && SITE.automemoForceFunc())) {
          makeautomemo()
          for (let t = 1; t < ENABLE_AUTOMEMO; t++) { setTimeout(makeautomemo, t * 2000); }
          debug && sw("automemo");
        } //debug&&t>0?popup3( t * t / 2 * 1000,2,1):0; }

        function makeautomemo() {
          if (ENABLE_AUTOMEMO && SITE.automemoURLRE && (location.href.match(SITE.automemoURLRE))) {
            SITE.automemoFunc();
          }
        }
    */
    //if(ENABLE_AUTOMEMO ){
    function mekeautomemo() {
      if (ENABLE_AUTOMEMO &&
        (SITE?.automemoURLRE && (location?.href?.match(SITE.automemoURLRE)) || isDetail || (SITE?.automemoForceFunc && SITE?.automemoForceFunc()))
      ) { SITE?.automemoFunc(); }
    }
    mekeautomemo()
    for (let t = 0; t < ENABLE_AUTOMEMO; t++) {
      setTimeout(() => {
        mekeautomemo()
      }, (t + 1) * 2000)
    }
    debug && sw("automemo")
    //debug&&t>0?popup3( t * t / 2 * 1000,2,1):0; }
    //}

    if (SITE.funcFinally) SITE.funcFinally(disableHide);
    return;
  }

  function restoreTranslucent() {
    if (pref(SITE.id + ' : SearchHideTitle')) {
      //      let fastmode = !fasttest ? null : !(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc;
      //      let fastmode = !fasttest ? null : SITE.title || (!(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc);
      let fastmode = !fasttest ? null : SITE.listTitleSearchFunc ? null : SITE.title || (!(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc);
      //      var fasttext = !fasttest ? null : fastmode ? document.body.textContent?.nfd() || "" : document.body.innerHTML?.nfd() || "";
      var fasttext = !fasttest ? null : fastmode ? document.body.textContent || "" : document.body.innerHTML || "";

      var fastMatch = !fasttest ? null : fastmode ? (SITE.title ? elegeta(SITE.title) : []).concat(SITE.listTitleXP ? elegeta(SITE.listTitleXP) : []).concat((SITE.listTitleXP2 ? elegeta(SITE.listTitleXP2) : [])).concat((SITE.detailTitleXP ? elegeta(SITE.detailTitleXP) : [])) : null;

      debug && dc(fastmode ? "restoreTranslucent : use fastmode" : "restoreTranslucent : not use fastmode")
      debug && sw("reset")
      var i = 0;
      var hitTitle = [];
      var titles = pref(SITE.id + ' : SearchHideTitle').map(e => e = e)
      if (fasttest) {
        if (fastMatch) {
          for (let ele of fastMatch) {
            var a = titles.filter(t => ele.textContent.indexOf(t) !== -1);
            if (a) hitTitle = hitTitle.concat(a);
          }
        } else {
          hitTitle = titles.filter(t => { return fasttext.indexOf(t) !== -1 });
        }
        hitTitle = [...new Set(hitTitle)];
      } else {
        hitTitle = pref(SITE.id + ' : SearchHideTitle') || []
      }
      for (let title of hitTitle) showByTitle(title, 0);
      debug && sw("restoreTranslucent")
    }
    if (SITE.funcOnTOn) SITE.funcOnTOn();
  }

  function eletext(xpa, xp) {
    if (typeof xpa == "string") { // string
      let e = eleget0(xpa);
      if (e) debugEle(e);
      return e ? e.innerText : "";
    } else { // array
      let text = "";
      xpa.forEach(xp => {
        elegeta(xp).forEach(e => {
          debugEle(e);
          text = text + (e.innerText + "\n");
        })
      })
      return text;
    }
  }

  function autoMemo(re, text) {
    let automemotarget = SITE.automemoSearchFunc();
    let node = document.body;
    let sou = automemotarget.match(re);
    if (sou && sou.length) {
      sou.shift();
      var memo = Array.from(new Set(sou)).join(" ").replace(/[A-Za-z0-9.,]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248) }).replace(/\s{2,99}| /gm, " ").trim();
      // node.innerHTML=node.innerHTML.replace(re,"<mark>$1</mark>");
      var title = getDetailTitle()
      if (!title) return;
      var tmp = pref(SITE.id + ' : SearchMyMemo') || [];
      var isExist = tmp.filter(e => e.t == title && e.m == memo);
      if (isExist.length == 0) {
        if (debug) popup3(memo, 2, 5000);
        storeMemo(title, memo, COLOR3, node);
      }
      return true;
    }
    return false;
  }

  function getDetailTitle(x, y) {
    //    var ele = (SITE.detailTitleXP && isDetail) ? eleget0(SITE.detailTitleXP) : document.elementFromPoint(mousex, mousey);
    //    var ele = ((SITE.detailTitleXP && isDetail) && eleget0(SITE.detailTitleXP)) || (SITE?.automemoForceFunc()) || document.elementFromPoint(mousex, mousey);
    var ele = ((SITE.detailTitleXP && isDetail) && eleget0(SITE.detailTitleXP)) || (eleget0(SITE?.title)) || document.elementFromPoint(mousex, mousey);
    if (!ele) return;
    var title = getTitleFromParent(ele);
    if (!title) return;
    return title;
  }

  function getTitleFromParent(ele, nodisplay = 0) { // ele要素の親の出品物タイトルを返す
    if (!nodisplay)
      debug && dc("start at : " + ele.innerText);
    if (SITE.title) {
      let box = ele?.closest(SITE.box)
      if (box) {
        let title = eleget0(SITE.title, box)?.textContent?.trim()
        if (title) { return title }
        return
      }
    }
    //    if (isDetail) return tri((SITE.useText ? ele.textContent.replace(/\|/g, '\|') : ele.title || ele.textContent.replace(/\|/g, '\|') || ele.alt));
    if (isDetail) return tri((SITE.useText ? ele.textContent.replace(/\|/g, '\|') : SITE.useURL ? ele.getAttribute("href").replace(/\?.*$/, "") : ele.title || ele.textContent.replace(/\|/g, '\|') || ele.alt));
    for (let i = 0; i < (SITE.listGen); i++) {
      if (!nodisplay)
        debug && dc("go up (" + i + ") : " + ele.innerText)
      var ele2 = elegeta(SITE.listTitleXP, ele);
      if (!nodisplay)
        debug && dc("length:" + ele2.length)
      if (ele2.length === 1 || (SITE.searchAllowLength && ele2.length)) {
        if (!nodisplay)
          debug && dc("href : " + ele2[0].getAttribute("href") + "\ntitle : " + tri((ele2[0].title + " \ntextContent : " + ele2[0].textContent.replace(/\|/g, '\|') + " \nalt : " + ele2[0].alt)));
        return SITE.useURL ? ele2[0].getAttribute("href").replace(/\?.*$/, "") : SITE.useText ? tri(ele2[0].textContent.replace(/\|/g, '\|')) : tri((ele2[0].title || ele2[0].textContent.replace(/\|/g, '\|') || ele2[0].alt));
      }
      if (ele === document) return;
      ele = ele.parentNode;
    }
    return;
  }

  function tri(str) {
    if (!str) return "";
    if (str.match(/\"/)) { popup3("項目名に \" を含むので多分うまく処理できません"); return ""; }
    return (SITE.trim) ? str.trim() : str;
  }

  function memoElement(ele, node, color = COLOR1, memoword = "") { //12 memo
    if (!ele) return;
    var title = typeof ele === "string" ? ele : getTitleFromParent(ele);
    if (!title) return;
    if (SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
    if (!title) return;
    var memo = memoword || (prompt("『" + title + "』\nのメモを書いてください") || "").trim();
    //        storeMemo(title, sani(memo), color, node);
    storeMemo(title, memo, color, node);
    return true;
  }

  function storeMemo(title, memo, color = COLOR1, node = document, jumpUrl = null) {
    if (title && memo) {
      memo = sani(memo)
      let tmp = pref(SITE.id + ' : SearchMyMemo') || [];

      var isExist = tmp.filter(e => e.t === title && e.c === color && e.m === memo); // 重複してなければ
      if (isExist.length == 0) {

        jumpUrl ? tmp.push({ t: title, m: memo, c: color, u: jumpUrl }) : tmp.push({ t: title, m: memo, c: color })
        pref(SITE.id + ' : SearchMyMemo', tmp)
        memoByTitle(title, memo, node, color, jumpUrl);
      }
    }
  }

  function memoByTitle(title, memo, node, color, jumpUrl = null) {
    if ((SITE.preventMemo && SITE.preventMemo(memo)) || (title.indexOf('"') !== -1 && !SITE.box)) return; // todo:タイトルに"があると正しく検索できないので処理しない
    //    var xp = SITE?.listTitleMemoSearchXP?.replaceTitle(title?.nfd());
    var xp = SITE?.listTitleMemoSearchXP?.replaceTitle(title);
    let isChapterMemo = color === COLORVIDEOTIME; // && memo.match0(/^([\d:]+)\s/)
    let memoPosition = SITE.memoPosition || "afterend"
    for (let titleEle of
        //        SITE.memo ? elegeta(SITE.title, node).filter(e => e?.textContent === title || e?.title === title || SITE.trim && e?.textContent?.trim() === title).map(e => SITE.memo(e)) :
        //        SITE.title ? elegeta(SITE.title, node).filter(e => e?.textContent === title || e?.title === title || SITE.trim && e?.textContent?.trim() === title) :
        SITE.title ?
        SITE.titleSubstr ? elegeta(SITE.title, node).filter(e => e?.textContent.indexOf(title) !== -1) :
        elegeta(SITE.title, node).filter(e => e?.textContent === title || e?.title === title || SITE.trim && e?.textContent?.trim() === title) :
        elegeta(xp, node)) {
      //for (let titleEle of SITE.title ? elegeta(SITE.title, node).filter(e => e?.textContent?.trim()?.nfd() === title?.nfd() || e?.title?.nfd() === title?.nfd() || SITE.trim && e?.textContent?.trim()?.nfd() === title?.nfd()) : elegeta(xp, node)) {
      if (titleEle) {
        var ele1 = SITE.memoFunc ? SITE.memoFunc(titleEle) : // titleノードから位置をずらす関数
          SITE.listTitleMemoSearchXPSameGen ? titleEle :
          titleEle.parentNode;
        let isCPU = memo.match(/Pentium|Celeron|Core\s?i\d|Ryzen|GHz|AMD.*APU/i);
        //        ele1.insertAdjacentHTML("afterend", '<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo" id="' + escape(title + memo + color) + '" title="『' + title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>") + '』についたメモ(クリックで削除)' + (isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "") + '" style="' + MEMOSTYLE + (isCPU ? " cursor:help; " : "") + ' background-color:' + color + ';">' + memo + '<span style="display:none">ഛഥ</span></span>')
        //ele1.insertAdjacentHTML("afterend", '<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo" id="' + escape(title + memo + color) + '" title="『' + title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>") + '』についたメモ(クリックで削除)' + (isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "") + '" style="' + MEMOSTYLE + (isCPU ? " cursor:help; " : "") + ' background-color:' + color + ';">' + memo + '</span>')
        //                ele1.insertAdjacentHTML("afterend", '<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo" id="' + escape(title + memo + color) + '" data-color="'+(color===COLOR2?"x":"o")+'" title="『' + title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>") + '』についたメモ(クリックで削除)' + (isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "") + '" style="' + MEMOSTYLE + (isCPU ? " cursor:help; " : "") + ' background-color:' + color + ';">' + memo + '</span>')
        //        ele1.insertAdjacentHTML("afterend", '<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo yhmMyMemo' + (color === COLOR2 ? "X" : "O") + '" id="' + escape(title + memo + color) + '" title="『' + title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>") + '』についたメモ(クリックで削除)' + (isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "") + '" style="' + MEMOSTYLE + (isCPU ? " cursor:help; " : "") + ' background-color:' + color + ';">' + memo + '</span>')
        ele1.insertAdjacentHTML(memoPosition, '<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo yhmMyMemo' + (color === COLOR2 ? "X" : "O") + '" id="' + escape(title + memo + color) + '" title="『' + title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>") + '』についたメモ(クリックで削除)' + (isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "") + '" style="' + MEMOSTYLE + (isCPU ? " cursor:help; " : "") + ' background-color:' + color + ';">' + memo + '</span>')
        var ele = memoPosition !== "afterend" ? ele1.firstElementChild : ele1.nextElementSibling.firstElementChild
        //if (!memofast) $(ele).hide().fadeIn(SITE.observe ? 0 : 150);
        $(ele).hide().fadeIn(SITE.observe || memofast ? 0 : 150);
        //$(ele).hide().fadeIn(SITE.observe ? 0 : 150);

        // CPUモデルナンバーを右クリックでuserbenchmark検索
        if (isCPU) {
          $(ele).on('contextmenu', (function(title, memo) {
            return function() {
              if (pref("lastItemName") == undefined) { // 前回の処理が終わってないとだめ
                pref("lastItemName", title);
                popup3(title);
                memo = memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+");
                window.open("https://duckduckgo.com/?q=!ducky+" + memo + "+userbenchmark");
                setTimeout(() => {
                  if (pref("lastItemName")) {
                    popup3("Investigating " + memo + " timed out");
                    pref("lastItemName", "");
                  }
                }, 30000); // 30秒以内に見ないとだめ
              }
              return false;
            }
          })(title, memo));
        }
        // チャプターメモメモを右クリックでその場所に移動 u::
        if (isChapterMemo) {
          ele.dataset.cm = "1"
          //        if(!GF.plNotFlex){GM_addStyle("#meta.ytd-playlist-panel-video-renderer{display:block}"),GF.plNotFlex=1;} // プレイリストがdisplay:flexで1行に詰め込めないので外す試用
          // var p=ele.closest('#meta');if(p)p.style.display="block !important"
          if (/\/watch/.test(location.href) && (ele.closest("#title,.ytd-video-primary-info-renderer") || ele1?.classList?.contains("HeaderContainer-topAreaLeft"))) {
            //            $(ele).on('contextmenu', (function(title, memo) {
            ele.addEventListener('contextmenu', e => {
              var videoEle = eleget0('//video');
              if (!videoEle) return
              videoEle.currentTime = hms2sec(memo.match0(/^([\d:]+)\s/)) || videoEle.currentTime
              //videoEle.scrollIntoView({ block: "center", behavior: "smooth" })
              e.preventDefault()
              return false;
            })
            //})(title, memo));
          } else {
            var p = ele.closest('.ytd-playlist-panel-video-renderer')?.style?.display;
            p = "block !important"
            if (jumpUrl) ele.dataset.url = jumpUrl
            ele.addEventListener('contextmenu', e => {
              var jumpUrl = e.target.dataset.url || null
              if (jumpUrl) {
                (eleget0('//video') && !eleget0('//video')?.paused) || e.ctrlKey ? (eleget0('//video')?.pause(), window.open(jumpUrl)) : location.href = jumpUrl;
                e.preventDefault()
                return false;
              }
            })
          }
        }
        setRemoveMemo(ele, title, memo, color)
      }
    }
  }

  function setRemoveMemo(ele, title, memo, color) { // メモをクリックで消す処理
    $(ele).on("click", e => { // 遅いかも?
      e.preventDefault();
      e.stopPropagation();
      pref(SITE.id + ' : SearchMyMemo', (pref(SITE.id + ' : SearchMyMemo') || []).filter(n => !(n.t == title && n.m == memo && n.c == color)))
      for (let e of elegeta('//span[contains(@class,"yhmMyMemo") and @id="' + escape(title + memo + color) + '"]')) $(e).hide(200).queue(function() { $(this.parentNode).remove() }); //e.remove(); //ele.remove();
      //document.body.dispatchEvent(new Event('yhmMyMemoRemoved'))
      adja(document.body, "afterbegin", "<yhmmymemoremoved></yhmmymemoremoved>");
      eleget0('yhmmymemoremoved')?.remove(); // 学園祭用に消去を告知
    })
  }

  function blockElement(ele) { //Q:: toggle
    if (!ele) return;
    var title = getTitleFromParent(ele);
    debug && dc(`got : 『${ title}』`)
    addNG(title);
  }

  function hideByTitle(titleOrEle, node, targetXP = SITE.listTitleSearchXP) {
    let i = 0;
    if (!isDetail || SITE.hideListEvenDetail) {
      let resHit = [];
      if (SITE.listTitleSearchFunc) resHit = SITE.listTitleSearchFunc(titleOrEle); // 主に5ch用、レス中キーワードNG
      // 1項目ずつ
      //      for (let ele of typeof titleOrEle === "object" ? [titleOrEle] : elegeta(targetXP.replaceTitle(titleOrEle), node).concat(resHit)) { // titleがテキストなら項目タイトルにヒットする要素、DOM要素なら直接それを隠す
      for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title, node).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.trim()) : v.textContent?.trim()) === titleOrEle).map(v => v.closest(SITE.box)) : elegeta(targetXP.replaceTitle(titleOrEle), node)).concat(resHit)) { // titleがテキストなら項目タイトルにヒットする要素、DOM要素なら直接それを隠す
        if (!ele) continue;
        i++;
        //        ele.dataset.hidden = "1";
        //        if (!disableHide && !SITE.forceTranslucentFunc?.includes(ele?.tagName)) {
        //        if (!disableHide && !SITE.forceTranslucentFunc?.test(ele?.tagName)) {
        //        if (!disableHide && (!SITE.forceTranslucentFunc || !ele.closest(SITE.forceTranslucentFunc))) {
        //        if (!disableHide && (!SITE.forceTranslucentFunc || !ele.closest(SITE.forceTranslucentFunc)) && (!SITE.forceTranslucentFunc || !SITE.forceTranslucentFunc(ele))) {
        if (!disableHide && (!SITE.forceTranslucentFunc || !SITE.forceTranslucentFunc(ele))) {
          //        if (!disableHide && (!SITE.forceTranslucentFunc || (typeof SITE.forceTranslucentFunc==="String"? !ele.closest(SITE.forceTranslucentFunc)):(!SITE.forceTranslucentFunc(ele)))) {
          $(ele).fadeOut(17);
          ele.dataset.hidden = "1";
          ele.dataset.yhmkey = titleOrEle;
        } else {
          ele.style.opacity = "0.75";
          setTimeout(function() { ele.style.opacity = "0.50" }, 17 * 2);
          ele.dataset.hidden = "2"; // 必要?
          ele.dataset.yhmkey = titleOrEle;
          elegeta('//*[text()="' + titleOrEle + '"]').forEach(e => { debugEle(e, "autoRemove") });
          //          if (!ele.title && typeof titleOrEle === "string") { ele.dataset.whybehidden = `非表示登録『${titleOrEle}』にヒット` }
          //          if (!ele.title && typeof titleOrEle === "string") { ele.dataset.whybehidden = `非表示登録『${titleOrEle}』にヒット`; ele.title=`非表示登録『${titleOrEle}』にヒット` }
          if (!ele.title) ele.title = `非表示登録『${titleOrEle}』にヒット`
          ele.dataset.whybehidden = `非表示登録『${titleOrEle}』にヒット`
        }
      }
    }
    if (isDetail) {
      // 詳細:画面全体
      if (isDetail && SITE.detailTitleXP && SITE.detailTitleSearchXP) {
        var xp = SITE.detailTitleSearchXP.replaceTitle(titleOrEle) // isearでハイライトされていると×
        for (let ele of elegeta(xp, node)) {
          if (!ele) continue;
          debug && dc(xp, ele, ele.textContent);
          i++;
          ele.style.opacity = "0.5";
          if (!ele.title) ele.title = `非表示登録『${titleOrEle}』にヒット`
          ele.dataset.whybehidden = `非表示登録『${titleOrEle}』にヒット`
        }
      }
    }
    return i;
  }

  function showByTitle(titleOrEle, time = 34, xpath = SITE.listTitleSearchXP) {
    //    if (!xpath) return
    if (!isDetail || SITE.hideListEvenDetail) {
      let resHit = [];
      if (SITE.listTitleSearchFunc) resHit = SITE.listTitleSearchFunc(titleOrEle);
      // 1項目ずつ
      //var xp = xpath.replaceTitle(titleOrEle);
      //          SITE.title ? elegeta(SITE.title, node).filter(v => (SITE.titleProcessFunc?SITE.titleProcessFunc(v.textContent):v.textContent) === titleOrEle).map(v => v.closest(SITE.box)) :
      //      for (let ele of typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title).filter(e => e?.textContent == titleOrEle).map(e => e?.closest(SITE.box)) : elegeta(xpath.replaceTitle(titleOrEle)).concat(resHit)) {

      for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.trim()) : v.textContent?.trim()) === titleOrEle).map(e => e?.closest(SITE.box)) : elegeta(xpath.replaceTitle(titleOrEle))).concat(resHit)) {

        if (!ele) continue;
        if (ele) ele.style.opacity = "1";
        $(ele).fadeIn(time);
        //        delete ele.dataset.hidden;
        if (ele) ele.dataset.hidden = null; //ele.dataset.yhmkey=null;
        //setTimeout(function() { ele.style.opacity = "1" }, 17 * 2);
      }
    }
    if (isDetail) {
      // 詳細:画面全体
      if (isDetail && SITE.detailTitleXP && SITE.detailTitleSearchXP) {
        var xp = SITE.detailTitleSearchXP.replaceTitle(titleOrEle) // isearでハイライトされていると×
        for (let ele of elegeta(xp)) {
          if (!ele) continue;
          ele.style.opacity = "1";
        }
      }
    }
  }

  function addNGWord() {
    //    var newWord = (prompt(`非表示にしたい項目のタイトルが含むNGワードを入力してください${SITE.QRule}\nすでに登録されている文字列を入力するとそれを削除します\n\n現在の全体\n${JSON.stringify(pref(SITE.id + ' : SearchHideTitle') || []) }\n\n`) || "").trim();
    var newWord = (prompt(`非表示にしたい項目が含むNGワードを入力してください${SITE.QRule||""}\nすでに登録されている文字列を入力するとそれを削除します\n\n現在の全体\n${JSON.stringify(pref(SITE.id + ' : SearchHideTitle') || []) }\n\n`) || "").trim();
    addNG(newWord);
  }

  function addNG(title) {
    if (!title) return;
    if (SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
    if (!title) return;
    let resist = pref(SITE.id + ' : SearchHideTitle') || [];
    let i = resist.indexOf(title);
    if (i !== -1) {
      resist.splice(i, 1);
      pref(SITE.id + ' : SearchHideTitle', resist);;
      popup2("『" + title + "』\nを非表示登録から削除しました", 1);
      showByTitle(title);
      if (isDetail && SITE.showFunc) SITE.showFunc();
    } else {
      resist.push(title);
      pref(SITE.id + ' : SearchHideTitle', resist);
      popup2("『" + title + "』\nを非表示登録しました(" + KEYUNDO + ":取り消し " + KEYEDIT + ":編集)", 1);
      hideByTitle(title);
    }
  }

  // キャッシュ付き
  var elegetaCacheXP = "";
  var elegetaCacheLastTime = new Date();
  var elegetaCacheResult = [];
  var elegetaCacheNode = "";
  var ehit = 0;
  var emiss = 0;

  /*function elegeta(xpath, node = document) {
    if (!xpath || !node) return [];
    let flag
    if (!/^\.?\//.test(xpath)) return /:visible$/.test(xpath) ? [...node.querySelectorAll(xpath.replace(/:visible$/, ""))].filter(e => e.offsetHeight) : [...node.querySelectorAll(xpath)]
    try {
      var array = [];
      var ele = document.evaluate("." + xpath.replace(/:visible$/, ""), node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
      let l = ele.snapshotLength;
      for (var i = 0; i < l; i++) array[i] = ele.snapshotItem(i);
      return /:visible$/.test(xpath) ? array.filter(e => e.offsetHeight) : array;
    } catch (e) { popup3(e + "\n" + xpath + "\n" + JSON.stringify(node), 1); return []; }
  }

  function eleget0(xpath, node = document) {
    if (!xpath || !node) return null;
    if (!/^\.?\//.test(xpath)) return /:visible$/.test(xpath) ? [...node.querySelectorAll(xpath.replace(/:visible$/, ""))].filter(e => e.offsetHeight)[0] ?? null : node.querySelector(xpath.replace(/:visible$/, ""));
    try {
      var ele = document.evaluate("." + xpath.replace(/:visible$/, ""), node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
      return ele.snapshotLength > 0 ? ele.snapshotItem(0) : null;
    } catch (e) { alert(e + "\n" + xpath + "\n" + JSON.stringify(node)); return null; }
  }
*/
  function elegeta(xpath, node = document) {
    if (!xpath || !node) return [];
    //    let xpath2 = xpath.replace(/:inv?screen|:visible|:text\*=[^:]*/g, "") // text*=~中で:は使えない
    let xpath2 = xpath.replace(/:inscreen|:visible|:text\*=[^:]*/g, "") // text*=~中で:は使えない
    let array = []
    try {
      if (!/^\.?\//.test(xpath)) {
        array = [...node.querySelectorAll(xpath2)]
      } else {
        var snap = document.evaluate("." + xpath2, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)
        let l = snap.snapshotLength
        for (var i = 0; i < l; i++) array[i] = snap.snapshotItem(i)
      }
      if (/:visible/.test(xpath)) array = array.filter(e => e.offsetHeight)
      //if (/:invscreen/.test(xpath)) array = array.filter(e => { var eler = e.getBoundingClientRect(); return (eler.bottom >= 0 && eler.top <= document.documentElement.clientHeight) }) // 画面縦内に1ピクセルでも入っている
      else if (/:inscreen/.test(xpath)) array = array.filter(e => { var eler = e.getBoundingClientRect(); return (eler.bottom >= 0 && eler.right >= 0 && eler.left <= document.documentElement.clientWidth && eler.top <= document.documentElement.clientHeight) }) // 画面内に1ピクセルでも入っている
      if (/:text\*=./.test(xpath)) { let text = xpath.replace(/^.*:text\*=([^:]*)$/, "$1"); if (text) array = array.filter(e => new RegExp(text).test(e?.textContent)) }
    } catch (e) { return []; }
    return array
  }

  function eleget0(xpath, node = document) {
    if (!xpath || !node) return null;
    //    if (/:inv?screen|:visible|:text\*=/.test(xpath)) return elegeta(xpath, node)?.shift();
    if (/:inscreen|:visible|:text\*=/.test(xpath)) return elegeta(xpath, node)?.shift();
    if (!/^\.?\//.test(xpath)) return node.querySelector(xpath);
    try {
      var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
      return ele.snapshotLength > 0 ? ele.snapshotItem(0) : null;
    } catch (e) { alert(e + "\n" + xpath + "\n" + JSON.stringify(node)); return null; }
  }

  function dc(str, force = 0) {
    //if (debug == 1) console.log(str);
    if (debug >= 1 || force) popup3(str, 0, 31000, "top");
    return str;
  }

  function popup3(text, i = 0, timer = 5000, alignY = "bottom") {
    if (!ENABLE_HELP_CONCLUSION) return;
    if (text === undefined || text === null) text = "<null>"
    if (typeof text == "string") text = text.slice(0, 200);
    //    if (typeof text == "number") text = String(text);
    if (typeof text == "number") text = String(text);
    text = text.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>")
    let id = Math.random().toString(36).substring(2);
    let maey = alignY == "bottom" ? 0 : elegeta(".wcspu3top").map(e => e.getBoundingClientRect().bottom).reduce((a, b) => Math.max(a, b), 0) + 2;
    if (i > 0) $(`.pu3line${i}s`).remove()
    var ele = $(`<span id="wcspu3${id}" class="ignoreMe wcspu3${alignY} pu3line${i}s" style="all:initial; max-width:33%;font-family:sans-serif; position: fixed; right:0em; ${ alignY }:${((maey) + i * 18)}px; z-index:2147483647; opacity:1; font-size:15px; margin:0px 1px; text-decoration:none !important;  padding:1px 6px 1px 6px; word-break: break-all !important; border-radius:12px; background-color:#6080ff; color:white; ">${ text }</span>`).appendTo('body');
    let ey = ele[0]?.getBoundingClientRect()?.height
    //    if (ele[0].getBoundingClientRect().bottom >= (window.innerHeight)) {
    if (ele[0].getBoundingClientRect().bottom >= (window.innerHeight)) {
      elegeta('.wcspu3top').forEach(e => { e.style.top = parseFloat(e?.style?.top) - (ey) - 2 + "px" })
    }
    if (typeof text == "string") { maey += (text.match(/<br>/gmi) || []).length || 0; } //console.log((text.match(/<br>/gmi) || [] ).length) }
    setTimeout(() => {
      eleget0('//span[@id="wcspu3' + id + '"]')?.remove();
    }, timer);
  }
  var maet;

  function popup2(text, i = 0, style = "", position = "bottom") {
    if (!ENABLE_HELP_CONCLUSION) return;
    text = String(text).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>")
    var mae = eleget0('//span[@id="yhmbox"]');
    if (maet && mae) {
      mae.remove();
      clearTimeout(maet);
    }
    let bgcol = (pref("translucent") != "on") ? "#6080ff" : "#909090";
    var ele = $(`<span id="yhmbox" class="ignoreMe" style="all:initial; font-family:sans-serif; cursor:pointer; position: fixed; right:0em; ${position}:${(i * 2 + 2) }em; z-index:2147483647; opacity:1; font-size:15px; margin:0px 1px; text-decoration:none !important; padding:1px 6px 1px 6px; word-break: break-all !important; border-radius:12px; background-color:${bgcol}; color:white; ${style}">${text}</span>`).appendTo('body');
    maet = setTimeout(function() {
      var mae = eleget0('//span[@id="yhmbox"]');
      if (mae) { mae.remove(); }
    }, 5000);
    $(ele).attr("title", "クリックでこのガイドを一時的に消す").click(function() {
      $(this).fadeOut(200).queue(function() {
        $(this).remove();
        clearTimeout(maet);
      })
    });
  }

  function prefCacheEqual(id) {
    return JS(prefCache[id] || []) === JS(pref(id) || [])
  }

  function prefCacheClear() { prefCache = [] }

  function pref(name, store = null) { // prefs(name,data)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)、prefs(name)で読み出し
    if (store === null) { // 読み出し
      let data = GM_getValue(name) || GM_getValue(name);
      if (data == undefined) return null; // 値がない
      if (data.substring(0, 1) === "[" && data.substring(data.length - 1) === "]") { // 配列なのでJSONで返す
        //        try { return JSON.parse(data || '[]'); } catch (e) {
        try {
          let a = JSON.parse(data || '[]');
          prefCache[name] = a;
          return a
        } catch (e) {
          alert("データベースがバグってるのでクリアします\n" + e);
          pref(name, []);
          prefCache[name] = []
          return;
        }
      } else return data;
    }
    if (store === "" || store === []) { // 書き込み、削除
      GM_deleteValue(name);
      prefCache[name] = []
      return;
    } else if (typeof store === "string") { // 書き込み、文字列
      GM_setValue(name, store);
      prefCache[name] = store
      return store;
    } else { // 書き込み、配列
      //      try { GM_setValue(name, JSON.stringify(store)); } catch (e) {
      try {
        let a = JSON.stringify(store);
        GM_setValue(name, a);
        prefCache[name] = a
      } catch (e) {
        alert("データベースがバグってるのでクリアします\n" + e);
        pref(name, "");
      }
      return store;
    }
  }

  function prefRestrict(name, type) {
    let data = pref(name);
    if (!data) return data;
    if (type === "array") {
      if (typeof data === "object") {
        //            alert("correct");
        return data;
      } else {
        alert("データベースの形式に誤りがある(配列/オブジェクトでない)ためクリアします\n");
        pref(name, "");
        return [];
      }
    }
    return data;
  }

  function prefl(name, store = undefined, logLen = 50) { // prefl(name,data,len)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)・"name+Log"にlen個の履歴保存、prefl(name)で読み出し
    if (store === undefined) { // 読み出し
      return pref(name);
    } else { // 書き込み、削除
      if (store) {
        var a = pref(name + "Log") || [];
        a.unshift(store);
        a = [...new Set(a)];
        pref(name + "Log", a.slice(0, logLen));
      }
      return pref(name, store);
    }
  }

  function debugEle(ele, command = "") {
    if (!ele) return
    if (command.indexOf("remove") !== -1) {
      ele.style.outline = "";
      ele.style.boxShadow = "";
      return;
    }
    if (ENABLE_HELP_CONCLUSION && (debug || command.indexOf("force") !== -1)) {
      var col = getColorFromText(ele.innerText);
      if (command.indexOf("random") !== -1) col = '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
      ele.style.outline = "3px dotted " + col;
      ele.style.boxShadow = " 0px 0px 4px 4px " + col + "30, inset 0 0 100px " + col + "20";
      //      ele.title='\n@class="'+ele.className+'"\n@id="'+ele.id+'"';
      if (command.indexOf("autoRemove") !== -1) {
        setTimeout(() => {
          ele.style.outline = "";
          ele.style.boxShadow = "";
        }, 60000)
      }
    }
  }

  function getColorFromText(str) {
    if (!str) return "#808080"
    var col = 0;
    for (letter of str) { col = (col + str.charCodeAt(letter) ** 3); }
    return '#' + (0x1000000 + col % 0xffffff).toString(16).substr(1, 6);
  }

  function advertiseEle(ele, force = "") {
    if (debug || force == "force") {
      if (ele) ele.style.outline = "4px dotted red";
    }
  }

  function sw(job, mode = "dc") {
    //    if (ENABLE_MEASURE_TIME_SPENT == 0) return;
    if (debug < 2 && !ENABLE_MEASURE_TIME_SPENT) return;
    if (job !== "reset") {
      if (mode === "dc")
        debug && dc(job + " : " + ((new Date().getTime()) - (swb.getTime())) + " ms");
      if (mode === "notify") notifyMe(job + " : " + ((new Date().getTime()) - (swb.getTime())) + " ms");
    }
    if (job !== "reset")
      swb = new Date();
  }

  function isSeller() {
    return location.href.match(/\/seller\//);
  }

  function proInput(prom, defaultval, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
    let r = window.prompt(prom, defaultval)
    if (r === null) return null
    return Math.min(Math.max(
      Number(r.replace(/[A-Za-z0-9.]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248); }).replace(/[^-^0-9^\.]/g, "")), min), max);
  }

  function notifyMe(body, title = "", clickfunc = null) {
    if (!("Notification" in window)) return;
    else if (Notification.permission == "granted") {
      var notify = new Notification(title, { body: body });
      if (clickfunc) {
        notify.onclick = clickfunc
      }
    } else if (Notification.permission !== "denied") Notification.requestPermission().then(function(permission) {
      if (permission === "granted") new Notification(title, { body: body });
    });
  }

  function setupbutton(id, title, func, tips, command) {
    $(`<span id='${id}' class='ignoreMe' title='${tips}' style='cursor:pointer; color:#505050; font-size:15px; background:#ffffffc0; padding:3px; border-radius:9px;border:#505050 1px solid; position:fixed; bottom:3em; right: 1em;'>${title}</span>`).appendTo(document.body).click(function() { func(); if (/removeWhenClicked/.test(command)) { $(this).remove(); } });
  }

  // eleはスクロール画面内に入ってる?
  function isinscreen(ele, evencorner = 0, borderHeight = 0) {
    if (!ele) return;
    var eler = ele.getBoundingClientRect();
    if (evencorner) return (eler.top > 0 - eler.height - borderHeight && eler.left > 0 && eler.left < document.documentElement.clientWidth && eler.top < Math.min(window.innerHeight, document.documentElement.clientHeight) + borderHeight);
    else return (eler.top > 0 - 0 && eler.left > 0 && eler.left + eler.width < document.documentElement.clientWidth && eler.top + eler.height < Math.min(window.innerHeight, document.documentElement.clientHeight) + 0);
  }

  function autoPagerized(callback, command) {
    if (command !== "not1st") callback(document.body)
    document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { callback(evt.target); }, false);
    //    document.body.addEventListener('2chanReloaded', function() { setTimeout(() => { callback() }, 1) }, false);
    if (lh(".2chan.")) document.body.addEventListener('2chanReloaded', function() { setTimeout(() => { callback() }, 1) }, false);
  }

  function searchWithHistory(id, sitename, url, orSeparator = "|") {
    var selection = null;
    let prev = pref(id + " : searchWithHistory")
    if (orSeparator) {
      let query = prompt(`${sitename}で全体検索します\n|でOR\n\n履歴(${id}):\n${ (pref(id + " : searchWithHistoryLog") || []).slice(0, 50).join("\n") }\n\n` + url.replace(/\*\*\*/, "${キーワード}") + '\n\n', selection || (prev ? prev + "|" : ""))
      if (query) {
        query = Array.from(new Set(query.replace(/\|/g, "|").replace(/|+/gmi, "|").split("|"))).join("|").replace(/^[|\|]+|[|\|]+$/gmi, "").trim() // 重複自動削除
        if (!selection) prefl(id + " : searchWithHistory", query.replace(/\|/g, "|"))
        window.open(`${url.replace(/\*\*\*/,encodeURI(query.replace(/|/g,orSeparator)))}`)
      }
    } else {
      let query = prompt(`${sitename}で全体検索します\n\n履歴(${id}):\n${ (pref(id + " : searchWithHistoryLog") || []).slice(0, 50).join("\n") }\n\n` + url.replace(/\*\*\*/, "${キーワード}") + '\n\n', selection || prev || "")
      if (query) {
        if (!selection) prefl(id + " : searchWithHistory", query?.trim())
        window.open(`${url.replace(/\*\*\*/,encodeURI(query?.trim()))}`);
      }
    }
    return false;
  }

  function sec2hms(s) {
    return new Date(s * 1000).toISOString().substr(11, 8).replace(/^00\:0|^00\:/, "");
  }

  function hms2sec(s) {
    return ((s.match0(/^(\d+):\d+:\d+$/) || 0) * 60 * 60) + ((s.match0(/^\d+:(\d+):\d+$/) || 0) * 60) + ((s.match0(/^(\d+):\d+$/) || 0) * 60) + ((s.match0(/^\d+:\d+:(\d+)$/) || 0) * 1) + ((s.match0(/^\d+:(\d+)$/) || 0) * 1);
  }

  //  function chapterMemo(requireUrlRE, videoTitleXP, newUrl, copy = 0) {
  function chapterMemo(requireUrlRE, videoTitleXP, newUrl, copy = 0) {
    if (!location.href.match0(requireUrlRE)) return
    var videoEle = eleget0('//video');
    if (!videoEle) { return; } else { var currentTime = sec2hms(Math.floor(videoEle.currentTime)); }
    if (typeof videoTitleXP == "string") {
      var videoTitleEle = eleget0(videoTitleXP);
      if (!videoTitleEle) return;
      var videoTitle = videoTitleEle.textContent;
    } else { var videoTitle = videoTitleXP(); if (!videoTitle) return false; } //eleget0(videoTitleXP);

    var curMemos = pref(SITE.id + ' : SearchMyMemo') || [];
    var chaMemos = curMemos.filter(e => (e.t == videoTitle && e.c == COLORVIDEOTIME)).sort((a, b) => hms2sec(a.m.match0(/^([\d:]+)\s/)) > hms2sec(b.m.match0(/^([\d:]+)\s/)) ? 1 : -1);
    var chaMemoTU = "";
    chaMemos.forEach(c => { chaMemoTU += `${videoTitle} ${c.m}\n${newUrl.replace(/\*\*time\*\*/,hms2sec(c.m.match0(/^([\d:]+)\s/)))}\n` })
    if (!copy) {
      var jumpUrl = location.href.match0(/https:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11})/);
      if (jumpUrl) jumpUrl = `https://youtu.be/${jumpUrl}&t=${Math.floor(videoEle.currentTime)}`;

      var word = window.getSelection().toString().trim() || (prompt(`『${videoTitle}』\n${currentTime=="0:00"?"に付ける":"の "+currentTime+" に付けるチャプター"}メモを入力してください\n${chaMemoTU?"\n\n列挙(Shift+Uでコピー):\n"+chaMemoTU:""}\n`) || "").trim();
      if (!word) return;
      storeMemo(videoTitle, (currentTime != "0:00" ? currentTime + " " : "") + word.trim(), currentTime == "0:00" ? COLOR1 : COLORVIDEOTIME, document, jumpUrl || "")
    } else {
      GM.setClipboard(chaMemoTU)
      popup2(chaMemoTU, -1, "", "top")
      //var newstr = (pref(SITE.id + ' : SearchMyMemo') || []).filter(e => (e.c === COLORVIDEOTIME));
      //prompt(`チャプターメモから再生するURLの列挙をコピーしました\n\n入力フォームよりチャプターメモのエクスポートとマージが行えます\nコピーしてテキストファイル等に保存すればエクスポートとなり、他環境からエクスポートしたものを入力すればマージになります\n変更せずにEnterかEscを押せば何もしません\n\n${JSON.stringify(newstr)}`, JSON.stringify(newstr))
    }
  }

  // intervalが1以上かつ設定値がdefValueと違っていればintervalミリ秒事に再処理、そうでなければ割り込みはせず、初回の実行もしない
  function setSlider(placeEle, min = 0, max = 100, defValue = 0, title = "", key = "SliderValue", onchangecallback, interval = 0, addProperty = "") { // interval:1なら初回一度だけcallbackも実行、2~ならそのms間隔で定期実行
    if (placeEle && !eleget0(`//input[@id="setSlider${key}"]`)) {
      let val = pref(key) || defValue;
      placeEle.insertAdjacentHTML("afterend", `<input type="range" class="setSlider" id="setSlider${key}" min="${min}" max="${max}" value="${val}" ${addProperty} title="${title.replace("***",val)}\n右クリック:デフォルトに戻す" oninput="this.title='${title}'.replace('***',this.value);" oncontextmenu="this.value='${defValue}'; this.dispatchEvent(new Event('input')); return false;">`)

      let adjustFunc = function(key, interval = 0, defValue = 0, onchange = 0) {
        //popup2(`${interval} ${onchange}`)
        let sliderEle = eleget0(`#setSlider${key}`)
        let sliderEleNum = Number(sliderEle.value)
        onchangecallback(sliderEleNum)
        if (onchange) pref(key, sliderEleNum)
        if (interval && sliderEleNum != defValue) setTimeout(() => { adjustFunc(key, interval, defValue) }, interval)
        //        if (interval>0 && sliderEleNum != defValue) setTimeout(() => { adjustFunc(key, interval, defValue) }, interval)
      }
      let sliderEle = eleget0(`#setSlider${key}`)
      if (sliderEle) {
        sliderEle.addEventListener('input', () => adjustFunc(key, interval, defValue, 1));
        if (Number(sliderEle.value) != defValue) adjustFunc(key, interval, defValue)
      }
      //if (interval == 1) adjustFunc(key, 0, defValue)
      if (interval == 1) onchangecallback(Number(eleget0(`#setSlider${key}`)?.value || defValue))
    }
  }

  function domsort(container, doms, func, prepend = 0) { // container:domsの入っている大枠、省略時はdomsの1つ親 doms:並べ替える要素たち prepend:0:containerの最後に付ける 1:最初に付ける(逆順) 2:最後につける(逆順)(0or2) 3:最初に付ける(昇順) // 1と3のほうが継ぎ足し位置マーカーが上に来ないので多分良い
    if (container === "") container = doms[0]?.parentNode
    if (!container || !doms.length) return
    if (Array.isArray(container)) container = container.shift()
    let col = new Intl.Collator("ja", { numeric: true, sensitivity: 'base' })
    if (prepend == 2 || prepend == 3) doms.map(function(v, i) { return { dom: v, value: func(v, i) } }).sort(function(b, a) { return (!isNaN(b.value) && !isNaN(a.value) ? b.value == a.value ? 0 : (b.value - a.value) : b.value == a.value ? 0 : (col.compare(a.value, b.value))) }).forEach(function(v) { prepend == 3 ? container?.prepend(v.dom) : container?.appendChild(v.dom) })
    if (prepend == 1 || prepend == 0) doms.map(function(v, i) { return { dom: v, value: func(v, i) } }).sort(function(a, b) { return (!isNaN(b.value) && !isNaN(a.value) ? b.value == a.value ? 0 : (b.value - a.value) : b.value == a.value ? 0 : (col.compare(a.value, b.value))) }).forEach(function(v) { prepend ? container?.prepend(v.dom) : container?.appendChild(v.dom) })
  }

  function sortdom(doms, func, prepend = 0) { // doms:並べ替える要素たち prepend:0:昇順 1:降順
    let position = doms[0]?.previousElementSibling
    let container = doms[0]?.parentNode
    if (!container || !doms.length) return
    let col = new Intl.Collator("ja", { numeric: true, sensitivity: 'base' })
    let fragment = new DocumentFragment();
    doms.map((v, i) => { return { dom: v, value: func(v, i) } }).sort((a, b) => (prepend == 0 ?
      (!isNaN(b.value) && !isNaN(b.value) ? a.value == b.value ? 0 : (a.value - b.value) : a.value == b.value ? 0 : (col.compare(a.value, b.value))) :
      (!isNaN(a.value) && !isNaN(b.value) ? a.value == b.value ? 0 : (b.value - a.value) : a.value == b.value ? 0 : (col.compare(b.value, a.value)))
    )).forEach(v => fragment?.append(v.dom))
    position ? position.parentNode.insertBefore(fragment, position.nextSibling) : container.prepend(fragment)
  }

  function before(e, html) { e?.insertAdjacentHTML('beforebegin', html); return e?.previousElementSibling; }

  function begin(e, html) { e?.insertAdjacentHTML('afterbegin', html); return e?.firstChild; }

  function end(e, html) { e?.insertAdjacentHTML('beforeend', html); return e?.lastChild; }

  function after(e, html) { e?.insertAdjacentHTML('afterend', html); return e?.nextElementSibling; }

  function ctLong(callback, name = "test", time = 10) { console.time(name); for (let i = time; i--;) { callback() } console.timeEnd(name) } // 速度測定(もともと長くかかるもの)
  function ct(callback, name = "test", time = 10) { let i = 0; let st = Date.now(); while (Date.now() - st < 1000) { i++, callback() } console.log(`${name} ${i} / 1sec`) } // 速度測定(一瞬で終わるもの)
  function lh(re) { let tmp = location.href.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可
  /*  function JS(v) { return JSON.stringify(v) }

    function JP(v) { return JSON.parse(v) }
  */
  function JS(v) { try { return JSON.stringify(v) } catch { return null } }

  function JP(v) { try { return JSON.parse(v) } catch { return null } }

  function e2sel(ele) { return `${ele.tagName?.toLowerCase()}${ele.id?"#"+ele.id:""}${ele.className?"."+ele.className.replace(/\s/g,"."):""}` }

  function han(str) { return str?.replace(/[A-Za-z0-9]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248) }) || "" }

  function sani(s) { return s?.replace(/&/g, "&amp;")?.replace(/"/g, "&quot;")?.replace(/'/g, "&#39;")?.replace(/`/g, '&#x60;')?.replace(/</g, "&lt;")?.replace(/>/g, "&gt;") || "" }

  function gettime(_fmt = 'YYYY/MM/DD hh:mm:ss.iii', _dt = new Date()) {
    return [
      ['YYYY', _dt.getFullYear()],
      ['MM', _dt.getMonth() + 1],
      ['DD', _dt.getDate()],
      ['hh', _dt.getHours()],
      ['mm', _dt.getMinutes()],
      ['ss', _dt.getSeconds()],
      ['iii', _dt.getMilliseconds()],
    ].reduce((s, a) => s.replace(a[0], `${a[1]}`.padStart(a[0].length, '0')), _fmt)
  }

  function isValidRE(str) {
    try { new RegExp(str) } catch (e) { return false }
    return true
  }

  function matchGG(str, re) {
    return str?.match(new RegExp(re, "gm"))?.map(v => v?.match(new RegExp(re, "m"))?.[1])
  }

})();