CINXE.COM

nikkie-ftnextの日記

<!DOCTYPE html> <html lang="ja" data-admin-domain="//blog.hatena.ne.jp" data-admin-origin="https://blog.hatena.ne.jp" data-author="nikkie-ftnext" data-avail-langs="ja en" data-blog="nikkie-ftnext.hatenablog.com" data-blog-comments-top-is-new="1" data-blog-host="nikkie-ftnext.hatenablog.com" data-blog-is-public="1" data-blog-name="nikkie-ftnextの日記" data-blog-owner="nikkie-ftnext" data-blog-show-ads="1" data-blog-show-sleeping-ads="" data-blog-uri="https://nikkie-ftnext.hatenablog.com/" data-blog-uuid="8599973812319890363" data-blogs-uri-base="https://nikkie-ftnext.hatenablog.com" data-brand="hatenablog" data-data-layer="{&quot;hatenablog&quot;:{&quot;admin&quot;:{},&quot;analytics&quot;:{&quot;brand_property_id&quot;:&quot;&quot;,&quot;measurement_id&quot;:&quot;&quot;,&quot;non_sampling_property_id&quot;:&quot;&quot;,&quot;property_id&quot;:&quot;UA-134137157-1&quot;,&quot;separated_property_id&quot;:&quot;UA-29716941-22&quot;},&quot;blog&quot;:{&quot;blog_id&quot;:&quot;8599973812319890363&quot;,&quot;content_seems_japanese&quot;:&quot;true&quot;,&quot;disable_ads&quot;:&quot;&quot;,&quot;enable_ads&quot;:&quot;true&quot;,&quot;enable_keyword_link&quot;:&quot;true&quot;,&quot;entry_show_footer_related_entries&quot;:&quot;true&quot;,&quot;force_pc_view&quot;:&quot;false&quot;,&quot;is_public&quot;:&quot;true&quot;,&quot;is_responsive_view&quot;:&quot;false&quot;,&quot;is_sleeping&quot;:&quot;false&quot;,&quot;lang&quot;:&quot;ja&quot;,&quot;name&quot;:&quot;nikkie-ftnext\u306e\u65e5\u8a18&quot;,&quot;owner_name&quot;:&quot;nikkie-ftnext&quot;,&quot;uri&quot;:&quot;https://nikkie-ftnext.hatenablog.com/&quot;},&quot;brand&quot;:&quot;hatenablog&quot;,&quot;page_id&quot;:&quot;index&quot;,&quot;permalink_entry&quot;:null,&quot;pro&quot;:&quot;free&quot;,&quot;router_type&quot;:&quot;blogs&quot;}}" data-device="pc" data-dont-recommend-pro="false" data-global-domain="https://hatena.blog" data-globalheader-color="b" data-globalheader-type="pc" data-has-touch-view="1" data-help-url="https://help.hatenablog.com" data-page="index" data-parts-domain="https://hatenablog-parts.com" data-plus-available="" data-pro="false" data-router-type="blogs" data-sentry-dsn="https://03a33e4781a24cf2885099fed222b56d@sentry.io/1195218" data-sentry-environment="production" data-sentry-sample-rate="0.1" data-static-domain="https://cdn.blog.st-hatena.com" data-version="1ca111bc9f0112690b12e1842a1ce8" data-initial-state="{}" > <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#"> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="robots" content="max-image-preview:large" /> <meta charset="utf-8"/> <meta http-equiv="X-UA-Compatible" content="IE=7; IE=9; IE=10; IE=11" /> <title>nikkie-ftnextの日記</title> <link rel="canonical" href="https://nikkie-ftnext.hatenablog.com/"/> <meta itemprop="name" content="nikkie-ftnextの日記"/> <meta itemprop="image" content="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png"/> <meta property="og:title" content="nikkie-ftnextの日記"/> <meta property="og:type" content="blog"/> <meta property="og:url" content="https://nikkie-ftnext.hatenablog.com/"/> <meta property="og:image" content="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png"/> <meta property="og:image:alt" content="nikkie-ftnextの日記"/> <meta property="og:description" content="イベントレポートや読書メモを発信" /> <meta property="og:site_name" content="nikkie-ftnextの日記"/> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:image" content="https://cdn.blog.st-hatena.com/images/theme/og-image-1500.png" /> <meta name="twitter:title" content="nikkie-ftnextの日記" /> <meta name="twitter:description" content="イベントレポートや読書メモを発信" /> <meta name="twitter:app:name:iphone" content="はてなブログアプリ" /> <meta name="twitter:app:id:iphone" content="583299321" /> <meta name="twitter:app:url:iphone" content="hatenablog:///open?uri=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2F" /> <script id="embed-gtm-data-layer-loader" data-data-layer-page-specific="" > (function() { function loadDataLayer(elem, attrName) { if (!elem) { return {}; } var json = elem.getAttribute(attrName); if (!json) { return {}; } return JSON.parse(json); } var globalVariables = loadDataLayer( document.documentElement, 'data-data-layer' ); var pageSpecificVariables = loadDataLayer( document.getElementById('embed-gtm-data-layer-loader'), 'data-data-layer-page-specific' ); var variables = [globalVariables, pageSpecificVariables]; if (!window.dataLayer) { window.dataLayer = []; } for (var i = 0; i < variables.length; i++) { window.dataLayer.push(variables[i]); } })(); </script> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-P4CXTW');</script> <!-- End Google Tag Manager --> <link rel="shortcut icon" href="https://nikkie-ftnext.hatenablog.com/icon/favicon"> <link rel="apple-touch-icon" href="https://nikkie-ftnext.hatenablog.com/icon/touch"> <link rel="icon" sizes="192x192" href="https://nikkie-ftnext.hatenablog.com/icon/link"> <link rel="alternate" type="application/atom+xml" title="Atom" href="https://nikkie-ftnext.hatenablog.com/feed"/> <link rel="alternate" type="application/rss+xml" title="RSS2.0" href="https://nikkie-ftnext.hatenablog.com/rss"/> <link rel="author" href="http://www.hatena.ne.jp/nikkie-ftnext/"> <link rel="stylesheet" type="text/css" href="https://cdn.blog.st-hatena.com/css/blog.css?version=1ca111bc9f0112690b12e1842a1ce8"/> <link rel="stylesheet" type="text/css" href="https://usercss.blog.st-hatena.com/blog_style/8599973812319890363/60f7ca22d809bff304f0be63f3fd1c80cc38ed56"/> <script> </script> <style> div#google_afc_user, div.google-afc-user-container, div.google_afc_image, div.google_afc_blocklink { display: block !important; } </style> <script src="https://cdn.pool.st-hatena.com/valve/valve.js" async></script> <script id="test-valve-definition"> var valve = window.valve || []; valve.push(function(v) { v.config({ service: 'blog', content: { result: 'adtrust', documentIds: ["blog:entry:6802418398333212789","blog:entry:6802418398333175149","blog:entry:6802418398332943620","blog:entry:6802418398332660287","blog:entry:6802418398332416182","blog:entry:6802418398332115117","blog:entry:6802418398331855418"] } }); v.defineDFPSlot({"lazy":1,"sizes":{"mappings":[[[320,568],[[336,280],[300,250],"fluid"]],[[0,0],[[300,250]]]]},"slotId":"ad-in-entry","unit":"/4374287/blog_pc_entry_sleep_in-article"}); v.defineDFPSlot({"lazy":"","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_0","unit":"/4374287/blog_user"}); v.defineDFPSlot({"lazy":"","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_1","unit":"/4374287/blog_user_2nd"}); v.defineDFPSlot({"lazy":"","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_2","unit":"/4374287/blog_user_2nd"}); v.defineDFPSlot({"lazy":"1","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_3","unit":"/4374287/blog_user_2nd"}); v.defineDFPSlot({"lazy":"1","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_4","unit":"/4374287/blog_user_2nd"}); v.defineDFPSlot({"lazy":"1","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_5","unit":"/4374287/blog_user_2nd"}); v.defineDFPSlot({"lazy":"1","sizes":[[300,250],[336,280],[468,60],"fluid"],"slotId":"google_afc_user_container_6","unit":"/4374287/blog_user_2nd"}); v.sealDFPSlots(); }); </script> <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"nikkie-ftnextの日記","url":"https://nikkie-ftnext.hatenablog.com/"}</script> <script type="module"> import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; mermaid.initialize({ startOnLoad: true }); </script> </head> <body class="page-index globalheader-ng-enabled"> <div id="globalheader-container" data-brand="hatenablog" > <iframe id="globalheader" height="37" frameborder="0" allowTransparency="true"></iframe> </div> <nav class=" blog-controlls "> <div class="blog-controlls-blog-icon"> <a href="https://nikkie-ftnext.hatenablog.com/"> <img src="https://cdn.blog.st-hatena.com/images/admin/blog-icon-noimage.png" alt="nikkie-ftnextの日記"/> </a> </div> <div class="blog-controlls-title"> <a href="https://nikkie-ftnext.hatenablog.com/">nikkie-ftnextの日記</a> </div> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_campaign=subscribe_blog&amp;utm_medium=button&amp;utm_source=blogs_topright_button" class="blog-controlls-subscribe-btn test-blog-header-controlls-subscribe"> 読者になる </a> </nav> <div id="container"> <div id="container-inner"> <header id="blog-title" data-brand="hatenablog"> <div id="blog-title-inner" > <div id="blog-title-content"> <h1 id="title"><a href="https://nikkie-ftnext.hatenablog.com/">nikkie-ftnextの日記</a></h1> <h2 id="blog-description">イベントレポートや読書メモを発信</h2> </div> </div> </header> <div id="content" class="hfeed" > <div id="content-inner"> <div id="wrapper"> <div id="main"> <div id="main-inner"> <!-- google_ad_section_start --> <!-- rakuten_ad_target_begin --> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2400 words-200 mode-markdown entry-odd" id="entry-6802418398333212789" data-keyword-campaign="" data-uuid="6802418398333212789" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/03/03" rel="nofollow"> <time datetime="2025-03-03T12:32:56Z" title="2025-03-03T12:32:56Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">03</span><span class="hyphen">-</span><span class="date-day">03</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02" class="entry-title-link bookmark">nikkie v2025.02 リリースのお知らせ</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/%E3%81%98%E3%81%B6%E3%82%93%20Release%20Notes" class="entry-category-link category-じぶん-Release-Notes">じぶん Release Notes</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p><a href="https://x.com/imasml_theater/status/1896372453414207780">ひなたまつり</a>(かわいい) nikkieです。</p> <p>2月のふりかえり記事です。<br/> 1月はこちら</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fnikkie-release-note-2025-01" title="nikkie v2025.01 リリースのお知らせ - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#1日1エントリ継続中">1日1エントリ継続中</a></li> <li><a href="#技術まわり">技術まわり</a><ul> <li><a href="#カンファレンス2つで登壇">カンファレンス2つで登壇</a></li> <li><a href="#LLM">LLM</a></li> <li><a href="#タスクランナーを教えていただきありがとうございました">タスクランナーを教えていただき、ありがとうございました</a></li> <li><a href="#OSS">OSS</a></li> </ul> </li> <li><a href="#サブカルまわり">サブカルまわり</a><ul> <li><a href="#メダリスト">メダリスト</a></li> <li><a href="#STARDOM-ROAD-THEATER">STARDOM ROAD THEATER</a></li> </ul> </li> <li><a href="#終わりに">終わりに</a></li> </ul> <h3 id="1日1エントリ継続中">1日1エントリ継続中</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Farchive%2F2025%2F02" title="2025-02-01から1ヶ月間の記事一覧 - nikkie-ftnextの日記" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p><strong>830日</strong>を超えました。<br/> 読んでいただきありがとうございます!</p> <h3 id="技術まわり">技術まわり</h3> <h4 id="カンファレンス2つで登壇">カンファレンス2つで登壇</h4> <ul> <li>2/8 PyCon mini Shizuoka 2024 continue</li> <li>2/22 DjangoCongress JP 2025</li> </ul> <p>それぞれ、ライブラリ開発者向けのロギングの話と、現場で使っているFastAPIの話でした。<br/> どちらも登壇報告やイベントレポートを書く余地を残しています(まだ終わっていないってことだ!)</p> <p><strong>pyconshizuで出会ったPyodide</strong>が、2/28の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BF%B7%BD%C9%B8%E6%B1%F1">新宿御苑</a>.wasmでのLTにつながりました!<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup><br/> Pyodideは新しい遊び場で、とても楽しいです</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fflake8-kotoha-playground-alpha-version-by-pyodide-" title="#新宿御苑dev でのPyodideネタLTを記事化:ブラウザで動く、flake8-kotohaのplaygroundを作りました - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <h4 id="LLM">LLM</h4> <p>2月はどんどん新しいモデルが登場しましたね。<br/> お財布のことはいったんおいといて、可能な限り触るっ!!<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup></p> <ul> <li>ChatGPT deep research</li> <li>NotebookLM</li> <li>Grok 3</li> <li>Devin</li> <li>Operator</li> </ul> <p>deep researchに翻弄されるnikkie氏(みんな、<strong>o3</strong>だぞ!)</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">みなさんDeep Researchどうやってるんです?<br>o1 pro + Deep Researchで「リサーチ完了後、レポートを提示しますので、少々お待ちください。」って言われてるんだけど、3時間くらい放置されてる。モデルの選択間違ってるのかな<br><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>ン並べてるだけでウィノグラード先生のいうコミットメントないもんな <a href="https://t.co/VlZuPPvrLl">https://t.co/VlZuPPvrLl</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1886755733552947609?ref_src=twsrc%5Etfw">2025年2月4日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p><strong>ChatGPT deep researchは劇的に私の世界を変えて</strong>います。<br/> Open sourceな実装も提案されていて、あの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D6%A5%E9%A5%A6%A5%B8%A5%F3%A5%B0">ブラウジング</a>がどう実現されているか知りたく覗いたり(<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C8%A1%BC%A5%AF">トーク</a>ンを並べるしかできないLLMが、<strong>コンピュータを操作する</strong>んですよ!)</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fhuggingface-smolagents-examples-with-gemini-2.0-flash" title="Hugging Faceによるエージェントライブラリ smolagents をGemini 2.0 Flashで動かす - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>NotebookLM、便利〜(常習者に)</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fgoogle-notebooklm-is-awesome-for-me-reading-pep" title="雑記:NotebookLMを使うことで、硬めの一次情報ドキュメントに挑むの、すっごく楽になりそう - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>Grok 3で<a class="keyword" href="https://d.hatena.ne.jp/keyword/Twitter">Twitter</a>の話題を掴むのが簡単に</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">東北大入試<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A5%E3%A5%CB%A5%DE%A5%B9">シャニマス</a>出題の反応を聞いてみました<a href="https://t.co/mnBdTxtCnh">https://t.co/mnBdTxtCnh</a> <br>東北大の赤本に、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B7%A5%E3%A5%CB%A5%DE%A5%B9">シャニマス</a>載るってことか</p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1894370288034537914?ref_src=twsrc%5Etfw">2025年2月25日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>Devinは私の"分身"として使えるようになりたいな〜</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Ftry-devin-case-sphinx-new-tab-link-remove-rel-noopener" title="Devinお試し&amp;観察記:sphinx-new-tab-linkへの小さなプルリクエストを出してもらいました - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <h4 id="タスクランナーを教えていただきありがとうございました">タ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%E9%A5%F3">スクラン</a>ナーを教えていただき、ありがとうございました</h4> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">📣uv使ってるみんな〜!!<br>タ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%E9%A5%F3">スクラン</a>ナー機能、uvにまだないと思うんですが、どう実現してますか?<br>知りたい(知りたい)<br>教えて(教えて)<br>私は<a class="keyword" href="https://d.hatena.ne.jp/keyword/Makefile">Makefile</a><br><br>uvで管理する<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>プロジェクトにタ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%E9%A5%F3">スクラン</a>ナーが欲しいのですが、みなさんどうしてますか? - nikkie-ftnextの日記 <a href="https://t.co/wAtwAfooZ3">https://t.co/wAtwAfooZ3</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1886622165019345108?ref_src=twsrc%5Etfw">2025年2月4日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fawesome-uv-task-runners-thanks-replies-202502" title="皆さんに教えていただいた、uvで管理するPythonプロジェクトで使っているタスクランナーたち - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>(ChatGPT deep research出現と大体同じタイミング。これからは全部deep researchになっちゃうかもな〜)</p> <h4 id="OSS"><a class="keyword" href="https://d.hatena.ne.jp/keyword/OSS">OSS</a></h4> <p>2月が2025年の初登壇。<br/> スライドを作り始める前に、自分用に<a class="keyword" href="https://d.hatena.ne.jp/keyword/sphinx">sphinx</a>-revealjsの拡張を少し整えました</p> <ul> <li><a href="https://github.com/ftnext/sphinx-revealjs-copycode/releases/tag/v0.2.0">https://github.com/ftnext/sphinx-revealjs-copycode/releases/tag/v0.2.0</a></li> <li><a href="https://github.com/ftnext/sphinx-revealjs-ext-codeblock/releases/tag/0.1.0">https://github.com/ftnext/sphinx-revealjs-ext-codeblock/releases/tag/0.1.0</a> (新作)</li> </ul> <p>静岡での登壇と合わせて、<strong><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>使いをロギングで幸せに</strong>しようと思い立ちました(落ち着いたから拡張していきたい!)</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Frelease-happy-python-logging-v0.0.1-easy-library-logger" title="ライブラリ開発者に贈る from happy_python_logging import getLoggerForLibrary (バージョン0.0.1公開!) - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>SpeechRecognitionメンテナはお休みの月でした</p> <h3 id="サブカルまわり"><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B5%A5%D6%A5%AB%A5%EB">サブカル</a>まわり</h3> <h4 id="メダリスト">メダリスト</h4> <p>狂わされております</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/%E3%83%A1%E3%83%80%E3%83%AA%E3%82%B9%E3%83%88?src=hash&amp;ref_src=twsrc%5Etfw">#メダリスト</a> 俺は速い!(世界最速)<br>リアタイしちゃう</p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1885727588490068066?ref_src=twsrc%5Etfw">2025年2月1日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/%C2%E7%BF%DC">大須</a>のリンクにも行けました!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fnagoya-short-tour-2025-february-tabimas-medalist-piyorin" title="旅マス!メダリスト!でかぴよりん! 名古屋弾丸旅行記(2025年2月) - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <h4 id="STARDOM-ROAD-THEATER">STARDOM ROAD THEATER</h4> <p>してやられました。<br/> ミリシタ運営、最高!</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">はいいいいいいいいい!?!?(悲鳴。そうくるのか〜)<a href="https://twitter.com/hashtag/%E3%83%9F%E3%83%AA%E3%82%B7%E3%82%BF?src=hash&amp;ref_src=twsrc%5Etfw">#ミリシタ</a> <a href="https://t.co/Xa2E6m6AnC">https://t.co/Xa2E6m6AnC</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1890020183693255034?ref_src=twsrc%5Etfw">2025年2月13日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <h3 id="終わりに">終わりに</h3> <p>nikkie v2025.02がリリースされました。</p> <ul> <li>2つのカンファレンスで登壇。発表を聞いて、新たな技術との出会い!</li> <li>新たなLLMの登場が止まらない!全部触ればええやろ。💸</li> <li>引き続きメダリスト、また<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A2%A5%A4%A5%DE%A5%B9">アイマス</a>(ミリオンライブ!)に楽しませてもらってます</li> </ul> <p>そして、次のバージョン(v2025.03)に向けての旅が続くのです!</p> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> djangocongressでも<a class="keyword" href="https://d.hatena.ne.jp/keyword/Django">Django</a> Ninjaと出会いました。にんにん!<a href="#fnref:1" rev="footnote">&#8617;</a></li> <li id="fn:2"> <blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">インターネットのそーだいさん「全部やればええやろ。」<br><br>現場のそーだいさん「全部やればええやろ。」</p>&mdash; そーだい@初代ALF (@soudai1025) <a href="https://twitter.com/soudai1025/status/1842232684430643679?ref_src=twsrc%5Etfw">2024年10月4日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <a href="#fnref:2" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/%E3%81%98%E3%81%B6%E3%82%93%20Release%20Notes" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">じぶん Release Notes</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">エンジニア</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/%E3%81%B5%E3%82%8A%E3%81%8B%E3%81%88%E3%82%8A" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">ふりかえり</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02"><time data-relative datetime="2025-03-03T12:32:56Z" title="2025-03-03T12:32:56Z" class="updated">2025-03-03 21:32</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_campaign=subscribe_blog&amp;utm_medium=button&amp;utm_source=blogs_entry_footer"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02" data-hatena-star-title="nikkie v2025.02 リリースのお知らせ" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=%E3%81%98%E3%81%B6%E3%82%93+Release+Notes&amp;hashtags=%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2&amp;hashtags=%E3%81%B5%E3%82%8A%E3%81%8B%E3%81%88%E3%82%8A&amp;text=nikkie+v2025.02+%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%AE%E3%81%8A%E7%9F%A5%E3%82%89%E3%81%9B+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fnikkie-release-note-2025-02" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <div id="google_afc_user_container_0" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-4400 words-400 mode-markdown entry-even" id="entry-6802418398333175149" data-keyword-campaign="" data-uuid="6802418398333175149" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/03/02" rel="nofollow"> <time datetime="2025-03-02T13:17:56Z" title="2025-03-02T13:17:56Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">03</span><span class="hyphen">-</span><span class="date-day">02</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt" class="entry-title-link bookmark">llms.txtを作るツールとして、Firecrawlをセルフホストで試す</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/LLM" class="entry-category-link category-LLM">LLM</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p><em><a href="https://x.com/miiiiiina_cat/status/1896001705457959133">お目目パッチン</a></em>、nikkieです。</p> <p>llms.txtなるものを知り、作り方に興味を持ったところ、Firecrawlがサポートしているらしいと知り、試しました。</p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#llmstxt">llms.txt</a></li> <li><a href="#llmstxtの作り方">llms.txtの作り方</a></li> <li><a href="#セルフホストしたFirecrawlでllmstxtを作る">セルフホストしたFirecrawlでllms.txtを作る</a></li> <li><a href="#終わりに">終わりに</a></li> <li><a href="#おまけGeminiなら無料で">おまけ:Geminiなら無料で?</a></li> </ul> <h3 id="llmstxt">llms.txt</h3> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a class="keyword" href="https://d.hatena.ne.jp/keyword/SEO">SEO</a>はもう終わり、時代はLLMOですよ <a href="https://t.co/xFIjVZp9GT">pic.twitter.com/xFIjVZp9GT</a></p>&mdash; ところてん (@tokoroten) <a href="https://twitter.com/tokoroten/status/1895501801727885504?ref_src=twsrc%5Etfw">2025年2月28日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <blockquote><p>ウェブサイトに設置するLLMエージェントに向けた参考文献</p></blockquote> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fllmstxt.org%2F" title="The /llms.txt file – llms-txt" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>2024年9月提案</p> <blockquote><p>We propose adding a /llms.txt <a class="keyword" href="https://d.hatena.ne.jp/keyword/markdown">markdown</a> file to websites to provide LLM-friendly content.</p></blockquote> <p>私が知ったきっかけは2月下旬の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%C3%A5%AF%A5%DE%A1%BC%A5%AF">はてなブックマーク</a><sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>。<br/> 辿った先のページに</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdev.classmethod.jp%2Farticles%2Fllms-txt-for-ai-crawlers%2F" title="急増するAIクローラー対策として「llms.txt」を導入してみた | DevelopersIO" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>このクラスメソッドさん記事からリンクしている <a href="https://zenn.dev/minedia/articles/llmtxt-in-action">LLMS.txt: AI&#x6642;&#x4EE3;&#x306E;Web&#x30B5;&#x30A4;&#x30C8;&#x6700;&#x9069;&#x5316;&#x30AC;&#x30A4;&#x30C9;</a> では2種類紹介されています。</p> <ul> <li>/llms.txt: サマリー</li> <li>/llms-full.txt: 完全版<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup></li> </ul> <h3 id="llmstxtの作り方">llms.txtの作り方</h3> <p>言及している記事を見つけました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftowardsdatascience.com%2Fllms-txt-414d5121bcb3%2F" title="LLMs.txt Explained | Towards Data Science" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>「How to generate LLMs.txt files」より</p> <ul> <li><a href="https://mintlify.com/">Mintlify</a></li> <li><a href="https://github.com/dotenvx/llmstxt">dotenvx/llmstxt</a></li> <li><a href="https://llmstxt.firecrawl.dev/">https://llmstxt.firecrawl.dev/</a></li> </ul> <p>3点目は過去に触ったことがあるFirecrawlです。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Ffirecrawl-self-host-docker-compose-and-openai-key" title="スクレイピングツール Firecrawl をセルフホストで動かす🔥(docker composeで楽々でした) - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/OSS">OSS</a>の実装の方でも、ちょうどllms.txt生成機能が追加されたようです。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fmendableai%2Ffirecrawl%2Freleases%2Ftag%2Fv1.5.0" title="Release Self-Host Overhaul - v1.5.0 · mendableai/firecrawl" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <blockquote><p>LLM Text Generator: Added a new endpoint for llms.txt generation (#1201)</p></blockquote> <h3 id="セルフホストしたFirecrawlでllmstxtを作る">セルフホストしたFirecrawlでllms.txtを作る</h3> <p>過去記事同様に <a href="https://github.com/mendableai/firecrawl">mendableai/firecrawl</a> を<code>git clone</code>して始めました(コミットは<code>fea249c568c4a8d63bcc2e560fd3655e73350be6</code>)。</p> <pre class="code" data-lang="" data-unlink>% docker --version Docker version 27.5.0-rd, build 7a37716</pre> <pre class="code" data-lang="" data-unlink>% cp apps/api/.env.example .env % docker compose build % docker compose up</pre> <p><code>.env</code>編集内容</p> <pre class="code lang-diff" data-lang="diff" data-unlink><span class="synComment">## To turn on DB authentication, you need to set up supabase.</span> <span class="synSpecial">-USE_DB_AUTHENTICATION=true</span> <span class="synIdentifier">+USE_DB_AUTHENTICATION=false</span> <span class="synComment"># add for LLM dependednt features (image alt generation, etc.)</span> <span class="synIdentifier">+OPENAI_BASE_URL=https://api.openai.com/v1/</span> <span class="synSpecial">-OPENAI_API_KEY=</span> <span class="synIdentifier">+OPENAI_API_KEY=&lt;入力する&gt;</span> </pre> <p>これでllms.txtが作れます<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>。</p> <pre class="code" data-lang="" data-unlink>% curl http://localhost:3002/v1/llmstxt --json &#39;{&#34;url&#34;: &#34;https://firecrawl.dev&#34;, &#34;maxUrls&#34;: 2, &#34;showFullText&#34;: false}&#39; % curl http://localhost:3002/v1/llmstxt/3928d51b-83a7-49ef-84a7-b1f43e16a49b | jq . &gt; firecrawl.llms.txt % jq -r &#39;.data.llmstxt&#39; firecrawl.llms.txt # https://firecrawl.dev llms.txt - [Web Data Extraction](https://www.firecrawl.dev/): Transform websites into clean, LLM-ready data effortlessly. - [Flexible Web Scraping Pricing](https://www.firecrawl.dev/pricing): Flexible pricing plans for web scraping and data extraction. </pre> <p><a href="http://localhost:3002/admin/@/queues">http://localhost:3002/admin/@/queues</a> から状況が見えました。<br/> <a href="http://localhost:3002/admin/@/queues/queue/%7BgenerateLlmsTxtQueue%7D?status=completed">http://localhost:3002/admin/@/queues/queue/%7BgenerateLlmsTxtQueue%7D?status=completed</a></p> <p>OpenAIのBASE_URLと<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>_KEYを設定する必要があるというのは、プルリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トから当たりをつけました。<br/> <a href="https://github.com/mendableai/firecrawl/pull/1201/files#diff-84d99b7f2375d99875234d5e138420b3dcf6aaccfe3d1c942a0f2fc781fdcd60">https://github.com/mendableai/firecrawl/pull/1201/files#diff-84d99b7f2375d99875234d5e138420b3dcf6aaccfe3d1c942a0f2fc781fdcd60</a><br/> <strong>gpt-4o-miniを使っている</strong>んですよ!</p> <pre class="code" data-lang="" data-unlink>Generate a 9-10 word description and a 3-4 word title of the entire page based on ALL the content one will find on the page for this url: ${document.metadata?.url}. This will help in a user finding the page for its intended purpose. Here is the content: ${document.markdown}</pre> <h3 id="終わりに">終わりに</h3> <p>llms.txtを知り、またFirecrawlがそれを作るツールにもなることを知りました。<br/> Firecrawlでの作り方はLLM(gpt-4o-mini)を使うものですが、プロンプトを参考にして任意のモデルでllms.txtを作れそうですね。</p> <p>llms.txtやllms-full.txt、標準化はまだだと思いますが、サポートした方が有利な雰囲気があり、普及していくんじゃないかと思います。<br/> これが用意してサイトは閲覧者がNotebookLMなどで恩恵を受けられそうですからね。</p> <h3 id="おまけGeminiなら無料で">おまけ:Geminiなら無料で?</h3> <p>GeminiはOpenAIの<a class="keyword" href="https://d.hatena.ne.jp/keyword/API">API</a>互換のエンドポイントも提供しているのですよ<sup id="fnref:4"><a href="#fn:4" rel="footnote">4</a></sup>。<br/> <code>.env</code>を編集するだけで切り替えられたと思います!<sup id="fnref:5"><a href="#fn:5" rel="footnote">5</a></sup></p> <pre class="code" data-lang="" data-unlink>MODEL_NAME=gemini-2.0-flash OPENAI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/ OPENAI_API_KEY=&lt;Google AIから発行したGemini APIキー(※Vertex AIではないです)&gt;</pre> <pre class="code" data-lang="" data-unlink>% curl http://localhost:3002/v1/llmstxt --json &#39;{&#34;url&#34;: &#34;https://firecrawl.dev&#34;, &#34;maxUrls&#34;: 2, &#34;showFullText&#34;: false}&#39; % curl http://localhost:3002/v1/llmstxt/63f62916-d8ec-4bf0-ac15-ad4a3113102d | jq -r &#39;.data.llmstxt&#39; # https://firecrawl.dev llms.txt - [Firecrawl: Web Scraping](https://www.firecrawl.dev/): Firecrawl: Web scraping and crawling API for AI, offering clean, LLM-ready data. - [Firecrawl Pricing](https://www.firecrawl.dev/pricing): Explore Firecrawl&#39;s flexible pricing plans for web scraping and data extraction needs </pre> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> <a href="https://b.hatena.ne.jp/entry/s/dev.classmethod.jp/articles/aws-waf-bot-control-claudebot-spike/">https://b.hatena.ne.jp/entry/s/dev.classmethod.jp/articles/aws-waf-bot-control-claudebot-spike/</a><a href="#fnref:1" rev="footnote">&#8617;</a></li> <li id="fn:2"> このZennの記事では /llms-full.txt を NotebookLM に入れるという使い方が紹介されています <blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">I provided <a href="https://twitter.com/aisdk?ref_src=twsrc%5Etfw">@aisdk</a> llms.txt to <a href="https://twitter.com/NotebookLM?ref_src=twsrc%5Etfw">@NotebookLM</a>.<br><br>It created an Audio Overview.<br><br>You can listen to AI&#39;s conversation, covering generateText, streamText, Tools, GenerateObject, and more.<a href="https://t.co/X9dXKjYZB5">https://t.co/X9dXKjYZB5</a></p>&mdash; vivek patel (@patelvivekdev) <a href="https://twitter.com/patelvivekdev/status/1886557582501777540?ref_src=twsrc%5Etfw">2025年2月3日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <a href="#fnref:2" rev="footnote">&#8617;</a></li> <li id="fn:3"> <code>curl --json</code>便利〜! <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fcurl-json-option-from-7.82.0-is-awesome" title="curl 7.82.0(2022年3月リリース)から --json を指定することで -H &#39;Content-Type: application/json&#39; が不要になってました - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:3" rev="footnote">&#8617;</a></li> <li id="fn:4"> 過去の出来心 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fpromptflow-request-gemini-openai-compatible-endpoint" title="Microsoft製OSS Prompt flowをローカルで動かし、GoogleのGeminiのOpenAI互換エンドポイントにリクエストを送る - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:4" rev="footnote">&#8617;</a></li> <li id="fn:5"> 上で見たプルリクはモデル名のハードコードでしたが、最新では<a class="keyword" href="https://d.hatena.ne.jp/keyword/%B4%C4%B6%AD%CA%D1%BF%F4">環境変数</a><code>MODEL_NAME</code>を見て、なければハードコードしたモデルというイケてる実装でした。<a href="https://github.com/mendableai/firecrawl/blob/fea249c568c4a8d63bcc2e560fd3655e73350be6/apps/api/src/lib/generate-llmstxt/generate-llmstxt-service.ts#L140">https://github.com/mendableai/firecrawl/blob/fea249c568c4a8d63bcc2e560fd3655e73350be6/apps/api/src/lib/generate-llmstxt/generate-llmstxt-service.ts#L140</a><a href="#fnref:5" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/llms.txt" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">llms.txt</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Firecrawl" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Firecrawl</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt"><time data-relative datetime="2025-03-02T13:17:56Z" title="2025-03-02T13:17:56Z" class="updated">2025-03-02 22:17</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_campaign=subscribe_blog&amp;utm_medium=button&amp;utm_source=blogs_entry_footer"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt" data-hatena-star-title="llms.txtを作るツールとして、Firecrawlをセルフホストで試す" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=llms.txt&amp;hashtags=Firecrawl&amp;text=llms.txt%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%84%E3%83%BC%E3%83%AB%E3%81%A8%E3%81%97%E3%81%A6%E3%80%81Firecrawl%E3%82%92%E3%82%BB%E3%83%AB%E3%83%95%E3%83%9B%E3%82%B9%E3%83%88%E3%81%A7%E8%A9%A6%E3%81%99+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Ffirecrawl-oss-v1.5.0-support-generate-llmstxt" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <div id="google_afc_user_container_1" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user_2nd"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2800 words-200 mode-markdown entry-odd" id="entry-6802418398332943620" data-keyword-campaign="" data-uuid="6802418398332943620" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/03/01" rel="nofollow"> <time datetime="2025-03-01T14:30:57Z" title="2025-03-01T14:30:57Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">03</span><span class="hyphen">-</span><span class="date-day">01</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace" class="entry-title-link bookmark">チームに新しい開発者を迎え入れるように、Devinも&quot;オンボーディング&quot;するのか〜</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/LLM" class="entry-category-link category-LLM">LLM</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p>ロコ〜!歩夢ちゃん〜!お誕生日おめでとうございます!! nikkieです。</p> <p>今週プライベートでDevinを使い始めました💸<br/> Cognition AIの中の方と(英語で)話せるOnboardingがあり<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>、そこで知ったことを書き留めます</p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#Devin俺をonboardingしてくれよな">Devin「俺をonboardingしてくれよな」</a></li> <li><a href="#人類に残された仕事Devinが使う開発環境のセットアップ">人類に残された仕事:Devinが使う開発環境のセットアップ</a></li> <li><a href="#先日はDevinさんに無茶振りしていたのか">先日はDevinさんに無茶振りしていたのか!</a></li> <li><a href="#Devinが使う開発環境のセットアップに思うこと">Devinが使う開発環境のセットアップに思うこと</a></li> <li><a href="#終わりに">終わりに</a></li> </ul> <h3 id="Devin俺をonboardingしてくれよな">Devin「俺をonboardingしてくれよな」</h3> <blockquote><p>Hey there, nikkie! Like any new engineer, I'll need help with my onboarding. Let's get things set up so I can start contributing.</p></blockquote> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250301/20250301225914.png" width="824" height="565" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>やったこと✅</p> <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/GitHub">GitHub</a>と接続</li> </ul> <p>skip</p> <ul> <li>Slack接続:WebからDevinを使えると知っていたので</li> <li>チームメイトの招待:私だけのものだよ</li> </ul> <p>よくわからなかったもの(今回質問)</p> <ul> <li>Set Up Your First Repository</li> </ul> <h3 id="人類に残された仕事Devinが使う開発環境のセットアップ">人類に残された仕事:Devinが使う開発環境のセットアップ</h3> <p>ドキュメントもありました</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.devin.ai%2Fget-started%2Fquickstart%23setup-devin%25E2%2580%2599s-development-environment-upfront-you%25E2%2580%2599ll-be-able-to-start-new-devin-sessions-from-this-point%252C-every-time" title="Quickstart - Devin Docs" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.devin.ai/get-started/quickstart#setup-devin%E2%80%99s-development-environment-upfront-you%E2%80%99ll-be-able-to-start-new-devin-sessions-from-this-point%2C-every-time">docs.devin.ai</a></cite></p> <p>video tutorialを見て、人間が何をする必要があるかを得心しました(百聞は一見に如かずでした)。<br/> <strong>Devinが使う環境を人間がセットアップすることで、Devinに使うコマンドを伝えます</strong>。</p> <p><iframe src="https://www.loom.com/embed/8612d68820ef402c84d903c603ac7b32" frameborder="0" width="1672" height="1254" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></p> <p>手元のブラウザでDevinの開発環境(<a class="keyword" href="https://d.hatena.ne.jp/keyword/VS%20Code">VS Code</a><sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>)が立ち上がります。<br/> そこで人がコマンドを入力・動作確認して、登録していきます。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250301/20250301225955.png" width="1200" height="581" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>Update Dependencies(用コマンド<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>)</p> <pre class="code" data-lang="" data-unlink>cd ~/repos/sphinx-new-tab-link &amp;&amp; python -m pip install -e &#39;.[dev,lint,testing,typecheck]&#39;</pre> <p>Run Tests</p> <pre class="code" data-lang="" data-unlink>task test</pre> <p>Repo Note</p> <pre class="code lang-markdown" data-lang="markdown" data-unlink>For most simple tasks, just use <span class="synSpecial">`</span>task test<span class="synSpecial">`</span> to check your work. By taskipy's pre and post hooks, you can ensure that your code is linted, tested, and type checked. Always open PRs from separate branches into main. Always check lint, test, type check locally with <span class="synSpecial">`</span>task test<span class="synSpecial">`</span> before making commits and in addition to that, please check CI on github before reporting completion. </pre> <h3 id="先日はDevinさんに無茶振りしていたのか">先日はDevinさんに無茶振りしていたのか!</h3> <p>小さいプルリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トがうまくいったという記事を書きました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Ftry-devin-case-sphinx-new-tab-link-remove-rel-noopener" title="Devinお試し&amp;観察記:sphinx-new-tab-linkへの小さなプルリクエストを出してもらいました - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>この記事では「Set Up Your First Repository」をスキップしました。<br/> 公式が推奨する、<strong>人間によるDevin向け環境セットアップは、一切やっていません</strong>。<br/> そんな中でもDevinはリントや型チェック、テスト実行をして、プルリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トを出しています。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>の構成に依存すると思いますが、Devinが使う開発環境のセットアップは必須ではないようです(人間がやることでDevinがタスクに取り組む成功率が上がるのでしょう)。</p> <blockquote><p>Devinさん、taskipyのpre_hook, post_hookは理解してないよう。</p></blockquote> <p>ここは人間がDevinが使う開発環境のセットアップをしておくことで、理解しているように振る舞わせられそうです。</p> <h3 id="Devinが使う開発環境のセットアップに思うこと">Devinが使う開発環境のセットアップに思うこと</h3> <p>実は私は<strong><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>ごとに<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>開発環境を変えて</strong>います。<br/> ある<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>ではpip、別の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>ではuv、さらに別の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>ではHatchのような感じで、たっくさんある<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>開発環境管理ツールのキャッチアップも兼ねてやっています。<br/> このスタンスと、Cognition AI社が推奨する「Devinが使う開発環境のセットアップ」は、うまく両立させられないかもと思いました。</p> <p>Devinのonboardingは<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>単位でできるようです(朗報)。<br/> ただ<strong>ぶっちゃけ<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>ごとにやりたくない</strong>んですよね...<br/> pip, uv, Hatchといったツールには、私と同程度の知識とまではいかなくとも、<strong>使い方を調べて使える</strong>レベル感をDevinにも期待しています。<br/> 無茶振りしてうまくいった例では使い方を見出していたので、私が都度セットアップしなくてもいいように賢くならないかなと感じています(開発者の<em>分身</em>になることを期待してます)。</p> <h3 id="終わりに">終わりに</h3> <p>Devinもオンボーディングするということを知りました。<br/> Devinに振りたいタスクのある<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>で実行するコマンドを、人間が最初に示します。<br/> これが、人類に残された仕事...!</p> <p>オンボーディングする必要があると私が認識していなかったために、先日はDevinさんに無茶振りしてしまっていました。<br/> ところが、無茶振りされたDevinさんはコマンドを見出していてこれはとても助かりました。<br/> この方向に進化してほしいなと強く思います</p> <p>ジュニアエンジニア想定と謳っていますが、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>ごとにここまでやる必要があるのはちょっとおんぶにだっこすぎる感もあり、自走してみて詰まったら質問する動き方が好ましく感じます。<br/> 気づいたこととしては、他の開発者に環境構築手順が分かりやすくなるよう、開発者向けのドキュメントは用意してみます。</p> <p>最後に。Devinの友達料は決して安くないので、「私もDevin使ってみるぞ」って方は、<strong>ぜひ以下の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%E9">リファラ</a>ルリンクをお使いください</strong>🙏<br/> 紹介した側・された側双方にACUが付与されます</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fapp.devin.ai%2Finvite%2FCtjefdpUWWCghU5m" title="Devin (the Developer)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> ACUに釣られました(月$500の友達料のために、カツカツなんですよ)<a href="#fnref:1" rev="footnote">&#8617;</a></li> <li id="fn:2"> Devinが使うブラウザも設定できる(<a href="https://docs.devin.ai/get-started/quickstart#using-web-platforms">Using Web Platforms</a>)ようですが、私の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>では不要でした<a href="#fnref:2" rev="footnote">&#8617;</a></li> <li id="fn:3"> 直前の画像では「Install Dependencies」<a href="#fnref:3" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Devin" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Devin</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/%E3%82%AA%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">オンボーディング</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace"><time data-relative datetime="2025-03-01T14:30:57Z" title="2025-03-01T14:30:57Z" class="updated">2025-03-01 23:30</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_source=blogs_entry_footer&amp;utm_medium=button&amp;utm_campaign=subscribe_blog"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace" data-hatena-star-title="チームに新しい開発者を迎え入れるように、Devinも&quot;オンボーディング&quot;するのか〜" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=Devin&amp;hashtags=%E3%82%AA%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0&amp;text=%E3%83%81%E3%83%BC%E3%83%A0%E3%81%AB%E6%96%B0%E3%81%97%E3%81%84%E9%96%8B%E7%99%BA%E8%80%85%E3%82%92%E8%BF%8E%E3%81%88%E5%85%A5%E3%82%8C%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%80%81Devin%E3%82%82%22%E3%82%AA%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%22%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8B%E3%80%9C+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fdevin-needs-onboarding-human-run-commands-in-devins-workspace" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <div id="google_afc_user_container_2" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user_2nd"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2400 words-100 mode-markdown entry-even" id="entry-6802418398332660287" data-keyword-campaign="" data-uuid="6802418398332660287" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/02/28" rel="nofollow"> <time datetime="2025-02-28T14:43:20Z" title="2025-02-28T14:43:20Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">02</span><span class="hyphen">-</span><span class="date-day">28</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-" class="entry-title-link bookmark">#新宿御苑dev でのPyodideネタLTを記事化:ブラウザで動く、flake8-kotohaのplaygroundを作りました</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/Python%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83" class="entry-category-link category-Python開発環境">Python開発環境</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>使い、nikkieです。</p> <p><a href="https://shinjukugyoen.connpass.com/event/342134/">新宿御苑.wasm #2025.2.28</a>にて、PyodideネタでLTしました。<br/> スライドを用意せずにやったので、発表した内容を簡単に書き留めておきます</p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#PyodideネタでLTしました">PyodideネタでLTしました</a></li> <li><a href="#作りたかったもの">作りたかったもの</a></li> <li><a href="#flake8-kotohaのplayground">flake8-kotohaのplayground!</a></li> <li><a href="#flake8-kotoha-playgroundを実現できたポイント">flake8-kotoha playgroundを実現できたポイント</a><ul> <li><a href="#micropipでPyPIからインストール">micropipでPyPIからインストール</a></li> <li><a href="#flake8コマンドの出力をJavaScriptで受け取る">flake8コマンドの出力をJavaScriptで受け取る</a></li> </ul> </li> <li><a href="#発表後記">発表後記</a></li> <li><a href="#終わりに">終わりに</a></li> </ul> <h3 id="PyodideネタでLTしました">PyodideネタでLTしました</h3> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Pyodideネタで発表します <a href="https://twitter.com/hashtag/%E6%96%B0%E5%AE%BF%E5%BE%A1%E8%8B%91dev?src=hash&amp;ref_src=twsrc%5Etfw">#新宿御苑dev</a><br>デモページに全振りしたので、資料はございません!<br>作りたいものが作れたという興奮だけがあります!!<a href="https://t.co/m2aOVNhhJz">https://t.co/m2aOVNhhJz</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1895431694708260906?ref_src=twsrc%5Etfw">2025年2月28日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p><a href="https://pyodide.org/en/stable/index.html#what-is-pyodide">https://pyodide.org/en/stable/index.html#what-is-pyodide</a> より</p> <blockquote><p>Pyodide is a port of CPython to WebAssembly/<a class="keyword" href="https://d.hatena.ne.jp/keyword/Emscripten">Emscripten</a>.</p></blockquote> <p>CPythonをWasmにポートしたもの、という理解です。</p> <h3 id="作りたかったもの">作りたかったもの</h3> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/GitHub">GitHub</a> Actionsの<a class="keyword" href="https://d.hatena.ne.jp/keyword/YAML">YAML</a>ファイルのリンター actionlint のplaygroundです<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Frhysd.github.io%2Factionlint%2F" title="actionlint playground" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <iframe class="speakerdeck-iframe" style="border: 0px; background: rgba(0, 0, 0, 0.1) padding-box; margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;" frameborder="0" src="https://speakerdeck.com/player/4c9229de12454a6da6bad5d6b77d1f0b?slide=23" title="actionlint の Linter 設計" allowfullscreen="true" data-ratio="1.7777777777777777"></iframe> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>のリンター flake8(の自作<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D7%A5%E9%A5%B0%A5%A4%A5%F3">プラグイン</a> flake8-kotoha<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>)のplaygroundが作れるんじゃないかと思ったんですよね。</p> <h3 id="flake8-kotohaのplayground">flake8-kotohaのplayground!</h3> <p>上記ツイートのリンクをクリックすると体験できます。<br/> <a href="https://ftnext.github.io/pyodide-practice/kotoha-playground.html#ZnJvbSBjb2xsZWN0aW9ucy5hYmMgaW1wb3J0IEl0ZXJhYmxlCgoKZGVmIHBsdXNfb25lX25nKG51bWJlcnM6IGxpc3RbaW50XSkgLT4gbGlzdFtpbnRdOgogICAgcmV0dXJuIFtuICsgMSBmb3IgbiBpbiBudW1iZXJzXQoKCmRlZiBwbHVzX29uZV9vayhudW1iZXJzOiBJdGVyYWJsZVtpbnRdKSAtPiBsaXN0W2ludF06CiAgICByZXR1cm4gW24gKyAxIGZvciBuIGluIG51bWJlcnNd">https://ftnext.github.io/pyodide-practice/kotoha-playground.html#ZnJvbSBjb2xsZWN0aW9ucy5hYmMgaW1wb3J0IEl0ZXJhYmxlCgoKZGVmIHBsdXNfb25lX25nKG51bWJlcnM6IGxpc3RbaW50XSkgLT4gbGlzdFtpbnRdOgogICAgcmV0dXJuIFtuICsgMSBmb3IgbiBpbiBudW1iZXJzXQoKCmRlZiBwbHVzX29uZV9vayhudW1iZXJzOiBJdGVyYWJsZVtpbnRdKSAtPiBsaXN0W2ludF06CiAgICByZXR1cm4gW24gKyAxIGZvciBuIGluIG51bWJlcnNd</a></p> <p>textareaが2つ。<br/> 上のtextareaには、リント対象の<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コードが書かれます<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>。<br/> 「Run」をクリックすると、下のtextarea(<code>Output:</code>)にはリント結果が出力されます。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250228/20250228233417.png" width="1200" height="801" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>Pyodideを使って、このplaygroundを実装しました!</p> <h3 id="flake8-kotoha-playgroundを実現できたポイント">flake8-kotoha playgroundを実現できたポイント</h3> <p>実現できたポイントは2つあったと考えています。</p> <h4 id="micropipでPyPIからインストール">micropipで<a class="keyword" href="https://d.hatena.ne.jp/keyword/PyPI">PyPI</a>からインストール</h4> <p>1つは<a href="https://pypi.org/project/flake8-kotoha/">flake8-kotoha</a>(や依存するflake8)のインストールです。<br/> これはmicropipで可能でした。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fpyodide-micropip-install-pure-python-packages-from-pypi-example-emire" title="Pyodide素振りの記:micropipでなんとPyPIからインストールできちゃいます!(愛しのemi-reをブラウザで動かせたぜ🤗) - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>flake8やflake8-kotohaは<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>のみで実装されているので、micropipでインストールできます。<br/> ブラウザ上に簡単に環境構築できたので、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BF%B7%BD%C9%B8%E6%B1%F1">新宿御苑</a>.wasmのLTを締切に設定しました</p> <h4 id="flake8コマンドの出力をJavaScriptで受け取る">flake8コマンドの出力を<a class="keyword" href="https://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>で受け取る</h4> <p>もう1つはflake8コマンドの出力を画面に出すところです。<br/> Pyodideで<code>print()</code>を含む<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コードを<code>runPython()</code>したときの標準出力の扱い(<code>setStdout</code>)を知り、実現できました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fpyodide-quickstart-alternative-example-setstdout-for-python-print" title="Pyodide素振りの記:ブラウザから入力された1行のPythonコードを実行して画面を更新。さらにprint()にも対応 - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <h3 id="発表後記">発表後記</h3> <p>スケジュールがタイトだったため、実装は粗いです。<br/> 例えば、URLのハッシュ以降に含める<a class="keyword" href="https://d.hatena.ne.jp/keyword/base64">base64</a><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%F3%A5%B3%A1%BC%A5%C9">エンコード</a>した<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%BD%A1%BC%A5%B9%A5%B3%A1%BC%A5%C9">ソースコード</a>の実装にはブラッシュアップの余地を残します(actionlintの実装を理解しきれず一部から始めました)</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fweb.dev%2Farticles%2Fbase64-encoding%3Fhl%3Dja" title="JavaScript での Base64 エンコード文字列の微妙な違い  |  Articles  |  web.dev" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>懇親会で話して印象に残ったのは、(flake8は下火なので)Ruffでも同様のplaygroundができるのかという質問。<br/> RuffはRust実装のためにmicropipではインストールできないのではないかと思われます(ただし未検証)。<br/> ですが、Rust実装ということはWasmに<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>できるわけで、なんらか手段はありそうに思います(要調査)</p> <h3 id="終わりに">終わりに</h3> <p>Pyodideを使って、flake8-kotohaのplaygroundを実現できました。<br/> actionlintのplaygroundは再現させたかったので、Pyodideで実現できて達成感!<br/> ちょこちょこと細かいところを作り込んでいきます</p> <p>主催のasukaさんをはじめ、発表者・参加者の皆さま、ありがとうございました!<br/> また、BuySell Technologiesさん、素敵なオフィスを使わせていただき、ありがとうございます</p> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> 2024年6月の #<a class="keyword" href="https://d.hatena.ne.jp/keyword/dena">dena</a>_lint_night で目撃しました <blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Go の Single Binary を Playground にのせるときに WASM つかうのよさそう…… <a href="https://twitter.com/hashtag/dena_lint_night?src=hash&amp;ref_src=twsrc%5Etfw">#dena_lint_night</a></p>&mdash; usagiga (@usagiga_) <a href="https://twitter.com/usagiga_/status/1799028683187130445?ref_src=twsrc%5Etfw">2024年6月7日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <a href="#fnref:1" rev="footnote">&#8617;</a></li> <li id="fn:2"> 「引数の型ヒントをlistにしてはいけません」と指摘します <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fimas-hack-2024-release-flake8-kotoha-0.1.0" title="琴葉ちゃん「引数の型ヒントをlistにしてはいけません」をflake8のプラグインとして実装しました( #imas_hack でflake8-kotoha 0.1.0を開発!) - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:2" rev="footnote">&#8617;</a></li> <li id="fn:3"> actionlintのplaygroundをパクって、<strong>URLでこのコードが渡せています</strong>(詳細はまたの機会に)<a href="#fnref:3" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Pyodide" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Pyodide</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/wasm" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">wasm</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/flake8" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">flake8</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-"><time data-relative datetime="2025-02-28T14:43:20Z" title="2025-02-28T14:43:20Z" class="updated">2025-02-28 23:43</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_source=blogs_entry_footer&amp;utm_medium=button&amp;utm_campaign=subscribe_blog"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-" data-hatena-star-title="#新宿御苑dev でのPyodideネタLTを記事化:ブラウザで動く、flake8-kotohaのplaygroundを作りました" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=Pyodide&amp;hashtags=wasm&amp;hashtags=flake8&amp;text=%23%E6%96%B0%E5%AE%BF%E5%BE%A1%E8%8B%91dev+%E3%81%A7%E3%81%AEPyodide%E3%83%8D%E3%82%BFLT%E3%82%92%E8%A8%98%E4%BA%8B%E5%8C%96%EF%BC%9A%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%A7%E5%8B%95%E3%81%8F%E3%80%81flake8-kotoha%E3%81%AEplayground%E3%82%92%E4%BD%9C%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fflake8-kotoha-playground-alpha-version-by-pyodide-" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <script> (valve = window.valve || []).push(function(v) { v.displayDFPSlot('google_afc_user_container_3'); }); </script> <div id="google_afc_user_container_3" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user_2nd"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2000 words-200 mode-markdown entry-odd" id="entry-6802418398332416182" data-keyword-campaign="" data-uuid="6802418398332416182" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/02/27" rel="nofollow"> <time datetime="2025-02-27T14:46:20Z" title="2025-02-27T14:46:20Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">02</span><span class="hyphen">-</span><span class="date-day">27</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print" class="entry-title-link bookmark">Pyodide素振りの記:ブラウザから入力された1行のPythonコードを実行して画面を更新。さらにprint()にも対応</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/Python%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83" class="entry-category-link category-Python開発環境">Python開発環境</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p>㊗️<a href="https://twitter.com/imasml_theater/status/1894764360909594665">ミリオンライブ!12周年</a> nikkieです😭</p> <p>Pyodide素振りの第2弾です。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>のコード1行を入力すると、それを実行した結果を返すページを作りました</p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#前回のPyodide素振り">前回のPyodide素振り</a></li> <li><a href="#Getting-startedのAlternative-Example">「Getting started」の「Alternative Example」</a></li> <li><a href="#Pythonコード中のprintにも対応したい">Pythonコード中のprintにも対応したい</a></li> <li><a href="#pyodidesetStdout">pyodide.setStdout()</a></li> <li><a href="#終わりに">終わりに</a></li> </ul> <h3 id="前回のPyodide素振り">前回のPyodide素振り</h3> <p>「Getting started」から<a href="https://pyodide.org/en/stable/usage/quickstart.html#complete-example">Complete example</a>を写経しました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fpyodide-micropip-install-pure-python-packages-from-pypi-example-emire" title="Pyodide素振りの記:micropipでなんとPyPIからインストールできちゃいます!(愛しのemi-reをブラウザで動かせたぜ🤗) - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <ul> <li><code>loadPyodide()</code>して、<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コード(文字列)を渡して実行できる!(<code>pyodide.runPython()</code>)</li> <li>micropipで<a class="keyword" href="https://d.hatena.ne.jp/keyword/PyPI">PyPI</a>から<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>だけで実装されたパッケージをインストールできる!</li> </ul> <h3 id="Getting-startedのAlternative-Example">「Getting started」の「<a class="keyword" href="https://d.hatena.ne.jp/keyword/Alternative">Alternative</a> Example」</h3> <p>Complete exampleはブラウザのコンソールに出力する例でした。<br/> 実装は同様ですが、<strong><a class="keyword" href="https://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>を使ってHTML要素を操作</strong>する例もあります。<br/> それが<a class="keyword" href="https://d.hatena.ne.jp/keyword/Alternative">Alternative</a> Example</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fpyodide.org%2Fen%2Fstable%2Fusage%2Fquickstart.html%23alternative-example" title="Getting started — Version 0.27.3" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://pyodide.org/en/stable/usage/quickstart.html#alternative-example">pyodide.org</a></cite></p> <p>ばーん!</p> <p><script src="https://gist.github.com/ftnext/102c2d4d08c001355359e55c25c6a821.js"> </script></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250227/20250227231632.png" width="776" height="257" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>1行のコードを実行できました!!</p> <h3 id="Pythonコード中のprintにも対応したい"><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コード中のprintにも対応したい</h3> <p>遊んでいる中で気づいたことが1つ。<br/> <code>print()</code>に対応していないのです。</p> <pre class="code" data-lang="" data-unlink>&gt;&gt;&gt; print(sum([1, 2, 3, 4, 5])) undefined</pre> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250227/20250227231646.png" width="775" height="259" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>以下のように理解しました。</p> <ul> <li>画面に表示されなかったが、開発者ツールのコンソールに出力されている</li> <li><code>pyodide.runPython()</code>の返り値は、実行した<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コードの最後の式 <ul> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>の<code>print()</code>は返り値なし。すなわち<code>None</code>を返す</li> <li><a class="keyword" href="https://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>で<code>undefined</code>として受け取られた</li> </ul> </li> </ul> <h3 id="pyodidesetStdout"><code>pyodide.setStdout()</code></h3> <p>対処法を調べて見つかったのが、<code>pyodide.setStdout()</code>。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fpyodide%2Fpyodide%2Fdiscussions%2F4358%23discussioncomment-8000783" title="undefined output from print · pyodide pyodide · Discussion #4358" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p><a href="https://pyodide.org/en/stable/usage/api/js-api.html#pyodide.setStdout">https://pyodide.org/en/stable/usage/api/js-api.html#pyodide.setStdout</a></p> <p>batchedハンドラを設定します。</p> <blockquote><p>A batched handler is called with a string whenever a newline character is written or stdout is flushed.</p></blockquote> <p>変更後の<code>evaluatePython()</code>です<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>。<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コードの<code>print()</code>の出力を<a class="keyword" href="https://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>の配列に集め(※コンソール出力はしません)、コードの実行結果の前にHTMLに出力します。</p> <pre class="code lang-javascript" data-lang="javascript" data-unlink><span class="synStatement">async</span> <span class="synStatement">function</span> <span class="synIdentifier">evaluatePython</span><span class="synSpecial">()</span> <span class="synSpecial">{</span> <span class="synType">let</span> pyodide <span class="synStatement">=</span> <span class="synStatement">await</span> pyodideReadyPromise<span class="synStatement">;</span> <span class="synType">const</span> stdoutOutputs <span class="synStatement">=</span> <span class="synSpecial">[]</span><span class="synStatement">;</span> pyodide<span class="synStatement">.</span><span class="synIdentifier">setStdout</span><span class="synSpecial">({</span> <span class="synIdentifier">batched</span><span class="synStatement">:</span> <span class="synSpecial">(</span>msg<span class="synSpecial">)</span> <span class="synStatement">=&gt;</span> stdoutOutputs<span class="synStatement">.</span><span class="synIdentifier">push</span><span class="synSpecial">(</span>msg<span class="synSpecial">)</span> <span class="synSpecial">})</span><span class="synStatement">;</span> <span class="synIdentifier">addToOutput</span><span class="synSpecial">(</span><span class="synConstant">&quot;&gt;&gt;&gt; &quot;</span> <span class="synStatement">+</span> code<span class="synStatement">.</span>value<span class="synSpecial">)</span><span class="synStatement">;</span> <span class="synStatement">try</span> <span class="synSpecial">{</span> <span class="synType">const</span> codeOutput <span class="synStatement">=</span> pyodide<span class="synStatement">.</span><span class="synIdentifier">runPython</span><span class="synSpecial">(</span>code<span class="synStatement">.</span>value<span class="synSpecial">)</span><span class="synStatement">;</span> stdoutOutputs<span class="synStatement">.</span><span class="synIdentifier">forEach</span><span class="synSpecial">((</span>output<span class="synSpecial">)</span> <span class="synStatement">=&gt;</span> <span class="synIdentifier">addToOutput</span><span class="synSpecial">(</span>output<span class="synSpecial">))</span><span class="synStatement">;</span> <span class="synStatement">if</span> <span class="synSpecial">(</span>codeOutput <span class="synStatement">!</span>== <span class="synConstant">undefined</span><span class="synSpecial">)</span> <span class="synSpecial">{</span> <span class="synIdentifier">addToOutput</span><span class="synSpecial">(</span>codeOutput<span class="synSpecial">)</span><span class="synStatement">;</span> <span class="synSpecial">}</span> <span class="synSpecial">}</span> <span class="synStatement">catch</span> <span class="synSpecial">(</span>err<span class="synSpecial">)</span> <span class="synSpecial">{</span> <span class="synIdentifier">addToOutput</span><span class="synSpecial">(</span>err<span class="synSpecial">)</span><span class="synStatement">;</span> <span class="synSpecial">}</span> <span class="synSpecial">}</span> </pre> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250227/20250227231700.png" width="776" height="256" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>なおまだ伸びしろはあって、文字列の出力が<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>対話モードそのものではないです</p> <pre class="code" data-lang="" data-unlink>&gt;&gt;&gt; print(&#34;a&#34; + &#34;b&#34;) ab &gt;&gt;&gt; &#34;a&#34; + &#34;b&#34; # 対話モードだと &#39;ab&#39; ab</pre> <h3 id="終わりに">終わりに</h3> <p>Pyodideによってブラウザで実行した<a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コードの結果を、HTMLを書き換えて表示できました!<br/> <a class="keyword" href="https://d.hatena.ne.jp/keyword/Python">Python</a>コード中の<code>print()</code>は、<code>pyodide.setStdout()</code>を使って<a class="keyword" href="https://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>で受け取るように対応しました。</p> <p>前回の素振りと組み合わせると、<strong><a class="keyword" href="https://d.hatena.ne.jp/keyword/PyPI">PyPI</a>にある<em>60万</em>のパッケージをインストールして、ブラウザで対話的に実行できる</strong>ということになりますね。わくわく!</p> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> 全容 <script src="https://gist.github.com/ftnext/84d54657f603a72155adc2fd0fb7b548.js"> </script><a href="#fnref:1" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Pyodide" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Pyodide</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Getting%20Started" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Getting Started</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/wasm" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">wasm</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/print" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">print</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print"><time data-relative datetime="2025-02-27T14:46:20Z" title="2025-02-27T14:46:20Z" class="updated">2025-02-27 23:46</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_campaign=subscribe_blog&amp;utm_source=blogs_entry_footer&amp;utm_medium=button"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print" data-hatena-star-title="Pyodide素振りの記:ブラウザから入力された1行のPythonコードを実行して画面を更新。さらにprint()にも対応" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=Pyodide&amp;hashtags=Getting+Started&amp;hashtags=wasm&amp;hashtags=print&amp;text=Pyodide%E7%B4%A0%E6%8C%AF%E3%82%8A%E3%81%AE%E8%A8%98%EF%BC%9A%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%8B%E3%82%89%E5%85%A5%E5%8A%9B%E3%81%95%E3%82%8C%E3%81%9F1%E8%A1%8C%E3%81%AEPython%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%97%E3%81%A6%E7%94%BB%E9%9D%A2%E3%82%92%E6%9B%B4%E6%96%B0%E3%80%82%E3%81%95%E3%82%89%E3%81%ABprint()%E3%81%AB%E3%82%82%E5%AF%BE%E5%BF%9C+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fpyodide-quickstart-alternative-example-setstdout-for-python-print" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <script> (valve = window.valve || []).push(function(v) { v.displayDFPSlot('google_afc_user_container_4'); }); </script> <div id="google_afc_user_container_4" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user_2nd"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-2400 words-200 mode-markdown entry-even" id="entry-6802418398332115117" data-keyword-campaign="" data-uuid="6802418398332115117" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/02/26" rel="nofollow"> <time datetime="2025-02-26T13:19:30Z" title="2025-02-26T13:19:30Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">02</span><span class="hyphen">-</span><span class="date-day">26</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/keycloak-getting-started-run-docker-local" class="entry-title-link bookmark">keycloakのdockerイメージをローカル環境で動かす🔑</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/Docker" class="entry-category-link category-Docker">Docker</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p><em><a href="https://twitter.com/ftnext/status/1894588435832443325">京大 タテカン 2025</a></em> nikkieです。</p> <p><em>keycloak</em>という、<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%F3%A5%BD%A1%BC%A5%B9">オープンソース</a>の Identity and <a class="keyword" href="https://d.hatena.ne.jp/keyword/Access">Access</a> Management ツールを触ってみました。<br/> CNCFのincubation projectです。</p> <p>※認証まわりは正確に理解したいので、考え違いをしていたら<em>やさしく</em>ご指摘いただけると大変助かります</p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#Get-started-with-Keycloak-on-Docker">「Get started with Keycloak on Docker」</a><ul> <li><a href="#Start-Keycloak">Start Keycloak</a></li> <li><a href="#adminでrealmを作成">adminでrealmを作成</a></li> <li><a href="#adminでrealmにuserを作成">adminでrealmにuserを作成</a></li> <li><a href="#Secure-the-first-application">Secure the first application</a></li> </ul> </li> <li><a href="#curlの例">curlの例</a></li> <li><a href="#終わりに">終わりに</a></li> </ul> <h3 id="Get-started-with-Keycloak-on-Docker">「Get started with Keycloak on Docker」</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.keycloak.org%2Fgetting-started%2Fgetting-started-docker" title="Docker" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>DockerでkeycloakにGetting startedしていきます。</p> <pre class="code" data-lang="" data-unlink>% docker --version Docker version 27.5.0-rd, build 7a37716</pre> <h4 id="Start-Keycloak">Start Keycloak</h4> <p>keycloakのdockerイメージを動かします。</p> <pre class="code lang-sh" data-lang="sh" data-unlink>% docker run <span class="synSpecial">--rm</span> <span class="synSpecial">--name</span> keycloak <span class="synSpecial">-p</span> 8080:8080 <span class="synStatement">\</span> <span class="synSpecial">-e</span> <span class="synIdentifier">KC_BOOTSTRAP_ADMIN_USERNAME</span>=admin <span class="synStatement">\</span> <span class="synSpecial">-e</span> <span class="synIdentifier">KC_BOOTSTRAP_ADMIN_PASSWORD</span>=adminpass <span class="synStatement">\</span> quay.io/keycloak/keycloak:26.<span class="synConstant">1</span>.<span class="synConstant">2</span> start-dev </pre> <p><a href="http://localhost:8080/admin">http://localhost:8080/admin</a> から、adminのユーザ名とパスワードでログインします。</p> <h4 id="adminでrealmを作成">adminでrealmを作成</h4> <p>Getting startedに沿って、myrealmを「Create realm」します。<br/> 直URLは <a href="http://localhost:8080/admin/master/console/#/master/add-realm">http://localhost:8080/admin/master/console/#/master/add-realm</a></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226212355.png" width="1200" height="523" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h4 id="adminでrealmにuserを作成">adminでrealmにuserを作成</h4> <p>作ったmyrealmにmyuserを作ります。<br/> <a href="http://localhost:8080/admin/master/console/#/myrealm/users">http://localhost:8080/admin/master/console/#/myrealm/users</a> から「Add user」</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226212416.png" width="1200" height="586" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>Getting startedでは、myuserのパスワードをadminの方で設定します(例:mysecretpassword)。<br/> シークレットウィンドウで <a href="http://localhost:8080/realms/myrealm/account">http://localhost:8080/realms/myrealm/account</a> を開いて、<strong>myuserでログインできます</strong></p> <h4 id="Secure-the-first-application">Secure the first application</h4> <p>adminでmyrealmにclientを作ります。<br/> <a href="http://localhost:8080/admin/master/console/#/myrealm/clients">http://localhost:8080/admin/master/console/#/myrealm/clients</a> から「Create client」(すでに数ページ分Client IDが見つかります)</p> <p>ドキュメントに沿って設定していきます。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226212505.png" width="1200" height="582" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226212931.png" width="1200" height="583" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226212952.png" width="1200" height="590" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>clientを作成した後は <a href="https://www.keycloak.org/app/">https://www.keycloak.org/app/</a> から動作確認できます。</p> <p>初期値で保存し、</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226213116.png" width="1200" height="581" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <p>「<a class="keyword" href="https://d.hatena.ne.jp/keyword/Sign">Sign</a> in」をクリックすると、(シークレットウィンドウで開いたのと同様の)ログイン画面の表示。<br/> <strong>myuserでログインできます</strong>。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/nikkie-ftnext/20250226/20250226213018.png" width="1200" height="336" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <h3 id="curlの例"><a class="keyword" href="https://d.hatena.ne.jp/keyword/curl">curl</a>の例</h3> <p>ChatGPT deep researchで知った例です(※公式ドキュメントから外れるので、誤解があったら教えてください)</p> <pre class="code lang-sh" data-lang="sh" data-unlink>% curl <span class="synSpecial">-v</span> <span class="synSpecial">--request</span> POST <span class="synStatement">'</span><span class="synConstant">http://localhost:8080/realms/myrealm/protocol/openid-connect/token</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">--header</span> <span class="synStatement">'</span><span class="synConstant">Content-Type: application/x-www-form-urlencoded</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">--data-urlencode</span> <span class="synStatement">'</span><span class="synConstant">client_id=myclient</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">--data-urlencode</span> <span class="synStatement">'</span><span class="synConstant">username=myuser</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">--data-urlencode</span> <span class="synStatement">'</span><span class="synConstant">password=mysecretpassword</span><span class="synStatement">'</span> <span class="synStatement">\</span> <span class="synSpecial">--data-urlencode</span> <span class="synStatement">'</span><span class="synConstant">grant_type=password</span><span class="synStatement">'</span> | jq . </pre> <p><code>access_token</code>や<code>refresh_token</code>を含んだ<a class="keyword" href="https://d.hatena.ne.jp/keyword/JSON">JSON</a>が返ってきました<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>。<br/> 今回はここまでです(理解を深めたい!)</p> <h3 id="終わりに">終わりに</h3> <p>keycloakの素振りでした。<br/> OAuth 2.0の上に成り立つ <em><a class="keyword" href="https://d.hatena.ne.jp/keyword/OpenID">OpenID</a> Connect</em>、その具体の一つとしてkeycloakが立ち現れており、これらの理解を深めていきたいなと思っています</p> <p>以下のスライドで見た用語がkeycloakの画面でも登場していたような...(Auth屋さん書籍の出番かも)</p> <iframe class="speakerdeck-iframe" style="border: 0px; background: rgba(0, 0, 0, 0.1) padding-box; margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 100%; height: auto; aspect-ratio: 560 / 315;" frameborder="0" src="https://speakerdeck.com/player/c4052e3c99684810bc5223d83e4d332b?slide=8" title="やさしく入門するOAuth2.0/easy-entry-oauth" allowfullscreen="true" data-ratio="1.7777777777777777"></iframe> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> 理解を深めるために <a href="https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_authorization_api">https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_authorization_api</a> のあたりを読んでみる?<a href="#fnref:1" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Keycloak" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Keycloak</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Getting%20Started" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Getting Started</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/keycloak-getting-started-run-docker-local"><time data-relative datetime="2025-02-26T13:19:30Z" title="2025-02-26T13:19:30Z" class="updated">2025-02-26 22:19</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_campaign=subscribe_blog&amp;utm_medium=button&amp;utm_source=blogs_entry_footer"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/keycloak-getting-started-run-docker-local" data-hatena-star-title="keycloakのdockerイメージをローカル環境で動かす🔑" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/keycloak-getting-started-run-docker-local" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/keycloak-getting-started-run-docker-local" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/keycloak-getting-started-run-docker-local"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=Keycloak&amp;hashtags=Getting+Started&amp;text=keycloak%E3%81%AEdocker%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99%F0%9F%94%91+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fkeycloak-getting-started-run-docker-local" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <script> (valve = window.valve || []).push(function(v) { v.displayDFPSlot('google_afc_user_container_5'); }); </script> <div id="google_afc_user_container_5" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user_2nd"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <article class="entry hentry test-hentry js-entry-article date-first autopagerize_page_element chars-4000 words-400 mode-markdown entry-odd" id="entry-6802418398331855418" data-keyword-campaign="" data-uuid="6802418398331855418" data-publication-type="entry"> <div class="entry-inner"> <header class="entry-header"> <div class="date entry-date first"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/02/25" rel="nofollow"> <time datetime="2025-02-25T13:16:17Z" title="2025-02-25T13:16:17Z"> <span class="date-year">2025</span><span class="hyphen">-</span><span class="date-month">02</span><span class="hyphen">-</span><span class="date-day">25</span> </time> </a> </div> <h1 class="entry-title"> <a href="https://nikkie-ftnext.hatenablog.com/entry/try-devin-case-sphinx-new-tab-link-remove-rel-noopener" class="entry-title-link bookmark">Devinお試し&amp;観察記:sphinx-new-tab-linkへの小さなプルリクエストを出してもらいました</a> </h1> <div class="entry-categories categories"> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/LLM" class="entry-category-link category-LLM">LLM</a> <a href="https://nikkie-ftnext.hatenablog.com/archive/category/Sphinx" class="entry-category-link category-Sphinx">Sphinx</a> </div> </header> <div class="entry-content hatenablog-entry"> <h3 id="はじめに">はじめに</h3> <p><a href="https://twitter.com/ftnext/status/1894337028042666021">こいつは"本物"だぜ... </a> nikkieです</p> <p>俺がDevinにお願いして作ったプルリクを見てくれ!<br/> 今日はこのログです。</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">うおおおお!!<br>Issueを詳細に書いて結構お膳立てしたんですが、Devinさんすごいいいいい!!!<br>私の小さな<a class="keyword" href="https://d.hatena.ne.jp/keyword/OSS">OSS</a>に小さなプルリク出してくれた<a href="https://t.co/WYQltyiAyb">https://t.co/WYQltyiAyb</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1894178333388411330?ref_src=twsrc%5Etfw">2025年2月25日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <h3 id="目次">目次</h3> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#目次">目次</a></li> <li><a href="#Devinお試しの機運">Devinお試しの機運</a></li> <li><a href="#2024年時点のブラウザではtarget_blankと合わせたrelnoopenerが不要に">2024年時点のブラウザではtarget="_blank"と合わせたrel="noopener"が不要に</a></li> <li><a href="#Devin観察記sphinx-new-tab-linkにプルリクエストを送るまで">Devin観察記:sphinx-new-tab-linkにプルリクエストを送るまで</a></li> <li><a href="#終わりに">終わりに</a></li> </ul> <h3 id="Devinお試しの機運">Devinお試しの機運</h3> <p>「ぶっちゃけDevinなんて<em>おもちゃ</em>でしょ」と斜に構えてたんですよ。<br/> ところが、LayerXさんのブログがきっかけに、使ってみてもいいかもしれないと思い直しました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.layerx.co.jp%2Fentry%2F2025%2F02%2F06%2F110027" title="Devinにコンテナイメージサイズを70%削減・デプロイ時間を40%削減してもらった話 - LayerX エンジニアブログ" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>このブログではかなり賢い働きをしています。<br/> また、やりたいことたくさんで時間が足りない私には、<strong>Devinで手数を増やしてみる</strong>のもありかもと思ったのです。</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">先日のCursorはスケールアップとDevinはスケールアウトという話の発展。スケールアップツールは個人の生産性向上を実現するツールであり、スケールアウトツールは組織全体の生産性を向上させるツール。</p>&mdash; NISHIO Hirokazu (@nishio) <a href="https://twitter.com/nishio/status/1892401871840825537?ref_src=twsrc%5Etfw">2025年2月20日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p>2月冒頭時点でDevinにまずお願いしたいタスクは小さく切り出せていました。<br/> あとは2つの登壇<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>が終わってやりたい開発に全振りできるタイミングを待っていました。</p> <h3 id="2024年時点のブラウザではtarget_blankと合わせたrelnoopenerが不要に">2024年時点のブラウザでは<code>target=&quot;_blank&quot;</code>と合わせた<code>rel=&quot;noopener&quot;</code>が不要に</h3> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">全然知らなかった。<br><a class="keyword" href="https://d.hatena.ne.jp/keyword/sphinx">sphinx</a>-new-tab-link、見直そう <a href="https://t.co/bahiRDOvmt">https://t.co/bahiRDOvmt</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1876414087321768397?ref_src=twsrc%5Etfw">2025年1月6日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdeveloper.mozilla.org%2Fja%2Fdocs%2FWeb%2FHTML%2FElement%2Fa" title="&lt;a&gt;: アンカー要素 - HTML: ハイパーテキストマークアップ言語 | MDN" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <blockquote><p><code>target="_blank"</code> implies <code>rel="noopener"</code> behavior (<a href="https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%83%BC%E3%81%AE%E4%BA%92%E6%8F%9B%E6%80%A7">ブラウザーの互換性</a>)</p> <p>新しい版の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%D6%A5%E9%A5%A6%A5%B6%A1%BC">ブラウザー</a>では target="_blank" を設定すると、rel="noopener" と同じ保護が提供されます。(<a href="https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3%E3%81%A8%E3%83%97%E3%83%A9%E3%82%A4%E3%83%90%E3%82%B7%E3%83%BC">セキュリティとプライバシー</a>)</p></blockquote> <p><a class="keyword" href="https://d.hatena.ne.jp/keyword/Sphinx">Sphinx</a>で作ったHTMLドキュメントのリンクを別のタブで開くようにする拡張 <a class="keyword" href="https://d.hatena.ne.jp/keyword/sphinx">sphinx</a>-new-tab-link にもこちらを適用します。</p> <p>今は</p> <pre class="code lang-html" data-lang="html" data-unlink>External link: <span class="synIdentifier">&lt;</span><span class="synStatement">a</span><span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">&quot;reference external&quot;</span><span class="synIdentifier"> </span><span class="synType">href</span><span class="synIdentifier">=</span><span class="synConstant">&quot;https://example.com/&quot;</span><span class="synIdentifier"> </span><span class="synType">rel</span><span class="synIdentifier">=</span><span class="synConstant">&quot;noopener noreferrer&quot;</span><span class="synIdentifier"> </span><span class="synType">target</span><span class="synIdentifier">=</span><span class="synConstant">&quot;_blank&quot;</span><span class="synIdentifier">&gt;</span><span class="synUnderlined">Example</span><span class="synIdentifier">&lt;/</span><span class="synStatement">a</span><span class="synIdentifier">&gt;</span> </pre> <p>なのですが、<code>rel="noopener"</code>を削って</p> <pre class="code lang-html" data-lang="html" data-unlink>External link: <span class="synIdentifier">&lt;</span><span class="synStatement">a</span><span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">&quot;reference external&quot;</span><span class="synIdentifier"> </span><span class="synType">href</span><span class="synIdentifier">=</span><span class="synConstant">&quot;https://example.com/&quot;</span><span class="synIdentifier"> </span><span class="synType">rel</span><span class="synIdentifier">=</span><span class="synConstant">&quot;noreferrer&quot;</span><span class="synIdentifier"> </span><span class="synType">target</span><span class="synIdentifier">=</span><span class="synConstant">&quot;_blank&quot;</span><span class="synIdentifier">&gt;</span><span class="synUnderlined">Example</span><span class="synIdentifier">&lt;/</span><span class="synStatement">a</span><span class="synIdentifier">&gt;</span> </pre> <p>としたいです。<br/> 私が手を動かしてもいいのですが、<strong>Devinに<a class="keyword" href="https://d.hatena.ne.jp/keyword/%BC%AB%C1%B3%B8%C0%B8%EC">自然言語</a>でお願いするだけでできるんじゃないか</strong>と思えたので、題材にしました。</p> <h3 id="Devin観察記sphinx-new-tab-linkにプルリクエストを送るまで">Devin観察記:<a class="keyword" href="https://d.hatena.ne.jp/keyword/sphinx">sphinx</a>-new-tab-linkにプルリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トを送るまで</h3> <p>上記内容を記載したIssueを用意しました。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fftnext%2Fsphinx-new-tab-link%2Fissues%2F20" title="Follow newer browser&#39;s behavior; No need rel=&quot;noopener&quot; · Issue #20 · ftnext/sphinx-new-tab-link" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>行レベルで実装のこことテストのここを直すとできるとまで書いています(お膳立て)。</p> <p>Devinにお願いをします。</p> <pre class="code" data-lang="" data-unlink>このissueに取り組んでほしいです https://github.com/ftnext/sphinx-new-tab-link/issues/20</pre> <p>Devinはissueを確認し(<code>gh issue view</code>)、planを作り、コマンドを実行し始めました(見守っていたのでplanは未確認です)</p> <ul> <li><code>gh repo clone</code>してきて、<code>/home/ubuntu/repos/sphinx-new-tab-link</code><a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リに移動</li> <li><code>ls -al</code>を打ち、いくつかのファイルを読んでいます <ul> <li>issueで挙げた2ファイル</li> <li>README.md</li> <li>pyproject.toml</li> </ul> </li> <li><code>find . -type f -name "*.py" | grep -v "__pycache__" | sort</code>(なんかファイル一覧してる!)</li> <li><code>cat pyproject.toml | grep -A 10 "taskipy.tasks"</code></li> </ul> <p>ファイルを編集した後、taskipyまわりでつまづき、自己解決してました。</p> <pre class="code" data-lang="" data-unlink>$ task format bash: task: command not found</pre> <pre class="code" data-lang="" data-unlink>$ pip install taskipy $ task format /bin/sh: 1: autoflake: not found</pre> <p>ここで <a href="https://app.devin.ai/knowledge/testing-changes-locally">https://app.devin.ai/knowledge/testing-changes-locally</a> を見た(私には見えない...)</p> <pre class="code" data-lang="" data-unlink>$ pip install -e &#34;.[dev,lint,testing,typecheck]&#34; $ task format All done! ✨ 🍰 ✨ 19 files left unchanged. $ task check Success: no issues found in 11 source files $ task test All done! ✨ 🍰 ✨ 19 files left unchanged. ============================= test session starts ============================== &lt;省略&gt; ============================== 35 passed in 4.10s ============================== Success: no issues found in 11 source files</pre> <p>テスト実行できた!<br/> ここからプルリク<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トが上がります。<br/> お疲れさまでした!</p> <p>Devinさん、taskipyのpre_hook, post_hook<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup>は理解してないよう。<br/> こういうとき調べさせて、メモらせる(Knowledgeなるもの?)のがいいのかも。</p> <p>Devinはシェルやエディタを持っている<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup>と<a href="https://findy.connpass.com/event/344270/">Devin&#x4F7F;&#x3063;&#x3066;&#x307F;&#x3066;&#x3069;&#x3046;&#x3060;&#x3063;&#x305F;&#xFF1F; &#xFF5E;&#x6D3B;&#x7528;&#x4E8B;&#x4F8B;&#x3068;&#x5C0E;&#x5165;&#x6642;&#x306E;&#x30DD;&#x30A4;&#x30F3;&#x30C8;&#xFF5E; - connpass</a>で聞いて<sup id="fnref:4"><a href="#fn:4" rel="footnote">4</a></sup>、ちょっと興味を持っていました。<br/> 実際にコマンドを打っていく様子を目の当たりにして、「コマンドを打って出力を読んで現状を掴み次に進んでいる。これは開発者だな」と思いました<sup id="fnref:5"><a href="#fn:5" rel="footnote">5</a></sup></p> <p>planを見てみると、CodeAgent<sup id="fnref:6"><a href="#fn:6" rel="footnote">6</a></sup>ぽさがあります。</p> <pre class="code" data-lang="" data-unlink> 001 create_branch() 002 modify_rel_attributes_in_files() &gt; 003 run_format_and_lint() 004 run_tests() 005 commit_and_push_changes() 006 create_pr() 007 wait_for_ci() 008 report_pr_to_user()</pre> <h3 id="終わりに">終わりに</h3> <p>Devinに小さなタスクをお願いしてみました。<br/> けっこうお膳立てしており、「<strong>ジュニアエンジニア</strong>と想定して」というドキュメントの注文に沿っていたように思います</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdocs.devin.ai%2Fessential-guidelines%2Fwhen-to-use-devin" title="When to Use Devin - Devin Docs" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://docs.devin.ai/essential-guidelines/when-to-use-devin">docs.devin.ai</a></cite></p> <p>どれくらい雑にお願いしていいのかは今後探ります。<br/> 例えば、テストの方はファイル指定だけでいけるのか、変更箇所を考えさせるようなこともできるのか</p> <p>やってみて<strong>スケールアウト</strong>を感じます。<br/> 自分が手を動かさなくてもいい軽めタスクは、お願いしちゃえばいいんだ!</p> <p>最後に。Devinの友達料は決して安くないので、「私もDevin使うぞ」って方は、<strong>ぜひ以下の<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%E9">リファラ</a>ルリンクをお使いください</strong>🙏</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fapp.devin.ai%2Finvite%2FCtjefdpUWWCghU5m" title="Devin (the Developer)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe></p> <p>教祖のも置いておきます〜(選択は自由です)</p> <p><blockquote data-conversation="none" class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/devin_findy?src=hash&amp;ref_src=twsrc%5Etfw">#devin_findy</a> のこちらの<a class="keyword" href="https://d.hatena.ne.jp/keyword/%A5%EA%A5%D5%A5%A1%A5%E9">リファラ</a>ルリンクを使わせていただいています。感謝<br>Devinさんに&quot;友達料&quot;を要求されている(がま口カパ) <a href="https://t.co/pep1lsgjL3">https://t.co/pep1lsgjL3</a> <a href="https://t.co/VU0Ly45mc4">pic.twitter.com/VU0Ly45mc4</a></p>&mdash; nikkie(にっきー) / にっP (@ftnext) <a href="https://twitter.com/ftnext/status/1894172724396003771?ref_src=twsrc%5Etfw">2025年2月24日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <div class="footnotes"> <hr/> <ol> <li id="fn:1"> PyCon mini Shizuoka 2024 continue と DjangoCongress JP 2025 です<a href="#fnref:1" rev="footnote">&#8617;</a></li> <li id="fn:2"> Devinさん、ここ読んでみてください <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fstart-taskipy-without-poetry" title="Python向けタスクランナーとして気になっていたtaskipy 素振りの記、Poetryのない環境でお試し - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:2" rev="footnote">&#8617;</a></li> <li id="fn:3"> 「<em>In Devin’s Workspace, you’ll find:</em>」 <a href="https://docs.devin.ai/get-started/devin-intro#general-product-features">https://docs.devin.ai/get-started/devin-intro#general-product-features</a><a href="#fnref:3" rev="footnote">&#8617;</a></li> <li id="fn:4"> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fposfie.com%2F%40chellusam%2Fp%2Fguv0NCu" title="Devin使ってみてどうだった? ~活用事例と導入時のポイント~" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:4" rev="footnote">&#8617;</a></li> <li id="fn:5"> こちらの記事の「<em>具体的にどんなデータを学習させているのか?</em>」のデータのイメージを思い出しました。ActionやObservation、Thinking(思考)を羅列したテキストから訓練されていて実現できるようです(魔法かな) <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.layerx.co.jp%2Fentry%2F2025%2F02%2F13%2F175317" title="ChatGPT deep researchに見る⁨⁩AIが自律的に考える未来 - LayerX エンジニアブログ" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:5" rev="footnote">&#8617;</a></li> <li id="fn:6"> smolagentsで知りました <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Fhuggingface-smolagents-examples-with-gemini-2.0-flash" title="Hugging Faceによるエージェントライブラリ smolagents をGemini 2.0 Flashで動かす - nikkie-ftnextの日記" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><a href="#fnref:6" rev="footnote">&#8617;</a></li> </ol> </div> </div> <footer class="entry-footer"> <div class="entry-tags-wrapper"> <div class="entry-tags"> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/Devin" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">Devin</span> </a> </span> <span class="entry-tag"> <a href="https://d.hatena.ne.jp/keyword/sphinx-new-tab-link" class="entry-tag-link"> <span class="entry-tag-icon">#</span><span class="entry-tag-label">sphinx-new-tab-link</span> </a> </span> </div> </div> <p class="entry-footer-section track-inview-by-gtm" data-gtm-track-json="{&quot;area&quot;: &quot;finish_reading&quot;}"> <span class="author vcard"><span class="fn" data-load-nickname="1" data-user-name="nikkie-ftnext" >nikkie-ftnext</span></span> <span class="entry-footer-time"><a href="https://nikkie-ftnext.hatenablog.com/entry/try-devin-case-sphinx-new-tab-link-remove-rel-noopener"><time data-relative datetime="2025-02-25T13:16:17Z" title="2025-02-25T13:16:17Z" class="updated">2025-02-25 22:16</time></a></span> <span class=" entry-footer-subscribe " data-test-blog-controlls-subscribe> <a href="https://blog.hatena.ne.jp/nikkie-ftnext/nikkie-ftnext.hatenablog.com/subscribe?utm_source=blogs_entry_footer&amp;utm_medium=button&amp;utm_campaign=subscribe_blog"> 読者になる </a> </span> </p> <div class="hatena-star-container" data-hatena-star-container data-hatena-star-url="https://nikkie-ftnext.hatenablog.com/entry/try-devin-case-sphinx-new-tab-link-remove-rel-noopener" data-hatena-star-title="Devinお試し&amp;観察記:sphinx-new-tab-linkへの小さなプルリクエストを出してもらいました" data-hatena-star-variant="profile-icon" data-hatena-star-profile-url-template="https://blog.hatena.ne.jp/{username}/" ></div> <div class="social-buttons"> <div class="social-button-item"> <a href="https://b.hatena.ne.jp/entry/s/nikkie-ftnext.hatenablog.com/entry/try-devin-case-sphinx-new-tab-link-remove-rel-noopener" class="hatena-bookmark-button" data-hatena-bookmark-url="https://nikkie-ftnext.hatenablog.com/entry/try-devin-case-sphinx-new-tab-link-remove-rel-noopener" data-hatena-bookmark-layout="vertical-balloon" data-hatena-bookmark-lang="ja" title="この記事をはてなブックマークに追加"><img src="https://b.st-hatena.com/images/entry-button/button-only.gif" alt="この記事をはてなブックマークに追加" width="20" height="20" style="border: none;" /></a> </div> <div class="social-button-item"> <div class="fb-share-button" data-layout="box_count" data-href="https://nikkie-ftnext.hatenablog.com/entry/try-devin-case-sphinx-new-tab-link-remove-rel-noopener"></div> </div> <div class="social-button-item"> <a class="entry-share-button entry-share-button-twitter test-share-button-twitter" href="https://x.com/intent/tweet?hashtags=Devin&amp;hashtags=sphinx-new-tab-link&amp;text=Devin%E3%81%8A%E8%A9%A6%E3%81%97%26%E8%A6%B3%E5%AF%9F%E8%A8%98%EF%BC%9Asphinx-new-tab-link%E3%81%B8%E3%81%AE%E5%B0%8F%E3%81%95%E3%81%AA%E3%83%97%E3%83%AB%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%82%92%E5%87%BA%E3%81%97%E3%81%A6%E3%82%82%E3%82%89%E3%81%84%E3%81%BE%E3%81%97%E3%81%9F+-+nikkie-ftnext%E3%81%AE%E6%97%A5%E8%A8%98&amp;url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2Fentry%2Ftry-devin-case-sphinx-new-tab-link-remove-rel-noopener" title="X(Twitter)で投稿する" ></a> </div> </div> <div class="google-afc-image test-google-rectangle-ads"> <script> (valve = window.valve || []).push(function(v) { v.displayDFPSlot('google_afc_user_container_6'); }); </script> <div id="google_afc_user_container_6" class="google-afc-user-container google_afc_blocklink2_5 google_afc_boder" data-test-unit="/4374287/blog_user_2nd"></div> <a href="http://blog.hatena.ne.jp/guide/pro" class="open-pro-modal" data-guide-pro-modal-ad-url="https://hatena.blog/guide/pro/modal/ad">広告を非表示にする</a> </div> <div class="customized-footer"> </div> <div class="comment-box js-comment-box"> <a class="leave-comment-title js-leave-comment-title">コメントを書く</a> <ul class="comment js-comment"> <li class="read-more-comments" style="display: none;"><a>もっと読む</a></li> </ul> </div> </footer> </div> </article> <!-- rakuten_ad_target_end --> <!-- google_ad_section_end --> <div class="pager autopagerize_insert_before"> <span class="pager-next"> <a href="https://nikkie-ftnext.hatenablog.com/?page=1740489377" rel="next">次のページ</a> </span> </div> </div> </div> <aside id="box1"> <div id="box1-inner"> </div> </aside> </div><!-- #wrapper --> <aside id="box2"> <div id="box2-inner"> <div class="hatena-module hatena-module-profile"> <div class="hatena-module-title"> プロフィール </div> <div class="hatena-module-body"> <a href="https://nikkie-ftnext.hatenablog.com/about" class="profile-icon-link"> <img src="https://cdn.profile-image.st-hatena.com/users/nikkie-ftnext/profile.png" alt="id:nikkie-ftnext" class="profile-icon" /> </a> <span class="id"> <a href="https://nikkie-ftnext.hatenablog.com/about" class="hatena-id-link"><span data-load-nickname="1" data-user-name="nikkie-ftnext">id:nikkie-ftnext</span></a> </span> <div class="hatena-follow-button-box btn-subscribe js-hatena-follow-button-box" > <a href="#" class="hatena-follow-button js-hatena-follow-button"> <span class="subscribing"> <span class="foreground">読者です</span> <span class="background">読者をやめる</span> </span> <span class="unsubscribing" data-track-name="profile-widget-subscribe-button" data-track-once> <span class="foreground">読者になる</span> <span class="background">読者になる</span> </span> </a> <div class="subscription-count-box js-subscription-count-box"> <i></i> <u></u> <span class="subscription-count js-subscription-count"> </span> </div> </div> <div class="profile-about"> <a href="https://nikkie-ftnext.hatenablog.com/about">このブログについて</a> </div> </div> </div> <div class="hatena-module hatena-module-search-box"> <div class="hatena-module-title"> 検索 </div> <div class="hatena-module-body"> <form class="search-form" role="search" action="https://nikkie-ftnext.hatenablog.com/search" method="get"> <input type="text" name="q" class="search-module-input" value="" placeholder="記事を検索" required> <input type="submit" value="検索" class="search-module-button" /> </form> </div> </div> <div class="hatena-module hatena-module-links"> <div class="hatena-module-title"> リンク </div> <div class="hatena-module-body"> <ul class="hatena-urllist"> <li> <a href="https://hatena.blog/">はてなブログ</a> </li> <li> <a href="https://hatena.blog/guide?via=200109">ブログをはじめる</a> </li> <li> <a href="http://blog.hatenablog.com">週刊はてなブログ</a> </li> <li> <a href="https://hatena.blog/guide/pro">はてなブログPro</a> </li> </ul> </div> </div> <div class="hatena-module hatena-module-recent-entries "> <div class="hatena-module-title"> <a href="https://nikkie-ftnext.hatenablog.com/archive"> 最新記事 </a> </div> <div class="hatena-module-body"> <ul class="recent-entries hatena-urllist "> <li class="urllist-item recent-entries-item"> <div class="urllist-item-inner recent-entries-item-inner"> <a href="https://nikkie-ftnext.hatenablog.com/entry/nikkie-release-note-2025-02" class="urllist-title-link recent-entries-title-link urllist-title recent-entries-title">nikkie v2025.02 リリースのお知らせ</a> </div> </li> <li class="urllist-item recent-entries-item"> <div class="urllist-item-inner recent-entries-item-inner"> <a href="https://nikkie-ftnext.hatenablog.com/entry/firecrawl-oss-v1.5.0-support-generate-llmstxt" class="urllist-title-link recent-entries-title-link urllist-title recent-entries-title">llms.txtを作るツールとして、Firecrawlをセルフホストで試す</a> </div> </li> <li class="urllist-item recent-entries-item"> <div class="urllist-item-inner recent-entries-item-inner"> <a href="https://nikkie-ftnext.hatenablog.com/entry/devin-needs-onboarding-human-run-commands-in-devins-workspace" class="urllist-title-link recent-entries-title-link urllist-title recent-entries-title">チームに新しい開発者を迎え入れるように、Devinも&quot;オンボーディング&quot;するのか〜</a> </div> </li> <li class="urllist-item recent-entries-item"> <div class="urllist-item-inner recent-entries-item-inner"> <a href="https://nikkie-ftnext.hatenablog.com/entry/flake8-kotoha-playground-alpha-version-by-pyodide-" class="urllist-title-link recent-entries-title-link urllist-title recent-entries-title">#新宿御苑dev でのPyodideネタLTを記事化:ブラウザで動く、flake8-kotohaのplaygroundを作りました</a> </div> </li> <li class="urllist-item recent-entries-item"> <div class="urllist-item-inner recent-entries-item-inner"> <a href="https://nikkie-ftnext.hatenablog.com/entry/pyodide-quickstart-alternative-example-setstdout-for-python-print" class="urllist-title-link recent-entries-title-link urllist-title recent-entries-title">Pyodide素振りの記:ブラウザから入力された1行のPythonコードを実行して画面を更新。さらにprint()にも対応</a> </div> </li> </ul> </div> </div> <div class="hatena-module hatena-module-archive" data-archive-type="default" data-archive-url="https://nikkie-ftnext.hatenablog.com/archive"> <div class="hatena-module-title"> <a href="https://nikkie-ftnext.hatenablog.com/archive">月別アーカイブ</a> </div> <div class="hatena-module-body"> <ul class="hatena-urllist"> <li class="archive-module-year archive-module-year-hidden" data-year="2025"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025" class="archive-module-year-title archive-module-year-2025"> 2025 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/03" class="archive-module-month-title archive-module-month-2025-3"> 2025 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/02" class="archive-module-month-title archive-module-month-2025-2"> 2025 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2025/01" class="archive-module-month-title archive-module-month-2025-1"> 2025 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2024"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024" class="archive-module-year-title archive-module-year-2024"> 2024 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/12" class="archive-module-month-title archive-module-month-2024-12"> 2024 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/11" class="archive-module-month-title archive-module-month-2024-11"> 2024 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/10" class="archive-module-month-title archive-module-month-2024-10"> 2024 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/09" class="archive-module-month-title archive-module-month-2024-9"> 2024 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/08" class="archive-module-month-title archive-module-month-2024-8"> 2024 / 8 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/07" class="archive-module-month-title archive-module-month-2024-7"> 2024 / 7 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/06" class="archive-module-month-title archive-module-month-2024-6"> 2024 / 6 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/05" class="archive-module-month-title archive-module-month-2024-5"> 2024 / 5 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/04" class="archive-module-month-title archive-module-month-2024-4"> 2024 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/03" class="archive-module-month-title archive-module-month-2024-3"> 2024 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/02" class="archive-module-month-title archive-module-month-2024-2"> 2024 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2024/01" class="archive-module-month-title archive-module-month-2024-1"> 2024 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2023"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023" class="archive-module-year-title archive-module-year-2023"> 2023 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/12" class="archive-module-month-title archive-module-month-2023-12"> 2023 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/11" class="archive-module-month-title archive-module-month-2023-11"> 2023 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/10" class="archive-module-month-title archive-module-month-2023-10"> 2023 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/09" class="archive-module-month-title archive-module-month-2023-9"> 2023 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/08" class="archive-module-month-title archive-module-month-2023-8"> 2023 / 8 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/07" class="archive-module-month-title archive-module-month-2023-7"> 2023 / 7 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/06" class="archive-module-month-title archive-module-month-2023-6"> 2023 / 6 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/05" class="archive-module-month-title archive-module-month-2023-5"> 2023 / 5 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/04" class="archive-module-month-title archive-module-month-2023-4"> 2023 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/03" class="archive-module-month-title archive-module-month-2023-3"> 2023 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/02" class="archive-module-month-title archive-module-month-2023-2"> 2023 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2023/01" class="archive-module-month-title archive-module-month-2023-1"> 2023 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2022"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022" class="archive-module-year-title archive-module-year-2022"> 2022 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/12" class="archive-module-month-title archive-module-month-2022-12"> 2022 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/11" class="archive-module-month-title archive-module-month-2022-11"> 2022 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/10" class="archive-module-month-title archive-module-month-2022-10"> 2022 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/09" class="archive-module-month-title archive-module-month-2022-9"> 2022 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/08" class="archive-module-month-title archive-module-month-2022-8"> 2022 / 8 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/07" class="archive-module-month-title archive-module-month-2022-7"> 2022 / 7 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/06" class="archive-module-month-title archive-module-month-2022-6"> 2022 / 6 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/05" class="archive-module-month-title archive-module-month-2022-5"> 2022 / 5 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/04" class="archive-module-month-title archive-module-month-2022-4"> 2022 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/03" class="archive-module-month-title archive-module-month-2022-3"> 2022 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/02" class="archive-module-month-title archive-module-month-2022-2"> 2022 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2022/01" class="archive-module-month-title archive-module-month-2022-1"> 2022 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2021"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021" class="archive-module-year-title archive-module-year-2021"> 2021 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/12" class="archive-module-month-title archive-module-month-2021-12"> 2021 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/11" class="archive-module-month-title archive-module-month-2021-11"> 2021 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/10" class="archive-module-month-title archive-module-month-2021-10"> 2021 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/09" class="archive-module-month-title archive-module-month-2021-9"> 2021 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/05" class="archive-module-month-title archive-module-month-2021-5"> 2021 / 5 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/04" class="archive-module-month-title archive-module-month-2021-4"> 2021 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/03" class="archive-module-month-title archive-module-month-2021-3"> 2021 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/02" class="archive-module-month-title archive-module-month-2021-2"> 2021 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2021/01" class="archive-module-month-title archive-module-month-2021-1"> 2021 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2020"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020" class="archive-module-year-title archive-module-year-2020"> 2020 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/12" class="archive-module-month-title archive-module-month-2020-12"> 2020 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/11" class="archive-module-month-title archive-module-month-2020-11"> 2020 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/10" class="archive-module-month-title archive-module-month-2020-10"> 2020 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/09" class="archive-module-month-title archive-module-month-2020-9"> 2020 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/08" class="archive-module-month-title archive-module-month-2020-8"> 2020 / 8 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/06" class="archive-module-month-title archive-module-month-2020-6"> 2020 / 6 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/04" class="archive-module-month-title archive-module-month-2020-4"> 2020 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/03" class="archive-module-month-title archive-module-month-2020-3"> 2020 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/02" class="archive-module-month-title archive-module-month-2020-2"> 2020 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2020/01" class="archive-module-month-title archive-module-month-2020-1"> 2020 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2019"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019" class="archive-module-year-title archive-module-year-2019"> 2019 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/12" class="archive-module-month-title archive-module-month-2019-12"> 2019 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/11" class="archive-module-month-title archive-module-month-2019-11"> 2019 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/10" class="archive-module-month-title archive-module-month-2019-10"> 2019 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/09" class="archive-module-month-title archive-module-month-2019-9"> 2019 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/08" class="archive-module-month-title archive-module-month-2019-8"> 2019 / 8 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/07" class="archive-module-month-title archive-module-month-2019-7"> 2019 / 7 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/06" class="archive-module-month-title archive-module-month-2019-6"> 2019 / 6 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/05" class="archive-module-month-title archive-module-month-2019-5"> 2019 / 5 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/04" class="archive-module-month-title archive-module-month-2019-4"> 2019 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/03" class="archive-module-month-title archive-module-month-2019-3"> 2019 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/02" class="archive-module-month-title archive-module-month-2019-2"> 2019 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2019/01" class="archive-module-month-title archive-module-month-2019-1"> 2019 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2018"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018" class="archive-module-year-title archive-module-year-2018"> 2018 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/12" class="archive-module-month-title archive-module-month-2018-12"> 2018 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/11" class="archive-module-month-title archive-module-month-2018-11"> 2018 / 11 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/10" class="archive-module-month-title archive-module-month-2018-10"> 2018 / 10 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/09" class="archive-module-month-title archive-module-month-2018-9"> 2018 / 9 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/08" class="archive-module-month-title archive-module-month-2018-8"> 2018 / 8 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/07" class="archive-module-month-title archive-module-month-2018-7"> 2018 / 7 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/06" class="archive-module-month-title archive-module-month-2018-6"> 2018 / 6 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/05" class="archive-module-month-title archive-module-month-2018-5"> 2018 / 5 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/04" class="archive-module-month-title archive-module-month-2018-4"> 2018 / 4 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/03" class="archive-module-month-title archive-module-month-2018-3"> 2018 / 3 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/02" class="archive-module-month-title archive-module-month-2018-2"> 2018 / 2 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2018/01" class="archive-module-month-title archive-module-month-2018-1"> 2018 / 1 </a> </li> </ul> </li> <li class="archive-module-year archive-module-year-hidden" data-year="2017"> <div class="archive-module-button"> <span class="archive-module-hide-button">▼</span> <span class="archive-module-show-button">▶</span> </div> <a href="https://nikkie-ftnext.hatenablog.com/archive/2017" class="archive-module-year-title archive-module-year-2017"> 2017 </a> <ul class="archive-module-months"> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2017/12" class="archive-module-month-title archive-module-month-2017-12"> 2017 / 12 </a> </li> <li class="archive-module-month"> <a href="https://nikkie-ftnext.hatenablog.com/archive/2017/11" class="archive-module-month-title archive-module-month-2017-11"> 2017 / 11 </a> </li> </ul> </li> </ul> </div> </div> </div> </aside> </div> </div> </div> </div> <footer id="footer" data-brand="hatenablog"> <div id="footer-inner"> <address class="footer-address"> <a href="https://nikkie-ftnext.hatenablog.com/"> <img src="https://cdn.blog.st-hatena.com/images/admin/blog-icon-noimage.png" width="16" height="16" alt="nikkie-ftnextの日記"/> <span class="footer-address-name">nikkie-ftnextの日記</span> </a> </address> <p class="services"> Powered by <a href="https://hatena.blog/">Hatena Blog</a> | <a href="https://blog.hatena.ne.jp/-/abuse_report?target_url=https%3A%2F%2Fnikkie-ftnext.hatenablog.com%2F" class="report-abuse-link test-report-abuse-link" target="_blank">ブログを報告する</a> </p> </div> </footer> <script async src="https://s.hatena.ne.jp/js/widget/star.js"></script> <script> if (typeof window.Hatena === 'undefined') { window.Hatena = {}; } if (!Hatena.hasOwnProperty('Star')) { Hatena.Star = { VERSION: 2, }; } </script> <div id="fb-root"></div> <script>(function(d, s, id) { var js, fjs = d.getElementsByTagName(s)[0]; if (d.getElementById(id)) return; js = d.createElement(s); js.id = id; js.src = "//connect.facebook.net/ja_JP/sdk.js#xfbml=1&appId=719729204785177&version=v17.0"; fjs.parentNode.insertBefore(js, fjs); }(document, 'script', 'facebook-jssdk'));</script> <div class="quote-box"> <div class="tooltip-quote tooltip-quote-stock"> <i class="blogicon-quote" title="引用をストック"></i> </div> <div class="tooltip-quote tooltip-quote-tweet js-tooltip-quote-tweet"> <a class="js-tweet-quote" target="_blank" data-track-name="quote-tweet" data-track-once> <img src="https://cdn.blog.st-hatena.com/images/admin/quote/quote-x-icon.svg?version=1ca111bc9f0112690b12e1842a1ce8" title="引用して投稿する" > </a> </div> </div> <div class="quote-stock-panel" id="quote-stock-message-box" style="position: absolute; z-index: 3000"> <div class="message-box" id="quote-stock-succeeded-message" style="display: none"> <p>引用をストックしました</p> <button class="btn btn-primary" id="quote-stock-show-editor-button" data-track-name="curation-quote-edit-button">ストック一覧を見る</button> <button class="btn quote-stock-close-message-button">閉じる</button> </div> <div class="message-box" id="quote-login-required-message" style="display: none"> <p>引用するにはまずログインしてください</p> <button class="btn btn-primary" id="quote-login-button">ログイン</button> <button class="btn quote-stock-close-message-button">閉じる</button> </div> <div class="error-box" id="quote-stock-failed-message" style="display: none"> <p>引用をストックできませんでした。再度お試しください</p> <button class="btn quote-stock-close-message-button">閉じる</button> </div> <div class="error-box" id="unstockable-quote-message-box" style="display: none; position: absolute; z-index: 3000;"> <p>限定公開記事のため引用できません。</p> </div> </div> <script type="x-underscore-template" id="js-requote-button-template"> <div class="requote-button js-requote-button"> <button class="requote-button-btn tipsy-top" title="引用する"><i class="blogicon-quote"></i></button> </div> </script> <div id="hidden-subscribe-button" style="display: none;"> <div class="hatena-follow-button-box btn-subscribe js-hatena-follow-button-box" > <a href="#" class="hatena-follow-button js-hatena-follow-button"> <span class="subscribing"> <span class="foreground">読者です</span> <span class="background">読者をやめる</span> </span> <span class="unsubscribing" data-track-name="profile-widget-subscribe-button" data-track-once> <span class="foreground">読者になる</span> <span class="background">読者になる</span> </span> </a> <div class="subscription-count-box js-subscription-count-box"> <i></i> <u></u> <span class="subscription-count js-subscription-count"> </span> </div> </div> </div> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <script src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script> <script type="text/javascript" src="https://cdn.blog.st-hatena.com/js/external/jquery.min.js?v=1.12.4&amp;version=1ca111bc9f0112690b12e1842a1ce8"></script> <script src="https://cdn.blog.st-hatena.com/js/texts-ja.js?version=1ca111bc9f0112690b12e1842a1ce8"></script> <script id="vendors-js" data-env="production" src="https://cdn.blog.st-hatena.com/js/vendors.js?version=1ca111bc9f0112690b12e1842a1ce8" crossorigin="anonymous"></script> <script id="hatenablog-js" data-env="production" src="https://cdn.blog.st-hatena.com/js/hatenablog.js?version=1ca111bc9f0112690b12e1842a1ce8" crossorigin="anonymous" data-page-id="index"></script> <script>Hatena.Diary.GlobalHeader.init()</script> <script id="valve-dmp" data-service="blog" src="https://cdn.pool.st-hatena.com/valve/dmp.js" data-test-id="dmpjs" async></script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10