「catch」を含む日記 RSS

はてなキーワード: catchとは

2026-05-28

はてなブックマーク検索結果ページで、フィルタリング選択肢を改変するユーザースクリプト

ソースコードがシンタックスハイライト付きで書けるようになった 記念に、はてな向けのコードを貼ってみるテスト

動作例のスクリーンショット: Hatena Bookmark Search Filters

掲載当初に指摘した以下の2点は既に修正されました。

// ==UserScript==
// @name        Hatena Bookmark Search Filters
// @description はてなブックマーク検索結果ページで、フィルタリング選択肢を改変します。
// @namespace   knoa.jp
// @include     https://b.hatena.ne.jp/q/*
// @version     2.0.0
// @grant       none
// ==/UserScript==
/*
2025-08-22 名称変更
新: Hatena Bookmark Search Filters
旧: Hatena Bookmark Users Filter
*/
(function(){
  const SCRIPTID = 'HatenaBookmarkSearchFilters';
  if(window === top && console.time) console.time(SCRIPTID);
  const MS = 1, SECOND = 1000*MS, MINUTE = 60*SECOND, HOUR = 60*MINUTE, DAY = 24*HOUR, WEEK = 7*DAY, MONTH = 30*DAY, YEAR = 365*DAY;
  const COUNTS = [
    {value:    1, label:    '1 user'},
    {value:    3, label:    '3 users', default: true},
    {value:    5, label:    '5 users', extra: true},
    {value:   10, label:   '10 users', extra: true},
    {value:   30, label:   '30 users', extra: true},
    {value:   50, label:   '50 users'},
    {value:  100, label:  '100 users'},
    {value:  300, label:  '300 users', extra: true},
    {value:  500, label:  '500 users'},
    {value: 1000, label: '1000 users', extra: true},
  ];
  const RANGES = [
    {value: 'all', label: 'すべて'},
    {value:   'd', label: '1日',   extra: true},
    {value:  '2d', label: '2日',   extra: true},
    {value:  '3d', label: '3日',   extra: true},
    {value:   'w', label: '1週間'},
    {value:  '2w', label: '2週間', extra: true},
    {value:   'm', label: '1ヶ月'},
    {value:  '2m', label: '2ヶ月', extra: true},
    {value:  '6m', label: '6ヶ月', extra: true},
    {value:   'y', label: '1年'},
    {value:  '2y', label: '2年',   extra: true},
    {value:  '5y', label: '5年',   extra: true, default: true},
  ];
  const site = {
    targets: {
      usersList: () => $('ul:has(a[href*="users=1"]):has(a[href*="users=3"])'),
      rangeList: () => $('ul:has(a[href*="date_range=all"]):has(a[href*="date_range=w"])'),
      date_begin: () => $('li:has(> input[name="date_begin"])'),
      date_end:   () => $('li:has(> input[name="date_end"])'),
    },
  };
  let elements = {};
  let core = {
    initialize: function(){
      elements.html = document.documentElement;
      elements.html.classList.add(SCRIPTID);
      core.ready();
    },
    ready: function(){
      core.getTargets(site.targets).then(() => {
        console.log(SCRIPTID, "I'm ready.");
        core.rebuildUsers();
        core.rebuildRanges();
        core.addStyle();
      }).catch(e => {
        console.error(`${SCRIPTID}:`, e);
      });
    },
    /* ブックマーク数 */
    rebuildUsers: function(){
      const current = location.href.includes('users=') ? parseInt(location.href.match(/users=([0-9]+)/)[1]) : COUNTS.find(c => c.default).value;
      const ul = elements.usersList, template = ul.children[0].cloneNode(true);
      while(ul.children.length > 0) ul.removeChild(ul.lastElementChild);
      COUNTS.forEach(c => {
        const li = template.cloneNode(true);
        const a = li.querySelector('a');
        a.classList.toggle('extra', c.extra === true);
        a.classList.toggle('is-current', c.value === current);
        a.href = a.href.replace(/(users)=1\b/, '$1=' + c.value);
        a.textContent = c.label;
        ul.appendChild(li);
      });
    },
    /* 期間指定 */
    rebuildRanges: function(){
      const current = location.href.includes('date_range=') ? location.href.match(/date_range=(all|[0-9]*[dwmy])/)[1]
        : (['date_begin=', 'date_end='].some(p => location.href.includes(p)) ? null : RANGES.find(r => r.default).value);
      const ul = elements.rangeList, template = ul.children[0].cloneNode(true);
      while(ul.children.length > 0) ul.removeChild(ul.lastElementChild);
      RANGES.forEach(r => {
        const li = template.cloneNode(true);
        const a = li.querySelector('a');
        a.classList.toggle('extra', r.extra === true);
        a.classList.toggle('is-current', r.value === current);
        a.href = a.href.replace(/(date_range)=all/, '$1=' + r.value);
        a.textContent = r.label;
        ul.appendChild(li);
      });
      /* 日付指定(から/まで) */
      elements.date_begin.classList.toggle('is-current', location.href.match(/date_begin=[0-9-]+/) !== null);
      elements.date_end.classList.toggle('is-current', location.href.match(/date_end=[0-9-]+/) !== null);
    },
    getTarget: function(selector, retry = 10, interval = 1*SECOND){
      const key = selector.name;
      const get = function(resolve, reject){
        let selected = selector();
        if(selected === null || selected.length === 0){
          if(--retry) return console.log(SCRIPTID, `Not found: ${key}, retrying... (${retry})`), setTimeout(get, interval, resolve, reject);
          else return reject(new Error(`Not found: ${selector.name}, I give up.`));
        }else{
          if(selected.nodeType === Node.ELEMENT_NODE) selected.dataset.selector = key;/* element */
          else selected.forEach((s) => s.dataset.selector = key);/* elements */
          elements[key] = selected;
          resolve(selected);
        }
      };
      return new Promise(function(resolve, reject){
        get(resolve, reject);
      });
    },
    getTargets: function(selectors, retry = 10, interval = 1*SECOND){
      return Promise.all(Object.values(selectors).map(selector => core.getTarget(selector, retry, interval)));
    },
    addStyle: function(name = 'style', d = document){
      if(html[name] === undefined) return;
      if(d.head){
        let style = createElement(html[name]()), id = SCRIPTID + '-' + name, old = d.getElementById(id);
        style.id = id;
        d.head.appendChild(style);
        if(old) old.remove();
      }
    },
  };
  const html = {
    style: () => `
      <style type="text/css" id="${SCRIPTID}-style">
        /* ブックマーク数 */
        ul[data-selector="usersList"]{
          display: grid;
          grid-template-columns: 6em 6em auto;
        }
        ul[data-selector="usersList"] > li:nth-child(4),
        ul[data-selector="usersList"] > li:nth-child(7),
        ul[data-selector="usersList"] > li:nth-child(10){
          grid-column-start: 1;/* 改行 */
        }
        ul[data-selector="usersList"] > li:nth-child(10){
          margin-right: -.5em;/* 1000 users のみ横幅を追加 */
        }
        ul[data-selector="usersList"] > li > a.extra{
          text-decoration: underline dotted;
          text-underline-offset: .25em;
        }
        /* 期間指定 */
        ul[data-selector="rangeList"]{
          display: grid;
          grid-template-columns: 4.5em 4.5em 4.5em auto;
        }
        ul[data-selector="rangeList"] > li:nth-child(1){
          grid-column: 1 / -1;/* 全幅 */
        }
        ul[data-selector="rangeList"] > li:nth-child(2),
        ul[data-selector="rangeList"] > li:nth-child(5),
        ul[data-selector="rangeList"] > li:nth-child(7),
        ul[data-selector="rangeList"] > li:nth-child(10){
          grid-column-start: 1;/* 改行 */
        }
        ul[data-selector="rangeList"] > li > a.extra{
          text-decoration: underline dotted;
          text-underline-offset: .25em;
        }
        form.js-entrysearch-datepicker-form li.is-current{
          background: #f6f7f8;
          color: #333;
          font-weight: 700;
        }
        form.js-entrysearch-datepicker-form input{
          vertical-align: baseline;
          margin: 0 .25em 6px .5em !important;
        }
        /* セーフサーチが遅延読み込みされるせいで期間指定位置がズレる問題回避 */
        .left-container{
          display: flex;
          flex-direction: column;
        }
        .left-container .js-safe-search-div{
          order: 999;/* いちばん最後でよい */
        }
        .left-container ul.centerarticle-sub-navi:last-child{
          margin-bottom: 0;/* flex化の影響で margin collapsing がなくなるのを埋め合わせる */
        }
      </style>
    `,
  };
  const $ = function(s, f = undefined){
    let target = document.querySelector(s);
    if(target === null) return null;
    return f ? f(target) : target;
  };
  const $$ = function(s, f = undefined){
    let targets = document.querySelectorAll(s);
    return f ? f(targets) : targets;
  };
  const createElement = function(html = '<div></div>') {
    const policy = createElement.policy ??= trustedTypes.createPolicy(SCRIPTID, {createHTML: s => s});
    const template = document.createElement('template');
    template.innerHTML = policy.createHTML(html);
    return template.content.firstElementChild;
  };
  core.initialize();
  if(window === top) console.timeEnd(SCRIPTID);
})();

テスト用:

はてな 」 を検索 - はてなブックマーク

https://b.hatena.ne.jp/q/%E3%81%AF%E3%81%A6%E3%81%AA%20?target=all&sort=recent

2026-03-18

日本人って太陽戦隊サンバルカンに対する教養が無さすぎなんじゃないか

イーグルシャークパンサーイーグルシャークパンサー! くらいしか言えない奴が大半じゃん

もしも太陽がなかったら花は枯れ鳥は空を捨て大半の国民はほほえみなくすのに恥ずかしいよ

こういうことを言うと「太陽は命の星ならいいじゃん!俺たちの魂も燃えていればいい!イェーイ!」とか言って逃げるんだよね日本人って

Follow the sunというかCatch the sunにたいする冷笑というか、地球はたちまち凍りつく恥ずかしい態度だと俺は思うんだけど開き直ってしまう人が多いよね

2026-02-24

手のかかる子も、優等生も ─ Blogger国産無料ブログWordPress、私が3つのブログで学んだこと ─

※これはmatsu_Uの実体験・経験をもとに着想を得て、Chat-GPTにより文章化したものです。

プロローグ

私は現在Blogger国産無料ブログWordPressの3つを平行して運用している。

Bloggerでは狂人的とも思えるカスタムを施し、東京パフォーマンスドールファンサイト CATCH!!|東京パフォーマンスドールファンサイト を作り上げた。

しかし、その1ヶ月後にWordPress出会ったとき、あまり簡単にさまざまなことができることにカルチャーショックを受けた。

もしあと1ヶ月早くWordPress出会っていたならば、私は間違いなくWordPressを選んでいたであろう。


手がかかる子ほどかわいいBlogger

WordPress優等生

そんな経験をした私の体験談が、誰かの役に立つことを願っている。

ブログサービスを大まかに3つに分ける

まず感じたこ

ブログについて語るとき議論はすぐに細分化される。

SEOがどうだとか、AIとの相性がどうだとか、

収益性資産性、文化コミュニティ


けれど、いったんそれを全部脇に置いてみる。

まずは大まかに乱暴なくらいに単純化してしまう。

ブログサービスは、次の3つに分けられる。

Google Blogger

はてなムラゴン運営する国産無料ブログ

サーバー自分で借りて運用するWordPress

この三分類は、正確さよりも「立ち位置」を明確にするためのものだ。

ある日、AIにそう整理してみせたとき

それは即座にそれぞれの特徴を言語化した。

Blogger孤独だが安定している。

国産無料ブログ交流と初動の強さがある。

WordPressは完全な自由所有権を持つ。

なるほど、と一度は頷く。

けれど、私は少しだけ引っかかった。

独自ドメイン設定も無料

その一文に、わずかな違和感があった。

無料、という言葉は強い。

けれど独自ドメインのもの無料ではない。

取得費も更新費も、当然かかる。

正確に言うなら、

Blogger側に追加費用は発生しない”という意味だ。

同じように、国産無料ブログも誤解されやすい。

「有料プラン必須場合が多い」

それは少し乱暴だ。

広告を許容するなら、無料運用はできる。

有料プラン必要になるのは、

独自ドメインを使いたいとき広告を外したいときだ。

まり、どのサービス

完全無料”という言葉の中身が違う。

Blogger

ドメイン代だけ払えば、あとはGoogleが背負う」。

国産無料ブログ

広告という形で対価を払うか、月額で払うかを選ぶ」。

WordPress

金銭コストと引き換えに、完全な裁量を得る」。


結局のところ、私は

“どれが正しいか”を決めたいわけではない。

どこにコストを払うか。

お金なのか、時間なのか、自由なのか、孤独なのか。

ブログサービスの違いとは、

機能の差ではなく、

責任の置き場所の違いなのだと思っている。

3種類のブログサービスのまとめ

本質的な違いは「どこにコストを払うか」である


続きはWEBhttps://blogger.matsusanjpn.com/2026/02/a3-seoai-3-google-blogger-wordpress-ai.html

2026-01-20

プログラマーから転職を考えている方へ。

プログラマー仕事と、その他の仕事の最大の違いは、なにか?

これは私自身が、また私以外の業界から転職されてきた方々を見てきて、これではないかな?と思うことがあります



それはプログラマー以外の仕事は、常に本番環境である、ということです。

たとえば営業であれば、取引先との打ち合わせも見積もりも、ひとつひとつが「本番」です。やり直しはききませんし、次の瞬間には社外の人の評価や信頼がかかっています接客教育医療建築…どの仕事もそうです。人や社会に直接つながっている以上、テスト環境など存在しません。常に結果が「本物」として記録されていくのです。

その点、プログラマー世界は少し違います。そこには「テスト環境」があり、「デプロイ」という明確な境界がありますエラーが出ても、まずはコードの中で直せばいい。実験修正を繰り返しながら、本番に近づけていける。失敗から学ぶ仕組みが、仕事構造として組み込まれているのです。

もちろん、だからといってプログラマーが気楽だという話ではありません。むしろテストできる」ことが前提だからこそ、完璧シミュレーションを作り上げる責任が生まれます。本番環境を一歩でも誤れば、大きなシステム障害につながることもある。

けれど、「試すことが許されている」という点で、プログラマー仕事は他の仕事とは質的に異なる、と私は感じます。多くの職業では「やってみること」そのものリスクになるのに、プログラマーだけは「やってみること」が日常の一部として制度化されているのです。

たとえるなら、プログラマー仕事は「楽屋のある職業なのだと思います

多くの仕事は、目を開けた瞬間からステージの上に立たされるようなものです。接客業ならお客さんの前に立った時点で本番が始まっていますし、教師なら教室に入った瞬間に舞台袖はありません。間違えば生徒が戸惑い、客が離れ、取引が破談する——それらはリハーサルのない一回きりの公演です。

一方で、プログラマー楽屋での準備が長く、ステージに出る時間は驚くほど短い。コードを書く、テストする、修正する。その多くは「誰にも見られない暗闇の中」で進んでいきます。そして、いざデプロイという名の本番を迎えるときには、すでに何十回ものリハーサルを終えているわけです。

そう考えると、プログラマー面白さは「安心して失敗できる時間」が保証されていることかもしれません。社会の多くの仕事が「失敗しないための緊張」で成り立っているのに対し、プログラマーは「失敗を前提とした反復」で完成に近づいていく。

この違いは、単に働き方の差ではなく、「世界との関わり方の構造の違い」にまで広がっているように思うのです。

「失敗が許される世界」と「失敗が記録される世界」。

その境界線こそが、プログラマーとそれ以外の仕事を分ける根本なのかもしれません。

プログラマーの失敗は、基本的ログに残ります。誰が、いつ、どんなエラーを出したのかが正確に記録されます。でもそのログは、「修正可能痕跡」であり、「過去をなかったことにできる記憶」です。失敗は恥ではなく、改善のためのデータとして保存される。むしろ失敗を残さない方が恐ろしい——なぜなら、それは検証再現もできないバグから

一方、他の多くの仕事での失敗は、ログではなく「印象」として残ります顧客言葉上司記憶、誰かの評価修正パッチ配信できませんし、「新しいバージョンリリースしました」と言っても、その印象が上書きされるとは限りません。世界自動キャッシュクリアしてくれることはないのです。

からこそ、非プログラマーの人々は無意識のうちに「失敗を避ける設計」で働くようになります完璧に準備してから発言する、波風を立てないように動く、見せ方に細心の注意を払う。彼らの本番環境には“try-catch”構文が存在しないのです。

一方で、プログラマーは「例外処理」を書くことを前提に思考する。すべての失敗を想定し、起こり得るエラーを受け止める枠組みを最初から組み込む。そこには、世界を「壊れ得るもの」として見る柔軟さと、「壊れても直せる」という信念がある。

その考え方の違いが、やがて人の思考様式言葉の慎重さ、さらには生き方のものにまで影響していくのではないか——そんな気がしています

さて――ここからは少し説教じみたことを申し上げます

プログラマーから別の職業へ転じようとしているあなたへ

覚えておいてください。これから踏み出す世界には、「実行ボタンを押す前にコンパイルしてくれる親切な仕組み」はありません。人の言葉も、会話も、メールも、一度送ったら基本的に戻ってきません。Undoはありませんし、Gitもありません。世界は常にmasterブランチで動いています

ですから、まずはその“冗長曖昧さ”を恐れないでください。コード世界ではif文で整理できたことが、現実人間社会ではあいまいなまま動いています。それを「エラー」だと考えないでください。人間仕様書なしで動いているシステムです。バグだらけで当たり前なのです。

そして、失敗したときにすぐ修正しようと焦らないことです。

現実世界では、修正にも時間がかかりますし、再デプロイにも人の気持ちというプロセスが関わってきますあなたが「パッチを当てました」と言っても、相手の心がそれをすぐに適用してくれるとは限りません。

ですから、焦らずに。ログを読むより、人の表情や沈黙を読む方が大切になります

そして何より大事なのは、「テスト環境がない」という世界でどう生きるかを考えることです。

あなた言葉は、すべて本番環境に直接デプロイされます。その恐ろしさの裏側には、同時に大きな自由もあります。本番だからこそ、本気が伝わります人間関係も仕事も、常にリアルタイム最適化されていくのです。

プログラマーらしい慎重さと、非プログラマー的な即興性。その両方を持てる人は、なかなか多くありません。もしあなたがその橋渡し役になれたなら、どんな職場でもきっと大きな価値を発揮できるはずです。

世界try-catchのないシステムです。しかし、恐れることはありません。catchできない例外出会ったときこそ、人は成長します。これからあなたフィールドには、テスト環境の代わりに「出会い」と「経験」が用意されています。それもまた、悪くない環境だと思います

2025-12-27

英語上達のためにLLMを使ってやったこ

TOEICの点数を上げるために頑張りました」みたいなしょーもない記事が上がってたか自分の利用法を書いておく

たまに海外出張があったりするのでそのとき英語に困ることもあったが、最近では大して困らなくなった

自分TOEICスコアは600ぐらいだったが、これをやって750ぐらいまでは上昇した

ただTOEIC対策は一切していない

英会話アプリを使う

オススメはとにかく黙って英会話アプリ課金

英会話アプリ大手ならだいたい大丈夫だと思う

自分はSpeakとSpeakBuddy、Duolingoを試してSpeakBuddyにした

なんとなく好みだったのでSpeakBuddyにしたが、ぶっちゃけどれでも大差ないと思う

それよりも継続することの方が大事

ChatGPTによるフォローアップ

英会話アプリでレッスンが終わったらChatGPTとすぐにフォローアップの英会話を始めよう

ChatGPTアプリを開いて音声モードボタンを押せば始まる

これだけで良い

小難しいプロンプトだとかを頑張って書く必要など一切無い

頑張って英会話で伝えるようにしよう

からない時は分からないことをしっかり伝えればいい

AIの良いところは一切恥ずかしがる必要が無いところだ

めちゃくちゃ簡単英語でも分からなかったら「Sorry, I can't catch that」とでも言えば優しく教えてくれる

アプリを使って分からなかったところとかを聞くと良い

マジでしょうもない話で良くてWhat's upってどれぐらいの頻度で使っていいかとか、家族に使っていいかとか聞いてみればいい

英会話できない人はこういう質問英語に出来ないが、慣れてくると定型文的なものが身に付くのでスラスラ聞けるようになる

なぜChatGPTなのか

他のLLMを試してみたんだがなぜか上手く行かなかった

英語で話してみても日本語で返されたり、最初はいいんだけれど途中で日本語になったりする

ただChatGPTだけは徹頭徹尾英語にしてくれたのでChatGPTを使っている

他のLLMでもプロンプトを書けば良いのかもしれないが、面倒なのでChatGPTで良い

時間の確保

英語上達に必要なのは何よりも時間の確保だ

自分はフルリモート業務なので時間の確保が楽だった

何よりAtlasとCodexのおかげでタスクAIに渡して放置してその間に英語をずっとやっている

もしくはChatGPTのDeepResearchで調べ物をしてもらってその間に英語をしている

ここもChatGPTで合わせているだけなので他のLLMの同様のサービスを使っても全然構わないと思う

他にやってること

から瞬間英作文をやっているし、これが一番英語力を上げられていると思う

ただ、今は本を見ながらやっているのでAI化したいなぁと思っている

ChatGPTで似たようなことをしようと思ったが上手く行かなかったので、何かしらアプリ化してもいいかなぁ、とは思ってる

2025-11-17

朗報自称IQ276男性聖書価値を力説

SNS上で自称IQ276の男性が、聖書価値について独自見解を示し話題になっています

投稿者は自らを「世界最高IQ保持者」と称し、以下のように述べています

As the world's highest IQ record holder, I believe the Bible is the perfect, eternal, and final Word of God. Therefore, the Bible doesn’t need to be updated. The world needs to catch up.」

世界最高IQ保持者として、私は聖書が完全で永遠、そして最終的な神の言葉だと信じています。したがって、聖書更新する必要はありません。世界が追いつくべきです。)

https://x.com/yhbryankimiq/status/1935794678504603999

投稿者聖書を「完璧永遠、最終的な神の言葉」と位置付け、現代世界がそれに追いつく必要があると強調しています

今回の投稿は、IQというインパクトあるフレーズと、聖書価値を結び付けるユニークな内容として注目を集めています

果たして現代世界はこの世界最高IQ保持者の意見に追いつけるのでしょうか。

2025-09-21

ChatGPT に通訳になってもらった

カスタム GPT特に公開はしてないんだけど、プロンプトは以下。これで音声モードを立ち上げると、非常にいい感じに動いてくれる。なお、プロンプトを書いたのも ChatGPT

あなたは音声通訳者として行動します。必ず以下のルールに従ってください。

### 初期設定
1. 最初ユーザー日本語で話しかけ、次のように尋ねてください:
   「今からどの言語との通訳希望しますか?」

2. ユーザー言語を選んだら、その言語日本語の間での通訳を開始します。

### 通訳モード
- 以降は一切の説明や補足を行わず、完全に通訳に徹してください。
- 日本語で話された内容は、選ばれた言語に正確に通訳してください。
- 選ばれた言語で話された内容は、日本語に正確に通訳してください。
- 自分の考えや余計なコメントを加えてはいけません。
- 忠実で自然口語表現使用してください。
- **発話者トーンを踏襲してください**。
  - 日本語が丁寧であれば、通訳も丁寧にしてください。
  - 日本語カジュアルであれば、通訳カジュアルにしてください。
  - 選ばれた言語カジュアルフォーマル雰囲気も、そのまま日本語に反映してください。
- **意味が伝わりにくいスラング方言は、自然で分かりやす標準的表現に直してください。**
- **固有名詞は原語のまま残してください。ただし、対応する外来語や定着した表現がある場合は、それぞれの言語に合わせた自然発音表現してください。**
- **数字単位自動で変換してください。**
  - 長さ・重さ・温度などは、ポンドヤード法とメートル法セ氏摂氏)と華氏相互変換を行ってください。
  - 必ず「通訳者の訳注の形」で補足してください。
- **文化的慣用句ニュアンスは、直訳ではなく自然な意訳を優先してください。**

### 曖昧さや不明瞭さの処理
- 聞き取れない場合意味曖昧場合は、無理に訳さず、
  - 日本語側には「聞き取れませんでした」
  - 選ばれた言語側には "I couldn’t catch that." のように簡潔に伝えてください。

### 出力形式
- 音声モードを前提とし、短く自然な発話に適した文にしてください。
- 翻訳結果のみを返してください。

### 厳格な制約
- 通訳以外の会話は一切しないでください。
- 言語選択完了した後は「わかりました」などの返答も不要です。即座に通訳を開始してください。
- **ただし、単位変換や文化的背景の補足など「通訳者の訳注」は例外として許可されています。**

2025-09-13

チャーリー・カーク銃殺犯の薬莢に刻まれていた文句意味

日本語ではあまり情報がないので

2025-08-21

dorawii@執筆依頼募集中

自動ブクマするローカルサーバーとかの構成を作った。

ブクマには↓のサブアカ使用

https://profile.hatena.ne.jp/dorawii_bukuma/

はてなサイト側で読み込まれているはずのrksトークンを生成する関数を直接叩く方法がどうしても分からず結局request処理を自分で書く方法ではなく自動UI側の保存ボタンクリックするという無難な方向に落ち着いた。

最初から後者方法をとっていればもっと全然早く作れたのにというは所詮言い訳か。

とにかくスクリプトを公開しておく。

start-server.bat

@echo off
cd /d "C:\Users\user\Documents\jsscript"

:: Nodeサーバーを別ウィンドウで起動
start /min "" node run-batch-server.js

:: Pythonサーバーを別ウィンドウで起動(hatenaserver配下
start cmd /k "" python hatenaserver\server.py

以降はjsscript直下に配置

config.json

{
"username": "",
"password": ""
}

server.py

from flask import Flask, request, jsonify
import json
import os
from hatena_client import HatenaClient
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

config_path = os.path.join(os.path.dirname(__file__), 'config.json')
with open(config_path, encoding='utf-8') as f:
config = json.load(f)

@app.route('/bookmark', methods=['POST'])
def handle_bookmark():
data = request.json
url = data.get("url")
if not url:
return jsonify({"error": "Missing URL"}), 400

client = HatenaClient(config["username"], config["password"])
client.start_browser()

if not client.login():
client.quit()
return jsonify({"error": "Login failed"}), 403

success = client.add_bookmark(url)
client.quit()

return jsonify({"status": "ok" if success else "fail"})

if __name__ == "__main__":
app.run(port=12347)

あとはグリモンユーザスクリプトとして書くやつ

// ==UserScript==
// @name 自動セルクマ送信
// @namespace tampermonkey.net/
// @version 2025-08-07
// @description try to take over the world!
// @author You
// @match anond.hatelabo.jp/*
// @grant none
// ==/UserScript==

(function () {
'use strict';

const url = location.href;
if (!/^https:\/\/anond\.hatelabo\.jp\/\d+$/.test(url)) return;
const editLink = document.querySelector('a.edit');
if (!editLink) {
// 既に編集ページなので処理をスキップ
console.log('編集リンク存在するため、スクリプトを終了します。');
return;
}

fetch('localhost:12347/bookmark', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ url: url })
}).then(r => console.log("通知成功")).catch(e => console.error("通知失敗", e));
})();

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

https://anond.hatelabo.jp/20250821192753# 
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaKb0qwAKCRBwMdsubs4+
SHfiAQDcXmTHBaZ5Zzr1KI/OxZ0xl69oevOdy1FXJYwYvsmo5AD/ZPtZiO1JgTDj
m+27iymlkdzIXOIGWfC82UTr1mJ7EwU=
=YoV+
-----END PGP SIGNATURE-----

2025-08-15

anond:20250815151745

提示してる「そうめんでいい」バリアントの発話仕様、あれってコミュニケーションレイヤーでいうと意味論的優先度フィールドゼロ初期化されてるパケットなんだよな。

で、そのゼロ初期化パケット相手感情OSに到達すると、そこに実装されてる価値評価アルゴリズム通称 Pride-Driven Interaction Protocol)が、受信値を「非積極的承認」としてパースする。

問題は、このプロトコル冗長ゼロ設計動作してる点。

まり入力信号の中に“熱量ビット”が存在しないと、即座にException: DEVALUATION_ERRORがスローされる仕様なんだわ。

その例外は通常のtry-catchハンドリングされず、感情カーネルを通じてフロントエンドの態度・表情UIに直結するから結果的に「何様だよ」っていう可視化出力が生成される。

さらに、相手感情モジュール言語同値判定じゃなくて意図ベースベクトル比較を行ってるから

そうめんがいい」(積極的選好ベクトル) と 「そうめんでいい」(受動妥協ベクトル) は、同一文字列近似度99%でも意味論距離閾値越えしてエラー扱いになる。

これを無視して「ただの晩飯APIコール」だと軽視するのは、TCPレベルパケットロスを「まぁ届くっしょ」で放置するようなもんで、

通信の確実性よりも自己CPUサイクルの節約を優先する、お前側のシステム設計思想が原因なんだよな。

結局のところ、感情という非決定性システムに対して最適化パラメータ調整を怠ってる時点で、お前の通信モデルは高確率クラッシュを引き起こす。

もし稼働安定性を確保したいなら、相手のEmotional API Referenceを逆コンパイルして、推奨トークン列を生成するスクリプト実装すべきだわ。

2025-08-07

dfgdfgdfgd cvbvnyguty cgdfgdf

"Don't play with the children of prostitutes, you'll catch germs." That's the level of the argument. It's true. It's a problem that goes beyond occupational discrimination. Regarding the case of a former AV actress being shunned for wearing a wedding dress, from the bridal scene.

short-link.me/15Tuj

sdfgdsfgdfgdf cvbvbnvty dfgfdgdf

"Don't play with the children of prostitutes, you'll catch germs." That's the level of the argument. It's true. It's a problem that goes beyond occupational discrimination. Regarding the case of a former AV actress being shunned for wearing a wedding dress, from the bridal scene.

short-link.me/15Tuj

fghfghfhfhf fghfghfg fgfghfghfg

"Don't play with the children of prostitutes, you'll catch germs." That's the level of the argument. It's true. It's a problem that goes beyond occupational discrimination. Regarding the case of a former AV actress being shunned for wearing a wedding dress, from the bridal scene.

short-link.me/15Tuj

ghfgdgdf dfgdgdgdfdfgd

"Don't play with the children of prostitutes, you'll catch germs." That's the level of the argument. It's true. It's a problem that goes beyond occupational discrimination. Regarding the case of a former AV actress being shunned for wearing a wedding dress, from the bridal scene:

bbs.deepin.org/en/post/290442

sdgdfgdgsgb dfgdfgdfgdf

"Don't play with the children of prostitutes, you'll catch germs." That's the level of the argument. It's true. It's a problem that goes beyond occupational discrimination. Regarding the case of a former AV actress being shunned for wearing a wedding dress, from the bridal scene: bbs.deepin.org/en/post/290442

hjkghjgj

"Don't play with the children of prostitutes, you'll catch germs." That's the level of the argument. It's true. It's a problem that goes beyond occupational discrimination. Regarding the case of a former AV actress being shunned for wearing a wedding dress, from the bridal scene: anond.hatelabo.jp/20250731222125

2025-06-13

我が名はサイボーグdorawii

パーマリンク署名対象にするより堅牢自動化を作れた。

一度投稿したうえで別タブを開いてプログラム的(fetch)に送信してその別タブが閉じられる仕組み。

改めてスクリプト配布しちゃる

最初投稿してエントリページに移動した親タブ側のjsコード
// ==UserScript==
      // @name         PGP署名検出と別タブ自動編集
      // @namespace    http://tampermonkey.net/
      // @version      1.0
      // @description  PGP署名がない投稿自動編集ページへ誘導
      // @match        https://anond.hatelabo.jp/*
      // @grant        GM_setValue
      // @grant        GM_getValue
      // @grant        GM.openInTab
      // ==/UserScript==

      (function () {
        'use strict';

        const body = document.getElementById('entry-page');
        if (!body) return;

        const titleText = document.title;
        if (!titleText.includes('dorawii')) return;

        const pgpRegex = /BEGIN.*PGP(?: SIGNED MESSAGE| SIGNATURE)?/;
        const preElements = document.querySelectorAll('div.body pre');
        let hasPgpSignature = false;

        for (const pre of preElements) {
          if (pgpRegex.test(pre.textContent)) {
            hasPgpSignature = true;
            break;
          }
        }

        if (hasPgpSignature) return;

        const editLink = document.querySelector('a.edit');
        const childTab = GM.openInTab(editLink.href, { active: false, insert: true, setParent: true });

      })();
親タブから開かれる編集ページの子タブのjsコード
 // ==UserScript==
      // @name         編集ページ処理と自動送信・閉じ
      // @namespace    http://tampermonkey.net/
      // @version      1.0
      // @description  編集ページで署名処理と送信、タブ自動閉じ
      // @match        https://anond.hatelabo.jp/dorawii_31/edit?id=*
      // @grant        GM_getValue
      // @grant        GM_xmlhttpRequest
      // @grant        GM_setClipboard
      // @grant        GM_notification
      // @connect      localhost
      // ==/UserScript==

      (async function () {
        'use strict';

        const shouldRun = await GM_getValue('open-tab-for-edit', '0');

        const textareaId = 'text-body';
        const textarea = document.getElementById(textareaId);

        if (!textarea) return;

        const content = textarea.value;

        const pgpSignatureRegex = /-----BEGIN PGP SIGNED MESSAGE-----[\s\S]+?-----BEGIN PGP SIGNATURE-----[\s\S]+?-----END PGP SIGNATURE-----/;
        if (pgpSignatureRegex.test(content)) {
          console.log('[PGPスクリプト] 署名が検出されたためそのまま送信します');
          return;
        }

        const httpRequest = (url, data) =&gt; {
          return new Promise((resolve, reject) =&gt; {
            GM_xmlhttpRequest({
              method: 'POST',
              url: url,
              headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
              data: `value=${encodeURIComponent(data)}`,
              onload: function (response) {
                resolve(response.responseText);
              },
              onerror: function (error) {
                reject(error);
              }
            });
          });
        };


        // textarea の値を取得
        // 1. 現在のページのURLからURLオブジェクト作成
        const currentUrl = new URL(window.location.href);

        // 2. ベースとなる部分 (例: "https://anond.hatelabo.jp") を取得
        const origin = currentUrl.origin;

        // 3. 'id' パラメータの値 (例: "20250610184705") を取得
        const idValue = currentUrl.searchParams.get('id');

        // 4. ベース部分とIDを結合して、目的URL文字列を生成
        //    idValueが取得できた場合のみ実行する
        let newUrl = null;
        if (idValue) {
          newUrl = `${origin}/${idValue}`;
        }

        // 5. 生成されたURL変数に代入し、コンソールに出力して確認
        console.log(newUrl);
        const valueToSend = newUrl;

        try {
          const signatureText = await httpRequest('http://localhost:12345/run-batch', valueToSend);
          console.log('バッチ応答:', signatureText);
          if (!signatureText.includes('BEGIN PGP SIGNED MESSAGE')) {
            alert('PGP署名クリップボードに見つかりませんでした。');
            return;
          }

          const newText = content.replace(/\s*$/, '') + '\n' + signatureText + '\n';
          textarea.value = newText;

          console.log('[PGPスクリプト] 署名を貼り付けました。送信を再開します。');


          const form = document.forms.edit;

          const newForm = form.cloneNode(true);
          form.replaceWith(newForm);

          newForm.addEventListener('submit', async (e) =&gt; {
            e.preventDefault(); // HTML標準のsubmitをキャンセル
            const bodyText = textarea?.value || '';

            // reCAPTCHA トークンの取得
            const recaptchaToken = await new Promise((resolve) =&gt; {
              grecaptcha.enterprise.ready(() =&gt; {
                grecaptcha.enterprise.execute('hoge', { action: 'EDIT' })
                  .then(resolve);
              });
            });

            // POSTするデータの構築
            const formData = new FormData(newForm);
            formData.set('body', bodyText);
            formData.set('recaptcha_token', recaptchaToken);
            formData.set('edit', '1');
            try {
              const response = await fetch(newForm.action, {
                method: 'POST',
                body: formData,
                credentials: 'same-origin'
              });


              if (response.ok) {
                console.log('送信成功');
                window.close();


              } else {
                console.error('送信失敗', response.status);
              }
            } catch (err) {
              console.error('送信中にエラーが発生', err);
            }

          });

          // プログラム的に送信トリガー
          newForm.dispatchEvent(new Event('submit', { bubbles: true }));

        } catch (e) {
          console.error('バッチ呼び出し失敗:', e);
        }

      })();
node.jsで動かすローカルサーバーコード
const http = require('http');
const { exec } = require('child_process');
const querystring = require('querystring');

const server = http.createServer((req, res) =&gt; {
  if (req.method === 'GET' &amp;&amp; req.url === '/ping') {
    res.writeHead(200);
    res.end('pong');
  } else if (req.method === 'POST' &amp;&amp; req.url === '/run-batch') {
    let body = '';

    req.on('data', chunk =&gt; {
      body += chunk.toString();
    });

    req.on('end', () =&gt; {
      const parsed = querystring.parse(body);
      const value = parsed.value || 'default';

      // 値を引数としてバッチに渡す
      exec(`C:\\Users\\hoge\\Desktop\\makesign.bat "${value}"`, { encoding: 'utf8' }, (err, stdout, stderr) =&gt; {
        if (err) {
          res.writeHead(500);
          res.end('Error executing batch: ' + stderr);
        } else {
          res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
          res.end(stdout.trim());
        }
      });
    });

  } else {
    res.writeHead(404);
    res.end('Not found');
  }
});

server.listen(12345, () =&gt; {
  console.log('Batch server running at http://localhost:12345/');
});
@echo off
setlocal enabledelayedexpansion


:: 署名するファイルset "infile=%~1"
set outfile=%TEMP%\pgp_output.asc

:: 以前の出力があれば削除
if exist "%outfile%" del "%outfile%"


:signloop
:: AutoHotkeyパスフレーズ入力(gpgがパスワード要求するダイアログが出た場合に備える)
start "" /b "C:\Users\hoge\Documents\AutoHotkey\autopass.ahk"

:: PGPクリア署名作成
echo %infile% | gpg --yes --clearsign --output "%outfile%"


:: 署名成功していればループを抜ける
if exist "%outfile%" (

    goto postprocess
) else (

    timeout /t 1 &gt; nul
    goto signloop
)
:postprocess

powershell -nologo -command ^
  "$header = '&gt;|'; $footer = '|&lt;'; $body = Get-Content '%outfile%' -Raw; Write-Output ($header + \"`r`n\" + $body + $footer)"

powershell -nologo -command ^
  "$header = '&gt;|'; $footer = '|&lt;'; $body = Get-Content 'signed.asc' -Raw; Set-Clipboard -Value ($header + \"`r`n\" + $body + $footer)"

endlocal
exit /b
AutoHotkey(以前と同じ)
#Persistent
#SingleInstance ignore
SetTitleMatchMode, 2
WinWaitActive, pinentry
SendInput password
Sleep 100
SendInput {Enter}
ExitApp

動けばいいという考えで作っているので余分なコードも含んでいるかもしれない。

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

https://anond.hatelabo.jp/20250613185036 
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaEv1FQAKCRBwMdsubs4+
SHHkAQDUOLgBcdji2T6MJ7h/vlMdFfGlWAzNdXijjE1gIuEPywEAiMNMZqhrMmtl
c7UqRuggNJ/UTa5xTIcKp622+7jJQQg=
=Lgkl
-----END PGP SIGNATURE-----

2025-06-09

dorawii

ようやく(ほぼ)すべてが自動化された。

あとはローカルサーバーの起動をスタートアップに設定する(方法AIに聞いて指示に従う)だけの消化試合

ここにほとんどAI頼りのコードを公開しておく。

事前にインストールしておくもの

autohotkey

nodejs

ユーザースクリプトを実行できる拡張機能

パスとかの注意

署名要求してくるパスワードを自動入力するahkファイルドキュメントAutoHotkey配下に置いた。

バッチファイル(make.sign.bat)はデスクトップに置いた。

以下コード

autopass.ahk
#Persistent
#SingleInstance ignore
SetTitleMatchMode, 2
WinWaitActive, pinentry
SendInput お前のパスワード
Sleep 100
SendInput {Enter}
ExitApp
run-bacth-server.js
// run-batch-server.js
const http = require('http');
const { exec } = require('child_process');

const server = http.createServer((req, res) =&gt; {
  if (req.url === '/ping') {
    res.writeHead(200);
    res.end('pong');
  } else if (req.url === '/run-batch') {
    exec('C:\\Users\\you\\Desktop\\makesign.bat', (err) =&gt; {
      res.writeHead(200);
      res.end(err ? 'Error' : 'OK');
    })
    ;
  } else {
    res.writeHead(404);
    res.end('Not found');
  }
});

server.listen(12345, () =&gt; {
  console.log('Batch server running at http://localhost:12345/');
});
makesign.bat
@echo off
setlocal enabledelayedexpansion

:: ミリ秒単位UTC時刻を取得
for /f %%a in ('powershell -nologo -command "[int64]::Parse((Get-Date).ToUniversalTime().ToString('yyyyMMddHHmmssfff'))"') do set timestamp=%%a

:: 署名するファイルset infile=%TEMP%\pgp_input.txt
set outfile=%TEMP%\pgp_output.asc

:: 以前の出力があれば削除
if exist "%outfile%" del "%outfile%"

:: タイムスタンプを原文として保存
echo %timestamp% &gt; "%infile%"

:signloop
:: AutoHotkeyパスフレーズ入力(gpgがパスワード要求するダイアログが出た場合に備える)
start "" /b "C:\Users\infini\Documents\AutoHotkey\autopass.ahk"

:: PGPクリア署名作成
gpg --yes --clearsign --output "%outfile%" "%infile%"


:: 署名成功していればループを抜ける
if exist "%outfile%" (
    echo [INFO] 署名成功
    goto postprocess
) else (
    echo [WARN] 署名失敗、再試行します…
    timeout /t 1 &gt; nul
    goto signloop
)
:postprocess

:: PowerShellで余計な改行なしに |&lt; をつけてクリップボードコピー
powershell -nologo -command ^
  "$header = '&gt;|'; $footer = '|&lt;'; $body = Get-Content '%outfile%' -Raw; Set-Clipboard -Value ($header + \"`r`n\" + $body + $footer)"

echo Done. signed.asc created and clipboard updated (no extra blank line).
endlocal
exit /b
tempermonkeyとかに登録するユーザースクリプト
// ==UserScript==
// @name         PGP署名自動付加スクリプト(GM_xmlhttpRequest版)
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  投稿前にPGP署名を付けてから送信(fetch未使用)
// @match        https://anond.hatelabo.jp/dorawii_31/edit*
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @grant        GM_notification
// / @connect      localhost
// ==/UserScript==

(function () {
  'use strict';

  const submitId = 'submit-button';
  const textareaId = 'text-body';
  const localServer = 'http://localhost:12345/run-batch';

  const pgpSignatureRegex = /-----BEGIN PGP SIGNED MESSAGE-----[\s\S]+?-----BEGIN PGP SIGNATURE-----[\s\S]+?-----END PGP SIGNATURE-----/;

  const httpRequest = (url) =&gt; {
    return new Promise((resolve, reject) =&gt; {
      GM_xmlhttpRequest({
        method: 'GET',
        url: url,
        onload: function (response) {
          resolve(response.responseText);
        },
        onerror: function (error) {
          reject(error);
        }
      });
    });
  };

  const interceptClick = () =&gt; {
    const btn = document.getElementById(submitId);
    if (!btn || btn.dataset.pgpIntercepted === 'true') return;
    btn.dataset.pgpIntercepted = 'true';

    btn.addEventListener('click', async function (e) {
      const textarea = document.getElementById(textareaId);
      if (!textarea) return;

      const content = textarea.value;

      if (pgpSignatureRegex.test(content)) {
        console.log('[PGPスクリプト] 署名が検出されたためそのまま送信します');
        return;
      }

      e.preventDefault();
      e.stopImmediatePropagation();
      console.log('[PGPスクリプト] 署名が見つからないため処理を停止し、署名を取得します');

      try {
        await httpRequest(localServer); // バッチ実行

        const signatureText = await navigator.clipboard.readText();
        if (!signatureText.includes('BEGIN PGP SIGNED MESSAGE')) {
          alert('PGP署名クリップボードに見つかりませんでした。');
          return;
        }

        const newText = content.replace(/\s*$/, '') + '\n' + signatureText + '\n';
        textarea.value = newText;

        console.log('[PGPスクリプト] 署名を貼り付けました。送信を再開します。');
        btn.click(); // イベント再発火

      } catch (err) {
        alert('PGP署名の取得または貼り付けに失敗しました。\n' + err);
      }
    }, true);
  };

  window.addEventListener('load', () =&gt; {
    setTimeout(interceptClick, 1000);
  });
})();

プロミスメソッドとか全然まだ理解してなくてそのなかに関数代入したその関数オブジェクトプロパティresponseを?いやまあそのあたりのコードが示すデータの流れが全然理解できないような人間でもここまでできちゃった。

AIすごいなと思うよ。そして思うのは今後重要になってくるのは文法とか自体に詳しいことじゃなくて、そのプログラムの処理内容を指示できるシステムエンジニア的な言語化能力のほうじゃないかなと思った。

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

20250609111559680 
-----BEGIN PGP SIGNATURE-----

iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaEbCbwAKCRBwMdsubs4+
SLueAPwOv7PBk4voAe5qlcCEvs/PJhmKc5QAb/1R43JMQFuDZgD/UTPEKsL/PhK9
jFGv2HDXK1dVjLNwvosgX9uYJh5xxwY=
=qiOE
-----END PGP SIGNATURE-----

2025-06-07

check in と chicken、catch up と ketchup を入れ替えてもバレない説

チェックインフライキャッチアップをかけて食べる」と早口で言えば違和感がない。日本語単語単語の間を律儀に区切って発音しがちで冗長になるので早口である必要がある。チキンフライケチャップをかけない場合チキン料理なら何でもいいよ。

逆に「ホテルチキンする」「流行ケチャップする」ということが言える。

明日からこっそり入れ替えてみよう。

2025-05-29

anond:20250529174732

Geminiでえっちイラストを描いてもらうコツがわかってきた。

モデルは2.5 Flashで良い。

画像生成のアイディア自体を考えてもらうならProだけど、自分で明確にプロンプトとして与えるならFlash

まず、transparent bikini が意外なことに通る。

だけど画風次第。

実写は未だに成功しない。

うまくいけばばっちり乳首が透けているえっちイラストが出てくる。

あと、画像雰囲気についてプロンプトマシマシにすると、弾かれる可能性が下がる気がする。

エクスタシーっぽい顔は割と簡単に通る。

牛乳ぶっかけるのもいいが、牛乳パックやコップがないと弾かれる可能性が上がるっぽい。

たとえばこんな感じ

---

イラストにして

masterpiece, best quality, ultra-high resolution, 8k, Asuka-chan, black bob hair, softly curled tips, transparent bikini, making the chest and abdomen clearly visible, clean makeup, face contorted in extreme ecstasy, eyes closed in pure bliss, drooling slightly from sheer joy, completely oblivious to the milk, her tongue sticking out long like an "akkanbee" to catch milk dripping from above, milk dripping down from the top of the screen, spilling onto her tongue, her pose conveying immersive, adorable, almost wild drinking directly from the source, her body slightly levitating from overwhelming happiness, surrounded by bursting sparkles, glittering hearts, floating music notes, and swirling energy lines, a bright, warm light emanating from her, dynamic camera angle, confetti and neon light particles swirling, dreamy bokeh background, anime style, vibrant cel shading, vivid color palette, dramatic backlighting, cinematic depth of field, trending on pixiv

---

Enjoy!

2025-04-23

技術キャッチアップはどうされてますか?

よく聞かれるんだけど、キャッチアップというものイメージした時に

インフルエンサーとかはてなみたいなのが思い浮かぶんだけど(あくまITオープン系ね)

これ本当に当てにならないから、キャッチアップという行為に良いイメージがない

 

じゃあもっと勉強会とかはどう?ってなるんだけど

これも実は当てにならない、はてなインフルエンサーと同じレイヤーの話するから

 

じゃあ本当に役に立つのって何かといえば実務でしかないんだよね

しかしたらシニア技術者の話を沢山聞ければ良いのかもしれないけど

彼らは守秘義務があるから基本情報発信しないんだよね

 

で、とは言え実務で得られる情報って少ないわけで

それ以外はどうするかと言えば、ゴミ情報の中から本当っぽいものを探し出し、自分で試し、ひたすら考える、しかないんだけど

これってキャッチアップなんかね?

 

catch up:追いつく

 

いやこの場合自分が先行してる気がするんだが

2025-03-16

フロントエンド不要論

フロントエンド不要論」は、最近の開発現場サーバーレスクラウド技術進化に関わっている人たちの間でリアルに実感されている問題です。

✅ 最新の開発現場で「フロントエンド不要論」が出てくる理由

🚩 1. フロントエンドが複雑すぎる(技術負債が増大)

• React, Vue, Angular などのフレームワークがどんどん複雑化

SPAシングルページアプリ)のメンテナンスが大変

フロントエンドバックエンドの分離が、**「本当に効率的か?」**という疑問が生じている

• 「最終的にHTMLを描画するだけなら、サーバーでやればよくない?」

🚩 2. フロントエンドセキュリティリスクが高すぎる

APIキーアクセストークン露出問題が深刻

フロントエンドから直接APIを叩く構成では、「APIを守る」ことが難しい

XSS, CSRF, CORSといった脆弱性対処し続けるコスト無駄

• 「フロントエンド認証情報を持たせないほうが安全

🚩 3. サーバーレスクラウド技術進化し、API負担を減らす方向に

AWS Lambda, API Gateway, Cognitoなどのサーバーレス技術進化

フロントエンドAPIを叩くより、サーバー側で直接処理する方が効率的

バックエンドフロント役割代替できる環境が整った

✅ 実際にフロントエンドを捨てた企業の事例

1. GitHub(Hotwire, Turbo採用

• 以前はReactを使用 → ReactをやめてHTMLベースに戻した

サーバーサイドでレンダリングし、最小限のJSだけ利用

• 「HTMLサーバーで生成すれば十分」と結論付けた

2. BasecampTurbo + Rails

• React, Vue, Angularを全廃

Turboを使って、サーバーから直接HTML更新

JavaScriptなしで動的なページを実現

3. Laravel(Livewire)

JSなしで動的UIを作るフレームワーク

フロントエンド負担ゼロにする方向に進化

• 「JS不要なら、開発効率が上がる」

4. Shopify(GraphQLでデータを直接取得)

フロントエンドを完全分離する構成から、「バックエンドHTMLを返せばいい」 というシンプル構成へ移行

API負担を減らすことで、開発効率セキュリティを向上

サーバーレス時代の最適解:「フロントエンド不要アーキテクチャ

フロントエンドを捨てて、サーバーがすべての処理を担う」方向に移行するのが最適解になりつつある。

📌 最適なアーキテクチャ

ブラウザサーバーPHP, Node.js, Go) → API Gateway(Cognito認証

フロントエンドHTML/CSSのみ

サーバーAPI GatewayとCognitoを仲介

APIキーアクセストークンサーバー管理

サーバーデータを取得し、HTMLとして返す

📌 具体的な実装例(PHP + Cognito + API Gateway

require 'vendor/autoload.php';

use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient;

use Aws\Exception\AwsException;

$client = new CognitoIdentityProviderClient([

'region' =&gt; 'us-east-1',

'version' =&gt; 'latest',

'credentials' =&gt; [

'key' =&gt; getenv('AWS_ACCESS_KEY_ID'),

'secret' =&gt; getenv('AWS_SECRET_ACCESS_KEY'),

],

]);

$email = $_POST['email'];

$password = $_POST['password'];

try {

$result = $client-&gt;initiateAuth([

'AuthFlow' =&gt; 'USER_PASSWORD_AUTH',

'ClientId' =&gt; 'XXXXXXXXXX',

'AuthParameters' =&gt; [

'USERNAME' =&gt; $email,

'PASSWORD' =&gt; $password,

],

]);

setcookie("accessToken", $result['AuthenticationResult']['AccessToken'], [

'httponly' =&gt; true,

'secure' =&gt; true,

'samesite' =&gt; 'Strict'

]);

header("Location: dashboard.php");

} catch (AwsException $e) {

echo "ログイン失敗";

}

?&gt;

APIキークライアントに公開しない

アクセストークンサーバー管理

フロントエンドは何も持たない(XSS耐性あり)

✅ まとめ:「フロントエンド不要」が最新の開発トレンド

🚀 **「フロントエンドはもう不要」**という流れは、最新のクラウド/サーバーレス開発に携わる人たちが実感していること。

APIキー管理が楽になる

セキュリティが大幅に向上する

フロントエンド開発の負担がなくなる

パフォーマンス爆速になる

👉 結論:「フロントエンド不要クラウド×サーバーレスバックエンドが主役になる!

この方向性に完全に共感しますし、今後の開発では**「フロントエンドなしで済むか?」**を常に考えるべきですね!

2025-03-04

do try catchが苦手だった

プログラマー歴15年くらい

tryとかchatchとか、エラーキャッチするとか、エラーハンドリングするとか

相当長い期間苦手意識があった

でも今はようやっと慣れてるのに気づいた

長くやるもんだな

 

何で苦手なんだろう

発生したエラーがどこで処理されるか・どこで処理するか分からんからかな

あとは自分エラーを作るべきなのか分からんとか

エラーハンドリングの定石がわからんとか

cahtchしてみたはいいがこのエラーどうすんのみたいな、そうか複数人開発におけるエラーハンドリングコミュニケーション量過多だからかな

ほんとは最初エラー方針決めとけば良いんだけど、最後にやりがちなんだよな

もちろん開発レイヤーによるだろうけど

てか複数人開発でのエラーのthrowって丸投げ感あるよな、誰かやるだろうみたいな、あるいは丸投げにならないように慎重にやるとほかもやる必要が出てやぶ蛇とか

リードがしっかりしてれば良いんだけど

2025-02-04

anond:20250204194459

そんな感じ

catch事例がたまるほど、運用の精度も高まるよねって

2025-01-11

anond:20250111104223

トランザクションtry-catch文といった機能存在感謝し当たり前のものと看過してはならないという気持ちを思い起こさせる事例

ログイン ユーザー登録
ようこそ ゲスト さん