CINXE.COM
2016年4月5日の日記 - 氾濫原
<!DOCTYPE html> <html data-auth="" data-permalink="" itemscope itemtype="http://schema.org/Blog" lang=ja> <head> <meta charset=utf-8> <title>2016年4月5日の日記 - 氾濫原</title> <meta content="width=device-width,initial-scale=1,maximum-scale=2,user-scalable=yes" name=viewport> <meta content=#000000 name=theme-color> <link href=/feed rel=alternate title=Feed type=application/atom+xml> <meta content=unsafe-url name=referrer> <meta content="2016年4月5日の日記 - 氾濫原" itemprop=name> <meta content=写真・文章による、ある普通の人間の人生の記録 itemprop=description> <meta content="2016年4月5日の日記 - 氾濫原" property=og:title> <meta content="blog" property=og:type> <meta content="https://lowreal.net/" property=og:url> <meta content=cho45@lowreal.net property=og:email> <meta content=cho45 property=fb:admins> <link href="/css/style.css" rel=stylesheet> <link href="/css/github.css" rel=stylesheet> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel=stylesheet> <link href="/api/similar?id=20647&id=20648&" rel=preload as=fetch crossorigin id=preload-similar-entries> <link href="/api/exif?id=20647&id=20648&" rel=preload as=fetch crossorigin id=preload-exif-entries> <!-- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:foaf="http://xmlns.com/foaf/0.1/"> <rdf:Description rdf:about="https://lowreal.net/"> <foaf:maker rdf:parseType="Resource"> <foaf:holdsAccount> <foaf:OnlineAccount foaf:accountName="cho45"> <foaf:accountServiceHomepage rdf:resource="http://www.hatena.ne.jp/"/> </foaf:OnlineAccount> </foaf:holdsAccount> </foaf:maker> </rdf:Description> </rdf:RDF> --> <!--[if lt IE 9]><script src=https://html5shiv.googlecode.com/svn/trunk/html5.js></script><![endif]--> <script defer src="/js/daterelative.js"></script> <script defer src="/js/balancetext/tinysegmenter.js"></script> <script defer src="/js/balancetext/balance.js"></script> <script defer src="/js/abcjs_basic_5.1.1-min.js"></script> <script defer src="/js/nogag.js"></script> </head> <body> <header id=global-header> <h1 id=header> <a href=/ > <img alt="2016年4月5日の日記 - 氾濫原" height=50 src=/images/hanrangen.svg width=60 style=margin:auto;display:block> </a> </h1> </header> <nav id=global-navigation> <ul> <li><a href=/ >最新</a></li> <li><a href=/photo/ >写真</a></li> <li><a href=https://www.lowreal.net/ >誰?</a></li> </ul> </nav> <div id=content> <div class=entries> <div class=date><a href="/2016/04/05/">2016年 04月 05日</a></div> <article class="tech status-public" data-id="20647" id="post-1459865670" itemprop=blogPosts itemscope itemtype=http://schema.org/BlogPosting> <header> <h2 itemprop=name><a href="/2016/04/05/1" class=bookmark rel=bookmark itemprop=url>lowreal.net のHTTP2/HTTPS 化を実施</a></h2> <div class=metadata> <a href="/tech/"><span itemprop=keywords>tech</span></a> | <time datetime="2016-04-05T14:14:30Z" data-epoch="1459865670" itemprop=datePublished> 23:14 </time> | <div style=display:none> <meta content="/2016/04/05/1" itemprop=mainEntityOfPage itemscope itemtype=https://schema.org/WebPage> <span itemprop=headline>全部 HTTPS 対応にしてリダイレクトかけるようにしました。cho45.stfuawsc.com は既に HTTPS にしてありま…</span> <span itemprop=author itemscope itemtype=https://schema.org/Person> <a href=http://www.lowreal.net/ itemprop=url> <span itemprop=name>cho45</span> </a> </span> <div itemprop=publisher itemscope itemtype=https://schema.org/Organization> <div itemprop=logo itemscope itemtype=https://schema.org/ImageObject> <meta content=https://www.lowreal.net/images/logo.png itemprop=url> <meta content=189 itemprop=width> <meta content=105 itemprop=height> </div> <meta content=cho45 itemprop=name> </div> <meta content="2016-04-05T14:14:30Z" itemprop=datePublished> <meta content="2020-07-29T09:52:42Z" itemprop=dateModified> <div itemprop=image itemscope itemtype=https://schema.org/ImageObject> <meta content="/images/entry/2016-04-05" itemprop=url> <meta content=800 itemprop=width> <meta content=800 itemprop=height> </div> </div> </div> </header> <div class=content itemprop=articleBody> <p> <span itemscope itemtype=http://schema.org/Photograph> <a href=https://picasaweb.google.com/114431815111528304586/April52016#6270078726448024770 class=picasa itemprop=url><img alt=photo itemprop=image src="/images/entry/2016-04-05 23.13.18.png"></a> </span> <p>全部 HTTPS 対応にしてリダイレクトかけるようにしました。<p>cho45.stfuawsc.com は既に HTTPS にしてありました。こちらは nginx に letsencrypt の証明書を入れた構成だったのですが、これを機に HTTPS のフロントを h2o にして、nginx は HTTP だけを配信するようにしました。これで HTTPS は HTTP2 に対応になりました。<p>このサイトは割と複雑な URL の rewrite ルールをしいているので、バックエンドのアプリケーションに直接ディスパッチせず、一旦 HTTPS でも nginx を経由するようにして設定し、徐々に h2o で全リクエストを処理するように置き換えていきました。<a href=https://www.lowreal.net/ >www.lowreal.net</a> も同時に HTTPS 対応しましたがそれぞれのドメインの構成は以下の通りです</p> <ul> <li>cho45.stfuawsc.com <ul> <li>h2o → static file</li> <li>h2o → backend</li> </ul></li> <li>lowreal.net <ul> <li>h2o → static file</li> <li>h2o → backend</li> </ul></li> <li>www.lowreal.net <ul> <li>h2o → static file (accept-language を mruby で見てる)</li> </ul></li> </ul> <section class=level-1> <h3>証明書以外にやったこと</h3> <p>一応 mixed content を回避したり、push してみたりしたくていろいろやりました</p> <ul> <li>はてなスターのスキーム変更</li> <li>スター画像のホスト元 (フォトライフ) のドメイン変更 (cdn-akナントカに)</li> <li>tumblr のスキーム変更</li> <li>facebook ボタン廃止</li> <li>twitter ボタンのスキーム変更</li> <li>Amazon 画像のドメイン変更 (過去に遡ってエントリ内の画像URLを変更)</li> <li>バックエンドアプリケーション (ブログシステム) へ Link: rel=preload を簡単に吐ける機能を追加</li> </ul> </section> <section class=level-1> <h3>h2o での server push の確認方法</h3> <p>h2o は server push したコンテンツのヘッダに x-http2-push: pushed を含めてくれるので、ちゃんと push されてるか確認する一番簡単な方法はこれを見ることっぽいです。</p> </section> <ol itemscope itemtype=http://schema.org/BreadcrumbList><li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem><a href=/ itemprop=item><span itemprop=name>トップ</span></a> <meta content=1 itemprop=position> </li> <li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem> <a href="/tech/" itemprop=item><span itemprop=name>tech</span></a> <meta content=2 itemprop=position> </li> <li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem> <a href="https://lowreal.net/2016/04/05/1" itemprop=item><span itemprop=name>lowreal.net のHTTP2/HTTPS 化を実施</span></a> <meta content=3 itemprop=position> </li> </ol> </div> <div class="content similar-entries"> </div> <div class=social> <span class=hatena-star></span> <p class=share-buttons> <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Flowreal.net%2F2016%2F04%2F05%2F1" class=share-button rel="noopener nofollow" onclick='ga("send","social","Facebook","Share","https://lowreal.net/2016/04/05/1")' style=background:#3b5998 target=_blank> <img alt=Facebook height=18 src=/images/sharebuttons/FB-f-Logo__white_50.png width=18> </a> <a href="https://bsky.app/intent/compose?text=lowreal.net%20%E3%81%AEHTTP2%2FHTTPS%20%E5%8C%96%E3%82%92%E5%AE%9F%E6%96%BD%20https%3A%2F%2Flowreal.net%2F2016%2F04%2F05%2F1" class=share-button rel="noopener nofollow" onclick='ga("send","social","Bluesky","Share","https://lowreal.net/2016/04/05/1")' style=background:#efefef target=_blank> <img alt=Bluesky height=40 src=/images/bluesky_media_kit_logo_svgs.svg width=40> </a> <a href="http://b.hatena.ne.jp/add?url=https%3A%2F%2Flowreal.net%2F2016%2F04%2F05%2F1" class=share-button rel="noopener nofollow" onclick='ga("send","social","Hatena::Bookmark","Share","https://lowreal.net/2016/04/05/1")' style=background:#00a4de target=_blank> <img alt=はてなブックマーク height=40 src=/images/sharebuttons/hatenabookmark-logomark.svg width=40> </a> </p> </div> </article> <article class="tech status-public" data-id="20648" id="post-1459866122" itemprop=blogPosts itemscope itemtype=http://schema.org/BlogPosting> <header> <h2 itemprop=name><a href="/2016/04/05/2" class=bookmark rel=bookmark itemprop=url>nginx の rewrite ルールっぽく h2o の mruby でリクエストの rewrite を行う</a></h2> <div class=metadata> <a href="/tech/"><span itemprop=keywords>tech</span></a> | <time datetime="2016-04-05T14:22:02Z" data-epoch="1459866122" itemprop=datePublished> 23:22 </time> | <div style=display:none> <meta content="/2016/04/05/2" itemprop=mainEntityOfPage itemscope itemtype=https://schema.org/WebPage> <span itemprop=headline>このサイトのHTTPS化にあたって nginx で書いていた rewrite のルールを h2o の mruby で処理するように変…</span> <span itemprop=author itemscope itemtype=https://schema.org/Person> <a href=http://www.lowreal.net/ itemprop=url> <span itemprop=name>cho45</span> </a> </span> <div itemprop=publisher itemscope itemtype=https://schema.org/Organization> <div itemprop=logo itemscope itemtype=https://schema.org/ImageObject> <meta content=https://www.lowreal.net/images/logo.png itemprop=url> <meta content=189 itemprop=width> <meta content=105 itemprop=height> </div> <meta content=cho45 itemprop=name> </div> <meta content="2016-04-05T14:22:02Z" itemprop=datePublished> <meta content="2016-04-13T16:47:03Z" itemprop=dateModified> <div itemprop=image itemscope itemtype=https://schema.org/ImageObject> <meta content=https://www.lowreal.net/images/logo.png itemprop=url> <meta content=189 itemprop=width> <meta content=105 itemprop=height> </div> </div> </div> </header> <div class=content itemprop=articleBody> <p><a href=https://lowreal.net/2016/04/05/1>このサイトのHTTPS化にあたって</a> nginx で書いていた rewrite のルールを h2o の mruby で処理するように変える必要がありました。<p>しかしベタで書くのも面倒なので、そこそこ機械的な置換ですむような書きかたができるようなライブラリを書いてしのぎました。</p> <section class=level-1> <h3>mruby.handler</h3> <pre class="code lang-ruby hljs"> <span class=hljs-symbol>paths:</span> <span class=hljs-string>"/"</span>: proxy.reverse.<span class=hljs-symbol>url:</span> <span class=hljs-symbol>http:</span>/<span class=hljs-regexp>/localhost:5001 proxy.preserve-host: ON mruby.handler: | require "/srv</span><span class=hljs-regexp>/www/rewrite</span>_rules.rb<span class=hljs-string>" lambda do |env| RewriteRules.rewrite(env) do rewrite '/favicon.ico', '/images/favicon.ico', :break rewrite '/apple-touch-icon.png', '/images/apple-touch-icon.png', :break rewrite %r{^/2005/colors-canvas\.xhtml$}, '/2005/colors-canvas.html', :permanent rewrite %r{^/2005/colors-canvas$}, '/2005/colors-canvas.html', :permanent rewrite %r{^/logs/latest$}, '/', :permanent rewrite %r{^/logs/latest.rdf$}, '/feed', :permanent rewrite %r{^/logs/latest.atom$}, '/feed', :permanent rewrite %r{^/latest\.rdf$}, '/feed', :permanent rewrite %r{^/blog/index\.(rdf|atom)$}, '/feed', :permanent rewrite %r{^/logs(/.+?)(\.(rdf|atom))$}, '/feed', :permanent rewrite %r{^/logs(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent rewrite %r{^/blog(/.+?)(\.(x?html|xml|txt))?$}, '\1', :permanent rewrite %r{^/photo$}, '/photo/', :permanent rewrite %r{^/(\d\d\d\d/\d\d(/\d\d)?)$}, '/\1/', :permanent rewrite %r{^/\d\d\d\d/$}, '/', :redirect rewrite %r{^/view-img(/.+?)$}, '\1', :permanent end end</span></pre> <p>h2o の path はディレクトリの指定しかできないみたいなので (自動的に末尾スラッシュがついたりする)、rewrite で同時にパス決め打ちのディスパッチも行っています。<p>rewrite_rules.rb</p> <pre class="code lang-ruby hljs"><span class=hljs-class><span class=hljs-keyword>class</span> <span class=hljs-title>RewriteRules</span></span> <span class=hljs-class><span class=hljs-keyword>class</span> <span class=hljs-title>RewriteRulesException</span> < Exception</span> <span class=hljs-keyword>attr_reader</span> <span class=hljs-symbol>:response</span> <span class=hljs-function><span class=hljs-keyword>def</span> <span class=hljs-title>initialize</span><span class=hljs-params>(response)</span></span> @response = response <span class=hljs-keyword>end</span> <span class=hljs-keyword>end</span> <span class=hljs-keyword>attr_reader</span> <span class=hljs-symbol>:env</span> <span class=hljs-keyword>attr_reader</span> <span class=hljs-symbol>:path</span> <span class=hljs-function><span class=hljs-keyword>def</span> <span class=hljs-title>self</span>.<span class=hljs-title>rewrite</span><span class=hljs-params>(env, &block)</span></span> <span class=hljs-keyword>self</span>.new(env).run(&block) <span class=hljs-keyword>end</span> <span class=hljs-function><span class=hljs-keyword>def</span> <span class=hljs-title>initialize</span><span class=hljs-params>(env, &block)</span></span> @env = env @path_orig = <span class=hljs-string>"<span class=hljs-subst>#{env[<span class=hljs-string>'SCRIPT_NAME'</span>]}</span><span class=hljs-subst>#{env[<span class=hljs-string>'PATH_INFO'</span>]}</span>"</span> @path = @path_orig.dup <span class=hljs-keyword>end</span> <span class=hljs-function><span class=hljs-keyword>def</span> <span class=hljs-title>run</span><span class=hljs-params>(&block)</span></span> <span class=hljs-keyword>begin</span> instance_eval(&block) <span class=hljs-keyword>if</span> @path != @path_orig <span class=hljs-keyword>return</span> [ <span class=hljs-number>307</span>, { <span class=hljs-string>'x-reproxy-url'</span> => path }, [ ] ] <span class=hljs-keyword>else</span> <span class=hljs-keyword>return</span> [ <span class=hljs-number>399</span>, {}, [ ] ] <span class=hljs-keyword>end</span> <span class=hljs-keyword>rescue</span> RewriteRulesException => e <span class=hljs-keyword>return</span> e.response <span class=hljs-keyword>end</span> <span class=hljs-keyword>end</span> <span class=hljs-function><span class=hljs-keyword>def</span> <span class=hljs-title>rewrite</span><span class=hljs-params>(regexp, replace, flag=<span class=hljs-symbol>:continue</span>)</span></span> <span class=hljs-keyword>if</span> @path.gsub!(regexp, replace) <span class=hljs-keyword>case</span> flag <span class=hljs-keyword>when</span> <span class=hljs-symbol>:redirect</span> raise RewriteRulesException.new([ <span class=hljs-number>302</span>, { <span class=hljs-string>'Location'</span> => @path }, [ ] ]) <span class=hljs-keyword>when</span> <span class=hljs-symbol>:permanent</span> raise RewriteRulesException.new([ <span class=hljs-number>301</span>, { <span class=hljs-string>'Location'</span> => @path }, [ ] ]) <span class=hljs-keyword>when</span> <span class=hljs-symbol>:break</span> raise RewriteRulesException.new([ <span class=hljs-number>307</span>, { <span class=hljs-string>'x-reproxy-url'</span> => @path }, [ ] ]) <span class=hljs-keyword>when</span> <span class=hljs-symbol>:continue</span> <span class=hljs-comment># nothing</span> <span class=hljs-keyword>else</span> raise <span class=hljs-string>"unsupported flag: <span class=hljs-subst>#{flag}</span>"</span> <span class=hljs-keyword>end</span> <span class=hljs-keyword>end</span> <span class=hljs-keyword>end</span> <span class=hljs-keyword>end</span> </pre> <pre class="code lang-ruby hljs"><span class=hljs-keyword>require</span> <span class=hljs-string>'rspec'</span> describe RewriteRules <span class=hljs-keyword>do</span> it <span class=hljs-string>"should treat :permanent as 302 redirect"</span> <span class=hljs-keyword>do</span> env = { <span class=hljs-string>'PATH_INFO'</span> => <span class=hljs-string>'/logs/latest'</span> } expect(RewriteRules.rewrite(env) { rewrite %r{^<span class=hljs-regexp>/logs/latest</span>$}, <span class=hljs-string>'/'</span>, <span class=hljs-symbol>:permanent</span> rewrite %r{^<span class=hljs-regexp>/logs(/</span>.+?)(\.(x?html<span class=hljs-params>|xml|</span>txt))?$}, <span class=hljs-string>'\1'</span>, <span class=hljs-symbol>:permanent</span> rewrite %r{^<span class=hljs-regexp>/foobar/</span>}, <span class=hljs-string>'/bazbaz/'</span> }).to eq( [<span class=hljs-number>301</span>, {<span class=hljs-string>"Location"</span>=><span class=hljs-string>"/"</span>}, []]) <span class=hljs-keyword>end</span> it <span class=hljs-string>"should treat :redirect as 301 redirect"</span> <span class=hljs-keyword>do</span> env = { <span class=hljs-string>'PATH_INFO'</span> => <span class=hljs-string>'/logs/piyo.html'</span> } expect(RewriteRules.rewrite(env) { rewrite %r{^<span class=hljs-regexp>/logs/latest</span>$}, <span class=hljs-string>'/'</span>, <span class=hljs-symbol>:permanent</span> rewrite %r{^<span class=hljs-regexp>/logs(/</span>.+?)(\.(x?html<span class=hljs-params>|xml|</span>txt))?$}, <span class=hljs-string>'\1'</span>, <span class=hljs-symbol>:redirect</span> rewrite %r{^<span class=hljs-regexp>/foobar/</span>}, <span class=hljs-string>'/bazbaz/'</span> }).to eq([<span class=hljs-number>302</span>, {<span class=hljs-string>"Location"</span>=><span class=hljs-string>"/piyo"</span>}, []]) <span class=hljs-keyword>end</span> it <span class=hljs-string>"should treat as internal proxy by default"</span> <span class=hljs-keyword>do</span> env = { <span class=hljs-string>'PATH_INFO'</span> => <span class=hljs-string>'/foobar/baz'</span> } expect(RewriteRules.rewrite(env) { rewrite %r{^<span class=hljs-regexp>/logs/latest</span>$}, <span class=hljs-string>'/'</span>, <span class=hljs-symbol>:permanent</span> rewrite %r{^<span class=hljs-regexp>/logs(/</span>.+?)(\.(x?html<span class=hljs-params>|xml|</span>txt))?$}, <span class=hljs-string>'\1'</span>, <span class=hljs-symbol>:permanent</span> rewrite %r{^<span class=hljs-regexp>/foobar/</span>}, <span class=hljs-string>'/bazbaz/'</span> }).to eq([<span class=hljs-number>307</span>, {<span class=hljs-string>"x-reproxy-url"</span>=><span class=hljs-string>"/bazbaz/baz"</span>}, []]) <span class=hljs-keyword>end</span> it <span class=hljs-string>"can write logic in dsl"</span> <span class=hljs-keyword>do</span> env = { <span class=hljs-string>'PATH_INFO'</span> => <span class=hljs-string>'/foobar/baz'</span>, <span class=hljs-string>'XXX'</span> => <span class=hljs-literal>true</span>, } expect(RewriteRules.rewrite(env) { <span class=hljs-keyword>if</span> env[<span class=hljs-string>'XXX'</span>] rewrite %r{^<span class=hljs-regexp>/foobar/</span>}, <span class=hljs-string>'/bazbaz/'</span> <span class=hljs-keyword>end</span> }).to eq([<span class=hljs-number>307</span>, {<span class=hljs-string>"x-reproxy-url"</span>=><span class=hljs-string>"/bazbaz/baz"</span>}, []]) env = { <span class=hljs-string>'PATH_INFO'</span> => <span class=hljs-string>'/foobar/baz'</span>, <span class=hljs-string>'XXX'</span> => <span class=hljs-literal>false</span> } expect(RewriteRules.rewrite(env) { <span class=hljs-keyword>if</span> env[<span class=hljs-string>'XXX'</span>] rewrite %r{^<span class=hljs-regexp>/foobar/</span>}, <span class=hljs-string>'/bazbaz/'</span> <span class=hljs-keyword>end</span> }).to eq([<span class=hljs-number>399</span>, {}, []]) <span class=hljs-keyword>end</span> <span class=hljs-keyword>end</span></pre> </section> <section class=level-1> <h3>ところで</h3> <p>rewrite ルールが ruby で書けるということは、すなわち自由にテスト可能であることを意味します。Apache の RewriteRule や nginx の rewrite をテストするのはかなり面倒なので、かなり強力で嬉しい感じがします。</p> </section> <ol itemscope itemtype=http://schema.org/BreadcrumbList><li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem><a href=/ itemprop=item><span itemprop=name>トップ</span></a> <meta content=1 itemprop=position> </li> <li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem> <a href="/tech/" itemprop=item><span itemprop=name>tech</span></a> <meta content=2 itemprop=position> </li> <li itemprop=itemListElement itemscope itemtype=http://schema.org/ListItem> <a href="https://lowreal.net/2016/04/05/2" itemprop=item><span itemprop=name>nginx の rewrite ルールっぽく h2o の mruby でリクエストの rewrite を行う</span></a> <meta content=3 itemprop=position> </li> </ol> </div> <div class="content similar-entries"> </div> <div class=social> <span class=hatena-star></span> <p class=share-buttons> <a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Flowreal.net%2F2016%2F04%2F05%2F2" class=share-button rel="noopener nofollow" onclick='ga("send","social","Facebook","Share","https://lowreal.net/2016/04/05/2")' style=background:#3b5998 target=_blank> <img alt=Facebook height=18 src=/images/sharebuttons/FB-f-Logo__white_50.png width=18> </a> <a href="https://bsky.app/intent/compose?text=nginx%20%E3%81%AE%20rewrite%20%E3%83%AB%E3%83%BC%E3%83%AB%E3%81%A3%E3%81%BD%E3%81%8F%20h2o%20%E3%81%AE%20mruby%20%E3%81%A7%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%AE%20rewrite%20%E3%82%92%E8%A1%8C%E3%81%86%20https%3A%2F%2Flowreal.net%2F2016%2F04%2F05%2F2" class=share-button rel="noopener nofollow" onclick='ga("send","social","Bluesky","Share","https://lowreal.net/2016/04/05/2")' style=background:#efefef target=_blank> <img alt=Bluesky height=40 src=/images/bluesky_media_kit_logo_svgs.svg width=40> </a> <a href="http://b.hatena.ne.jp/add?url=https%3A%2F%2Flowreal.net%2F2016%2F04%2F05%2F2" class=share-button rel="noopener nofollow" onclick='ga("send","social","Hatena::Bookmark","Share","https://lowreal.net/2016/04/05/2")' style=background:#00a4de target=_blank> <img alt=はてなブックマーク height=40 src=/images/sharebuttons/hatenabookmark-logomark.svg width=40> </a> </p> </div> </article> </div> <div class=pager> </div> </div> <footer id=global-footer> <h2>書いている人</h2> <div class=author> <div class=image> <img alt=Photo height=160 src=/images/profile.jpg width=160 loading=lazy> </div> <div class=desc> <p> cho45 (<a href=https://www.lowreal.net/ rel=author>www.lowreal.net</a>) <<a href=mailto:cho45@lowreal.net>cho45@lowreal.net</a>> </p> <p> JavaScript, Perl, Ruby, HTML, CSS, Web etc </p> <p> <a href=https://github.com/cho45 rel=nofollow class="button github-button" onclick='ga("send","social","GitHub","Follow","cho45")'><i></i> <span class=label> Follow <b>@cho45</b> </span> </a> </p> <p> <a href=/archive>アーカイブ</a> </p> </div> </div> </footer>