<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>freedom-man.com</title><link>https://blog.freedom-man.com/index.html</link><description>Recent content on freedom-man.com</description><generator>Hugo</generator><language>ja</language><lastBuildDate>Tue, 30 Dec 2025 21:15:00 +0900</lastBuildDate><atom:link href="https://blog.freedom-man.com/feed.xml" rel="self" type="application/rss+xml"/><item><title>2025年の振り返り</title><link>https://blog.freedom-man.com/2025-summary.html</link><pubDate>Tue, 30 Dec 2025 21:15:00 +0900</pubDate><guid>https://blog.freedom-man.com/2025-summary.html</guid><description>&lt;p>今年もええ感じに振り返っていくよ！&lt;/p>
&lt;h2 id="仕事">仕事&lt;/h2>
&lt;p>今年やった主な仕事の記事はこちら&lt;/p>
&lt;p>&lt;a href="https://tech.bm-sms.co.jp/entry/2025/12/08/110000">人材紹介サービス向け社内基盤 Career Portal の技術紹介&lt;/a>&lt;/p>
&lt;p>ざっくりいうと社内システム周りを中心にエンジニアリングしていた。
Google Cloud, Next.js, Prisma, Zod, FastAPI など今まであまり触ったこと無い技術を経験できたのがとても良かった。&lt;/p>
&lt;p>それ以外だと、既存サービスのフロントエンド改善もやっていて、ViteによるJSビルド、Vitest・Alpine.js・Biome・TypeScriptの導入、不要コード削除などなど相変わらず色々やっていたり。おかげさまでレガシーフロントエンド改善も得意技になった感じ。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/2024-summary">2024年の振り返り&lt;/a> で&lt;/p>
&lt;pre tabindex="0">&lt;code>ビジネス理解や業務理解を高めるところがまだ全然できていない
&lt;/code>&lt;/pre>&lt;p>と書いたのだが、今年はビジネス理解・業務理解をかなり深めれた一年だったと思う。このビジネス理解・業務理解のプロセスが非常に面白かったのと、自身のエンジニアリングに対する考え方がもう一段階ブラッシュアップされた感じもあり、得るものが大きかったように思う。&lt;/p>
&lt;p>一方で、技術的なスケールといった課題に対しては行動量・成果ともにほとんどできなかった。スタッフエンジニアの４タイプでいうところのソルバーを相変わらずやっていた感じで、当初想定していたテックリード・アーキテクトあたりは全くできなかったのが残念。もうちょっと自分で動けるところはあったかもしれないが、開発から離れてしまった領域のテックリーディングは中々厳しく、開発しているサービスのテックリーディングの割合は少なかった（ソルバーの割合を強くしていくのが良いと判断した）という感じでなかなか難しい。&lt;/p>
&lt;p>そもそも、この４タイプで考え過ぎてしまうこと自体がナンセンスな感じもしており、「業務理解」「ビジネス構造の理解」の上でステークホルダーコミュニケーションを含めた「プロジェクトリーディング」「プロダクトリーディング」があり、これらの能力を各人が身につけることが大事なのでは？という気持ちが強い。もちろんそれらを満たすのがスタッフエンジニアなのかもしれないんだけど、上記の能力を身に着けたうえでどこに比重を置くかが４タイプの違いでしかない感じがしている。&lt;/p>
&lt;p>という示唆を与えてくれた貴重な１年だった。&lt;/p>
&lt;h2 id="アウトプット">アウトプット&lt;/h2>
&lt;p>今年は &lt;a href="https://fortee.jp/phperkaigi-2025/proposal/fbcca06d-c654-4df9-b51a-8390b30e1ad7">PHPerKaigi&lt;/a> に登壇した。PHPerKaigiは久々の参加・登壇になったが、Alpine.js周りのニッチな話をめっちゃしたかったのでCfP通って嬉しいし発表できて良かった！&lt;/p>
&lt;p>今年は（というか下半期は）自分のブログをかなり書いた。ソフトスキル面で色々と思っていることを公私ともにダンプしていなかったり、今時点での考え方をダンプしていくことは考えの整理など有用だと感じたのが主なモチベーション。また、ハードスキル面もネタが豊富にあるのにアウトプットする習慣がなくなっていたというのもある。11月以降はだいぶ失速したけど色々書けて楽しかった。&lt;/p>
&lt;p>来年も登壇・ブログなどアウトプット量を増やせていけると良いなぁ。&lt;/p>
&lt;h2 id="育児">育児&lt;/h2>
&lt;p>相変わらず楽しい。運動能力や言語能力が上がったり食べれるものが増えるようになったりと楽しみの幅が広がったように思う。喋れるようになった分色々大変というのはあるけど…ｗ&lt;/p>
&lt;p>昨年12月は喘息で入院してたけど、今年は喘息の発作みたいなのはほとんど出ず、体調的にも特に問題なく安定して過ごせたのがとても良かった。旅行もたくさん行けた！&lt;/p>
&lt;h2 id="旅行">旅行&lt;/h2>
&lt;p>箱根、横浜（中華街側）、鬼怒川（with 母A）、沖縄、甲府、伊豆（with 母B）、ディズニーランド、横浜(みなとみらい側)、という感じでたくさん行った。&lt;/p>
&lt;p>横浜・ディスニーは日帰りで行ける位置なのだが移動のストレスも結構あるし現地でゆったりしたかったので泊まってみたのだが、これが結構良かった。移動距離も旅行にしては短く、ホテルや周辺コンテンツが充実していたり、何か忘れても何とかなる安心感もとても良い…ｗ&lt;/p>
&lt;p>ディズニーシーはここ数年で２回ほど行っていたんだけど、ランドの方は25年ぶりくらいに行った。懐かしさを感じたりシーとのコンセプトの違いを感じながら、普通に楽しめた。パレードはランドの方が好きかも。建造物とか雰囲気はシーが好きなのでシーもまた行きたいなぁ。ミラコスタ泊まりたい。&lt;/p>
&lt;p>鬼怒川はスペーシアX、伊豆はサフィール踊り子の個室席を使った。個室の電車は本当に居心地が良いし、小さい子連れだと発する音が気にならないのでストレスが少ない。サフィール踊り子は海沿いなので海を見ながら移動できたりしてとても体験が良い。スペーシアXは海のコンテンツは無いものの、コクピットスイートというVIPな個室席があって超オススメ。どちらもホテルや航空機のVIPな席よりも遥かに安く利用できるので、移動で利用できるタイミングがある方はぜひ…！！&lt;/p>
&lt;p>沖縄はオーシャンビューなホテルに泊まってマジ最高だった。他の旅行に比べると移動が大変（飛行機で2〜3時間、陸路でプラス2時間くらい）だったけどまぁ何とかなった…けどやっぱり大変だった。でも毎年何かしら南国には行きたいと思うくらいには本当に楽しかった。&lt;/p>
&lt;p>ディズニーも伊豆も横浜もオーシャンビューな部屋だったんだけど、意外と飽きることなくいろんな海を堪能できたし、朝起きて海見れたり海辺を散歩できたりするのはマジで体験が良かった。&lt;/p>
&lt;p>部屋からきれいなお庭が見えて、部屋からその庭の鯉に餌を上げれるような素敵な部屋に泊まったりもして、そういう風情のある旅館も良かった。&lt;/p>
&lt;p>親孝行的な旅行ができたのものよかった。自分達がこれから親孝行できる期間のことを考えると年１回ずつくらいは一緒に行けると良いなぁと思っていたり。&lt;/p>
&lt;p>来年は海外とか行けるんじゃないかと思いつつ未定。国内外問わず月１くらいでいけると良いなぁ。貸別荘系も気になっているし、行けていない地域もたくさんあるのでどんどん行きたい。&lt;/p>
&lt;p>とまぁ色々パッション持って書けるくらいには旅行が楽しいフェーズだったりする。
海外ももちろん行きたいんだけど、日本の旅館のクオリティが本当に高くて、一休とか見てると国内だけでもかなり良い宿があって時間とお金が足りない。これといった趣味が無い自分にとっては、もはや旅行のために働いているといっても良いかもしれない。&lt;/p>
&lt;h2 id="飲み会">飲み会&lt;/h2>
&lt;p>昨年は会社の飲み会は１回だけあったっきりで歓迎会（自分のも含む）・送別会・忘年会・新年会がなくてアレだなぁと思って、今年の２月くらいに自分が飲み会を企画したりした。で、そのあたりを皮切りに、というかそのあとグループでちゃんとそういうのをやる体制が整ったり、飲み会を企画してくれる人が入社してくれたのもあり、飲み会をたくさんやった。&lt;/p>
&lt;p>結果、会社の飲み会は8〜9回くらいやっていて、プライベートはそれ以上という感じでここ数年で一番飲み会をやった年になった。ちょくちょく体調不良とか予定合わずで休んだりしたけどそれでも結構多かった…ｗ&lt;/p>
&lt;p>会社もプライベートも誘われるのはやっぱり嬉しいのでついつい参加しちゃいますねぇ。
というのとやっぱり飲みながらじゃないと聞けない、話せないような話はそれなりにあるもので、そういう意味でも貴重な機会だし大事にしたい。&lt;/p>
&lt;h2 id="今年の振り返り来年に向けて">今年の振り返り＆来年に向けて&lt;/h2>
&lt;p>仕事では社内の人と飲みに行ったり仕事での関わりが増える中で、コミュニケーションとビジネス構造と業務理解がいかに大事かを思い知らされた１年だったように思う。これは自分のエンジニア観が少し変わったかもしれない、というくらいにはインパクトがあった。&lt;/p>
&lt;p>あと知っている人の体調があれこれという話を聞いたりして、明日は我が身だし１日１日マジで大切に生きないといけないなぁと。冗談でも悲観的でもなくいつ何が起こるかわからない、ということをどこか頭の片隅に置かないといけないなと割と真剣に思っていたりする。&lt;/p>
&lt;p>いずれにしてもワクワクやパッションが自分の原動力でありキャリアの源泉なので大事にしていきたいし、そういったワクワクやパッションを積極的に見つけていきたい。&lt;/p>
&lt;p>あとは色んなところに旅行したい！！！&lt;/p>
&lt;br/>
ということで今年も大変お世話になりました！&lt;br/>
来年もよろしくお願いいたしまっす！！</description></item><item><title>Salesforceはなぜ負債になりやすいのか</title><link>https://blog.freedom-man.com/why_salesforce_tech_dept.html</link><pubDate>Thu, 20 Nov 2025 22:05:00 +0900</pubDate><guid>https://blog.freedom-man.com/why_salesforce_tech_dept.html</guid><description>&lt;p>&lt;strong>※Salesforceを悪く言うつもりは全く無く、使い方を間違えなければとても良いツールだと思うし、何を使っても使い方と適材適所ですよね、という話です…！&lt;/strong>&lt;/p>
&lt;p>Salesforceの負債の95%くらいは以下の3つの機能・特徴にあると思っています。&lt;/p>
&lt;ol>
&lt;li>DMLをフックとした機能全般&lt;/li>
&lt;li>データの取り回しのしづらさ&lt;/li>
&lt;li>Apex/VF/LWCなどの開発・保守性が悪くなりがちな機能&lt;/li>
&lt;/ol>
&lt;h2 id="1-dmlをフックとした機能全般">1. DMLをフックとした機能全般&lt;/h2>
&lt;p>Salesforceに限らずDMLをフックとした機能は処理が追いづらく、影響範囲が読めないため保守性の悪化につながりやすいです。&lt;/p>
&lt;p>Salesforceだとワークフロールール/プロセスビルダー/フロー/トリガーが該当しますし、Salesforce以外だとRails / ActiveRecordで言うところのcallback、Laravel / Eloquent でいうところのモデルイベント、DBでいうところのトリガーになります。&lt;/p>
&lt;p>Salesforceだとノーコード・プロコードの機能が混在していてさらに処理が追いづらく、それらの処理が互いに作用してうまく動かないこともよくあります。トリガーが２回評価されたり、評価順による不具合発生もよくあります。フローのようなノーコード機能だとテストコードを書かないことがほとんどなので不具合も発生しやすいです。&lt;/p>
&lt;p>Salesforce以外の場合はDMLフックの機能を利用せず、DMLと一緒にベタに処理を記述するというアプローチができます。Laravelだとこんな感じでコントローラなどに処理を書いていく形になります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$attr&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">sendMessage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>対象DML全てで共通化できないデメリットはありますが、処理の追いやすさと不具合の発生しづらさという意味では許容できるトレードオフなのかなと思っています。&lt;/p>
&lt;p>では、Salesforceではどうなのかというと、VF/LWCなどApexが記述できる &lt;code>カスタムなページ&lt;/code> や &lt;code>カスタムのAPI&lt;/code> であれば対応できます。一方で、Salesforceの &lt;strong>基本&lt;/strong> は標準機能である「一覧画面」「詳細画面」「作成・編集画面」　です。全てのオブジェクトでカスタムページを作って対応するのはとてもコストが高くSalesforceの良さを活かしきれません。そのため、画面に関しては標準機能を使って、それでも実現できないビジネスロジックはDMLフックの機能で実現するのがSalesforceの一般的なプラクティスです。データインポートウィザードやデータローダーによる一括作成・更新などのユースケースにも対応できるため、そこまでロジックが複雑でなければ比較的安牌な選択肢とも言えます。&lt;/p>
&lt;p>しかしながら、前述のようにロジックが肥大化したりいろんな場所に無秩序に実装されたりすると負債化するのと、途中でDMLフック方式からカスタムページ形式に移行するのは腕力・体力のいる作業になるため、DMLフックの力学が強く働いてしまいます。テストコードのない処理に対して振る舞いを変えずにノーコードをコードに置き換えないといけない、という難しさは容易に想像がつくのではないかと思います。&lt;/p>
&lt;h2 id="2-データの取り回しのしづらさ">2. データの取り回しのしづらさ&lt;/h2>
&lt;p>Salesforceの標準機能の詳細画面では1:N前提の関連表示しかありません。そのため、1:1でテーブル切って、詳細画面には親テーブルの項目と並列で項目を表示する、といった表現ができません。また、レポート機能では1:1の参照として項目を横並びに表示することが実質的&lt;sup id="fnref:1">&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref">1&lt;/a>&lt;/sup>にできません。&lt;/p>
&lt;p>以上から、Webで言う1:1でテーブル分割した方が良いようなケースにおいても、1テーブルに全てまとめた方がSalesforceとしては取り回しが良いことになります。こうして1テーブルに項目が大量に詰め込まれるという力学が働くことになります。&lt;/p>
&lt;p>データ移行に関してもWebと比べると難易度が高いです。一般的なRDBだと &lt;code>UPDATE xxx&lt;/code> &lt;code>INSERT INTO ... SELECT ...&lt;/code> のような一括更新の作業は考慮事項の多さはあれど、手順としてそこまで複雑になるケースは少ないような気がします。&lt;/p>
&lt;p>一方、Salesforceはこれらの一括更新をするにはデータインポートウィザードやデータローダーを使ってCSVでそれぞれのレコードを入力する必要があり、移行作業の複雑さが増える傾向にあります。また一時テーブルを作るような操作も実質的に難しいので取れる選択肢が多くありません。なにかあったときにPITRやDBインスタンスから復元するといったこともできません。フルバックアップも厳しいです。また、オブジェクトが各機能と密結合だったり、影響範囲を特定する難易度が高かったりと、Webでは「難易度高い」案件もSalesforceでは「実質不可能」になることも少なくないです。&lt;/p>
&lt;h2 id="3-apexvflwcなどの開発保守性が悪くなりがちな機能">3. Apex/VF/LWCなどの開発・保守性が悪くなりがちな機能&lt;/h2>
&lt;p>Apex/VF/LWCいずれもプロプライエタリな技術なため、Webな人がコードを読みづらい、あるいはスキルポータビリティが低くなる傾向があります。&lt;/p>
&lt;p>VF/LWCではReactなどの技術スタックで記述することが可能ですが、相当技術感度が高い組織じゃない限りは採用されていない気がします。&lt;sup id="fnref:2">&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref">2&lt;/a>&lt;/sup>&lt;/p>
&lt;p>Apex・Visualforce・LWC ・SOQL・ガバナなどの制約によりコードの保守性が悪くなる傾向もあります。ライブラリなどのエコシステムも育っているとは言い難く、Web開発よりは導入ハードルが高くなりがちです。&lt;/p>
&lt;div class="footnotes" role="doc-endnotes">
&lt;hr>
&lt;ol>
&lt;li id="fn:1">
&lt;p>「実質的に」というのは頑張ればできるんだけど実用に向かないという意味です。&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;li id="fn:2">
&lt;p>&lt;a href="https://rajaraodv.medium.com/developing-react-redux-apps-in-salesforce-s-visualforce-3ad7be560d1c">https://rajaraodv.medium.com/developing-react-redux-apps-in-salesforce-s-visualforce-3ad7be560d1c&lt;/a>&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink">&amp;#x21a9;&amp;#xfe0e;&lt;/a>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/div></description></item><item><title>前提を変える力</title><link>https://blog.freedom-man.com/change_the_premise.html</link><pubDate>Sat, 08 Nov 2025 22:20:00 +0900</pubDate><guid>https://blog.freedom-man.com/change_the_premise.html</guid><description>&lt;p>前提を変える力って大事だなぁと、ふと思ったので駄文を書く。&lt;/p>
&lt;h2 id="前提を変えれないと戦略を間違う">前提を変えれないと戦略を間違う&lt;/h2>
&lt;p>アプリケーションコードに何百行・何千行の関数のような負債があったとする。そのアプリケーションにはテストコードがない。リファクタリングをしたいが、どうすれば良いか。&lt;/p>
&lt;ul>
&lt;li>A. 頑張ってリファクタリングする。手動でテストをする。&lt;/li>
&lt;li>B. アプリケーションを捨てて新規に作り直す。&lt;/li>
&lt;li>C. 周辺のテストコードを書く。そしてリファクタリングする。&lt;/li>
&lt;/ul>
&lt;p>ご存知のとおりAやBは茨の道だ。もちろん状況によっては選択しても良い。ただ、Cという選択肢を検討せずにAやBを選択するのは良くない。
Cはテストコードを書くことによって「テストコードがない」という前提を変えている。&lt;/p>
&lt;p>このように前提を変えれることを知らずに、あるいは前提を変えることを考えずに判断してしまうケースは多々ある。インフラを知らないエンジニアが、インフラで解決すべき課題をアプリケーション側で無理やり解決する、あるいはその逆のパターンはよくある話だ。&lt;/p>
&lt;h2 id="フルスタックとフルサイクル">フルスタックとフルサイクル&lt;/h2>
&lt;p>前提を変えれるかどうかの勘所は経験やスキルに強く依存している。
たとえばフロントエンドもサーバーサイドもインフラもわかるフルスタックエンジニアは前提を変えやすい。アーキテクチャを正確に理解し、解決手段の引き出しが多く、前提を変えれることを知っているからだ。&lt;/p>
&lt;p>フルスタックでなくても、サーバーサイドエンジニアがフロントエンド・インフラ担当のエンジニアと密にコミュニケーションを取れれば、前提を変えることができる。企画・要件定義からリリース・分析・運用まで入れば、より大きく前提を変えることができる。これがフルサイクルエンジニアと呼ばれるロール・スキルなのだと思っている。&lt;/p>
&lt;h2 id="技術に依らない">技術に依らない&lt;/h2>
&lt;p>そしてこれはエンジニアリングに依らない。ビジネス・組織・業務プロセスなどあらゆる領域で変えることができる前提がある。前提を変えるために必要なステップがある。それらの引き出しが仕事力と言われるものになるのだろうし、ビジネスを力強く推進できる能力になるのだと思っている。あるいはビジネスとは前提を変えることなのかもしれないなぁ、とか。&lt;/p></description></item><item><title>たたき台のお作法</title><link>https://blog.freedom-man.com/draft_manners.html</link><pubDate>Mon, 03 Nov 2025 22:25:00 +0900</pubDate><guid>https://blog.freedom-man.com/draft_manners.html</guid><description>&lt;p>物事を前に進めるうえで、たたき台を作るのは大事。&lt;/p>
&lt;p>ということで、自分がたたき台を作る上で気をつけていることなどを雑に書いていく。&lt;/p>
&lt;h2 id="たたき台がなぜ必要なのか">たたき台がなぜ必要なのか&lt;/h2>
&lt;p>単に最終決定に対する「原稿」の役割もあるが、それ以外にも&lt;/p>
&lt;ul>
&lt;li>テキスト・図によって認識が揃いやすくなる。&lt;/li>
&lt;li>認識が揃うことで議論が進みやすくなる。次にやるべきことが見えやすくなる。&lt;/li>
&lt;li>作った人が思考が整理できる。&lt;/li>
&lt;/ul>
&lt;p>といった効果が期待できる。たたき台が無いと空中線になり、議論の前提や発言の意図を揃えることに時間を使い、議論が進みづらくなる。&lt;/p>
&lt;h2 id="何を使ってたたき台を作るか">何を使ってたたき台を作るか&lt;/h2>
&lt;h3 id="タスクを洗い出すためのたたき台">タスクを洗い出すためのたたき台&lt;/h3>
&lt;p>Google DocsやWikiなどにタスクを一覧化して書いてみる。Google Docsだとコメントを入れられるので議論しやすいが、最終的な決定を追いづらいのでそれはWikiに残しておくと良さそう。ちなみにタスク以外にも議題を予め書いておくのも「たたき台」だと思っている。&lt;/p>
&lt;h3 id="要件定義のためのたたき台">要件定義のためのたたき台&lt;/h3>
&lt;p>何か新しい画面やアプリケーションを提供するのであればfigmaやmiroなどのツールを使って画面・フローを書いてみて、それを共有し認識を揃えたり課題点を洗い出していく。
最近では生成AIを使って簡単にデモアプリケーションを作成できるので、そういったものを使って動くたたき台を作っていくのも良い。この段階のたたき台では「絵」が大事だったりする。&lt;/p>
&lt;h3 id="設計を議論するためのたたき台">設計を議論するためのたたき台&lt;/h3>
&lt;p>要件定義で確定した画面や処理を実装するための詳細設計をしていくためのたたき台。
テーブルやAPI定義、シーケンス図が主なたたき台・成果物になっていく。&lt;/p>
&lt;p>API定義はwikiやOpenAPI、実装からAPI定義を記述できるものは簡易実装でも良い。
テーブル定義もwikiや実際のマイグレーションコードでたたき台を作っていく形になる。
シーケンス図は &lt;a href="http://draw.io">draw.io&lt;/a> を使うと簡単に記述できる。「絵」や「表」をメインにしつつ文字列で詳細を補足していくイメージ。&lt;/p>
&lt;h2 id="作ったたたき台を自分の言葉で話せるようにする">作った「たたき台」を自分の言葉で話せるようにする&lt;/h2>
&lt;p>生成AIがこういうの出してきました！で、自分の脳を通さずにたたき台を出すのはダメ。
自分の言葉で話せることが大事。初版は自分で作って、観点が足りないかどうかを生成AIにレビューしてもらうのが良さそう。&lt;/p>
&lt;h2 id="作ったたたき台にこだわらない">作った「たたき台」にこだわらない&lt;/h2>
&lt;p>たたき台なので、やっぱ全然違うとなって全部破棄されたとしても気にしない。
認識を揃えるのに価値が有るので破棄されることはどうでも良い。&lt;/p>
&lt;h2 id="細部にこだわらないスピードが大事">細部にこだわらない。スピードが大事&lt;/h2>
&lt;p>議論を進めるためのものなのでスピードが大事。議論の中で細部を補足したり決めていけば良い。&lt;/p></description></item><item><title>ビジネスモデルと労働集約</title><link>https://blog.freedom-man.com/business_model_labor_intensive.html</link><pubDate>Mon, 03 Nov 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/business_model_labor_intensive.html</guid><description>&lt;p>ビジネスモデルと労働集約について考えを書いてみた。いちエンジニアの戯言です。&lt;/p>
&lt;h2 id="it業界におけるビジネスモデル">IT業界におけるビジネスモデル&lt;/h2>
&lt;p>IT業界における受託開発とSaaSのような自社サービスを例に出して考えてみる。&lt;/p>
&lt;p>受託開発は、営業が案件を受注し、請負契約を結んで成果物を納品して売上が発生する。保守のような売上が毎月発生するような場合もあるが、基本的に新規案件・追加案件の受注と納品が売上の源泉になる。ということは、営業が案件を受注することも大事だし、デリバリーする部隊も大事ということで、「人」が軸になってくる。管理コストなどはさておき「人」を増やせば利益が上がる、まさに労働集約型のビジネスと言える。納期やコストを守り、品質の高いシステムを納品した結果、利益率や売上が上がるかもしれないが、トップラインを継続的に上げていくには「人」や「単価」を上げていくしかないように思える。&lt;/p>
&lt;p>SaaSの自社サービスだと、営業が案件を受注するところは同じだが、サービス利用費（初期・月額）として毎月売上が発生するのが違う部分だ。売上が継続的に発生するため、仮にチャーンレートが0%であれば追加の営業をしなくても売上が発生するし、システム保守・運用費も受託開発などの初期構築費用と比べると低コスト・低リスクなため、「システム」が重要になる。システムが安定的に動いたり、継続的な機能改善を行っていくことでチャーンレートが下がり、売上貢献につながる。受託開発と比較すると労働集約性は低くなる。&lt;br>
とはいえ、チャーンはある程度発生するし、トップラインを伸ばすためには営業は引き続き重要だ。ほとんどのSaaSがSales Led Growthだ。継続して利用していただくためにはカスタマーサクセスやカスタマーサポートのような組織も必要になってくるかもしれない。ということで引き続き「人」は大事なのである。&lt;/p>
&lt;p>このようにビジネスモデルがある程度「労働集約性」を決定づけてしまうように思えてきていて、ビジネスモデルの重要性を感じていたりする。&lt;/p>
&lt;h2 id="ソフトウェアエンジニアとしてこれをどう解釈して動いていくべきか">ソフトウェアエンジニアとしてこれをどう解釈して動いていくべきか&lt;/h2>
&lt;p>とはいえビジネス・ビジネスモデルを自分がどうこうできる感じでも無い。なんか良いアイデアがあるわけでもなく、正直あったとしても遂行できる感じもしない。&lt;/p>
&lt;p>ということで、戦術であるところの「システム開発」を一生懸命頑張っていくしか無くて、質の高い課題を解決して、利益を出せる体質にするのがエンジニアとしての責務とも思う。エンジニアリングのケイパビリティを上げていくことは、新しいビジネスを作っていく上でも重要なはずだ。&lt;/p>
&lt;p>また「労働集約」は悪いことではないと思っている。ビジネスを成り立たせるには結局「人」が一番大事、ということなのかもしれない。その上で、レバレッジの効きやすいエンジニアリングをどう活かしていくかを各組織・各プロダクトでゼロベースで考えていく必要がある。&lt;/p>
&lt;h2 id="余談">余談&lt;/h2>
&lt;p>必要とされるスキルや技術もこのビジネスモデルに左右されていそうな気がする。
受託開発はデリバリーが大事なので初期開発スキルやプロジェクトマネジメントスキルが必要になり、自社サービスは保守が大事なので運用保守の開発スキル、継続的デリバリーといったスキルが必要になる。技術も浅く広くなのか、深く狭くなのか、という違いも出てくる。&lt;/p></description></item><item><title>DBテストのデータ管理はトランザクション/ロールバック方式にしたい</title><link>https://blog.freedom-man.com/transaction_for_db_testing.html</link><pubDate>Sat, 01 Nov 2025 22:25:00 +0900</pubDate><guid>https://blog.freedom-man.com/transaction_for_db_testing.html</guid><description>&lt;p>自動テストにおいて、信頼性を上げるためにDBはモックではなく実際のDBを使ってテストをしたい。&lt;/p>
&lt;p>その場合、データ管理はテストケースの都度&lt;/p>
&lt;ol>
&lt;li>データベース・テーブルを再作成（DROP/CREATE）する&lt;/li>
&lt;li>テーブルデータを再作成（DELETE/TRUNCATE/INSERT）する&lt;/li>
&lt;li>テスト開始前にトランザクションを開始し、テスト終了後にロールバックする&lt;/li>
&lt;/ol>
&lt;p>といった方法を取っていることが多いと思う。&lt;/p>
&lt;p>この方式で &lt;code>3&lt;/code> のトランザクション/ロールバック方式のデータ管理の採用を第一に検討すべきだよね、という話を書いていく。&lt;/p>
&lt;h2 id="理由1-高速である">理由1: 高速である&lt;/h2>
&lt;p>DROP/DELETE/TRUNCATE/CREATEは実行コストが高く、一般的には遅い操作となる。
インメモリDBを使う方法もあるが、言語やライブラリの実装に強く依存するし、結局マイグレーションにコストがかかりがちだ。&lt;/p>
&lt;p>その点、トランザクション/ロールバック方式は一般的な高速な操作であり、テスト時間が増えがちなDBテストにおいては大きなメリットだ。&lt;/p>
&lt;h2 id="理由2-並列性が高い">理由2: 並列性が高い&lt;/h2>
&lt;p>トランザクション分離レベルに依るが、ダーティリードでなければトランザクション内に作成されたデータは他のトランザクションから見ることができないので、トランザクション/ロールバック方式は並列実行がしやすい。&lt;/p>
&lt;p>他の方式だと並列に実行する場合はデータベースを予め作成する必要があるし、並列数＝データベース数となってしまう。&lt;/p>
&lt;h2 id="理由3-データのcleanupが簡単">理由3: データのcleanupが簡単&lt;/h2>
&lt;p>トランザクション/ロールバック方式であればロールバックするだけでデータがリセットされる。そのためテストの安定性も上がりやすい。&lt;/p>
&lt;p>他の方式だと、データベースやデータのcleanupを明示的に行う必要があり、やや面倒だし安定性も下がりがち。&lt;/p>
&lt;h2 id="各言語フレームワークでは何を使うか">各言語/フレームワークでは何を使うか&lt;/h2>
&lt;p>PHP/Laravelでは &lt;code>DatabaseTransactions&lt;/code> トレイト&lt;br>
TypeScript/Prismaでは &lt;a href="https://github.com/Quramy/jest-prisma">Quramy/jest-prisma&lt;/a>&lt;br>
Goだと &lt;a href="https://github.com/DATA-DOG/go-txdb">DATA-DOG/go-txdb&lt;/a>&lt;/p>
&lt;p>あたりを利用することになりそう。&lt;/p>
&lt;p>ライブラリによってはトランザクションのネストに対応しておらず、結果としてアプリケーションのトランザクション処理に対応できないケースがあるので選定するときには注意が必要。&lt;/p></description></item><item><title>[小ネタ] Laravelではdisplay_errorsはOffになる</title><link>https://blog.freedom-man.com/laravel_display_errors.html</link><pubDate>Thu, 23 Oct 2025 21:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_display_errors.html</guid><description>&lt;p>Laravelではテスト環境以外ではdisplay_errorsが自動でOffになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">environment&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;testing&amp;#39;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">ini_set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;display_errors&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Off&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/570c154e7970193862b5c12bc13c3393e42949a1/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php#L56">https://github.com/laravel/framework/blob/570c154e7970193862b5c12bc13c3393e42949a1/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php#L56&lt;/a>&lt;/p>
&lt;p>その代わり &lt;code>set_exception_handler&lt;/code> や &lt;code>set_error_handler&lt;/code> を使ってcatchされていないExceptionが適切にハンドリングされます。&lt;/p></description></item><item><title>PHPStan導入・運用ガイド</title><link>https://blog.freedom-man.com/phpstan.html</link><pubDate>Tue, 21 Oct 2025 22:25:00 +0900</pubDate><guid>https://blog.freedom-man.com/phpstan.html</guid><description>&lt;p>どの会社でも同じようなwikiを書いているので、ここにまとめておきます。&lt;/p>
&lt;h2 id="phpstan-とは">&lt;a href="https://phpstan.org/">PHPStan&lt;/a> とは&lt;/h2>
&lt;p>PHPの静的解析ツールで、コードを実行せずにコードを検査できます。
具体的には未定義変数・関数・メソッド・プロパティ・クラスへのアクセス、引数の数・型の間違い、未使用変数・引数・useパラメータ、戻り値の型の不整合など様々なエラーを検知できます。&lt;/p>
&lt;p>例えば以下のようなコードを実際に動作させることなくエラーを検知できます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">someMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">int&lt;/span> &lt;span style="color:#953800">$someArg&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$nodefined&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">// Undefined variable: $nodefined.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$tmp1&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">NoExist&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#57606a">// Instantiated class NoExist not found.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$tmp2&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">noFunction&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#57606a">// Function noFunction not found
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">// Method Hoge::someMethod() should return string but returns int.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">privateMethod&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">fuga&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">// Access to an undefined property Hoge::$fuga
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">hello&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#57606a">// Call to an undefined method Hoge::hello().
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">someMethod&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#57606a">// Method Hoge::someMethod() invoked with 0 parameters, 1 required.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">someMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;123&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">// Parameter #1 $someArg of method Hoge::someMethod() expects int, string given.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">privateMethod&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#57606a">// Call to private method privateMethod() of class Hoge.
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>エラー検知例
&lt;a href="https://phpstan.org/r/cc1142d9-4418-4c88-8848-9aa10c1e3753">https://phpstan.org/r/cc1142d9-4418-4c88-8848-9aa10c1e3753&lt;/a>&lt;/p></description></item><item><title>Rectorの使い方とサンプル</title><link>https://blog.freedom-man.com/rector.html</link><pubDate>Tue, 21 Oct 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/rector.html</guid><description>&lt;p>どの会社でも同じようなwikiを書いているので、ここにまとめておきます。&lt;/p>
&lt;h2 id="rectorとは">Rectorとは&lt;/h2>
&lt;p>PHPの自動リファクタリングができるツールです。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/rectorphp/rector">https://github.com/rectorphp/rector&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://getrector.com/">https://getrector.com/&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>フレームワークのアップグレードによるコードの書き換え、自動型付けなどで活用できます。&lt;/p>
&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>パッケージインストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ composer require rector/rector --dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>実行（設定ファイル &lt;code>rector.php&lt;/code> が存在しない場合は作成される）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ vendor/bin/rector
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Laravel用のRectorプラグイン&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ composer require driftingly/rector-laravel --dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/driftingly/rector-laravel">https://github.com/driftingly/rector-laravel&lt;/a>&lt;/p>
&lt;h2 id="rectorphpサンプル">rector.phpサンプル&lt;/h2>
&lt;h3 id="自動で型付けしたい">自動で型付けしたい&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">declare&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">strict_types&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">Rector\Config\RectorConfig&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">RectorConfig&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">configure&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withPaths&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">__DIR__&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#39;/app&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withImportNames&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">importShortClasses&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withTypeCoverageLevel&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>typeDeclarationsを有効にすると以下のRectorルールが適用されます。
&lt;a href="https://getrector.com/find-rule?rectorSet=core-type-declarations&amp;amp;activeRectorSetGroup=core">https://getrector.com/find-rule?rectorSet=core-type-declarations&amp;amp;activeRectorSetGroup=core&lt;/a>&lt;/p>
&lt;p>withTypeCoverageLevelで段階的な適用もできます。
&lt;a href="https://getrector.com/documentation/levels">https://getrector.com/documentation/levels&lt;/a>&lt;/p>
&lt;p>withImportNamesを入れるとuseも適切に付与してくれます。
&lt;a href="https://getrector.com/documentation/import-names">https://getrector.com/documentation/import-names&lt;/a>&lt;/p>
&lt;h3 id="旧factoryから新factoryに移行したい">旧Factoryから新Factoryに移行したい&lt;/h3>
&lt;p>古いLaravelからバージョンアップするとき限定ですが…&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">declare&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">strict_types&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">Rector\Config\RectorConfig&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">RectorLaravel\Set\LaravelSetList&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">RectorConfig&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">configure&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withPaths&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">__DIR__&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#39;/app&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withImportNames&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">importShortClasses&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withSets&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">LaravelSetList&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">LARAVEL_LEGACY_FACTORIES_TO_CLASSES&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>参考: &lt;a href="https://zenn.dev/zatsuyooo/articles/laravel7-to-8">https://zenn.dev/zatsuyooo/articles/laravel7-to-8&lt;/a>&lt;/p>
&lt;h3 id="ルーティングの記述方法を配列方式に変更">ルーティングの記述方法を配列方式に変更&lt;/h3>
&lt;p>routes.php で &lt;code>'UserController@index'&lt;/code> の形式から &lt;code>[UserController::class, 'index']&lt;/code> の形式に変更したい場合に使う&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">declare&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">strict_types&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">Rector\Config\RectorConfig&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">RectorLaravel\Rector\StaticCall\RouteActionCallableRector&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">RectorConfig&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">configure&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withPaths&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">__DIR__&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#39;/routes&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withImportNames&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">importShortClasses&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withConfiguredRule&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">RouteActionCallableRector&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">RouteActionCallableRector&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">NAMESPACE&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;App\Http\Controllers&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="関連url">関連URL&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://getrector.com/find-rule">https://getrector.com/find-rule&lt;/a>
&lt;ul>
&lt;li>Rectorルールを探すときに活用ください&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://getrector.com/ast">https://getrector.com/ast&lt;/a>
&lt;ul>
&lt;li>カスタムルールを作るときなどASTの構造を知りたいときに便利です&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://getrector.com/demo">https://getrector.com/demo&lt;/a>
&lt;ul>
&lt;li>WebでRectorの動作を確認できるツール&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title>Next.jsのServer ActionsでCloud Tasksを呼び出すときはバンドル対象から除外する</title><link>https://blog.freedom-man.com/nextjs_cloud_tasks.html</link><pubDate>Mon, 20 Oct 2025 22:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/nextjs_cloud_tasks.html</guid><description>&lt;p>Next.jsのServer ActionsでCloud Tasksを呼び出したときにエラーになったのでメモ。&lt;/p>
&lt;p>具体的には以下のような感じでCloud Tasksを呼び出すとエラーになってしまった。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-jsx" data-lang="jsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">CloudTasksClient&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#34;@google-cloud/tasks&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">Home&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">handle&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;use server&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">client&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">CloudTasksClient&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">client&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createTask&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">parent&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">queueName&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">task&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">httpRequest&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...(snip)...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">button&lt;/span> &lt;span style="color:#1f2328">onClick&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">handle&lt;/span>&lt;span style="color:#1f2328">}&amp;gt;&lt;/span>&lt;span style="color:#1f2328">Click&lt;/span> &lt;span style="color:#1f2328">Me&lt;/span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">button&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>発生したエラーは以下の通り&lt;/p>
&lt;pre tabindex="0">&lt;code>Cannot find module &amp;#39;/path/to/my-app/node_modules/@google-cloud/tasks/build/esm/src/v2/cloud_tasks_client_config.json&amp;#39;
&lt;/code>&lt;/pre>&lt;p>webpackでビルドされるとき cloud_tasks_client_config.json が読み取れなくなっているのが原因のようなので、以下のような感じで next.config.ts の &lt;code>serverExternalPackages&lt;/code> に指定することで、バンドル対象から除外されてnode_modules配下のファイルを読み込んでくれるみたいです。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">serverExternalPackages&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;@google-cloud/tasks&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://nextjs.org/docs/app/api-reference/config/next-config-js/serverExternalPackages">https://nextjs.org/docs/app/api-reference/config/next-config-js/serverExternalPackages&lt;/a>&lt;/p>
&lt;p>ちなみに &lt;a href="https://github.com/aertje/cloud-tasks-emulator">aertje/cloud-tasks-emulator&lt;/a> で &lt;code>@grpc/grpc-js&lt;/code> を使っている場合、同様の理由で&lt;/p>
&lt;pre tabindex="0">&lt;code>[TypeError: Channel credentials must be a ChannelCredentials object]
&lt;/code>&lt;/pre>&lt;p>というエラーが発生するので、こちらも追加すればOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">serverExternalPackages&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;@google-cloud/tasks&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;@grpc/grpc-js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>NextAuth.jsで代理ログインを実装する方法</title><link>https://blog.freedom-man.com/nextauth_impersonate_login.html</link><pubDate>Mon, 20 Oct 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/nextauth_impersonate_login.html</guid><description>&lt;p>認証があるアプリケーションを実装しているとき、動作確認を行うため他のユーザになりすましてログインする「代理ログイン」をしたくなることがある。
&lt;a href="https://next-auth.js.org/">NextAuth.js&lt;/a> を認証基盤として利用している場合は、カスタム認証プロバイダとして代理ログイン用の処理を実装することで実現できる。&lt;/p>
&lt;p>PrismaをORMとして使っている場合は以下のようなカスタム認証プロバイダで実装すれば良い。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ts" data-lang="ts">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">CredentialsProvider&lt;/span> &lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#0a3069">&amp;#34;next-auth/providers/credentials&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">prisma&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#0a3069">&amp;#34;@/lib/prisma&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">logger&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#0a3069">&amp;#34;@/lib/logger&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// IDを指定するだけでログインできる認証プロバイダ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">impersonateCredentialsProvider&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">CredentialsProvider&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;impersonation&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">name&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Impersonation&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">credentials&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">targetUserId&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">label&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Target User ID&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">type&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;text&amp;#34;&lt;/span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">developerUserId&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">label&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Developer User ID&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">type&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;text&amp;#34;&lt;/span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#1f2328">authorize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">credentials&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// 必要に応じて環境・権限チェック 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// if (process.env.NEXT_PUBLIC_APP_ENV === &amp;#34;production&amp;#34;) {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// return null;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// バリデーション 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#1f2328">credentials&lt;/span>&lt;span style="color:#0550ae">?&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">targetUserId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">targetUser&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">prisma&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">user&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">findUnique&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">where&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>: &lt;span style="color:#cf222e">credentials.targetUserId&lt;/span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">`Developer &lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">credentials&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">developerUserId&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069"> impersonated user &lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">targetUser&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">email&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">`&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">id&lt;/span>: &lt;span style="color:#cf222e">targetUser.id&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">email&lt;/span>: &lt;span style="color:#cf222e">targetUser.email&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">name&lt;/span>: &lt;span style="color:#cf222e">targetUser.name&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">image&lt;/span>: &lt;span style="color:#cf222e">targetUser.image&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">impersonatedBy&lt;/span>: &lt;span style="color:#cf222e">credentials.developerUserId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">impersonatedAt&lt;/span>: &lt;span style="color:#cf222e">Math.floor&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">Date&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">/&lt;/span> &lt;span style="color:#0550ae">1000&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Impersonation authorization error:&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">error&lt;/span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>認証プロバイダの設定はこんな感じで環境変数を見て切り替える。以下では本番環境では代理ログインプロバイダを無効化している。&lt;/p></description></item><item><title>Cloud RunでCloud SQL接続するときは接続待機が必要</title><link>https://blog.freedom-man.com/cloud_run_wait_for_db.html</link><pubDate>Mon, 20 Oct 2025 21:45:00 +0900</pubDate><guid>https://blog.freedom-man.com/cloud_run_wait_for_db.html</guid><description>&lt;p>Cloud Run JobsでCloud SQL接続 ( &lt;code>/cloudsql/{instance_connection_name}&lt;/code> のUDSを使った接続）を使っている場合、アプリケーションコードからすぐに接続すると以下のような接続エラーが発生するときがある。&lt;/p>
&lt;pre tabindex="0">&lt;code>Can&amp;#39;t reach database server at /cloudsql/{project}:{region}:{instance}:5432
Please make sure your database server is running at /cloudsql/{project}:{region}:{instance}:5432.
&lt;/code>&lt;/pre>&lt;p>検証したところ立ち上がり時の接続のタイムラグがありそうだったので、DB接続待ちのコードを入れれば解消できる。例えば、Node.js / Prismaを使っている場合は、以下のようなコードをアプリケーションコードの事前処理に入れればOK。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ts" data-lang="ts">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">waitForDB() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">retry&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">10&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">// retry count
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">interval&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">5000&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">// retry interval in milliseconds
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">let&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#1f2328">retry&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">i&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">`Attempting to connect to DB (attempt &lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">/&lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">retries&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">)...`&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">prismaClient&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">$queryRaw&lt;/span>&lt;span style="color:#0a3069">`SELECT 1`&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Successfully connected to the database!&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">errorMessage&lt;/span> &lt;span style="color:#0550ae">=&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">error&lt;/span> &lt;span style="color:#cf222e">instanceof&lt;/span> &lt;span style="color:#6639ba">Error&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#1f2328">error.message&lt;/span> : &lt;span style="color:#cf222e">String&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">`Failed to connect to DB: &lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">errorMessage&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">`&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#1f2328">retries&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">`Retrying in &lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">interval&lt;/span> &lt;span style="color:#0550ae">/&lt;/span> &lt;span style="color:#0550ae">1000&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069"> seconds...`&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Promise&lt;/span>&lt;span style="color:#1f2328">((&lt;/span>&lt;span style="color:#1f2328">resolve&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">setTimeout&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">resolve&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">interval&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Max retries reached. Could not connect to the database.&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#1f2328">error&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">// 全ての試行が失敗したらエラーをスロー
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">main() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">waitForDB&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// アプリケーションコード ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>ロールをあえて決めるかどうか</title><link>https://blog.freedom-man.com/define_roles_or_not.html</link><pubDate>Sun, 19 Oct 2025 23:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/define_roles_or_not.html</guid><description>&lt;p>全員がプロダクトの責任を持ったりステークホルダーとのコミュニケーションを等しく行うという意味で &lt;code>リード&lt;/code> という役割を決めずにフラットに進めていったものの、責任者・判断する &lt;code>リード&lt;/code> を決めたほうが効率的に進むことがあったりする。&lt;/p>
&lt;p>フルスタックにバックエンドもフロントエンドもインフラも全部やろう、と進めたものの、インフラ側まで手が回らず、結果としてインフラ担当チームに依頼して進めた方が効率的に進むこともある。フルスタック・フルサイクルにできるエンジニアは実際にほとんどいなくて、各領域で中途半端になって、あまり良くない実装・設計になることもある。そんなわけで、現実的には &lt;code>インフラチーム&lt;/code> &lt;code>データ分析チーム&lt;/code> といった感じでチーム・ロールを分けることが多いと思う。&lt;/p>
&lt;p>チーム内の &lt;code>ロール&lt;/code> において、あえて決めずに行う理想形はありつつも &lt;code>ロール&lt;/code> を決める現実解になりがちだし、組織内の &lt;code>チーム&lt;/code> においても、チームを分けない理想形はあるけど現実的には分けざるを得ないケースが多いと思う。どちらも必要なスキルが不足していることに起因していそうだけど、実際そのスキルを身につけるには結構たいへん（採用も教育もたいへん）なのである。&lt;/p>
&lt;p>ということで個人的にはロールやチームを分けざるを得ないと思っていて、それによって責任の所在が明らかになり物事が進んだりする。一方でサイロ化や無関心みたいなことも発生しがちなので、チームを分けたときの「チーム間共有」、ロールを分けたときの「チーム内共有」といった工夫が必要になる。やっていることを知っているという透明性が大事で、それがある意味フルサイクルになる、的な。&lt;/p></description></item><item><title>Laravelのconfig()のカスタム値は環境依存の値にすべき</title><link>https://blog.freedom-man.com/laravel_config_usage.html</link><pubDate>Sun, 19 Oct 2025 22:15:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_config_usage.html</guid><description>&lt;p>Laravelのカスタムのconfigで環境に依存しない固定値やenum値を書いているコードを見たことがあるが、標準で用意されていないカスタムの値に関しては環境依存の値にすべきである。&lt;/p>
&lt;p>理由としては&lt;/p>
&lt;ul>
&lt;li>&lt;code>config()&lt;/code> 値の型解釈や補完はプラグインに依存する&lt;/li>
&lt;li>config/*.php に値があるため、app/ 配下のコードと距離が遠くなりコードの保守性が下がる&lt;/li>
&lt;/ul>
&lt;p>の2点。&lt;/p>
&lt;p>ということで、固定値であれば普通にその値に従属すべきモデルクラスのconstに定義し、enum値であればPHPのEnumを使えば良い。&lt;/p>
&lt;p>逆に環境依存の値、例えば環境変数の値や環境に依存する値（APP_ENVに間接的に依存する値）は config で管理する。app/ のアプリケーションコードに &lt;code>env()&lt;/code> を直接使うのはNGで &lt;code>config()&lt;/code> を使うのが推奨されているというのが理由。&lt;/p></description></item><item><title>メッセージ配信系バッチ実装ガイドライン</title><link>https://blog.freedom-man.com/message_batch_guideline.html</link><pubDate>Thu, 16 Oct 2025 21:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/message_batch_guideline.html</guid><description>&lt;p>どの会社でもバッチ実装系のガイドラインを書いている気がするので、もうここでまとめて参照させたいな、という意図で公開してみます。Laravelを想定して書いています。&lt;/p>
&lt;h2 id="must-テストを書く">[MUST] テストを書く&lt;/h2>
&lt;p>インシデント時の影響が大きいため、しっかりテストを書くことをオススメします。&lt;/p>
&lt;p>メール送信の場合は &lt;code>Mail&lt;/code> ファサードを使っている場合は簡単にテストが書けます。 それ以外の場合（ショートメッセージなど）はモックが出来るようにモジュールをDIしておくと簡単にテストできます。&lt;/p>
&lt;h2 id="must-dry-runできるようにする">[MUST] dry runできるようにする&lt;/h2>
&lt;p>dry runオプションで実際にメールなどが飛ばないように実装することで、開発・テスト環境でも安心して検証が可能です。本番環境においてもdry-runで送信対象が間違っていないかを確認できて安心です。&lt;/p>
&lt;p>実装イメージ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$dryRun&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">option&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;dry-run&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$customers&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$customer&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...(省略)...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$dryRun&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Log&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;送信対象: xxxx, 本文: xxxx&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">continue&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Mail&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">to&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="should-誰に送信したのかをidなどでロギングしておく">[SHOULD] 誰に送信したのかをIDなどでロギングしておく&lt;/h2>
&lt;p>不具合が発生したときなど誰に送信したのかをトレースできる仕組みがあると便利です。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$customers&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$customer&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...(省略)...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">\Log&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;送信対象: &lt;/span>&lt;span style="color:#0a3069">{&lt;/span>&lt;span style="color:#953800">$customer&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">\Mail&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">to&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="must-初回稼働時は実行に立会ってログの確認を行う">[MUST] 初回稼働時は実行に立会ってログの確認を行う&lt;/h2>
&lt;p>メール送信のインシデントは緊急性が高い可能性があるため、初回稼働時は可能な限りバッチ実行に立会ってログや動作の確認を行ってください。&lt;/p>
&lt;h2 id="should-本番テスト環境で処理を差し替える">[SHOULD] 本番・テスト環境で処理を差し替える&lt;/h2>
&lt;p>メッセージを送信するクラスを共通化した上で、送信する処理を本番環境とそれ以外の環境で処理を差し替えると、本番環境以外ではメッセージが送信されません。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">environment&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">!==&lt;/span> &lt;span style="color:#0a3069">&amp;#39;production&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ロギングや別の送信チャンネルに切り替え
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">\Log&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// メッセージ送信処理
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上記の例だと、実際の送信テストは本番環境でしかできないことに注意してください。&lt;/p>
&lt;h3 id="開発サーバーではmailのドライバーをlogにする">開発サーバーではMailのドライバーをlogにする&lt;/h3>
&lt;p>メール送信の場合は、Mailのドライバーをlogに変更すると、間違って送信してもログに吐かれるだけなので安全です。&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-dotenv" data-lang="dotenv">MAIL_DRIVER=log
&lt;/code>&lt;/pre>&lt;p>テキストメールの場合は実際にメール送信するより検証が容易かもしれません。&lt;/p>
&lt;p>ローカル開発環境では &lt;a href="https://mailpit.axllent.org/">mailpit&lt;/a> などのテストツールを使えば良いと思います。&lt;/p>
&lt;h2 id="must-ホワイトリスト方式のチェックを入れる">[MUST] ホワイトリスト方式のチェックを入れる&lt;/h2>
&lt;p>上記の &lt;code>環境による処理差し替え&lt;/code> との合わせ技になりますが、開発環境においては、事前に環境変数で定義した宛先のみメッセージを送信できるようにすると安全にテストができます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$arrowList&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">config&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;message.allow_list&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">environment&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0a3069">&amp;#39;production&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// メッセージ送信処理: 本番用
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">in_array&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$to&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$arrowList&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// メッセージ送信処理: 開発用
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// エラー or ロギング
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="must-api呼び出しの共通パラメータを環境変数化して切り替え">[MUST] API呼び出しの共通パラメータを環境変数化して切り替え&lt;/h2>
&lt;p>API経由でのメッセージ送信であればAPIエンドポイント（ホスト名）やAPIキーを環境変数化しておきます。&lt;/p></description></item><item><title>Laravelの各環境を視覚的に判別する</title><link>https://blog.freedom-man.com/laravel_dev_mark.html</link><pubDate>Wed, 15 Oct 2025 21:20:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_dev_mark.html</guid><description>&lt;p>Rubyで言うところの &lt;a href="https://github.com/dtaniwaki/rack-dev-mark">rack-dev-mark&lt;/a> 的なものをLaravelで実装したメモ。
パッケージもいくつか見つかるけどサクッと実装できてカスタマイズもしやすいので自前でやってみた。&lt;/p>
&lt;p>具体的には以下のようなミドルウェアを書いてwebなルートに適用すれば良い。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">namespace&lt;/span> &lt;span style="color:#1f2328">App\Http\Middleware&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">DevMark&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">isProduction&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">modifyResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">modifyResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">mixed&lt;/span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">void&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$content&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getContent&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$env&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">strtoupper&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">environment&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$renderedContent&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">HTML&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;style&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> #devmark {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> left: 10px;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> top: 10px;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> position: fixed;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> padding: 5px 8px;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> z-index: 100;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> background-color: green;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> color: white;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> border-radius: 0.5rem;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> display: flex;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> align-items: center;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> justify-content: center;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> font-size: 0.8rem;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> font-weight: 900;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/style&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;div id=&amp;#34;devmark&amp;#34; onclick=&amp;#34;this.style.display = &amp;#39;none&amp;#39;;&amp;#34;&amp;gt;{$env}&amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">HTML&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$pos&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">strripos&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;lt;/body&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$pos&lt;/span> &lt;span style="color:#0550ae">!==&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$content&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">substr&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$pos&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#953800">$renderedContent&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">substr&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$pos&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$content&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$content&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#953800">$renderedContent&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setContent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">headers&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">remove&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;Content-Length&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こんな感じで表示されてクリックすると非表示になる。&lt;/p></description></item><item><title>MVCでええやん</title><link>https://blog.freedom-man.com/mvc_is_good.html</link><pubDate>Mon, 13 Oct 2025 21:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/mvc_is_good.html</guid><description>&lt;p>フルスタックフレームワークでMVCのアーキテクチャを採用しているものは多い。
一方でレイヤード？ヘキサゴナル？オニオン？アーキテクチャを採用しているサービスも増えているように思う。&lt;/p>
&lt;p>個人的にはWebアプリケーションのほとんどのケースはMVCパターンで十分だと思っているのだが、今回はこのあたりの話を書いていく。なお、PHP/Laravelを例として記述していく。&lt;/p>
&lt;h2 id="mvcを使うときの大まかな設計の流れ">MVCを使うときの大まかな設計の流れ&lt;/h2>
&lt;p>実装内容の難しさによってどういった構成に着地するか変わってくるが、概ねこんな感じで考えている。&lt;/p>
&lt;h3 id="基本形バリデーション保存">基本形（バリデーション＋保存）&lt;/h3>
&lt;p>管理画面のマスタ管理など純粋なデータの作成・更新で使うようなパターン。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">UserRegistrationController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">store&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Request&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$attributes&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">validate&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;name&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;required|string|max:255&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$user&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">User&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$attributes&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">redirect&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;users.show&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>このパターンに収まるケースはそこまで多くないので、以降でロジックが増えてきたときのパターンでの構成を書いていく。&lt;/p>
&lt;h3 id="バリデーションが増えてきたら">バリデーションが増えてきたら…&lt;/h3>
&lt;p>FormRequestクラスにバリデーション処理を移行する。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">UserRegistrationController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">store&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">UserRegistrationRequest&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$user&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">User&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">validated&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">redirect&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;users.show&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="保存時の変換ロジックなどが増えてきたら">保存時の変換ロジックなどが増えてきたら…&lt;/h3>
&lt;p>Modelにメソッドを生やす&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">UserRegistrationController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">store&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">UserRegistrationRequest&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$user&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">User&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">register&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">validated&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">redirect&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;users.show&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>このModelのユースケースが限られている場合は &lt;code>create&lt;/code> 系のメソッドも増えないため、Modelに実装しちゃっても良いというケース。&lt;/p>
&lt;h3 id="もっと固有のロジックが増えてきてmodelが太ってきたら">もっと固有のロジックが増えてきてModelが太ってきたら…&lt;/h3>
&lt;p>FormクラスやWebのアクションに対して別のEntityを見出してクラス化し、そこにロジックを入れる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">UserRegistrationController&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">store&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">UserRegistrationRequest&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$form&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">UserRegistration&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">validated&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$user&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$form&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">save&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">redirect&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;users.show&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>このFormクラスに該当するクラスをUsecaseクラスやServiceクラスとして定義して利用しているプロジェクトもあると思う。ただ、ServiceクラスもUsecaseクラスも曖昧なまま利用されがちなので、利用する場合はチーム内でよく話し合ったほうが良い。例えばコントローラーから複数のServiceを呼び出したり、ServiceがServiceを呼び出したり、あるいは外部サービスに対するアクセス層としてServiceを定義したりするケースもある。そうすると、どこに記述すればよいのか、どこを読めばよいのか曖昧になり保守性が下がる。&lt;/p>
&lt;p>純粋なモデリング＝Entityを見出すことができるのであればModelを定義してそこから依存するModelを呼び出したり外部アプリケーションへの通信（メールやHTTP APIなど）をすれば良い。&lt;/p>
&lt;p>ちなみにFormクラス相当を作る場合でも↓こんな感じでModelディレクトリに切るのが好きです。&lt;/p>
&lt;pre tabindex="0">&lt;code>app/Models/User/Registration.php
&lt;/code>&lt;/pre>&lt;h2 id="fat-controllerでもええやん">Fat Controllerでもええやん&lt;/h2>
&lt;p>感覚的に100行くらいの処理であればModelにロジックを切らなくてもトランザクションスクリプトな感じで実装してもあまり問題ないように思う。&lt;br>
テストが書かれていればリファクタリングも容易だし、100行くらいであればあちこちファイルを移動する手間もなくなり保守性としても良くなりそう。&lt;/p>
&lt;p>過度にFat Controllerを怖れる必要はない。最初はFat Controllerで保守性厳しいなぁと思ったら適宜切り出せば良い。&lt;br>
同様にFat Modelの方もまずは一旦単一のModelに入れてみて、保守性が悪くなってきたと感じたタイミングでFormや他のModelクラスに切り出せば良い。保守性が悪くなることにはドメイン理解も進んでいるはずなので状況的にも切り出しやすくなっているように思う。&lt;/p>
&lt;p>いずれにしてもコントローラをテストできるFeatureテストの実装はとても大事。LaravelはFactoryやモックあたりも含めてとてもテストが書きやすいので正常系だけでも書いておくと良い。&lt;/p>
&lt;h2 id="そのデータソース切り替えは本当にあるのか">そのデータソース切り替えは本当にあるのか？&lt;/h2>
&lt;p>Repositoryで層を切っているとデータソースの切り替えがしやすいよね、と言われることがある。たしかにRepositoryの中のコードをいじれば二重書きなどができるようになるので変更は楽なように思える。&lt;/p></description></item><item><title>拡張性よりスピード感を大事にしたい</title><link>https://blog.freedom-man.com/speed_over_extensibility.html</link><pubDate>Sun, 12 Oct 2025 20:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/speed_over_extensibility.html</guid><description>&lt;p>「拡張性を考慮して」というワードをよく聞くが、その拡張する機会が訪れなかったり、想定していた拡張性と違っていたり、そもそも実装の筋が悪かったり、拡張性を考慮したことによりコードが保守しづらくなる、といった結果になったことも少なくない。&lt;/p>
&lt;p>例えば、こういった経験をしたことがあったりする。&lt;/p>
&lt;ul>
&lt;li>他の認証方式を追加するかもしれないからと思って拡張できるように作ったものの、認証方式は追加されなかった&lt;/li>
&lt;li>拡張性を考慮して管理画面で変更できるパラメータを増やしたが、あまり使われなかった&lt;/li>
&lt;li>データストレージを切り替えるためのリポジトリ層を用意したがデータストレージを切り替える機会がないまま終わる&lt;/li>
&lt;li>↑でデータストレージを切り替える機会があったもののリポジトリ層の抽象化の仕方が良くなくて、結局リポジトリ層を導入していないコードと同じくらいの労力がかかってしまった&lt;/li>
&lt;li>拡張性を考慮して抽象に対して実装したが、その拡張性を使う機会が全くなかった&lt;/li>
&lt;li>拡張性を考慮してマイクロサービスにしたが、その拡張が必要な規模にならず、分断されたモノリスになってしまったり、保守性が下がってしまった&lt;/li>
&lt;/ul>
&lt;p>ということで、拡張性を大事にしすぎるのも考えものだなぁと思っていたりする。
個人的にはそれよりもスピード感持って今の課題を解決していく方が大事なんじゃないかなとか思ったりしたので以下、駄文を書く。&lt;/p>
&lt;h2 id="その拡張性の効果が出るのはいつか">その拡張性の効果が出るのは「いつ」か？&lt;/h2>
&lt;p>1〜2ヶ月以内くらいに機能実装する予定なのか、半年後くらいなのか、1年以上あとなのか、というのでも結構変わってくる。その拡張性の効果が出るのは「いつ」か、と言い換えても良いかもしれない。&lt;/p>
&lt;p>たとえば半年後、1年以後の効果を見込んでいる場合には、状況がかなり変わっている可能性が高く、その拡張性のニーズも変わっているかもしれない。
逆に1〜2ヶ月以内であればそれなりにニーズが高い機能であり優先度としても高いため、拡張性を考慮した実装にしてもその実装が無駄になることは少ないように思う。&lt;/p>
&lt;h2 id="そのときに変更できるのかという判断軸">そのときに変更できるのか？という判断軸&lt;/h2>
&lt;p>その拡張に対応するときに現実的な工数で対応できるのであれば、「いますぐ」に拡張性のある実装をする必要はないかもしれない。その場合、ある程度実装方法のあたりを付けておいて「そのとき」が来たら一気に対応する、という感じになる。&lt;/p>
&lt;p>DBに関しては変更がしづらい代表格なので、もちろんある程度拡張性を考えても良いのだが、現状で参照・更新箇所が少なかったり使われ方の拡張性が見えづらいテーブルに関しては過度に考える必要はないかもしれない。&lt;br>
データ数がそこまで多くなく、影響範囲なども含めたマイグレーションプランも立てやすいものであれば一旦管理が楽な方に振り切って、ある程度見えてきた段階で変更する感じがリスクが少ないように思える。&lt;br>
とはいえ、このあたりの判断の閾値はチームの経験や腕力に強く依存するということも付け加えておく。&lt;/p>
&lt;p>いずれにしても実装時に &lt;code>将来的な変更を予想してみて、それが来たときにどういう変更をすればよいのか&lt;/code> を考えるのが大事なように思う。&lt;br>
「変更できるようにする」するのではなく、「変更を想定しておく」だけで良い。&lt;/p>
&lt;h2 id="拡張性よりもスピード">拡張性よりもスピード&lt;/h2>
&lt;p>ということで下手に拡張性を考えすぎて開発が遅れるよりは、拡張性は考慮しつつも現状の課題を解決するリリースをサクッとやってしまうのが良いと思っている。&lt;/p>
&lt;p>そのリリースをすることでフィードバックが得られ、未来にやるべきこと＝拡張の方向性が見えてくる。もし拡張が必要であればサクッとリリースしたことによって余った時間と想定していた変更方法を使ってサクッと拡張していけば良い。&lt;/p>
&lt;hr>
&lt;p>言い換えると &lt;code>決定を遅らせる&lt;/code> という話なんだけど、決定を遅らせるために抽象化して中小に対して実装するというような話ではなく、現在の課題を解決し、ちょっと先の不確実性の高い未来に対応できるためにも今やるべきことをうまくやっていきましょうという話なのかも。&lt;/p></description></item><item><title>useEffectのdependenciesに配列値を指定している場合の挙動</title><link>https://blog.freedom-man.com/react_use_effect_1.html</link><pubDate>Sat, 11 Oct 2025 21:25:00 +0900</pubDate><guid>https://blog.freedom-man.com/react_use_effect_1.html</guid><description>&lt;p>useEffectに配列値を指定している場合に、意図せず再評価されるケースが合ったのでメモ&lt;/p>
&lt;h2 id="useeffectのdependenciesと配列値">useEffectのdependenciesと配列値&lt;/h2>
&lt;p>以下のようなコードで、setValueで値が変更されて子コンポーネントが再評価されるとき、デフォルト引数の配列も再度生成されて参照が変わるため &lt;code>useEffect()&lt;/code> が再度評価される&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#1f2328">items&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">items?&lt;/span>: &lt;span style="color:#cf222e">number&lt;/span>&lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#1f2328">})&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">useEffect&lt;/span>&lt;span style="color:#1f2328">(()&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">items&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">items&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">setValue&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">useState&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">input&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onChange&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">setValue&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">target&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">App() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">Hoge&lt;/span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>呼び出し元で固定の配列を指定すると子コンポーネントの再評価時でitemsの参照が変わらない。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">App() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">Hoge&lt;/span> &lt;span style="color:#1f2328">items&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{[]}/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ただ、親コンポーネントが再評価されると、毎回新しい配列が生成されて参照が変わってしまう。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">App() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">setValue&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">useState&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">input&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onChange&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">setValue&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">target&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">Hoge&lt;/span> &lt;span style="color:#1f2328">items&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{[]}&lt;/span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>なので関数の外側でconst定義したものを固定配列として渡すと参照が変わらないのでuseEffectが再度実行されない。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">defaultItems&lt;/span>: &lt;span style="color:#cf222e">number&lt;/span>&lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">App() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">Hoge&lt;/span> &lt;span style="color:#1f2328">items&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">defaultItems&lt;/span>&lt;span style="color:#1f2328">}/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ちなみにプリミティブは大丈夫&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">Fuga&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#cf222e">number&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">boolean&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#cf222e">number&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">number&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">boolean&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">boolean&lt;/span> &lt;span style="color:#1f2328">})&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">useEffect&lt;/span>&lt;span style="color:#1f2328">(()&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">number&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">boolean&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#cf222e">number&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">boolean&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">setValue&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">useState&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">input&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onChange&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">setValue&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">target&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ということでこの問題は配列だけではなくオブジェクトや関数でも発生する。
constや外部関数などで参照を固定化しておくか、useMemoやuseCallbackなどでメモ化すれば良い。ただし、useMemo, useCallbackに関しては依存配列が結局その配列・オブジェクト・関数になりがちなので、結局useEffect()の依存配列に入れない、という選択肢になりそう。&lt;/p></description></item><item><title>ReactでEnterキーでサブミットする方法</title><link>https://blog.freedom-man.com/react_enter_submit.html</link><pubDate>Sat, 11 Oct 2025 15:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/react_enter_submit.html</guid><description>&lt;p>フロントエンドのメモ書き。&lt;/p>
&lt;p>結論としては極力formタグを使ったほうが良さそう。&lt;/p>
&lt;h2 id="formタグを使う">formタグを使う&lt;/h2>
&lt;p>推奨パターン。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-jsx" data-lang="jsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">App&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">form&lt;/span> &lt;span style="color:#1f2328">onSubmit&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">preventDefault&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// なんらかfetchしたりサブミットするコード
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}}&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">input&lt;/span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="onkeydownでenterキーの処理する">onKeyDownでEnterキーの処理する&lt;/h2>
&lt;p>IME予測変換のEnterでsubmitされないようにするため、 &lt;code>isComposing&lt;/code> を使って予測変換中かどうかを判定しないといけない。が、Safariでは以下のコードではうまく処理できない。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-jsx" data-lang="jsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">useState&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;react&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">App&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">isComposing&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">setIsComposing&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">useState&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">input&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f6f8fa;background-color:#82071e">//&lt;/span> &lt;span style="color:#1f2328">nativeEvent.isComposingを使う以外にもonCompositionStart&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">/&lt;/span>&lt;span style="color:#1f2328">EndでもOK&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f6f8fa;background-color:#82071e">//&lt;/span> &lt;span style="color:#1f2328">onCompositionStart&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">setIsComposing&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f6f8fa;background-color:#82071e">//&lt;/span> &lt;span style="color:#1f2328">onCompositionEnd&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">setIsComposing&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onKeyDown&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Enter&amp;#34;&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">nativeEvent&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">isComposing&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// なんらかfetchしたりサブミットするコード
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>非推奨ではあるが e.keyCode を使うとisComposingなしで動く＝Safariでも動く&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-jsx" data-lang="jsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">App&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">input&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onKeyDown&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0550ae">13&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// なんらかfetchしたりサブミットするコード
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>依存パッケージのLICENSEを調べる方法</title><link>https://blog.freedom-man.com/how_to_check_licenses.html</link><pubDate>Thu, 09 Oct 2025 17:07:00 +0900</pubDate><guid>https://blog.freedom-man.com/how_to_check_licenses.html</guid><description>&lt;p>依存パッケージのLICENSEを調べる方法を雑に調べたのでメモ&lt;/p>
&lt;h2 id="php">PHP&lt;/h2>
&lt;p>composerに &lt;a href="https://getcomposer.org/doc/03-cli.md#licenses">licenses&lt;/a> サブコマンドがある&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>composer licenses
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="javascript">JavaScript&lt;/h2>
&lt;p>&lt;a href="https://www.npmjs.com/package/license-checker">license-checker&lt;/a> を使う&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>npx license-checker
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="go">Go&lt;/h2>
&lt;p>&lt;a href="https://github.com/google/go-licenses">go-licenses&lt;/a> を使う&lt;/p>
&lt;p>インストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>go install github.com/google/go-licenses/v2@latest
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>実行&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>go-licenses report .
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="python">Python&lt;/h2>
&lt;p>&lt;a href="https://pypi.org/project/pip-licenses/">pip-licenses&lt;/a> を使う&lt;/p>
&lt;p>インストール: uvの例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>uv pip install pip-licenses
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>実行: uvの例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>uv run pip-licenses
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="ruby">Ruby&lt;/h2>
&lt;p>&lt;a href="https://github.com/pivotal/LicenseFinder">LicenseFinder&lt;/a> を使う&lt;/p>
&lt;p>インストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>group &lt;span style="color:#032f62">:development&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> gem &lt;span style="color:#0a3069">&amp;#39;license_finder&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#6639ba">require&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>bundle install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>実行&lt;/p>
&lt;pre tabindex="0">&lt;code>bundle exec license_finder
&lt;/code>&lt;/pre></description></item><item><title>Pushプレビュー画像の作り方</title><link>https://blog.freedom-man.com/how_to_create_push_preview_image.html</link><pubDate>Thu, 09 Oct 2025 16:45:00 +0900</pubDate><guid>https://blog.freedom-man.com/how_to_create_push_preview_image.html</guid><description>&lt;p>Web Pushを実装していて、Windows環境のPush通知のプレビュー画像が欲しくなった。自分はmacOSなのでWindowsを使っている人にキャプチャを依頼するのが正攻法だが、リリース前だったりして準備が大変そう。&lt;/p>
&lt;p>キャプチャの正確性はそこまで必要なかったのでモック生成してくれるツールが無いかと思ったら &lt;a href="https://onesignal.com/notification-preview">https://onesignal.com/notification-preview&lt;/a> というのがあって便利だった。OneSignalというプッシュ通知サービスが提供しているプレビューツールなので安心して使って良さそう。&lt;/p>
&lt;p>こんな感じな画像を作成できる↓&lt;br/>
&lt;img src="https://blog.freedom-man.com/img/2025/webpush.png" width="400px" />&lt;/p></description></item><item><title>SalesforceIDを15桁から18桁に変換するコード</title><link>https://blog.freedom-man.com/convert_salesforce_id.html</link><pubDate>Thu, 09 Oct 2025 15:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/convert_salesforce_id.html</guid><description>&lt;p>ぱっと検索してもプログラム上で変換するコードが見つからなかったので…！&lt;/p>
&lt;p>JavaScript version&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">convertSalesforceIdFrom15to18&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">let&lt;/span> &lt;span style="color:#1f2328">addon&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">let&lt;/span> &lt;span style="color:#1f2328">block&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">block&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">block&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">let&lt;/span> &lt;span style="color:#1f2328">loop&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">let&lt;/span> &lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">position&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">current&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">charAt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">block&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#0550ae">5&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">position&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">current&lt;/span> &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;A&amp;#34;&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#1f2328">current&lt;/span> &lt;span style="color:#0550ae">&amp;lt;=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Z&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>				&lt;span style="color:#1f2328">loop&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#1f2328">position&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">addon&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;ABCDEFGHIJKLMNOPQRSTUVWXYZ012345&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">charAt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">loop&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">`&lt;/span>&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#0a3069">}${&lt;/span>&lt;span style="color:#1f2328">addon&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">`&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>PHP version&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">convertSalesforceIdFrom15to18&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$input&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$addon&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$block&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#953800">$block&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#953800">$block&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$loop&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$position&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#953800">$position&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#953800">$position&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$index&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$block&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#0550ae">5&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#953800">$position&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$current&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$input&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$index&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$current&lt;/span> &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;A&amp;#34;&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#953800">$current&lt;/span> &lt;span style="color:#0550ae">&amp;lt;=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Z&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$loop&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#953800">$position&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$checksum_chars&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;ABCDEFGHIJKLMNOPQRSTUVWXYZ012345&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$addon&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#953800">$checksum_chars&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$loop&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$input&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#953800">$addon&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Go version&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">checksumChars&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;ABCDEFGHIJKLMNOPQRSTUVWXYZ012345&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">convertSalesforceIdFrom15to18&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">input&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">addon&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">block&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">block&lt;/span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">block&lt;/span>&lt;span style="color:#0550ae">++&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">loop&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">position&lt;/span>&lt;span style="color:#0550ae">++&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#1f2328">charIndex&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">block&lt;/span>&lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#0550ae">5&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">position&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#1f2328">current&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">charIndex&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">current&lt;/span> &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;A&amp;#39;&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#1f2328">current&lt;/span> &lt;span style="color:#0550ae">&amp;lt;=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>				&lt;span style="color:#1f2328">loop&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#1f2328">position&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">loop&lt;/span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span> &lt;span style="color:#6639ba">len&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">checksumChars&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#1f2328">addon&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#6639ba">string&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">checksumChars&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">loop&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">input&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">addon&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>参考URL: &lt;a href="https://help.salesforce.com/s/articleView?id=000385066&amp;amp;type=1">Convert a 15-character Id to an 18-character Id&lt;/a>&lt;/p></description></item><item><title>チームのための通知</title><link>https://blog.freedom-man.com/notification_for_team.html</link><pubDate>Tue, 07 Oct 2025 23:25:00 +0900</pubDate><guid>https://blog.freedom-man.com/notification_for_team.html</guid><description>&lt;p>SlackのGitHubアプリではGitHubリポジトリの通知を行うことができる。以前、この通知を個人DM向けに通知するのかチーム向けの通知チャンネルに通知するのか、という話があった。自分としては断然チームのチャンネルに通知すべきという意見なのだがその理由を書いてみる。&lt;/p>
&lt;h2 id="チームの開発状況はチームとして把握するべき">チームの開発状況はチームとして把握するべき&lt;/h2>
&lt;p>GitHubアプリではプルリクの作成、コメントなどが通知される。このコメントがオープンなSlackチャンネルに通知されることで、誰もがチームのレビュー状況や開発状況を把握できるようになる。ハマっているところがあればカバーしやすいし、そうでなくても今何に取り組んでいるのかがわかるとチーム感も生まれやすい。他の人のコメントも含めてやりとりを追うことも簡単で、議論の内容で気になったところがあれば良い意味で横槍を入れられる。&lt;/p>
&lt;p>GitHubのWebページからプルリクを見れば良いという意見もあるかもしれないが、その場合はPULL型の情報アクセスになるため自発的に情報を取りに行かないといけなくなる。Slack通知はPUSH型なので受動的に情報を受け取りやすくなる。結構ここの情報取得コストの差が大きかったりするので「見てもらう」ことを促進するためにはPUSH型の方が良い。&lt;/p>
&lt;h2 id="個々人が設定するオンボーディングコストがなくなる">個々人が設定するオンボーディングコストがなくなる&lt;/h2>
&lt;p>いちいちGitHubアプリの設定をするのはオンボーディングする側もされる側も面倒。人によって通知設定が変わってしまい良い意味での強制力もなくなってしまう。また、オンボーディングとしても過去のプルリクややりとりを追いやすくSlack検索もできるので便利ですよね。&lt;/p>
&lt;h2 id="これらはgithubの通知に限らない">これらはGitHubの通知に限らない&lt;/h2>
&lt;p>チーム開発に関係するやりとりは基本的にオープンかつディスカッションができるところでやるべきだと思う。また、やりとりの履歴もドキュメントを単に「公開する」だけではなくてちゃんとドキュメントがある旨を伝えるPUSH型のオープンネスが大事。階層が整備されていたり置くだけで特定の人に通知が来るような仕組みであれば明示的に伝える必要はないかもしれないが、そんな環境はほぼ無いと思うので、ちゃんと伝えていくのが大事。&lt;/p></description></item><item><title>「目の前の仕事に向き合って成長する」のもスキルの１つ</title><link>https://blog.freedom-man.com/focus_on_task_is_skill.html</link><pubDate>Mon, 06 Oct 2025 23:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/focus_on_task_is_skill.html</guid><description>&lt;p>目の前の仕事に向き合うことで成長する、というのはよく言われていることだし、自分もそうだなと思っている。
ただ、この「目の前の仕事に向き合う」というのは結構解釈が変わってくると言うか、向き合っているのに成長する人と成長しない人が分かれるような気がする。つまり、「目の前の仕事に向き合って成長する」のもスキルが必要ということ。&lt;/p>
&lt;p>ということで、目の前の仕事に向き合って成長するには具体的にどういうアクションが必要なのか、というのを雑に書いてみる。&lt;/p>
&lt;h2 id="課題の本質を深堀りする">課題の本質を深堀りする&lt;/h2>
&lt;p>これは技術でも非技術でも大事。&lt;/p>
&lt;p>技術においては例えば不具合が発生したときに、アプリケーションコードだけではなくライブラリのコードを読んだり、デバッグしたり、デバッグできるような仕組みを整えたりするスキルである。不具合の真因を理解することで次に同じような事象が発生したときも対応しやすく、原理を理解しているので応用が効きやすい。コードを書くときにも仕組みを理解しておくと罠にハマりづらい。&lt;/p>
&lt;p>非技術においては、本質的な課題やドメインを理解することで、より価値のあるプロダクト開発ができるようになり、結果として成長につながる。ステークホルダーとのコミュニケーションもソフトスキルの成長機会になるかもしれない。&lt;/p>
&lt;h2 id="課題解決方法を模索できる">課題解決方法を模索できる&lt;/h2>
&lt;p>「コードを書く以外の解決方法がないのか」「ライブラリを利用できないか」「フレームワークの機能はないのか」「自前で実装するとしてもどう書けば効率的なのか」「他の言語やフレームワークではどうやって解決しているのか」「他のチームや会社ではどうやっているのか」など課題の解決方法に関しても模索・深堀りできると成長できる。技術的な引き出しの広さと深さを高めていくプロセス。&lt;/p>
&lt;h2 id="振り返りをする">振り返りをする&lt;/h2>
&lt;p>良かったこと・悪かったことを自分なりに振り返って次のアクションに繋げるというのは大事。&lt;/p>
&lt;p>例えば何も振り返りせず淡々と目の前の仕事を &lt;code>こなす&lt;/code> だけでは、仕事の質は上げづらい。同じような仕事をこなすスピードは上がるし、ステークホルダーとのコミュニケーションもこなれてくるので信頼されてお互い気持ちよく仕事できてしまうのだが、本質的な課題を解決できてなかったり、ジリ貧な状態になりやすい。&lt;/p>
&lt;p>仕事のちゃんと成果を振り返ると、質とスピードを上げつつ、それをスケールさせる方法を模索・試行することができる。前回とは違う方法で仕事にアプローチすることで、それが結果的に成長につながる。&lt;/p></description></item><item><title>チームとしてスキルを持つ</title><link>https://blog.freedom-man.com/team_skill_than_individual.html</link><pubDate>Sat, 04 Oct 2025 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/team_skill_than_individual.html</guid><description>&lt;p>エンジニアってやるべきことが多いなぁと思います。&lt;/p>
&lt;p>粒度を雑に書いていくと&lt;/p>
&lt;ul>
&lt;li>要件・要求の把握&lt;/li>
&lt;li>ドメイン理解&lt;/li>
&lt;li>短・中・長期を見据えた設計&lt;/li>
&lt;li>実装（固有技術の習得）
&lt;ul>
&lt;li>フロントエンドもバックエンドもDBもインフラも…&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>チームへの共有・ドキュメンテーション&lt;/li>
&lt;li>ステークホルダーコミュニケーション&lt;/li>
&lt;li>自動テスト・CI/CDなどの基盤整備&lt;/li>
&lt;li>オブザーバビリティ&lt;/li>
&lt;li>セキュリティ&lt;/li>
&lt;li>チーム開発&lt;/li>
&lt;li>コードを書かない技術&lt;/li>
&lt;/ul>
&lt;p>などなどなど。１つのスキルを深堀りするだけでもかなりの時間を要し、チームやプロダクトによっては経験できないものもあったり、そもそも得意不得意があったりします。&lt;/p>
&lt;p>エンジニアとして練度が上がってくるともちろんこういったことが身についてきて良い感じに課題解決できるようになるわけですが、とはいえ認知負荷の問題はあります。例えば実装しているときには例外パターンを考慮できていなかったり命名が適当になっていたり、コードを書かなくても良い解決方法を模索せずについついコードを書いてしまったり。&lt;/p>
&lt;p>これ自体はしょうがないことなので、大事なのはチームとしてのレジリエンスを持っていることなのかなぁと思っていたりします。例えばレビュープロセスやデイリーMTGで指摘し合ったり、社内勉強会で共通認識を作ることで、こういった「うっかり」を減らせるし、チームであれば個人の認知負荷の限界を簡単に越えれます。得意不得意をチームで補うという感じ。シニアエンジニアでも抜け漏れはあるものなので、気にせず指摘し合えると良いのかなぁと思っています。&lt;/p>
&lt;hr>
&lt;p>それはそれとして個人としてもこういった抜け漏れは減らしたいですよね。これは認知負荷を減らすのが鍵なのかなと思っています。&lt;/p>
&lt;p>たとえば「実装」というタスクがあった場合、この中でも&lt;/p>
&lt;ul>
&lt;li>正常系を書く&lt;/li>
&lt;li>正常系のテストコードを書く&lt;/li>
&lt;li>例外パターンを書く&lt;/li>
&lt;li>例外パターンのテストコードを書く&lt;/li>
&lt;li>PRを作る&lt;/li>
&lt;li>セルフレビューしてみる&lt;/li>
&lt;li>レビュー依頼する&lt;/li>
&lt;/ul>
&lt;p>といった感じでやることを分割すると認知負荷を減らせます。セルフレビューも効果的で、IDEでコードを書く脳の使い方を、WebUIなどでコードを読む脳の使い方は結構違って、同じ人が同じコードを読む場合でも違う視点を手に入れることができます。また、１日寝かせることで固定観念を取り除くことができて「そもそもこうじゃなかったっけ…？」「実装しなくても解決できなかったっけ…？」といった視点になれるのでオススメです。&lt;/p></description></item><item><title>管理画面を作るときに気をつけていること</title><link>https://blog.freedom-man.com/admin_page_guideline.html</link><pubDate>Mon, 29 Sep 2025 22:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/admin_page_guideline.html</guid><description>&lt;p>管理画面を作るときに気をつけていることを雑に書いてみる。&lt;/p>
&lt;h2 id="作らない">作らない&lt;/h2>
&lt;p>管理画面に限らずですが「作る」と &lt;code>初期開発＋保守（不具合修正・機能追加/変更・FWアップグレード・認知負荷）&lt;/code> のコストかかります。時間は常に足りないものなので、モノづくりをせずにスマートに解決できる方法があればそれを選択すべきです。&lt;/p>
&lt;p>例えば「データを閲覧・分析したい」といった要件であれば管理画面で閲覧するのではなく、Metabase、Redash、Looker StudioなどのBIツールを使うことで作らずに要件を満たすことが出来ます。これらのBIツールは非エンジニアでも扱えることが多いため、作るためのコミュニケーションコストを削減できることもメリットです。
また、そもそもの要件や運用を見直すことで解決できる課題も多く、そのためには要件・ビジネスの深い理解と広い引き出しが必要になってきます。&lt;/p>
&lt;p>低頻度の要件であれば手順書を残した上であえて手動で対応することも検討すると良いです。例えば年１回の１時間の作業であれば、プログラムを実装・運用するコストよりも安くなるケースもあると思います。ただし手順書が複雑、あるいはセンシティブな操作を含む場合は自動化する範囲を限定して実装するなど柔軟に対応できるとベターです。&lt;/p>
&lt;h2 id="ssoな認証を入れる">SSOな認証を入れる&lt;/h2>
&lt;p>認証基盤をちゃんと作るには「登録」「ログイン」「パスワード変更」「パスワード忘れ」などの機能を作る必要があります。SSOな認証が入れられるケースだと「登録」「ログイン」のみ実装すればよいので保守性・管理性が良くなります。退職時などユーザを無効化したい場合はSSOのIdP側が無効化されれば、管理画面側もログインできなくなるので運用面においても簡単・安心です。（とはいえ、無効化する処理や運用もセーフティネットとして持っておいたほうが良いと思います）&lt;/p>
&lt;p>OIDC連携できるOSSも数多くありますし、Google CloudのIAPのようにインフラレベルで対応しているケースもあるので、比較的工数をかけずに実装ができます。&lt;/p>
&lt;h2 id="証跡を残す">証跡を残す&lt;/h2>
&lt;p>管理画面はマスタ管理や個人情報閲覧など重要な操作が含まれることが多いです。データの「変更」だけではなくデータの「閲覧」「ダウンロード」も重要な操作の１つです。&lt;/p>
&lt;p>セキュリティインシデントなど何か障害が発生した場合に、アクセスログは重要な証跡で、セキュリティインシデントにおいては「何かをした」ことだけではなく「何もしていない」の根拠になるのは非常に心強いです。そのため管理画面には必ずアクセスログを残しておきましょう。&lt;/p>
&lt;p>内容としては最低限以下の情報を含めておくと良いです。&lt;/p>
&lt;ul>
&lt;li>timestamp（いつ）&lt;/li>
&lt;li>管理者ID（誰が）&lt;/li>
&lt;li>HTTPメソッド（どうした）&lt;/li>
&lt;li>エンドポイント（何を）&lt;/li>
&lt;/ul>
&lt;p>ただし、個人情報はログに残さないように気をつけてください。&lt;/p>
&lt;h2 id="パーマリンクなurl設計">パーマリンクなURL設計&lt;/h2>
&lt;p>不具合報告、変更依頼などのコミュニケーションにおいて、具体的なURLベースでやりとりできると認識齟齬が減ったり調査がしやすくなります。基本的には参照系のリクエストはGET、更新系のリクエストはPOST(APIではPUT/PATCH/DELETEも含む)にするのを意識してURL設計してもらえれば基本的に問題ないです。&lt;/p>
&lt;p>例えば一覧検索が &lt;code>POST https://example.com/search&lt;/code> という感じで、参照系の処理をPOSTにするとURLに検索条件が入らないため、URLだけでは &lt;code>どのパラメータを指定してアクセスしたのか&lt;/code> の情報が落ちてしまいます。また一覧・検索系の画面ではURLパラメータを残すことで指定の検索条件をブックマークできるメリットもあります。&lt;/p>
&lt;h2 id="シンプルで統一されたuiuxにする">シンプルで統一されたUI/UXにする&lt;/h2>
&lt;p>パーマリンクのところと通じるところがありますが、マスタ管理系であれば以下の画面をベースにするとUI/UXが統一されて良いです。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>機能&lt;/th>
 &lt;th>エンドポイント&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>一覧（検索含む）&lt;/td>
 &lt;td>&lt;code>GET /entity&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>新規作成画面&lt;/td>
 &lt;td>&lt;code>GET /entity/create&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>詳細画面&lt;/td>
 &lt;td>&lt;code>GET /entity/{id}&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>編集画面&lt;/td>
 &lt;td>&lt;code>GET /entity/{id}/edit&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>新規作成処理&lt;/td>
 &lt;td>&lt;code>POST /entity&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>更新処理&lt;/td>
 &lt;td>&lt;code>PUT /entity/{id}&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>削除処理&lt;/td>
 &lt;td>&lt;code>DELETE /entity/{id}&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Laravelには &lt;a href="https://laravel.com/docs/11.x/controllers#resource-controllers">resource&lt;/a> というルーティング定義やscaffoldがあるのでそちらを利用すると良いです。&lt;/p>
&lt;p>要件によっては詳細画面が不要（編集画面で十分）なケースや、新規作成はエンジニアが手動でDB INSERTし、管理画面上は更新のみでOKといったケースもあると思うので、そのあたりはケースバイケースで。&lt;/p>
&lt;p>ただ、UIを変えると開発者も利用者も認知負荷や考慮事項も増えがちなので、そのあたりは仕様を慎重に検討していくとよいかと思います。JavaScriptも開発の認知負荷を上げる要因にもなるので必要最小限の利用に留めると良いです。&lt;/p>
&lt;h2 id="利用環境を制限する">利用環境を制限する&lt;/h2>
&lt;p>フロントエンドではブラウザごとの差分があるため、可能であれば利用ブラウザなどを制限できると良いです。例えばChromeの最新版を使う、といった制限を行うことでブラウザ間の互換性を気にしなくても良いのに加え、JSの最新の機能を使えたり、そもそもJSを書かなくてもHTML/CSSだけで対応できるようなケースも増え、工数削減や保守性の向上を見込めます。また、トラブルシューティングの際も同一ブラウザで検証できるため、対応コストが低くなります。&lt;/p>
&lt;h2 id="ヘルプ説明を入れる">ヘルプ・説明を入れる&lt;/h2>
&lt;p>複雑な操作・危険な操作はヘルプ・説明を入れておくと安心です。
画面上部やツールチップなどでメッセージを表示しても良いですし、
wikiのURLを貼っておけば、ヘルプの更新性が上がるためオススメです。ドキュメントは基本読まれないので、管理画面の機能とリンクさせておくことで読まれやすくして、トラブルが発生したときなどでドキュメントに辿りやすくするという仕掛けにもなっています。&lt;/p>
&lt;h2 id="危険な操作には確認を入れる">危険な操作には確認を入れる&lt;/h2>
&lt;p>JSのconfirm()や確認画面を入れておくと比較的安心です。&lt;/p>
&lt;h2 id="代理ログイン">代理ログイン&lt;/h2>
&lt;p>権限系のテストを簡単に行えるように、代理ログイン（他のユーザになりすましてログイン）する機能を開発環境に入れたりすることがあります。ロール・属性操作で簡単に検証できることもあるので入れなくても十分なこともある。&lt;/p></description></item><item><title>お金は物事を動かす</title><link>https://blog.freedom-man.com/money_makes_things_happen.html</link><pubDate>Sun, 28 Sep 2025 22:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/money_makes_things_happen.html</guid><description>&lt;p>当たり前だけど、ビジネスで物事を動かすのはいつだって「お金」だ。と改めて思ったので駄文を書く。&lt;/p>
&lt;hr>
&lt;p>ビジネスをしている以上は売上＝お金が大事なので、だいたいの施策は「売上を伸ばす」（トップラインを上げる）か「コストカットをする」（人件費や固定費を減らす）の二軸になると思っている。&lt;/p>
&lt;ul>
&lt;li>顧客向けの機能開発は、売上を伸ばすため（営業力強化・チャーン回避）&lt;/li>
&lt;li>社内向けの機能開発は、効率化による人件費削減＝コストカットをするため&lt;/li>
&lt;li>インフラコストの削減は固定費削減＝コストカット&lt;/li>
&lt;li>ツールやサービスの見直しは固定費削減＝コストカット&lt;/li>
&lt;li>技術的負債の解消は開発生産性向上により、間接的に売上を伸ばしたり人件費のコストカットをするため&lt;/li>
&lt;/ul>
&lt;p>といった感じ。&lt;/p>
&lt;p>なのでわかりやすく売上やコストカットに結びつく施策は通りやすく評価もされやすい。既存・潜在顧客からのリクエストが高い機能は優先されるし、固定費が確実に削減されるインフラやサービスの見直しも案件化されやすい。&lt;/p>
&lt;p>一方で、R&amp;amp;D、PoC、大規模な技術基盤改善の案件などは、プロジェクト化ができなかったり、途中で打ち切りになるケースもそれなりに見たことがある。これも一種の「お金」が物事を動かしたケースで、直接的な売上貢献・コストカットの効果やその期限が見えづらい、というのが原因ではないかと思っている。&lt;/p>
&lt;p>という感じで、何か課題を感じたときに、その課題解決をするためにはどうやればお金と結びつけれるのか、というのを考えるとよいのかもしれない。開発生産性であれば具体的な指標が提示できると良いし、施策開発のついでに技術的負債の解消をするというのも「お金」に結びつけた戦略的なやりかたである。&lt;/p>
&lt;p>とはいえ、技術的負債の解消は「お金」と結びつけるにはかなり難しく、計測の前提を揃えることがほとんど不可能なので定量的な効果を伝えづらい。例えば、リプレースの案件ではリプレース以外をやろうとしたり、適切に「作らない選択」をしないと工期が延びて疲弊するため、一般的にはアンチパターンだと思っている。しかしながら「お金」と結びつけるには、リプレース以外の付加価値をエンドユーザにわかりやすい形で提供しないとプロジェクトの効果を伝えづらいため、リプレース以外のことをやるのも戦略としては大事だったりする。&lt;/p>
&lt;p>ということで、こういった定量化や可視化、といったことも意識していろんな引き出しを持っておくとより技術力を活かせるのではないのかなぁと思ったり。&lt;/p></description></item><item><title>レガシーフロントエンドの漸進的改善戦略</title><link>https://blog.freedom-man.com/modern_js_for_legacy.html</link><pubDate>Sat, 27 Sep 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/modern_js_for_legacy.html</guid><description>&lt;p>jQueryベースのレガシーフロントエンドをモダンにするためのアレコレをまとめます。なお、一足飛びなリプレースの話ではなく地に足ついた一歩ずつの改善です。&lt;/p>
&lt;h2 id="不要コードの削除">不要コードの削除&lt;/h2>
&lt;p>モダン化のすべての基本ですね！不要なコードを削除していきましょう。バックエンドと違って静的解析で検知することが若干難しいのですが、コードをgrepしたりアクセスログを見て利用していないことを確認すれば比較的安全に削除していくことができます。&lt;/p>
&lt;p>なぜ最初にやるかというと、フォーマッタやLinterが全適用になるので無駄な変更になったり認知負荷が上がるためです。&lt;/p>
&lt;h2 id="フォーマッタやlinterを入れる">フォーマッタやLinterを入れる&lt;/h2>
&lt;p>とりあえず何かしらフォーマッタやLinterは入れておきましょう。
フォーマッタは一括適用でき、リスクが低めなので早めに入れましょう。Linterはエラーをすべて解消するのは大変なのでignoreしたり設定を無効化したりして導入しましょう。&lt;/p>
&lt;p>使うツールとしては設定が簡単でフォーマッタとLinter両方に対応している &lt;a href="https://biomejs.dev/ja/">Biome&lt;/a> がオススメ。どのツールを使うかよりは導入すること自体の価値のほうが圧倒的に高いので、何でも良いのでそれなりに枯れているツールを迷わず入れれば良いと思います。&lt;/p>
&lt;h2 id="javascriptのビルド環境を整える">JavaScriptのビルド環境を整える&lt;/h2>
&lt;p>ビルド環境が整っていないと、お手製のキャッシュバスティングをしていたり（あるいはキャッシュバスティング忘れてうまく変更が反映されなかったり）、HMRが効かなかったり、minifyなど最適化した状態で配信されていなかったり、Nodeモジュールが使えなかったり、TypeScriptが使えなかったりと色々と不便です。適切にモジュール化できれば、グローバル汚染も防げます。ということでビルド環境を整えましょう。&lt;/p>
&lt;p>使うツールとしてはとりあえず &lt;a href="https://ja.vite.dev/">Vite&lt;/a> を入れておけばOK。Laravelなら &lt;a href="https://github.com/laravel/vite-plugin">Laravel Vite Plugin&lt;/a> で良い感じにVite連携できます。&lt;/p>
&lt;p>ビルド環境を整えずNative ESMを使う方法もありますが、キャッシュバスティングやHMRなどのメリットを考えると、ちょっと頑張ってビルド環境を整えたほうが良いと思います。&lt;/p>
&lt;h2 id="nodeモジュールを使ったバージョン管理">Nodeモジュールを使ったバージョン管理&lt;/h2>
&lt;p>ダウンロードしたjQueryなどのライブラリをそのままGit管理していたりするのはレガシーフロントあるあるですね。ということで、上記でビルド環境を整えたらライブラリをNodeモジュール(NPM)から使うように変更しましょう。これによってGit管理も軽くなるし、Renovate/Dependabotなどの自動アップデートも機能するようになります。&lt;/p>
&lt;p>CDNや &lt;code>type=&amp;quot;javascript&amp;quot;&lt;/code> で読み込んでいるライブラリはwindowのグローバルに定義されているため、最初は以下のようにESM内でグローバルに定義することで既存のコードを変更せずにNPM板を利用することができます。&lt;/p>
&lt;pre tabindex="0">&lt;code>import $ from &amp;#39;jquery&amp;#39;;

globalThis.$ = $;
&lt;/code>&lt;/pre>&lt;h2 id="エラー管理ツールを導入">エラー管理ツールを導入&lt;/h2>
&lt;p>レガシーフロントエンドを改善するとき、予期せぬエラーが発生するのは常です。というか改善して無くてもエラーが出てます。気づいてないだけ。特に本番環境ではブラウザやネットワークなど様々な要因でエラーが発生しがちです。ということでエラーを早く検知できるようにSentryなどのエラー管理ツールを導入して、検知・管理ができるようにしましょう。&lt;/p>
&lt;h2 id="typescriptを使った型付け">TypeScriptを使った型付け&lt;/h2>
&lt;p>フロントエンドはバックエンドと比べるとテストが書きづらい、あるいはテストの効果を出しづらいです。ということでTypeScriptを使って型安全にしておくと堅牢性が上がって良いです。関数化された処理では引数や戻り値を型付けしていくと安心です。とはいえ、jQueryなどの直接的なDOM操作だとTypeScriptの型付けの恩恵が受けづらいです。できれば部分的にAlpine.jsやReactなどの宣言的UIに置き換えてTypeScriptの恩恵を受けれるような形に持っていくのがオススメです。&lt;/p>
&lt;h2 id="テスト実装">テスト実装&lt;/h2>
&lt;p>フロントエンドもテストできる部分は関数化するなどしてテストを書いていきましょう。ツールとしてはVitestがオススメで導入が簡単なのと、&lt;a href="https://vitest.dev/guide/browser/">Vitest Browser Mode&lt;/a> を使えばjQueryのテストも可能です。&lt;/p>
&lt;h2 id="ライブラリの定期アップデート">ライブラリの定期アップデート&lt;/h2>
&lt;p>ライブラリがNPM管理されていると、ライブラリの定期アップデートができます。ということでRenovateやDependabotによる定期アップデートを入れましょう。個人的にはRenovateがオススメです。よく使う設定は以下のブログ記事を参照。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/renovate_config">よく使う Renovate の設定&lt;/a>&lt;/p>
&lt;h2 id="リファクタリングする">リファクタリングする&lt;/h2>
&lt;p>以下のようなリファクタリングをちょっとずつ行います。&lt;/p>
&lt;h3 id="var-ではなく-let-const-を使う">&lt;code>var&lt;/code> ではなく &lt;code>let&lt;/code> &lt;code>const&lt;/code> を使う&lt;/h3>
&lt;p>varは再宣言や巻き上げ（ホスティング）の問題があり、可読性の低いコードや予期せぬ挙動を生む可能性が高いため利用しない方が良いです。 基本的にconstを使い、再代入が必要なものだけletを使うと安全です。&lt;/p>
&lt;p>&lt;a href="https://qiita.com/cheez921/items/7b57835cb76e70dd0fc4">【JavaScript】var / let / const を本気で使い分けてみた&lt;/a>&lt;/p>
&lt;h3 id="グローバル定義を使わない">グローバル定義を使わない&lt;/h3>
&lt;p>&lt;code>&amp;lt;script&amp;gt;&lt;/code> の中で定義した変数・関数や、ESMで &lt;code>window.xxx = ...;&lt;/code> と書いたものはグローバル（windowオブジェクト）に定義されます。 グローバルに定義されると影響範囲がわかりづらくなるので、別ファイルから使う関数は export しておき、利用側で import してください。共通で使いたいモジュールローカルな変数はexportしたsetter/getter経由でアクセスする感じになります。&lt;/p></description></item><item><title>Laravel Vite PluginのTIPS</title><link>https://blog.freedom-man.com/laravel_vite_config.html</link><pubDate>Mon, 22 Sep 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_vite_config.html</guid><description>&lt;p>LaravelでViteを良い感じに使うプラグイン &lt;a href="https://github.com/laravel/vite-plugin">Laravel Vite Plugin&lt;/a> のTIPS的な。&lt;/p>
&lt;h2 id="laravel-vite-plugin-で-tsconfigpaths-がうまく効かないケースがある">Laravel Vite Plugin で tsconfigPaths がうまく効かないケースがある&lt;/h2>
&lt;p>tsconfig.jsonのpathsで &lt;code>@/*&lt;/code> に &lt;code>./resources/js/*&lt;/code> 以外（例えば &lt;code>./resources/ts/*&lt;/code> とか）を指定した状態で、&lt;a href="https://www.npmjs.com/package/vite-tsconfig-paths">vite-tsconfig-paths&lt;/a> を使っても &lt;code>./resources/js/*&lt;/code> の方にaliasが効いてしまう（エディタ上ではtsconfig.jsonを見て補完や型が効いたりするがビルドで失敗する）。&lt;/p>
&lt;p>理由としては vite-tsconfig-paths はモジュールパス解決（resolve）に対して変更するのだが、 laravel-vite-plugin がaliasを自動設定するため @ のresources/jsのエイリアスが先に効いてしまうため。&lt;/p>
&lt;p>解消方法としては tsconfig.json と同じ設定を vite.config.js にいれる。&lt;/p>
&lt;p>以下のような感じでtsconfig.jsonをパースしてaliasを自動設定することも可能だが、ちょっとtoo muchな感じもする…。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">resolve&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">alias&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#6639ba">Object&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">fromEntries&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">Object&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">entries&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">tsconfig&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">compilerOptions&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">paths&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">map&lt;/span>&lt;span style="color:#1f2328">(([&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">])&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">let&lt;/span> &lt;span style="color:#1f2328">value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">endsWith&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/*&amp;#34;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">slice&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">slice&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">nodeModulesPrefix&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;node_modules/&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">startsWith&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">nodeModulesPrefix&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">nodeModulesPrefix&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">path&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">__dirname&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="https対応">HTTPS対応&lt;/h2>
&lt;p>ローカル開発環境をHTTPSでホスティングしている場合、Viteのサーバーの方もHTTPS対応しないとMixed Contentでうまく動かない。&lt;/p>
&lt;p>以下のような感じで秘密鍵や証明書を設定すればOK。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">https&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">readFileSync&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/app/dev-key.pem&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">cert&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">readFileSync&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/app/dev.pem&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>HTTPSでホスティングする場合はホスト名でのアクセスになると思うので、その場合はViteにもホスト名を設定する必要がある。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">host&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">hmr&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">host&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;{domain}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">cors&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">origin&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https://{domain}:{port}&amp;#39;&lt;/span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>「スクラム開発しよう」じゃなくて「チーム開発しよう」でええやん</title><link>https://blog.freedom-man.com/not_scrum_but_teamdev.html</link><pubDate>Sat, 20 Sep 2025 22:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/not_scrum_but_teamdev.html</guid><description>&lt;p>「スクラム開発しようぜ」みたいなのが何となくあまり好きじゃなくて…スクラムの概念は好きなんだけどイベントを教条的にやるのが嫌い。というか、あのわかりづらいイベント名が嫌いなのかもしれない。&lt;/p>
&lt;p>とりあえずチーム開発において以下を重視したいと思っている。&lt;/p>
&lt;h2 id="デイリーmtg">デイリーMTG&lt;/h2>
&lt;p>日々の進捗や困りごとを雑に共有していきたい。自然発生的な雑談をしても良い。デイリーMTGはコミュニケーションの基盤。開発TIPSとか便利ツールとか気になった記事とか共有しても良い。
今、誰が何をやっているのか、なにかバッティングしそうなタスクはないか、フォローできることがないか、そういった個人がやっているタスクをチームのタスクにする意味合いもあるかもしれない。&lt;/p>
&lt;p>「スクラム」では「デイリースクラム」って呼ぶらしい。&lt;/p>
&lt;h2 id="タスクの棚卸し進捗確認">タスクの棚卸し・進捗確認&lt;/h2>
&lt;p>差し込みタスクや改善系タスクなど諸々棚卸しして、適切にタスクを割り振っていきたい。棚卸しする過程でチームメンバーは &lt;code>プロダクトの動き&lt;/code> みたいなのを知ることができる。&lt;/p>
&lt;p>だいたいこのタスクやっていこう、これくらいのスケジュールでちゃんとやっていきましょう、みたいなのが全体的に認識を揃えることが大事。納期を守ることも大事だが、納期があることを意識するのが大事。そうすると、差し込みが発生したときに別のタスクが送れるよね、みたいなのが可視化できて説明しやすい。&lt;/p>
&lt;p>「スクラム」では「スプリントプランニング」って言うらしい。&lt;/p>
&lt;h2 id="振り返り">振り返り&lt;/h2>
&lt;p>めっちゃ大事。個人やチームの成長に影響を与える。&lt;/p>
&lt;p>１〜２週間ごとの全体的な振り返り（よかったこと、これからこうしたい、とか）をしていく。これ以上頻度が低いと思い出しづらいし、頻度が高いとネタがなくなりがち。振り返り手法はなんでも良い。振り返り自体を楽しむことが大事。振り返り自体も大事なコミュニケーション手段。&lt;/p>
&lt;p>定期的な振り返り以外にもポストモーテムといった障害発生時の振り返りも行う。プロジェクトなどの大きめなタスクもステークホルダーを巻き込んでちゃんと振り返る。エンジニア以外も巻き込むことで新しい視点が手に入る。振り返りをしたらネクストアクションやその期日を設定できるとベターだが、慣れていなければ振り返るだけでもOKだと思っている。&lt;/p>
&lt;p>「スクラム」では「レトロスペクティブ」って言うらしい。わかりにくい…。&lt;/p>
&lt;h2 id="結局スクラムと同じことやってるじゃん">結局スクラムと同じことやってるじゃん&lt;/h2>
&lt;p>はい。そうなんだけど専門用語なくて素人でもわかりやすくない…？&lt;/p>
&lt;p>変に「スクラム勉強します！」ってならなそうじゃない？ｗ&lt;/p>
&lt;p>何がチームに不足しているのか、それを取り入れるだけで良いじゃない。&lt;/p>
&lt;p>っていうのと、これくらいのチーム開発におけるイベントは、だいたいどのチームもやっていると思うんですよね。スクラム云々じゃなくて。&lt;/p>
&lt;h2 id="ところでスプリントレビューは">ところでスプリントレビューは？&lt;/h2>
&lt;p>成果物のレビューはステークホルダーと開発者間で当たり前のように実施されるべきなので省きました。普通にステークホルダーのレビューなしでリリースしませんよね…？&lt;/p>
&lt;p>で、開発に携わっていない開発者も含めたチーム全体のスプリントレビューでいうと、やった方が良いけど工数の問題やどこまでリソース割く？みたいな話もあるのでデイリーMTGやタスクの棚卸しMTGでちょろっと会話できそうであればそこで軽く共有するとかでも良いのでは？と思っている。&lt;/p>
&lt;p>やるとしても「スプリントレビュー」という名前ではなく「成果物のレビューとフィードバックの会」という名前にすると思う。&lt;/p></description></item><item><title>よく使う Renovate の設定</title><link>https://blog.freedom-man.com/renovate_config.html</link><pubDate>Sat, 20 Sep 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/renovate_config.html</guid><description>&lt;p>定期パッケージアップデートで &lt;a href="https://www.mend.io/renovate/">Renovate&lt;/a> をよく使っています。
柔軟なスケジュール管理やアップデート対象をグルーピングできたりするので便利です。が、設定がちょっと色々できるので、推奨設定や運用方法をまとめておきます。&lt;/p>
&lt;p>設定例ベースで紹介していきます。&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-json5" data-lang="json5">{
 $schema: &amp;#34;https://docs.renovatebot.com/renovate-schema.json&amp;#34;,
 extends: [&amp;#34;config:recommended&amp;#34;, &amp;#34;helpers:pinGitHubActionDigests&amp;#34;],
 timezone: &amp;#34;Asia/Tokyo&amp;#34;,
 schedule: [&amp;#34;before 9am on Monday&amp;#34;],
 minimumReleaseAge: &amp;#34;3 days&amp;#34;,
 rangeStrategy: &amp;#34;pin&amp;#34;,
 packageRules: [
 // Python / uv
 {
 matchUpdateTypes: [&amp;#34;minor&amp;#34;, &amp;#34;patch&amp;#34;],
 matchDepTypes: [&amp;#34;project.dependencies&amp;#34;],
 groupName: &amp;#34;python dependencies&amp;#34;,
 groupSlug: &amp;#34;python-dependencies&amp;#34;,
 },
 {
 matchUpdateTypes: [&amp;#34;minor&amp;#34;, &amp;#34;patch&amp;#34;],
 matchDepTypes: [&amp;#34;dependency-groups&amp;#34;],
 groupName: &amp;#34;python dev dependencies&amp;#34;,
 groupSlug: &amp;#34;python-dev-dependencies&amp;#34;,
 },
 
 // Node.js / NPM
 {
 matchManagers: [&amp;#34;npm&amp;#34;],
 matchUpdateTypes: [&amp;#34;patch&amp;#34;, &amp;#34;minor&amp;#34;],
 matchDepTypes: [&amp;#34;devDependencies&amp;#34;],
 groupName: &amp;#34;NPM dev dependencies&amp;#34;,
 groupSlug: &amp;#34;npm-dev-dependencies&amp;#34;,
 },
 // PHP / Composer
 {
 matchManagers: [&amp;#34;composer&amp;#34;],
 matchUpdateTypes: [&amp;#34;patch&amp;#34;, &amp;#34;minor&amp;#34;],
 matchDepTypes: [&amp;#34;require&amp;#34;],
 groupName: &amp;#34;Composer dependencies&amp;#34;,
 groupSlug: &amp;#34;composer-dependencies&amp;#34;,
 },
 {
 matchManagers: [&amp;#34;composer&amp;#34;],
 matchUpdateTypes: [&amp;#34;patch&amp;#34;, &amp;#34;minor&amp;#34;, &amp;#34;major&amp;#34;],
 matchDepTypes: [&amp;#34;require-dev&amp;#34;],
 groupName: &amp;#34;Composer dev dependencies&amp;#34;,
 groupSlug: &amp;#34;composer-dev-dependencies&amp;#34;,
 },
 // PHP/MySQLのメジャー・マイナーバージョンのPRは作成しない
 {
 matchPackageNames: [&amp;#34;php&amp;#34;, &amp;#34;mysql&amp;#34;],
 matchUpdateTypes: [&amp;#34;major&amp;#34;, &amp;#34;minor&amp;#34;],
 enabled: false,
 },
 // LaravelのメジャーバージョンのPRは作成しない
 {
 matchUpdateTypes: [&amp;#34;major&amp;#34;],
 enabled: false,
 matchPackageNames: [&amp;#34;/laravel/framework/&amp;#34;],
 },
 ],
}
&lt;/code>&lt;/pre>&lt;h2 id="json5を使う">json5を使う&lt;/h2>
&lt;p>設定ファイルとしてjsonではなくjson5 ( &lt;code>renovate.json5&lt;/code> ）を使いましょう。
コメントが書けたり色々使い勝手が良いです。
一応Renovateの仕様上は &lt;code>.json&lt;/code> でもコメントが書けるようなのですが、json5の拡張子にしておいたほうがIDEのサポートも受けられるため明示的に指定したほうが良いです。&lt;/p></description></item><item><title>他人のサンクコストは捨てづらい</title><link>https://blog.freedom-man.com/discard_other_sunk_cost.html</link><pubDate>Wed, 17 Sep 2025 23:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/discard_other_sunk_cost.html</guid><description>&lt;p>自分は自分自身のサンクコストを捨てれる方だとは思っている。そもそも仕様解釈が間違っていたり、実装方針間違っていたり、あるいはより良い解決策があればそれを選択すべきだと思っている。&lt;/p>
&lt;p>しかしながら、サンクコストを捨てれるかどうかは人に依る。
大きな方針転換があったときに「せっかくこんなに工数かけて頑張って作ったのに！」みたいな反応する人も少なからず居る。
また、たとえサンクコストを捨てれる人であっても気を使うことが多い。&lt;/p>
&lt;p>ということで他人のサンクコストは捨てづらい。というか捨ててもらうには仕事の進め方やコミュニケーション戦略が必要になる。個人的には以下を気をつけたほうが良いのかなと思っている。&lt;/p>
&lt;ol>
&lt;li>その人との信頼関係を作る&lt;/li>
&lt;li>サンクコストを捨てやすい状況を作る（大きなサンクコストにならないようにする）&lt;/li>
&lt;li>サンクコストを捨てなくてもよくする&lt;/li>
&lt;li>情報を丁寧に伝える&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>1&lt;/strong> はまぁそりゃそうだよねという話。信頼関係や心理的安全体があればサンクコストは捨てやすくなる。&lt;br>
&lt;strong>2&lt;/strong> は例えばタスクを細分化して、サンクコスト自体を下げて捨てやすくする。PRならレビューできる粒度で分割するし、コードじゃなくても何をやっているかの進捗共有をこまめにやっていく、とか。&lt;br>
&lt;strong>3&lt;/strong> も似たような感じで、そもそも手戻りが多くなったりサンクコストが大きくなってくるのは後ろの工程になるので、前の工程、例えば「要求整理」「要件定義」「設計」といった前提のところからちゃんとレビューなり一緒に作業していくことで、認識のズレが少なくなる。&lt;br>
&lt;strong>2&lt;/strong> や &lt;strong>3&lt;/strong> はすでに大きなサンクコストになっている場合は対応できない。その場合、&lt;strong>4&lt;/strong> で前提となる情報を丁寧に伝えていき、少しずつ誘導していくような形になりそう。&lt;/p>
&lt;p>「せっかくこんなに工数かけて頑張って作ったのに！」といった問題が発生するのは一見するとその人のサンクコストの捨てづらさの問題もあるけど、単にコミュニケーションの問題でもあったりする。もっと事前にレビュー入ってたら良かったな、とかもう少し丁寧に情報共有すれば良かったな、とか。&lt;/p>
&lt;hr>
&lt;p>ところで生成AIはそのへんのサンクコストが低いので捨てやすい。この「捨てやすさ」が生成AIの武器なんだろうなぁとは思ったり。&lt;/p></description></item><item><title>laravel newしたFrankenPHPなアプリケーションをCloud Runでホスティングするまで</title><link>https://blog.freedom-man.com/frankenphp.html</link><pubDate>Tue, 16 Sep 2025 23:05:00 +0900</pubDate><guid>https://blog.freedom-man.com/frankenphp.html</guid><description>&lt;p>FrankenPHPを &lt;code>laravel new&lt;/code> して最速で使う方法をメモ&lt;/p>
&lt;h2 id="とりあえず-laravel-new">とりあえず laravel new&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>laravel new frankenphp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>フロントエンドは &lt;code>React&lt;/code> を選択&lt;/p>
&lt;h2 id="ローカル環境のdockerを整備">ローカル環境のDockerを整備&lt;/h2>
&lt;p>とりあえずDockerfileやcompose.ymlを作る&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">FROM&lt;/span>&lt;span style="color:#0a3069"> dunglas/frankenphp:1-php8.4-bookworm&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">ENV&lt;/span> &lt;span style="color:#953800">COMPOSER_ALLOW_SUPERUSER&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">ENV&lt;/span> &lt;span style="color:#953800">DEBCONF_NOWARNINGS&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>yes
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">RUN&lt;/span> ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">RUN&lt;/span> apt-get update &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> apt-get install -y --no-install-recommends &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> locales strace vim git less unzip&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">RUN&lt;/span> install-php-extensions @composer xdebug&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">RUN&lt;/span> curl -sLS https://deb.nodesource.com/setup_24.x &lt;span style="color:#1f2328">|&lt;/span> bash - &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> apt-get install -y nodejs&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">RUN&lt;/span> sed -i -e &lt;span style="color:#0a3069">&amp;#39;s/# \(ja_JP.UTF-8\)/\1/&amp;#39;&lt;/span> /etc/locale.gen &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> locale-gen &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> update-locale &lt;span style="color:#953800">LANG&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>ja_JP.UTF-8&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">ENV&lt;/span> &lt;span style="color:#953800">LANG&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>ja_JP.UTF-8&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">RUN&lt;/span> cp /usr/local/etc/php/php.ini-development /usr/local/etc/php/php.ini&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>必要に応じて &lt;code>pdo_mysql&lt;/code> とか &lt;code>intl&lt;/code> とかをインストールする。&lt;/p></description></item><item><title>プロジェクトがうまくいく要因</title><link>https://blog.freedom-man.com/project_gowell_factor.html</link><pubDate>Sun, 14 Sep 2025 22:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/project_gowell_factor.html</guid><description>&lt;p>プロジェクトがうまく行ったな、と思うときどういう要素があるのかなと雑に考えたメモ&lt;/p>
&lt;h2 id="ドメイン理解ができている">ドメイン理解ができている&lt;/h2>
&lt;p>周辺のドメイン理解を深めたり、ヒアリングや適切なフィードバックを受けることで作るものが全く検討違いにならないようにする。検討しすぎも注意で、デリバリーも大事なので100点を目指さず60〜80点くらいを目指すバランス感覚も大事。&lt;/p>
&lt;h2 id="デリバリーを概ね納期通りに完了させる">デリバリーを概ね納期通りに完了させる&lt;/h2>
&lt;p>デリバリーが大幅に遅延してしまうと、そのプロジェクトへの期待感が下がってしまうような感覚がある。メンバーの士気も下がるだろうし、全体的に熱量が下がってしまう感じ。リリースというのは成果物を公開することによる期待値調整の意味もあるので、多少品質が悪くても早めに出すことで「あのプロジェクトの人達何してるの？」感もなくなるし、フィードバックを早く受けれるようになり、改善サイクルをより回すことができる。&lt;/p>
&lt;h2 id="リリース後のマーケティングができている">リリース後のマーケティングができている&lt;/h2>
&lt;p>リリースしたあとにその機能やサービスを全員使ってくれるかと言うとそうではない。機能・サービスの啓蒙やユースケース（＝使ってくれた人の成功体験）の共有を根強くやっていかないと使ってくれない。&lt;/p>
&lt;p>特にユースケースの共有は机上ではない現実的な成功体験なので利用者もイメージが湧きやすく、体験した人は自己肯定感が上がり、共有された人もワクワク感があるのではないかなと思ったりする。&lt;/p>
&lt;hr>
&lt;p>ということで、技術力というのは実はファクターとしてはそこまで大きくないのではないのかなと思ったりした。いや、もちろん技術が無いとデリバリーできないし、プロジェクトの後の別のデリバリーの速度が落ちたりするわけで大事なんですけど。ドメイン理解とリリース後のマーケティング・セールスもそれ以上に大事ですよね、みたいな。&lt;/p></description></item><item><title>ORMのselect()は原則使わない方が良いのでは？</title><link>https://blog.freedom-man.com/orm_select_method.html</link><pubDate>Sat, 13 Sep 2025 22:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/orm_select_method.html</guid><description>&lt;p>と思ってます。&lt;/p>
&lt;p>Laravelだとこういうクエリは原則使わないほうが良いのかなぁと。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">User&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">select&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;id&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;name&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="項目が限定されて取得されているという認知負荷">項目が限定されて取得されている、という認知負荷&lt;/h2>
&lt;p>項目が限定されて取得されているので、select()されていないデータを取得しようとして、DBにデータが入っているのにnullを返してしまったりします。直接的にデータ取得するときもそうですが、getterなど間接的に利用されている場合はさらにわかりづらいです。&lt;/p>
&lt;p>また、仕様変更などでselectする項目が増えたときに修正箇所が増えて面倒というのもあります。selectの修正漏れで期待通りに動かず右往左往、ということもありそうです。&lt;/p>
&lt;p>静的解析でのチェックも基本的に難しく Laravel/Eloquent で言うと PHPStan/Larastan でselectされていない項目をnull判定するなどの細かい検知はできません。&lt;/p>
&lt;p>ちなみに、Node.jsのPrismaはselectした項目を良い感じに型付けしているORMなので静的解析でのチェック・補完ができるのですが、仕様変更時などでselectを逐一追加する運用コストは変わりません。また、こういったselectレベルで型安全なORMはPrismaくらいしかなさそう、というのもあります。&lt;/p>
&lt;h2 id="selectしたところでそんなにパフォーマンスは上がらない">selectしたところでそんなにパフォーマンスは上がらない&lt;/h2>
&lt;p>だいたいパフォーマンス目的で！みたいなこと言われるんですがそんなにパフォーマンス上がりますか？測りましたか？ところでそれは人件費よりもコスパ良いですか？&lt;/p>
&lt;p>もちろんORMはメモリを食いがちですが、それであればORMのモデルクエリよりはクエリビルダでSQLを直接書いたほうが良いかもしれません。&lt;/p></description></item><item><title>オンボーディングはこうしたら良いんじゃね</title><link>https://blog.freedom-man.com/onboarding.html</link><pubDate>Fri, 12 Sep 2025 22:50:00 +0900</pubDate><guid>https://blog.freedom-man.com/onboarding.html</guid><description>&lt;p>自分が今までオンボーディングを受けてきた中で、受け入れ側が「良いオンボーディング」をするために具体的に何をしたら良いんだろうかみたいな駄文を書く。なお、自分は受け入れ側で全然できていない感じがする…ｗ&lt;/p>
&lt;h2 id="チームで顔合わせする">チームで顔合わせする&lt;/h2>
&lt;p>初日に顔合わせの時間（自己紹介などの時間）をしっかり取る。大事なのは「顔合わせ」することなのでMeetやZoomでちゃんと顔出しする。顔や話し方を見ないと人となりがわかりづらくてコミュニケーションしづらいんですよね。そういう意味でもできればオフラインが良いと思う。&lt;/p>
&lt;p>初日以外でもチームのデイリーMTGや振り返りMTGなどは積極的に参加してもらったほうが良い。アンチパターンとしては「あの人は入社したてなのでMTG入ってもしょうがないので参加しなくて良いよね」みたいなムーブはしないほうが良い。&lt;/p>
&lt;h2 id="初日初月にウェルカム感を出す">初日/初月にウェルカム感を出す&lt;/h2>
&lt;p>ジョインした直後は色々不安になっている。人間関係うまくいくかなぁとかドメイン知識無くて何言っているかわからないとか、総合的にマッチする環境なのかなぁとか。そんな中、入社おめでとう感を出してもらえると新入社員としては安心する。今までの会社だと&lt;/p>
&lt;ul>
&lt;li>ウェルカムバルーン（風船に名前が書いてある）&lt;/li>
&lt;li>ウェルカムランチ（チームメンバーや新入社員同士とのランチ。あとはメンターとご飯に行ったり）&lt;/li>
&lt;li>1on1リレー&lt;/li>
&lt;/ul>
&lt;p>をやっていることが多い。ウェルカムランチは1on1よりもカジュアルに雑談や仕事の相談とかもできるので結構良いなぁと思ってる。バルーン用意するのは面倒かもしれないけどウェルカムランチは予定抑えるだけだからすぐできると思うし。&lt;/p>
&lt;h2 id="good-first-issue-をやってもらう">Good First Issue をやってもらう&lt;/h2>
&lt;p>前述の通りジョインした直後は貢献していけるのか不安になるので、少しでも早く貢献してもらってチームの一員になったということを実感してもらうのが良い。&lt;/p>
&lt;p>内容としては文言変更のレベルで良い。文言で検索して直すだけでよく、影響範囲も少ない、切り戻しもしやすい、UI変更なのでテストしやすい・わかりやすいのがメリット。開発環境が整っていなくても文言変更だけであれば何とかなる。&lt;/p>
&lt;p>できれば社員研修を除いた初日にリリースしたい。そのためにもローカル開発環境を整えて簡単に環境立ち上げ・開発できるようにしておきたいし、CI/CD環境を整えて簡単にリリースできるようにしておきたい。Good First Issueを提供するには定常的にタスクを棚卸ししておく必要もある。&lt;/p>
&lt;p>ということで総合的に色々とできていないといけないんだが、仮にそういった環境がなかったとしても「早めに初回リリースしてもらう」意識はしておくと良い。基盤が整っていなくてもそういった姿勢が見えるとウェルカム感があって嬉しい。&lt;/p>
&lt;h2 id="プロアクティブにコミュニケーションする">プロアクティブにコミュニケーションする&lt;/h2>
&lt;p>タスクをやってもらうとき、なにかあればいつでも質問してください！という姿勢（PULL型）も大事なのだが、どちらかというと定期的にMeet/Zoomなどで時間を取って質問ありますか？どんな感じですか？みたいなPUSH型のコミュニケーションをするとやりやすい。シニアだからPULL型で質問してよ、みたいなのは気持ちはわかるし、まぁそうだよねって思うんだけど、それでも補助いただけると嬉しい。&lt;/p>
&lt;p>あとやっぱ大体の人って忙しいので聞きづらいんですよ。どこに何のドキュメントがあるかもわからないし、初月は質問だらけになってメンターのタスクを止めてもらうことになるし。いや、それを理解したうえで質問しまくったほうがよいんだけど、メンター側がどう思っているかという不安はあるわけですよね、人間関係が構築できていないので。&lt;/p></description></item><item><title>ログ・アラート ガイドライン</title><link>https://blog.freedom-man.com/log_alert_guideline.html</link><pubDate>Fri, 12 Sep 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/log_alert_guideline.html</guid><description>&lt;p>どの会社でもログやアラートのガイドラインというのを書いているなぁという感じなので、もうここでまとめて参照させたい、という意図で公開してみる。&lt;/p>
&lt;h2 id="ログ">ログ&lt;/h2>
&lt;h3 id="ログレベル">ログレベル&lt;/h3>
&lt;p>基本的には以下の４つで利用することを推奨。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>レベル&lt;/th>
 &lt;th>説明&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>DEBUG&lt;/td>
 &lt;td>開発用。&lt;br/>デバッグは各種デバッガーでやることが多いのであまり出番はないかも。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>INFO&lt;/td>
 &lt;td>どこまで正常に終了したかを確認したり、アクセスログなど簡易的に追いたい指標として利用。&lt;br/>処理が長くなりがちなバッチ処理で利用することが多い。&lt;br/>有用ではないログが大量に出る感じでなければ手軽に使ってOK。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>WARN&lt;/td>
 &lt;td>即時対応が必要ではないエラーのログに利用。&lt;br/>例えば、単位時間あたりに閾値以上の回数エラーが発生すると異常とみなすようなときなど。&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>ERROR&lt;/td>
 &lt;td>即時対応が必要なエラーの場合に証跡を残すために利用。&lt;br/>別途SentryやDatadogなどエラー管理ツールに送信するとベター。ログと連動させて自動で送信しても良いが、意図せず通知してしまうことも多いので運用上注意が必要。&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>MonoLogの場合は他にも&lt;code>NOTICE&lt;/code> &lt;code>ALERT&lt;/code> &lt;code>CRITICAL&lt;/code> &lt;code>EMERGENCY&lt;/code> のログレベルがあるが、使い分けが難しく運用しきれない可能性が高いため、まずは上記の４つで運用する。細かく分けないと厳しいケースが出てきたら改めて検討する。&lt;/p>
&lt;h3 id="ログの出力内容">ログの出力内容&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>[MUST]&lt;/strong> 個人情報を載せないように注意する
&lt;ul>
&lt;li>アクセスログにはクエリパラメータも載るのでURL設計にも注意する（例えば &lt;code>?name=山田太郎&lt;/code> のようにクエリパラメータに個人情報が載らないようにする）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>[MUST]&lt;/strong> バッチ処理など長めの処理は障害発生時に「どこまで成功したのか」がわかりづらいため、INFOログを適度に残しておく。&lt;/li>
&lt;li>&lt;strong>[SHOULD]&lt;/strong> ログ出力のコスト（CPU/IOや転送料金など）が増えたり、本質的なログが見えづらくなることもあるので、Webアプリケーションなどログが増えそうな箇所には不要なログはできるだけ載せない。&lt;/li>
&lt;li>&lt;strong>[SHOULD]&lt;/strong> アプリケーションログを出力した場所（クラス、ファイル名、行番号）も入れておくと障害時に追いやすい&lt;/li>
&lt;li>&lt;strong>[SHOULD]&lt;/strong> Exceptionのエラーログはスタックトレースも残す
&lt;ul>
&lt;li>スタックトレースに引数の値が載らないように設定する。PHPの場合は以下のような感じでiniを設定する。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;pre tabindex="0">&lt;code>zend.exception_ignore_args = On
zend.exception_string_param_max_len = 0
&lt;/code>&lt;/pre>&lt;ul>
&lt;li>&lt;strong>[SHOULD]&lt;/strong> アプリケーションログにはトレースIDを入れておくと１リクエスト単位でまとめてログを確認できるので追いやすいので推奨
&lt;ul>
&lt;li>分散システムの場合は必須。&lt;/li>
&lt;li>DatadogやNewRelicが自動でつけてくれたりする。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="ログフォーマット">ログフォーマット&lt;/h3>
&lt;p>外部ツール連携性が高いので構造化ログ（JSONL）にする。&lt;/p>
&lt;p>Laravelログの例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;some message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;context&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;level&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0550ae">200&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;level_name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;INFO&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;channel&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;production&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;datetime&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;2024-11-26T16:08:19.585601+09:00&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;extra&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;platform&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;laravel&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;url&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/home&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;ip&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;x.x.x.x&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;http_method&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;GET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;server&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;example.com&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;referrer&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://example.com/referrer&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/var/www/html/app/Models/Hoge.php&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;line&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;class&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;App\\Models\\Hoge&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;callType&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;-&amp;gt;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;function&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;fuga&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;uid&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;8a1d991&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>属性&lt;/th>
 &lt;th>説明&lt;/th>
 &lt;th>必須&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>message&lt;/td>
 &lt;td>メッセージ&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>context&lt;/td>
 &lt;td>コンテキスト（Laravel）&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>level&lt;/td>
 &lt;td>レベル（数字）&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>level_name&lt;/td>
 &lt;td>レベル（文字列）&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>channel&lt;/td>
 &lt;td>チャンネル&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>datetime&lt;/td>
 &lt;td>ログ出力日時&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.url&lt;/td>
 &lt;td>リクエストURL&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.ip&lt;/td>
 &lt;td>IPアドレス&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.http_method&lt;/td>
 &lt;td>HTTPメソッド&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.referrer&lt;/td>
 &lt;td>リファラ&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.file&lt;/td>
 &lt;td>ログ出力したファイル&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.line&lt;/td>
 &lt;td>ログ出力した行番号&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.class&lt;/td>
 &lt;td>ログ出力したクラス名&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.function&lt;/td>
 &lt;td>ログ出力したメソッド名&lt;/td>
 &lt;td>-&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>extra.uid&lt;/td>
 &lt;td>トレースID&lt;/td>
 &lt;td>◯&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h3 id="ログ出力場所">ログ出力場所&lt;/h3>
&lt;p>コンテナ化している場合はCloudWatch Logsに連携する。アプリケーションでは標準出力に出せばOK。&lt;/p></description></item><item><title>時間不足ではなくスキル不足</title><link>https://blog.freedom-man.com/not_a_matter_of_time.html</link><pubDate>Wed, 10 Sep 2025 22:45:00 +0900</pubDate><guid>https://blog.freedom-man.com/not_a_matter_of_time.html</guid><description>&lt;p>自分もそういう発言をすることがあるのだが「時間がなくて」できませんでした、やりませんでした、というのを聞くことがある。「時間がなくて」「施策タスクに追われていて」「スピード重視」で、ローカル開発環境やCIの整備ができていなかったりテストコードを書けていなかったり、コードの品質が悪かったり…などなど。&lt;/p>
&lt;p>もちろん本当に時間がないケースもあるが、大抵の場合は純粋なスキル不足のことが多い。&lt;/p>
&lt;p>1〜2時間で終わるようなローカル開発環境の整備、CIの整備、ちょっとしたテストコードを年レベルで放置されているのは、おそらくどうローカル開発環境を作ればよいのか、CIを実装すればよいのか、テストコードを書けばよいのかがわかっていない、つまり純粋なスキルや経験が不足している。あるいはこれらが「足りていない」「施策開発に影響を与えている」ことを認識できていないというスキル不足でもある。質とスピードは両立する、ハイスキルな人はある程度の質を担保した上でスピードを出せる、ロースキルな人は時間をかけても質をあげれない、といった話はよく耳にする。&lt;/p>
&lt;p>なので、明らかにスキル不足なのに「時間がない」ことを原因とするような主張をされると非常にモヤッてしまう。スキル不足を認めないとその人自身が次のステップに進めないような気もしている。職位・役職関係なく誰しもがスキル不足なのである。それを認めるための振り返りが「ポストモーテム」だったりする。振り返りができる人やチームは、開発環境やCIやテストコードを整備するだろうし、恒久対策のネクストアクションとしてもやりやすいため、結果としてスキルや経験を磨ける、といったことがある。&lt;/p>
&lt;p>ということで言い訳したい気持ちはとてもわかるけど、どこかで言い訳せずに向き合って良い感じに前に進めていけると良いな、と自分も含めて思うのだった。&lt;/p></description></item><item><title>Better PHP Guideline</title><link>https://blog.freedom-man.com/better_php_guideline.html</link><pubDate>Tue, 09 Sep 2025 22:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/better_php_guideline.html</guid><description>&lt;p>フォーマッタレベルの話ではないここは抑えてほしいなという感じのPHPのガイドラインというのをどの会社でも毎回書いている気がするので、もうここでまとめて参照させたいな、という意図で公開してみます。&lt;/p>
&lt;hr>
&lt;h2 id="型-を書く">&lt;a href="https://www.php.net/manual/ja/language.types.declarations.php">型&lt;/a> を書く&lt;/h2>
&lt;p>PHPは型宣言がサポートされています。適切に型付けしておくと&lt;/p>
&lt;ul>
&lt;li>IDEなどでコード補完が効くようになる&lt;/li>
&lt;li>静的解析ツールで型の不整合を事前検知できる&lt;/li>
&lt;li>型情報がドキュメンテーションとなり可読性が上がる&lt;/li>
&lt;/ul>
&lt;p>といったようなメリットが得られるため、積極的に型を付けていくと良いです。&lt;/p>
&lt;p>型付けできるところは以下の箇所になります。&lt;/p>
&lt;ul>
&lt;li>関数・メソッドの引数&lt;/li>
&lt;li>関数・メソッドの戻り値&lt;/li>
&lt;li>クラス定数&lt;/li>
&lt;li>プロパティ&lt;/li>
&lt;/ul>
&lt;p>静的解析ツールを使ってより詳細に型検査を行いたい場合はPHPDocによる型記述も有効です。&lt;/p>
&lt;p>PHPでは文字列の配列も数字の配列も同じ &lt;code>array&lt;/code> で表現されますがPHPDocの場合は&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">/** @var string[] */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">/** @var int[] */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">/** @var array&amp;lt;int, string&amp;gt; */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">/** @var array&amp;lt;int, int&amp;gt; */&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>のような型宣言によって区別することができます。&lt;/p>
&lt;p>併せてPHPStanなどの静的解析も入れられると完璧です！&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># bad
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">someMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$arg&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># good
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">someMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$arg&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">void&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="strict_-を有効化する">&lt;a href="https://www.php.net/manual/ja/language.types.declarations.php#language.types.declarations.strict">strict_types&lt;/a> を有効化する&lt;/h2>
&lt;p>デフォルトでは関数・メソッドの引数の型と実際の値が間違っていても型変換を行おうとします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$str&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">var_dump&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$str&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">// =&amp;gt; string(1) &amp;#34;1&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">// =&amp;gt; string(0) &amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>strict_typesを有効にしておくと、実行時に引数の型が間違っている場合にエラーが発生します。これにより、意図しない引数の型やキャストを防ぐことができます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">declare&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">strict_types&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$str&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">var_dump&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$str&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">// =&amp;gt; TypeError hoge(): Argument #1 ($str) must be of type string, int given, called on line 2.
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>strict types宣言をしたファイル内での呼び出し元のみエラーが発生することに注意してください。&lt;br>
参考: &lt;a href="https://qiita.com/Hiraku/items/735f0666ab3d34c52efa">https://qiita.com/Hiraku/items/735f0666ab3d34c52efa&lt;/a>&lt;/p></description></item><item><title>ローカル開発環境を作るときにやっていること</title><link>https://blog.freedom-man.com/local_dev.html</link><pubDate>Tue, 09 Sep 2025 21:45:00 +0900</pubDate><guid>https://blog.freedom-man.com/local_dev.html</guid><description>&lt;p>ローカル開発環境を作ることがめちゃくちゃ多くて（というかジョインしたサービスで整備されていないことが多くて…ｗ）自分が作ったり改善していることが多いのだが、何をやっているのか、どういうことに気をつけているのかを書いてみる。&lt;/p>
&lt;h2 id="dockerによるローカル開発環境構築">Dockerによるローカル開発環境構築&lt;/h2>
&lt;p>開発環境構築ツールは色々あれど、現状ではDockerコンテナでアプリケーションを動かすのが無難な感じはしている。&lt;/p>
&lt;p>docker-compose.ymlを作っておきApp/DBサーバーを立ち上げれるようにしておく。
AWSやメールなどはモックサーバー( &lt;a href="https://github.com/localstack/localstack">localstack&lt;/a> や &lt;a href="https://github.com/axllent/mailpit">Mailpit&lt;/a> )を入れておく。&lt;/p>
&lt;p>開発環境のDockerfileには各言語のランタイム以外には&lt;/p>
&lt;ul>
&lt;li>vim&lt;/li>
&lt;li>git&lt;/li>
&lt;li>curl&lt;/li>
&lt;li>procps&lt;/li>
&lt;li>less&lt;/li>
&lt;/ul>
&lt;p>あたりは入れるようにしている。日本語化やタイムゾーン設定も忘れずに。&lt;/p>
&lt;h2 id="makeタスクの整理">Makeタスクの整理&lt;/h2>
&lt;p>賛否両論あるが、Makeコマンド・タスクは便利だと思っていて、Makefileは必ず用意している。&lt;/p>
&lt;p>個人的にMakeが良いと思っているのは&lt;/p>
&lt;ul>
&lt;li>言語に依存しないのでコンテキストスイッチがかからない&lt;/li>
&lt;li>構文が簡単で必要十分な機能を備えている
&lt;ul>
&lt;li>タスクの依存関係を簡単に記述できる&lt;/li>
&lt;li>複数コマンド実行を改行区切りで記述できて読みやすい&lt;/li>
&lt;li>分岐や変数が使える&lt;/li>
&lt;li>並列実行&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>動くREADMEでコメントも自由に書ける&lt;/li>
&lt;/ul>
&lt;p>あたり。&lt;/p>
&lt;p>だいたいこんな感じなものを作っている。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Makefile" data-lang="Makefile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> help
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">help&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## ヘルプ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	@awk &lt;span style="color:#0a3069">&amp;#39;BEGIN {FS = &amp;#34;:.*?## &amp;#34;} /^[a-zA-Z0-9_\/-]+:.*?## / {printf &amp;#34;\033[36m%-15s\033[0m %s\n&amp;#34;, $$1, $$2}&amp;#39;&lt;/span> &lt;span style="color:#cf222e">$(&lt;/span>MAKEFILE_LIST&lt;span style="color:#cf222e">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> up
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">up&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## Dockerコンテナの立ち上げ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose up -d
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> init
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">init&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## 初期化
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	&lt;span style="color:#57606a"># ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> install
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">install&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## ライブラリのインストール
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> web composer install
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> web npm install
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">test&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## テスト実行
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> web ./vendor/bin/phpunit
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> lint
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">lint&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## lint実行
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> web ./vendor/bin/pint --test
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> lint
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">lint/fix&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## lintのautofix
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> web ./vendor/bin/pint
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> console
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">console&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## Webのコンテナに入る
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> -it web /bin/bash
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> db/console
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">db/console&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## DBのMySQLのコンソールに入る
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose &lt;span style="color:#6639ba">exec&lt;/span> -it db /bin/bash -c &lt;span style="color:#0a3069">&amp;#39;mysql -h {host} -u{user} -p{password} {database}&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">.PHONY&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> logs/web
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">logs/web&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#57606a">## Webコンテナのログを表示
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>	docker compose logs -f web
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>初期構築は &lt;code>make init&lt;/code> だけで済ませれるようにしておくとよいのだが、必要なツールやファイルのダウンロードなどが必要になったりするので、あまりワンコマンドにこだわらないようにしている。&lt;/p></description></item><item><title>Laravelアプリケーションにはこれを入れておこう 2025</title><link>https://blog.freedom-man.com/laravel_2025.html</link><pubDate>Sun, 07 Sep 2025 22:35:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_2025.html</guid><description>&lt;p>ということで書いていく。&lt;/p>
&lt;h2 id="バックエンド">バックエンド&lt;/h2>
&lt;h3 id="phpstan--larastan">&lt;a href="https://phpstan.org/">PHPStan&lt;/a> / &lt;a href="https://github.com/larastan/larastan">Larastan&lt;/a>&lt;/h3>
&lt;p>Laravel、というよりPHPアプリケーションに対して必須といっても良いくらい大事。&lt;/p>
&lt;p>テストを書かない人はまだまだ大半を占めていると感じていたり、カバレッジが充足していないアプリケーションがほとんどだと思うので、テストを書かなくてもある程度堅牢にしてくれるのはレガシー改善職人としては嬉しいところ。&lt;/p>
&lt;p>また、Laravelはマジックメソッドが多いためLarastanは必須。Eloquentモデルのプロパティやファサードなどを良い感じに型推論してくれるのはめちゃくちゃ便利。もちろん限界はあるのである程度は割り切って使うのが吉。&lt;/p>
&lt;h3 id="構造化ログ">構造化ログ&lt;/h3>
&lt;p>ローカル開発環境はプレーンテキストなログでOKだけど、本番環境・ステージング環境などコンテナサービス上で動いているアプリケーションの場合はJSON形式の構造化ログを出力しておくと良い。こんな感じでログ出力ができる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">LoggerCustomSetting&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__invoke&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Logger&lt;/span> &lt;span style="color:#953800">$logger&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">void&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$introspectionProcessor&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">IntrospectionProcessor&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Level&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">Debug&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;Illuminate\\&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$webProcessor&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">WebProcessor&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// リクエストごとのユニークIDをコンテキストに付与
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$logger&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">pushProcessor&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">UidProcessor&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ファイル名・クラス名・関数名・行番号などをコンテキストに付与
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$logger&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">pushProcessor&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$introspectionProcessor&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// Webリクエスト情報をコンテキストに付与
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$logger&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">pushProcessor&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$webProcessor&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$logger&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getHandlers&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$handler&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$handler&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">StreamHandler&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$handler&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setFormatter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">JsonFormatter&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>config/logging.phpはこんな感じで上記クラスをtapに設定すればOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;stdout&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;driver&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;monolog&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;level&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">env&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;LOG_LEVEL&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;debug&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;handler&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">StreamHandler&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;tap&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">LoggerCustomSetting&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;with&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;stream&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;php://stdout&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="modelshouldbestrict">Model::shouldBeStrict()&lt;/h3>
&lt;p>遅延ロードを防ぐための設定。これによりN+1クエリがある程度防げる。
また、意図しない属性アクセスなども防ぐことができるのでタイポ防止効果もある。
エラーになってしまうため、開発環境のみに入れておいて気付けるような仕組みにしておくと良い。&lt;/p>
&lt;p>以下のような感じな設定にすると、本番環境以外でもignore_strictをURLパラメータに入れておくとエラーをスルーして実行できるので必要に応じて入れておくと便利。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Model&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">shouldBeStrict&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">isProduction&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;request&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;request&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">has&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;ignore_strict&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="laravel-debugbar">&lt;a href="https://laraveldebugbar.com/">Laravel Debugbar&lt;/a>&lt;/h3>
&lt;p>開発用にデバッグを簡単にできるツールを入れておくと何かと便利。
Laravel Debugbarは画面下部にデバッグコンソールが表示され、そこでログやクエリ発行、セッション・リクエスト情報を見ることができるので、デバッグ時のvar_dump代わりにもなる。&lt;/p>
&lt;p>インストール方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ composer require barryvdh/laravel-debugbar --dev
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="laravel-pint">&lt;a href="https://laravel.com/docs/12.x/pint">Laravel Pint&lt;/a>&lt;/h3>
&lt;p>フォーマッターは色々あるが、とりあえずLaravel PintというPHP CS FixerをラッピングしたLaravel公式のフォーマッタがあるのでこれを使っておけばOK。気に食わないところはpint.jsonでカスタマイズしつつ。&lt;/p></description></item><item><title>コンテキストによって「工数」の解釈が変わることに注意しないといけない</title><link>https://blog.freedom-man.com/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E5%B7%A5%E6%95%B0%E3%81%AE%E8%A7%A3%E9%87%88%E3%81%8C%E5%A4%89%E3%82%8F%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%91%E3%81%AA%E3%81%84.html</link><pubDate>Sat, 06 Sep 2025 22:55:00 +0900</pubDate><guid>https://blog.freedom-man.com/%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E5%B7%A5%E6%95%B0%E3%81%AE%E8%A7%A3%E9%87%88%E3%81%8C%E5%A4%89%E3%82%8F%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AB%E6%B3%A8%E6%84%8F%E3%81%97%E3%81%AA%E3%81%84%E3%81%A8%E3%81%84%E3%81%91%E3%81%AA%E3%81%84.html</guid><description>&lt;p>&lt;code>工数&lt;/code> という言葉でやりとりするときに人によって解釈が変わっていて納期や見積もりに齟齬が生じることがある。&lt;/p>
&lt;h2 id="工数と工期">工数と工期&lt;/h2>
&lt;p>&lt;code>工数&lt;/code> は「その人がフルアサインされている状態でどの程度時間がかかるか」を示しており、1人日のタスクを1人で行う場合、差し込みがなければ1日で終わるし、その工数のタスクを2つ並行してタスクをやれば2日かかる。&lt;/p>
&lt;p>一方で &lt;code>工期&lt;/code> はそのタスクが完了するまでの期間を指しており、1人日のタスクを1人で行う場合は1日、差し込みがあればもっと時間がかかるだろう。&lt;/p>
&lt;h2 id="何が問題になるのか">何が問題になるのか&lt;/h2>
&lt;p>「工数はどれくらいですか？」と聞かれる場合、 &lt;code>工数&lt;/code> ではなく &lt;code>工期&lt;/code> を指していることがあることに注意しなければならない。&lt;/p>
&lt;p>プロジェクトのディレクションやマネージメントをする人が、タスクに対する &lt;code>工期&lt;/code> そのものを聞きたいのか、 &lt;code>工数&lt;/code> に対してバッファを載せたり人員を適切にアサインしてディレクション側で &lt;code>工期&lt;/code> を算出したいのか、を配慮する必要がある。&lt;/p>
&lt;p>&lt;code>工数&lt;/code> を聞きたいのに &lt;code>工期&lt;/code> を出してしまうとバッファが２重で乗ってしまったりして納期や見積もりの精度が大きく狂うし、 &lt;code>工期&lt;/code> に対して &lt;code>工数&lt;/code> を出してしまうと差し込みなど別タスクに取られる時間もあり納期に間に合わない、といったことが発生する。&lt;/p>
&lt;h2 id="どうすればよいのか">どうすればよいのか&lt;/h2>
&lt;p>&lt;code>工数&lt;/code> と &lt;code>工期&lt;/code> の違いに対してチームメンバーで再認識しつつ、
各コンテキストにおいて何をヒアリングしたいのか、というのを確認しながら進めていくのが良さそう。&lt;/p>
&lt;p>納期を大事にする人は &lt;code>工期&lt;/code> を答えがちで、タスクの精緻な見積もりをしたい人は &lt;code>工数&lt;/code> を答えがち。何が良い悪いではなくコンテキストや関心事が違うだけなので、お互いいい感じにコミュニケーションして認識をすり合わせていけると良いのかなぁとか。&lt;/p></description></item><item><title>ロガーインターフェースについて思いを馳せる</title><link>https://blog.freedom-man.com/logger_interface.html</link><pubDate>Wed, 03 Sep 2025 22:55:00 +0900</pubDate><guid>https://blog.freedom-man.com/logger_interface.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/pino_logger_customize">pinoのロガーインターフェースを変更する&lt;/a> という記事を書いたが、そもそもロガーインターフェースって各言語 / FWどんな感じになってたっけ？というのを気になって調べたのでメモ。&lt;/p>
&lt;p>自分が馴染みのある &lt;code>PHP&lt;/code> &lt;code>Ruby&lt;/code> &lt;code>Go&lt;/code> &lt;code>Python&lt;/code> &lt;code>Node.js&lt;/code> が比較対象。&lt;/p>
&lt;h2 id="string-string-object-パターン">(string), (string, object) パターン&lt;/h2>
&lt;p>PHP / MonoLog&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$log&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Logger&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;name&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$log&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$log&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;number&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Python / logging&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># extraを表示するにはformatterを調整する必要あり&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>logger&lt;span style="color:#0550ae">.&lt;/span>info&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> extra&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#39;number&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Go / slog&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">slog&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">slog&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">slog&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;number&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="string-のみパターン">(string) のみパターン&lt;/h2>
&lt;p>Ruby / Logger&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>logger&lt;span style="color:#0550ae">.&lt;/span>info&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ちなみにActiveSupportのTaggedLoggingを使うとタグ（コンテキスト）を付与したロガーを生成できる&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>logger &lt;span style="color:#0550ae">=&lt;/span> logger&lt;span style="color:#0550ae">.&lt;/span>tagged&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;context&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="その他">その他&lt;/h2>
&lt;h3 id="string-object-object-string-パターン">(string), (object), (object, string) パターン&lt;/h3>
&lt;p>Node.js / pino&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;string message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#1f2328">message&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json message&amp;#39;&lt;/span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#1f2328">message&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json message&amp;#39;&lt;/span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#0a3069">&amp;#39;string message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="string-object-object-パターン">(string, object), (object) パターン&lt;/h3>
&lt;p>winston&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;string message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;string message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">message&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json&amp;#39;&lt;/span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#1f2328">message&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json&amp;#39;&lt;/span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="個人的に好んでいるロガーインターフェース">個人的に好んでいるロガーインターフェース&lt;/h2>
&lt;p>好みの問題かもしれないが (string, object) をサポートしていると嬉しいなと思っている。&lt;/p></description></item><item><title>SWR の revalidateOnFocus は window.confirm() でも再検証が動く</title><link>https://blog.freedom-man.com/revalidate_on_window_confirm.html</link><pubDate>Wed, 03 Sep 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/revalidate_on_window_confirm.html</guid><description>&lt;p>&lt;a href="https://swr.vercel.app/">SWR&lt;/a> の &lt;code>revalidateOnFocus&lt;/code> オプションが効いた状態で &lt;code>window.confirm()&lt;/code> によるダイアログでOK/キャンセルを選択した際にもフォーカスが戻ったとみなされて再検証が動くらしい、というメモ。&lt;/p>
&lt;p>再現コードはこんな感じ。confirmを閉じるタイミングで毎回refreshされる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-tsx" data-lang="tsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">useSWR&lt;/span> &lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#0a3069">&amp;#34;swr&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">App() {&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">data&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">useSWR&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/hello&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#6639ba">Math&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">random&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">revalidateOnFocus&lt;/span>: &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">span&lt;/span>&lt;span style="color:#1f2328">&amp;gt;{&lt;/span>&lt;span style="color:#1f2328">data&lt;/span>&lt;span style="color:#1f2328">}&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">span&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">button&lt;/span> &lt;span style="color:#1f2328">onClick&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{()&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">confirm&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;OK?&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)}&amp;gt;&lt;/span>&lt;span style="color:#1f2328">confirm&lt;/span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">button&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#1f2328">App&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>連続してconfirmを押すとrefreshされないことがあるが、多分連続して押したときにブラウザがフォーカスイベントを発生させないのかもしれない。5秒間隔くらいで押すと毎回refreshされる感じ。&lt;/p>
&lt;p>なので、window.confirm()しつつその後データ更新を行い、更新後のデータを取得するという場合にはmutate()を使わなくてもリフレッシュされちゃったりする。
（とはいえ &lt;code>mutate()&lt;/code> を明示的に呼び出したほうが良いんだけど）&lt;/p></description></item><item><title>pinoのロギングを (string, object) のインターフェースで呼び出したい</title><link>https://blog.freedom-man.com/pino_logger_customize.html</link><pubDate>Tue, 02 Sep 2025 22:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/pino_logger_customize.html</guid><description>&lt;p>Node.jsのロガーライブラリの &lt;a href="https://github.com/pinojs/pino">pino&lt;/a> は以下のようなインターフェースでログ出力できる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">pino&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;pino&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">logger&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">pino&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;string message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#1f2328">message&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json message&amp;#39;&lt;/span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">({&lt;/span> &lt;span style="color:#1f2328">message&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json message&amp;#39;&lt;/span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#0a3069">&amp;#39;string message&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>見てもらえるとわかるように&lt;/p>
&lt;ul>
&lt;li>第１引数が文字列のみ&lt;/li>
&lt;li>第１引数がオブジェクトのみ&lt;/li>
&lt;li>第１引数がオブジェクトで第２引数が文字列&lt;/li>
&lt;/ul>
&lt;p>に対応しているが、 &lt;code>第１引数が文字列で第２引数がオブジェクト（メタデータ・コンテキスト）&lt;/code> には対応していない。&lt;/p>
&lt;p>他の言語のロガーはだいたいこの方式に対応していたりするので、pinoもこのインターフェースに対応したい。ということで以下のような感じでカスタマイズできる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ts" data-lang="ts">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">pino&lt;/span> &lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#0a3069">&amp;#34;pino&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">logger&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">pino&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">hooks&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">logMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">method&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// 第１引数が文字列, 第２引数がオブジェクトの場合
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0550ae">2&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">typeof&lt;/span> &lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0a3069">&amp;#34;string&amp;#34;&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">typeof&lt;/span> &lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0a3069">&amp;#34;object&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">msg&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">context&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// @ts-expect-error
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">method&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">apply&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[{&lt;/span> &lt;span style="color:#1f2328">...&lt;/span>&lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">msg&lt;/span> &lt;span style="color:#1f2328">}]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// @ts-expect-error
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">method&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">apply&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">inputArgs&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これで&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">info&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;string message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">userId&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0550ae">123&lt;/span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>という感じで呼び出すと&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">&amp;#34;level&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0550ae">30&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">&amp;#34;time&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0550ae">1756819989743&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">&amp;#34;pid&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0550ae">27639&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">&amp;#34;hostname&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#34;xxxx&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">&amp;#34;userId&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">&amp;#34;msg&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#34;string message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>という感じな出力になる。&lt;/p></description></item><item><title>vitest-browser-html というライブラリを書いた</title><link>https://blog.freedom-man.com/vitest_browser_html.html</link><pubDate>Mon, 01 Sep 2025 22:20:00 +0900</pubDate><guid>https://blog.freedom-man.com/vitest_browser_html.html</guid><description>&lt;p>Vitest Browser モードはブラウザ上でテストを実行できるモードで、JSDOMを使わずにブラウザのAPIを使ってちゃんとテストできるのが便利。&lt;/p>
&lt;p>しかしながら、対応しているライブラリが React や Vue などモダンなものばっかりで、jQueryやAlpine.jsなどには対応していなかった。ということで &lt;a href="https://www.npmjs.com/package/vitest-browser-html">vitest-browser-html&lt;/a> というライブラリを作って公開してみた。&lt;/p>
&lt;h2 id="使い方">使い方&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>npm install -D vitest-browser-html
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>でインストールして、以下のようにして利用する。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">render&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vitest-browser-html&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">page&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;@vitest/browser/context&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">expect&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">it&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vitest&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">it&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;render String&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">screen&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;lt;div&amp;gt;String&amp;lt;/div&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">expect&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">element&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">screen&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getByText&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;String&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)).&lt;/span>&lt;span style="color:#1f2328">toBeVisible&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>render関数の中にHTML文字列を入れてもらえればOK。&lt;/p>
&lt;p>Alpine.jsでテストしたい場合は &lt;code>Alpine.initTree()&lt;/code> をcontainerに適用すればOK。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">render&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vitest-browser-html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">it&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">expect&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vitest&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">Alpine&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;alpinejs&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">it&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;render by Alpine&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">screen&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;&amp;lt;div x-data=&amp;#34;{ foo: `bar` }&amp;#34; x-text=&amp;#34;foo&amp;#34;&amp;gt;Hello World&amp;lt;/div&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Alpine&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">initTree&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">screen&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">container&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">expect&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">element&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">screen&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getByText&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;bar&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)).&lt;/span>&lt;span style="color:#1f2328">toBeVisible&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>jQueryの場合はこんな感じでテストできるようになる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">render&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vitest-browser-html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">it&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">expect&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vitest&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">$&lt;/span> &lt;span style="color:#1f2328">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;jquery&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">it&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;render by jQuery&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">async&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">screen&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;&amp;lt;div id=&amp;#34;some-id&amp;#34; data-testid=&amp;#34;some-id&amp;#34;&amp;gt;hoge&amp;lt;/div&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;#some-id&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;fuga&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">await&lt;/span> &lt;span style="color:#1f2328">expect&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">element&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">screen&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getByTestId&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;some-id&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)).&lt;/span>&lt;span style="color:#1f2328">toHaveTextContent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;fuga&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これでjQueryを使っているDOM操作系の関数やAlpine.jsのコンポーネントのテストができるようになる…！&lt;/p></description></item><item><title>Laravelでちょっとした非同期処理をしたい場合は defer() を使うと良いかもよ</title><link>https://blog.freedom-man.com/laravel_defer.html</link><pubDate>Sun, 31 Aug 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_defer.html</guid><description>&lt;p>Laravelで非同期処理を行いたいときの選択肢はキューワーカーかプロセスの非同期実行になりがちで、キューワーカーは正攻法ではあるがインフラやアプリケーションコードが大掛かりになるし、プロセスの非同期実行はそれ用のスクリプトを書く必要があり、ちょっとした非同期処理を行いたいときには少し面倒だったりする。&lt;/p>
&lt;p>ということで調べたら &lt;code>defer()&lt;/code> というヘルパー関数があって、プロダクションで使ってみたらめっちゃ便利に使えたのでメモ&lt;/p>
&lt;h2 id="defer-とは">defer() とは？&lt;/h2>
&lt;p>&lt;a href="https://laravel.com/docs/12.x/helpers#deferred-functions">defer()&lt;/a> は Laravel 11.23 から利用できるヘルパー関数で、HTTPレスポンスをクライアントに返した後に任意の処理を実行できる。&lt;/p>
&lt;p>具体的には以下のような形で呼び出して、擬似的な非同期処理を実行できる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">defer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// なんか重い処理
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">response&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">json&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$data&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>擬似的な&lt;/code> と表現したのは、別プロセス/スレッドで行うような非同期処理ではなく、HTTPレスポンスを送信したあとに同一プロセス/スレッド内で実行するため。&lt;/p>
&lt;h2 id="どう動いているのか">どう動いているのか&lt;/h2>
&lt;p>deferで呼ばれた関数は &lt;code>Illuminate\Support\Defer\DeferredCallback&lt;/code> でラップされたあとに、 &lt;code>Illuminate\Support\Defer\DeferredCallbackCollection&lt;/code> にarray pushされる。&lt;/p>
&lt;p>&lt;a href="https://github.com/laravel/framework/blob/66d16cb899e007dc8f5f8db33445cfbc9b69a20c/src/Illuminate/Support/functions.php#L18-L29">https://github.com/laravel/framework/blob/66d16cb899e007dc8f5f8db33445cfbc9b69a20c/src/Illuminate/Support/functions.php#L18-L29&lt;/a>&lt;/p>
&lt;p>&lt;code>Illuminate\Foundation\Http\Middleware\InvokeDeferredCallbacks&lt;/code> のミドルウェアの &lt;code>terminate()&lt;/code> では &lt;code>DeferredCallbackCollection&lt;/code> の &lt;code>invokeWhen&lt;/code> の処理を呼び出す。
&lt;a href="https://github.com/laravel/framework/blob/66d16cb899e007dc8f5f8db33445cfbc9b69a20c/src/Illuminate/Foundation/Http/Middleware/InvokeDeferredCallbacks.php#L25-L37">https://github.com/laravel/framework/blob/66d16cb899e007dc8f5f8db33445cfbc9b69a20c/src/Illuminate/Foundation/Http/Middleware/InvokeDeferredCallbacks.php#L25-L37&lt;/a>&lt;/p>
&lt;p>ミドルウェアの &lt;code>terminate()&lt;/code> はレスポンスを送信したあとに動くので、擬似的な非同期処理を実現できるという感じ。&lt;/p>
&lt;h2 id="httpレスポンス送信後に接続が切れて処理が中断されないのか">HTTPレスポンス送信後に接続が切れて処理が中断されないのか？&lt;/h2>
&lt;p>という疑問があったので調べてみました。結論、送信後は接続が切れても処理は中断されないみたい。&lt;/p>
&lt;h3 id="mod_php">mod_php&lt;/h3>
&lt;p>&lt;a href="https://www.php.net/manual/ja/function.flush.php">flush()&lt;/a> したあとにクライアントから接続が切られても後続の処理は実行されていそう。&lt;/p>
&lt;p>&lt;a href="https://github.com/php/php-src/blob/ca4a841921b2c51fc9aa0c1847f0cdd801844ef5/sapi/apache2handler/sapi_apache2.c#L287-L311">https://github.com/php/php-src/blob/ca4a841921b2c51fc9aa0c1847f0cdd801844ef5/sapi/apache2handler/sapi_apache2.c#L287-L311&lt;/a>&lt;/p>
&lt;p>クライアントから接続が &lt;code>flush()&lt;/code> 前に切られていたら後続処理も実行されないが、そもそもレスポンスも返さないのでまぁしょうがない。&lt;/p>
&lt;p>プロダクションのmod_phpな環境で数秒程度かかる処理にdefer()を使っているが問題なく動いている。web記事だとfastcgiでしか使えない？みたいなことが書かれてあったりするけどmod_phpでも普通に動いてます。&lt;/p>
&lt;h3 id="fastcgi">fastcgi&lt;/h3>
&lt;p>fastcgiの場合は &lt;a href="https://www.php.net/manual/ja/function.fastcgi-finish-request.php">fastcgi_finish_request()&lt;/a> が呼ばれるが、ドキュメントによるとクライアントにflushしつつ、後続処理を実行できるらしい。&lt;/p>
&lt;h2 id="注意">注意&lt;/h2>
&lt;p>同一プロセス/スレッドで動く制約上、長時間かかるような処理だとプロセス/スレッドを占有し続けてしまうため、バッチやキューワーカーで対応するのが良い。それ以前にロードバランサやWebサーバーのTimeoutに引っかかりそうだけど…。&lt;/p>
&lt;p>同様の理由で数秒程度であってもリクエスト数が多い場合でも同じく占有する可能性があるので別の方法を検討したほうが良さそう。ただし、プロセス/スレッド数/インスタンス数を増やすという手もあるのでケースバイケース。&lt;/p>
&lt;h2 id="参考url">参考URL&lt;/h2>
&lt;p>&lt;a href="https://www.amitmerchant.com/the-magic-behind-laravels-new-defer-helper/">https://www.amitmerchant.com/the-magic-behind-laravels-new-defer-helper/&lt;/a>&lt;/p></description></item><item><title>DockerでPHP環境を構築するには install-php-extensions を使うと良いかもよ</title><link>https://blog.freedom-man.com/install_php_extensions.html</link><pubDate>Sat, 30 Aug 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/install_php_extensions.html</guid><description>&lt;p>&lt;a href="https://frankenphp.dev/docs/docker/#how-to-install-more-php-extensions">Frankenphpのドキュメント&lt;/a> を見ていたら &lt;code>install-php-extensions&lt;/code> という &lt;code>docker-php-ext-install&lt;/code> みたいなコマンドでPHP拡張をインストールしていたので気になったので調べてみたメモ。&lt;/p>
&lt;h2 id="docker-php-ext-install">docker-php-ext-install&lt;/h2>
&lt;p>公式のPHPのDockerイメージに入っている &lt;a href="https://github.com/docker-library/php/blob/29d20bc9c45e6ce6342e01ada7743e4b24d3c399/docker-php-ext-install">docker-php-ext-install&lt;/a> はPHP拡張をインストールしてくれるのだが、そのPHP拡張をインストールするために必要な依存関係をaptやapkで自動インストールしてくれないので、その依存パッケージを調べて自前でインストールする必要がある。そして、これがとても面倒で、毎回ググっていたりする。
また、peclでインストールする必要がある拡張もあるため、ext-installだっけ？peclだっけ？みたいな脳内分岐ロジックが発生していた。結果としてDockerfileのRUNの中身が増えがちだった。&lt;/p>
&lt;h2 id="install-php-extensions">install-php-extensions&lt;/h2>
&lt;p>docker-php-ext-installの課題を解決してくれるのが &lt;a href="https://github.com/mlocati/docker-php-extension-installer/blob/be8fcebbcb397bc10885bcd31f8db7e6d16b10a1/install-php-extensions">install-php-extensions&lt;/a> で、依存関係も含めてapt/apk installしてくれたり、pecl経由のインストールもすべてこのスクリプトが担ってくれている。&lt;/p>
&lt;p>例えば &lt;code>zip&lt;/code> をインストールするには &lt;code>libzip&lt;/code> が必要になったりするがその依存関係を意識することなく以下のコマンドだけでインストールできる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>install-php-extensions zip
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>さらにはcomposerもインストールできる。マルチステージビルドでcomposer取ってきたりしなくても良い。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>install-php-extensions @composer
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ということでめっちゃ便利だしFrankenphpのDockerfileでも使われていて品質的にも問題なさそうに思うので、積極的に使ったほうが良いかもなーと思ったりしている。&lt;/p></description></item><item><title>コードレビューの真の価値はコミュニケーション</title><link>https://blog.freedom-man.com/code_review_communication.html</link><pubDate>Thu, 28 Aug 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/code_review_communication.html</guid><description>&lt;p>コードレビューは概ね以下のような目的で行われている。&lt;/p>
&lt;ol>
&lt;li>コード自体の品質を担保する
&lt;ul>
&lt;li>外部品質 = ちゃんと動くのか。UI/UX的に問題ないのか。&lt;/li>
&lt;li>内部品質 = 保守性（可読性・拡張性）・セキュリティ・パフォーマンス・自動テスト&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>コードをチームに共有する（＝チームの所有物にすること）&lt;/li>
&lt;li>ドメイン（ビジネス・技術）の共有&lt;/li>
&lt;li>コードを通じたコミュニケーション&lt;/li>
&lt;/ol>
&lt;p>1の品質担保が一番重要そうなのだが、実際はそれ以外が大事だよ、という駄文を書く。&lt;/p>
&lt;h2 id="コードをチームに共有する">コードをチームに共有する&lt;/h2>
&lt;p>コードレビューによって書いたコードがチームの持ち物になる。&lt;/p>
&lt;p>何か不具合が発生したときも、そのコードを理解している人が1人でも増えれば不具合解消までの時間は減るかもしれない。解消までの時間が減らなくても不具合発生時の実装者の心理的負担は少なくなる。
そのコードに関する機能追加をしたいときもコードがチームの持ち物になれば他の人が対応しやすくなり、チーム全体の生産性が上がる。&lt;/p>
&lt;p>コードレビューでは「誰か１人レビュー通ればOK」とか「チームリーダーがレビューする」という運用をしているところがあると思うが、コードの共有という意味ではできるだけ多くの人がレビューしたほうが価値があるし、時間があるときに軽く目を通しておくと良かったりする。&lt;/p>
&lt;h2 id="ドメインビジネス技術の共有">ドメイン（ビジネス・技術）の共有&lt;/h2>
&lt;p>コードレビューはドメインを共有する機会にもなる。&lt;/p>
&lt;p>このテーブルはレコード数が多い、エンドポイントのリクエスト数が多い、同じような処理がありドメインとしても共通化できそう、とか。
要求や要件のレビューを通じてビジネスドメインを知る機会になるかもしれない。&lt;/p>
&lt;p>エンジニアが技術的な知見を共有し合うチャンネルとしても有効だ。
影響範囲を出すための方法、データベース設計やパフォーマンスチューニングの知見、セキュリティを考慮した実装など。コードを実装しなくても解決できるような技術的引き出しを共有することで、より本質的な課題解決ができるようになるかもしれない。&lt;/p>
&lt;h2 id="コードを通じたコミュニケーション">コードを通じたコミュニケーション&lt;/h2>
&lt;p>コミュニケーションは質より量を意識したほうが良い。
エンジニアにとってコードレビューはそれ自体が貴重なコミュニケーションチャンネルの１つだ。&lt;/p>
&lt;p>ドメインや知見を共有しなくても「この実装良いですね！」とか「対応ありがとうございます！」とか絵文字のリアクションをつけたりするだけで、お互いに仕事がしやすくなる。&lt;/p>
&lt;p>「一旦この実装でOKで、チームで改めて方針は再検討しても良いですね！」みたいな課題発見や問題提起をしても良い。エンジニアはコードがあるからこそ会話しやすい側面もあるので、コードレビューというコミュニケーションチャンネルを活かさないのはとてももったいなく感じる。&lt;/p>
&lt;h2 id="生成aiによる自動レビューでは負担は減るけど工数は減らない">生成AIによる自動レビューでは負担は減るけど工数は減らない。&lt;/h2>
&lt;p>生成AIによる自動レビューは主に品質問題を解消する効果がある。
一方で、品質問題を解消しているからといって人間によるレビューが不要になる、ということは全くない。
前述の通り、人間がコードレビューをしないとコードがチームに共有されず、知見を共有する機会が減ってしまう。勉強会などで知見を共有する方法はあるかもしれないが、実務ベース・実コードに勝る教材はない。&lt;/p>
&lt;p>生成AIのよる自動レビューによって、品質観点のレビューに対する人間の負担は少しは減るのだろうが、共有やコミュニケーションといった部分に関しては無視できない工数がかかるし、無視してはいけない。&lt;/p>
&lt;h2 id="レビューで品質を担保することは難しい">レビューで品質を担保することは難しい&lt;/h2>
&lt;p>品質は「内部品質」「外部品質」に分類される。&lt;/p>
&lt;p>「外部品質」の観点だと、開発物が正常に動くのかを見ることになるが、何が正常かどうかは実装した本人とステークホルダーが詳しいはずで、レビュワーは責任を持つべきではない。レビューで細かいところは見切れないし、相当のスキルが求められるため品質担保を目的とするのは現実的ではないというのもある。また、実装者本人が責任を持つからこそ、自動テストや手動テストに対する意識が高まるという効果もある。実際に障害が発生して振り返りをするプロセスを踏むからこそ品質を強く意識するようになる。&lt;/p>
&lt;p>「内部品質」の観点だと、事業や組織体制、プロダクトの特性とメンバーの経験や能力によって良い品質の定義が変わってしまう。半端な知識で良い品質を求めた結果、オーバースペックになったりすることはよくあるし、すぐ捨てるコードであれば高い可読性は不要になる。そのため、コードレビューによって品質をある程度担保、くらいはできるが高い水準で担保することは現実的には不可能かもしれない。&lt;/p>
&lt;h2 id="コードレビューはコミュニケーションである">コードレビューはコミュニケーションである&lt;/h2>
&lt;p>端的に言ってしまうとコードレビューは単なるコミュニケーションなので、
生成AIで完全代替はできないし、工数はこれからも下がらないだろう。
もし下がったのであれば単純にコミュニケーションが足りていないだけである。&lt;/p>
&lt;p>コミュニケーションだからこそ、新規参画者やスキルセットが十分ではないメンバーほどコードレビューに参加したほうがチームとして役に立つ。その前提を踏まえた上で、現実的な工数感とかも考慮してレビュープロセスの運用を考えていくとよいのではないかなと思ったり。&lt;/p></description></item><item><title>チームの能力はそのチームが経験することに依存するのでそう簡単に伸ばせない</title><link>https://blog.freedom-man.com/team_learning.html</link><pubDate>Sun, 17 Aug 2025 21:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/team_learning.html</guid><description>&lt;p>チームの能力はそのチームが経験することに依存するのでそう簡単に伸ばせない、という駄文を書いてみる。
&lt;br/>
&lt;br/>&lt;/p>
&lt;p>例えば、テストを書いていないチームにシニアエンジニアがジョインして諸々を整備したり啓蒙したとしても、チームがテストの有用性について経験していないためテスト文化が浸透しづらくテストカバレッジが思ったより上がらない、ということがよくある。
&lt;br/>&lt;/p>
&lt;p>一方でテストコードで防げたはずの手戻りやインシデント、ミドルウェアやライブラリのアップグレード時の苦難をチームが経験するとテストを推進しやすくなる。ビジネスインパクトの面でステークホルダーへの説明もしやすい。
&lt;br/>
&lt;br/>&lt;/p>
&lt;p>書籍や登壇資料、Web記事を読んでインプットすることは非常に有用だと思う一方で、それよりは経験から学ぶことが大きいし今後のその人の考え方やキャリアに強く影響する。パフォーマンスやセキュリティ、保守性の問題を経験したエンジニアはその問題に対して強い感度や考えを持つ、という感じ。また、個々人が今まで行ってきた経験よりも、そのチームでの歴史的な経験がチームの考え方に強く影響を及ぼしている。そのため、どんなにシニアエンジニアの経験値や実力が凄かったとしてもチームの能力は、そのチームが経験することに依存する。
&lt;br/>
&lt;br/>&lt;/p>
&lt;p>チームが学習するためには、ただ単純に「経験」するだけではなく「経験」の後の「振り返り」とその次の「アクション」が重要だったりする。どんなに手戻りやインシデントを経験してもそもそも振り返りをしていなかったり、振り返りに対応するネクストアクションが未熟だと何も変わらない。&lt;/p>
&lt;p>例えばテストコードで防げる不具合に対する対策として手動テストの項目をむやみに増やしたり（もちろん手動テストも大事なんだけど）、オペレーションミスに対してシステムや運用フローによって認知負荷を下げるような仕組みを考えずにひたすらにダブルチェック・トリプルチェックとやってしまうと（もちろんレビュープロセスも大事だけど）やはり学習機会にはつながりづらい。&lt;/p>
&lt;h2 id="シニアエンジニアの振る舞い">シニアエンジニアの振る舞い&lt;/h2>
&lt;p>シニアエンジニアが環境を整備したり啓蒙することはもちろん大事なのだが、一番大事なのは失敗しやすい土壌を整え、振り返りを促進し、アクションを提案し、チームとして強くなるきっかけを作ってあげることなのではないかと思ったりする。&lt;/p>
&lt;p>小さく早く失敗し、振り返り、学習することがチームにとって重要なので、それを整えてあげたり率先してその姿勢を見せるのもシニアとしての振る舞いとしてよいのかもしれない。&lt;/p>
&lt;h2 id="余談">余談&lt;/h2>
&lt;p>チームの状態に依るのだが、コードレビューに関しては個人的な意見はもちろん述べつつも大きな問題がなければ通すことがある。その設計でうまくいけば良いし、もしうまくいかなかったらそれがチームの経験になり、それを振り返り、改善することで学習につなげることができるからだ。意見を矯正しすぎてしまうのは個々人やチームの成長機会を奪ってしまうような気がしている。IMOなので参考にしてね、くらい。もちろんリスクが大きいもの、切り戻しがしづらいものに関してはしっかりとレビューをしている。&lt;/p></description></item><item><title>LaravelとReactを使いたいならInertia.jsを使ったほうが良いんじゃね</title><link>https://blog.freedom-man.com/laravel_inertia.html</link><pubDate>Mon, 11 Aug 2025 23:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_inertia.html</guid><description>&lt;p>バックエンドにLaravel、フロントエンドにReactを使いたい場合、ルーティングライブラリにNext.jsを採用し、LaravelはAPIサーバーとして利用するケースが多く見られる。&lt;/p>
&lt;p>が、個人的にはこの構成は学習コストや保守性の観点であまりおすすめしておらず、 Inertia.jsを使ったほうが良いのではと思っている。ルーティングがLaravelだけで管理されるだけでなく、APIを意識しないシームレスなデータ連携ができるし、Next.jsほど複雑な仕組みではないので学習コストも低い。OpenAPIやRPC系ツールが目指したようなバックエンド・フロントエンド間の型安全性も Laravel Data や TypeScript Transformer を使うことで解決できる。&lt;/p>
&lt;p>ということで、今回はこのあたりの技術について紹介する。&lt;/p>
&lt;h2 id="inertiajs">&lt;a href="https://inertiajs.com/">Inertia.js&lt;/a>&lt;/h2>
&lt;p>Bladeは「型安全じゃない」「UIライブラリのエコシステムが弱い」「小さなコンポーネントには向かない」などの理由で色々辛くなりがち。ビューへの変数の受け渡しは実行時にしか検証できないため、不要な変数の検知やリファクタリングが難しく、補完も効かせづらい。&lt;/p>
&lt;p>フロントエンドのロジック実装に関しては &lt;a href="https://alpinejs.dev/">Alpine.js&lt;/a> を使うと保守性が上がるものの、Bladeでコンポーネント指向に書くには少しハードルを感じるし、Alpine.jsはコンポーネント化にあまり向いていない印象。Web Components を使ったとしてもSSRの仕組みが別途必要になったりエコシステムがあまり強くない。&lt;/p>
&lt;p>Inertia.js を使うとテンプレートエンジンのように React や Vue を利用でき、「型安全であり」「UIライブラリのエコシステムが強く」「小さなコンポーネント」を作れる。SSRも対応しているのでSEO系も問題なし。画面遷移もSPAな感じでいける。ReactやVueでフロントエンドを実装できるのは開発生産性だけではなく、エンジニアの技術的キャリア形成としても良さそうだし採用面でも期待できる。&lt;/p>
&lt;p>Inertia.jsは以下のブログ記事にまとめていたりするので詳細はそちらで。&lt;br>
&lt;a href="https://tech.yappli.io/entry/inertiajs">https://tech.yappli.io/entry/inertiajs&lt;/a>&lt;/p>
&lt;h2 id="typescript-transformer">&lt;a href="https://spatie.be/docs/typescript-transformer/v2/introduction">TypeScript Transformer&lt;/a>&lt;/h2>
&lt;p>Inertia.jsを使うと「型安全になる」と言ったが、バックエンドとフロントエンドの境界（propsの受け渡し）はInertia.jsだけでは型安全にならない。そこで、TypeScript Transformerというツールを使うとPHPクラスをTypeScriptの型定義に変換できるため、Inertia.jsのprops受け渡しも型安全にできる。&lt;/p>
&lt;p>具体的には &lt;code>Inertia.render()&lt;/code> するときにPHPのクラスを引数に指定し、そのPHPクラスの型定義をフロントエンドのpropsで利用すれば良い。Viteのカスタムプラグインでファイル監視しつつ自動的に型定義を生成する、といったことも簡単。&lt;/p>
&lt;p>コントローラ例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;demo&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">Inertia&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;demo&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">DemoData&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;hoge&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">})&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">name&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;demo&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ページコンポーネント例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-typescript" data-lang="typescript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// App.Data.DemoData の型がPHPのコードから自動生成される
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">export&lt;/span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">Demo&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">props&lt;/span>: &lt;span style="color:#cf222e">App.Data.DemoData&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://gist.github.com/tzmfreedom/909fe18979982eff98fc307766188795">Viteのカスタムプラグイン例&lt;/a>&lt;/p>
&lt;h2 id="laravel-data">&lt;a href="https://spatie.be/docs/laravel-data/v4/introduction">Laravel Data&lt;/a>&lt;/h2>
&lt;p>FormRequestは「テストがしづらい」「補完が効かない」「型安全じゃない」といった課題があり、ApiResourceも同様の問題を抱えている。&lt;/p>
&lt;p>Laravel Dataを使うとマジックメソッドを使っていないので「補完が効く」し「型安全」になる。また、インスタンス化も簡単でバリデーションもでき「テストもしやすい」。マジックメソッドを使わないので前述のTypeScript Transformerとの相性も良い。&lt;/p>
&lt;h2 id="その他">その他&lt;/h2>
&lt;p>Inertia.jsで利用できるフロントエンドライブラリは &lt;code>React&lt;/code> &lt;code>Vue&lt;/code> &lt;code>Svelte&lt;/code> になる。UIライブラリの充実性と生成AIとの相性を考えてReactを選択するとよいのではないかと思っている。&lt;/p>
&lt;p>実装するWebサイトがリッチなフロントエンドを必要としない場合でも&lt;/p>
&lt;ul>
&lt;li>単純なページ表示であればpropsを受け取ってレンダリングするだけ
&lt;ul>
&lt;li>stateやeffect管理は不要で、Reactの学習コストが気にならない&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>ちょっとした表示コンポーネントの共通化も気軽にできる&lt;/li>
&lt;li>それでいて型安全、補完が効くので開発体験が良く、負債になりづらい&lt;/li>
&lt;/ul>
&lt;p>といった理由で採用する価値があると思っている。&lt;/p>
&lt;p>&lt;a href="https://speakerdeck.com/tzmfreedom/alpine-dot-js-mpa">以前はAlpine.jsを推していた&lt;/a> のだがコンポーネント性の弱さや、ビュー全体の型安全性も担保できないので、今はInertia.js推しになっている感じ。&lt;/p>
&lt;h2 id="とはいえ越えられない壁はある">とはいえ越えられない壁はある&lt;/h2>
&lt;p>RSCやReact Router v7、RPC系のライブラリはフロントエンドとバックエンドがTypeScriptということもあり、データの受け渡しなど非常にシームレスな開発ができる。&lt;/p>
&lt;p>この点はInertia.jsもそうだが、バックエンドで他の言語を使っている以上はこの開発体験を越えることはできない。また、TypeScriptほどの型表現を持っているバックエンドの言語は限られるため、そのあたりのインピーダンスミスマッチみたいなのもありそう。&lt;/p>
&lt;p>とはいえ、バックエンドのエコシステムや開発生産性といったところで別言語のメリットが強い部分もあるため、このあたりはトレードオフとも言えそう。&lt;/p></description></item><item><title>正論モンスターはなぜダメなのか</title><link>https://blog.freedom-man.com/righteous_argument.html</link><pubDate>Sat, 02 Aug 2025 23:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/righteous_argument.html</guid><description>&lt;p>私はいわゆる「正論モンスター」がとても苦手なのだが（そして苦手な人が大多数だと思うのだが）なぜダメなのか、どうするべきなのか駄文を書く。&lt;/p>
&lt;h2 id="理由1-正論を言うだけでは何も変わらない">理由1: 正論を言うだけでは何も変わらない&lt;/h2>
&lt;p>正論をストレートに言えば、周りに思いが伝わって勝手に状況が改善されるのかというと全くそんなことはない。むしろ「そんなことはわかっているけどできないんだよ」といった感じで反感を買ってしまったり、それによって協力を得られづらい状況になることがほとんどだろう。&lt;/p>
&lt;p>そもそも組織や文化によっては、その正論が本当に正しいのかすら怪しい。仮に正しかったとしても、その理想状態を作っていくためには「自分で手をちゃんと動かして少しずつ改善する」とか「人を巻き込んで仕組みを変えていく」ことが大事なのかなと思っている。&lt;/p>
&lt;p>正論だけではなく次のアクションや巻き込みに対する言葉が無いと何も変わらない。&lt;/p>
&lt;h2 id="理由2-正論を言うだけではリスペクトに欠ける">理由2: 正論を言うだけではリスペクトに欠ける&lt;/h2>
&lt;p>「正論モンスター」と「正論を言うけどちゃんと物事を動かしてくれる人」の大きな違いの１つに周りへの配慮・リスペクトが見えるかどうかというのがある。&lt;/p>
&lt;p>今そこでパッションを持って働いている人がいることに対して配慮が足りていないのはあまり好きではない。楽しく働けて、それでいて厳しさもあり成長し合える環境が望ましいのに、リスペクトが欠けてしまうと居心地は良くないだろう。実情はどうであれ、正論を投げ捨てるだけの人は単純に自分の憂さ晴らしをしたいだけのように思えてしまう。&lt;/p>
&lt;p>また、歴史的経緯や組織的状況など様々な要因があるはずなのに、それに対する配慮が欠けていると残念な気持ちになってしまう。チームにジョインした直後など、心理的安全とはいえハレーションが起きやすい状況においては、リスペクトを感じさせる言動や態度が大事だと思う。&lt;/p>
&lt;h2 id="ではどうすればよいのか">ではどうすればよいのか？&lt;/h2>
&lt;p>自分が新しいチームに入って、ペインや改善点を見つけたとき&lt;/p>
&lt;ul>
&lt;li>「テストや静的解析が無いと不安なので導入しちゃって良いですか！？誰か着手中じゃなければ！」&lt;/li>
&lt;li>「◯◯の振り返りしませんか？自分ファシリやるんで！」&lt;/li>
&lt;/ul>
&lt;p>みたいな感じで &lt;code>提案&lt;/code> をしつつ &lt;code>責任&lt;/code> を自分に向けるようにしている。
慣れてきたら &lt;code>責任&lt;/code> をチームで分担する形にするが、ずっと自分でやっても良いなという心持ちではいる。&lt;/p>
&lt;p>これを例えば「テストや静的解析が無くてレガシーですね」とか「振り返りやらないとかダメじゃないですか？」という感じで正論を投げ捨ててしまうのは絶対に良くないパターン。それに対してどう改善したいか、どう動くのかが明示されていないと誰も動かないし、言い方にリスペクトがないと正しかったとしても人は動かない。人は論理ではなく感情で動く。&lt;/p>
&lt;p>また、「言い出しっぺがそのタスクをやるのは嫌」という意見があると違和感がある。「言い出しっぺこそそのタスクをやるべき」だし「言い出しっぺだからこそ成長できる」とも言える。&lt;/p>
&lt;hr>
&lt;p>とまぁ偉そうなことを言っているが自分が20代の頃は「正論モンスター」だったときもあるし、今も意図せずリスペクトを欠いた発言をしているかもしれない。「正論モンスター」にならないために少し控えめになってしまっている部分もあるかもしれない。&lt;/p></description></item><item><title>必要になったらやれば良い vs 今やらないと一生やらない</title><link>https://blog.freedom-man.com/yagni_or_not.html</link><pubDate>Wed, 30 Jul 2025 22:30:18 +0900</pubDate><guid>https://blog.freedom-man.com/yagni_or_not.html</guid><description>&lt;p>私は基本的に「必要になったらやれば良いじゃん」という強めのYAGNI派閥なのだが、一方で「それって一生やらないから今やろう」という意見もそれなりに聞く。そのたびにモヤモヤしていたのだけど、最近わりと自分の中で整理できたので駄文を書く。&lt;/p>
&lt;p>まず、自分は腕力があるタイプなので「必要になったらやれば良いじゃん」と思ってしまうのだが、一般的に腕力があるエンジニアは少ないので大抵の組織において「必要になったらやれば良いじゃん」のハードルが高い。&lt;/p>
&lt;p>例えば軽いリファクタリング系のタスクであってもバックログに積まれっぱなしで本流の開発と並行してサブタスクをやる余裕はほとんどのチームにおいて無いのである。いわゆる改善デーのような本流の開発以外のサブタスクを集中的にやる期間を設けたとしても優先度が他のタスクに負けてしまい、腕力の総量不足も相まって「一生やらない」ことになってしまう。おそらく「それって一生やらないから今やろう」の主張の人はこういった経験が強いのだと思うし、シニアエンジニア＝腕力タイプというわけではないので、シニアかどうかに限らずこういった意見はあるのかもしれない。&lt;/p>
&lt;p>というわけで、理想的にはYAGNIは良いと思っているし、これからの考え方としてもベースに置きつつも、現実的には開発リソースは有限かつそこまで高くないのが常なので少し過剰かもしれないけど今やっておく、が実は後々良い結果をもたらすこともあるのかもしれないし、その主張も理解できるかもなぁと思ったのであった。（とはいえ過剰な設計が保守性など後々悪い結果をもたらすことが多いと経験上感じるので、そのあたりと折り合いを付ける必要はある）&lt;/p>
&lt;p>また、この件に限らず「自分が手を動かすなら」ではなく「他の人が手を動かすなら」とかそういう視点で考えるとチームで認識を揃えるときにもう少し現実的な落とし所が見つかるのかもなぁと思っていたりする。&lt;/p></description></item><item><title>リスクを取る人は凄いしカッコいい</title><link>https://blog.freedom-man.com/risk_taker.html</link><pubDate>Mon, 28 Jul 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/risk_taker.html</guid><description>&lt;p>リスクを取る人は凄いしカッコいい。と最近思ったので駄文を書く。&lt;/p>
&lt;p>リターンがあるからこそリスクを取るし、大きなリターンを取ろうとすればするほどリスクも伴う。&lt;/p>
&lt;p>例えば&lt;/p>
&lt;ul>
&lt;li>新しい技術を使うことで課題解決したり新たな知見・経験を得ることができるリターンがある一方で失敗するリスクがある&lt;/li>
&lt;li>価値のある難しいタスクをやることは失敗する可能性も高い&lt;/li>
&lt;li>技術的に正しいことをやっていても、多少のハレーションを生むかもしれない&lt;/li>
&lt;li>そのアプローチが短期的にはうまくいくが中長期的にはうまくいかないかもしれない&lt;/li>
&lt;li>中長期的に施行している（しようとしている）タスクがうまくいかないかもしれない&lt;/li>
&lt;/ul>
&lt;p>などなど、仕事をしていると日々大小さまざまなリスクと向き合うことになる。&lt;/p>
&lt;p>ここで言っているリスクはビジネス的な損失だけではなく失敗による自分あるいは他者からのネガティブな感情も含んでいる。&lt;/p>
&lt;p>そもそも失敗というのはただの行動した出力結果に過ぎないので、そうネガティブに感じなくても良いのだが、
それをわかっていても当の本人はそういったニュートラルな感情になりにくい。&lt;/p>
&lt;p>数カ月・数年後には成長のきっかけだなと思えることであっても、その当時はそんな感情には一切ならないことが多い。&lt;/p>
&lt;p>そもそもその案件やタスクをやるべきではなかったのではないか？と思ってしまうこともあるだろう。&lt;/p>
&lt;p>しかし、「現状をよりよくする」ことを目的に実際に行動をしたのだから行動していない人よりも称賛されても良いような気がしている。&lt;/p>
&lt;p>逆に、大きなリターンのためにリスクを取った人に対して、安全なところから批評・批判されているのを見るのはあまり気分が良いものではない。&lt;/p>
&lt;p>というわけで改めてリスクを取っている人は凄いなと思ったし、自分も適切にリスクテイクしていかないとなと思うのだった。&lt;/p></description></item><item><title>安定して回っている良いチームの定義</title><link>https://blog.freedom-man.com/good_team.html</link><pubDate>Sun, 27 Jul 2025 21:59:18 +0900</pubDate><guid>https://blog.freedom-man.com/good_team.html</guid><description>&lt;p>自分が入らなくてもうまく回っていて安心して案件を任せられるな、という良いチームの定義について考えてみた。&lt;/p>
&lt;br/>
&lt;h2 id="チームになっていること">チームになっていること&lt;/h2>
&lt;p>チーム内で助け合う風土やコミュニケーションが十分にできていること。&lt;/p>
&lt;p>朝会など頻度の高いコミュニケーションを行っていたり、技術的な議論やドメインの共有ができていること。&lt;/p>
&lt;hr>
&lt;p>技術云々の前にこれができていないと、チームで物事を進めれず、生産性・開発物の質とスピードが圧倒的に落ちてしまうのでなかなか厳しい。&lt;/p>
&lt;br/>
&lt;h2 id="技術基盤ができていること">技術基盤ができていること&lt;/h2>
&lt;p>アプリケーションのコード基盤、CI/CDやローカル開発環境、コンテナやIaCなど変更に強いインフラ基盤、監視・アラートなどなど、最低限の基盤ができていること。アプリケーションコードのテストを書く習慣があること。&lt;/p>
&lt;p>あるいはこれからできる素養があり、技術的に強いメンバーが参画したり、チームとして基盤技術をキャッチアップして現実に適用する能力があること。&lt;/p>
&lt;hr>
&lt;p>プロダクトエンジニアリングで価値を出していくには一定以上の技術基盤は必要。
質とスピードに直結するし、オブザーバビリティ・セキュリティ・パフォーマンスなどは安定して運用するうえで重要。
チーム外のシニアエンジニアに一時的に手を借りて技術基盤を作ってもらったとしても、
その技術基盤に対してオーナーシップを持って積極的に保守・運用・改善を行うことが大事。&lt;/p>
&lt;br/>
&lt;h2 id="チーム外の有識者に適切なコミュニケーション相談ができること">チーム外の有識者に適切なコミュニケーション・相談ができること&lt;/h2>
&lt;p>チームの経験不足を補う手段としてチーム外の有識者に適切なコミュニケーション・相談ができること。
また、技術者だけではなく、ビジネスのステークホルダーとのコミュニケーションが円滑にできていること。&lt;/p>
&lt;hr>
&lt;p>ビジネスを回していくうえで、技術者・非技術者問わずステークホルダーと適切にコミュニュケーションするスキルは大事。
または、フォローしやすい体制を整えていくことも大事。&lt;/p>
&lt;br/>
&lt;h2 id="良いチームは誰が作るか">良いチームは誰が作るか&lt;/h2>
&lt;p>良いチームは「チームメンバーが作る」側面もあるが、そうなるように適切にフォローする・しやすい体制を整えるのが大事。&lt;/p>
&lt;ul>
&lt;li>技術共有・ドメイン共有の仕組みを最初に整備してリーディングする。&lt;/li>
&lt;li>技術基盤を整えるのにシニアエンジニアが一時的にお手伝いする。&lt;/li>
&lt;li>コミュニケーションのフックを作りやすいように1on1を設定してあげる。&lt;/li>
&lt;/ul>
&lt;p>などなど。&lt;/p></description></item><item><title>物事がうまく進まないパターン</title><link>https://blog.freedom-man.com/move_forward.html</link><pubDate>Thu, 19 Jun 2025 22:40:00 +0900</pubDate><guid>https://blog.freedom-man.com/move_forward.html</guid><description>&lt;p>抽象的なプロジェクトでうまく物事が進まないなぁというのはよくある。&lt;/p>
&lt;p>進まない、あるいはプロジェクトが頓挫してしまうよくある理由を雑にまとめてみた。&lt;/p>
&lt;h2 id="締切がない">締切がない&lt;/h2>
&lt;p>締切があれば何かしらのアウトプットは生みやすい。アウトプットがあればフィードバックを受けて次のステップに進むことができる。&lt;/p>
&lt;p>逆に締め切りがないとずっと議論をして物事が進まない。
トップダウン的に締め切りを切ってもらうのが一番楽だが、ボトム的にマイルストーンを定義して進めていくことも大事。&lt;/p>
&lt;p>シンプルにして最重要かも。&lt;/p>
&lt;h2 id="議論が空中戦になりがち">議論が空中戦になりがち&lt;/h2>
&lt;p>議論が空中戦になって、今議論すべき課題、次に決めるべき課題があやふやになったりすると危ない。
システムで言うと、プロトタイプ的な動くものが無いと議論が空中戦になりがちで、ドメインを熟知している人同士がずっと話しがち。
動くものがあれば、それを見て共通認識を作れるし、見て初めて分かることもあるしもっと物事を進められる。&lt;/p>
&lt;h2 id="理想を追いすぎてしまう">理想を追いすぎてしまう&lt;/h2>
&lt;p>これは「締切がない」に関連していて、「締切がない」と理想を追いすぎてしまい要件や考えるべきこと、議論すべきことが増えてしまう。
理想を追う議論はとても大事だが、追いすぎて時間を使ってしまうのも危険だと思う。
抽象的なプロジェクトこそ現実的で具象的なタスクやシステムに落とし込んでトライ＆エラーで漸進的に進めるのが良い。
まずは20点くらいのプロトタイプを作って、議論してフィードバックを受けてそれを60点にしてリリースするイメージ。&lt;/p>
&lt;h2 id="アサインが中途半端">アサインが中途半端&lt;/h2>
&lt;p>そのプロジェクトが主務ではない場合、手を動かしたりじっくり考える時間無いと物事が進まない。&lt;/p>
&lt;h2 id="ステークホルダーが多い">ステークホルダーが多い&lt;/h2>
&lt;p>MTGの参加人数が10人前後になると「議論が空中戦になりがち」「理想を追いすぎてしまう」などが発生する。&lt;/p>
&lt;h2 id="決める権限が無い">決める権限が無い&lt;/h2>
&lt;p>決める権限＝決定し、遂行し、リスクを背負うメンバーがいないのも危ない。
これも「締切がある」と、決定せざるを得ないし、それまでに情報をある程度集めないといけないので物事が進む。&lt;/p></description></item><item><title>自動テストについて思っていることメモ</title><link>https://blog.freedom-man.com/testing.html</link><pubDate>Thu, 19 Jun 2025 00:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/testing.html</guid><description>&lt;p>自動テストについて思っていることを雑に書いてみる&lt;/p>
&lt;h2 id="なぜテストコードを書くのか">なぜテストコードを書くのか&lt;/h2>
&lt;p>自動テストは主に「コードを変更した際の予期せぬ不具合を防ぐ」「各コンポーネントが期待通り動くことを保証する」という目的を達成するためにあると思っている（設計のカナリアなどは一旦ここでは除外）。 &lt;strong>有効なテスト&lt;/strong> を書くことで、新規コードの不具合を未然に防ぎ、既存コードを安全に変更できるようになり、結果としてアウトプットの質とスピードが上がる。手法はさておき、これらの目的を満たすテストを書くことが重要だ。&lt;/p>
&lt;h2 id="内側のテストと外側のテスト">内側のテストと外側のテスト&lt;/h2>
&lt;p>内側のテスト（単体テスト）を書くだけではリグレッションテストができないため、外側のテスト（インテグレーションテスト・E2Eテスト）も書いたほうが良い。たとえば、あるAPIエンドポイントの一部の処理を担うクラス・メソッドの変更を安全に行うにはインテグレーションテストが書かれていないとAPIとしての動作保証ができない。内側のテストと外側のテストの検証内容が一致するのであれば外側のテストだけ書くほうが保守も考えるとコスパが良い。もちろん、境界値テストなど処理パターンの複雑さによっては外側のテストだけではデータの用意が煩雑になったりテスト時間が伸びる可能性があるため、その場合は内側のテストでカバーすると良い。&lt;/p>
&lt;h2 id="モック">モック&lt;/h2>
&lt;p>外側・内側どちらのテストにおいてもモックは避けたほうが良い。モックは開発者の自作自演のテストになり、リグレッションテストの効果が薄れる。さらに、モックするメソッドの変更に追従する必要があり壊れやすいテストになるため保守性が下がる。モックしない場合はテストデータなどを事前に用意する必要があるが、今どきのフルスタックフレームワークであれば苦労せずテストデータの作成ができるはずだ（テストのしやすさで技術選定するべきとも言える）。むしろ、アプリケーションはデータが中心なので、データを用意しなければ本質的なテストはできない。DBアクセスなどでテスト時間が伸びがちだが、並列化やCIでの自動テストの対象を限定するなどやりようは色々ある。フィードバックの速さが開発者体験的に大事というのは理解できるが、だからといってモックにしてしまうのは本来の目的を見失っていると思う。そういうわけで、モックはHTTPリクエストなどコンテナ等で用意できない要素に絞るなど最小限の利用にすべきだ。&lt;/p>
&lt;h2 id="privateメソッドのテスト">privateメソッドのテスト&lt;/h2>
&lt;p>内側のテストと外側のテストと考え方は同じで、privateメソッド（内側）をテストしたい場合、ロジックが単純であればpublicメソッド（外側）経由のテストで十分だ。privateメソッドのロジックが複雑で、publicメソッドのテストでやるにはコストがかかるようなケースでは単体テスト（内側のテスト）を行うようにprivateメソッドをテストしても良い。ただし、別クラスにメソッドを適切に移譲できないかどうかは検討する必要がある。ドメインモデル貧血になっていないかは注意が必要で、privateメソッドの処理は概ね既存モデルに移管できることも少なくはなさそう。&lt;/p>
&lt;h3 id="テストのために可視性を緩めるかどうか問題">テストのために可視性を緩めるかどうか問題&lt;/h3>
&lt;p>前モデルにも移譲しづらく、クラス分けするほどでもない場合はprivateメソッドのテストをするのは良いと思う。テストをする際はリフレクションを使ってもよいが、可視性を上げて呼び出せるようにしても概ね問題ないように思う。&lt;/p>
&lt;p>Java(Guava)やFlutterにはVisibleForTestingアノテーションがあり、テスト用に可視性を上げていることが一目でわかるようにできるし、静的解析でテスト以外で呼び出している場合に警告を出すことも可能だ。&lt;/p>
&lt;p>ちなみにPHP(PHPStan)でも同様のアノテーションを作ってみたので良ければ使ってみてほしい。
&lt;a href="https://github.com/tzmfreedom/phpstan-visible-for-testing">https://github.com/tzmfreedom/phpstan-visible-for-testing&lt;/a>&lt;/p>
&lt;h3 id="privateメソッドのテストは壊れやすい">privateメソッドのテストは壊れやすい？&lt;/h3>
&lt;p>privateメソッドは公開インターフェースじゃないので、privateメソッドを削除したりインターフェースを変更したり振る舞いを変えたらテストも大幅に変更する必要がある。&lt;/p>
&lt;p>テストしたいprivateメソッドがあるということはそのドメインに対して重要なロジックが含まれているということだ。単純なロジックであればpublicメソッド経由でテストすれば良いし、複雑なロジックだからこそprivateメソッドに分割してテストをしたいということだ。その複雑で重要なドメインロジックを有するprivateメソッドを変更するというのはそれなりに大工事をしているわけで、その周辺のテストが壊れるのは想定内であるべきだしテストが落ちること自体は良いことだ。また、もともとのprivateメソッドのテスト自体は「内部テスト」として価値を出していたのではないだろうか。&lt;/p>
&lt;p>privateメソッドをモックをしなければインターフェースやメソッドの削除をしても既存の外側のテストは壊れないし、偽陰性・偽陽性は発生しない。&lt;/p>
&lt;h3 id="責務分離クラス新規作成をすべきかどうか問題">責務分離＝クラス新規作成をすべきかどうか問題&lt;/h3>
&lt;p>privateメソッドをテストしたくなったら、別のクラスを新規作成して、そのクラスにメソッドを実装し呼び出す（移譲する）べきという主張があると思う。これはドメインモデル貧血を防ぐためにも概ね同意ではあるもののモデルに属しづらい処理がある場合、毎回クラスを新規作成するとそれはそれで読み手も書き手もやりづらくないかという気持ちもある。また、クラス新規作成したところで結局同じメソッドが場所を移動しただけになるので、保守性・可読性を考えてリファクタリングを選択すべき。&lt;/p>
&lt;h2 id="余談-phplaravelのfacade">余談: PHP/LaravelのFacade&lt;/h2>
&lt;p>LaravelのFacadeって嫌われがちだが、モックしやすいので良い選択だと思っている。
例えばHTTP Facadeを使ってくれれば結合テストを後から書くのがめっちゃ楽。逆にcurlを直接使っていたり、Guzzleをその場でインスタンス生成していたりすると大変。良い感じにDIしてくれれば良いだが、現実はそんなに甘くない…。&lt;/p>
&lt;h2 id="まとめ">まとめ&lt;/h2>
&lt;p>とにかく &lt;strong>有効なテスト&lt;/strong> を書くことが大事。
経験上、有効なテストが十分に書かれていないアプリケーションはとても多い。体感7割以上。
レガシーコードと言われているアプリケーションのほとんどがテストが書かれていない。
テストがないからコードを安全に変更できない、安全に変更できないからミドルウェア・ライブラリがアップデートできず、顧客に価値提供ができない、といった形だ。また、書かれていてもモックだらけだったりして真にリグレッションテストができていないコードに出くわすことも少なくない。&lt;/p>
&lt;p>テスト時間が遅くなる、テストの保守性が悪い（壊れやすいテストがある）という悩みは本当に幸せな悩みだと思う。テストが無いアプリケーションはテストを増やして防波堤を作るまでの量的な壁があるし、テストを書く文化を根付かせるのはより難易度が高い。だからこそエンジニアにはハードスキルとしてテストを書くスキルを磨いてほしいと思っている。テスト駆動開発じゃなくても全く問題ない。生成AIだとテスト書くのめっちゃ楽だし。原理主義に陥らずテストを書く経験を増やすことが大事。&lt;/p></description></item><item><title>対内的アウトプットの重要性</title><link>https://blog.freedom-man.com/the_output.html</link><pubDate>Wed, 18 Jun 2025 23:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/the_output.html</guid><description>&lt;p>エンジニアはアウトプットが大事とよく言われる。&lt;/p>
&lt;p>この文脈ではXやブログ記事の投稿、登壇など対外的なアウトプットを指すことが多い。&lt;/p>
&lt;p>しかしながら業務においては以下のような対内的なアウトプットの方が必須スキルだと思っている。&lt;/p>
&lt;ol>
&lt;li>自分のやっていることの発信&lt;/li>
&lt;li>自分の考え・感情の表明&lt;/li>
&lt;li>技術・ビジネスドメインの言語化&lt;/li>
&lt;/ol>
&lt;p>&lt;code>1&lt;/code> に関してはフルリモート環境において、自分の周りの人が何をやっているかわからない、という状況がよくある。
この状況を改善するには一人ひとりが自分のやっていることを発信していくことだと思っている。
&lt;code>timesチャンネル&lt;/code> はその方法の１つだと思うし、デイリーMTGがあれば、やっていることの発信が強制されるのでチーム内で何をやっているのかを把握できる。&lt;/p>
&lt;p>&lt;code>2&lt;/code> の自分の考え・感情を表明していくのも大事だ。現在の状況や出来事に対してどのように課題に感じているのか、どう解決しようとしているのか、何に困っているのか、といったことを知ることで、解決に向けてフォローしたりされたり、あるいは共感を得ることで少し気が楽になるかもしれない。
デイリーMTGにおける「困りごと」「相談事項」の共有や上長とのMTGではこのアウトプットに該当する。
振り返りも考え方を共有する貴重な機会だ。&lt;/p>
&lt;p>&lt;code>3&lt;/code> の言語化＝ドキュメンテーションは、自分の中でものごとを整理できるだけでなく、組織や未来の自分にとって重要な資産となる。
READMEやwiki、ADR以外にもMTGの議事録を書くことも該当する。&lt;/p>
&lt;p>こうして考えると &lt;code>透明性&lt;/code> と言われるものは、 &lt;code>各人のアウトプット&lt;/code> の努力やそれを推進・強制する仕組み（デイリーMTG、振り返り、1on1など）が重要なのかもしれない。もし、デイリーMTGや振り返りや1on1が無かったり頻度が十分ではない場合は、透明性が失われチーム感が無くなり当事者意識も無くなってしまうかもしれない。当たり前のようにある仕組みは意外と大事なんだなぁと改めて思ったりしたのであった。&lt;/p></description></item><item><title>技術選定の難しさメモ</title><link>https://blog.freedom-man.com/tech_decision.html</link><pubDate>Wed, 18 Jun 2025 23:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/tech_decision.html</guid><description>&lt;p>技術選定に解はなく、組織やユースケースなど様々なファクターが絡み合う、という大前提の上で自分は枯れた技術を選びがちである。&lt;/p>
&lt;p>例えば不確実性の高い要件であれば、チームや自分の経験値が高い枯れたフルスタックフレームワークを選択するし、なるべくシステムをシンプルに認知負荷が上がらないようにする気持ちがある。その枯れた技術の中で少しずつ新しい技術を取り入れてリスクテイクしている感じ。&lt;/p>
&lt;p>流行りの技術＝枯れていない技術とすると、流行りの技術は以下のような懸念があるのかなと思っている。&lt;/p>
&lt;ul>
&lt;li>なにか技術的な問題が発生したときに自力で解決できる技術力が必要&lt;/li>
&lt;li>流行りの技術が何かに秀でている要素が合ったとして、トレードオフがある可能性があり、結果枯れた技術を採用するのとプラマイゼロのケースがある&lt;/li>
&lt;li>「流行りの技術を使って楽しい」と思えるのはせいぜい数ヶ月から１年くらいな気がする&lt;/li>
&lt;/ul>
&lt;p>一方で枯れた技術を選択し続けることで、学習機会を奪ってしまっているのではないかという懸念もある。
既存技術の延長でしか成長できないのではないか、とか。&lt;/p>
&lt;p>また、以下のようなケースであれば新しい技術を採用するのは良いと思う。&lt;/p>
&lt;ul>
&lt;li>なにかパフォーマンスの問題などでマイクロサービスで局所的に解消できるケース&lt;/li>
&lt;li>その技術選定にチームが中長期的に覚悟を持って取り組めるケース&lt;/li>
&lt;li>なにか問題が発生したときに捨てれる、あるいはビジネスに全く影響なく作り直すなどなんとかする技術力を有しているケース。あるいはドメイン的に作り直しが全く問題ない、リスクがないケース。&lt;/li>
&lt;/ul>
&lt;p>ビジネス要件と技術選定が紐づくため、枯れた技術で解決できない課題があれば積極的に新しい技術を検討すべきだし、
採用など中長期的に覚悟を持って取り組めるのであれば止めるものは何もないのかな、といった感じ。&lt;/p>
&lt;p>逆に避けるべきケースとしては↓こんな感じ。&lt;/p>
&lt;ul>
&lt;li>チームとしてその技術を使ってビジネスを遂行できない&lt;/li>
&lt;li>中長期的なPros/Consを検討できていない。例えば運用負荷・認知負荷を全く検討できていない、とか。&lt;/li>
&lt;/ul>
&lt;p>とはいえ、技術選定に解はない（再掲）なので難しいんだよなぁ。&lt;/p></description></item><item><title>Terraform業務で触ってみたメモ</title><link>https://blog.freedom-man.com/terraform.html</link><pubDate>Wed, 18 Jun 2025 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/terraform.html</guid><description>&lt;p>仕事で &lt;a href="https://developer.hashicorp.com/terraform">Terraform&lt;/a> をガッツリ触る機会があったのでキャッチアップでやったことや見た資料をざっと書く。Google Cloudに適用する、というコンテキスト。&lt;/p>
&lt;p>雑に書くので結構間違いあるかもだがメモということで&lt;/p>
&lt;h2 id="必要なツールをインストール">必要なツールをインストール&lt;/h2>
&lt;p>Terraformのバージョンマネージャーである &lt;a href="https://github.com/tfutils/tfenv">tfenv&lt;/a> をインストールして &lt;code>tfenv install xxx&lt;/code> で対象バージョンのterraformをインストール。
&lt;code>.terraform-version&lt;/code> ファイルを用意してバージョン切り替えする。&lt;/p>
&lt;p>補完やsyntax highlightの目的で、VSCodeなどの拡張機能を適宜インストール。&lt;br>
&lt;a href="https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform">HashiCorp Terraform&lt;/a>&lt;/p>
&lt;p>インストールしたら対象のワークディレクトリで &lt;code>terraform init&lt;/code> してモジュールなどをダウンロード。&lt;/p>
&lt;h2 id="フォーマッタとtflintとバリデーションの整備">フォーマッタとtflintとバリデーションの整備&lt;/h2>
&lt;p>&lt;a href="https://github.com/terraform-linters/tflint">tflint&lt;/a> やプロバイダーのplugin入れたり、CIやMakefileで実行したり、 &lt;a href="https://github.com/terraform-docs/terraform-docs">tarraform-docs&lt;/a> を導入して自動でドキュメントを生成したり。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>tflint
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>terraform validate
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>terraform fmt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="コマンドを叩いて色々確認">コマンドを叩いて色々確認&lt;/h2>
&lt;p>planコマンドを叩いたりapplyしてみたり&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-hcl" data-lang="hcl">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">terraform&lt;/span> &lt;span style="color:#cf222e">plan&lt;/span>&lt;span style="color:#57606a">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># 対象モジュール・リソース指定: 同時並行で色々やってるときに開発環境に試し適用するときに使ったり
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">terraform&lt;/span> &lt;span style="color:#cf222e">plan&lt;/span> &lt;span style="color:#f6f8fa;background-color:#82071e">-&lt;/span>&lt;span style="color:#cf222e">target&lt;/span> &lt;span style="color:#cf222e">module&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">module_name&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">terraform&lt;/span> &lt;span style="color:#cf222e">plan&lt;/span> &lt;span style="color:#f6f8fa;background-color:#82071e">-&lt;/span>&lt;span style="color:#cf222e">target&lt;/span> &lt;span style="color:#cf222e">module&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">module_name&lt;/span>}&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">resource&lt;/span>}&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">resource_name&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">terraform&lt;/span> &lt;span style="color:#cf222e">apply&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">terraform&lt;/span> &lt;span style="color:#cf222e">apply&lt;/span> &lt;span style="color:#f6f8fa;background-color:#82071e">-&lt;/span>&lt;span style="color:#cf222e">target&lt;/span> &lt;span style="color:#cf222e">module&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">module_name&lt;/span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">terraform&lt;/span> &lt;span style="color:#cf222e">apply&lt;/span> &lt;span style="color:#f6f8fa;background-color:#82071e">-&lt;/span>&lt;span style="color:#cf222e">target&lt;/span> &lt;span style="color:#cf222e">module&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">module_name&lt;/span>}&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">resource&lt;/span>}&lt;span style="color:#1f2328">.&lt;/span>{&lt;span style="color:#cf222e">resource_name&lt;/span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="terraform自体の勉強">terraform自体の勉強&lt;/h2>
&lt;p>基本的な書き方をキャッチアップしつつ以下の記事を読んで作法やTerraform利用時の課題感を理解&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-hcl" data-lang="hcl">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">lifecycle&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> prevent_destroy &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>でterraformからの誤った削除を防止したり
リソース自体に削除防止機能があればそれを有効化しておく。
Cloud SQLだと &lt;code>deletion_protection = true&lt;/code> を指定したり。&lt;/p>
&lt;p>tosetで変数を使いたい場合はキーがknown valueじゃないといけないので、outputやリソース参照などknown valueじゃない場合は
keyがknown valueなmapを使ったりして対応。&lt;/p>
&lt;p>リソース名は変更するとdestroy/createになるので注意。
terraform mvとかmovedブロックを使うことになる。&lt;/p>
&lt;p>dataブロックを使うとproviderの情報を良い感じに使うことができて便利&lt;/p>
&lt;h2 id="github-actionsによる自動planapply">GitHub Actionsによる自動plan/apply&lt;/h2>
&lt;p>手元でデプロイしても良いが自動化したくなったりミスオペ怖かったりするのでCI/CDした。
手元でデプロイする場合も権限はCI/CDで実行するユーザ（workfload identity）にimpersonateするように調整した。&lt;/p></description></item><item><title>共有と定着</title><link>https://blog.freedom-man.com/share.html</link><pubDate>Thu, 02 Jan 2025 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/share.html</guid><description>&lt;p>技術共有やドメイン共有をやっていると、共有したものがチームに定着してないなと感じることがよくある。&lt;/p>
&lt;p>これは&lt;/p>
&lt;ol>
&lt;li>共有内容や共有方法が良くない、分かりづらい&lt;/li>
&lt;li>共有内容とチームのレベルにギャップがある&lt;/li>
&lt;li>共有回数や頻度が少ないので理解・定着しない&lt;/li>
&lt;/ol>
&lt;p>といった理由がありそうなのだが、そもそも「共有しただけでは定着しない」という面がある。手を動かしたり自分の頭で整理して考える、経験することで初めて共有したものが定着する。&lt;/p>
&lt;p>自分の経験的にも、共有されたときに内容を理解したとしても定着している感じはしない。例えば、ある運用方法について座学で共有をされるよりは、作ってもらった資料を見ながら運用を実際に経験するほうがずっと定着する。とはいえその座学による共有が無駄かというと全くそうではなくて、一度座学で概要理解したからこそ手を動かしたときに理解がしやすくなっている。&lt;/p>
&lt;p>なので共有したことがゴールではなく共有した後が実は大事で&lt;/p>
&lt;ul>
&lt;li>XXの開発・運用するときは資料を参考にしてください！もしわからなかったらお気軽にメンションください！&lt;/li>
&lt;li>XXの技術で困ったときは自分に問い合わせください！&lt;/li>
&lt;/ul>
&lt;p>みたいな感じで、共有された人の次のアクション（共有されたドメインの開発・運用、技術導入など）のハードルを下げるような振る舞いと伴走が必要と感じている。&lt;/p>
&lt;p>ということで、共有したものが定着しないと感じたときは共有のやり方を見直しつつ、そもそも「手を動かして経験しないと定着しない」ことを念頭に置くと少し気が楽になるかもしれない。&lt;/p>
&lt;p>逆に、共有された人は積極的にアクションしていくことが大事で、詳しい人にタスクを任せようではなく、自分がやってみようという心意気が必要と感じる。ドメイン共有であれば関連するコードを時間を作って追ってみたりテストコードを書いてみる、というのも定着につなげる大事なアクションだ。&lt;/p></description></item><item><title>2025</title><link>https://blog.freedom-man.com/2025.html</link><pubDate>Wed, 01 Jan 2025 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2025.html</guid><description/></item><item><title>2024年の振り返り</title><link>https://blog.freedom-man.com/2024-summary.html</link><pubDate>Mon, 30 Dec 2024 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/2024-summary.html</guid><description>&lt;p>今年もええ感じに振り返っていくよ！&lt;/p>
&lt;h2 id="転職した仕事について">転職した＆仕事について&lt;/h2>
&lt;p>個人ブログや会社ブログにいくつか書いたが今年4月に転職した。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://blog.freedom-man.com/leaving_3rd_company">https://blog.freedom-man.com/leaving_3rd_company&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.freedom-man.com/job_change_to_4th">https://blog.freedom-man.com/job_change_to_4th&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.bm-sms.co.jp/entry/2024/08/27/110000">https://tech.bm-sms.co.jp/entry/2024/08/27/110000&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>入社してからやったこととしてはこのあたり&lt;/p>
&lt;ul>
&lt;li>担当サービスの施策開発&lt;/li>
&lt;li>&lt;a href="https://tech.bm-sms.co.jp/entry/2024/12/04/100000_1">担当サービスの技術基盤改善&lt;/a>&lt;/li>
&lt;li>横断的な技術基盤整備&lt;/li>
&lt;/ul>
&lt;p>担当サービスの施策開発と技術基盤改善がメインタスクで、以下のことを目的として取り組んでいた。&lt;/p>
&lt;ol>
&lt;li>担当サービス自体をグロースさせるため&lt;/li>
&lt;li>担当サービスの技術基盤を整備することで他のサービスも真似しやすくなり、結果として全体的な技術基盤改善につなげるため&lt;/li>
&lt;li>運用する上で足りない機能を洗い出し、横断的な技術基盤として実装推進するため&lt;/li>
&lt;li>ドメインや技術的特性を知るため&lt;/li>
&lt;li>自身のサービス担当者としての信頼貯金を貯めるため&lt;/li>
&lt;/ol>
&lt;p>個人的には特に3,4,5を期待してやっていて、来年はもう一段階広い視点で業務に取り組むことになりそうなこともあり、よりレバレッジが高そうな施策に取り組むためのファーストステップをやっていった感じ。色々タスクをこなした結果、組織やビジネスに対する解像度がかなり上がったと思う。&lt;/p>
&lt;p>横断的な技術基盤整備でいうと「ログ出力」「バッチ実装」「データ変更」に関するガイドラインや「PHPStan」「PHPUnit」「Datadog APM」「CloudWatch Logs」あたりの入門向けのドキュメントを書いていたりした。 中長期的に効くものだと思うので、引き続きコンテンツを増やしていけると良いなと思っている。来年はこれに加えて社内勉強会とかもちょくちょく開催できるとより良さそうかなと思っていたり。&lt;/p>
&lt;p>あとは前職と同様に会社のSlackチャンネルにPHPの記事を投下していたりして、PHPがなんか得意そうな人がいるという感じでプレゼンスも上げれたんじゃないかな、多分。&lt;/p>
&lt;p>一方でアンラーニングはあまりできなかった印象。ビジネス理解や業務理解を高めるところがまだ全然できていないとか、技術以外の改善施策を全然打てなかったなぁとか。Salesforceを使い倒している組織なので、Salesforceも学び直ししないといけない感じもしている。&lt;/p>
&lt;h2 id="体調面">体調面&lt;/h2>
&lt;p>仕事自体は全体で見ると比較的パフォーマンス出せたところがある一方で、社会人になってから一番体調を崩したんじゃないかというぐらい不調な１年だった。特に5月と12月がずっと体調悪くて大変だった。こどもが4月に保育園入園してからはこどもが体調を崩したり親に伝染ったりしはじめてそこから大きく崩れた感じがする。あるあるとはいえ中々に大変。&lt;/p>
&lt;p>体調不良によってキャンセルした予定も結構あって、同月に2〜3キャンセルするとさすがに精神的にも気が滅入る感じだった。逆に予定入れなくてよかったなと思うくらいのときもあり、あまり健全な状態ではないので体調面に関しては本当にどうにかしたい。&lt;/p>
&lt;p>運動もほとぼそとランニングを続けていたりしたのだが体調不良が続いて最近は全然走れてない。来年はもう少し頻度上げたい…（そのためには体調面どうにかしないと）&lt;/p>
&lt;h2 id="アウトプット">アウトプット&lt;/h2>
&lt;p>&lt;a href="https://fortee.jp/phpcon-2024/proposal/200bfecc-5527-4da8-905c-a4d4a43710b3">phpcon 2024に登壇&lt;/a>した。育児の関係で２年間登壇を控えていたので、久しぶりに登壇できてとても嬉しい。前述の通り12月はめちゃくちゃ体調悪い月で、登壇もギリギリ体調が間に合った日だったので登壇のクオリティはさておき参加できて本当に嬉しかった。とはいえ体調面でトークがあまり見れず懇親会も参加できなかったのは残念だった。来年も何かしら登壇できると良いなぁというのと体調整えて全力で参加していきたい。&lt;/p>
&lt;p>ブログもいくつか書けた。プライベートの方は主にLaravelのコードリーディングで、おかげで理解度はかなり上がった気がする。今後は技術に限らず色々と考え方をもう少し雑に書いていこうかなぁと思っていたりする。会社の方のブログは前述の2本。来年もこれくらい書けると良いなぁ。&lt;/p>
&lt;h2 id="その他">その他&lt;/h2>
&lt;h3 id="育児">育児&lt;/h3>
&lt;p>相変わらずこどもは可愛くて楽しく過ごせている。保育園も楽しく遊んでいるようで友達が増えていたり、まだ2歳に満たないのに集団生活をしていて本当にすごいなぁという感じ。離乳食から幼児食に変わったり歩いたり話したり手が器用になったり物事を理解できるようになったり毎日成長していて驚かされている。&lt;/p>
&lt;p>一方で夜泣きが本格化して大変な１年だった。特に体調不良の中やる夜泣き対応は肉体的にも本当に厳しい感じだった。&lt;/p>
&lt;h3 id="ゲーム">ゲーム&lt;/h3>
&lt;p>ゴーストオブツシマを買って全クリまで。龍が如く７外伝と龍が如く８も買ったのだが全然できていない。外伝が中盤くらいで止まっていてストーリー忘れかけているｗ&lt;/p>
&lt;h3 id="本">本&lt;/h3>
&lt;p>全然読めなかった…。来年はガツガツ読んでいきたい。&lt;/p>
&lt;h3 id="買ったもの">買ったもの&lt;/h3>
&lt;p>夜泣きなどで睡眠量が確保できないケースもあり、エアウィーヴを導入して睡眠の質を上げようとしたがもともと睡眠自体が得意だったので効果はちょっとわからない。&lt;/p>
&lt;p>ちょっとした距離の移動でバス利用が面倒だったのもあり、電動自転車と普通の自転車を買った。結果、行動範囲を広げれたり、こどもを乗せてサイクリングできたのでとても良い買い物だった。バス移動だとこどもの機嫌が悪いと精神的に疲弊するのだが、自転車だと機嫌が良くてだいたい寝てくれるのでそういう意味でもとても楽。&lt;/p>
&lt;h2 id="今年の振り返り来年に向けて">今年の振り返り＆来年に向けて&lt;/h2>
&lt;p>体調面以外は公私ともに良い感じに過ごせた１年だった。
会社もポジションも良い選択をしたと思っていて、今の会社でしかできない仕事・経験があり、とてもワクワクしている。今までやってきたアプローチでは通用しないところもありそうで、そこは愚直にアンラーニングしていきたいし、結果的に成長につながると確信しているので引き続き頑張っていきたい。&lt;/p>
&lt;p>ということで、来年はまずは体調を整えるということが一番。その上で公私ともに楽しくできれば良いと思っている。来年は沖縄あたり旅行したいなぁ。&lt;/p>
&lt;br/>
ということで今年も大変お世話になりました！&lt;br/>
来年もよろしくお願いいたしまっす！！</description></item><item><title>LaravelのEloquentの仕組み: Model::find()</title><link>https://blog.freedom-man.com/laravel_eloquent_find.html</link><pubDate>Wed, 24 Jul 2024 22:10:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_eloquent_find.html</guid><description>&lt;p>Laravelのコードリーディングメモ。今日はいよいよEloquent。&lt;/p>
&lt;p>まずは&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">HogeModel&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">find&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>がどうやって動いているのかを見ていきます。&lt;/p>
&lt;hr>
&lt;p>まず &lt;code>Model::__callStatic()&lt;/code> が呼ばれ、staticメソッドはインスタンスメソッドに置き換えて実行されます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__callStatic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$parameters&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#953800">$parameters&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L2349-L2352">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L2349-L2352&lt;/a>&lt;/p>
&lt;p>インスタンスメソッドにも &lt;code>find()&lt;/code> メソッドは存在しないので &lt;code>__call()&lt;/code> が呼ばれます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__call&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$parameters&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">in_array&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;increment&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;decrement&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;incrementQuietly&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;decrementQuietly&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#953800">$parameters&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$resolver&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">relationResolver&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$resolver&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Str&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">startsWith&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;through&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">method_exists&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$relationMethod&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">Str&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">of&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">after&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;through&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">lcfirst&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">toString&lt;/span>&lt;span style="color:#1f2328">()))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">through&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$relationMethod&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">forwardCallTo&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">newQuery&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#953800">$method&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$parameters&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>最終的に &lt;code>$this-&amp;gt;newQuery()&lt;/code> に処理が委譲されます。&lt;/p>
&lt;p>&lt;code>newQuery()&lt;/code> は対象のモデルを &lt;code>setModel()&lt;/code> でセットした &lt;code>Illuminate\Database\Eloquent\Builder&lt;/code> のインスタンスを生成します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">newQuery&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">registerGlobalScopes&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">newQueryWithoutScopes&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">newQueryWithoutScopes&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">newModelQuery&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">with&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">with&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withCount&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withCount&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">newModelQuery&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">newEloquentBuilder&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">newBaseQueryBuilder&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setModel&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">newEloquentBuilder&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$query&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Builder&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$query&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1487-L1490">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1487-L1490&lt;/a>
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1534-L1539">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1534-L1539&lt;/a>
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1497-L1502">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1497-L1502&lt;/a>
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1569-L1572">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Model.php#L1569-L1572&lt;/a>
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Builder.php#L1837-L1844">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Builder.php#L1837-L1844&lt;/a>&lt;/p>
&lt;p>&lt;code>forwardCallTo()&lt;/code> は &lt;code>$object&lt;/code> の &lt;code>$method&lt;/code> を &lt;code>$parameters&lt;/code> パラメータを付けて呼び出す委譲メソッドです。ということで今回はEloquentBuilderの &lt;code>find()&lt;/code> が呼ばれます。&lt;/p></description></item><item><title>Laravelのエラーハンドリングの仕組み</title><link>https://blog.freedom-man.com/laravel_error_handler.html</link><pubDate>Tue, 23 Jul 2024 21:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_error_handler.html</guid><description>&lt;p>Laravelのエラーハンドリングのコードリーディングメモ。&lt;/p>
&lt;p>適当なコントローラーでExceptionをスローしたときのケースを追っていきます。&lt;/p>
&lt;p>Exceptionがスローされると &lt;code>Pipeline::prepareDestination()&lt;/code> 内のcatch句でハンドリングされます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">prepareDestination&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$destination&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$passable&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$destination&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$destination&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$passable&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Throwable&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$passable&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pipeline/Pipeline.php#L140-L149">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pipeline/Pipeline.php#L140-L149&lt;/a>&lt;/p>
&lt;p>&lt;code>handleException()&lt;/code> はExceptionHandlerに紐づくクラスをインスタンス化し、&lt;code>report()&lt;/code> を呼び出しつつ &lt;code>render()&lt;/code> でレスポンスを返します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handleException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$passable&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Throwable&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">container&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">bound&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ExceptionHandler&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">||&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$passable&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$handler&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">container&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">make&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ExceptionHandler&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$handler&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">report&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$handler&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$passable&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">is_object&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#1f2328">method_exists&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;withException&amp;#39;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleCarry&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Pipeline.php#L40-L58">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Pipeline.php#L40-L58&lt;/a>&lt;/p>
&lt;h2 id="report">report&lt;/h2>
&lt;p>&lt;code>report()&lt;/code> は &lt;code>shouldntReport()&lt;/code> でレポートするかの判定を行い、レポート対象であれば &lt;code>reportThrowable()&lt;/code> でレポートします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">report&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Throwable&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$e&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">mapException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">shouldntReport&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">reportThrowable&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L328-L337">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L328-L337&lt;/a>&lt;/p>
&lt;p>&lt;code>shouldntReport()&lt;/code> ではスローされたExceptionが &lt;code>$dontReport&lt;/code> &lt;code>$internalDontReport&lt;/code> のインスタンスであればレポートしない処理が入っています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">shouldntReport&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Throwable&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withoutDuplicates&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">reportedExceptionMap&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">??&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$dontReport&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">array_merge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">dontReport&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">internalDontReport&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#1f2328">is_null&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Arr&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">first&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$dontReport&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">fn&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$type&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$e&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#953800">$type&lt;/span>&lt;span style="color:#1f2328">)))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">rescue&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">fn&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">with&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">throttle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">),&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$throttle&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$throttle&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Unlimited&lt;/span> &lt;span style="color:#0550ae">||&lt;/span> &lt;span style="color:#953800">$throttle&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$throttle&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Lottery&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$throttle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">container&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">make&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">RateLimiter&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">attempt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">with&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$throttle&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;illuminate:foundation:exceptions:&amp;#39;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">fn&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">hashThrottleKeys&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#1f2328">md5&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$throttle&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">maxAttempts&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fn&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$throttle&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">decaySeconds&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}),&lt;/span> &lt;span style="color:#1f2328">rescue&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">report&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L396-L424">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L396-L424&lt;/a>&lt;/p></description></item><item><title>Laravelのページネーションの仕組み</title><link>https://blog.freedom-man.com/laravel_pagination.html</link><pubDate>Thu, 04 Jul 2024 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_pagination.html</guid><description>&lt;p>Laravelのページネーションのコードリーディングメモ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$users&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">User&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">paginate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">15&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;&lt;/span>&lt;span style="color:#1f2328">div&lt;/span> &lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;container&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">@&lt;/span>&lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$users&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{{&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">name&lt;/span> &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">@&lt;/span>&lt;span style="color:#cf222e">endforeach&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>&lt;span style="color:#1f2328">div&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{{&lt;/span> &lt;span style="color:#953800">$users&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">links&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="ページネーションデータの準備">ページネーションデータの準備&lt;/h2>
&lt;p>&lt;code>Builder::paginate()&lt;/code> で処理されます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">paginate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$perPage&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$columns&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;*&amp;#39;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span> &lt;span style="color:#953800">$pageName&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;page&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$page&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$total&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$page&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$page&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#1f2328">Paginator&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">resolveCurrentPage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$pageName&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$total&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$total&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">??&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">toBase&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getCountForPagination&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$perPage&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$perPage&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$total&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">model&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getPerPage&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$results&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$total&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">forPage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$page&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$columns&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">model&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">newCollection&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">paginator&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$results&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$total&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$page&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;path&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">Paginator&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">resolveCurrentPath&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;pageName&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$pageName&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Builder.php#L920-L939">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Eloquent/Builder.php#L920-L939&lt;/a>&lt;/p>
&lt;p>&lt;code>Paginator::resolveCurrentPage()&lt;/code> では&lt;code> Paginator::currentPageResolver()&lt;/code> で設定したClosureを使ってページ番号を取得します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Paginator&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">currentPageResolver&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$pageName&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;page&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$page&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;request&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$pageName&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">filter_var&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$page&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">FILTER_VALIDATE_INT&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">!==&lt;/span> &lt;span style="color:#cf222e">false&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">int&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#953800">$page&lt;/span> &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">int&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#953800">$page&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/PaginationState.php#L19-L27">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Pagination/PaginationState.php#L19-L27&lt;/a>&lt;/p>
&lt;p>&lt;code>page&lt;/code> のリクエストパラメータから番号を取得、バリデーションした上で値を返しています。&lt;/p>
&lt;p>&lt;code>Builder::getCountForPagination()&lt;/code> ではモデルのカウントを取っています。
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Query/Builder.php#L3034-L3078">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Query/Builder.php#L3034-L3078&lt;/a>&lt;/p>
&lt;p>&lt;code>Builder::forPage()&lt;/code> ではページ番号、1ページあたりのレコード数を使ってOFFSET/LIMITでレコードを取得します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">forPage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$page&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">15&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">offset&lt;/span>&lt;span style="color:#1f2328">((&lt;/span>&lt;span style="color:#953800">$page&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">limit&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$perPage&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Query/Builder.php#L2596-L2599">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Query/Builder.php#L2596-L2599&lt;/a>&lt;/p>
&lt;p>&lt;code>BuildsQueries::paginator()&lt;/code> ではLengthAwarePaginatorクラスのインスタンスを作成します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">paginator&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$items&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$total&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$perPage&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$currentPage&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$options&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">Container&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">getInstance&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">makeWith&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">LengthAwarePaginator&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">compact&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;items&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;total&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;perPage&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;currentPage&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;options&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Concerns/BuildsQueries.php#L492-L497">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Database/Concerns/BuildsQueries.php#L492-L497&lt;/a>&lt;/p>
&lt;h2 id="ページネーションの表示">ページネーションの表示&lt;/h2>
&lt;p>&lt;code>LengthAwarePaginator::links()&lt;/code> は &lt;code>LengthAwarePaginator::render()&lt;/code> を呼び出しています。&lt;/p></description></item><item><title>Laravelの認証の仕組み</title><link>https://blog.freedom-man.com/laravel_authenticate.html</link><pubDate>Wed, 26 Jun 2024 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_authenticate.html</guid><description>&lt;p>Laravelの認証周りのコードリーディングメモ。&lt;/p>
&lt;p>↓こんな感じなパターンを見ていく&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/resources&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$user&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">Auth&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">user&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">})&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">middleware&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;auth&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">post&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/login&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Auth&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">attempt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">all&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="認証チェック">認証チェック&lt;/h2>
&lt;p>&lt;code>Illuminate\Auth\Middleware\Authenticate&lt;/code> ミドルウェアでチェックしています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">...&lt;/span>&lt;span style="color:#953800">$guards&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">authenticate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$guards&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">authenticate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#953800">$guards&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">empty&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$guards&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$guards&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$guards&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$guard&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">auth&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">guard&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$guard&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">check&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">auth&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">shouldUse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$guard&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">unauthenticated&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$guards&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/Middleware/Authenticate.php#L60-L65">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/Middleware/Authenticate.php#L60-L65&lt;/a>
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/Middleware/Authenticate.php#L76-L89">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/Middleware/Authenticate.php#L76-L89&lt;/a>&lt;/p>
&lt;p>&lt;code>Illuminate\Auth\AuthManager::guard($guard)-&amp;gt;check()&lt;/code> でチェックして認証が通っていなければ &lt;code>unauthenticated()&lt;/code> メソッド経由で &lt;code>AuthenticationException&lt;/code> をスローします。&lt;/p>
&lt;p>&lt;code>guard()&lt;/code> は引数がnullの場合は &lt;code>getDefaultDriver()&lt;/code> でdriver名を取得して &lt;code>resolve()&lt;/code> した値を取得します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">guard&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$name&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$name&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$name&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getDefaultDriver&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">guards&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">??&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">guards&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">resolve&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/AuthManager.php#L66-L71">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/AuthManager.php#L66-L71&lt;/a>&lt;/p>
&lt;p>&lt;code>resolve()&lt;/code> はconfigから取得してdriverを取得して各driverメソッドを呼び出します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">resolve&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$config&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getConfig&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">is_null&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$config&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">InvalidArgumentException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Auth guard [&lt;/span>&lt;span style="color:#0a3069">{&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">] is not defined.&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">customCreators&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$config&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;driver&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]]))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">callCustomCreator&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$config&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$driverMethod&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;create&amp;#39;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#1f2328">ucfirst&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$config&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;driver&amp;#39;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#0a3069">&amp;#39;Driver&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">method_exists&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$driverMethod&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#953800">$driverMethod&lt;/span>&lt;span style="color:#1f2328">}(&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$config&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">InvalidArgumentException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;Auth driver [&lt;/span>&lt;span style="color:#0a3069">{&lt;/span>&lt;span style="color:#953800">$config&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;driver&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">] for guard [&lt;/span>&lt;span style="color:#0a3069">{&lt;/span>&lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">] is not defined.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/AuthManager.php#L81-L102">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Auth/AuthManager.php#L81-L102&lt;/a>&lt;/p></description></item><item><title>LaravelのRouteパラメータのバインディングの仕組み</title><link>https://blog.freedom-man.com/laravel_substitute_bindings.html</link><pubDate>Tue, 25 Jun 2024 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_substitute_bindings.html</guid><description>&lt;p>LaravelのSubstituteBindingsのコードリーディングメモ。&lt;/p>
&lt;p>まずは暗黙的なバインディング・明示的なバインディングの以下のようなシンプルなパターンで見ていきます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/hoges/{hoge}&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Request&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">view&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;welcome&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/foos/{foo}&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Request&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$foo&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">view&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;welcome&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">boot&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">void&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">bind&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;foo&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">tap&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">\stdClass&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$obj&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$obj&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">hello&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>Illuminate\Routing\Middleware\SubstituteBindings&lt;/code> でパラメータのバインドが行われます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">router&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">substituteBindings&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$route&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">router&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">substituteImplicitBindings&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ModelNotFoundException&lt;/span> &lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getMissing&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getMissing&lt;/span>&lt;span style="color:#1f2328">()(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Middleware/SubstituteBindings.php#L39">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Middleware/SubstituteBindings.php#L39&lt;/a>&lt;/p>
&lt;h2 id="明示的バインディング">明示的バインディング&lt;/h2>
&lt;p>まずは、明示的なバインディング（上記の &lt;code>foo&lt;/code> の方）を見ていきます。&lt;/p>
&lt;p>&lt;code>Illuminate\Routing\Router::substituteBindings()&lt;/code> で明示的なバインドが行われます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">substituteBindings&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">parameters&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">binders&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">]))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setParameter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">performBinding&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$route&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Router.php#L937-L946">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Router.php#L937-L946&lt;/a>&lt;/p>
&lt;p>&lt;code>\Illuminate\Routing\Route::parameters()&lt;/code> は &lt;code>{ 'hoge' =&amp;gt; 1 }&lt;/code> のようなarrayが入ります。&lt;/p>
&lt;p>&lt;code>boot()&lt;/code> 内で &lt;code>Illuminate\Routing\Router::bind()&lt;/code> を呼び出すと &lt;code>$binders&lt;/code> プロパティのキーに &lt;code>$binder&lt;/code> のClosureがセットされます。&lt;/p></description></item><item><title>Laravelのスロットリングの仕組み</title><link>https://blog.freedom-man.com/laravel_throttle_request.html</link><pubDate>Thu, 20 Jun 2024 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_throttle_request.html</guid><description>&lt;p>LaravelのThrottleRequestのコードリーディングメモ。&lt;/p>
&lt;p>今回はこんな感じなコードで何が起きているかを見ます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">Route&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">middleware&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>&lt;span style="color:#0a3069">&amp;#39;throttle:api&amp;#39;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">group&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * Bootstrap any application services.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">boot&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">void&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">RateLimiter&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">for&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;api&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Request&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">Limit&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">perMinute&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">60&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">by&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">user&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">?-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">id&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">ip&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;p>&lt;code>throttle&lt;/code> は &lt;code>\Illuminate\Routing\Middleware\ThrottleRequests&lt;/code> のエイリアスなのでそこから見ていきます。&lt;/p>
&lt;p>&lt;code>throttle:api&lt;/code> のコロンのあとは引数になるので、以下の &lt;code>$maxAttempts&lt;/code> は &lt;code>api&lt;/code> が入ります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$maxAttempts&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">60&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$decayMinutes&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$prefix&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">is_string&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$maxAttempts&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#1f2328">func_num_args&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#1f2328">is_null&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limiter&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">limiter&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">limiter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$maxAttempts&lt;/span>&lt;span style="color:#1f2328">)))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleRequestUsingNamedLimiter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$maxAttempts&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$limiter&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">object&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;key&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$prefix&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">resolveRequestSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;maxAttempts&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">resolveMaxAttempts&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$maxAttempts&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;decaySeconds&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0550ae">60&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#953800">$decayMinutes&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;responseCallback&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Middleware/ThrottleRequests.php#L82-L102">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Middleware/ThrottleRequests.php#L82-L102&lt;/a>&lt;/p>
&lt;p>&lt;code>throttle:api&lt;/code> の場合は最初のif分岐に入ります。&lt;/p>
&lt;p>&lt;code>handleRequestUsingNamedLimiter()&lt;/code> は &lt;code>$limiter()&lt;/code> を呼び出し &lt;code>RateLimiter::for()&lt;/code> で定義したClosureの戻り値を取得し、その設定を使ってリクエストの閾値チェックを行っています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handleRequestUsingNamedLimiter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$limiterName&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$limiter&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$limiterResponse&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$limiter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limiterResponse&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Response&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$limiterResponse&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">elseif&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limiterResponse&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Unlimited&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">collect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Arr&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">wrap&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limiterResponse&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">map&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limit&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limiterName&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">object&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;key&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#953800">$shouldHashKeys&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#1f2328">md5&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$limiterName&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#953800">$limit&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$limiterName&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#0a3069">&amp;#39;:&amp;#39;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#953800">$limit&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;maxAttempts&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$limit&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">maxAttempts&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;decaySeconds&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$limit&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">decaySeconds&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;responseCallback&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$limit&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">responseCallback&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">})&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">all&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Middleware/ThrottleRequests.php#L115-L137">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Routing/Middleware/ThrottleRequests.php#L115-L137&lt;/a>&lt;/p></description></item><item><title>LaravelのSession/CSRFの仕組み</title><link>https://blog.freedom-man.com/laravel_session.html</link><pubDate>Wed, 19 Jun 2024 21:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_session.html</guid><description>&lt;p>Laravelのsession/csrfまわりのハンドリング何しているかのコードリーディングメモ。&lt;/p>
&lt;h2 id="session">Session&lt;/h2>
&lt;p>&lt;code>Illuminate\Session\Middleware\StartSession&lt;/code> ミドルウェアでセッションのハンドリングをしています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">sessionConfigured&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$session&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getSession&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">manager&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">shouldBlock&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">||&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Route&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">route&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">locksFor&lt;/span>&lt;span style="color:#1f2328">()))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleRequestWhileBlocking&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handleStatefulRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L51-L65">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L51-L65&lt;/a>&lt;/p>
&lt;p>&lt;code>getSession()&lt;/code> ではクッキーからセッションIDを取得し、 &lt;code>Illuminate\Session\Store::setId()&lt;/code> で取得したセッションIDをセットします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">getSession&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Request&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">tap&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">manager&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">driver&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setId&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">cookies&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getName&lt;/span>&lt;span style="color:#1f2328">()));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L157-L162">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L157-L162&lt;/a>&lt;/p>
&lt;p>&lt;code>setId()&lt;/code> は指定したIDを設定するか、新しくセッションIDを発行します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">setId&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">id&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">isValidId&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$id&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">generateSessionId&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Store.php#L649-L652">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Store.php#L649-L652&lt;/a>&lt;/p>
&lt;p>セッションIDを設定したあとは、 &lt;code>handleStatefulRequest()&lt;/code> を呼び出します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handleStatefulRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Request&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setLaravelSession&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">startSession&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...(省略)...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$next&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">storeCurrentUrl&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">addCookieToResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$session&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">saveSession&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L110-L133">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L110-L133&lt;/a>&lt;/p>
&lt;p>&lt;code>setLaravelSession()&lt;/code> では &lt;code>$request-&amp;gt;session()&lt;/code> などのリクエストクラスからのsession呼び出しができるようにしています。&lt;/p>
&lt;p>&lt;code>startSession()&lt;/code> では &lt;code>Store::start()&lt;/code> =&amp;gt; &lt;code>Store::loadSession()&lt;/code> という感じで呼び出していて、セッションIDを使ってセッションストレージからセッションを取り出して &lt;code>$attributes&lt;/code> プロパティにセットしています。&lt;/p></description></item><item><title>LaravelのValidationExceptionのハンドリングの仕組み</title><link>https://blog.freedom-man.com/laravel_validation_exception.html</link><pubDate>Tue, 18 Jun 2024 22:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_validation_exception.html</guid><description>&lt;p>Laravelの &lt;code>ValidationException&lt;/code> のハンドリングが何をやっているのかコードリーディングメモ。&lt;/p>
&lt;hr>
&lt;p>&lt;code>Illuminate\Foundation\Exceptions\Handler&lt;/code> のこの部分。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Throwable&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...(省略)...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">finalizeRenderedResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">match&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$e&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">HttpResponseException&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getResponse&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$e&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">AuthenticationException&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">unauthenticated&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$e&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">ValidationException&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">convertValidationExceptionToResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">default&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">renderExceptionResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L584">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L584&lt;/a>&lt;/p>
&lt;p>&lt;code>convertValidationExceptionToResponse()&lt;/code> ではJSONを返さない場合は &lt;code>invalid()&lt;/code> が呼ばれます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">convertValidationExceptionToResponse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ValidationException&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">response&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">shouldReturnJson&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">invalidJson&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">invalid&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L720-L729">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L720-L729&lt;/a>&lt;/p>
&lt;p>&lt;code>invalid()&lt;/code> はRedirectResponseを作成しています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">invalid&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">ValidationException&lt;/span> &lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">redirect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">redirectTo&lt;/span> &lt;span style="color:#0550ae">??&lt;/span> &lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">previous&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withInput&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Arr&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">except&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">dontFlash&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">withErrors&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">errors&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;_error_bag&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$exception&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">errorBag&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L738-L743">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Exceptions/Handler.php#L738-L743&lt;/a>&lt;/p>
&lt;p>&lt;code>withInput()&lt;/code> は &lt;code>Illuminate\Session\Store::flashInput()&lt;/code> を呼び出し、 &lt;code>_old_input&lt;/code> にflashデータとして入力値をセットします。これによって入力値がリダイレクトGET後の一回限りのセッションデータとして利用できるようになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">withInput&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#953800">$input&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">session&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">flashInput&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">removeFilesFromInput&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#1f2328">is_null&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$input&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$input&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Http/RedirectResponse.php#L74-L81">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Http/RedirectResponse.php#L74-L81&lt;/a>
&lt;a href="https://github.com/laravel/framework/blob/11.x/src/Illuminate/Session/Store.php#L534-L537">https://github.com/laravel/framework/blob/11.x/src/Illuminate/Session/Store.php#L534-L537&lt;/a>&lt;/p>
&lt;p>&lt;code>withErrors()&lt;/code> も &lt;code>Illuminate\Session\Store::flash()&lt;/code> を叩いて &lt;code>ValidationException::errors()&lt;/code> の内容をゴニョゴニョしてセットしてます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">withErrors&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$provider&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;default&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">parseErrors&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$provider&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$errors&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">session&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;errors&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">ViewErrorBag&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$errors&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">ViewErrorBag&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$errors&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">ViewErrorBag&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">session&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">flash&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;errors&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$errors&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Http/RedirectResponse.php#L131-L146">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Http/RedirectResponse.php#L131-L146&lt;/a>&lt;/p></description></item><item><title>Laravelのflashの仕組み</title><link>https://blog.freedom-man.com/laravel_flash.html</link><pubDate>Tue, 18 Jun 2024 21:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_flash.html</guid><description>&lt;p>Laravelの &lt;code>RedirectResponse::with()&lt;/code> のflashが何をやっているのかコードリーディングメモ。&lt;/p>
&lt;hr>
&lt;p>&lt;code>RedirectResponse::with()&lt;/code> は &lt;code>Illuminate\Session\Store::flash()&lt;/code> を呼び出します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">with&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">is_array&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$k&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$v&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">session&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">flash&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$k&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$v&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Http/RedirectResponse.php#L35-L51">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Http/RedirectResponse.php#L35-L51&lt;/a>&lt;/p>
&lt;p>&lt;code>flash()&lt;/code> では以下のようなことをやっています。&lt;/p>
&lt;ul>
&lt;li>&lt;code>$attributes&lt;/code> プロパティに属性をセット&lt;/li>
&lt;li>&lt;code>_flash.new&lt;/code> に &lt;code>$key&lt;/code> を追加&lt;/li>
&lt;li>&lt;code>_flash.old&lt;/code> から &lt;code>$key&lt;/code> を削除&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">flash&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;_flash.new&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">removeFromOldFlashData&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Store.php#L443-L450">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Store.php#L443-L450&lt;/a>&lt;/p>
&lt;p>例えば &lt;code>with(['message' =&amp;gt; 'OK'])&lt;/code> という呼び出しをした場合、&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>key&lt;/th>
 &lt;th>value&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>message&lt;/td>
 &lt;td>OK&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>_flash.new&lt;/td>
 &lt;td>[message]&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>_flash.old&lt;/td>
 &lt;td>[]&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>という状態になります。&lt;/p>
&lt;p>この &lt;code>Illuminate\Session\Store&lt;/code> は &lt;code>Illuminate\Session\Middleware\StartSession::saveSession()&lt;/code> で &lt;code>save()&lt;/code> メソッドが呼ばれます。
&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L245">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Middleware/StartSession.php#L245&lt;/a>&lt;/p>
&lt;p>&lt;code>save()&lt;/code> では以下の処理を行ってます。&lt;/p>
&lt;ul>
&lt;li>&lt;code>_flash.old&lt;/code> に入っているキーの値をセッションストレージから削除&lt;/li>
&lt;li>&lt;code>_flash.old&lt;/code> に &lt;code>_flash.new&lt;/code> の値（flashのキー配列）をセット&lt;/li>
&lt;li>&lt;code>_flash.new&lt;/code> の値をクリア&lt;/li>
&lt;li>&lt;code>$attributes&lt;/code> の値をセッションストレージに格納&lt;/li>
&lt;/ul>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">save&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">ageFlashData&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">prepareErrorBagForSerialization&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">handler&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">write&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getId&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">prepareForStorage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">serialization&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0a3069">&amp;#39;json&amp;#39;&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#1f2328">json_encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">attributes&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">serialize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">attributes&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">started&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Store.php#L166-L177">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Session/Store.php#L166-L177&lt;/a>&lt;/p></description></item><item><title>LaravelのFormRequestの仕組み</title><link>https://blog.freedom-man.com/laravel_request_validation.html</link><pubDate>Mon, 17 Jun 2024 23:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/laravel_request_validation.html</guid><description>&lt;p>LaravelのFormRequestの仕組みを調べてみたので備忘録。
Laravelのバージョンは11.0.7です。&lt;/p>
&lt;h2 id="serviceproviderでのコールバック関数の設定">ServiceProviderでのコールバック関数の設定&lt;/h2>
&lt;p>ServiceProviderでFormRequestのインスタンス化とバリデーションする処理の追加をしています。&lt;/p>
&lt;p>Illuminate\Foundation\Providers\FoundationServiceProvider経由でIlluminate\Foundation\Providers\FormRequestServiceProviderが呼ばれます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * Bootstrap the application services.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @return void
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">boot&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">afterResolving&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ValidatesWhenResolved&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$resolved&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$resolved&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">validateResolved&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">resolving&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">FormRequest&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$request&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">FormRequest&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">createFrom&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;request&amp;#39;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setContainer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setRedirector&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">make&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Redirector&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Providers/FormRequestServiceProvider.php#L27-L38">https://github.com/laravel/framework/blob/v11.0.7/src/Illuminate/Foundation/Providers/FormRequestServiceProvider.php#L27-L38&lt;/a>&lt;/p>
&lt;p>&lt;code>Container::resolving()&lt;/code> では &lt;code>$resolvingCallbacks&lt;/code> プロパティにコールバック関数がセットされます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * Register a new resolving callback.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param \Closure|string $abstract
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param \Closure|null $callback
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @return void
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">resolving&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">?&lt;/span>&lt;span style="color:#1f2328">Closure&lt;/span> &lt;span style="color:#953800">$callback&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">is_string&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$abstract&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getAlias&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">is_null&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$callback&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#953800">$abstract&lt;/span> &lt;span style="color:#1f2328">instanceof&lt;/span> &lt;span style="color:#1f2328">Closure&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">globalResolvingCallbacks&lt;/span>&lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">resolvingCallbacks&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">][]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$callback&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/11.x/src/Illuminate/Container/Container.php#L1163-L1174">https://github.com/laravel/framework/blob/11.x/src/Illuminate/Container/Container.php#L1163-L1174&lt;/a>&lt;/p></description></item><item><title>PHPStanの拡張機能の作り方</title><link>https://blog.freedom-man.com/phpstan_extensions.html</link><pubDate>Thu, 11 Apr 2024 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/phpstan_extensions.html</guid><description>&lt;p>PHPStanの拡張機能の作り方をざっと調べてみたので備忘録。
拡張機能といっても色々あるが、ライブラリ以外のプロダクションコードでよく使いそうな &lt;code>Custom Rules&lt;/code> &lt;code>Class Reflection Extensions&lt;/code> &lt;code>Dynamic Return Type Extensions&lt;/code> の３つについて書いていく。&lt;/p>
&lt;p>詳細は&lt;a href="https://phpstan.org/developing-extensions/extension-types">公式ドキュメント&lt;/a>を参照。&lt;/p>
&lt;h2 id="custom-rules">&lt;a href="https://phpstan.org/developing-extensions/rules">Custom Rules&lt;/a>&lt;/h2>
&lt;p>検証ルールを独自に作成できる拡張機能。&lt;code>PHPStan\Rules\Rule&lt;/code> インターフェースをimplementしたクラスを実装すればOKで、どのNodeに対して（&lt;code>getNodeType()&lt;/code>）、どういう検査を行うのか（&lt;code>processNode&lt;/code>）を記述していく。検査時にエラーがあれば &lt;code>processNode()&lt;/code> でエラー文字列の配列を返せば良い。&lt;/p>
&lt;p>例えばメソッド呼び出しに対して検査したい場合は以下のような感じで実装する。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span> &lt;span style="color:#cf222e">declare&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">strict_types&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">namespace&lt;/span> &lt;span style="color:#1f2328">App&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PhpParser\Node&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PhpParser\Node\Expr\MethodCall&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PHPStan\Analyser\Scope&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PHPStan\Rules\Rule&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">XXXRule&lt;/span> &lt;span style="color:#cf222e">implements&lt;/span> &lt;span style="color:#1f2328">Rule&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">getNodeType&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ここに検査対象のノードのクラス名を記述する
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">MethodCall&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">processNode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Node&lt;/span> &lt;span style="color:#953800">$node&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">Scope&lt;/span> &lt;span style="color:#953800">$scope&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// エラーがあれば return [&amp;#39;エラーメッセージ&amp;#39;]; という感じで文字列配列を返す。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// エラーがなければ return []; を返す。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://phpstan.org/developing-extensions/abstract-syntax-tree">$node&lt;/a> は対象のASTノードで &lt;code>getNodeType()&lt;/code> で返したクラスのオブジェクトが入る。上記例だと$nodeに入る &lt;a href="https://github.com/nikic/PHP-Parser/blob/v5.0.2/lib/PhpParser/Node/Expr/MethodCall.php">MethodCall&lt;/a> クラスはメソッド名を表す &lt;code>$name&lt;/code>、レシーバーを表す &lt;code>$var&lt;/code>、引数を表す &lt;code>$args&lt;/code> の3つのノードを持っているので、これらのプロパティを使って検査をしていくことになる。&lt;/p>
&lt;p>&lt;a href="https://phpstan.org/developing-extensions/scope">$scope&lt;/a> はそのノードに対するスコープ／状態を表している。例えばメソッドAで &lt;code>$var = 'hoge';&lt;/code> メソッドBで &lt;code>$var = 1;&lt;/code> といった形で同名の変数が異なる型、コンテキストで利用されている場合、メソッドA内では文字列型、メソッドB内では数値型として扱われるべきだが、これは変数名だけでは確定できない。そのため、そのスコープ／状態に応じて型を検査する必要があるが、それを表すオブジェクトが &lt;a href="https://github.com/phpstan/phpstan-src/blob/1.11.x/src/Analyser/Scope.php">Scope&lt;/a> インターフェースの$scope変数である。例えば &lt;code>$scope-&amp;gt;getVariableType('変数名')&lt;/code> という形で呼び出すと、そのスコープに応じた変数名の型を抽出できる。他にも &lt;code>$scope-&amp;gt;getFile()&lt;/code> でそのノードの元ファイル名、 &lt;code>$scope-&amp;gt;getNamespace()&lt;/code> で名前空間を取得できる。&lt;/p></description></item><item><title>3回目の転職の備忘録</title><link>https://blog.freedom-man.com/job_change_to_4th.html</link><pubDate>Wed, 13 Mar 2024 07:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/job_change_to_4th.html</guid><description>&lt;p>5ヶ月間ほど3回目の転職活動していたので備忘として雑に残しておく。&lt;/p>
&lt;p>関連する退職エントリは&lt;a href="https://blog.freedom-man.com/leaving_3rd_company">こちら&lt;/a>。&lt;/p>
&lt;h2 id="利用した転職媒体など">利用した転職媒体など&lt;/h2>
&lt;p>Forkwell, Findy, LAPRAS, 転職ドラフトなどの転職媒体や知人からのリファラルで転職活動をした。媒体内での企業検索は行わずスカウトを主に利用したが、スカウト起点だと最低限のフィルタリングは通っている（と思いたい）のでミスマッチが多少防げるかなと思っている。スカウトが少なければ検索も利用しようと思ったが、これらの媒体で220社以上からスカウトが来ており、検討する会社としては十分だったためスカウトのみの利用となった。&lt;/p>
&lt;p>ちなみに、会社や事業の面白さ・ワクワク感を大事にしていたので、スカウトの文面に関してはパーソナライズされているかどうかはそこまで気にならなかった。もちろんパーソナライズしないと見てくれない層もいると思うしパーソナライズされたスカウトは第一印象が良いのでやった方が良いとは思う。&lt;/p>
&lt;h3 id="forkwellの上級エンジニア特化のエージェントサービス">Forkwellの上級エンジニア特化のエージェントサービス&lt;/h3>
&lt;p>Forkwellに関しては &lt;a href="https://jobs.forkwell.com/forkwell_careersuccess/jobs/23270">上級エンジニア特化のエージェントサービス&lt;/a> があったためそちらも活用させていただいた。エージェントと書いてあるが、基本的には自分が応募先などのコントロールを行い、アドバイザーとして入ってもらうような形で利用している。転職のサポート（企業情報・ノウハウ共有）以外だとキャリアの壁打ちもやってもらい「キャリアの川下り型・山登り型」「入社後の適応グラフ（ハネムーン期など）」「&lt;a href="https://pr.forkwell.com/career_navi/six_patterns_of_tech_leads/">テックリードの6系統&lt;/a>」「&lt;a href="https://pr.forkwell.com/data_insights/annual-income-distribution-of-it-developers/">年収分布の話&lt;/a>」など自分を客観的に分析するきっかけになったし、利害関係が無くITエンジニアのキャリアの専門家に相談できるのはとても有意義な時間だった。対応いただいた &lt;a href="https://twitter.com/Akira_Akagawa">赤川さん&lt;/a> は以前から一方的に存じあげていて、実際面談してみるとキャリアや転職事情に関して詳しいだけではなくエンジニアリングマネジメントや事業責任者の経験もお持ちなのでそれらの視点も踏まえたアドバイスもいただけたのはとても良かった。&lt;/p>
&lt;h3 id="転職ドラフトと想定年収">転職ドラフトと想定年収&lt;/h3>
&lt;p>他の転職媒体と違って、転職ドラフトは各指名に想定年収が提示される（そのまま採用に至った場合は9割保証される）ため、市場価値・条件面での目安になるのが良かった。というのも、3社目の待遇が高かったので、市場価値的に同額貰えることにイマイチ確信が持てず、転職により年収が下がることを懸念していたからである。&lt;/p>
&lt;p>参加してみた結果、ある回で指名数トップ（〜60社）で1位指名が〜20社、最高提示年収も5位以内と非常に良い結果になり、現年収とそこまで乖離がないことが確認できた。ちなみに4年前も転職ドラフトに参加していて、その時も指名数トップだったが最高提示年収は〜25位程度で、想定年収の中央値も今回の方が300万ほど高い。4年前は提示年収をもっと上げていかないとなぁとぼんやり思っていたので、この結果には大変満足しているし、転職を決意する１要素となった。&lt;/p>
&lt;h3 id="余談-過去の転職活動について">余談: 過去の転職活動について&lt;/h3>
&lt;p>1社目 =&amp;gt; 2社目の転職は受託開発会社から事業会社への転職だった。最初の転職だったのもあり、ビジネスドメイン問わず事業会社を幅広く受けていて、Green、Wantedlyなどの転職媒体やエージェントを使って転職活動をしていた。エージェントは会社を幅広く紹介してくれたり転職のノウハウを教えてくれるため、最初の転職としては良い選択だったと思う。ただ、良くも悪くもエージェントのペースになることもあるのでそこのハンドリングは必要とも思った。そのため今回は、前述のForkwellのエージェントサービスでは転職サポートという立ち位置で入っていただき、案件紹介や転職活動の壁打ちなどをメインに活用させていただいた形となる。&lt;/p>
&lt;p>2社目 =&amp;gt; 3社目の転職はエージェントは特に利用せずスカウト起点でカジュアル面談・面接を経て採用に至った。結局1社しか選考に進まなかったので面接の場数を踏んで練習することができなかった。また、1社だけだと給与交渉がしづらく、入社時の待遇は2社目より下がってしまった。そのため後述の通り、今回は複数の会社の選考を受けることを意識していた。&lt;/p>
&lt;h2 id="カジュアル面談">カジュアル面談&lt;/h2>
&lt;p>Forkwell の赤川さんからは、カジュアル面談を20社ほど受けてみてはと言われていたが（この数は相手の状況や考え方によるそう）、結果として2ヶ月で40社ほど受けた（平日1日1社ペース）。これは、それぐらいの数の会社の話を聞いておけば納得感ある転職活動になるかと思ったのと、面談の場数を踏むことで自身の気持ちの整理やべシャリの練習になると思ったためである。特にドメインを絞ることなく幅広く聞いていて、面白そうな会社が多かったので結果的にそうなったとも言える。ちなみにこんなにカジュアル面談を受ける人はいないらしい。&lt;/p>
&lt;p>カジュアル面談では現場エンジニア、マネージャー、人事、VPoE、CTOが対応するパターンなど色々と経験できた。会社や事業の内容など簡単に説明いただき、「組織的課題」「ビジネス的課題」「技術的課題」についてヒアリングしていた。会社の課題感などがわかると、「課題を解決するスキルセット的にマッチしているか」「課題を解決することでスキルを上げていけそうか」などよりキャリア的なイメージも湧きやすいためである。個人的にはVPoE、CTOレベルの方にご対応いただけると、よりリアルな組織的課題・技術的課題をヒアリングできたので良かった。逆に人事レベルだとこのあたりが全然聞けず、会社や事業を説明いただくだけで終わるのでやや厳しいイメージ。採用サイトや会社のテックブログがあると事前にインプットできる情報量が増えてカジュアル面談が充実するのでとても良かった。&lt;/p>
&lt;p>ちなみに、技術スタックに依らず色々と会社を見てきたが、サーバーサイドの技術スタック的にはRubyを使っている会社が多く、次点でGo、その次がPHPという感じだった。PHPは比較的歴史が長いプロダクト、Rubyは直近5〜10年でリリースされたプロダクトやもともとRubyでの知見がある会社で採用されているイメージ。&lt;/p>
&lt;p>面談候補日程に関しては手動（メッセージでのやりとり）やSpirなどのwebスケジューリングツールを使った方式の2パターンあるが、40社も受けるとスケジュール管理がめっちゃ大変なので後者のようなツールを使うパターンの方が圧倒的に楽だった。すべてリモートでのカジュアル面談だったが、ツールとしてはGoogle Meetが多く、次点でZoomという感じ。&lt;/p>
&lt;h2 id="面接">面接&lt;/h2>
&lt;p>カジュアル面談を受けた中から絞り込んで最終的に4社の選考に進んだ。対面の面接だけではなく、アプリケーションを事前に構築するような技術課題やリファレンスチェック（&lt;a href="https://site.backcheck.jp/">back check&lt;/a>）もあった。通常の面接よりも技術課題やリファレンスチェックの方が時間や調整面など精神的に大変だったかもしれない。一方でこれらの効果や意図も理解できるので、採用する側の視点で採用面接ムズいなぁと思った。&lt;/p>
&lt;p>また、転職というのは会社とのマッチングなのだなぁというのは改めて思った。ソフトスキル・ハードスキルだけではなく会社のカルチャーや事業フェーズ、キャリア・条件面のすり合わせがあり、スキルの高いエンジニアであれば入れる会社も増えるということは無く、歳を重ねるにつれて本当に入りたい入れる会社というのは狭まっていくようにも思う。とはいえ、スキルを磨けば見えなかったものが見えるようになり、エンジニアリングをもっと楽しめるようになるし人生の幅も広がるような気もしているので、もっとスキルを磨いていきたい。&lt;/p>
&lt;h2 id="その他">その他&lt;/h2>
&lt;p>このブログや会社のテックブログの記事のウケが良かった。特に会社のテックブログの方はドメインなど泥臭いところも色々書いていたので事前にどういうことをどういう考えでやってきたかを明確に伝えることができたのが良かった。プライベートのブログはかなりニッチな記事が多いんだけど反応してもらえるとめっちゃ嬉しいし、それをベースに面談・面接で雑談が弾んだりした。&lt;/p>
&lt;p>また、Job Descriptionなどを見てて、ICやスタッフエンジニアなどプレイヤーとしてのロールが話題になりつつも、現状の日本においてはマネジメント層がモテる＝ニーズがあり給与が高い感じなんだなぁと思ったりした。EMも専門職だし向き不向きがあると思うのでEMになった方が良いとは思わず、社会的にはそんな感じだよなぁという単なる感想なのだが、そういったソフトスキルもちゃんとICとして磨いていかないとなぁと考えさせられた。&lt;/p>
&lt;h2 id="まとめ">まとめ&lt;/h2>
&lt;p>今回の転職活動についてざっくばらんに書いてみた。エンジニア向けの転職媒体やサービスが増えて転職活動がしやすくなった気がする。特に会社以外で利害関係無くキャリアの壁打ちが手軽にできるのはとても体験が良かった。今回の転職活動でお世話になった皆様、本当にありがとうございました！&lt;/p>
&lt;p>上述の通り、まだまだスキルも磨いていかないといけないなと思うことが多々あるのでこれからもやっていき！&lt;/p></description></item><item><title>3社目の退職と振り返り</title><link>https://blog.freedom-man.com/leaving_3rd_company.html</link><pubDate>Fri, 01 Mar 2024 07:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/leaving_3rd_company.html</guid><description>&lt;p>4月15日付けで3社目である現職を退職するので心境などいろいろ書いてみる。
（対面・口頭だとなかなか説明しきれないので…ｗ&lt;/p>
&lt;h2 id="現職に転職した理由">現職に転職した理由&lt;/h2>
&lt;p>自分が魅力に感じるプロダクト、伸ばしていきたいプロダクトの開発をやってみたいというのが主なモチベーションで4年前に転職した。やりたいプロダクトに携わることで技術力も非技術力ももっと伸ばしていけるのではないか、日々の仕事の充実感も上がるのではないかと思ったからであり、そう思わせてくれるくらい魅力を感じたのが現職のプロダクトだった。&lt;/p>
&lt;p>現職にジョインするにあたり、成果を早く出すことを強く意識した。というのも、前職（2社目）は技術力・仕事力は身についたものの、成果を出し切ることができなかったところがあり、不完全燃焼に終わってしまっていた。とにかく変に達観せずに手を動かして早く結果を出して信頼貯金を貯め、サービスをエンジニアリングでどんどんグロースさせていく、ということができれば最高だと思っていた。後述の通り、これは圧倒的に達成できた。&lt;/p>
&lt;h2 id="現職でなにをしていたか">現職でなにをしていたか&lt;/h2>
&lt;p>一言でいうと、ICとしてプロダクトを進化させビジネスを加速させる仕事をやっていた。&lt;/p>
&lt;ul>
&lt;li>新機能開発、機能改善、リファクタリング、CI/CD、開発環境整備など開発全般&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/yappli_block_ui">新基盤のプロジェクトリード&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/crm_dx_improvement">プロダクト開発内製化のプロジェクトリード&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/archive/author/tzmfreedom">テックブログ執筆&lt;/a>、&lt;a href="https://tech.yappli.io/entry/phpcon2021">カンファレンス登壇&lt;/a>、&lt;a href="https://tech.yappli.io/entry/talk_tech_news">社内技術共有&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/server_recruiting_2021">採用&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>スタッフエンジニアでいうところのソルバー強め、テックリード・アーキテクト少々、という感じだろうか。現職ではテックリードというロールはないのだが、実質テックリードと言っても良いくらいの動きはしていたと思う。リポジトリに依っては創業CTOの次くらいコードを書いていた。仕事がとにかく楽しくて休日も仕事のことを考えていたし、週末は月曜日が待ち遠しかった。仕事に熱中した結果、市場価値は上がり、お金が転職のモチベーションにならない程度の待遇になり、職務経歴書に自信を持って書けるような仕事も数多くできた。&lt;/p>
&lt;p>また、入社当時のエンジニアのキャリアラダー・評価は&lt;/p>
&lt;pre tabindex="0">&lt;code>エンジニア &amp;lt; マネージャー &amp;lt; 部長 &amp;lt; ...
&lt;/code>&lt;/pre>&lt;p>といった評価・給与レンジになっていて、ICもマネージャーと同列の専門職として評価される土台を作れれば良いなと思って仕事をしていた。最終的に上記の評価レンジを大幅に崩すくらいの評価をいただき、社内の上級ICの職位（例えばシニア、スタッフ、プリンシパル）を作ることはできなかったものの、手を動かす上級ICの１例になれたのは良かった。&lt;/p>
&lt;h2 id="なぜ転職するのか">なぜ転職するのか&lt;/h2>
&lt;p>昨年育児休暇を取得したのだが、育休復帰後なぜかモチベーションが上がらない時期が続いていた。カジュアル面談してみたり整理した結果、仕事へのワクワク感がなくなってしまっていることがわかった。技術者であるがゆえ、Horizontal SaaSとして解消できる課題の幅や深さ、スケーラビリティがビジネス的にも技術的にも理解できてしまった結果、今やっている仕事がもたらす社会的な成果に対してワクワク感が減ってしまっていた。また、キャリア面においても、普段の仕事において持っている技術や経験の切り崩しが多くなっていたことや、手を動かす以外のエンジニアリングをもっとやっていきたいという意向もあった。これ自体は現職にいても実現できそうではあったものの、やはり上記のビジネスに対するワクワク感というところがネックになった。&lt;/p>
&lt;p>ライフステージが変わったことにより興味領域の変化も感じている。育児をしていると様々な社会保障を受けることになり、国や自治体の施策などには今まで以上に目がいくようになった。また、親が後期高齢者であるため介護も自分事になってきている。&lt;/p>
&lt;p>そういったわけでビジネスドメインとしてもっとワクワクできる仕事をやってみたいと思ったのがきっかけでカジュアル面談を受け始め、実際にワクワクできるビジネスドメイン、会社に出会って転職を決意した。&lt;/p>
&lt;p>現職の環境はとても良く、トライできる仕事もまだまだありそうだったし、やり残したことはそれなりにある。信頼貯金の積み直し、環境の変化など、転職することによるリスクもあった。とはいえ、ビジネスへのモチベーションとそれによるキャリアなどのリターンを考え、今このタイミングで転職するのがベストだと判断した。&lt;/p>
&lt;h2 id="今後何をしたいのか">今後何をしたいのか&lt;/h2>
&lt;p>カジュアル面談をする中で社会課題を解決するようなビジネスにとてもワクワクした。社会課題は国や自治体の施策だけでは解決できず、民間企業だからこそ継続的に熱意を持って取り組むことができ、社会をよりよくできるのではないかと思っている。自分が直面する環境を自分で良くできることも魅力に感じている。&lt;/p>
&lt;p>また、キャリアとしては個人として成果を出す、ではなく組織としてのパフォーマンスを最大化するため成果を出して行きたいと思っている。正直個人の成果としては今まで十二分にパフォーマンスを発揮できたのではないかと思っている。それ自体はとても良いのだがもっと組織に目を向けて中長期的に組織のパフォーマンスを最大化するようなことをやっていくことが上級ICとしても必要なんじゃないかと思っている。もちろん個人としてのパフォーマンスを期待されることもあるし、発揮する場面、発揮したほうが良い場面もたくさんがあると思うが、「組織として」「中長期的に」成長していくという軸を念頭に置いて、よりレバレッジの高い仕事をやっていきたいと思っている。&lt;/p>
&lt;p>次の会社は社会的なインパクトの大きさを考えてもワクワクするし、組織視点での行動がより求められる事業環境なのでとてもワクワクしている。&lt;/p>
&lt;h2 id="余談">余談&lt;/h2>
&lt;p>これまでの会社やモチベーションを振り返ってみると&lt;/p>
&lt;p>1社目はなんとなくITおもしろそう、凄そうくらいの感じで入社して&lt;br>
2社目は技術をもっとやっていきたいなと思って入社して&lt;br>
3社目はプロダクトが好きでもっとグロースさせていきたいなと思って入社して&lt;br>
4社目はビジネス・業界をもっと良くしていきたいなと思って入社する。&lt;/p>
&lt;p>どの会社に居たときも全力で仕事をしてきたからこそ、こういった感情やモチベーションの変化があり、結果として視座が高くなっているような気がしていて面白い。&lt;/p>
&lt;h2 id="最後に">最後に&lt;/h2>
&lt;p>現職はとても良い会社だったし、良い会社だったから４年も働けたし、成果を出して市場価値も上げれた。そしてこれからもっと良くなる会社であることは間違いない。それくらい良い人が集まり、居心地が良く、それでいて改善力が高い組織だった。&lt;/p>
&lt;p>このタイミングで転職したことが正解だったと言えるくらい次の会社でも成果を残し、成長できるよう頑張っていきたい。&lt;/p></description></item><item><title>2024</title><link>https://blog.freedom-man.com/2024.html</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2024.html</guid><description/></item><item><title>2023年の振り返り</title><link>https://blog.freedom-man.com/2023-summary.html</link><pubDate>Sat, 30 Dec 2023 23:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/2023-summary.html</guid><description>&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8">&lt;/script>
&lt;p>今年もええ感じに振り返っていくよ！&lt;/p>
&lt;h2 id="新規プロダクト-yappli-crm-の内製化とグロース">新規プロダクト Yappli CRM の内製化とグロース&lt;/h2>
&lt;p>今年はYappli CRMという顧客管理サービスにフルコミットした１年だった。
Yappli CRMは当初外注して作ってもらっていたサービスで、よりサービスを成長させていくべく内製化が今年始まり、その内製化及びサービスグロースのプロジェクトのリードエンジニアを私が担当した。&lt;/p>
&lt;p>やったことは↓このあたりに書いてある&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tech.yappli.io/entry/crm_dx_improvement">Yappli CRMの開発者体験を3ヶ月で爆上げした&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/kaizen_longrunning_batch">実行時間に１週間かかっていた日次バッチ処理を６分に短縮した話&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>大変だったが、それ以上にめちゃくちゃ楽しくて、ここ数年で一番楽しかったんじゃないかというくらい。
4月に子供が生まれて4〜7月は育休を取ったので、そこでリードエンジニアは別の人にスイッチした。
育休明けの8月からも同サービスを担当していて、メンバーとして新機能開発・不具合修正・改善など色々やった。10月からはCRMの運用保守チームに入って、問い合わせ、調査、小規模〜中規模の改善案件などやった。具体的には、不要なRedshiftクラスタを停止して１つのクラスタに集約したり、Redshiftで運用すべきではない機能をMySQLに移行したり、40〜50以上あるtroccoの転送設定を１つのバッチに共通化、運用効率化したり、各種データに対してCSVで一括入稿できるようにしたり、パフォーマンス最適化したり。調べてみたら、今年のPR数が合計300くらいだった。コード書く以外の仕事・改善もめっちゃやったことを考えると結構成果出せたんじゃないかと思う。&lt;/p>
&lt;p>7年前にSalesforceの導入・支援をやっていた自分が、CRMのSaaSを作ることになるのはとても感慨深かった。Salesforceはこういう機能があったな、こういう指向性のサービスだったな、Salesforceと違ってこうしたい、という感じで思いを馳せながら開発していたし、Salesforceの凄さみたいなものも改めて感じた。&lt;/p>
&lt;h2 id="子供爆誕">子供爆誕&lt;/h2>
&lt;p>4月中旬に子供が生まれた。とにかく無事生まれてくれてよかった。妻にも大感謝。子供が毎日毎秒めちゃくちゃ可愛くてどうしようもない。&lt;/p>
&lt;p>1ヶ月目の新生児期間は家事も含めて母乳以外のことはすべて自分がやる、という感じでやっていて、2ヶ月目以降は妻の体調も良くなってきたので料理は基本全部自分が作るがそれ以外の家事育児はちょくちょくやってもらう、という感じにシフトした。育休前は全然料理しなかったが、クラシルとクックドゥを駆使して1〜2週間ローテくらいの料理は作れる感じになった。&lt;/p>
&lt;p>子供は今のところあまり手がかからず、育児初心者の我々にとっては非常に助かった。夜なんか寝かしつけせずとも電気を消せば勝手に寝てくれる。正直このあたりは個人差がかなりあるんだろうなぁと思う。&lt;/p>
&lt;p>育休中は子が寝ている時間など細切れに暇な時間が発生したので合間に会社のSlackとかTwitter/Xとかはてぶを見ていた。途中からそれにも飽きて会社ブログとかも書いていた。&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">はてぶやSlackやtwitter飽きてきたので合間でブログ書き始めてる&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1656590482527645697?ref_src=twsrc%5Etfw">May 11, 2023&lt;/a>&lt;/blockquote>
&lt;p>育休は「自分がもし退職したらどんな感じになるか」を疑似体験できて、自分がいなくてもうまく回っている様子を見て色々と考えさせられた期間でもあった。&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">育休という長期休暇で良かったことの１つとして自分が会社辞めた後にどんな感じになるのか疑似体験できたこと、というのがある…w&lt;br>自分がやらなくても良い、あるいはやった方が良い仕事というのがわかってくるし、任せることが如何に大事かというのも痛感する。&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1676515179767689217?ref_src=twsrc%5Etfw">July 5, 2023&lt;/a>&lt;/blockquote>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">自身がいなくても価値をコンスタントに出し続けれるような技術的、非技術的改善はやっぱレバレッジ高いよなぁと社のSlack見て思ったりする。技術的アプローチだと、1Qで取り組んだ開発基盤やCI/CD環境、ドキュメンテーションとか。非技術だとプロジェクト化、組織変更とか仕組み化全般という感じ&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1661168396778500097?ref_src=twsrc%5Etfw">May 24, 2023&lt;/a>&lt;/blockquote>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">俺は技術的アプローチは得意なのだが非技術はあまりやったことが無いなぁとか、技術的アプローチも質と量を上げていかないとなぁとか。これらは中長期的視点なんだが、一方で短期的に大量に改善していく仕組みも必要だなぁとか。&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1661170511391387650?ref_src=twsrc%5Etfw">May 24, 2023&lt;/a>&lt;/blockquote>
&lt;p>あとは、午前中見る番組がルーティン化したり&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">毎日、zip→朝ドラ→あさイチ→DayDay→ヒルナンデス、してる&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1656847417227239424?ref_src=twsrc%5Etfw">May 12, 2023&lt;/a>&lt;/blockquote>
&lt;p>ネットスーパーで時短したり&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">ネットスーパー、月額料金以外にも割高気味ではあるものの時間＝精神的余裕ができるので今のところかなり助かってる&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1665994265883979777?ref_src=twsrc%5Etfw">June 6, 2023&lt;/a>&lt;/blockquote>
&lt;p>金曜日はアンパンマン見たり&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">金曜日はアンパンマンの日です&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1656846731215253505?ref_src=twsrc%5Etfw">May 12, 2023&lt;/a>&lt;/blockquote>
&lt;p>最初は妻が外出できず、子も長時間外出できないので癒やしを求めてベランピングしようと試みたり&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">環境整ってきた &lt;a href="https://t.co/WdX3dq8uCw">pic.twitter.com/WdX3dq8uCw&lt;/a>&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1655758384786993154?ref_src=twsrc%5Etfw">May 9, 2023&lt;/a>&lt;/blockquote>
&lt;p>骨伝導イヤホン買ってランニングしたり&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">骨伝導イヤホン買ってみたけどなかなか良い&lt;/p>&amp;mdash; tzm_freedom (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1665596830619701250?ref_src=twsrc%5Etfw">June 5, 2023&lt;/a>&lt;/blockquote>
&lt;p>近くのプールで泳いだり&lt;/p></description></item><item><title>抽象に依存しなくても良くない？</title><link>https://blog.freedom-man.com/interface.html</link><pubDate>Sat, 15 Jul 2023 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/interface.html</guid><description>&lt;p>抽象に依存するとかインターフェースを使うとか、そういった話や現実の実装を見てきて、そのメリットもそれなりに理解しているものの、実はそんなに必要ないんじゃないかと思っていたりする。Clean Architectureっぽいコードや過剰に設計を意識してそうなコードを読むとインターフェースを多用していることが多い。抽象化に加えて多階層だったりするとより読みづらいし書きづらい。&lt;/p>
&lt;h2 id="抽象化することによる可読性と保守性の問題">抽象化することによる可読性と保守性の問題&lt;/h2>
&lt;p>実装を読むときに抽象型が引数だったりすると、IDEの定義ジャンプのときに抽象型の定義に飛んでしまったりする。IDEや設定によってはその抽象型を実装する具象型に飛ぶこともできるけど、抽象型の定義に飛ぶのか具象型の定義に飛ぶのかという選択が必要となる。読むだけではなく書くときもやることが増える。新しくメソッドを定義したりメソッドの引数を変更する場合は抽象型と具象型の両方で対応する必要がある。変更に強くなるはずの抽象化をすることで、変更に弱くなっている…？&lt;/p>
&lt;p>ポリモーフィズムのようにビジネスロジック的に抽象型が必要な場合は、利用する具象型が一意に決まらないので抽象に依存する他ない。ただ、if文/switch文の方が逆に読みやすいケースもあるので、可読性や保守性を考えて抽象化を適用した方が良さそうではある。&lt;/p>
&lt;p>将来的にビジネスロジック的に必要になるかもしれないから抽象化しているという言い分もありそうだが、そのときにリファクタリングすれば良いじゃん、そのためにテストを書いておけば良いじゃん、と思ったりする。「変更のためにコードを書き換える必要がない」ではなく「変更のためにコードを書き換えても安全」という方が現実的かなという感じ。&lt;/p>
&lt;h2 id="テストと抽象化">テストと抽象化&lt;/h2>
&lt;p>ビジネスロジックではなくテストだけのモチベーションで抽象化したい場合は、テストに必要な最低限のコードをモックできるよう抽象化すれば良い。ただ、基本的にモックはあまりしない方がよいと思っていて、DBなどCIで準備しやすいものは現物を使ってテストをした方がリグレッションテストとしても望ましい。テストの速度は当然遅くなり、肥大化すれば開発者体験を損なう可能性もあるが、本物のテストをするためには必要なコストとも思うし、肥大化したときは並列化など対応策がある。&lt;/p>
&lt;p>ここで言っている抽象化すべき最低限のコードというのは、外部APIの呼び出しなどコントロールできないコンポーネントのことである。これらはローカル開発環境やCI環境で準備できないが、抽象化することでモックを使ってテストができるようになる。この場合も、むやみに抽象化すると認知負荷を上げる要因となるため、テスタビリティを意識して必要な要素だけ抽象化する方が良い。&lt;/p>
&lt;h2 id="余談-phpはテストがしやすい">余談: PHPはテストがしやすい&lt;/h2>
&lt;p>ただし、PHPだとその言語特性が故に抽象型を使わなくてもモックができてしまう。PHPUnitのモックや、&lt;a href="https://www.php.net/manual/ja/class.streamwrapper.php">streamWrapper&lt;/a> を使った &lt;a href="https://github.com/php-vcr/php-vcr">PHP-VCR&lt;/a> など、動的にクラスを定義したりコードを書き換える黒魔術によりテストが困難なアプリケーションであっても後付けでテストできることが多い。つまり外部API呼び出しなど一般的には抽象化しないとテストができないものに関しても、PHPでは抽象化する必要無くテストができる。&lt;/p>
&lt;p>逆に静的型付け言語の場合は抽象型を使わないとモックができない場合が多い。PHPの場合はそうであるだけの話で、それがPHPのメリットでもある。モックをする箇所は外部APIなど大抵I/Oの処理なので、PHPはI/Oがあるアプリケーションにおいてテストがしやすいということになる。Easyな思想でテストがしやすい、それでありながら型付けができる柔軟性の高い言語、PHP。&lt;/p>
&lt;h2 id="理想と現実">理想と現実&lt;/h2>
&lt;p>自分は現実主義なので、理想は理想で理解しようと試みつつ現実の課題を最大限解いていきたい。技術はそれ自体のメリットだけではなく学習コスト・認知負荷・サービスやチームの状況も考えて導入する必要がある。抽象化も当たり前のようにやる技術というよりは、このあたり考えて導入した方がよい技術なのではないかと思ったり思わなかったり&lt;/p></description></item><item><title>2023</title><link>https://blog.freedom-man.com/2023.html</link><pubDate>Sun, 01 Jan 2023 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2023.html</guid><description/></item><item><title>2022年の振り返り</title><link>https://blog.freedom-man.com/2022-summary.html</link><pubDate>Thu, 29 Dec 2022 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/2022-summary.html</guid><description>&lt;p>今年もええ感じに振り返っていくよ！&lt;/p>
&lt;h2 id="新機能開発プロジェクトのリードエンジニア">新機能開発プロジェクトのリードエンジニア&lt;/h2>
&lt;p>&lt;a href="https://tech.yappli.io/entry/yappli_block_ui">新機能開発&lt;/a> のプロジェクトリードを今年の８月まで担当した。
プロジェクト自体の担当期間は２年間、リードとしては昨年も合わせて１年間担当したことになる。
初回リリースは１月で、昨年は新基盤の立ち上げフェーズ、今年はエンハンスするフェーズだった。&lt;/p>
&lt;p>振り返ると、基盤改善と銘打つだけあり抽象度が高く要件定義に難航したプロジェクトだった。
昨年は要件定義から実装まで結構タスクをこなしていたものの、実際のリリースは今年ということで昨年の年末年始はわりと精神的にやられていた。
とはいえ、無事ランディングできたことはかなり自信にもなったし、社内外での評価も高く、プロジェクトメンバー的にもやったことが報われたのは本当に良かった。
エンハンスもスケジュール的に大きな遅延なく、むしろ初回リリースよりもかなり複雑な機能追加の仕様に向き合ったことを考えると
俺もメンバーも力を出し切った良いプロジェクトだったように思う。&lt;/p>
&lt;p>全体的なスループットなどを考えて、自分はほぼ実装をやらず、各種調整・要件詳細決め・タスク割当て・設計・QA調整などに全振りした。
プロジェクトとしては筋の良いアサインを行ったと思うのだが、自身が成果を出すのではなくチーム全体が成果を出せるような仕組みづくりや小石取りが主業務になるので、
自身の成果を感じにくく、モチベーションとして維持しづらいというのは正直あったかもしれない。
このあたりはアンラーニングしないといけない部分だとは思うもののまだ振り切れていない感じ。
とはいえ、プロジェクトリードであっても課題解決の連続で、プロジェクトリードでしか学べないたくさんのことを経験できた。&lt;/p>
&lt;p>特に様々なメンバーとコミュニケーションを取ることによる気づきがたくさんあった。
例えば、その人の得意領域と業務がマッチしたときの成果の質とスピードや、自分には到底出来ない仕事の成果を目の当たりにし、
人の得意不得意を活かすコミュニケーションは大事だなと思ったし、専門性の高いメンバーと一緒に仕事ができる楽しみも一層感じた。
一方で、コミュニケーションの難しさも痛感しており、適切な言語化みたいなところももっと勉強しないといけないなと思った。&lt;/p>
&lt;p>ちなみにこの新機能のプロジェクトリード自体は9月初旬で引き継ぎを行い、9月中旬からは後述のサーバーサイドの改善を行っていた。
のだが、実は来年また違うサービスのプロジェクトリードになることが決まっていたりする。
今回の役割はどちらかというとテックリードに近く、調整業というよりは実装で結果を出すことが求められる感じなのでめちゃくちゃ楽しみ。&lt;/p>
&lt;h2 id="改善業">改善業&lt;/h2>
&lt;p>入社当初から技術的な課題でずっと気になっているところがあり、プロジェクトの合間を縫ってちょいちょい改善していたのだが、
重めの課題にあまり着手できていなかったのと、プロジェクトが一段落するちょうど良い節目だったので9月中旬から上記プロジェクトを外れて改善業を行った。&lt;/p>
&lt;p>具体的には↓のタスクをだいたい数ヶ月〜半年くらいの期間で行った&lt;/p>
&lt;ul>
&lt;li>EOLなPHPやフレームワーク・ライブラリをアップグレード&lt;/li>
&lt;li>一部テーブルをSQLite3からMySQLに移行するプロジェクトの引き継ぎ＆完遂&lt;/li>
&lt;li>主要アプリケーションでテストカバレッジを75%程度まで引き上げ（引き上げ前は50〜60%くらい）&lt;/li>
&lt;li>不要コード削除（有識者に聞いたりログを見たりしてコードが半分くらいになった）&lt;/li>
&lt;li>インデックスを貼ってない部分やTwigのキャッシュ設定やAPIレスポンスの調整を行って高速化&lt;/li>
&lt;li>共通化・エラーハンドリングの強化・autoload化・単体テストができるようにするリファクタリング&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/symfony_panther">symfony/pantherを使ったE2Eテストの導入&lt;/a>&lt;/li>
&lt;li>lintの導入・適用やPHPStanのレベル上げ&lt;/li>
&lt;li>CircleCIのイメージを新しいものにしたり、カバレッジ測定をphpdbgに切り替えたり&lt;/li>
&lt;/ul>
&lt;p>改善業としてはだいたい最低限やりきったなという感じで、私が入社した３年前と比べると本当にだいぶ良くなったなと思っていたりする…ｗ
テストは無かったしlintや静的解析も無いしライブラリやミドルウェアもEOLだし不要コードもたくさんあったし、冗長なコードだらけな状態だったしWARNING, Noticeも出し放題だったのが
今ではほとんど解消しているし、改善方法を社内共有会やSlackやPRで残せているので、少なくとも３年前よりは俺じゃなくてもトライできる環境になっているのではないかと思う。&lt;/p>
&lt;p>これ以外だと、今まであまりメンバーが触ったことのないサービスに関する改善も積極的に首をつっこんで改善していった。
結果として他のメンバーもそのサービスを改善できていたりするので、結構良いムーブだったんじゃないかなと思う。&lt;/p>
&lt;p>また、プロジェクトリード業で実装に関われないフラストレーション解消のため
たびたび話題に出ていた &lt;a href="https://news.yappli.co.jp/n/n4edd0dc8b9da">ちょっと重そうな機能追加&lt;/a> の実装にも関われた。
というか「これやりましょうよ、俺実装やるんで」みたいな感じで声がけして一気に要件定義して実装・QA・リリースした案件で、
これもムーブとしては良かったんじゃないかと思う。
本当はこういう感じでメンバードリブン・エンジニアドリブンでどんどん良さそうな機能を立案したりあーでもないこーでもないと
言って議論して進めていくのが良いと思うんだけど、こういう事例をたくさん作ってそういうムーブが生まれやすくするのも俺の責務かなとも思っていたりする。&lt;/p>
&lt;h2 id="phperkaigi-phpconferenceの登壇">PHPerKaigi, PHPConferenceの登壇&lt;/h2>
&lt;p>4月、10月に行われたPHPerKaigi、PHPConferenceのCfPを提出、ありがたいことに採択いただき登壇した。
前述の通り、プロジェクトリード業が主だったので昨年と違ってPHP系の仕事ネタが無く、趣味の内容に振り切った。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://speakerdeck.com/tzmfreedom/dgbp-php-debugger">DBGpを使ってPHPのデバッガーをつくろう / DGBp PHP Debugger&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://speakerdeck.com/tzmfreedom/php-src-codereading">php-srcを読んでみよう / php-src codereading&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>DBGpのネタは &lt;a href="https://blog.freedom-man.com/xdebug-dbgp">結構前に書いたブログ&lt;/a> を焼き直しした内容で、
派生してphp-srcを読んで、PHPConferenceにphp-srcネタで登壇するなど yak shaving な登壇ができたのは面白かった。
なんやかんやPHPerKaigiもPHPConferenceも現職入って２回ずつ登壇していてるんだよなぁｗ&lt;/p>
&lt;h2 id="ブログ執筆">ブログ執筆&lt;/h2>
&lt;p>会社のテックブログは14本ほど書いた。
昨年に比べるとプロジェクト系やテックブログのノウハウなど結構大きめなトピックで書くこともあり、社内での反響もそれなりにあって発信してよかったなと思った。&lt;/p></description></item><item><title>LiteFSコードリーディング：その２</title><link>https://blog.freedom-man.com/litefs2.html</link><pubDate>Tue, 16 Aug 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/litefs2.html</guid><description>&lt;p>&lt;a href="https://github.com/superfly/litefs">LiteFS&lt;/a> の仕組みについて読み解いてみました。
今回はFUSEとノード間の同期処理周りを読んでみました。&lt;/p>
&lt;p>ReplicaはPrimaryにHTTPで問い合わせを行い（ロングポーリング）、ユーザはFUSE経由でPrimaryのSQLite3ファイルにアクセスします。
DMLが発行されるとファイルの書き込みが走るのでdirtyPageとしてマーキングしておき、COMMITしたらdirtyPageの情報を使って差分のページ領域をまとめたLTXファイルをReplicaに送ります。
Replicaは返されたLTXファイルを使って差分のページ領域を更新します。&lt;/p>
&lt;img src="https://blog.freedom-man.com/img/2022/8/litefs2.png" alt="LiteFSのシーケンス" />
&lt;h2 id="fuseの処理">FUSEの処理&lt;/h2>
&lt;p>&lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/fuse/fuse.go#L67-L82">Filesystem.Mount()&lt;/a>
でFUSEを使ったマウントを行います。v0.1.0の時点では &lt;a href="https://github.com/hanwen/go-fuse">hanwen/go-fuse&lt;/a>
を使っていますが、masterの最新では &lt;a href="https://github.com/bazil/fuse">bazil/fuse&lt;/a> を使っています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// Mount mounts the file system to the mount point.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">fs&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">FileSystem&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">Mount&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#cf222e">error&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#57606a">// Create FUSE server and mount it.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewServer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">path&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>&lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">MountOptions&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">Name&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;litefs&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">Debug&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Debug&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">EnableLocks&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">SingleThreaded&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">// TODO: Remove; Release() is causing an unexpected race error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">err&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">go&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Serve&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">WaitMount&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>fuse.NewServerの第一引数でFUSEのハンドラーとして &lt;code>RawFileSystem&lt;/code> のinterfaceをセットしています。
FUSEでマウントしたディレクトリ内のファイルを開くときは &lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/fuse/fuse.go#L222-L229">FileSystem.Open()&lt;/a>
が呼ばれ、ファイル読み込みのときは &lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/fuse/fuse.go#L393-L400">FileSystem.Read()&lt;/a>
といった感じでFileSystemの関数が呼ばれます。&lt;/p>
&lt;p>SQLite3のファイルを開いたときは &lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/fuse/fuse.go#L238-L261">FileSystem.openDBFile()&lt;/a>
が呼ばれます。開かれるのは &lt;code>${マウントディレクトリ}/{DB番号}/database&lt;/code> のファイルになります。これが操作するSQLite3ファイルの実体になります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">fs&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">FileSystem&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">openDBFile&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">cancel&lt;/span> &lt;span style="color:#0550ae">&amp;lt;-&lt;/span>&lt;span style="color:#cf222e">chan&lt;/span> &lt;span style="color:#cf222e">struct&lt;/span>&lt;span style="color:#1f2328">{},&lt;/span> &lt;span style="color:#1f2328">input&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">OpenIn&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">out&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">OpenOut&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">code&lt;/span> &lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Status&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">dbID&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">fileType&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#6639ba">ParseInode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">NodeId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Printf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;fuse: open(): cannot parse inode: %d&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">NodeId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ENOENT&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">db&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">store&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">DB&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">dbID&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">db&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ENOENT&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">f&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">os&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">OpenFile&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">filepath&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Path&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#6639ba">FileTypeFilename&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">fileType&lt;/span>&lt;span style="color:#1f2328">)),&lt;/span> &lt;span style="color:#6639ba">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Flags&lt;/span>&lt;span style="color:#1f2328">),&lt;/span> &lt;span style="color:#1f2328">os&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">FileMode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Mode&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Printf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;fuse: open(): cannot open file: %s&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#6639ba">toErrno&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fh&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">fs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewFileHandle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">fileType&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">f&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">out&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Fh&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">fh&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">ID&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">out&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">OpenFlags&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">input&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Flags&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fuse&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">OK&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SQLite3のファイルを読み込む場合は &lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/fuse/fuse.go#L407-L424">FileSystem.readDBFile()&lt;/a>
が呼ばれます。読み込み時には特に何も行わないため、Open()で開いたdatabaseファイルのファイルディスクリプタを使って読み込みを行います。&lt;/p></description></item><item><title>LiteFSコードリーディング：その１</title><link>https://blog.freedom-man.com/litefs.html</link><pubDate>Sun, 14 Aug 2022 19:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/litefs.html</guid><description>&lt;p>&lt;a href="https://github.com/superfly/litefs">LiteFS&lt;/a> の仕組みについて読み解いてみました。
今回は起動〜リードレプリカの部分をざっくり紹介します。
FUSE周りの仕組みに関しては別記事で紹介予定。&lt;/p>
&lt;p>ちなみにLiteFSを試したときに使ったDockerfileなどは&lt;a href="https://github.com/tzmfreedom/go-sample/tree/f56e6dd11f09bb5b099b419ba99eb0ae56b60b7d/litefs">こちら&lt;/a>に置いているので手軽に動かしたいときにご活用ください🙏&lt;/p>
&lt;h2 id="コードリーディング">コードリーディング&lt;/h2>
&lt;p>全体としてはこういうシーケンスになっている（間違っていたらご指摘ください&lt;/p>
&lt;img alt="LiteFSのシーケンス" src="https://blog.freedom-man.com/img/2022/8/litefs.png" width="850px" />
&lt;hr>
&lt;p>&lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/cmd/litefs/main.go#L169-L205">Main.Run()&lt;/a>
がメインの処理なのでここから見ていきます。&lt;/p>
&lt;ol>
&lt;li>initStore()&lt;/li>
&lt;li>initHttpServer()&lt;/li>
&lt;li>initConsul()&lt;/li>
&lt;li>openStore()&lt;/li>
&lt;li>initFileSystem()&lt;/li>
&lt;/ol>
&lt;p>の順に実行されます。&lt;/p>
&lt;p>まず、 &lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/cmd/litefs/main.go#L228-L238">Main.initStore()&lt;/a>
でStoreのstructを初期化をします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">Main&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">initStore&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ctx&lt;/span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Context&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">error&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">mountDir&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">filepath&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Abs&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">MountDir&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Errorf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;abs: %w&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">dir&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">file&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">filepath&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Split&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">mountDir&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Store&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">litefs&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewStore&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">filepath&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">dir&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#1f2328">file&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Store&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Client&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">http&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewClient&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>NewStoreの引数を見てもらうとわかるように、&lt;code>${マウントディレクトリの親ディレクトリ}/.${マウントのファイル名}&lt;/code> にストアのパスが設定されます。
例えば &lt;code>/tmp/hoge&lt;/code> をマウントした場合は &lt;code>/tmp/.hoge&lt;/code> にストアのパスが設定されます。
これはFUSEのマウント先としては &lt;code>/tmp/hoge&lt;/code> として利用し、SQLite3やLTXファイルなどの実体は &lt;code>/tmp/.hoge&lt;/code> に置いて管理しているためです。&lt;/p>
&lt;p>&lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/cmd/litefs/main.go#L265-L272">Main.initHttpServer()&lt;/a>はノード間での通信を行うためのHTTPサーバーを初期化します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">Main&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">initHTTPServer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ctx&lt;/span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Context&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">error&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">server&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">http&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewServer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Store&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">HTTP&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Addr&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Listen&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Errorf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;cannot open http server: %w&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">HTTPServer&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">server&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/cmd/litefs/main.go#L207-L226">Main.initConsul()&lt;/a>
ではLeaserの構造体を初期化しています。LiteFSではPrimaryのノードを決定するためにConsulの &lt;a href="https://learn.hashicorp.com/tutorials/consul/application-leader-elections">client-side leader elections&lt;/a> を利用しています。
PrimaryのノードはLeaserを使ってキーを一定期間リースし、定期的にTTLを更新（Renew）します。何らかでPrimaryのノードが死んでしまった場合はリース切れし、別のノードがPrimaryになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">Main&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">initConsul&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ctx&lt;/span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Context&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">error&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#57606a">// TEMP: Allow non-localhost addresses.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#57606a">// Find advertise URL from function if this is a test.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">advertiseURL&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Consul&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AdvertiseURL&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AdvertiseURLFn&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">advertiseURL&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">AdvertiseURLFn&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">leaser&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">consul&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewLeaser&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Consul&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">URL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">advertiseURL&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">leaser&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Key&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Consul&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Key&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">leaser&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Open&lt;/span>&lt;span style="color:#1f2328">();&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Errorf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;cannot connect to consul: %w&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Printf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;initializing consul: key=%s url=%s advertise-url=%s&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Consul&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">URL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Config&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Consul&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">advertiseURL&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Leaser&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">leaser&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/superfly/litefs/blob/v0.1.0/cmd/litefs/main.go#L240-L243">Main.openStore()&lt;/a>
はデータベースをオープンし、goroutineを使ってレプリケーションのモニタリングを行います。&lt;/p></description></item><item><title>[Laravel読書録]その２: $kernel->handle()</title><link>https://blog.freedom-man.com/laravel_2.html</link><pubDate>Sat, 28 May 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/laravel_2.html</guid><description>&lt;p>Laravelの &lt;code>$kernel-&amp;gt;handle()&lt;/code> は何をしているのか調べてみたメモ。
Laravelのバージョンは &lt;code>v9.8.1&lt;/code> です&lt;/p>
&lt;p>$kernel は &lt;code>\App\Http\Kernel&lt;/code> のインスタンスです。&lt;/p>
&lt;p>&lt;code>handle()&lt;/code> はこんな感じ。$requestは &lt;code>Illuminate\Http\Request&lt;/code> のインスタンスが入る。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">handle&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">enableHttpMethodParameterOverride&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">sendRequestThroughRouter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Throwable&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">reportException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$response&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">renderException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$e&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;events&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">dispatch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">RequestHandled&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>sendRequestThroughRouter()&lt;/code> では &lt;code>$request&lt;/code> をapp（&lt;code>Illuminate\Foundation\Application&lt;/code>）のinstancesにセット、 &lt;code>bootstrap()&lt;/code> を呼び出しPipelineを使ってRouterを呼び出す。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">sendRequestThroughRouter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">instance&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;request&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Facade&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">clearResolvedInstance&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;request&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">bootstrap&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Pipeline&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$request&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">through&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">shouldSkipMiddleware&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">middleware&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">dispatchToRouter&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>bootstrap()&lt;/code> は &lt;code>bootstrappers()&lt;/code> を引数に &lt;code>app-&amp;gt;bootstrapWith()&lt;/code> を呼び出す。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">bootstrap&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">hasBeenBootstrapped&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">bootstrapWith&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">bootstrappers&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>bootstrapWith()&lt;/code> はbootstrappersをmakeでインスタンス化して &lt;code>bootstrap()&lt;/code> を呼び出す。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">bootstrapWith&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#953800">$bootstrappers&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">hasBeenBootstrapped&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$bootstrappers&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$bootstrapper&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;events&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">dispatch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;bootstrapping: &amp;#39;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#953800">$bootstrapper&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">make&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$bootstrapper&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">bootstrap&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;events&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">dispatch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;bootstrapped: &amp;#39;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#953800">$bootstrapper&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Foundation/Application.php#L239">https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Foundation/Application.php#L239&lt;/a>&lt;/p></description></item><item><title>[Laravel読書録]その１: $app->make()</title><link>https://blog.freedom-man.com/laravel_1.html</link><pubDate>Mon, 23 May 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/laravel_1.html</guid><description>&lt;p>Laravelの &lt;code>$app-&amp;gt;make()&lt;/code> は何をしているのか調べてみたメモ。
バージョンは &lt;code>v9.8.1&lt;/code> です。&lt;/p>
&lt;p>$app は &lt;code>Illuminate\Foundation\Application&lt;/code> のインスタンス。&lt;/p>
&lt;h2 id="illuminatefoundationapplication-のコンストラクタの処理">Illuminate\Foundation\Application のコンストラクタの処理&lt;/h2>
&lt;p>コンストラクタではbasePathなどを設定しつつデフォルトのbindings, providers, aliasの登録をしている。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$basePath&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$basePath&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setBasePath&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$basePath&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">registerBaseBindings&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">registerBaseServiceProviders&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">registerCoreContainerAliases&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Foundation/Application.php#L172-L181">https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Foundation/Application.php#L172-L181&lt;/a>&lt;/p>
&lt;p>&lt;code>registerBaseBindings()&lt;/code> はこんな感じな処理になっている。 &lt;code>static::setInstance()&lt;/code> はシングルトンとしてApplicationを登録。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">registerBaseBindings&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">setInstance&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">instance&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;app&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">instance&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Container&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">singleton&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Mix&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">singleton&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">PackageManifest&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">PackageManifest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Filesystem&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">basePath&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getCachedPackagesPath&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Foundation/Application.php#L198-L212">https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Foundation/Application.php#L198-L212&lt;/a>&lt;/p>
&lt;p>&lt;code>instance()&lt;/code> はこんな感じで $this-&amp;gt;instances にセットしている&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">instance&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$instance&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">removeAbstractAlias&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$isBound&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">bound&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">unset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">aliases&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// We&amp;#39;ll check to determine if this type has been bound before, and if it has
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// we will fire the rebound callbacks registered with the container and it
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// can be updated with consuming classes that have gotten resolved here.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">instances&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$instance&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$isBound&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">rebound&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$abstract&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$instance&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Container/Container.php#L468-L486">https://github.com/laravel/framework/blob/v9.8.1/src/Illuminate/Container/Container.php#L468-L486&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１９: opcacheの最適化処理</title><link>https://blog.freedom-man.com/php_src_19.html</link><pubDate>Tue, 03 May 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_19.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１８&lt;/p>
&lt;p>今日はopcacheによる最適化機構。
理解しやすかったpass1,3,10あたりから。&lt;/p>
&lt;p>最適化は &lt;code>zend_optimize()&lt;/code> で行われている&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/Optimizer/zend_optimizer.c#L889:L889">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/Optimizer/zend_optimizer.c#L889:L889&lt;/a>&lt;/p>
&lt;h2 id="pass-1-simple-local-optimizations">pass 1 (Simple local optimizations)&lt;/h2>
&lt;p>&lt;code>zend_optimizer_pass1()&lt;/code> で最適化が行われる。コメントの通り以下の最適化を行う。&lt;/p>
&lt;pre tabindex="0">&lt;code>/* pass 1 (Simple local optimizations)
 * - persistent constant substitution (true, false, null, etc)
 * - constant casting (ADD expects numbers, CONCAT strings, etc)
 * - constant expression evaluation
 * - optimize constant conditional JMPs
 * - pre-evaluate constant function calls
 * - eliminate FETCH $GLOBALS followed by FETCH_DIM/UNSET_DIM/ISSET_ISEMPTY_DIM
 */
&lt;/code>&lt;/pre>&lt;p>あらかじめstringにcastする（&lt;code>constant casting (ADD expects numbers, CONCAT strings, etc)&lt;/code>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/Optimizer/pass1.c#L48-L63">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/Optimizer/pass1.c#L48-L63&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/Optimizer/pass1.c#L106-L111">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/Optimizer/pass1.c#L106-L111&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１８: opcacheのファイルキャッシュ</title><link>https://blog.freedom-man.com/php_src_18.html</link><pubDate>Fri, 29 Apr 2022 00:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_18.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１８&lt;/p>
&lt;p>今日はopcacheのファイルキャッシュ&lt;/p>
&lt;h2 id="キャッシュをファイルに保存">キャッシュをファイルに保存&lt;/h2>
&lt;p>&lt;code>cache_script_in_shared_memory()&lt;/code> で &lt;code>zend_file_cache_script_store()&lt;/code> が呼ばれる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1650:L1650">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1650:L1650&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_file_cache_script_store()&lt;/code> で &lt;code>zend_file_cache_get_bin_file_path()&lt;/code> が呼ばれキャッシュファイルのパスを生成する&lt;/p>
&lt;pre tabindex="0">&lt;code>/tmp/095a04392b125a7d278d14ce75956467/root/php-src-php-8.1.4/1.php.bin
&lt;/code>&lt;/pre>&lt;p>こんな感じで &lt;code>opcache.file_cache&lt;/code> にファイルの絶対パスを追加したファイルパスになる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L990:L990">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L990:L990&lt;/a>&lt;/p>
&lt;p>そのファイルパスのディレクトリを再帰的に作成する&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L992:L992">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L992:L992&lt;/a>&lt;/p>
&lt;p>そのファイルパスで &lt;code>zend_file_cache_open()&lt;/code> でファイルを開き、&lt;code>writev()&lt;/code> でキャッシュを書き込んでいる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L998:L998">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L998:L998&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L1052:L1052">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L1052:L1052&lt;/a>&lt;/p>
&lt;p>キャッシュを書き込む前に構造体をごにょる必要がある。なんでかというと構造体に含まれるポインタはその実行環境におけるポインタになるので、次にロードされるときには不正なポインタになってしまう。
各ポインタをメモリの先頭アドレスからの差分にして保存、利用するときはメモリの先頭アドレスにその差分を足せば正しいポインタになるので、ポインタの変換をキャッシュの保存・取得時に行っている。&lt;/p>
&lt;p>ファイルキャッシュに保存する際の変換は &lt;code>zend_file_cache_serialize&lt;/code> で行われる。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L908-L913">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L908-L913&lt;/a>&lt;/p>
&lt;p>このあたりでファイルキャッシュに保存する構造体に値をセットしている&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L896-L905">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L896-L905&lt;/a>&lt;/p>
&lt;p>その後、 &lt;code>SERIALIZE_STR&lt;/code> や &lt;code>zend_file_cache_serialize_hash&lt;/code> などでポインタ変換を行う。
&lt;code>SERIALIZE_STR&lt;/code> はこんな感じで &lt;code>(ptr) = (void*)((char*)(ptr) - (char*)script-&amp;gt;mem);&lt;/code> によって先頭アドレスからの差分に変換している。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#define SERIALIZE_STR(ptr) do { \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">		if (ptr) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">			if (IS_ACCEL_INTERNED(ptr)) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">				(ptr) = zend_file_cache_serialize_interned((zend_string*)(ptr), info); \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">			} else { \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">				ZEND_ASSERT(IS_UNSERIALIZED(ptr)); \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">				&lt;/span>&lt;span style="color:#57606a">/* script-&amp;gt;corrupted shows if the script in SHM or not */&lt;/span>&lt;span style="color:#57606a"> \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">				if (EXPECTED(script-&amp;gt;corrupted)) { \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">					GC_ADD_FLAGS(ptr, IS_STR_INTERNED); \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">					GC_DEL_FLAGS(ptr, IS_STR_PERMANENT); \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">				} \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">				(ptr) = (void*)((char*)(ptr) - (char*)script-&amp;gt;mem); \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">			} \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">		} \
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">	} while (0)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="キャッシュをファイルから取得">キャッシュをファイルから取得&lt;/h2>
&lt;p>&lt;code>read()&lt;/code> でファイルからキャッシュを読み取り&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L1715:L1715">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L1715:L1715&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L1763:L1763">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_file_cache.c#L1763:L1763&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１７: opcacheの保存と取得</title><link>https://blog.freedom-man.com/php_src_17.html</link><pubDate>Wed, 27 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_17.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１７&lt;/p>
&lt;p>opcache続き。コードを読む前にnikic大先生の記事を読むのが良さそう&lt;br>
&lt;a href="https://www.npopov.com/2021/10/13/How-opcache-works.html">https://www.npopov.com/2021/10/13/How-opcache-works.html&lt;/a>&lt;/p>
&lt;h2 id="zend_なんちゃらの差し替え">zend_なんちゃらの差し替え&lt;/h2>
&lt;pre tabindex="0">&lt;code>main()
=&amp;gt; php_cli_startup()
=&amp;gt; php_module_startup()
=&amp;gt; zend_startup_extensions()
=&amp;gt; zend_llist_apply_with_del()
=&amp;gt; zend_extension_startup()
=&amp;gt; opcache.so!accel_startup()
&lt;/code>&lt;/pre>&lt;p>という感じで &lt;code>accel_startup()&lt;/code> が呼ばれる&lt;/p>
&lt;p>&lt;code>accel_startup()&lt;/code> では &lt;code>zend_post_startup_cb&lt;/code> に &lt;code>accel_post_startup()&lt;/code> をセットしている。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3156:L3156">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3156:L3156&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_post_startup_cb&lt;/code> は以下の経路で呼ばれる&lt;/p>
&lt;pre tabindex="0">&lt;code>main()
=&amp;gt; php_cli_startup()
=&amp;gt; php_module_startup()
=&amp;gt; zend_post_startup()
=&amp;gt; opcache.so!accel_post_startup()
&lt;/code>&lt;/pre>&lt;p>&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend.c#L1045">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend.c#L1045&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_compile_file&lt;/code> &lt;code>zend_stream_open_function&lt;/code> &lt;code>zend_resolve_path&lt;/code> にそれぞれ、&lt;br>
&lt;code>persistent_compile_file&lt;/code> &lt;code>persistent_stream_open_function&lt;/code> &lt;code>persistent_zend_resolve_path&lt;/code> を設定&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3279-L3291">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L3279-L3291&lt;/a>&lt;/p>
&lt;h2 id="キャッシュの取得と保存">キャッシュの取得と保存&lt;/h2>
&lt;p>&lt;code>zend_compile_file&lt;/code> 経由で &lt;code>persistent_compile_file()&lt;/code> が呼ばれキャッシュを検索する。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2000-L2007">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2000-L2007&lt;/a>&lt;/p>
&lt;p>&lt;code>ZCSG(hash)&lt;/code> というのがファイル名から生成したキー =&amp;gt; キャッシュの実態（oparrayとかclassやfunction tableなど） のハッシュテーブルになる（後述）&lt;/p>
&lt;p>ファイルの場合はこの辺で判定&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1961-L1965">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1961-L1965&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2136-L2138">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2136-L2138&lt;/a>&lt;/p>
&lt;p>キャッシュがない場合 &lt;code>opcache_compile_file()&lt;/code> を呼び出す&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2160:L2160">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2160:L2160&lt;/a>&lt;/p>
&lt;p>&lt;code>opcache_compile_file()&lt;/code> は &lt;code>accelerator_orig_compile_file()&lt;/code> を呼び出し、元のzend_compile_fileでop_arrayを生成する。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1789:L1789">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1789:L1789&lt;/a>&lt;/p>
&lt;p>その後 &lt;code>cache_script_in_shared_memory()&lt;/code> でキャッシュする&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2169:L2169">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L2169:L2169&lt;/a>&lt;/p>
&lt;p>&lt;code>cache_script_in_shared_memory()&lt;/code> は &lt;code>zend_accel_script_persist()&lt;/code> を呼び出す&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1600:L1600">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/ZendAccelerator.c#L1600:L1600&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_accel_script_persist()&lt;/code> では共有メモリ内にopcacheを生成している。
例えば &lt;code>zend_shared_memdup_put()&lt;/code> などで共有メモリ内に領域を確保する。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_persist.c#L525:L525">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_persist.c#L525:L525&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_shared_alloc.c#L391-L393">https://github.com/php/php-src/blob/PHP-8.1.4/ext/opcache/zend_shared_alloc.c#L391-L393&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１６: gdbserver</title><link>https://blog.freedom-man.com/php_src_16.html</link><pubDate>Sun, 24 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_16.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１６&lt;/p>
&lt;p>今日からopcache&lt;/p>
&lt;p>の前にmacOSでsoのgdbデバッグがうまくいかなかったので備忘録。&lt;/p>
&lt;h2 id="発生していた事象">発生していた事象&lt;/h2>
&lt;p>&amp;ndash;enable-debugでビルドしても &lt;code>opcache.so&lt;/code> がうまく解釈されずこんな感じに &lt;code>??&lt;/code> となってしまってブレークポイントも効かない状態に。&lt;/p>
&lt;pre tabindex="0">&lt;code>(gdb) b compile_file
Breakpoint 2 at 0x100458c32: file Zend/zend_language_scanner.l, line 642.
(gdb) r
Starting program: sapi/cli/php -dopcache.enable_cli=1 -dopcache.opt_debug_level=0x10000 -dopcache.jit=disable -dzend_extension=/path/to/modules/opcache.so 1.php
[New Thread 0x260b of process 93229]
[New Thread 0x2303 of process 93229]
warning: unhandled dyld version (17)

Thread 2 hit Breakpoint 2, compile_file (file_handle=0x7ff7bfefe228, type=8) at Zend/zend_language_scanner.l:642
642 zend_op_array *op_array = NULL;
(gdb) bt
#0 compile_file (file_handle=0x7ff7bfefe228, type=8) at Zend/zend_language_scanner.l:642
#1 0x0000000100217e69 in phar_compile_file (file_handle=0x7ff7bfefe228, type=8) at ext/phar/phar.c:3351
#2 0x0000000102da18e4 in ?? ()
#3 0x0000000264e8ae9a in ?? ()
#4 0x0100000102a5b5a0 in ?? ()
#5 0x0000000100ecd508 in ?? ()
#6 0x0000000000000000 in ?? ()
&lt;/code>&lt;/pre>&lt;p>本当はこうなってほしい&lt;/p></description></item><item><title>[php-src読書録]その１５: interfaceとtrait</title><link>https://blog.freedom-man.com/php_src_15.html</link><pubDate>Thu, 21 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_15.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１５&lt;/p>
&lt;p>今日はinterfaceとtrait&lt;/p>
&lt;h2 id="interface">interface&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">interface&lt;/span> &lt;span style="color:#1f2328">Base&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span> &lt;span style="color:#cf222e">implements&lt;/span> &lt;span style="color:#1f2328">Base&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
; (lines=2, args=0, vars=0, tmps=0)
; (before optimizer)
; /path/to/15.php:1-14
; return [] RANGE[0..0]
0000 DECLARE_CLASS string(&amp;#34;hoge&amp;#34;)
0001 RETURN int(1)

Base::hoge:
; (lines=1, args=0, vars=0, tmps=0)
; (before optimizer)
; /path/to/15.php:5-5
; return [] RANGE[0..0]
0000 RETURN null

Hoge::hoge:
; (lines=1, args=0, vars=0, tmps=0)
; (before optimizer)
; /path/to/15.php:10-12
; return [] RANGE[0..0]
0000 RETURN null
&lt;/code>&lt;/pre>&lt;p>implementsした場合は &lt;code>DECLARE_CLASS&lt;/code> opcodeが出力されているのがポイント。
前回はuseとimplementsがないパターンの継承パターンだったが、useとimplementsがある場合はフローがちょっと変わってくる。&lt;/p></description></item><item><title>[php-src読書録]その１４: 継承</title><link>https://blog.freedom-man.com/php_src_14.html</link><pubDate>Fri, 15 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_14.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１４&lt;/p>
&lt;p>引き続きclass。今日は継承&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Base&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">call&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span> &lt;span style="color:#cf222e">extends&lt;/span> &lt;span style="color:#1f2328">Base&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">call&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=5, args=0, vars=0, tmps=3)
 ; (before optimizer)
 ; /path/to/14.php:1-18
 ; return [] RANGE[0..0]
0000 V0 = NEW 0 string(&amp;#34;Hoge&amp;#34;)
0001 DO_FCALL
0002 INIT_METHOD_CALL 0 V0 string(&amp;#34;call&amp;#34;)
0003 DO_FCALL
0004 RETURN int(1)
LIVE RANGES:
 0: 0001 - 0002 (new)

Base::call:
 ; (lines=2, args=0, vars=0, tmps=0)
 ; (before optimizer)
 ; /path/to/14.php:7-10
 ; return [] RANGE[0..0]
0000 ECHO int(123)
0001 RETURN null
&lt;/code>&lt;/pre>&lt;p>extendsが定義されていると、 &lt;code>ce-&amp;gt;parent_name&lt;/code> にスーパークラスの名前がセットされる。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7721-L7724">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7721-L7724&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１３: プロパティのデフォルト値, static method</title><link>https://blog.freedom-man.com/php_src_13.html</link><pubDate>Wed, 13 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_13.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１３&lt;/p>
&lt;p>引き続きclass。今日はプロパティのデフォルト値, static method&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#953800">$hoge&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">call&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">hoge&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">call&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=8, args=0, vars=0, tmps=4)
 ; (before optimizer)
 ; /path/to/13.php:1-14
 ; return [] RANGE[0..0]
0000 V0 = NEW 0 string(&amp;#34;Hoge&amp;#34;)
0001 DO_FCALL
0002 T2 = FETCH_OBJ_R V0 string(&amp;#34;hoge&amp;#34;)
0003 ECHO T2
0004 INIT_STATIC_METHOD_CALL 0 string(&amp;#34;Hoge&amp;#34;) string(&amp;#34;call&amp;#34;)
0005 V3 = DO_UCALL
0006 ECHO V3
0007 RETURN int(1)
LIVE RANGES:
 0: 0001 - 0002 (new)

Hoge::call:
 ; (lines=2, args=0, vars=0, tmps=0)
 ; (before optimizer)
 ; /path/to/13.php:7-9
 ; return [] RANGE[0..0]
0000 ECHO int(123)
0001 RETURN null
&lt;/code>&lt;/pre>&lt;h2 id="プロパティのデフォルト値">プロパティのデフォルト値&lt;/h2>
&lt;p>&lt;code>zend_compile_prop_decl()&lt;/code> は &lt;code>zend_const_expr_to_zval()&lt;/code> を呼び出す&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7352:L7352">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7352:L7352&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１２: method呼び出し, private, protected</title><link>https://blog.freedom-man.com/php_src_12.html</link><pubDate>Tue, 12 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_12.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１２&lt;/p>
&lt;p>classの続き。method呼び出し, private, protected&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$fuga&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">call&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$foo&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$foo&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">call&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">111&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$hoge&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">fuga&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=9, args=0, vars=1, tmps=5)
 ; (before optimizer)
 ; /path/to/12.php:1-16
 ; return [] RANGE[0..0]
0000 V1 = NEW 0 string(&amp;#34;Hoge&amp;#34;)
0001 DO_FCALL
0002 ASSIGN CV0($hoge) V1
0003 INIT_METHOD_CALL 1 CV0($hoge) string(&amp;#34;call&amp;#34;)
0004 SEND_VAL_EX int(111) 1
0005 DO_FCALL
0006 T5 = FETCH_OBJ_R CV0($hoge) string(&amp;#34;fuga&amp;#34;)
0007 FREE T5
0008 RETURN int(1)
LIVE RANGES:
 1: 0001 - 0002 (new)

Hoge::call:
 ; (lines=3, args=1, vars=1, tmps=0)
 ; (before optimizer)
 ; /path/to/12.php:7-10
 ; return [] RANGE[0..0]
0000 CV0($foo) = RECV 1
0001 ECHO CV0($foo)
0002 RETURN null
&lt;/code>&lt;/pre>&lt;p>&lt;code>INIT_METHOD_CALL&lt;/code> &lt;code>FETCH_OBJ_R&lt;/code> あたり&lt;/p></description></item><item><title>[php-src読書録]その１１: classとコンストラクタ</title><link>https://blog.freedom-man.com/php_src_11.html</link><pubDate>Mon, 11 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_11.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１１&lt;/p>
&lt;p>今回はいよいよ（？）class。&lt;/p>
&lt;p>コンストラクタと初期化部分から&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#953800">$fuga&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$fuga&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">fuga&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$fuga&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">111&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=5, args=0, vars=1, tmps=3)
 ; (before optimizer)
 ; /path/to/11.php:1-20
 ; return [] RANGE[0..0]
0000 V1 = NEW 1 string(&amp;#34;Hoge&amp;#34;)
0001 SEND_VAL_EX int(111) 1
0002 DO_FCALL
0003 ASSIGN CV0($hoge) V1
0004 RETURN int(1)
LIVE RANGES:
 1: 0001 - 0003 (new)

Hoge::__construct:
 ; (lines=4, args=1, vars=1, tmps=1)
 ; (before optimizer)
 ; /path/to/11.php:7-10
 ; return [] RANGE[0..0]
0000 CV0($fuga) = RECV 1
0001 ASSIGN_OBJ THIS string(&amp;#34;fuga&amp;#34;)
0002 OP_DATA CV0($fuga)
0003 RETURN null
&lt;/code>&lt;/pre>&lt;p>class定義は &lt;code>zend_compile_class_decl()&lt;/code> でコンパイルされる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7646:L7646">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7646:L7646&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その１０: if/else/switch</title><link>https://blog.freedom-man.com/php_src_10.html</link><pubDate>Sun, 10 Apr 2022 00:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_10.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その１０&lt;/p>
&lt;p>今回はif/else/switch&lt;/p>
&lt;p>まずはif/else&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0550ae">111&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0550ae">222&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">$&lt;/span>&lt;span style="color:#900;font-weight:bold">_main&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>lines&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> args&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> vars&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> tmps&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>before optimizer&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#0550ae">/&lt;/span>path&lt;span style="color:#0550ae">/&lt;/span>to&lt;span style="color:#0550ae">/&lt;/span>&lt;span style="color:#0550ae">10.&lt;/span>&lt;span style="color:#900;font-weight:bold">php&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#0550ae">8&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">[]&lt;/span> RANGE&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0..0&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">0000&lt;/span> JMPZ &lt;span style="color:#cf222e">bool&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">true&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">0003&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">0001&lt;/span> ECHO &lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">111&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">0002&lt;/span> JMP &lt;span style="color:#0550ae">0004&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">0003&lt;/span> ECHO &lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">222&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">0004&lt;/span> RETURN &lt;span style="color:#cf222e">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>zend_compile_if()&lt;/code> でコンパイルされる&lt;/p>
&lt;p>条件のコンパイル&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5392:L5392">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5392:L5392&lt;/a>&lt;/p>
&lt;p>JMPZの設定。ジャンプ先は後で設定。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5393:L5393">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5393:L5393&lt;/a>&lt;/p>
&lt;p>if文のいずれかの処理にマッチした場合はif文を抜ける必要があるのでそのJMPの設定。JMP先は最後に設定&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5397-L5399">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5397-L5399&lt;/a>&lt;/p>
&lt;p>&lt;code>i != list-&amp;gt;children - 1&lt;/code> の条件は最後のelseifはジャンプしないので分岐している感じっぽい&lt;/p>
&lt;p>JMPZで条件に合致しなかったときのJMP先を次のelseif, elseの開始位置に設定&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5400">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5400&lt;/a>&lt;/p>
&lt;p>elseの場合は条件なしで実行する&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5404">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5404&lt;/a>&lt;/p>
&lt;p>if文のいずれかの処理にマッチしたときのif分を抜けるためのジャンプ先をここで設定&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5408-L5413">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5408-L5413&lt;/a>&lt;/p>
&lt;h2 id="opcode">opcode&lt;/h2>
&lt;p>&lt;code>JMPZ&lt;/code> は &lt;code>ZEND_JMPZ_SPEC_CONST_HANDLER&lt;/code> で処理される&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-ca" data-lang="ca">val = RT_CONSTANT(opline, opline-&amp;gt;op1);

if (Z_TYPE_INFO_P(val) == IS_TRUE) {
	ZEND_VM_NEXT_OPCODE();
} else if (EXPECTED(Z_TYPE_INFO_P(val) &amp;lt;= IS_TRUE)) {
	// ...
	ZEND_VM_JMP_EX(OP_JMP_ADDR(opline, opline-&amp;gt;op2), 0);
}

SAVE_OPLINE();
op1_type = IS_CONST;
if (i_zend_is_true(val)) {
	opline++;
} else {
	opline = OP_JMP_ADDR(opline, opline-&amp;gt;op2);
}
// ...
ZEND_VM_JMP(opline);
&lt;/code>&lt;/pre>&lt;p>&lt;code>Z_TYPE_INFO_P(val) == IS_TRUE&lt;/code> だったり、 &lt;code>i_zend_is_true(val)&lt;/code> がtrueの場合は次の処理に以降し、
そうでない場合は &lt;code>OP_JMP_ADDR(opline, opline-&amp;gt;op2)&lt;/code> によって次の分岐部分（elseif か else）にジャンプします。&lt;/p></description></item><item><title>[php-src読書録]その９: whileとforeach</title><link>https://blog.freedom-man.com/php_src_9.html</link><pubDate>Sat, 09 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_9.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その９&lt;/p>
&lt;p>今回はwhileとforeach&lt;/p>
&lt;h2 id="while">while&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">while&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$i&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=7, args=0, vars=1, tmps=3)
 ; (before optimizer)
 ; /path/to/9.php:1-8
 ; return [] RANGE[0..0]
0000 ASSIGN CV0($i) int(0)
0001 JMP 0004
0002 ECHO int(123)
0003 PRE_INC CV0($i)
0004 T3 = IS_SMALLER CV0($i) int(1)
0005 JMPNZ T3 0002
0006 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>見るとfor文とほぼ同じで、for文はinit/loopを書く場所が確保されているだけで本質的にはwhileと変わらないことがわかる。&lt;/p>
&lt;p>JMPを生成&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5187:L5187">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5187:L5187&lt;/a>&lt;/p>
&lt;p>statementを生成&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5192">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5192&lt;/a>&lt;/p>
&lt;p>条件分岐前にJMP先を設定&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5195">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5195&lt;/a>&lt;/p>
&lt;p>条件判定とJMPを生成&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5196-L5198">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5196-L5198&lt;/a>&lt;/p>
&lt;h2 id="foreach">foreach&lt;/h2>
&lt;p>foreachのスクリプト例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">foreach&lt;/span>&lt;span style="color:#1f2328">([&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$a&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$a&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=6, args=0, vars=1, tmps=1)
 ; (before optimizer)
 ; /path/to/9_1.php:1-6
 ; return [] RANGE[0..0]
0000 V1 = FE_RESET_R array(...) 0004
0001 FE_FETCH_R V1 CV0($a) 0004
0002 ECHO CV0($a)
0003 JMP 0001
0004 FE_FREE V1
0005 RETURN int(1)
LIVE RANGES:
 1: 0001 - 0004 (loop)
&lt;/code>&lt;/pre>&lt;p>&lt;code>FE_RESET_R&lt;/code> &lt;code>FE_FETCH_R&lt;/code> &lt;code>FE_FREE&lt;/code> あたりが新出なのでこのあたりを見ていく&lt;/p></description></item><item><title>Xdebugコードリーディング</title><link>https://blog.freedom-man.com/xdebug_codereading.html</link><pubDate>Sat, 09 Apr 2022 02:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/xdebug_codereading.html</guid><description>&lt;p>PHPerKaigi 2022でXdebugのデバッガの話をするのですが、その調べ物ついでにXdebugのコードリーディングをしたのでその備忘録。&lt;/p>
&lt;p>ちなみに発表資料はこちら&lt;/p>
&lt;iframe class="speakerdeck-iframe" frameborder="0" src="https://speakerdeck.com/player/0f0c9197f13e4131aafe801e927a49b0" title="DBGpを使って PHPのデバッガーをつくろう / DGBp PHP Debugger " allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" style="border: 0px; background: padding-box padding-box rgba(0, 0, 0, 0.1); margin: 0px; padding: 0px; border-radius: 6px; box-shadow: rgba(0, 0, 0, 0.2) 0px 5px 40px; width: 560px; height: 314px;" data-ratio="1.78343949044586">&lt;/iframe>
&lt;p>Xdebugのバージョンは3.1.3です。&lt;/p>
&lt;h2 id="zend拡張の登録">Zend拡張の登録&lt;/h2>
&lt;p>&lt;code>xdebug_zend_startup()&lt;/code> が初期設定です。xdebug_zend_startupは &lt;code>zend_startup_module(&amp;amp;xdebug_module_entry)&lt;/code> を呼び出しています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>ZEND_DLEXPORT zend_extension zend_extension_entry &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">char&lt;/span>&lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> XDEBUG_NAME&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">char&lt;/span>&lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> XDEBUG_VERSION&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">char&lt;/span>&lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> XDEBUG_AUTHOR&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">char&lt;/span>&lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> XDEBUG_URL_FAQ&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">char&lt;/span>&lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> XDEBUG_COPYRIGHT_SHORT&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	xdebug_zend_startup&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	xdebug_zend_shutdown&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* activate_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* deactivate_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* message_handler_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* op_array_handler_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	xdebug_statement_call&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* statement_handler_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* fcall_begin_handler_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* fcall_end_handler_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	xdebug_init_oparray&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* op_array_ctor_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">NULL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">/* op_array_dtor_func_t */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	STANDARD_ZEND_EXTENSION_PROPERTIES
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://github.com/xdebug/xdebug/blob/3.1.3/xdebug.c#L806-L824">https://github.com/xdebug/xdebug/blob/3.1.3/xdebug.c#L806-L824&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その８: forループ</title><link>https://blog.freedom-man.com/php_src_8.html</link><pubDate>Fri, 08 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_8.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その８&lt;/p>
&lt;p>今日はforループ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#953800">$i&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$i&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcodes&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=7, args=0, vars=1, tmps=3)
 ; (before optimizer)
 ; /path/to/8.php:1-6
 ; return [] RANGE[0..0]
0000 ASSIGN CV0($i) int(0)
0001 JMP 0004
0002 ECHO CV0($i)
0003 PRE_INC CV0($i)
0004 T3 = IS_SMALLER CV0($i) int(2)
0005 JMPNZ T3 0002
0006 RETURN int(1)
&lt;/code>&lt;/pre>&lt;h2 id="ast">AST&lt;/h2>
&lt;p>&lt;code>zend_compile_for()&lt;/code> でforがコンパイルされる。&lt;/p>
&lt;p>&lt;code>zend_compile_expr_list()&lt;/code> で &lt;code>$i = 0;&lt;/code> の部分がコンパイルされる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5258:L5258">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5258:L5258&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_emit_jump()&lt;/code> でJMPのopcodeが生成される。ジャンプ先は後で設定する。&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5261">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5261&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L2138-L2144">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L2138-L2144&lt;/a>&lt;/p>
&lt;p>opnum_jmpはopcodesのindex&lt;/p>
&lt;p>&lt;code>zend_compile_stmt()&lt;/code> でループ内のstmtのコンパイル&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5266">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5266&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_compile_expr_list()&lt;/code> でループの加算処理 &lt;code>$i++&lt;/code> をコンパイル&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5269">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5269&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_update_jump_target_to_next()&lt;/code> で最初のJMPオペコード &lt;code>opnum_jmp&lt;/code> のジャンプ先を設定している&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5272">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L5272&lt;/a>&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L2204">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L2204&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その７: ハッシュ</title><link>https://blog.freedom-man.com/php_src_7.html</link><pubDate>Thu, 07 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_7.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その７&lt;/p>
&lt;p>今回はハッシュ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$tmp&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;hoge&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$tmp&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;hoge&amp;#39;&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$tmp&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;fuga&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=6, args=0, vars=1, tmps=3)
 ; (before optimizer)
 ; /path/to/7.php:1-6
 ; return [] RANGE[0..0]
0000 ASSIGN CV0($tmp) array(...)
0001 T2 = FETCH_DIM_R CV0($tmp) string(&amp;#34;hoge&amp;#34;)
0002 FREE T2
0003 ASSIGN_DIM CV0($tmp) string(&amp;#34;fuga&amp;#34;)
0004 OP_DATA bool(false)
0005 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>FETCH_DIM_R, ASSIGN_DIM, OP_DATAなど基本的にはarrayと同じopcodeを使っている。&lt;/p>
&lt;p>&lt;code>zend_compile_array()&lt;/code> =&amp;gt; &lt;code>zend_try_ct_eval_array()&lt;/code> 経由で &lt;code>zend_symtable_update()&lt;/code> を呼び出す&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8533:L8533">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8533:L8533&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_symtable_update()&lt;/code> は &lt;code>zend_hash_update()&lt;/code> を呼び出す&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.h#L464:L464">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.h#L464:L464&lt;/a>&lt;/p>
&lt;p>&lt;code>_zend_hash_add_or_update_i()&lt;/code> を呼び出される
zend_stringからハッシュキーを算出。&lt;code>key.h&lt;/code> にセットされる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L736:L736">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L736:L736&lt;/a>&lt;/p>
&lt;p>初期化時に &lt;code>zend_hash_real_init_mixed()&lt;/code> が呼ばれる&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L741:L741">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L741:L741&lt;/a>&lt;/p>
&lt;p>&lt;code>emalloc()&lt;/code> でハッシュテーブルの領域が確保される&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L172">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L172&lt;/a>&lt;/p>
&lt;p>以下のバケット配列のサイズとハッシュテーブルのサイズを足した領域が確保される&lt;/p>
&lt;ul>
&lt;li>バケットのサイズ: (size_t)(8) * sizeof(Bucket)&lt;/li>
&lt;li>ハッシュのサイズ: ((size_t)(uint32_t)-(int32_t)((uint32_t)(-16))) * sizeof(uint32_t)&lt;/li>
&lt;/ul>
&lt;p>一番最初はデータの領域8要素分、ハッシュの領域16要素分の領域が確保される。&lt;/p></description></item><item><title>[php-src読書録]その６: array</title><link>https://blog.freedom-man.com/php_src_6.html</link><pubDate>Tue, 05 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_6.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その６&lt;/p>
&lt;p>今回はarray&lt;/p>
&lt;h2 id="定数配列">定数配列&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>以下がopcodeで、arrayがそのままアサインされることになる&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
; (lines=2, args=0, vars=1, tmps=1)
; (before optimizer)
; /path/to/6.php:1-4
; return [] RANGE[0..0]
0000 ASSIGN CV0($i) array(...)
0001 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>arrayは &lt;code>zend_compile_array()&lt;/code> でコンパイルされる。
定数配列の場合、 &lt;code>zend_compile_array()&lt;/code> 内の &lt;code>zend_try_ct_eval_array()&lt;/code> でarrayのzvalをコンパイルしている&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L9334">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L9334&lt;/a>&lt;/p>
&lt;p>以下で全要素が定数であるかの確認&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8454-L8483">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8454-L8483&lt;/a>&lt;/p>
&lt;p>&lt;code>array_init_size()&lt;/code> でarrayを初期化&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8494:L8494">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8494:L8494&lt;/a>&lt;/p>
&lt;p>マクロなどを全部展開するとこんな感じなコードになり、ハッシュテーブルをinitしてzvalにセットしている。&lt;/p>
&lt;pre tabindex="0">&lt;code>HashTable *ht = emalloc(sizeof(HashTable));
_zend_hash_init_int(ht, list-&amp;gt;children, ZVAL_PTR_DTOR, 0);

zend_array *__arr = ht;
zval *__z = result;
__z.value.arr = __arr;
__z.u1.type_info = IS_ARRAY_EX;
&lt;/code>&lt;/pre>&lt;p>各要素に対して &lt;code>zend_ast_get_zval()&lt;/code> でzvalを取得する&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8500">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8500&lt;/a>&lt;/p>
&lt;p>ここでresultにzvalをインサート&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8559">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L8559&lt;/a>&lt;/p>
&lt;p>&lt;code>ht-&amp;gt;arData + h&lt;/code> に配列としてデータを格納している&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L1077-L1084">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_hash.c#L1077-L1084&lt;/a>&lt;/p>
&lt;h2 id="変数入りの配列">変数入りの配列&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$j&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$i&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcodes&lt;/p></description></item><item><title>[php-src読書録]その５: function</title><link>https://blog.freedom-man.com/php_src_5.html</link><pubDate>Mon, 04 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_5.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その５&lt;/p>
&lt;p>今回はfunction&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$i&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=4, args=0, vars=0, tmps=1)
 ; (before optimizer)
 ; /path/to/5.php:1-6
 ; return [] RANGE[0..0]
0000 INIT_FCALL 1 96 string(&amp;#34;hoge&amp;#34;)
0001 SEND_VAL int(123) 1
0002 DO_UCALL
0003 RETURN int(1)

hoge:
 ; (lines=2, args=1, vars=1, tmps=0)
 ; (before optimizer)
 ; /path/to/5.php:3-3
 ; return [] RANGE[0..0]
0000 CV0($i) = RECV 1
0001 RETURN null
&lt;/code>&lt;/pre>&lt;h2 id="functionのコンパイル">functionのコンパイル&lt;/h2>
&lt;p>&lt;code>zend_compile_top_stmt()&lt;/code> から &lt;code>zend_compile_func_decl()&lt;/code> が呼ばれる
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L9936">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L9936&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_compile_func_decl()&lt;/code> では関数用のop_arrayを作成する&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7172-L7292">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7172-L7292&lt;/a>&lt;/p>
&lt;p>&lt;code>zend_compile_func_decl()&lt;/code> は &lt;code>zend_begin_func_decl()&lt;/code> を呼び出し&lt;br>
&lt;a href="https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7214:L7214">https://github.com/php/php-src/blob/PHP-8.1.4/Zend/zend_compile.c#L7214:L7214&lt;/a>&lt;/p></description></item><item><title>[php-src読書録]その４: ADDとTMPVAR</title><link>https://blog.freedom-man.com/php_src_4.html</link><pubDate>Sun, 03 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_4.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その４&lt;/p>
&lt;h2 id="デバッグの効率化">デバッグの効率化&lt;/h2>
&lt;p>今までgdbを使っていたんだけどTUIモードというのがあるのを初めて知った。
&lt;code>gdb -tui&lt;/code> で実行するとTUIモードでの実行になる。
&lt;code>gdb&lt;/code> を実行してから &lt;code>C-x C-a&lt;/code> でもOK。
tuiモードを使わないとステップ実行のたびに &lt;code>list&lt;/code> を実行するなどしてソースコードを表示する必要があって大変…&lt;/p>
&lt;p>そして、それよりもVSCodeのGUIデバッガの方がはるかに楽だった。
C/C++ のプラグインをインストールして &lt;code>launch.json&lt;/code> をこんな感じで設定してデバッグ実行すればOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;version&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;0.2.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;configurations&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;(gdb) Launch&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;cppdbg&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;request&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;launch&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;program&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;${workspaceFolder}/sapi/cli/php&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;args&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;test.php&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;stopAtEntry&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;cwd&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;${workspaceFolder}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;environment&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;externalConsole&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;MIMode&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;gdb&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;miDebuggerPath&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/usr/local/bin/gdb&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;setupCommands&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Enable pretty-printing for gdb&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;text&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;-enable-pretty-printing&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;ignoreFailures&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="addとtmpvar">ADDとTMPVAR&lt;/h2>
&lt;p>今回はこちらのコードを追っていく&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#953800">$i&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=4, args=0, vars=1, tmps=3)
 ; (before optimizer)
 ; /path/to/4.php:1-5
 ; return [] RANGE[0..0]
0000 ASSIGN CV0($i) int(1)
0001 T2 = ADD int(1) CV0($i)
0002 ASSIGN CV0($i) T2
0003 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>ASSIGNは前回説明済みなので割愛。&lt;/p></description></item><item><title>[php-src読書録]その３: 変数アサイン</title><link>https://blog.freedom-man.com/php_src_3.html</link><pubDate>Sat, 02 Apr 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_3.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その３&lt;/p>
&lt;p>今回見ていくスクリプトはこちら&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$i&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="変数アサイン">変数アサイン&lt;/h2>
&lt;p>opcode&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
; (lines=2, args=0, vars=1, tmps=1)
; (before optimizer)
; /path/to/3.php:1-4
; return [] RANGE[0..0]
0000 ASSIGN CV0($i) string(&amp;#34;hoge&amp;#34;)
0001 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>gdbでhandlerをデバッグ&lt;/p>
&lt;pre tabindex="0">&lt;code>(gdb) p execute_data-&amp;gt;opline-&amp;gt;handler
$1 = (const void *) 0x100517cb0 &amp;lt;ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER&amp;gt;
&lt;/code>&lt;/pre>&lt;p>ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLERが呼び出される&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">static&lt;/span> ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL &lt;span style="color:#6639ba">ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>ZEND_OPCODE_HANDLER_ARGS&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	USE_OPLINE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	zval &lt;span style="color:#0550ae">*&lt;/span>value&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	zval &lt;span style="color:#0550ae">*&lt;/span>variable_ptr&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">SAVE_OPLINE&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	value &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">RT_CONSTANT&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>opline&lt;span style="color:#1f2328">,&lt;/span> opline&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>op2&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	variable_ptr &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">EX_VAR&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>opline&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>op1&lt;span style="color:#1f2328">.&lt;/span>var&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	value &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">zend_assign_to_variable&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>variable_ptr&lt;span style="color:#1f2328">,&lt;/span> value&lt;span style="color:#1f2328">,&lt;/span> IS_CONST&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#6639ba">EX_USES_STRICT_TYPES&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">UNEXPECTED&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">ZVAL_COPY&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">EX_VAR&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>opline&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>result&lt;span style="color:#1f2328">.&lt;/span>var&lt;span style="color:#1f2328">),&lt;/span> value&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#57606a">/* zend_assign_to_variable() always takes care of op2, never free it! */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#6639ba">ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>RT_CONSTANTは定数のzvalを取得している。後述。&lt;/p></description></item><item><title>[php-src読書録]その２: echo</title><link>https://blog.freedom-man.com/php_src_2.html</link><pubDate>Thu, 31 Mar 2022 13:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_2.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。その２&lt;/p>
&lt;h2 id="opcodeの確認">opcodeの確認&lt;/h2>
&lt;p>OPcacheを使う方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sapi/cli/php -dopcache.enable_cli&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -dopcache.opt_debug_level&lt;span style="color:#0550ae">=&lt;/span>0x10000 &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -dzend_extension&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>&lt;span style="color:#6639ba">pwd&lt;/span>&lt;span style="color:#cf222e">)&lt;/span>/modules/opcache.so &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> hoge.php
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre tabindex="0">&lt;code>$_main:
; (lines=2, args=0, vars=0, tmps=0)
; (before optimizer)
; /path/to/hoge.php:1-4
; return [] RANGE[0..0]
0000 ECHO int(123)
0001 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>phpdbgを使う方法&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ./sapi/phpdbg/phpdbg &lt;span style="color:#0a3069">&amp;#39;-p*&amp;#39;&lt;/span> hoge.php PHP-8.1.4 ⬆ ✭ ✱ ◼
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;pre tabindex="0">&lt;code>$_main:
; (lines=2, args=0, vars=0, tmps=0)
; /path/to/hoge.php:1-4
L0003 0000 ECHO int(123)
L0004 0001 RETURN int(1)
[Script ended normally]
&lt;/code>&lt;/pre>&lt;h2 id="echoのハンドラーを見てみる">ECHOのハンドラーを見てみる&lt;/h2>
&lt;p>今回デバッグするスクリプト&lt;/p>
&lt;pre tabindex="0">&lt;code>&amp;lt;?php

echo &amp;#34;hoge&amp;#34;;
&lt;/code>&lt;/pre>&lt;p>opcodeはこんな感じ&lt;/p>
&lt;pre tabindex="0">&lt;code>$_main:
 ; (lines=2, args=0, vars=0, tmps=0)
 ; (before optimizer)
 ; /path/to/echo.php:1-4
 ; return [] RANGE[0..0]
0000 ECHO string(&amp;#34;hoge&amp;#34;)
0001 RETURN int(1)
&lt;/code>&lt;/pre>&lt;p>ECHO opcodeを詳しく見てみる。&lt;/p></description></item><item><title>[php-src読書録]その１: CLI実行からスクリプト実行まで</title><link>https://blog.freedom-man.com/php_src_1.html</link><pubDate>Thu, 31 Mar 2022 10:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_src_1.html</guid><description>&lt;p>php-srcのコードリーディングした内容をコツコツ残すテスト。&lt;/p>
&lt;h2 id="参考にした記事">参考にした記事&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.phpinternalsbook.com/index.html">PHP Internals Book&lt;/a>
&lt;ul>
&lt;li>PHPの内部のことが色々書いてある。&lt;/li>
&lt;li>PHPのビルド周りは、コード読みつつgdbで確認しつつ、という感じで理解を深めるために抑えておいたほうが良いかも。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="http://tech.respect-pal.jp/php-helloworld/">PHP による hello world 入門&lt;/a>
&lt;ul>
&lt;li>SAPIを含めたPHPの実行フローについてまとまっている記事&lt;/li>
&lt;li>mod_phpのapacheのハンドラ周りも書いてあって流石すぎる…&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://qiita.com/sj-i/items/836fa5a5e246961c40b6">PHP の関数実行とその計測（記事版）&lt;/a>
&lt;ul>
&lt;li>関数実行の計測の切り口でZend Engineについて説明されている記事。コールスタック周りの理解にめっちゃ有用でした。超感謝。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://www.npopov.com/2017/04/14/PHP-7-Virtual-machine.html">PHP 7 Virtual Machine&lt;/a>
&lt;ul>
&lt;li>nikic大先生によるZend Engineの解説。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="https://phpinternals.net/articles/implementing_a_range_operator_into_php">Implementing a Range Operator into PHP&lt;/a>
&lt;ul>
&lt;li>実装して理解しようシリーズ（？）&lt;/li>
&lt;li>Lexer, Parser, ASTからopcodeへのコンパイル, VM実行と一通り処理を追えるのでコピペでも良いからやってみると良さそう。&lt;/li>
&lt;li>ちなみに実装したときの備忘録は&lt;a href="https://blog.freedom-man.com/php_implement_operator">こちら&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="http://real-c.info/">本物のC&lt;/a>
&lt;ul>
&lt;li>C言語初心者には大変ありがたいサイト。マクロの定義や作法がわかってよき。&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="デバッグするにあたって">デバッグするにあたって&lt;/h2>
&lt;p>コード読むだけで理解しきるのは難しいのでgdbで実際の変数の中身を見ながらステップ実行していくと理解しやすい。
デバッグするにはsrcから&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./buildconf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./configure --enable-opcache --enable-debug
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>という感じでビルドしてgdbを実行すればOK&lt;/p>
&lt;pre tabindex="0">&lt;code>gdb --args sapi/cli/php test.php
&lt;/code>&lt;/pre>&lt;p>Macの場合は、brewでgdbをインストールできる&lt;/p>
&lt;pre tabindex="0">&lt;code>brew install gdb
&lt;/code>&lt;/pre>&lt;p>このままだと利用できないので以下の記事を参考にコード署名して利用する&lt;br>
&lt;a href="https://qiita.com/takahashim/items/204ffa698afe09bd4e28">OS XでGDBを使う（ためにコード署名をする）&lt;/a>&lt;/p>
&lt;pre tabindex="0">&lt;code>sudo codesign -s gdb-cert /usr/local/bin/gdb
&lt;/code>&lt;/pre>&lt;h2 id="c言語を読むための知識">C言語を読むための知識&lt;/h2>
&lt;p>特に読むのに苦労しているのがマクロ…。&lt;/p>
&lt;p>マクロはプリプロセッサで文字列置換をするものっぽい。&lt;/p>
&lt;p>例えば&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>dim &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">RT_CONSTANT&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>opline&lt;span style="color:#1f2328">,&lt;/span> opline&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>op2&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>は&lt;/p>
&lt;pre tabindex="0">&lt;code>dim = ((zval*)(((char*)(opline)) + (int32_t)(opline-&amp;gt;op2).constant))
&lt;/code>&lt;/pre>&lt;p>という感じで置換される。&lt;/p></description></item><item><title>[php-src勉強録]レンジオペレータの実装</title><link>https://blog.freedom-man.com/php_implement_operator.html</link><pubDate>Thu, 31 Mar 2022 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_implement_operator.html</guid><description>&lt;p>レンジオペレータを追加してみよう的な記事を見てやってみたので備忘録。
&lt;a href="https://phpinternals.net/articles/implementing_a_range_operator_into_php">https://phpinternals.net/articles/implementing_a_range_operator_into_php&lt;/a>&lt;/p>
&lt;p>わりとコピペなので深堀り（各関数が何やってるかとか）は別途やる予定。&lt;/p>
&lt;h2 id="phpのビルド方法">PHPのビルド方法&lt;/h2>
&lt;p>だいたいこんな感じでビルドできる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone git@github.com:php/php-src.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">cd&lt;/span> php-src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./buildconf
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./configure --with-iconv&lt;span style="color:#0550ae">=&lt;/span>/path/to/libiconv --enable-opcache
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make -j4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>このあとに、make installしても良いが面倒？な場合は&lt;code>sapi/cli/php&lt;/code> が作られるのでそれを実行して動作確認するでも良さそう。
拡張モジュールは &lt;code>modules/&lt;/code> にある。&lt;/p>
&lt;p>設定変えたりブランチ変えて再ビルドしたいときはこんな感じで&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>make clean
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./buildconf --force
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./config.nice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>make -j4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>詳細は&lt;a href="https://www.phpinternalsbook.com/php7/build_system/building_php.html">PHP Internals Book&lt;/a> にめっちゃ書かれているので参照すると良さそう&lt;/p>
&lt;h2 id="レンジオペレータの追加">レンジオペレータの追加&lt;/h2>
&lt;p>実装したものは&lt;a href="https://github.com/tzmfreedom/php-src/commit/6ffa69a32f8fe1f2b4644bb591548032c1710575">こちら&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://phpinternals.net/articles/implementing_a_range_operator_into_php">php internalsの記事&lt;/a> にあるように、
以下を実装していけばOK&lt;/p>
&lt;p>&lt;strong>1. Lexerの修正&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Zend/Zend/zend_language_scanner.l&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. Parserの修正&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Zend/zend_ast.h&lt;/li>
&lt;li>Zend/zend_language_parser.y&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. ASTからVMコードの出力&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Zend/zend_compile.c&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>4. VMの変更（オペレータ追加）&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Zend/zend_vm_def.h&lt;/li>
&lt;/ul>
&lt;p>zend_vm_def.hを修正して &lt;code>make&lt;/code> すると以下のファイルが自動生成される。
（PHPでCを生成しているの凄い。これも後で深堀りしたい&lt;/p>
&lt;ul>
&lt;li>Zend/zend_vm_execute.h&lt;/li>
&lt;li>Zend/zend_vm_handlers.h&lt;/li>
&lt;li>Zend/zend_vm_opcodes.h&lt;/li>
&lt;li>Zend/zend_vm_opcodes.c&lt;/li>
&lt;/ul>
&lt;p>&lt;a href="https://github.com/php/php-src/blob/48e07076209c6163ecb4a756f73f511f1f09200e/Zend/zend_vm_gen.php">Zend/zend_vm_gen.php&lt;/a> を使って生成しているのでこのスクリプトを実行するのでもOK（試してない&lt;/p>
&lt;h2 id="echoの改変例">echoの改変例&lt;/h2>
&lt;p>&lt;a href="https://github.com/tzmfreedom/php-src/commit/71f330a36f6863af382df0d774c7803f95e4d489">https://github.com/tzmfreedom/php-src/commit/71f330a36f6863af382df0d774c7803f95e4d489&lt;/a>&lt;/p>
&lt;p>とりあえずwrite()しまくる &lt;code>wei&lt;/code> ステートメントを追加してみた。
echoのコピペ。
coreの変更なのでmod_phpでもCLIでも &lt;code>wei&lt;/code> が使えるようになる。&lt;/p></description></item><item><title>2022</title><link>https://blog.freedom-man.com/2022.html</link><pubDate>Sat, 01 Jan 2022 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2022.html</guid><description/></item><item><title>2021年の振り返り</title><link>https://blog.freedom-man.com/2021-summary.html</link><pubDate>Thu, 30 Dec 2021 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/2021-summary.html</guid><description>&lt;h2 id="仕事">仕事&lt;/h2>
&lt;h3 id="採用へのチャレンジ">採用へのチャレンジ&lt;/h3>
&lt;p>今年の新しいチャレンジとして採用業務をやっていた。 最初はスカウト打つの手伝ってくれーという依頼から始まって、その延長でカジュアル面談や書類選考、採用面接などなど色々やった感じ。
前職でも新卒・中途の採用面談をやっていたりしたんだが、この１年間は質・量ともに今までで一番採用にコミットした。&lt;/p>
&lt;p>やったことはだいたいここに書いた。&lt;br>
&lt;a href="https://tech.yappli.io/entry/server_recruiting_2021">サーバーサイドエンジニアによるエンジニア採用の取り組み in 2021&lt;/a>&lt;/p>
&lt;p>採用ペルソナの定義、募集要項見直し、スカウト、カジュアル面談、書類選考、面接、技術ブログ執筆、技術スタックまとめ、イベント登壇、各種タスクの資料化などなど色々やった。
会社側のカジュアル面談は人生で初めてで、中途面接も片手で数えるくらいしかやったことがなかったけど、カジュアル面談・面接合わせて年間70回以上担当した。&lt;/p>
&lt;p>テックカンファレンスのスポンサーも声がけしてみてGo Conference Autumn 2021や来年のGo Conference Spring 2022, PHPerKaigi 2022などのスポンサーが決まったりした。&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">本日開催「Go conference 2021 Autumn」に株式会社ヤプリはSilverスポンサーとして協賛しています。Yappliは2020年に Go を用いて新たなCMSへ進化しており、私たちにとって欠かせない技術です。&lt;br>&lt;br>オフィスアワーでは、弊社のエンジニアがデモや取り組みなどお話しますのでお立ち寄りください！&lt;a href="https://twitter.com/hashtag/gocon?src=hash&amp;amp;ref_src=twsrc%5Etfw">#gocon&lt;/a> &lt;a href="https://t.co/86odpTvXVt">https://t.co/86odpTvXVt&lt;/a>&lt;/p>&amp;mdash; Yappli （ヤプリ）アプリ開発・運用・分析 (@yappli_jp) &lt;a href="https://twitter.com/yappli_jp/status/1459379313568993281?ref_src=twsrc%5Etfw">November 13, 2021&lt;/a>&lt;/blockquote>
&lt;p>OSSの寄付（例えばPHP Foundation）の話もちょっと頭出ししていたり、Meety開設してみて、何人かカジュアル面談させてもらったりした。&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">Meety立ててみた！／&lt;a href="https://t.co/LFiNJBgLbB">https://t.co/LFiNJBgLbB&lt;/a> &lt;a href="https://twitter.com/hashtag/Meety?src=hash&amp;amp;ref_src=twsrc%5Etfw">#Meety&lt;/a> &lt;a href="https://twitter.com/hashtag/%E3%83%8E%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89?src=hash&amp;amp;ref_src=twsrc%5Etfw">#ノーコード&lt;/a>&lt;/p>&amp;mdash; freedomな人 (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1461620484471017474?ref_src=twsrc%5Etfw">November 19, 2021&lt;/a>&lt;/blockquote>
&lt;p>こんな感じでとにかく色々アクションして採用現場のタスクをこなして経験値を積んでいて、結果として良い人を採用できている。
アイデアだけ出して他の人にやってもらうケースもあったり色々迷惑かけていた面もあると思うw
ということで人事チームや採用業務やってきたメンバーには超感謝。&lt;/p>
&lt;blockquote class="twitter-tweet">&lt;p lang="ja" dir="ltr">ひょっとして採用が最強のエンジニアリングなのでは…？&lt;/p>&amp;mdash; freedomな人 (@tzm_freedom) &lt;a href="https://twitter.com/tzm_freedom/status/1431189576379338752?ref_src=twsrc%5Etfw">August 27, 2021&lt;/a>&lt;/blockquote>
&lt;h3 id="技術ブログとイベント登壇">技術ブログとイベント登壇&lt;/h3>
&lt;p>採用へのチャレンジの一貫で会社の技術ブログもたくさん書いた。
これまで個人ブログで400を超える技術記事を書いてきたが、会社の技術ブログに書いたのは実は初めて。
書いてこなかった理由も自分のキャリアのため（会社に帰属させたくない）という思いだったんだが、
自分のブログのPVは以前より気にしなくなったし、逆に会社に帰属させたほうがキャリア上メリットがありそうだったのと、
なにより今の自分の興味関心がプロダクトのグロースだったので、会社の技術ブログを書くことは今はかなり前向き。
結果として弊社の中で一番ブログ記事書いてるギネスな人間になっている。&lt;/p>
&lt;p>社内でも「どうやってネタ出ししているのか？」とか「どう時間を使って書いているのか？」と聞かれることも増えており、
継続して技術ブログを書いてきてネタを考えてきた人間の知見が役立っているのも楽しい感じ。&lt;/p>
&lt;p>アーキテクチャなどカジュアル面談で説明しやすいように、かつ社内向けに認識を合わせるために記事を書いたり。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tech.yappli.io/entry/yappli_multitenant">Yappliにおけるマルチテナントアーキテクチャと課題&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>またアウトプットがインプットを呼ぶ効果も感じていて、以下の記事は社内でも議論のネタになったりした。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tech.yappli.io/entry/go_i18n">Goで多言語化を実装してみた&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/statik2goembed">ファイルの埋め込みをstatikからgo:embedに置き換えた&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>社内wikiで社内共有する代わりに書いた記事もある。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tech.yappli.io/entry/grpcgateway_swagger">gRPC-GatewayのAPIドキュメントを自動生成する&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://tech.yappli.io/entry/husky_codereading">huskyの仕組みを調べてみた&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>また、PHP Conference 2021に登壇し、仕事の取り組みの内容を発表した。
以前から仕事の取り組みをテックカンファレンスで発表してみたかったのだが、ちょうど弊社でのPHPの改善が良い感じにまとめれそうな段階だったのでCfPを出して、無事採択された。
イベント登壇の時期が採用とプロジェクトが重なったりして大変だったときもあるけど乗り切れてよかった…！&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tech.yappli.io/entry/phpcon2021">PHP Conference Japan 2021でYappliの改善事例を紹介しました！&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>発表内容的に改善しました！的な内容なんだが実はまだ改善しきれていない部分など色々あるので今後も地道に改善していきたい。
あと、PHP Conferenceは以前から聴く側として参加していたテックカンファレンスだったので登壇者として参加できて嬉しかった。&lt;/p></description></item><item><title>phpenv/anyenvでPHPをインストールする方法〜2021〜</title><link>https://blog.freedom-man.com/php_install_2021.html</link><pubDate>Mon, 23 Aug 2021 10:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/php_install_2021.html</guid><description>&lt;p>phpenvまでのインストールはすんなりいくがPHPのインストールでコケがちなのでメモ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>brew install bison re2c libxml2 zlib libzip libjpeg bzip2 &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> curl libiconv libedit pkg-config krb5 tidy-html5 &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> libpng icu4c oniguruma autoconf
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>してから.bashrcや.zshrcに以下の記述を入れる&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix bison&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix libxml2&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix bzip2&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix curl&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix libiconv&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix krb5&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix openssl&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix icu4c&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix tidy-html5&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/bin:&lt;/span>&lt;span style="color:#953800">$PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix krb5&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib/pkgconfig:&lt;/span>&lt;span style="color:#953800">$PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix openssl&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib/pkgconfig:&lt;/span>&lt;span style="color:#953800">$PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix icu4c&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib/pkgconfig:&lt;/span>&lt;span style="color:#953800">$PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix jpeg&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib/pkgconfig:&lt;/span>&lt;span style="color:#953800">$PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix tidy-html5&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib/pkgconfig:&lt;/span>&lt;span style="color:#953800">$PKG_CONFIG_PATH&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PHP_RPATHS&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix zlib&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib &lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix bzip2&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib &lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix curl&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib &lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix libiconv&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib &lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix libedit&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">/lib&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">PHP_BUILD_CONFIGURE_OPTS&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;--with-zlib-dir=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix zlib&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069"> --with-bz2=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix bzip2&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069"> --with-curl=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix curl&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069"> --with-iconv=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix libiconv&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069"> --with-libedit=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix libedit&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069"> --with-tidy=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix tidy-html5&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069"> --with-external-pcre=&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>brew --prefix pcre2&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="参考記事">参考記事&lt;/h3>
&lt;ul>
&lt;li>&lt;a href="https://www.ritolab.com/entry/211">phpenv &amp;amp; php-build で macOS Catalina に複数バージョンの PHP 環境を構築する&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://qiita.com/hamakou108/items/4744818dd166191c3e6b">MacOS に anyenv + phpenv で PHP 7.4.1 をインストールする&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>mac新調してインストール・設定したものメモ</title><link>https://blog.freedom-man.com/mac_install.html</link><pubDate>Mon, 23 Aug 2021 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/mac_install.html</guid><description>&lt;p>6年ぶりくらいにmacを新調したのでインストール・設定したことメモ&lt;/p>
&lt;ul>
&lt;li>Google Chromeインストール&lt;/li>
&lt;li>LastPassの拡張をインストール&lt;/li>
&lt;li>Chromeで自分のGoogleアカウントにログインして同期&lt;/li>
&lt;li>以下、Chromeでダウンロードしてきてインストール
&lt;ul>
&lt;li>Google日本語入力&lt;/li>
&lt;li>iTerm
&lt;ul>
&lt;li>インストール後にショートカットキーを設定&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Notion&lt;/li>
&lt;li>MacVim&lt;/li>
&lt;li>Hammerspoon&lt;/li>
&lt;li>Go&lt;/li>
&lt;li>Slack&lt;/li>
&lt;li>VSCode
&lt;ul>
&lt;li>Salesforce Extension&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Jetbrains Toolbox
&lt;ul>
&lt;li>IntelliJ Ultimate
&lt;ul>
&lt;li>ideavim&lt;/li>
&lt;li>Ruby&lt;/li>
&lt;li>PHP&lt;/li>
&lt;li>Python&lt;/li>
&lt;li>Go&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Alfred&lt;/li>
&lt;li>Docker Desktop&lt;/li>
&lt;li>Clipy&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>ssh-keygenしてGitHubに登録&lt;/li>
&lt;li>iTerm立ち上げてコマンドでインストール
&lt;ul>
&lt;li>brew&lt;/li>
&lt;li>ghq&lt;/li>
&lt;li>dotfiles取ってきてよしなにインストール&lt;/li>
&lt;li>tmux
&lt;ul>
&lt;li>reattach-to-user-namespace&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>anyenv
&lt;ul>
&lt;li>Ruby&lt;/li>
&lt;li>PHP&lt;/li>
&lt;li>Python&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>prezto&lt;/li>
&lt;li>htop&lt;/li>
&lt;li>binutils&lt;/li>
&lt;li>coreutils&lt;/li>
&lt;li>tree&lt;/li>
&lt;li>tig&lt;/li>
&lt;li>wget&lt;/li>
&lt;li>hub&lt;/li>
&lt;li>jq&lt;/li>
&lt;li>mysql&lt;/li>
&lt;li>peco&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title>VueやVuexのデータを操作するChrome拡張の作り方</title><link>https://blog.freedom-man.com/vue_chrome_extension.html</link><pubDate>Thu, 29 Apr 2021 09:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/vue_chrome_extension.html</guid><description>&lt;p>Vueコンポーネントの属性値(propsやcomputedなど)やVuexのstoreを操作するChrome拡張の作り方の備忘録&lt;/p>
&lt;h2 id="概要">概要&lt;/h2>
&lt;ol>
&lt;li>ContentScriptで対象のページにスクリプトをインジェクト&lt;/li>
&lt;li>インジェクトしたスクリプトでVueインスタンスを取り出す&lt;/li>
&lt;li>取り出したVueインスタンスをCustomEvent経由でContentScriptに渡したり、ContentScript側からCustomEvent経由で操作する&lt;/li>
&lt;/ol>
&lt;h2 id="実装例">実装例&lt;/h2>
&lt;p>manifest.json&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-json" data-lang="json">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;manifest_version&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Store Sample&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;version&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;content_scripts&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;matches&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;https://*/*&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;main.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;css&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;run_at&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;document_end&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;web_accessible_resources&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;resources&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;inject.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;matches&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;https://*/*&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;#34;extension_ids&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>main.js&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">onload&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addEventListener&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;yourCustomEvent&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;received&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">JSON&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">detail&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">script&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createElement&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;script&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">script&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setAttribute&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;type&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;text/javascript&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">script&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setAttribute&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;src&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">chrome&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">runtime&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getURL&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;inject.js&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">head&lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">documentElement&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">appendChild&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">script&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">script&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">remove&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>inject.js&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">$vue&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getElementById&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;__nuxt&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">__vue__&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">dispatchEvent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">CustomEvent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;yourCustomEvent&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">detail&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">JSON&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">stringify&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">$vue&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">$store&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">state&lt;/span>&lt;span style="color:#1f2328">)}));&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="解説">解説&lt;/h2>
&lt;p>以下はNuxt/Vuexの例ですが、DOMの &lt;code>__vue__&lt;/code> プロパティでvueオブジェクトを取り出せます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">$vue&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getElementById&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;__nuxt&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">__vue__&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Vuexを使っている場合はこの中にstoreが入っていて &lt;code>$vue.$store.state&lt;/code> で取得できます。&lt;/p>
&lt;p>ContentScriptとページ側ではJSの実行環境が違うようで、ContentScript側ではこのオブジェクトを取得できないため
ページ側で取得するようにscriptタグを動的に埋め込んでいます。&lt;/p>
&lt;p>書き換え操作したい場合はインジェクトしたスクリプトで &lt;code>__vue__&lt;/code> の操作を行い
読み込み操作したい場合はCustomEvent経由でContentScript側に送って操作することになります。&lt;/p>
&lt;p>CustomEventを使う場合はオブジェクトそのままではContentScriptに送れなかったのでJSON文字列にして送ってます。&lt;/p>
&lt;p>書き換える場合はインジェクトしたJSでCustomEventをlistenしてContentScript側でイベントを送ることで任意のタイミングで書き換えることができます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addEventListener&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;ActionEvent&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">$vue&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">$store&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">state&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">about&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;hogehoge&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ちなみにVuexのstore以外も、コンポーネントのDOMに &lt;code>__vue__&lt;/code> プロパティが生えているので、それを使ってコンポーネントの属性を取得・操作ができます。&lt;/p></description></item><item><title>iOSシミュレータ・Androidエミュレータの現在位置を変更する</title><link>https://blog.freedom-man.com/simulator_location.html</link><pubDate>Thu, 15 Apr 2021 09:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/simulator_location.html</guid><description>&lt;p>各シミュレータ・エミュレータでの現在位置の設定方法の備忘録&lt;/p>
&lt;h2 id="ios">iOS&lt;/h2>
&lt;p>Features &amp;gt; Location &amp;gt; Custom Locationを選択&lt;/p>
&lt;img src="https://blog.freedom-man.com/img/2021/04/ios_simulator_location.jpg" width="400px"/>
&lt;p>表示されるダイアログで緯度経度をセット&lt;/p>
&lt;img src="https://blog.freedom-man.com/img/2021/04/ios_simulator_custom_location.jpg" width="400px"/>
&lt;h2 id="android">Android&lt;/h2>
&lt;p>一番下の設定からLocationを選択して地図上の適当なところを選択してから右下のSET LOCATIONボタンを押下&lt;/p>
&lt;img src="https://blog.freedom-man.com/img/2021/04/android_simulator_location.jpg" width="400px"/>
&lt;p>あるいはエミュレータ起動した状態でtelnetでエミュレータに接続してgeo fixコマンドを叩く&lt;/p>
&lt;pre tabindex="0">&lt;code>$ telnet localhost 5554

auth {auth_token}
geo fix {longitude} {latitude}
&lt;/code>&lt;/pre>&lt;p>接続してから表示されるメッセージにも書いてあるとおり、auth_tokenは &lt;code>/Users/$(whoami)/.emulator_console_auth_token&lt;/code> に入っているのでそれを使う&lt;/p></description></item><item><title>Litestream入門</title><link>https://blog.freedom-man.com/litestream.html</link><pubDate>Sun, 04 Apr 2021 09:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/litestream.html</guid><description>&lt;p>&lt;a href="https://litestream.io">Litestream&lt;/a> というSQLite3をレプリケーションするOSSを調べてみました&lt;/p>
&lt;h2 id="インストール">インストール&lt;/h2>
&lt;p>macだと以下でインストールできます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ brew install benbjohnson/litestream/litestream
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>レプリケーション先は同一ホストの任意のパスやAmazon S3を利用できます。
今回はS3と互換性のあるオブジェクトストレージの &lt;a href="https://min.io/">MinIO&lt;/a> を使って検証してみました。&lt;/p>
&lt;p>MinIOの起動&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ docker run -p 9000:9000 minio/minio server /data
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>起動後は http://localhost:9000 でクレデンシャルに &lt;code>minioadmin&lt;/code> を指定してログインし、適当なバケットを作成します。
今回は &lt;code>mybkt&lt;/code> というバケットを作成しています。&lt;/p>
&lt;p>Litestream起動前にsqlite3で適当なDBを作っておきます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sqlite3 test.db
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">CREATE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">TABLE&lt;/span>&lt;span style="color:#fff"> &lt;/span>hoge&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">int&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">primary&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">key&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">INSERT&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">INTO&lt;/span>&lt;span style="color:#fff"> &lt;/span>hoge&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">VALUES&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">),(&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Litestreamを起動します&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">AWS_ACCESS_KEY_ID&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>minioadmin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">AWS_SECRET_ACCESS_KEY&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>minioadmin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ litestream replicate test.db s3://mybkt.localhost:9000/test.db
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これでtest.dbに対する変更がS3にレプリケーションされ、リストアできるようになります。&lt;/p>
&lt;h3 id="設定ファイル">設定ファイル&lt;/h3>
&lt;p>コマンド引数で対象のSQLite3のDBファイルやレプリケーション先を指定できますが、設定ファイルを使うと複数DB・レプリケーション先を指定できます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">access-key-id&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>minioadmin&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#0550ae">secret-access-key&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>minioadmin&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#0550ae">dbs&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>- &lt;span style="color:#0550ae">path&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>/path/to/test1.db&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">replicas&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>- &lt;span style="color:#0550ae">url&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>s3://mybkt.localhost:9000/test1.db&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>- &lt;span style="color:#0550ae">path&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>/path/to/test2.db&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">replicas&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>- &lt;span style="color:#0550ae">path&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>/path/to/replica&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>- &lt;span style="color:#0550ae">name&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>test2-1&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">url&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>s3://mybkt.localhost:9000/test2-1.db&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>- &lt;span style="color:#0550ae">name&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>test2-2&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">url&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>s3://mybkt.localhost:9000/test2-2.db&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>nameは省略可能で、省略するとタイプの名前(&lt;code>s3&lt;/code>や&lt;code>file&lt;/code>)が適用されます。
nameは各DBに対してユニークにする必要があるので、レプリカ先に同じタイプを複数利用する場合はnameを指定する必要があります。&lt;/p></description></item><item><title>rqlite入門</title><link>https://blog.freedom-man.com/rqlite.html</link><pubDate>Sun, 04 Apr 2021 09:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/rqlite.html</guid><description>&lt;p>&lt;a href="https://github.com/rqlite/rqlite">rqlite&lt;/a> というバックエンドにSQLite3を使った分散DBについて調べてみました&lt;/p>
&lt;h2 id="インストール">インストール&lt;/h2>
&lt;p>macの場合こんな感じでインストールできます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ curl -L https://github.com/rqlite/rqlite/releases/download/v5.10.2/rqlite-v5.10.2-darwin-amd64.tar.gz -o rqlite-v5.10.2-darwin-amd64.tar.gz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ tar xvfz rqlite-v5.10.2-darwin-amd64.tar.gz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> rqlite-v5.10.2-darwin-amd64
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cp rqlite /usr/local/bin/rqlite
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cp rqlited /usr/local/bin/rqlited
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cp rqbench /usr/local/bin/rqbench
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>各ノードのサービスの立ち上げはrqlitedでできます。&lt;br>
今回はシングルホストでクラスタリングを検証するため、↓をそれぞれ別シェルで実行します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ rqlited -node-id &lt;span style="color:#0550ae">1&lt;/span> ./node.1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ rqlited -node-id &lt;span style="color:#0550ae">2&lt;/span> -http-addr localhost:4003 -raft-addr localhost:4004 -join http://localhost:4001 ./node.2
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ rqlited -node-id &lt;span style="color:#0550ae">3&lt;/span> -http-addr localhost:4005 -raft-addr localhost:4006 -join http://localhost:4001 ./node.3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>↑の場合はリーダーノードは &lt;code>1&lt;/code> のノードになります。&lt;/p>
&lt;p>データ操作するにはHTTP APIを使うことになりますが、CLIのクライアント &lt;code>rqlite&lt;/code> も用意されています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ rqlite
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; CREATE TABLE hoge &lt;span style="color:#0550ae">(&lt;/span>id int primary key&lt;span style="color:#0550ae">)&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; INSERT INTO hoge VALUES &lt;span style="color:#0550ae">(&lt;/span>1&lt;span style="color:#0550ae">)&lt;/span>,&lt;span style="color:#0550ae">(&lt;/span>2&lt;span style="color:#0550ae">)&lt;/span>,&lt;span style="color:#0550ae">(&lt;/span>3&lt;span style="color:#0550ae">)&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;gt; SELECT * from hoge&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+----+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">|&lt;/span> id &lt;span style="color:#1f2328">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+----+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">|&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#1f2328">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+----+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">|&lt;/span> &lt;span style="color:#0550ae">2&lt;/span> &lt;span style="color:#1f2328">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+----+
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">|&lt;/span> &lt;span style="color:#0550ae">3&lt;/span> &lt;span style="color:#1f2328">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>+----+
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>リーダーノードはrqliteのコマンド &lt;code>.status&lt;/code> かStatus APIで確認可能です&lt;/p></description></item><item><title>Diagram Maker動かしてみた</title><link>https://blog.freedom-man.com/diagram-maker.html</link><pubDate>Sat, 27 Feb 2021 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/diagram-maker.html</guid><description>&lt;p>DiagramMakerを動かしてみたので備忘録。&lt;br>
すぐ動くサンプル無さそうだったので…&lt;/p>
&lt;p>サンプルはここに置いてます
&lt;a href="https://github.com/tzmfreedom/javascript-sample/tree/master/diagram-maker-sample">https://github.com/tzmfreedom/javascript-sample/tree/master/diagram-maker-sample&lt;/a>&lt;/p>
&lt;h2 id="インストール">インストール&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ npm install diagram-maker
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>TypeScriptじゃなくても動くようですが公式のサンプルがTypeScriptだったり、ちゃんとstyleあてないといけないといけなかったりするので
webpackや各種loaderも併せて一式インストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ npm install @types/node &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> style-loader &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> css-loader &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> sass &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> sass-loader &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> typescript &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> ts-loader &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> dagre &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> redux &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> webpack &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> webpack-cli
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="ざっと使い方">ざっと使い方&lt;/h2>
&lt;p>セレクタを指定して要素に対してDiagramMakerをアタッチするような使い方になるので、HTMLにそれ用の要素を用意します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&amp;lt;!DOCTYPE html&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">meta&lt;/span> &lt;span style="color:#1f2328">charset&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;UTF-8&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">title&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>DiagramMaker Test Environment&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">title&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">div&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;diagramMakerContainer&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">div&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;diagramMakerLogger&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;./bundle.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>JSはこんな感じで書く。第一引数はマウントするセレクタ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-TypeScript" data-lang="TypeScript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">DiagramMaker&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#0a3069">&amp;#39;diagram-maker&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">config&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">initData&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">diagramMaker&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">DiagramMaker&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;diagramMakerContainer&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">config&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// optionParams
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">initialData&lt;/span>: &lt;span style="color:#cf222e">initData&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>configの例&lt;/p></description></item><item><title>SQLite3の備忘録</title><link>https://blog.freedom-man.com/sqlite3.html</link><pubDate>Sat, 27 Feb 2021 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/sqlite3.html</guid><description>&lt;p>&lt;a href="https://www.sqlite.org/index.html">SQLite3&lt;/a> の備忘録&lt;/p>
&lt;h2 id="手軽に独自関数を定義できる">手軽に独自関数を定義できる&lt;/h2>
&lt;p>組み込みなので独自関数をプラグインとして事前ビルドすることなくアプリケーション内で定義して利用できる。&lt;br>
以下、PHPでやる例↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$db&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">\PDO&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;sqlite::memory:&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$db&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setAttribute&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">\PDO&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">ATTR_ERRMODE&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">\PDO&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">ERRMODE_EXCEPTION&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// ユーザー定義関数 regexp を登録
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#953800">$db&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">sqliteCreateFunction&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;hello&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#39;world&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$stmt&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$db&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">query&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;SELECT hello();&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">var_dump&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$stmt&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">fetchAll&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SQLite3にはLIKEのような比較演算子としてREGEXPが使えるのだが、これを利用するには事前にユーザ側でregexp()の独自関数を定義する必要がある。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$db&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">\PDO&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;sqlite::memory:&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$db&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setAttribute&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">\PDO&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">ATTR_ERRMODE&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">\PDO&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">ERRMODE_EXCEPTION&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$db&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">sqliteCreateFunction&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;regexp&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$pattern&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">mb_regex_encoding&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;UTF-8&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">false&lt;/span> &lt;span style="color:#0550ae">!==&lt;/span> &lt;span style="color:#1f2328">mb_ereg&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$pattern&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$stmt&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$db&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">query&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SELECT &amp;#39;world&amp;#39; REGEXP &amp;#39;^worl.*&amp;#39;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">var_dump&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$stmt&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">fetchAll&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="moderoでもflockされる">mode=roでもflockされる&lt;/h2>
&lt;p>Goで以下のURI filenamesでシステムコールを見てみると…
&lt;code>file:example.sqlite?mode=ro&amp;amp;nolock=0&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo dtruss ./main 2&amp;gt;&lt;span style="color:#1f2328">&amp;amp;&lt;/span>&lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#1f2328">|&lt;/span> grep fcntl
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x0, 0x3, 0x0&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">2&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x1, 0x3, 0x0&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x2, 0x3, 0x0&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl_nocancel&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x32, 0x7FFEEFBFEAE0&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x7, 0x7FFEEFBFDDA0&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFE858&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFE858&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFE858&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFE340&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFEE58&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFEE58&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFEE58&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fcntl&lt;span style="color:#0550ae">(&lt;/span>0x3, 0x8, 0x7FFEEFBFEE60&lt;span style="color:#0550ae">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>nolock &lt;code>file:example.sqlite?mode=ro&amp;amp;nolock=1&lt;/code> の場合&lt;/p></description></item><item><title>2021</title><link>https://blog.freedom-man.com/2021.html</link><pubDate>Fri, 01 Jan 2021 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2021.html</guid><description/></item><item><title>2020年の振り返り</title><link>https://blog.freedom-man.com/2020-summary.html</link><pubDate>Wed, 30 Dec 2020 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/2020-summary.html</guid><description>&lt;h2 id="仕事関連">仕事関連&lt;/h2>
&lt;h3 id="転職">転職&lt;/h3>
&lt;p>今年の２月に某ノーコードスマホアプリ開発プラットフォームな会社に転職。&lt;/p>
&lt;p>転職理由としてはこんな感じ↓&lt;/p>
&lt;ul>
&lt;li>ライフステージ的にも仕事的にも一区切りついた感があった&lt;/li>
&lt;li>前職でやりたかったこと（自社サービスの開発・保守の経験を積むことと、それによってエンジニアリング力を高めたいという思い）はある程度達成できた感覚があった&lt;/li>
&lt;li>エンジニアリング力に関しては良い評価をもらうことが増えてきて貢献度合いとしても最後の一年で納得感を得られた&lt;/li>
&lt;li>改めて自分のやりたい仕事を突き詰めて技術力も仕事力も高めていきたいなという思い&lt;/li>
&lt;li>カジュアル面談で良い会社と出会えたこと&lt;/li>
&lt;/ul>
&lt;p>ノーコード・ローコードなSalesforceを主軸としたシステム開発をやっていた１社目の経験と&lt;br>
チーム開発やエンジニアリング力を磨くことができた２社目の経験と&lt;br>
アプリ開発自体にハードルを感じていた自身の思いとプロダクトの面白さ、成長性&lt;br>
このあたりが決め手になった感じ。&lt;br>
そういうわけで今回の転職はこの１社しか受けていない。&lt;/p>
&lt;p>前職に大きな不満があるわけではなく、労働環境・福利厚生も良かったし&lt;br>
中堅としてこれから引っ張っていく立場な中で辞めるのは心苦しい感じでもあったのだけど&lt;br>
いつ人生が終わるかわからんし、タイミングとしても今を逃したくないという思いが強かった。&lt;/p>
&lt;p>結果として、転職して一年近く経った今でもプロダクトやチームに大きな魅力を感じていて&lt;br>
営業や導入・運用サポートも含めてプロダクトをもっと良くしていきたい気持ちがあり&lt;br>
結果論としても良い転職になったなぁと思う。&lt;/p>
&lt;h3 id="今年やった仕事">今年やった仕事&lt;/h3>
&lt;ul>
&lt;li>要望・改善・不具合系チケットの大量消化&lt;/li>
&lt;li>新機能プロジェクトのフロント・サーバーサイド担当&lt;/li>
&lt;li>レガシーPHPアプリケーション改善（E2Eテスト・単体テスト・静的解析導入・リファクタリング）&lt;/li>
&lt;li>Go/gRPCアプリケーションの結合テスト追加・CI調整&lt;/li>
&lt;li>暗黙知の形式知化（コンフルと社内勉強会での共有）&lt;/li>
&lt;li>オオカミ少年アラート対応（ログレベルの精査・Sentryの設定調整・リトライ/タイムアウト値などの実装調整）&lt;/li>
&lt;/ul>
&lt;p>チケット数としては100個ほど。PRだと400くらい。&lt;br>
気づいたら改善系の年間リリース数がトップだったり、GitHubのInsightsで見ても主要リポジトリのAdditionで２位〜４位くらいのコントリビューションになってた。&lt;br>
新機能開発や改修、障害対応を通じてドメイン知識や既存アーキテクチャを理解しつつ&lt;br>
暗黙知になっているドメイン知識を形式知化したり&lt;br>
テストコード自体を増やしたり結合テストが書けるようにしてデグレを事前に検知可能にしたり（というかテスト書く過程で既存の不具合を発見したり）&lt;br>
ログレベルを精査して大事なエラーアラートを見逃さないようにしたり&lt;br>
短期的に効く機能改善・追加も進めつつ、こういった中長期的に効く施策もガンガンやっていった。&lt;br>
Salesforceの実装相談を受けたり、汎用的に使えそうなRedashのクエリ作って共有したり、会社全体のスループットを上げるような仕事もできた。&lt;br>
結果として自動テスト・PHP・簡易的なデータ分析・その他ドメイン知識などなど &lt;br>
エンジニアチームの中で &lt;code>詳しい人&lt;/code> として動けているし頼られることも増えてきた。&lt;/p>
&lt;p>技術要素としては、Go/gRPC/TypeScript/Nuxt/Vue/PHP/Laravelあたりを中心に。&lt;br>
PHP以外は業務で扱うのは初めてだったんだけど業務に差し支えないレベルで会得できた感触がある。&lt;br>
手元でiOS/Androidシミュレータを動かしながら動作確認するのもだいぶ慣れてきた。&lt;/p>
&lt;p>来年はもう少し技術を深堀りしつつ、さらにドメイン知識を習得して良い感じに回していければ良いかなと。&lt;br>
視座も上げつつ課題に対する賢い解決方法をより提案・実行できれば良いなぁ。&lt;/p>
&lt;h3 id="副業">副業&lt;/h3>
&lt;p>今年は副業にチャレンジしてみた。&lt;/p>
&lt;p>今のところSalesforceに関する技術的な相談を受けたりサンプル作ったり実装したり、という仕事を請け負っている。&lt;/p>
&lt;p>モチベーションとしては小遣い稼ぎ的な資金面もあるが、
その会社の課題に対して自分の能力（Salesforceのノーコード〜プロコードの知識と一般的なWebエンジニアリング）が活かせそうだなと思ったのもある。&lt;/p>
&lt;p>Salesforce以外の副業もやりたい気持ちはあるのだが、実際に手を動かす系になるとあんまりワークしなさそうな感覚がありトライできていない。
レガシー改善に興味があるんだが、そういう仕事はドメイン知識が必要だったり、信頼貯金やスピード感的にもフルコミットじゃないと厳しい感じがしている。&lt;br>
いずれにせよ、チャレンジした結果、こんな感じで継続してできそうなボリューム感や請け負えそうな仕事内容がわかったのは収穫だった。&lt;/p>
&lt;p>ということで副業自体はもう少し色々試してみたいと思っているので&lt;br>
興味が有る方はお声をかけていただけると嬉しいかも。&lt;/p>
&lt;h2 id="ブログoss登壇">ブログ/OSS/登壇&lt;/h2>
&lt;p>今年はブログ記事を全然書かなかった。登壇もPHPerKaigiだけ。OSSコントリビューションもほぼ無し。&lt;br>
というか今年は意識的にこれらをやらないようにした。&lt;br>
業務時間外に勉強する時間を極力減らして、技術は極力業務時間内で学ぶようにアプローチを変えてみた。&lt;br>
キャッチアップのための勉強やスマホアプリ開発のHelloWorldをやったときもあったのだけど&lt;br>
例年と比べるとプライベートで技術系の本はあんまり読んでないしコードも書いていない。&lt;/p>
&lt;p>仕事の中で成長する要素というのはまだまだ有るので、今のところこのアプローチでうまくいっていると感じている。&lt;br>
仕事で使わない技術はすぐ忘れるので、LazyLoadなアプローチで勉強するのが自分には合っていそうだなとも思う。&lt;/p>
&lt;p>逆に仕事でどうやればもっとうまくできるのか、っていうのはプライベートでも考えてしまうようになっていて&lt;br>
これは良いのか悪いのかは全くわからない。&lt;br>
もう少し仕事のモチベーションをコントロールできるとバランスが取れてメンタル的にも良いのかもしれない。&lt;/p>
&lt;p>また、正直なところ、技術に対する飽きみたいなのがちょっと来ているのもある。&lt;br>
今のところそれによる危機感みたいなのは無いんだけど、「あれ、これが35歳なんちゃら説ってやつなのかな」とも思ったり。&lt;br>
実装スピードもそんなに衰えている感じがしないし、課題に対する視座も年々少しずつ高くなっていて&lt;br>
仕事のエンジニアリング力に関してはあまり心配していないのだが、技術に対するトキメキ・ワクワクが減ったなぁと。&lt;br>
あと何の技術にせよ見返りみたいなのを変に意識するようになってしまっている。&lt;br>
具体的には仕事で利用できそうかどうかで判断してしまっていて、それが原因でつまらなくなっていそうな感じもする。&lt;/p></description></item><item><title>ApexからGoogle APIを叩くときのサンプル</title><link>https://blog.freedom-man.com/google_api_apex.html</link><pubDate>Mon, 19 Oct 2020 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/google_api_apex.html</guid><description>&lt;p>ApexからGoogle Drive API, SpreadSheet APIを叩くAPIクライアントのサンプル書いてみたので備忘録。&lt;/p>
&lt;p>サンプルはこちら
&lt;a href="https://github.com/tzmfreedom/apex_google_api">https://github.com/tzmfreedom/apex_google_api&lt;/a>&lt;/p>
&lt;h2 id="事前準備">事前準備&lt;/h2>
&lt;ul>
&lt;li>GoogleのAPIを設定
&lt;ul>
&lt;li>Developer ConsoleからGoogle Drive API, SpreadSheet APIを有効化&lt;/li>
&lt;li>OAuth2.0クライアントIDを作成&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>認証プロバイダを作成
&lt;ul>
&lt;li>クライアントID／シークレットはGoogle Developer Consoleで取得したものを利用&lt;/li>
&lt;li>承認エンドポイントAPI =&amp;gt; &lt;code>https://accounts.google.com/o/oauth2/auth?access_type=offline&amp;amp;approval_prompt=force&lt;/code>
&lt;ul>
&lt;li>access_typeとapproval_promptを入れないとrefresh token取得できないので注意
（初回であればapproval_promptを入れなくても良いが２回目以降の認可をする場合は必要）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>トークンエンドポイントAPI =&amp;gt; &lt;code>https://oauth2.googleapis.com/token&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>named credential（指定ログイン情報）の作成
&lt;ul>
&lt;li>↑の認証プロバイダを指定&lt;/li>
&lt;li>スコープ =&amp;gt; &lt;code>https://www.googleapis.com/auth/drive openid email&lt;/code>&lt;/li>
&lt;li>Drive APIのURLは &lt;code>https://www.googleapis.com&lt;/code>&lt;/li>
&lt;li>SpreadSheet APIのURLは &lt;code>https://sheets.googleapis.com&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>参考: &lt;a href="https://qiita.com/sikj/items/1b0f51d3f9f119dc322c">https://qiita.com/sikj/items/1b0f51d3f9f119dc322c&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="サンプルのapiクライアントの使い方">サンプルのAPIクライアントの使い方&lt;/h2>
&lt;h3 id="drive-api">Drive API&lt;/h3>
&lt;p>フォルダの作成&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-apex" data-lang="apex">GoogleDriveAPIClient client = new GoogleDriveAPIClient();
GoogleDriveCreateResponse response = client.createFolder(&amp;#39;FolderName&amp;#39;, &amp;#39;ParentID&amp;#39;);
&lt;/code>&lt;/pre>&lt;p>ファイルのコピー&lt;/p>
&lt;pre tabindex="0">&lt;code>GoogleDriveCreateResponse response = client.copyFile(&amp;#39;SourceID&amp;#39;, &amp;#39;DestFileName&amp;#39;, &amp;#39;ParentID&amp;#39;);
&lt;/code>&lt;/pre>&lt;h3 id="spreadsheet-api">SpreadSheet API&lt;/h3>
&lt;p>スプレッドシートの値を更新&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-apex" data-lang="apex">SpreadSheetAPIClient client = new SpreadSheetAPIClient();
List&amp;lt;SpreadSheetUpdateValue&amp;gt; values = new List&amp;lt;SpreadSheetUpdateValue&amp;gt;();
values.add(new SpreadSheetUpdateValue(&amp;#39;シート1!A1:D5&amp;#39;, new List&amp;lt;List&amp;lt;Object&amp;gt;&amp;gt;{
 new List&amp;lt;Object&amp;gt;{
 1,
 2,
 3,
 4
 },
 new List&amp;lt;Object&amp;gt;{
 11,
 22,
 33,
 44
 }
}));
client.updateValues(&amp;#39;xxx&amp;#39;, values);
&lt;/code>&lt;/pre>&lt;h2 id="その他">その他&lt;/h2>
&lt;ul>
&lt;li>スプレッドシートの更新のAPIは３種類ある
&lt;ul>
&lt;li>参考: &lt;a href="https://qiita.com/howdy39/items/c28c0328038d9c43f389#%E3%81%9D%E3%81%AE%EF%BC%93-spreadsheetsvaluesbatchupdate">https://qiita.com/howdy39/items/c28c0328038d9c43f389#%E3%81%9D%E3%81%AE%EF%BC%93-spreadsheetsvaluesbatchupdate&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title>PHPのE2EテストでHTTPリクエストをモックする方法</title><link>https://blog.freedom-man.com/e2e_php_httpmock.html</link><pubDate>Thu, 17 Sep 2020 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/e2e_php_httpmock.html</guid><description>&lt;h2 id="背景">背景&lt;/h2>
&lt;p>自動テストの文脈でアプリケーションが外部に対してHTTPリクエスト行う場合&lt;br>
一般的には以下のパターンで行うことが多いと思います。&lt;/p>
&lt;ul>
&lt;li>DIやDIコンテナの仕組みでアプリケーション的にHTTPクライアントをモック&lt;/li>
&lt;li>実際のDB、コードを使うアプリケーションサーバをたてる&lt;/li>
&lt;li>仮のレスポンスを返すテスト用のモックサーバをたてる&lt;/li>
&lt;/ul>
&lt;p>ユニットテストの場合はアプリケーション的にHTTPクライアントをモックすることが多いと思いますが、
リモートホストに対してテストを行うE2Eテストだとアプリケーションサーバやモックサーバを立てる手法を取ることが多いと思います。&lt;/p>
&lt;p>しかしながら、実際のアプリケーションサーバやテスト用のモックサーバを立てるのはやや面倒ですし&lt;br>
実用的にはテストを行うホストから適切にHTTPレスポンスをコントロールできるような調整も必要です。&lt;/p>
&lt;p>そこで今回は &lt;a href="https://github.com/php-vcr/php-vcr">php-vcr&lt;/a> とauto_prepend_fileを使って
E2Eテスト時の外部HTTPリクエストをモックする方法を紹介します。&lt;/p>
&lt;h2 id="方法">方法&lt;/h2>
&lt;p>以下のようなPHPスクリプトを作成して、auto_prepend_fileに指定すれば&lt;br>
テスト側からphp-vcrのcassetteをコントロールしつつ外部HTTPリクエストをモックできます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">MockHandler&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$cassetteName&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// After turning on the VCR will intercept all requests
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">\VCR\VCR&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">turnOn&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// Record requests and responses in cassette file &amp;#39;example&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">\VCR\VCR&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">insertCassette&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$cassetteName&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__destruct&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// To stop recording requests, eject the cassette
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">\VCR\VCR&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">eject&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// Turn off VCR to stop intercepting requests
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">\VCR\VCR&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">turnOff&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$cassetteName&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$_SERVER&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;HTTP_X_VCR_CASSETTE&amp;#39;&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$_mockHandler&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">MockHandler&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$cassetteName&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>テストのHTTPリクエストのヘッダに &lt;code>X-VCR-CASSETTE&lt;/code> を指定すればカセットをコントロールできるようになっています。&lt;br>
リモートホスト側にカセットファイルを置く必要はありますが、リクエストごとにカセットを指定することでHTTPレスポンスをコントロールできます。&lt;/p></description></item><item><title>リモートホストで動くPHPアプリケーションに対するE2Eテストでカバレッジを測定する方法</title><link>https://blog.freedom-man.com/e2e_coverage.html</link><pubDate>Tue, 15 Sep 2020 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/e2e_coverage.html</guid><description>&lt;p>リモートホストで動くPHPアプリに対してE2Eテストをしたときのカバレッジを計測する方法を紹介します。&lt;/p>
&lt;p>なお、こちらの記事を参考にしています（というかほぼ同じです）&lt;/p>
&lt;p>&lt;a href="https://tarunlalwani.com/post/php-code-coverage-web-selenium/">PHP Code Coverage for your web/selenium automation · Tech Adventures by Tarun Lalwani&lt;/a>&lt;/p>
&lt;p>原理としてはリモートホスト上のスクリプトが実行する前に &lt;code>xdebug_start_code_coverage()&lt;/code> などのカバレッジ計測の関数を呼び出し
スクリプトが終了する前に &lt;code>xdebug_stop_code_coverage()&lt;/code> &lt;code>xdebug_get_code_coverage()&lt;/code> を呼び出してカバレッジを別ファイルに保存。
保存されたカバレッジファイルを集計してカバレッジのHTMLファイルを吐き出します。&lt;/p>
&lt;h3 id="1-スクリプトが実行する前にxdebug_start_code_coverageを呼び出す">1. スクリプトが実行する前にxdebug_start_code_coverageを呼び出す&lt;/h3>
&lt;p>PHPにはauto_prepend_fileという事前に呼び出すスクリプトを指定する仕組みがあります。&lt;/p>
&lt;p>具体的にはphp.iniやapache/nginxの設定ファイルに以下のような記述をすることで&lt;br>
指定したファイルがrequireされた状態でリクエストされたPHPファイルが呼び出されることになります。&lt;/p>
&lt;p>php.ini&lt;/p>
&lt;pre tabindex="0">&lt;code>auto_prepend_file=/path/to/start.php
&lt;/code>&lt;/pre>&lt;p>apache&lt;/p>
&lt;pre tabindex="0">&lt;code>php_value auto_prepend_file &amp;#34;/path/to/start.php&amp;#34;
&lt;/code>&lt;/pre>&lt;p>nginx&lt;/p>
&lt;pre tabindex="0">&lt;code>fastcgi_param PHP_VALUE &amp;#34;auto_prepend_file=\&amp;#34;/path/to/start.php\&amp;#34;&amp;#34;;
&lt;/code>&lt;/pre>&lt;p>事前に呼び出すスクリプトファイルはこちらです。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">xdebug_start_code_coverage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">XDEBUG_CC_UNUSED&lt;/span> &lt;span style="color:#0550ae">|&lt;/span> &lt;span style="color:#1f2328">XDEBUG_CC_DEAD_CODE&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">CoverageDumper&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$testName&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$testName&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">testName&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$testName&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__destruct&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$coverageName&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;/path/to/coverage/coverage-&amp;#39;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">testName&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#39;-&amp;#39;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">microtime&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">xdebug_stop_code_coverage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$codecoverageData&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">json_encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">xdebug_get_code_coverage&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">file_put_contents&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$coverageName&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#39;.json&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$codecoverageData&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Exception&lt;/span> &lt;span style="color:#953800">$ex&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">file_put_contents&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$coverageName&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#39;.ex&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$ex&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$testName&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$_COOKIE&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;test_name&amp;#39;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#cf222e">empty&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$_COOKIE&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;test_name&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]))&lt;/span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$_COOKIE&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;test_name&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;unknown_test_&amp;#39;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">time&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$_coverageDumper&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">CoverageDumper&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$testName&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>コード計測にはxdebugを使うのでリモートホスト先で有効化する必要があります。
最初に &lt;code>xdebug_start_code_coverage()&lt;/code> でカバレッジ計測を開始し
CoverageDumperのデストラクタに &lt;code>xdebug_stop_code_coverage()&lt;/code> &lt;code>xdebug_get_code_coverage()&lt;/code> を仕込むことで
呼び出し先のスクリプトが終了したときにカバレッジを書き出してくれるようになります。&lt;/p></description></item><item><title>goでvimのようなTUIテキストエディタを作ってみた</title><link>https://blog.freedom-man.com/myvim.html</link><pubDate>Sun, 22 Mar 2020 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/myvim.html</guid><description>&lt;p>goでvimのようなエディタを作ってみました&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/myvim">tzmfreedom/myvim&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="インストール">インストール&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go get github.com/tzmfreedom/myvim
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ myvim /path/to/file
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="実装方法">実装方法&lt;/h2>
&lt;p>基本的には&lt;/p>
&lt;ul>
&lt;li>描画&lt;/li>
&lt;li>キー入力
の繰り返しです。&lt;/li>
&lt;/ul>
&lt;p>描画はエスケープシーケンスで座標0:0にしたり画面クリアしたりしてます。&lt;/p>
&lt;p>キー入力によってコマンドモードと入力モードを切り替えたりコマンドを解釈してます。
キーイベントは&lt;a href="https://github.com/nsf/termbox-go">termbox&lt;/a>でハンドリングしてます。&lt;/p></description></item><item><title>text/templateを使って良い感じにファイルジェネレートできるprotocプラグインを作った</title><link>https://blog.freedom-man.com/protoc-template.html</link><pubDate>Sun, 22 Mar 2020 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/protoc-template.html</guid><description>&lt;p>Goのtext/templateのリテラルで記述されたテンプレートファイルを使って、protofileからファイルを出力するprotocプラグインを作ってみましたー。&lt;br>
protobufで自動生成されるファイル郡以外にも自動でコードジェネレートしたいというのがモチベーション。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/protoc-gen-template">protoc-gen-template&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>protocのプラグインの作り方はこちらを参考にしました&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://qiita.com/yugui/items/87d00d77dee159e74886">protocプラグインの書き方 - Qiita&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="インストール方法">インストール方法&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go get github.com/tzmfreedom/ptoroc-gen-template
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>protocで&amp;ndash;template_outを指定すればOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ protoc -I. --template_out&lt;span style="color:#0550ae">=&lt;/span>/path/to/template:. target.proto
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>テンプレートファイルはこんな感じでtext/templateで書きます&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-gotemplate" data-lang="gotemplate">type {{ .Prefix }}{{ .Name }} struct {
 {{ range .Fields -}}
 {{ getName .Name }} {{ propertyType . $.PackageName }}
{{ end -}}
}
&lt;/code>&lt;/pre>&lt;p>これにこんな感じなprotoを食わせると&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;proto3&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#24292e">helloworld&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#57606a">// The request message containing the user&amp;#39;s name.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#1f2328">HelloRequest&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#57606a">// The response message containing the greetings
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#1f2328">HelloReply&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> &lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こういうファイルが出力されます&lt;/p></description></item><item><title>protocのApexプラグインを作った</title><link>https://blog.freedom-man.com/protoc-apex.html</link><pubDate>Sat, 21 Mar 2020 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/protoc-apex.html</guid><description>&lt;p>protobufの勉強がてらprotocのApexのプラグインを作ってみました&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/protoc-gen-apex">protoc-gen-apex&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="インストール方法">インストール方法&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go get github.com/tzmfreedom/protoc-gen-apex
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>メッセージだけ作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ protoc -I. --apex_out&lt;span style="color:#0550ae">=&lt;/span>. target.proto
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>サービスクライアントも作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ protoc -I. &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -I&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#953800">GOPATH&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>/src &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -I&lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#953800">GOPATH&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> --apex_out&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#953800">host&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>example.com/hoge:. hello.proto
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>サービスクライアントを作成するときはgrpc-gatewayを使う前提のコードになっているので
こんな感じでprotoファイルを記述します&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;proto3&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#0a3069">&amp;#34;google/api/annotations.proto&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#24292e">helloworld&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#57606a">// The greeting service definition.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">service&lt;/span> Greeter &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#57606a">// Sends a greeting
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">rpc&lt;/span> SayHello &lt;span style="color:#1f2328">(&lt;/span>HelloRequest&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">returns&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>HelloReply&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">option&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>google.api.http&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> post&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/v1/say_hello&amp;#34;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> body&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;*&amp;#34;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="例">例&lt;/h2>
&lt;p>protoファイル&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-proto" data-lang="proto">&lt;span style="display:flex;">&lt;span>syntax &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;proto3&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#24292e">helloworld&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#0a3069">&amp;#34;google/api/annotations.proto&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#57606a">// The greeting service definition.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">service&lt;/span> Greeter &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#57606a">// Sends a greeting
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">rpc&lt;/span> SayHello &lt;span style="color:#1f2328">(&lt;/span>HelloRequest&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">returns&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>HelloReply&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">option&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>google.api.http&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> post&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/v1/say_hello&amp;#34;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> body&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;*&amp;#34;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">rpc&lt;/span> GetTask&lt;span style="color:#1f2328">(&lt;/span>HelloRequest&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">returns&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>HelloReply&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">option&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>google.api.http&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> get&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/v1/get_task&amp;#34;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#57606a">// The request message containing the user&amp;#39;s name.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#1f2328">HelloRequest&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">int32&lt;/span> a &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">int64&lt;/span> b &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> Hoge c &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">4&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">repeated&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> d &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#1f2328">Hoge&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#57606a">// The response message containing the greetings
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#1f2328">HelloReply&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span> &lt;span style="color:#cf222e">string&lt;/span> &lt;span style="color:#cf222e">message&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>出力ファイル&lt;/p></description></item><item><title>2020</title><link>https://blog.freedom-man.com/2020.html</link><pubDate>Wed, 01 Jan 2020 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2020.html</guid><description/></item><item><title>2019年の振り返り</title><link>https://blog.freedom-man.com/2019-summary.html</link><pubDate>Tue, 31 Dec 2019 09:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/2019-summary.html</guid><description>&lt;p>恒例？の年末振り返り&lt;/p>
&lt;h2 id="仕事">仕事&lt;/h2>
&lt;p>あんまり外で仕事の話をしないのでたまにはｗ&lt;br>
プライベートでSalesforce関連のアクティビティが多くて、たまに仕事の心配されるんだけどそうじゃないんですよって言いたいｗ&lt;/p>
&lt;p>現職に来てから昨年までの約２年くらいはRuby/Railsのサービス開発に携わっていたんだけど、今年はPHPのサービスをメインでやっていた一年でした。
PHPは前職で簡単なフォームやバッチ処理を作る程度の経験だったので、がっつりWebサービス開発業やって色々と勉強になったし、今のPHPはエコシステム的にも言語仕様的にもかなり良くなってきているなと感じました。
特に型付けに関しては他のLLには無い表現力があったり静的解析ツールのPHPStanやIDEが優秀だったり、書きやすくかつ堅牢な言語になっているなと実感しました。&lt;/p>
&lt;p>具体的な仕事としては&lt;/p>
&lt;ul>
&lt;li>サービスのSymfonyのバージョンを2.4 =&amp;gt; 3.4 =&amp;gt; 4.2にアップグレード&lt;/li>
&lt;li>15年以上続く独自フレームワークな老舗Webアプリ（600万ユーザ、〜70万行）のPHPのバージョンを5.6 =&amp;gt; 7.1にした&lt;/li>
&lt;li>それにあわせて依存パッケージを最新にアップグレードしたり、精査して別のパッケージに切り替えた&lt;/li>
&lt;li>定期アップグレードする仕組みを作った&lt;/li>
&lt;li>PHPStan導入したりdeclare(strict_types=1)した&lt;/li>
&lt;li>Opcache使って不要っぽいファイルの当たりを付けてガンガン削除していった&lt;/li>
&lt;li>インフラレベルでのちょっとした改善&lt;/li>
&lt;/ul>
&lt;p>と、まぁいわゆるTHE改善業でした。&lt;br>
ちなみにどのWebサービスも &lt;code>はじめまして&lt;/code> 状態からスタートしてそれなりのスピード感で改善できていたので、キャッチアップ力も我ながら良かったと思います。
そういや俺、１年以上携わってるサービス無いな…ｗ&lt;/p>
&lt;p>インフラ周りだとCloudFormationに初めて触ったんですが、PRで差分確認できたりChangeSet適用ポチっとするだけで適用できるのは良いな〜とIaCの良さを実感。&lt;/p>
&lt;p>あと、色々と改善業してみてわかったのが「テストがないコードはレガシー」というのはマジだな、ということ。&lt;/p>
&lt;p>逆にここだけちゃんとやっていればリファクタリングしてなんとか挽回できたり仕様の把握もテストコードレベルで確認できたりするけど
それが無いと、よりアンタッチャブルで経年劣化していくものなんだなぁというのも思いました。
LLなので削除漏れも検知できず結果として大量の不要ファイルが溢れたり。
静的解析や静的型付け言語・型推論あたりはトレンドだし意味があると思うけど、テストコードを書く（書けるようにする）ことが一番品質を上げやすいと思います。&lt;/p>
&lt;p>あとDBの負債はいろんなところに伝搬するし変更しづらいので、DBの設計は注意しないといけないなと思いました。
ロールバックもしづらいし…&lt;/p>
&lt;p>ちなみに大量の不要ファイルの削除は&lt;a href="https://blog.freedom-man.com/opcache_unused_files">Opcache法&lt;/a>でやったんだけど本当に簡単で便利な方法なので、不要ファイルを検知したい場合は是非ご活用ください。&lt;/p>
&lt;h2 id="oss">OSS&lt;/h2>
&lt;p>Contributionは880くらいでした〜。意外と例年より多かったｗ&lt;/p>
&lt;p>が、PR/issueは全然出さず…未マージのものも含めるとこんな感じっす&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/zendframework/zend-mail/pull/227">When set -f option, no set -f option automatically by tzmfreedom · Pull Request #227 · zendframework/zend-mail&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/nelmio/alice/pull/970">fix document on expression language by tzmfreedom · Pull Request #970 · nelmio/alice&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/KnpLabs/KnpPaginatorBundle/pull/532">Added Japanese translation by tzmfreedom · Pull Request #532 · KnpLabs/KnpPaginatorBundle&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/KnpLabs/php-github-api/pull/777">Update httplug and related packages version by tzmfreedom · Pull Request #777 · KnpLabs/php-github-api&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>全部PHP…ｗ アップグレードしていくときに困ったところでPRを上げていったという感じ。&lt;/p></description></item><item><title>Salesforceのオブジェクト定義から文字列を出力できるジェネレータを作った</title><link>https://blog.freedom-man.com/sf-metadata-converter.html</link><pubDate>Mon, 23 Dec 2019 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/sf-metadata-converter.html</guid><description>&lt;p>Salesforceのオブジェクト定義を使って文字列を出力できるジェネレータを作ってみましたー&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.npmjs.com/package/sf-metadata-converter">sf-metadata-converter&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>モチベーションとしては、VF + JSRemoting + Frontのフレームワークな構成を試していたんだけど
SObjectの定義を使ってJSやApexのファイルを作成する必要があったので若干面倒だったというやーつ&lt;/p>
&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>インストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ npm install -g sf-metadata-converter
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ID/PWDは環境変数で指定して叩くと、テンプレートにSObjectの定義をパラメータとしてバインドした文字列が標準出力に出力されます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">SALESFORCE_USERNAME&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">export&lt;/span> &lt;span style="color:#953800">SALESFORCE_PASSWORD&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>xxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sfmconv -T &lt;span style="color:#0550ae">{&lt;/span>SObject Name&lt;span style="color:#0550ae">}&lt;/span> -t &lt;span style="color:#0550ae">{&lt;/span>template file&lt;span style="color:#0550ae">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>template fileはEJSでこんな感じで書きます&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-ejs" data-lang="ejs">class &amp;lt;%= name %&amp;gt; {
 constructor() {
 this.params = [&amp;lt;%- fields.map(f =&amp;gt; `&amp;#39;${f.name}&amp;#39;`).join(&amp;#39;,&amp;#39;); %&amp;gt;];
 }
}
&lt;/code>&lt;/pre>&lt;p>ビルトインのテンプレートも持っていて、&lt;code>js&lt;/code> &lt;code>typescript&lt;/code> &lt;code>apex&lt;/code> を指定するとそれっぽいのが表示されます&lt;/p>
&lt;p>テンプレートにはURLの指定もOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sfmconv -T Account -t &lt;span style="color:#0a3069">&amp;#34;https://httpbin.org/get?q=%3C%=%20name%20%%3E&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>バインドしているパラメータはjsforceでmetadata describeしたときのレスポンスが入ります&lt;/p>
&lt;p>Apexのテストデータ作成とかSObjectのTypeScriptの型定義やJSのクラス生成とかに役立つのではないかと思いまっす&lt;/p></description></item><item><title>Opcacheによる不要ファイルの検知</title><link>https://blog.freedom-man.com/opcache_unused_files.html</link><pubDate>Mon, 09 Dec 2019 16:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/opcache_unused_files.html</guid><description>&lt;p>PHPのOpcacheの関数を使うと参照されていないコード（不要ファイル）を確認することができます。&lt;/p>
&lt;p>例えばこんな感じなファイルを作ってアクセスするとOpcacheに載っているファイル一覧を取得できます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">header&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Content-Type: text/csv&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;CACHEPREFIX&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">function_exists&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;opcache_reset&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">?&lt;/span>&lt;span style="color:#0a3069">&amp;#39;opcache_&amp;#39;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">function_exists&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;accelerator_reset&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">?&lt;/span>&lt;span style="color:#0a3069">&amp;#39;accelerator_&amp;#39;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$status&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">call_user_func&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">CACHEPREFIX&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#0a3069">&amp;#39;get_status&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$status&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;scripts&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$data&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$data&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;full_path&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">\t&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#953800">$data&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;hits&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>出力されたファイル一覧と実ファイル一覧を付け合わせることで、参照されていないコードを確認できます。&lt;/p>
&lt;p>SAPIごとに管理されているようで、CLIとWeb（mod_phpとか）は別のOpcacheが使われているのでWebで参照されているかどうかを見る場合には
CLIではなくWebからアクセスしてPHPを実行させる必要があるっぽいです。&lt;/p>
&lt;p>また、設定値によってOpcacheに載ってくる条件も多少変わってくるので注意です。
例えばファイルベースのOpcacheが有効でない場合は再起動後はキャッシュがクリアされていたり、max_accelerated_filesが少ないと載らないファイルも出てくると思います。&lt;/p></description></item><item><title>SOQLのdatabase/sqlドライバーを作った</title><link>https://blog.freedom-man.com/go-soql-driver.html</link><pubDate>Mon, 09 Dec 2019 16:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/go-soql-driver.html</guid><description>&lt;p>database/sqlのsqlドライバーを使ってSalesforceのSOQLを動かしてみましたー&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/go-soql-driver">tzmfreedom/go-soql-driver&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>ということで使い方とdatabase/sqlのドライバーの作り方を備忘として残しておきます。&lt;/p>
&lt;h2 id="使い方">使い方&lt;/h2>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go get github.com/tzmfreedom/go-soql-driver
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>して、以下のようにして使います&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#1f2328">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;database/sql&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;net/url&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;os&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">soqlDriver&lt;/span> &lt;span style="color:#0a3069">&amp;#34;github.com/tzmfreedom/go-soql-driver&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">main&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">username&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">os&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Getenv&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_USERNAME&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">password&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">os&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Getenv&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_PASSWORD&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">dsn&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">soqlDriver&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">CreateDsn&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">QueryEscape&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">username&lt;/span>&lt;span style="color:#1f2328">),&lt;/span> &lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">QueryEscape&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">password&lt;/span>&lt;span style="color:#1f2328">),&lt;/span> &lt;span style="color:#0a3069">&amp;#34;login.salesforce.com&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">sql&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Open&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;soql&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">dsn&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">rows&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Query&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SELECT Id, Name FROM Account&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">rows&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Next&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">name&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">rows&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Scan&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">&amp;amp;&lt;/span>&lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>&lt;span style="color:#1f2328">name&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">name&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">insert&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">db&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">sql&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">DB&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Exec&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;INSERT INTO Account(Name) VALUES (&amp;#39;Created By sql driver&amp;#39;)&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">RowsAffected&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">update&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">db&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">sql&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">DB&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Exec&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;UPDATE Account SET Name = &amp;#39;Updated By sql driver&amp;#39; WHERE Name = &amp;#39;Created By sql driver&amp;#39;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">RowsAffected&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">delete&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">db&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">sql&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">DB&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">db&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Exec&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;DELETE FROM Account WHERE Name = &amp;#39;Updated By sql driver&amp;#39;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">r&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">RowsAffected&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SOQLにはINSERT, UPDATE, DELETE構文はありませんが、よしなに変換してDMLを発行しています。&lt;/p></description></item><item><title>GoからRubyのDSLを読み込む方法</title><link>https://blog.freedom-man.com/go-mruby-dsl.html</link><pubDate>Mon, 09 Dec 2019 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/go-mruby-dsl.html</guid><description>&lt;p>この記事は&lt;a href="https://qiita.com/advent-calendar/2019/go5">Go5 Advent Calendar 2019&lt;/a>の9日目の記事です。&lt;/p>
&lt;hr>
&lt;p>RubyのDSLは表現力が高く書きやすいのですが、Ruby以外の言語からDSLを読み出すには何かしらのRubyのランタイムが必要です。&lt;/p>
&lt;p>そこで今回は、Go言語でmrubyを使ってRubyのDSLを読み込む方法を紹介します。&lt;/p>
&lt;h2 id="mitchellhgo-mrubyのインストール">mitchellh/go-mrubyのインストール&lt;/h2>
&lt;p>&lt;a href="https://github.com/mitchellh/go-mruby">mitchellh/go-mruby&lt;/a>は&lt;code>go get&lt;/code>でインストールできないので、リポジトリを取ってきて事前にmakeしておく必要があります。
ghqだとこんな感じ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ghq get mitchellh/go-mruby
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> &lt;span style="color:#0a3069">${&lt;/span>&lt;span style="color:#953800">GOPATH&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>/src/github.com/mitchellh/go-mruby
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ make
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>depを使う場合は&lt;code>dep ensure&lt;/code>した後、vendor配下でmakeすればOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> vendor/github.com/mitchellh/go-mruby
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ make
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="go-mrubyでrubyファイルの実行">go-mrubyでRubyファイルの実行&lt;/h2>
&lt;p>以下のようにして、GoでRubyのファイルを実行することができます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-go" data-lang="go">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#1f2328">main&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;errors&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;github.com/mitchellh/go-mruby&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#0a3069">&amp;#34;io/ioutil&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">func&lt;/span> &lt;span style="color:#6639ba">main&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">username&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">value&lt;/span> &lt;span style="color:#cf222e">string&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">isInConfig&lt;/span> &lt;span style="color:#cf222e">bool&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">rubyErr&lt;/span> &lt;span style="color:#cf222e">error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">mrb&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">NewMrb&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">defer&lt;/span> &lt;span style="color:#1f2328">mrb&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Close&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">kernel&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">mrb&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">KernelModule&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">kernel&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">DefineMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;username&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">func&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Mrb&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">self&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">MrbValue&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">username&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">GetArgs&lt;/span>&lt;span style="color:#1f2328">()[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">].&lt;/span>&lt;span style="color:#6639ba">String&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">ArgsReq&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">kernel&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">DefineMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;config&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">func&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Mrb&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">self&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">MrbValue&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">args&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">GetArgs&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">isInConfig&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">mrb&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Yield&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">args&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">isInConfig&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">ArgsReq&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">kernel&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">DefineMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;set&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">func&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">m&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Mrb&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">self&lt;/span> &lt;span style="color:#0550ae">*&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">MrbValue&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">args&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">m&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">GetArgs&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">!&lt;/span>&lt;span style="color:#1f2328">isInConfig&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#1f2328">rubyErr&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">errors&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">New&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;set should be called in config&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>			&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#1f2328">value&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">args&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">].&lt;/span>&lt;span style="color:#6639ba">String&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#1f2328">mruby&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">ArgsReq&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">b&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">:=&lt;/span> &lt;span style="color:#1f2328">ioutil&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">ReadFile&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;./config&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">_&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">mrb&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">LoadString&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">string&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">b&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">err&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Error&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">rubyErr&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>		&lt;span style="color:#6639ba">panic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">rubyErr&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Error&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">username&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>	&lt;span style="color:#1f2328">fmt&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">Println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上の例だと以下のようなRubyのDSLを読み込めます&lt;/p></description></item><item><title>SalesforceのOS `salesfOS` を作った</title><link>https://blog.freedom-man.com/salesfos.html</link><pubDate>Thu, 05 Dec 2019 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/salesfos.html</guid><description>&lt;p>この記事は &lt;a href="https://qiita.com/advent-calendar/2019/salesforce-platform">Salesforce Platform Advent Calendar 2019 - Qiita&lt;/a> 第5日目の投稿です。&lt;/p>
&lt;hr>
&lt;p>ネタです。ご査収ください。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://tzmfreedom.github.io/salesfOS">salesfOS&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>※最初に左下のアプリバーのボタンでログインしてね&lt;/p>
&lt;p>リポジトリ: &lt;a href="https://github.com/tzmfreedom/salesfOS">tzmfreedom/salesfOS&lt;/a>&lt;/p>
&lt;h2 id="利用技術あれこれ">利用技術あれこれ&lt;/h2>
&lt;ul>
&lt;li>ふつーの静的webサイト&lt;/li>
&lt;li>jsforce + jsforce-ajax-proxy on Heroku&lt;/li>
&lt;li>&lt;a href="https://qiita.com/riversun/items/1adffa5674bc5123b16d">JSFrame.js&lt;/a>でそれっぽいウィンドウを生成&lt;/li>
&lt;li>onmousedown, onmousemove, onmouseupでいい感じにアイコンのドラッグアンドドロップを実現&lt;/li>
&lt;/ul>
&lt;h2 id="使い方">使い方&lt;/h2>
&lt;ul>
&lt;li>左下のアプリバーのボタンを押すと認証・認可画面に遷移する。ここで認可しないとAPIっぽい機能は使えない&lt;/li>
&lt;li>適当にアイコンをダブルクリックしたりドラッグ＆ドロップしたりゴミ箱に放り込んでください&lt;/li>
&lt;/ul>
&lt;h2 id="今後の展望">今後の展望&lt;/h2>
&lt;ul>
&lt;li>もう少しOS感出す
&lt;ul>
&lt;li>ファイルエクスプローラー&lt;/li>
&lt;li>ユーティリティを充実させる&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>機能も充実させる
&lt;ul>
&lt;li>デプロイ&lt;/li>
&lt;li>Apexコード書けたら面白そう&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>jQuery卒業してReact使う（突貫で作ったので…&lt;/li>
&lt;li>そういやウィンドウの最大化・最小化実装するの忘れてた&lt;/li>
&lt;/ul>
&lt;h2 id="雑記">雑記&lt;/h2>
&lt;ul>
&lt;li>去年のアドカレで全力でモノづくりしすぎたせいか、ネタが尽きていた&lt;/li>
&lt;li>去年の私の記事、CLIネタが多かったしLANDも含めて結構地味だった&lt;/li>
&lt;li>adminにもわかりやすさを出すために画面が良いよね感&lt;/li>
&lt;li>OSもどき楽しそう&lt;/li>
&lt;li>でも、この着想に至るまでに&lt;a href="https://github.com/tzmfreedom/sfync">sfync&lt;/a>というRuby DSLでオブジェクトデプロイできるツールを中途半端に開発してたんだよね…&lt;/li>
&lt;/ul>
&lt;p>いずれ本当のOSも自作してみたいなぁと思いつつ、今回のWebで作るOSもどきもめっちゃ面白かったので引き続き続けたい気持ち&lt;/p></description></item><item><title>PHPでPHPを実装する</title><link>https://blog.freedom-man.com/phphp.html</link><pubDate>Tue, 03 Dec 2019 09:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/phphp.html</guid><description>&lt;p>この記事は&lt;a href="https://qiita.com/advent-calendar/2019/php">PHP Advent Calendar 2019&lt;/a>の3日目の記事です。&lt;/p>
&lt;hr>
&lt;p>言語実装入門編として、PHPでPHPを実装してみました。&lt;/p>
&lt;ul>
&lt;li>AST生成は&lt;a href="https://github.com/nikic/PHP-Parser">PHP-Parser&lt;/a>に一任&lt;/li>
&lt;li>バイトコードやバイナリ生成などはせず、Tree Walkなインタープリターとして実装&lt;/li>
&lt;/ul>
&lt;p>という感じで作っていきます。&lt;/p>
&lt;p>実装したものはこちら↓&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/phphp">tzmfreedom/phphp&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>&lt;code>composer global require tzmfreedom/phphp&lt;/code> でもインストールできます&lt;/p>
&lt;h2 id="helloworld">HelloWorld&lt;/h2>
&lt;p>まずは &lt;code>composer require nikic/php-parser&lt;/code> してPHP-Parserを追加します。&lt;/p>
&lt;p>基本形はこんな感じになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">require_once&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vendor/autoload.php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PhpParser\ParserFactory&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PhpParser\Parser&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">PhpParser\NodeDumper&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">PHPInterpreter&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @var Parser
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$parser&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">Parser&lt;/span> &lt;span style="color:#953800">$parser&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">parser&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$parser&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">run&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">string&lt;/span> &lt;span style="color:#953800">$code&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$ast&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">parser&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">parse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$code&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// $dumper = new NodeDumper;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#57606a">// echo $dumper-&amp;gt;dump($ast);
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ast&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$stmt&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">evaluate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$stmt&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">evaluate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$node&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">switch&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">get_class&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$node&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// ...
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$code&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">file_get_contents&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$argv&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$parser&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">ParserFactory&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">ParserFactory&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">PREFER_PHP7&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$interpreter&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">PHPInterpreter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$parser&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$interpreter&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">run&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$code&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ParserFactoryでパーサを生成して&lt;code>Parser#parse&lt;/code>を呼び出すとPHPの文字列からASTを生成してくれます。
ASTはStatementの配列になっているので &lt;code>evaluate&lt;/code> で順に処理していってます。&lt;/p></description></item><item><title>RustのSalesforce APIクライアント `rustforce` をリリースしました</title><link>https://blog.freedom-man.com/rustforce.html</link><pubDate>Sun, 06 Oct 2019 22:30:00 +0900</pubDate><guid>https://blog.freedom-man.com/rustforce.html</guid><description>&lt;p>RustのSalesforce REST APIクライアントのrustforceをリリースしました&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://crates.io/crates/rustforce">rustforce - crates.io: Rust Package Registry&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/tzmfreedom/rustforce">tzmfreedom/rustforce&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>クエリ例はこんな感じで&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-rust" data-lang="rust">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span>&lt;span style="color:#fff"> &lt;/span>rustforce::Client&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">use&lt;/span>&lt;span style="color:#fff"> &lt;/span>rustforce::response::&lt;span style="color:#1f2328">{&lt;/span>QueryResponse&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>ErrorResponse&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">use&lt;/span>&lt;span style="color:#fff"> &lt;/span>serde::Deserialize&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">use&lt;/span>&lt;span style="color:#fff"> &lt;/span>std::env&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">#[derive(Deserialize, Debug)]&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">#[serde(rename_all = &lt;/span>&lt;span style="color:#0a3069">&amp;#34;PascalCase&amp;#34;&lt;/span>&lt;span style="color:#57606a">)]&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">struct&lt;/span> &lt;span style="color:#1f2328">Account&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">#[serde(rename = &lt;/span>&lt;span style="color:#0a3069">&amp;#34;attributes&amp;#34;&lt;/span>&lt;span style="color:#57606a">)]&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>attributes: &lt;span style="color:#1f2328">Attribute&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>id: &lt;span style="color:#6639ba">String&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>name: &lt;span style="color:#6639ba">String&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">#[derive(Deserialize, Debug)]&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">struct&lt;/span> &lt;span style="color:#1f2328">Attribute&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>url: &lt;span style="color:#6639ba">String&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">#[serde(rename = &lt;/span>&lt;span style="color:#0a3069">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#57606a">)]&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>sobject_type: &lt;span style="color:#6639ba">String&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">fn&lt;/span> &lt;span style="color:#6639ba">main&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">let&lt;/span>&lt;span style="color:#fff"> &lt;/span>client_id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>env::var&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_CLIENT_ID&amp;#34;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>unwrap&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">let&lt;/span>&lt;span style="color:#fff"> &lt;/span>client_secret&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>env::var&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_CLIENT_SECRET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>unwrap&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">let&lt;/span>&lt;span style="color:#fff"> &lt;/span>username&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>env::var&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_USERNAME&amp;#34;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>unwrap&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">let&lt;/span>&lt;span style="color:#fff"> &lt;/span>password&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>env::var&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_PASSWORD&amp;#34;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>unwrap&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">let&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">mut&lt;/span>&lt;span style="color:#fff"> &lt;/span>client&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Client::new&lt;span style="color:#1f2328">(&lt;/span>client_id&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>client_secret&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>client&lt;span style="color:#1f2328">.&lt;/span>login_with_credential&lt;span style="color:#1f2328">(&lt;/span>username&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>password&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">let&lt;/span>&lt;span style="color:#fff"> &lt;/span>res: &lt;span style="color:#6639ba">Result&lt;/span>&lt;span style="color:#0550ae">&amp;lt;&lt;/span>QueryResponse&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Account&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">Vec&lt;/span>&lt;span style="color:#0550ae">&amp;lt;&lt;/span>ErrorResponse&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>client&lt;span style="color:#1f2328">.&lt;/span>query&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SELECT Id, Name FROM Account&amp;#34;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>to_string&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">println!&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">{:?}&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>QueryResponseのシリアライズの関係でライブラリ利用側もserdeのパッケージを使うようになってます。
いまのところログイン方式がResource Owner Password Grant（SalesforceではUsername Password Flowって言われてるやつ）しか対応していないです。&lt;br>
Authorization Code Grantあたりも実装予定。&lt;/p></description></item><item><title>Salesforce World Tour Tokyo 2019のDeveloper Theaterで登壇しました</title><link>https://blog.freedom-man.com/swtt-2019.html</link><pubDate>Thu, 03 Oct 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/swtt-2019.html</guid><description>&lt;p>&lt;a href="https://www.salesforce.com/jp/events/worldtour/ja/overview/">Salesforce World Tour Tokyo 2019&lt;/a> のDeveloper Theaterで &lt;code>Salesforceのツールの作り方&lt;/code> というタイトルで登壇してきましたー。&lt;/p>
&lt;p>資料はこちら&lt;/p>
&lt;script async class="speakerdeck-embed" data-id="6abdf0aa9dcb4eb5b8240044b2a01105" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js">&lt;/script>
&lt;p>実は &lt;code>別の言語でApexを動かすアプローチ&lt;/code> というのもCFP出してたんですがそちらは通らなかったという裏話もありますｗ&lt;/p>
&lt;h2 id="モチベーション">モチベーション&lt;/h2>
&lt;ul>
&lt;li>これまで作成してきたSalesforce関連ツールの数はコミュニティの中でも結構上位だと思い、これは私にしか出来無さそうなテーマだと思った&lt;/li>
&lt;li>Salesforceは知名度のわりに3rd partyのツールが少ないのでもっとツールを作る人が増えればよいと思った
&lt;ul>
&lt;li>もちろんSaaSだから、とか公式ツールがそれなりに充実してるからってのもあるけど、それにしても少ない印象&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>何の取り柄もないエンジニアがツールを作成する過程でプログラミングを楽しんだり技術力を伸ばせたので、そこらへんを共有するのは面白いと思った&lt;/li>
&lt;/ul>
&lt;h2 id="内容">内容&lt;/h2>
&lt;p>&lt;code>Salesforceのツールの作り方&lt;/code> というよりは &lt;code>ツール作っていこうぜ！&lt;/code> なエモい内容。&lt;/p>
&lt;p>この辺を話したかった↓&lt;/p>
&lt;ul>
&lt;li>目の前の課題に向き合うこと&lt;/li>
&lt;li>当たり前を疑ってアイデアを具現化していくこと&lt;/li>
&lt;li>プログラミングを楽しむこと&lt;/li>
&lt;/ul>
&lt;p>ってか過去の自分に伝えたかったことって感じかな。&lt;/p>
&lt;h2 id="思ったこと">思ったこと&lt;/h2>
&lt;p>登壇や資料整理の過程で、「あー俺はこういう観点でSalesforceのツールを作っていたのだなー」ってのが改めて整理できた。&lt;/p>
&lt;p>前職でSalesforceを使ったSIをやってたんだけど、現職ではSalesforceを全く触っていないし、今後もSalesforceをメインの軸としてエンジニアリングしていく予定・希望は無い。&lt;/p>
&lt;p>ただ、前職のときよりも今の方がプライベートで作っているSalesforceのツールの数は多くて、傍から見たら「Salesforce好きなんでしょ？」みたいに思われていて、それはちょっと違うなと毎回否定していたりするｗ&lt;/p>
&lt;p>じゃあなんで私がSalesforceのツールを作成しているのかっていうと、&lt;code>SalesforceのAPIが充実していて、データストアもあって、何か技術を試すためのBaaSとしては最適だから&lt;/code> というのが答えなのかな、と思った
（補足: プロダクトの立ち位置的にはSaaS/PaaSだけど私の用途としてはBaaSなのです）&lt;/p>
&lt;p>例えば新しいフロントエンドのフレームワークを試したいとき、大体の人がTODOアプリを作っていると思うけど、
そのTODOアプリが私にとってはSalesforce関連ツールだったりする。
SalesforceはAPIがかなり充実しているので、何も考えなくてもサーバが用意されているしAPIも用意されている。OIDCやOAuth2.0も完備されているのでユーザ認証を含めたフローの実装もできるし、firebaseのようにカスタムなAPIも実装できる。&lt;/p>
&lt;p>そういう意味で私にとって新しい技術を試すためのバックエンドサービスがSalesforceになっている。&lt;/p>
&lt;p>今回発表した内容で &lt;code>作りながら学ぶ、学ぶために作る&lt;/code> ということを話したんだけど、わりとそのモチベーションで作っているっていうのが現状で、どうせ作るなら面白いツール・自分のモチベーションが上がるツールを作りたいよね、ということで &lt;a href="https://github.com/tzmfreedom/land">Apex on Local&lt;/a> や &lt;a href="https://github.com/tzmfreedom/alt-apex">AltApex&lt;/a> にチャレンジしたという経緯がある。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/skillup-with-salesforce">Salesforceで技術は学べるのか&lt;/a> という記事を2年前くらいに書いたけど、日常的にSalesforceに触っていない今でもSalesforceは自分の技術力を上げるきっかけを作ってくれている。&lt;/p></description></item><item><title>streamWrapperを使ってphp://inputをモックする</title><link>https://blog.freedom-man.com/phpinput_streamwrapper.html</link><pubDate>Sun, 29 Sep 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/phpinput_streamwrapper.html</guid><description>&lt;p>PHPでrequestBodyがapplication/www-xxx以外のリクエスト（JSONとかXML）を処理する場合、
&lt;code>php://input&lt;/code> からデータを取得することになります。&lt;/p>
&lt;p>昨今のフレームワークであればリクエストに関するデータらはRequestオブジェクトなどに隠蔽されており、functional tests等でモックできるため
&lt;code>php://input&lt;/code> を意識することはほとんど無いと思います。&lt;/p>
&lt;p>ただ、フレームワークを使わない場合は &lt;code>php://input&lt;/code> を直接ハンドリングする必要があるのですが、その場合functional testsでは &lt;code>php://input&lt;/code> のモックをする必要があります。&lt;/p>
&lt;p>ということで今回は &lt;code>php://input&lt;/code> をstreamWrapperでモックしてphpunitでテストする方法について紹介します。&lt;/p>
&lt;hr>
&lt;p>以下のようなstreamWrapperなクラスを作ります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">PHPStreamWrapper&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$position&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param string $content
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">setContent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#953800">$content&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_open&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$path&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_read&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$count&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$ret&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">substr&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">position&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$count&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#1f2328">strlen&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ret&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$ret&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_stat&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_eof&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> &lt;span style="color:#1f2328">strlen&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>setContentはモックする文字列をセットする関数で、それ以外は&lt;code>php://input&lt;/code>からの読み込みで使う関数になります。
基本的にはsetContentでセットした文字列をstream_readで返していくだけ。&lt;/p>
&lt;p>あとはsetUpでstream_wrapper_registerして、tearDownでstream_wrapper_restoreして元のストリーム処理に戻せばOK。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">HogeTest&lt;/span> &lt;span style="color:#cf222e">extends&lt;/span> &lt;span style="color:#1f2328">PHPUnit\Framework\TestCase&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">setUp&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream_wrapper_unregister&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream_wrapper_register&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">PHPStreamWrapper&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">tearDown&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream_wrapper_restore&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">xxx&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">PHPStreamWrapper&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">setContent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;mock string&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// 何かテスト
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>仮想DOMを使ったなんちゃってReact/Reduxなフレームワークを作ってみた</title><link>https://blog.freedom-man.com/my-react-redux-jsx.html</link><pubDate>Sun, 29 Sep 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/my-react-redux-jsx.html</guid><description>&lt;p>React/Reduxの仕組みを知るために仮想DOMを使ったなんちゃってフレームワークを作ってみました。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/myvirtualdom">tzmfreedom/myvirtualdom&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>今回はその備忘録。&lt;/p>
&lt;p>Reactに関しては&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://kuroeveryday.blogspot.com/2018/11/how-to-create-virtual-dom-framework.html">自作フレームワークをつくって学ぶ 仮想DOM実践入門 | Black Everyday Company&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Reduxに関しては&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://qiita.com/miyarappo/items/30fff8d23704e92211b7">【React.js】createStoreを実装してみたらReduxの理解が捗った - Qiita&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>の記事を参考にしました。&lt;/p>
&lt;p>完成するとこんな感じで書けるようになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">App&lt;/span> &lt;span style="color:#cf222e">extends&lt;/span> &lt;span style="color:#1f2328">Base&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onMounted&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">state&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;hoge&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;fuga&amp;#39;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fetch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;https://httpbin.org/get&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">((&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">=&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setState&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">statusText&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">manager&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">scheduleRender&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onChangeText&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setState&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">target&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">dispatch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">changeMessage&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">target&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onClickButton&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">state&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">state&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setState&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">state&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">`&amp;lt;div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;if c=&amp;#34;this.state.text.length === 0&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;p&amp;gt;blank&amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;/if&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;if c=&amp;#34;this.state.text.length !== 0&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;p&amp;gt;{this.state.text}&amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;/if&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;ul&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;for records=&amp;#34;{this.state.records}&amp;#34; var=&amp;#34;record&amp;#34;&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;li&amp;gt;{variables.record}&amp;lt;/li&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;/for&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;/ul&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;p&amp;gt;{this.getStoreState().message + &amp;#39;!!&amp;#39;}&amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;input type=&amp;#34;text&amp;#34; value=&amp;#34;{this.state.text}&amp;#34; oninput=&amp;#34;{this.onChangeText.bind(this)}&amp;#34;/&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;input type=&amp;#34;button&amp;#34; value=&amp;#34;Add&amp;#34; onclick=&amp;#34;{this.onClickButton.bind(this)}&amp;#34;/&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;lt;Foo text=&amp;#34;{this.state.text}&amp;#34;/&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/div&amp;gt;`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Foo&lt;/span> &lt;span style="color:#cf222e">extends&lt;/span> &lt;span style="color:#1f2328">Base&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">`&amp;lt;div&amp;gt;{this.props.text}&amp;lt;/div&amp;gt;`&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#1f2328">manager&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">AppManager&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;#app&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">App&lt;/span>&lt;span style="color:#1f2328">({},&lt;/span> &lt;span style="color:#1f2328">{}));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">manager&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="なんちゃってreact">なんちゃってReact&lt;/h2>
&lt;p>最初のレンダリング時にはセレクタをコンポーネントのクラスを指定し、AppManagerはコンポーネントクラスを使ってDOMを構築してセレクタの要素に対して &lt;code>appendChild&lt;/code> します。&lt;/p></description></item><item><title>streamWrapperを使ってPHPの任意の関数をモックする</title><link>https://blog.freedom-man.com/php-mock-streamwrapper.html</link><pubDate>Wed, 12 Jun 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/php-mock-streamwrapper.html</guid><description>&lt;p>PHPでは&lt;a href="https://www.php.net/manual/ja/class.streamwrapper.php">streamWrapper&lt;/a>を使って特定のプロトコルに対するファイル入出力をフックすることができます。&lt;/p>
&lt;p>これを使ってcurl関数をモックしたものが&lt;a href="https://github.com/php-vcr/php-vcr">php-vcr&lt;/a>で技術的な詳細は以下の記事に書いてあります。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://kunit.jp/archives/108">PHP-VCR が curl 関数を乗っ取る方法 | NEW GAME @kunit&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="任意の関数をモックしてみる">任意の関数をモックしてみる&lt;/h2>
&lt;p>今回はこのstreamWrapperを使ってmail関数をモックしてみようと思います。&lt;/p>
&lt;p>streamWrapperは特定の関数を持つクラスになります。インターフェースをimplementsとかではなくダックタイプ的な感じで関数を定義していきます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">MailMockStreamWrapper&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$position&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">register&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream_wrapper_unregister&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream_wrapper_register&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">__CLASS__&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_open&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$path&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream_wrapper_restore&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$content&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">file_get_contents&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$path&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">content&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">str_replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;mail&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;MailMock::mail&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">register&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_read&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$count&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$ret&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">substr&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">content&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">position&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$count&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#1f2328">strlen&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ret&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$ret&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_stat&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">stream_eof&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">position&lt;/span> &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> &lt;span style="color:#1f2328">strlen&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">content&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>stream_open&lt;/code>でファイルをすべて読みこんで&lt;code>stream_read&lt;/code>で文字列の変数から中身を取り出す、という感じにしています。
（一般的にはopenではファイルをオープンするだけでreadのタイミングで読み込むのが良いと思います）&lt;/p>
&lt;p>ファイルを読み込む直前で&lt;code>stream_wrapper_restore&lt;/code>しておかないと&lt;code>file_get_contents&lt;/code>で再度stream_openが呼ばれ、無限再帰するため最初にrestoreで止めておく必要があります。&lt;/p>
&lt;p>あとはモックするクラス・メソッドを適当に定義してstream_wrapper_unregister, registerします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">MailMock&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">mail&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$to&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$subject&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;#34;to =&amp;gt; &lt;/span>&lt;span style="color:#0a3069">$to&lt;/span>&lt;span style="color:#0a3069">, subject =&amp;gt; &lt;/span>&lt;span style="color:#0a3069">$subject&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">stream_wrapper_unregister&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">stream_wrapper_register&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;MailMockStreamWrapper&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>この状態で適当なコードをrequireすると、requireしたファイルのmail関数が&lt;code>MailMock::mail&lt;/code>に置換されて実行されます。&lt;/p></description></item><item><title>Pimpleコードリーディング</title><link>https://blog.freedom-man.com/pimple-codereading.html</link><pubDate>Tue, 11 Jun 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/pimple-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/silexphp/Pimple">Pimple&lt;/a>のコードリーディングをしました。バージョンは3.2.3です。&lt;/p>
&lt;p>このケースで追ってみます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">require_once&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vendor/autoload.php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">use&lt;/span> &lt;span style="color:#1f2328">Pimple\Container&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$container&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Container&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$container&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;session&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$c&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Session&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">var_dump&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$container&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;session&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span> &lt;span style="color:#57606a">// eval
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#953800">$container&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;session&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$container&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">factory&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$c&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Session&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="コードリーディング">コードリーディング&lt;/h2>
&lt;p>Containerクラス内ではいくつかのインスタンス変数が管理されています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Container&lt;/span> &lt;span style="color:#cf222e">implements&lt;/span> &lt;span style="color:#1f2328">\ArrayAccess&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$values&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$factories&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$protected&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$frozen&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$raw&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$keys&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#953800">$values&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">factories&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">\SplObjectStorage&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">protected&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">\SplObjectStorage&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$values&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$key&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">offsetSet&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>\ArrayAccessをimplementsしてあるのでこれによって添字アクセスなどが可能になっています。&lt;/p>
&lt;p>&lt;code>#offsetSet&lt;/code>では&lt;code>values&lt;/code>や&lt;code>keys&lt;/code>に値をセットしています。keysの値はtrueがセットされJavaでいうSetのような感じで扱われています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">offsetSet&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">frozen&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">FrozenServiceException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$value&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">keys&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>#offsetGet&lt;/code>は以下のように定義されています。初回呼び出し時でClosureをセットしている場合は早期returnされず、&lt;code>$raw($this)&lt;/code>でClosureが評価されて評価された値が&lt;code>values&lt;/code>に再度セットされます。
さらに、&lt;code>raw&lt;/code>にClosure本体がセットされるので、factoryでセットしていなければ二回目以降の呼び出しは最初に生成したインスタンスがそのまま利用されることになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">offsetGet&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">keys&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">UnknownIdentifierException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">raw&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">||&lt;/span> &lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#1f2328">\is_object&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">||&lt;/span> &lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">protected&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">||&lt;/span> &lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#1f2328">\method_exists&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">],&lt;/span> &lt;span style="color:#0a3069">&amp;#39;__invoke&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">isset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">factories&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]]))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">](&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$raw&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$val&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">values&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$raw&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">raw&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$raw&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">frozen&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#953800">$id&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$val&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>factoryでセットしている場合は&lt;code>factories&lt;/code>という&lt;code>SplObjectStorage&lt;/code>のオブジェクトにClosureがattachされます。&lt;/p></description></item><item><title>phpdotenvコードリーディング</title><link>https://blog.freedom-man.com/phpdotenv-codereading.html</link><pubDate>Mon, 10 Jun 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/phpdotenv-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/vlucas/phpdotenv/">phpdotenv&lt;/a>のコードリーディングをしました。バージョンは3.3.3です。&lt;/p>
&lt;p>このケースで追ってみます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">require&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vendor/autoload.php&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$dotenv&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">Dotenv\Dotenv&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">__DIR__&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$dotenv&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">load&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#1f2328">getenv&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;FOO&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$_ENV&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;BAR&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$_SERVER&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;BAZ&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="コードリーディング">コードリーディング&lt;/h2>
&lt;p>Dotenv\Dotenv::createは以下のようにLoaderのインスタンスを生成し、それを引数にDotenv\Dotenvオブジェクトを生成して返します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Dotenv&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$paths&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$file&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">FactoryInterface&lt;/span> &lt;span style="color:#953800">$envFactory&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$loader&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">Loader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">getFilePaths&lt;/span>&lt;span style="color:#1f2328">((&lt;/span>&lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#953800">$paths&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$file&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;.env&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$envFactory&lt;/span> &lt;span style="color:#0550ae">?:&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">DotenvFactory&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$loader&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>Dotenv\Dotenv#load&lt;/code>は&lt;code>Dotenv\Loader#setImmutatable&lt;/code>したLoaderインスタンスの&lt;code>#load&lt;/code>をコールします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Dotenv&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">load&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">loadData&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">protected&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">loadData&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$overload&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">loader&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">setImmutable&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span>&lt;span style="color:#953800">$overload&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">load&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>LoaderのsetImmutableは以下のような実装になっていて、envVariablesに&lt;code>Dotenv\DotenvFactory#createImmutable&lt;/code>で生成した&lt;code>Dotenv\DotenvVariables&lt;/code>オブジェクトをセットします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Loader&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">setImmutable&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$immutable&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">envVariables&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">$immutable&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">?&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">envFactory&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">createImmutable&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">envFactory&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>Loader#load&lt;/code>はパス上のenvファイルをfile_get_contentsで読み込み、&lt;code>Lines::process&lt;/code>で環境変数を書き込んだ各行をstringのArrayにして返します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Loader&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">load&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">loadDirect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">findAndRead&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">filePaths&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">loadDirect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">processEntries&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Lines&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">process&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">preg_split&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/(&lt;/span>&lt;span style="color:#0a3069">\r\n&lt;/span>&lt;span style="color:#0a3069">|&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">|&lt;/span>&lt;span style="color:#0a3069">\r&lt;/span>&lt;span style="color:#0a3069">)/&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$content&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">findAndRead&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#953800">$filePaths&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$filePaths&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#1f2328">[])&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">InvalidPathException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;At least one environment file path must be provided.&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$filePaths&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$filePath&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$lines&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#1f2328">readFromFile&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$filePath&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$lines&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">isDefined&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#953800">$lines&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">throw&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">InvalidPathException&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">sprintf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;Unable to read any of the environment file(s) at [%s].&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">implode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;, &amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$filePaths&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>processEntriesでは各行（エントリ）を&lt;code>Dotenv\Parser::parse&lt;/code>でパースしてキーバリューに分解して&lt;code>Loader#setEnvironmentVariable&lt;/code>で環境変数にセットします。&lt;/p></description></item><item><title>PHPのテンプレートエンジンを自作してみた</title><link>https://blog.freedom-man.com/php-mytemplate.html</link><pubDate>Sun, 09 Jun 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/php-mytemplate.html</guid><description>&lt;p>PHPのテンプレートエンジンを作ってみましたー。&lt;br>
symfony/templatingとか読んでたら急に作りたくなったｗ&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/php-mytemplate-engine">tzmfreedom/php-mytemplate-engine&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="インストール">インストール&lt;/h2>
&lt;p>Packagistに登録していないのでGitHubのrepositoryを設定してよしなにインストールします&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ composer config repositories.tzmfreedom/php-mytemplate-engine vcs https://github.com/tzmfreedom/php-mytemplate-engine
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ composer require tzmfreedom/php-mytemplate-engine:dev-master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>Twigとか&lt;a href="https://github.com/symfony/templating">symfony/templating&lt;/a>のPHPEngineとかと同じ使い方です。というかインターフェースを合わせました。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">require_once&lt;/span> &lt;span style="color:#0a3069">&amp;#39;vendor/autoload.php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$engine&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">\MyTemplate\Engine&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$engine&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;sample.my&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;xxx&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;yyy&amp;#39;&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第一引数にテンプレートファイルのパス、第二引数にパラメータのarrayを入れます。&lt;/p>
&lt;p>テンプレートファイルはこんな感じで書けます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>{{ name }}&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">ul&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{{ for item : items }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">li&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>{{ item.name }}&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">li&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{{ end }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">ul&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{{ if display }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">p&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>foo&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">p&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{{ else }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">p&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>bar&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">p&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{{ end }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="実装方法">実装方法&lt;/h2>
&lt;p>基本的にASTいじりで、Lexerでトークナイズしてパーサーでツリー作ってVisitorパターンでevaluateしてPHPファイルを生成します。
&lt;a href="https://github.com/tzmfreedom/php-mytemplate-engine/blob/2d347f3e00e415587f368a9bbbb5893fbdae1de2/src/Lexer.php">Lexer&lt;/a>, &lt;a href="https://github.com/tzmfreedom/php-mytemplate-engine/blob/2d347f3e00e415587f368a9bbbb5893fbdae1de2/src/Parser.php">Parser&lt;/a>は手書きです。&lt;/p>
&lt;p>上のテンプレートファイルだとこういうPHPファイルになります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;html&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;body&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$name&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/div&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;ul&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">foreach&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$items&lt;/span> &lt;span style="color:#cf222e">as&lt;/span> &lt;span style="color:#953800">$item&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;li&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#953800">$item&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">getName&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/li&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/ul&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$display&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;p&amp;gt;foo&amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;p&amp;gt;bar&amp;lt;/p&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">echo&lt;/span> &lt;span style="color:#0a3069">&amp;lt;&amp;lt;&amp;lt;&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#0a3069">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/body&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/html&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>&lt;span style="color:#0a3069">EOS&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="所感">所感&lt;/h2>
&lt;p>どういう仕組みでテンプレートエンジンが動いているのかを実際に実装することで体験できたのは良かったです。&lt;br>
ASTの評価プロセスは、基本的には文字列を出力するだけなので言語作るよりかは楽だったｗ&lt;/p></description></item><item><title>KotlinでApexを記述できるAltApexを作っている話</title><link>https://blog.freedom-man.com/alt-apex.html</link><pubDate>Thu, 06 Jun 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/alt-apex.html</guid><description>&lt;p>KotlinでApexを記述できるAltApexというのを作っています。&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/alt-apex">AltApex&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>本記事ではAltApexを作った背景や使い方、現状の機能をざっと説明します。&lt;/p>
&lt;h2 id="背景">背景&lt;/h2>
&lt;p>現在、Salesforceのサーバーサイド言語としてはApexしか対応していません。
ApexはJavaに似た言語になっていますが、名前空間に対応していない、無名関数が無い、型の明示的な記述が必要など
書き味が悪く管理もしづらい言語仕様になっています。&lt;/p>
&lt;h2 id="altapexとは">AltApexとは&lt;/h2>
&lt;p>KotlinでApexを記述できるようにするトランスパイラです（JavaScriptに対するTypeScript的な）&lt;/p>
&lt;ol>
&lt;li>ANTLRでKotlinのファイルをパースしてASTを生成&lt;/li>
&lt;li>ASTを辿ってApexファイルを出力&lt;/li>
&lt;/ol>
&lt;p>というように処理をして動いています。&lt;/p>
&lt;h2 id="インストール">インストール&lt;/h2>
&lt;p>今のところバイナリを配布していないのでgo getしてください。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ go get -u github.com/tzmfreedom/alt-apex
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="使い方">使い方&lt;/h2>
&lt;p>Kotlinのファイルを指定すると標準出力にファイルの内容が出力されます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ alt-apex &lt;span style="color:#0550ae">{&lt;/span>file&lt;span style="color:#0550ae">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="対応状況">対応状況&lt;/h2>
&lt;p>Kotlinの文法対応状況ですが、現時点では以下のファイルが通るようになっています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-kotlin" data-lang="kotlin">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">package&lt;/span> &lt;span style="color:#24292e">hoge.foo&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">User&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">val&lt;/span> name&lt;span style="color:#1f2328">:&lt;/span> String&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#cf222e">var&lt;/span> age&lt;span style="color:#1f2328">:&lt;/span>Int &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">constructor&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>name&lt;span style="color:#1f2328">:&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span> age&lt;span style="color:#1f2328">:&lt;/span>Int&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>name&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>hoge&lt;span style="color:#1f2328">.&lt;/span>fuga&lt;span style="color:#1f2328">.&lt;/span>age &lt;span style="color:#1f2328">=&lt;/span> age
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">fun&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> i&lt;span style="color:#1f2328">:&lt;/span>Int &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>i &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">System&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>debug&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">System&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>debug&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> hoge&lt;span style="color:#1f2328">:&lt;/span>String &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>i &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;hello&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;world&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>number &lt;span style="color:#cf222e">in&lt;/span> numbers&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">System&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>debug&lt;span style="color:#1f2328">(&lt;/span>number&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">while&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>i &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">System&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>debug&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> i&lt;span style="color:#1f2328">:&lt;/span>Int &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">when&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>i&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>fuga&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#0550ae">-&amp;gt;&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>fuga&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;else&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">val&lt;/span> pr&lt;span style="color:#1f2328">:&lt;/span>PageReference &lt;span style="color:#1f2328">=&lt;/span> PageReference&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> pr&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#1f2328">Database&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>Hoge &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">Database&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>Hoge&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> pr&lt;span style="color:#1f2328">:&lt;/span>Int &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">System&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>debug&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">123&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> pr&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#1f2328">Database&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>Fuga &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">Database&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Hoge&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>Fuga&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> pr&lt;span style="color:#1f2328">:&lt;/span>Hoge &lt;span style="color:#1f2328">=&lt;/span> fuga&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">val&lt;/span> sum &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> x&lt;span style="color:#1f2328">:&lt;/span> Int&lt;span style="color:#1f2328">,&lt;/span> y&lt;span style="color:#1f2328">:&lt;/span>Int &lt;span style="color:#0550ae">-&amp;gt;&lt;/span> x &lt;span style="color:#1f2328">+&lt;/span> y &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">System&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>debug&lt;span style="color:#1f2328">(&lt;/span>sum&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Apexにトランスパイルされるとこんな感じ&lt;/p></description></item><item><title>Salesforce上で別言語を動かす試み</title><link>https://blog.freedom-man.com/lang-on-apex.html</link><pubDate>Thu, 09 May 2019 07:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/lang-on-apex.html</guid><description>&lt;p>Salesforce上でApexではないサーバーサイドなオレオレ言語を動かしてみます。&lt;/p>
&lt;p>成果物はこちら&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/mini-parser">tzmfreedom/mini-parser&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="実装方法">実装方法&lt;/h2>
&lt;p>Apexは文字列操作や制御構文などパースに必要な機能は一通り揃っているので、一般的なパーサを実装してASTを使って処理を実行していけばオレオレ言語を実装可能です。
バイナリ操作のメソッドが充実しておらずバイトコード的な実装は厳しいため、逐次コード文字列を読み取ってインタープリター的に実行するアプローチを取りました。&lt;/p>
&lt;p>一般的なパーサ実装はこんな感じです↓&lt;/p>
&lt;ul>
&lt;li>トークナイズ&lt;/li>
&lt;li>パースしてAST生成&lt;/li>
&lt;li>ASTを使ってコードを実行&lt;/li>
&lt;/ul>
&lt;h2 id="実装言語の仕様">実装言語の仕様&lt;/h2>
&lt;p>こんな感じな構文を動かせるようにします&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-golang" data-lang="golang">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">#&lt;/span> &lt;span style="color:#1f2328">動的に変数定義可能&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">a&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">123&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">#&lt;/span> &lt;span style="color:#1f2328">関数呼び出し&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">puts&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hello&amp;#34;&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">#&lt;/span> &lt;span style="color:#1f2328">for文&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">10&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0550ae">1&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">puts&lt;/span> &lt;span style="color:#1f2328">i&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">#&lt;/span> &lt;span style="color:#1f2328">while文&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">while&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">3&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">puts&lt;/span> &lt;span style="color:#1f2328">i&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">#&lt;/span> &lt;span style="color:#1f2328">if文&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">a&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">123&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">puts&lt;/span> &lt;span style="color:#0a3069">&amp;#34;a&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">puts&lt;/span> &lt;span style="color:#0a3069">&amp;#34;b&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="トークナイズlexer実装">トークナイズ（Lexer実装）&lt;/h2>
&lt;p>こんな感じで実装できます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Lexer&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>str&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>Integer&lt;span style="color:#fff"> &lt;/span>index&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>reserved&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#cf222e">while&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">Lexer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>str&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">str&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>str&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>0&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Token&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">parse&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Token&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>tokens&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Token&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">current&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">while&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Token&lt;span style="color:#fff"> &lt;/span>token&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">switch&lt;/span>&lt;span style="color:#fff"> &lt;/span>on&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>when&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;+&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;-&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;*&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;\n&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;(&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;)&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;{&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;}&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;!&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;lt;&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;!&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;lt;&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">peek&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>type&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">peek&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Token&lt;span style="color:#1f2328">(&lt;/span>type&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>type&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">next&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Token&lt;span style="color:#1f2328">(&lt;/span>current&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>when&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Pattern&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">matches&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">[&lt;/span>0&lt;span style="color:#0550ae">-&lt;/span>9&lt;span style="color:#0550ae">]&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parseInt&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Pattern&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">matches&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">[&lt;/span>a&lt;span style="color:#0550ae">-&lt;/span>zA&lt;span style="color:#0550ae">-&lt;/span>Z&lt;span style="color:#0550ae">]&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parseIdent&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">!=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>tokens&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>token&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">str&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#fff"> &lt;/span>1&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">break&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>current&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">next&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>tokens&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">peek&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">str&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">substring&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>1&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>2&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">current&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">str&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">substring&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>1&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">next&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">index&lt;/span>&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">current&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">// ...&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>受け取った文字列を１文字ずつ見ていってトークンの配列を生成します。
（Lexerを書いたことない人が見ると難しそうに見えたりしますが、ここは見た目ほど複雑じゃないただただ泥臭いコードです）&lt;/p></description></item><item><title>HaskellでインメモリなTODO APIアプリを作る</title><link>https://blog.freedom-man.com/haskell-inmemory-todoapi.html</link><pubDate>Fri, 12 Apr 2019 00:16:37 +0000</pubDate><guid>https://blog.freedom-man.com/haskell-inmemory-todoapi.html</guid><description>&lt;p>Haskellの練習がてらインメモリDBなTODO APIアプリを作ってみましたー&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/haskell-sample/blob/7bb14c2dd573fdd0b51834bd2cf391febdd6036c/warp-app/app/Main.hs">haskell-sample/Main.hs&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>全体的にはこんな感じです&lt;/p>
&lt;ul>
&lt;li>ベースの部分はWaiとWarpを利用&lt;/li>
&lt;li>ルーティングなどは自作（正規表現とか使わずパーサコンビネータで実装）&lt;/li>
&lt;li>データはメモリ上に保持（IORef）&lt;/li>
&lt;li>CRUDなAPI&lt;/li>
&lt;/ul>
&lt;p>あんまりHaskellでTODOアプリ作っている記事が見当たらなかったので、今回は備忘録も兼ねてどうやって作ったかを書いていきます。&lt;/p>
&lt;h2 id="アプリサーバを起動する">アプリサーバを起動する&lt;/h2>
&lt;p>waiとwarpを使ってWebサーバを起動します。run関数でアプリサーバを起動できます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">main&lt;/span> &lt;span style="color:#0550ae">::&lt;/span> &lt;span style="color:#cf222e">IO&lt;/span> &lt;span style="color:#6639ba">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">main&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> tasks &lt;span style="color:#0550ae">&amp;lt;-&lt;/span> defaultTasks
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> run &lt;span style="color:#0550ae">8080&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>server tasks&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>defaultTasksはデフォルトのDB情報（タスク）が入ったIORefを返します&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">defaultTasks&lt;/span> &lt;span style="color:#0550ae">::&lt;/span> &lt;span style="color:#cf222e">IO&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">IORef&lt;/span> &lt;span style="color:#cf222e">DB&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">defaultTasks&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> newIORef &lt;span style="color:#0550ae">$&lt;/span> &lt;span style="color:#cf222e">DB&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dbRecords &lt;span style="color:#0550ae">=&lt;/span> fromList &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">Task&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>taskId &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> taskTitle&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;foo&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> taskDescription&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;bar&amp;#34;&lt;/span>&lt;span style="color:#1f2328">}),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">Task&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>taskId &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> taskTitle&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> taskDescription&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;fuga&amp;#34;&lt;/span>&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dbNextTaskId &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">3&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>dbNextTaskIdには自動採番するための次のシーケンス番号、dbRecordsにはタスクレコードがData.Map型で入ってます。&lt;/p>
&lt;p>これをリクエストハンドラとなる関数に渡すことでリクエスト間で状態を保持できます。&lt;/p>
&lt;p>runの第三引数がリクエストハンドラにあたる部分で、型はApplicationになります。Applicationは &lt;code>Request -&amp;gt; (Response -&amp;gt; IO ResponseReceived) -&amp;gt; IO ResponseReceived&lt;/code> の型シノニムで、リクエストを受け取ってレスポンスを生成してそれを&lt;code>(Response -&amp;gt; IO ResponseReceived)&lt;/code> の関数に食わせて &lt;code>IO ResponseReceived&lt;/code> を返します。&lt;/p>
&lt;h2 id="ルーティング">ルーティング&lt;/h2>
&lt;p>parsecでルーティングを書いています。&lt;/p>
&lt;p>まずリクエスト（パスやメソッド）に応じてルーティングを変えていく必要があるので、リクエストを引数として &lt;code>Parser Handler&lt;/code> を生成します。
&lt;code>Handler&lt;/code>は&lt;code>Request -&amp;gt; IORef DB -&amp;gt; IO Response&lt;/code>の型シノニムです。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-haskell" data-lang="haskell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">getHandler&lt;/span> &lt;span style="color:#0550ae">::&lt;/span> &lt;span style="color:#cf222e">Handler&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">getHandler&lt;/span> req &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">case&lt;/span> parse &lt;span style="color:#1f2328">(&lt;/span>parseRoute req&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">CBS&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode &lt;span style="color:#0550ae">$&lt;/span> &lt;span style="color:#cf222e">BS&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>unpack path&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">of&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">Left&lt;/span> err &lt;span style="color:#0550ae">-&amp;gt;&lt;/span> error &lt;span style="color:#0550ae">$&lt;/span> &lt;span style="color:#0a3069">&amp;#34;ParserError&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">Right&lt;/span> ls &lt;span style="color:#0550ae">-&amp;gt;&lt;/span> ls req
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">where&lt;/span> path &lt;span style="color:#0550ae">=&lt;/span> rawPathInfo req
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ルーティングとしては以下を想定しています&lt;/p></description></item><item><title>自作gitを作ってみた</title><link>https://blog.freedom-man.com/mygit.html</link><pubDate>Sun, 07 Apr 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/mygit.html</guid><description>&lt;p>車輪の再発明シリーズ、今回は自作gitを作ってみましたー&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://github.com/tzmfreedom/mygit">tzmfreedom/mygit&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>gitの仕組みは公式に載っているのを参考にして実装しました&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88">Git - Gitオブジェクト&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>あとこちらの記事もとても詳しいです&lt;/p>
&lt;ul>
&lt;li>&lt;a href="http://koseki.hatenablog.com/entry/2014/04/22/inside-git-1">Git の仕組み (1) - こせきの技術日記&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>勉強目的なので、gitの仕様を完全に踏襲する感じではなくざっくり模倣しました。&lt;/p>
&lt;h2 id="実装内容">実装内容&lt;/h2>
&lt;p>だいたいこんなことをやってます↓&lt;/p>
&lt;ul>
&lt;li>&lt;code>mygit init&lt;/code> で &lt;code>.mygit&lt;/code> ディレクトリを作成。中身はこんな感じ↓
&lt;ul>
&lt;li>&lt;code>index&lt;/code> ファイル（ステージ用）&lt;/li>
&lt;li>&lt;code>refs&lt;/code> ディレクトリ（ブランチのreferenceを格納）&lt;/li>
&lt;li>&lt;code>objects&lt;/code> ディレクトリ（blobやらtreeやらcommitを格納）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>mygit add&lt;/code> で &lt;code>.mygit/index&lt;/code> にファイル情報をメモしつつ、&lt;code>.mygit/objects/{ファイルの中身のSHA1ハッシュ}&lt;/code> にファイルの中身を格納&lt;/li>
&lt;li>&lt;code>mygit commit&lt;/code> で &lt;code>.mygit/index&lt;/code> のファイルをコミット
&lt;ul>
&lt;li>&lt;code>.mygit/objects/{commitハッシュ}&lt;/code> にコミットのオブジェクトを作成&lt;/li>
&lt;li>新規ディレクトリが含まれている場合はtreeオブジェクトも作成&lt;/li>
&lt;li>既存tree内のオブジェクトの変更があればハッシュ値を更新（親treeに伝搬する）&lt;/li>
&lt;li>&lt;code>.mygit/index&lt;/code> をクリア&lt;/li>
&lt;li>&lt;code>.mygit/refs/heads/master&lt;/code> を最新のコミットに書き換え&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;code>mygit tree {commitハッシュ}&lt;/code> で対象コミットのファイルをツリー表示&lt;/li>
&lt;li>&lt;code>mygit diff {commitハッシュ} {commitハッシュ}&lt;/code>　で対象コミット間のdiffを表示&lt;/li>
&lt;li>&lt;code>mygit log&lt;/code> でコミットログを簡易的に表示&lt;/li>
&lt;li>&lt;code>mygit status&lt;/code> で &lt;code>.mygit/index&lt;/code> の中身を良い感じに表示&lt;/li>
&lt;li>&lt;code>mygit cat-file {ハッシュ}&lt;/code> で &lt;code>.mygit/objects/{ハッシュ}&lt;/code> の中身を良い感じに表示&lt;/li>
&lt;/ul>
&lt;p>commitのファイル仕様&lt;/p>
&lt;pre tabindex="0">&lt;code>commit
{treeハッシュ}
{前のcommitハッシュ}
{author}
{message}
&lt;/code>&lt;/pre>&lt;p>treeのファイル仕様&lt;/p></description></item><item><title>ブログをWordpressからNetlifyに移行しました</title><link>https://blog.freedom-man.com/blog-migrate-netlify.html</link><pubDate>Sun, 31 Mar 2019 22:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/blog-migrate-netlify.html</guid><description>&lt;p>ブログをWordpressから&lt;a href="https://www.netlify.com/">Netlify&lt;/a>に引っ越しましたー&lt;/p>
&lt;h2 id="移行した理由">移行した理由&lt;/h2>
&lt;ul>
&lt;li>旧ホスティング先のサーバのPHPのバージョンが古く、自身がアップグレードするモチベーションも湧かなかった&lt;/li>
&lt;li>静的ファイルでそんなに凝ったことしてないのにWordpress使っててtoo match感（そして遅い）&lt;/li>
&lt;li>記事編集で保存や新規記事画面への遷移も遅かった（かといってスケールアップする気にもならない）&lt;/li>
&lt;li>Wordpressのgutenbergが結構厳しくて、以前はプラグインの旧エディタ使っていたけど、旧エディタもMarkdownより書きづらいなーと思うことが増えてきた&lt;/li>
&lt;li>Wordpressのプラグインとか色々入れてて管理できてないし管理するモチベーションが（ｒｙ&lt;/li>
&lt;li>もっとシンプルにしてブログ自体を技術的な実験ができる場にしたい&lt;/li>
&lt;/ul>
&lt;p>と色々あったのです…。&lt;/p>
&lt;h2 id="変わったところ">変わったところ&lt;/h2>
&lt;ul>
&lt;li>Before
&lt;ul>
&lt;li>Wordpress&lt;/li>
&lt;li>VPS (DTIの月額500円プラン)でホスティング&lt;/li>
&lt;li>エッジはCloudFront&lt;/li>
&lt;li>オリジンはH2O + php-fpm&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>After
&lt;ul>
&lt;li>静的ファイル置くだけ
&lt;ul>
&lt;li>その静的ファイルは自前のブログジェネレータで生成&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Netlifyでホスティング&lt;/li>
&lt;li>&lt;a href="http://instantclick.io">instantclick.io&lt;/a>で別記事への遷移を爆速にした（やりたかった実験その１）&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="移行手順">移行手順&lt;/h2>
&lt;ul>
&lt;li>Wordpressから記事データのXMLをエクスポート
&lt;ul>
&lt;li>記事データのXMLから記事のデータを抽出&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Wordpressから画像データをエクスポート&lt;/li>
&lt;li>記事をごにょごにょ
&lt;ul>
&lt;li>画像のリンク先が &lt;code>/wp-content/uploads/...&lt;/code> とかってなってるのを一括置換&lt;/li>
&lt;li>コードのタグを調整(&lt;code>&amp;lt;pre class=&amp;quot;lang:ruby ...&amp;gt;&lt;/code> =&amp;gt; &lt;code>```ruby&lt;/code>)&lt;/li>
&lt;li>などなど&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>自前ジェネレータでmarkdownからhtml変換&lt;/li>
&lt;li>Netlifyにデプロイ（githubにpushして自動デプロイしたり手元からcliツールで手動デプロイしたり）&lt;/li>
&lt;/ul>
&lt;p>記事をごにょごにょするのは結構トライアンドエラーな感じだったのでRubyでちょろっとスクリプトを書きました。&lt;/p>
&lt;p>こんな感じ↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#!/usr/bin/env ruby&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">require&lt;/span> &lt;span style="color:#0a3069">&amp;#39;nokogiri&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">require&lt;/span> &lt;span style="color:#0a3069">&amp;#39;date&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>filename &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">ARGV&lt;/span>&lt;span style="color:#0550ae">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#0550ae">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>doc &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">Nokogiri&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">XML&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">File&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>open&lt;span style="color:#1f2328">(&lt;/span>filename&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#cf222e">do&lt;/span> &lt;span style="color:#0550ae">|&lt;/span>config&lt;span style="color:#0550ae">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> config&lt;span style="color:#0550ae">.&lt;/span>options &lt;span style="color:#0550ae">|=&lt;/span> &lt;span style="color:#0550ae">Nokogiri&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">XML&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">ParseOptions&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">HUGE&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>doc&lt;span style="color:#0550ae">.&lt;/span>css&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;item&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>each &lt;span style="color:#cf222e">do&lt;/span> &lt;span style="color:#0550ae">|&lt;/span>node&lt;span style="color:#0550ae">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">begin&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> title &lt;span style="color:#0550ae">=&lt;/span> node&lt;span style="color:#0550ae">.&lt;/span>xpath&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;title&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#0550ae">].&lt;/span>inner_text&lt;span style="color:#0550ae">.&lt;/span>strip&lt;span style="color:#0550ae">.&lt;/span>gsub&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#39;\&amp;#34;&amp;#39;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> postname &lt;span style="color:#0550ae">=&lt;/span> node&lt;span style="color:#0550ae">.&lt;/span>xpath&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;wp:post_name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#0550ae">].&lt;/span>inner_text&lt;span style="color:#0550ae">.&lt;/span>strip
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content &lt;span style="color:#0550ae">=&lt;/span> node&lt;span style="color:#0550ae">.&lt;/span>xpath&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;content:encoded&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#0550ae">].&lt;/span>inner_text&lt;span style="color:#0550ae">.&lt;/span>strip
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;#034;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#34;&amp;#39;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;#039;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#39;&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;quot;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#34;&amp;#39;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;gt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;gt;&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;lt;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;lt;&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;amp;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;amp;&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">/&amp;lt;pre class=&amp;#34;lang:default\s+[a-zA-Z:\s-]*&amp;#34;&amp;gt;/&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">```&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">/&amp;lt;pre class=&amp;#34;lang:language\-default\s+[a-zA-Z:\s-]*&amp;#34;&amp;gt;/&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">```&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">/&amp;lt;pre class=&amp;#34;lang:language\-([a-zA-Z]+)\s+[a-zA-Z:\s-]*&amp;#34;&amp;gt;/&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">```&lt;/span>&lt;span style="color:#0a3069">#{&lt;/span>&lt;span style="color:#953800">$1&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">/&amp;lt;pre class=&amp;#34;lang:(.+)\s+[a-zA-Z:\s-]*&amp;#34;&amp;gt;/&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">```&lt;/span>&lt;span style="color:#0a3069">#{&lt;/span>&lt;span style="color:#953800">$1&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;```sh&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#39;```bash&amp;#39;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> content&lt;span style="color:#0550ae">.&lt;/span>gsub!&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">/\n*&amp;lt;\/pre&amp;gt;/&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">\n&lt;/span>&lt;span style="color:#0a3069">```&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>自前のジェネレータは&lt;a href="https://github.com/tzmfreedom/blog-generator">これ&lt;/a>です。
ジェネレータといってもやっていることはこれくらい&lt;/p></description></item><item><title>Hackageに自作ライブラリを登録するまでのメモ</title><link>https://blog.freedom-man.com/hackage-register.html</link><pubDate>Fri, 08 Mar 2019 07:30:40 +0000</pubDate><guid>https://blog.freedom-man.com/hackage-register.html</guid><description>&lt;p>&lt;a href="http://hackage.haskell.org/" target="_blank" rel="noopener noreferrer">Hackage&lt;/a>に登録するまでの手順をざっくりメモった&lt;/p></description></item><item><title>HaskellのSalesforceクライアントを作ってみた</title><link>https://blog.freedom-man.com/hsforce.html</link><pubDate>Thu, 07 Mar 2019 07:30:33 +0000</pubDate><guid>https://blog.freedom-man.com/hsforce.html</guid><description>&lt;p>いつもの作ってみたシリーズ。今回はHaskell x Salesforceでございます。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/hsforce" target="_blank" rel="noopener noreferrer">tzmfreedom/hsforce&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="https://hackage.haskell.org/package/hsforce" target="_blank" rel="noopener noreferrer">hsforce: Salesforce API Client&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>DML文でSalesforceオブジェクトを操作できるsoql-cliを作った</title><link>https://blog.freedom-man.com/dml-soql-cli.html</link><pubDate>Sat, 05 Jan 2019 07:30:54 +0000</pubDate><guid>https://blog.freedom-man.com/dml-soql-cli.html</guid><description>&lt;p>SQLのDML構文でSalesforceのレコードを更新してみたい。ということで作ってみました&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/soql-cli" target="_blank" rel="noopener">tzmfreedom/soql-cli: Salesforce SOQL CLI like mysql, psql command&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>自作言語をAWS LambdaのCustom Runtimeで動かしてみた</title><link>https://blog.freedom-man.com/aws-lambda_custom-runtime_mylang.html</link><pubDate>Thu, 03 Jan 2019 09:30:45 +0000</pubDate><guid>https://blog.freedom-man.com/aws-lambda_custom-runtime_mylang.html</guid><description>&lt;p>自作言語を&lt;a href="https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/runtimes-custom.html" target="_blank" rel="noopener">AWS LambdaのCustom Runtime&lt;/a>で動かしてみました。&lt;/p></description></item><item><title>2019</title><link>https://blog.freedom-man.com/2019.html</link><pubDate>Tue, 01 Jan 2019 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2019.html</guid><description/></item><item><title>2018年の振り返り</title><link>https://blog.freedom-man.com/2018-summary.html</link><pubDate>Mon, 31 Dec 2018 07:30:10 +0000</pubDate><guid>https://blog.freedom-man.com/2018-summary.html</guid><description>&lt;p>今年はどんな一年だったのか振り返る的な&lt;/p></description></item><item><title>Land Playgroundのプレゼント</title><link>https://blog.freedom-man.com/land-playground.html</link><pubDate>Mon, 24 Dec 2018 07:30:22 +0000</pubDate><guid>https://blog.freedom-man.com/land-playground.html</guid><description>&lt;p>めりーくりすます&lt;/p>
&lt;p>&lt;a href="https://goland-server.herokuapp.com/" target="_blank" rel="noopener">&lt;a href="https://goland-server.herokuapp.com/">https://goland-server.herokuapp.com/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;ul>
 	&lt;li>Salesforce環境との接続なしのApexのコードお試し場&lt;/li>
 	&lt;li>コードスニペットのシェアができます。&lt;/li>
 	&lt;li>SOQL、ちょっとだけ使えます（テスト環境と繋がってます）
&lt;ul>
 	&lt;li>ってかAccountのSELECT句はId, Name, Website, Field1__cしか使えないですｗ&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>class構文は使えません。&lt;/li>
 	&lt;li>ビルトインのクラス・メソッドもほとんど無いのでSystem.debugくらいしかできないですorz&lt;/li>
 	&lt;li>変数定義・代入、if、for、whileくらいは通るはず&lt;/li>
 	&lt;li>エラー文とかまともに出してません。
&lt;ul>
 	&lt;li>レスポンスが返ってこない＝何かしらエラーで落ちてますm(_ _)m&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>ローカルでも試せます。
&lt;ul>
 	&lt;li>&lt;code>$ goland eval-server&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>Dreaminまでにはもう少しまともなの作ります。&lt;/li>
&lt;/ul></description></item><item><title>Xdebug, DBGPで簡易リモートデバッガを作る</title><link>https://blog.freedom-man.com/xdebug-dbgp.html</link><pubDate>Sun, 23 Dec 2018 00:00:07 +0000</pubDate><guid>https://blog.freedom-man.com/xdebug-dbgp.html</guid><description>&lt;p>Xdebug, DBGPで簡易デバッガを作ってみました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://gist.github.com/tzmfreedom/f12a572426c17a7c05c509d28dce290b" target="_blank" rel="noopener">SimpleDebugger.php&lt;/a>&lt;/li>
&lt;/ul>
この記事は&lt;a href="https://qiita.com/advent-calendar/2018/php" target="_blank" rel="noopener">PHP Advent Calendar 2018&lt;/a>の23日目の記事です。</description></item><item><title>YetでAnotherなSalesforce Dataloaderを作った</title><link>https://blog.freedom-man.com/yet-another-salesforce-dataloader.html</link><pubDate>Thu, 20 Dec 2018 00:00:41 +0000</pubDate><guid>https://blog.freedom-man.com/yet-another-salesforce-dataloader.html</guid><description>&lt;p>ということでデータローダ作りました。Salesforce Dataloaderができる基本的な機能は踏襲しつつYet Another感出してみました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/yasd" target="_blank" rel="noopener">tzmfreedom/yasd: Yet Another Salesforce Dataloader with golang&lt;/a>&lt;/li>
&lt;/ul>
あ、この記事は &lt;a href="https://adventar.org/calendars/3195">Trailblazer Advent Calendar 2018&lt;/a> 第20日目の記事となります。</description></item><item><title>Bulletコードリーディング</title><link>https://blog.freedom-man.com/bullet-codereading.html</link><pubDate>Wed, 19 Dec 2018 00:00:35 +0000</pubDate><guid>https://blog.freedom-man.com/bullet-codereading.html</guid><description>&lt;p>N+1クエリの検出ツールとして有名な&lt;a href="https://github.com/flyerhzm/bullet" target="_blank" rel="noopener">Bullet&lt;/a>のコードリーディングをしました。バージョンは5.9.0です。&lt;/p>
&lt;p>コードリーディングの過程で、False Negative, False Positiveなケースを発見したのでそれも併せて紹介します。&lt;/p>
&lt;p>※この記事は&lt;a href="https://qiita.com/advent-calendar/2018/rails">Ruby on Rails Advent Calendar 2018&lt;/a>の19日目の記事です。&lt;/p></description></item><item><title>デバッガのための実行基盤の実装について</title><link>https://blog.freedom-man.com/land-debugger-impl.html</link><pubDate>Fri, 14 Dec 2018 00:00:06 +0000</pubDate><guid>https://blog.freedom-man.com/land-debugger-impl.html</guid><description>&lt;p>この記事は&lt;a href="https://qiita.com/advent-calendar/2018/lang_dev">言語実装 Advent Calendar 2018 - Qiita&lt;/a>の14日目の記事です。&lt;/p>
&lt;p>Salesforce上で動く&lt;a href="https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_dev_guide.htm" target="_blank" rel="noopener">プログラミング言語Apex&lt;/a>をローカル環境で動かすLANDという実行基盤を作っています。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/goland" target="_blank" rel="noopener">tzmfreedom/goland: Salesforce Apex Execution Environment on Local System.&lt;/a>&lt;/li>
&lt;/ul>
LANDを作った契機などは&lt;a href="https://blog.freedom-man.com/salesforce-apex-local/" target="_blank" rel="noopener">こちらの記事&lt;/a>に書いてあります。ちなみにANTLR + Golang製です（最初はRacc/RexというRubyで書けるyacc/lexなツールで書いていたのですがJavaの文法がパースしづらく、ANTLRに切り替えたりと紆余曲折ありましたｗ）
&lt;p>言語実装のアドベントカレンダーとしては少し趣向が変わってきてしまうかもしれませんが、今回はLANDのデバッガの仕組みを紹介しようと思います。&lt;/p></description></item><item><title>[Salesforce] 真の開発者コンソールを作ってみた</title><link>https://blog.freedom-man.com/salesforce-terminal-ui.html</link><pubDate>Wed, 05 Dec 2018 00:00:41 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-terminal-ui.html</guid><description>&lt;p>アレなタイトルですがTUIなコンソールアプリを作ってみました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/lui" target="_blank" rel="noopener">tzmfreedom/lui: Salesforce Lightning TUI Application&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>config/initializers/new_framework_xxx.rbが効かなかったときのハマりメモ</title><link>https://blog.freedom-man.com/rails-initializers.html</link><pubDate>Fri, 16 Nov 2018 07:30:55 +0000</pubDate><guid>https://blog.freedom-man.com/rails-initializers.html</guid><description>&lt;p>Railsアップグレード時に &lt;code>bin/rails app:update&lt;/code>したときに生成される&lt;code>config/initializers/new_framework_xxx.rb&lt;/code>が効かなかったときのハマりメモ。Railsのバージョンは5.1.4です。&lt;/p></description></item><item><title>Couldn't find template for digestingエラー</title><link>https://blog.freedom-man.com/couldnt-find-template-digesting.html</link><pubDate>Thu, 15 Nov 2018 07:30:58 +0000</pubDate><guid>https://blog.freedom-man.com/couldnt-find-template-digesting.html</guid><description>&lt;p>Railsで以下のエラーがログに書かれていて、原因を調査したのでその備忘録。バージョンは5.2.1です。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">Couldn&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>t find template &lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#032f62">digesting&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> vars&lt;span style="color:#0550ae">/&lt;/span>var
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>ANTLR4でパーサをgolangで作る</title><link>https://blog.freedom-man.com/antlr4-parser-golang.html</link><pubDate>Tue, 09 Oct 2018 07:30:28 +0000</pubDate><guid>https://blog.freedom-man.com/antlr4-parser-golang.html</guid><description>&lt;p>ANTLR4のgolangでvisitorパターンで実装するサンプルが無かったので試しに作ってみました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/go-salesforce-formula-parser" target="_blank" rel="noopener">tzmfreedom/go-salesforce-formula-parser: Parse Salesforce Formula and, Build AST in Golang&lt;/a>&lt;/li>
&lt;/ul>
以下、golangで実装する場合の備忘録</description></item><item><title>ecs-deployコードリーディング</title><link>https://blog.freedom-man.com/ecs-deploy.html</link><pubDate>Mon, 01 Oct 2018 07:30:21 +0000</pubDate><guid>https://blog.freedom-man.com/ecs-deploy.html</guid><description>&lt;!-- wp:paragraph -->
&lt;p>&lt;a href="https://github.com/silinternational/ecs-deploy" target="_blank" rel="noopener">ecs-deploy&lt;/a>のコードリーディングをしました。バージョンは3.4.0です。&lt;/p>
&lt;p></description></item><item><title>env-injectorコードリーディング</title><link>https://blog.freedom-man.com/env-injector-codereading.html</link><pubDate>Tue, 11 Sep 2018 07:30:03 +0000</pubDate><guid>https://blog.freedom-man.com/env-injector-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/okzk/env-injector" target="_blank" rel="noopener">env-injector&lt;/a>のコードリーディングをしました。&lt;/p></description></item><item><title>Salesforce SOAP APIのgolangクライアント作った</title><link>https://blog.freedom-man.com/go-soapforce.html</link><pubDate>Mon, 10 Sep 2018 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/go-soapforce.html</guid><description>&lt;p>なぜ私はSalesforceのツールを作るのか…。ということでgolangのクライアント作りました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/go-soapforce" target="_blank" rel="noopener">tzmfreedom/go-soapforce: Salesforce SOAP API Client for golang&lt;/a>&lt;/li>
&lt;/ul>
モチベーションとしてはYet Another Salesforce Dataloaderをgolangで作ろうと思っているんですが、それを作るにはまずSOAPのクライアントで複数件の一括CRUDを実現させなければならない、ということでヤクの毛刈りをした感じです。</description></item><item><title>RackをバックエンドとするCLIツール Racliを作ってみた</title><link>https://blog.freedom-man.com/racli.html</link><pubDate>Wed, 29 Aug 2018 07:30:21 +0000</pubDate><guid>https://blog.freedom-man.com/racli.html</guid><description>&lt;p>表題のとおり、RackをバックエンドとしたCLIツール &lt;a href="https://github.com/tzmfreedom/racli" target="_blank" rel="noopener">Racli&lt;/a>を作ってみました。&lt;/p></description></item><item><title>RailsEventStoreコードリーディング</title><link>https://blog.freedom-man.com/rails-event-store-code-reading.html</link><pubDate>Tue, 28 Aug 2018 07:30:46 +0000</pubDate><guid>https://blog.freedom-man.com/rails-event-store-code-reading.html</guid><description>&lt;p>&lt;a href="https://github.com/RailsEventStore/rails_event_store" target="_blank" rel="noopener">RailsEventStore&lt;/a>のコードリーディングをしました。バージョンは0.31.1です。&lt;/p></description></item><item><title>SalesforceのワークフロールールをApexトリガに変換するヤーツ作った</title><link>https://blog.freedom-man.com/salesforce2apex.html</link><pubDate>Thu, 16 Aug 2018 07:30:33 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce2apex.html</guid><description>&lt;p>&lt;del>Apexをローカル環境で動かすのめっちゃムズイし現実逃避したくなったので
&lt;/del>SalesforceのワークフロールールをApexトリガに変換するヤーツを作りました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://www.npmjs.com/package/salesforce2apex" target="_blank" rel="noopener">salesforce2apex - npm&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/salesforce2apex" target="_blank" rel="noopener">tzmfreedom/salesforce2apex&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>[Salesforce] Apexのローカル実行環境を作ろうとしている話</title><link>https://blog.freedom-man.com/salesforce-apex-local.html</link><pubDate>Tue, 24 Jul 2018 07:30:25 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-apex-local.html</guid><description>&lt;p>ふと思い立ち、&lt;a href="https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_reference.htm" target="_blank" rel="noopener">SalesforceのApex言語&lt;/a>のローカル実行環境を作っています。&lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/apex_parser2" target="_blank" rel="noopener">tzmfreedom/apex_parser2&lt;/a>&lt;/p>
&lt;p>まだまだリリースにはほど遠いのですが、単純なコードであればある程度は動く状態になってきているので、モチベーション維持のためにここらで紹介記事を書きたいと思います。&lt;/p></description></item><item><title>Rodaコードリーディング</title><link>https://blog.freedom-man.com/roda-codereading.html</link><pubDate>Mon, 18 Jun 2018 07:30:29 +0000</pubDate><guid>https://blog.freedom-man.com/roda-codereading.html</guid><description>&lt;p>Rodaのコードリーディングをしました。バージョンは3.8.0です。&lt;/p></description></item><item><title>Hanamiコードリーディング【hanami new】</title><link>https://blog.freedom-man.com/hanami-codereading-new.html</link><pubDate>Tue, 12 Jun 2018 07:30:57 +0000</pubDate><guid>https://blog.freedom-man.com/hanami-codereading-new.html</guid><description>&lt;p>Hanamiのコードリーディングをしました。バージョンは1.2.0です。今回は &lt;code>hanami new&lt;/code> のアプリケーションの初期化コマンドのコードを追ってみます&lt;/p></description></item><item><title>TruffleRubyを動かしてみる</title><link>https://blog.freedom-man.com/truffleruby.html</link><pubDate>Mon, 11 Jun 2018 07:30:33 +0000</pubDate><guid>https://blog.freedom-man.com/truffleruby.html</guid><description>&lt;p>&lt;a href="https://www.graalvm.org/" target="_blank" rel="noopener">GraalVM&lt;/a>上で動く超絶速い&lt;a href="https://github.com/oracle/truffleruby" target="_blank" rel="noopener">TruffleRuby&lt;/a>を動かしてみました。&lt;/p></description></item><item><title>ArgumentError: path name contains null byte</title><link>https://blog.freedom-man.com/argumenterror-path-name-contains-null-byte.html</link><pubDate>Sun, 10 Jun 2018 17:28:44 +0000</pubDate><guid>https://blog.freedom-man.com/argumenterror-path-name-contains-null-byte.html</guid><description>&lt;p>bundle gemしたディレクトリ内でbundle installしようとしたら以下のエラーが発生した&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-default" data-lang="default">--- ERROR REPORT TEMPLATE -------------------------------------------------------
# Error Report

...

ArgumentError: path name contains null byte

...

Unfortunately, an unexpected error occurred, and Bundler cannot continue.

First, try this link to see if there are any existing issue reports for this error:
https://github.com/bundler/bundler/search?q=path+name+contains+null+byte&amp;amp;type=Issues

If there aren&amp;#39;t any reports for this error yet, please create copy and paste the report template above into a new issue. Don&amp;#39;t forget to anonymize any private data! The new issue form is located at:
https://github.com/bundler/bundler/issues/new
&lt;/code>&lt;/pre>&lt;p>原因は以下のようにgemspecのspec.filesの&lt;code>split(&amp;quot;\x0&amp;quot;)&lt;/code> を本来ダブルクォートで囲うべきなのにシングルクォートで囲ってしまったため。&lt;/p></description></item><item><title>optcarrotをmacOSで動かす</title><link>https://blog.freedom-man.com/optcarrot-macos.html</link><pubDate>Tue, 05 Jun 2018 23:00:25 +0000</pubDate><guid>https://blog.freedom-man.com/optcarrot-macos.html</guid><description>&lt;p>&lt;a href="https://github.com/mame/optcarrot" target="_blank" rel="noopener">optcarrot&lt;/a>をmacOSで動かすときのちょいメモ&lt;/p>
&lt;p>何はともあれ&lt;a href="https://www.libsdl.org/download-2.0.php" target="_blank" rel="noopener">SDL2&lt;/a>を使うのでインストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ tar -xf SDL2-2.0.8.tar.gz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> ./SDL2-2.0.8
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ./configure
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ make
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo make install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ファミコンをインストール&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">$&lt;/span> git &lt;span style="color:#6639ba">clone&lt;/span> &lt;span style="color:#032f62">http&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">//&lt;/span>github&lt;span style="color:#0550ae">.&lt;/span>com&lt;span style="color:#0550ae">/&lt;/span>mame&lt;span style="color:#0550ae">/&lt;/span>optcarrot&lt;span style="color:#0550ae">.&lt;/span>git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">$&lt;/span> cd optcarrot
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">$&lt;/span> bundle install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>立ち上げ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">$&lt;/span> bundle &lt;span style="color:#6639ba">exec&lt;/span> bin&lt;span style="color:#0550ae">/&lt;/span>optcarrot &lt;span style="color:#0550ae">--&lt;/span>sdl2 &lt;span style="color:#0550ae">--&lt;/span>audio&lt;span style="color:#0550ae">=&lt;/span>none examples&lt;span style="color:#0550ae">/&lt;/span>&lt;span style="color:#0550ae">Lan_Master&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>nes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>ひとりごと (2018/05/15)</title><link>https://blog.freedom-man.com/2018-05-15.html</link><pubDate>Tue, 15 May 2018 23:43:50 +0000</pubDate><guid>https://blog.freedom-man.com/2018-05-15.html</guid><description>&lt;p>2018/05/15分&lt;/p></description></item><item><title>ひとりごと (2018/05/13)</title><link>https://blog.freedom-man.com/2018-05-13.html</link><pubDate>Sun, 13 May 2018 21:50:54 +0000</pubDate><guid>https://blog.freedom-man.com/2018-05-13.html</guid><description>&lt;h2>記事紹介&lt;/h2>
&lt;h3>&lt;a href="https://semaphoreci.com/blog/2014/01/21/rails-testing-antipatterns-models.html" target="_blank" rel="noopener">Rails Testing Antipatterns: Models&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>Railsのモデルテストのアンチパターン&lt;/li>
 	&lt;li>build使ってDBに保存せずに高速に&lt;/li>
 	&lt;li>POROやconcerningで良い感じに分割してDB依存なくして高速に&lt;/li>
 	&lt;li>&lt;code>let&lt;/code> vs &lt;code>let!&lt;/code> vs &lt;code>before&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="https://medium.com/@adityatiwari01933/ruby-memoization-using-singleton-method-1a8ac4955083" target="_blank" rel="noopener">Ruby Memoization using Singleton Method&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>シングルトンメソッドを使ってMemorization&lt;/li>
 	&lt;li>初回ははインスタンスメソッドを呼び出して、そこで &lt;code>def self.xxx&lt;/code> でシングルトンメソッドを定義して二回目以降はシングルトンメソッドを呼び出す方法&lt;/li>
 	&lt;li>||=のMemorizationだとnilやfalseで再評価されるが、この方法だと再評価されない（シングルトンメソッドの有り無しが初期化しているかどうかの判別になる）&lt;/li>
 	&lt;li>||=より速いらしい&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>コメント
&lt;ul>
 	&lt;li>これは面白い初期化の方法だなー。Rubyの仕様的には問題無さそう。&lt;/li>
 	&lt;li>インスタンスメソッド経由でシングルトンメソッドを定義するの面白い&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="http://yukimotopress.github.io/" target="_blank" rel="noopener">Yuki &amp; Moto Press Bookshelf&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>Free Books in the Yuki &amp; Moto Press Series&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>コメント
&lt;ul>
 	&lt;li>凄い…時間があったらこれも読んでみます&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="https://medium.com/@farsi_mehdi/method-arguments-in-ruby-part-i-e033fd6bfd93" target="_blank" rel="noopener">Method Arguments in Ruby: Part I&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>メソッドの定義と呼び出し方について&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="https://medium.com/@farsi_mehdi/private-protected-a-matter-of-message-1a88b10acbf2" target="_blank" rel="noopener">Private &amp; Protected: a matter of Message&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>private, protectedについて&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="https://medium.com/@farsi_mehdi/ruby-object-model-part-1-4d06fa486bec" target="_blank" rel="noopener">Ruby Object Model - Part 1&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>Object, mainオブジェクトなどのRuby Objectに関して&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>コメント
&lt;ul>
 	&lt;li>Rubyを学び始めたとき、mainがトップレベルのコンテキストであることを知って面白いなーと思った。こういうオブジェクト指向の一貫性が好き&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="https://signalvnoise.com/posts/3372-put-chubby-models-on-a-diet-with-concerns" target="_blank" rel="noopener">Put chubby models on a diet with concerns&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>2012年の記事&lt;/li>
 	&lt;li>concern使って、ドメインモデルを考慮して良い感じにモデルをダイエットしていこう&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3>&lt;a href="https://www.rubyref.net/" target="_blank" rel="noopener">rubyref.net&lt;/a>&lt;/h3>
&lt;ul>
 	&lt;li>概要
&lt;ul>
 	&lt;li>Rubyのドキュメントに関するリファレンス一覧&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>コメント
&lt;ul>
 	&lt;li>こんなのあったんだなー。便利&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title>ひとりごと (2018/05/11)</title><link>https://blog.freedom-man.com/2018-05-11.html</link><pubDate>Fri, 11 May 2018 23:51:07 +0000</pubDate><guid>https://blog.freedom-man.com/2018-05-11.html</guid><description>&lt;p>技術記事やgemの紹介をデイリーでやっていく試み（つぶやきの延長です）&lt;/p></description></item><item><title>ひとりごと (2018/05/10)</title><link>https://blog.freedom-man.com/2018-05-10.html</link><pubDate>Thu, 10 May 2018 23:53:10 +0000</pubDate><guid>https://blog.freedom-man.com/2018-05-10.html</guid><description>&lt;p>技術記事やgemの紹介をデイリーでやっていく試み（つぶやきの延長です）&lt;/p></description></item><item><title>RubyGemsのinstallは何をやっているか</title><link>https://blog.freedom-man.com/rubygems-install.html</link><pubDate>Thu, 10 May 2018 07:30:39 +0000</pubDate><guid>https://blog.freedom-man.com/rubygems-install.html</guid><description>&lt;p>&lt;a href="https://github.com/rubygems/rubygems" target="_blank" rel="noopener">RubyGems&lt;/a>のコードリーディングをしました。バージョンは2.7.3です。今回は &lt;code>gem install&lt;/code>のパターンで追ってみます。&lt;/p></description></item><item><title>ひとりごと (2018/05/09)</title><link>https://blog.freedom-man.com/2018-05-09.html</link><pubDate>Wed, 09 May 2018 22:40:45 +0000</pubDate><guid>https://blog.freedom-man.com/2018-05-09.html</guid><description>&lt;p>技術記事やgemの紹介をデイリーでやっていく試み（つぶやきの延長です）&lt;/p></description></item><item><title>RubyGemsのrequireは何をやっているか</title><link>https://blog.freedom-man.com/rubygems-require.html</link><pubDate>Wed, 09 May 2018 07:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/rubygems-require.html</guid><description>&lt;p>＝gemspecのスタブの中で対象のファイルが存在すれば、それを返します。
def self.find_by_path path
path = path.dup.freeze
spec = @@spec_with_requirable_file[path] ||= (stubs.find { |s|
next unless Gem::BundlerVersionFinder.compatible?(s)
s.contains_requirable_file? path
} || NOT_FOUND)
spec.to_spec
end&lt;/p>
&lt;p>stubsはspecificationsディレクトリ内にある拡張子がgemspecのもの（＝インストール済みのrubygemのgemspec）を検索してGem::StubSpecificationのインスタンスを返します。
def self.stubs
@@stubs ||= begin
pattern = &amp;ldquo;*.gemspec&amp;rdquo;
stubs = default_stubs(pattern).concat installed_stubs(dirs, pattern)
stubs = uniq_by(stubs) { |stub| stub.full_name }&lt;/p>
&lt;pre>&lt;code> _resort!(stubs)
 @@stubs_by_name = stubs.group_by(:name)
 stubs
end
&lt;/code>&lt;/pre>
&lt;p>end&lt;/p>
&lt;p>default_stubsはspecifications/defaultのディレクトリ内にあるgemspecを拾ってStubSpecificationのインスタンスを生成します。defaultディレクトリには csv やjsonなどの標準ライブラリが入っています。
def self.default_stubs pattern
base_dir = Gem.default_dir
gems_dir = File.join base_dir, &amp;ldquo;gems&amp;rdquo;
gemspec_stubs_in(default_specifications_dir, pattern) do |path|
Gem::StubSpecification.default_gemspec_stub(path, base_dir, gems_dir)
end
end&lt;/p></description></item><item><title>Railsのミドルウェアのエラーハンドリング</title><link>https://blog.freedom-man.com/rails-middleware-errorhandling.html</link><pubDate>Tue, 03 Apr 2018 07:30:35 +0000</pubDate><guid>https://blog.freedom-man.com/rails-middleware-errorhandling.html</guid><description>&lt;p>RoutingErrorやRack::QueryParser::InvalidParameterErrorが発生した場合にはRackミドルウェアベースでエラーハンドリングされます。今回はこのエラーハンドリングの処理についてコードリーディングしていきます。Railsのバージョンは5.1.5です。&lt;/p></description></item><item><title>did_you_meanコードリーディング</title><link>https://blog.freedom-man.com/did_you_mean-codereading.html</link><pubDate>Mon, 02 Apr 2018 07:30:04 +0000</pubDate><guid>https://blog.freedom-man.com/did_you_mean-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/yuki24/did_you_mean" target="_blank" rel="noopener">did_you_mean&lt;/a>(1.2.0)のコードリーディングをしました。&lt;/p></description></item><item><title>bootsnapコードリーディング（load_iseqを使った高速読み込み）</title><link>https://blog.freedom-man.com/bootsnap-codereading-load_iseq.html</link><pubDate>Thu, 29 Mar 2018 07:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/bootsnap-codereading-load_iseq.html</guid><description>&lt;p>&lt;a href="https://github.com/Shopify/bootsnap" target="_blank" rel="noopener">bootsnap&lt;/a>(1.2.0)のコードリーディングをしました。今回はload_iseqによるrequire, loadの高速化を見ていきます。&lt;/p></description></item><item><title>simplecovコードリーディング</title><link>https://blog.freedom-man.com/simplecov-codereading.html</link><pubDate>Wed, 28 Mar 2018 07:30:52 +0000</pubDate><guid>https://blog.freedom-man.com/simplecov-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/colszowka/simplecov" target="_blank" rel="noopener">simplecov&lt;/a> (0.16.1)のコードリーディングをしました。&lt;/p></description></item><item><title>bootsnapコードリーディング（requireのパス検索の高速化）</title><link>https://blog.freedom-man.com/bootsnap-codereading-require.html</link><pubDate>Tue, 27 Mar 2018 07:30:17 +0000</pubDate><guid>https://blog.freedom-man.com/bootsnap-codereading-require.html</guid><description>&lt;p>require, loadの高速化を行う&lt;a href="https://github.com/Shopify/bootsnap" target="_blank" rel="noopener">bootsnap&lt;/a>(1.2.0)のコードリーディングをしました。今回はrequireのパス検索の高速化部分を読んでいきます。&lt;/p></description></item><item><title>yomikomuコードリーディング</title><link>https://blog.freedom-man.com/yomikomu-codereading.html</link><pubDate>Mon, 26 Mar 2018 07:30:09 +0000</pubDate><guid>https://blog.freedom-man.com/yomikomu-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/ko1/yomikomu" target="_blank" rel="noopener">yomikomu&lt;/a>(0.4.1)のコードリーディングをしました。&lt;/p></description></item><item><title>byebugがdebase(ruby-debug-ide)と同時に使えるようになった</title><link>https://blog.freedom-man.com/byebug-with-debase.html</link><pubDate>Sat, 24 Mar 2018 07:30:10 +0000</pubDate><guid>https://blog.freedom-man.com/byebug-with-debase.html</guid><description>&lt;p>&lt;a href="https://github.com/deivid-rodriguez/byebug" target="_blank" rel="noopener">byebug&lt;/a> 10.0.1でdebaseと同時に使えるようになったのでその紹介記事です。&lt;/p></description></item><item><title>pumaの再起動時のディレクトリについて</title><link>https://blog.freedom-man.com/puma-restart-diretory.html</link><pubDate>Fri, 23 Mar 2018 07:30:36 +0000</pubDate><guid>https://blog.freedom-man.com/puma-restart-diretory.html</guid><description>&lt;p>capistranoでデプロイをしてもRailsアプリのコードが反映されない！とハマったので備忘録&lt;/p></description></item><item><title>binding_of_callerコードリーディング</title><link>https://blog.freedom-man.com/binding_of_caller-codereading.html</link><pubDate>Thu, 22 Mar 2018 07:30:36 +0000</pubDate><guid>https://blog.freedom-man.com/binding_of_caller-codereading.html</guid><description>&lt;p>binding_of_caller (v0.8.0)のコードリーディングをしました。Rubyのバージョンは2系以上のものを扱っていきます。&lt;/p></description></item><item><title>rb-inotifyコードリーディング</title><link>https://blog.freedom-man.com/rb-inotify-codereading.html</link><pubDate>Tue, 20 Mar 2018 07:30:57 +0000</pubDate><guid>https://blog.freedom-man.com/rb-inotify-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/guard/rb-inotify" target="_blank" rel="noopener">rb-inotify&lt;/a> (0.9.10)のコードリーディングをしました。listenで利用されているgemです。&lt;/p></description></item><item><title>byebugコードリーディング</title><link>https://blog.freedom-man.com/byebug-codereading.html</link><pubDate>Mon, 19 Mar 2018 07:30:03 +0000</pubDate><guid>https://blog.freedom-man.com/byebug-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/deivid-rodriguez/byebug" target="_blank" rel="noopener">byebug&lt;/a>(10.0.0)のコードリーディングをしました。&lt;/p></description></item><item><title>Railsアセットパイプラインのコードリーディング</title><link>https://blog.freedom-man.com/assetpipeline-codereading.html</link><pubDate>Fri, 16 Mar 2018 07:30:38 +0000</pubDate><guid>https://blog.freedom-man.com/assetpipeline-codereading.html</guid><description>&lt;p>Railsのアセットパイプライン周りのコードリーディングをしました。今回は&lt;code>assets:precompile&lt;/code>のRakeタスクで何をやっているかをコードベースで追っていきます。Railsのバージョンは5.1.5です。&lt;/p></description></item><item><title>capistrano/sshkitコードリーディング</title><link>https://blog.freedom-man.com/sshkit-codereading.html</link><pubDate>Thu, 08 Mar 2018 07:30:55 +0000</pubDate><guid>https://blog.freedom-man.com/sshkit-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/capistrano/capistrano" target="_blank" rel="noopener">capistrano&lt;/a> (3.10.1)の&lt;a href="https://github.com/capistrano/sshkit" target="_blank" rel="noopener">SSHKit&lt;/a>を利用する部分をコードリーディングしてみました。&lt;/p></description></item><item><title>Rack CORSコードリーディング</title><link>https://blog.freedom-man.com/rack-cors-codereading.html</link><pubDate>Wed, 07 Mar 2018 07:30:52 +0000</pubDate><guid>https://blog.freedom-man.com/rack-cors-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/cyu/rack-cors" target="_blank" rel="noopener">rack-cors&lt;/a> (1.0.2)のコードリーディングをしました。&lt;/p></description></item><item><title>tachikomaコードリーディング</title><link>https://blog.freedom-man.com/tachikoma-codereading.html</link><pubDate>Tue, 06 Mar 2018 07:30:32 +0000</pubDate><guid>https://blog.freedom-man.com/tachikoma-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/sanemat/tachikoma" target="_blank" rel="noopener">tachikoma&lt;/a> (5.2.0)のコードリーディングをしました。&lt;/p></description></item><item><title>Railsのform helper周りのコードリーディング</title><link>https://blog.freedom-man.com/rails-formhelper-codereading.html</link><pubDate>Mon, 05 Mar 2018 07:30:21 +0000</pubDate><guid>https://blog.freedom-man.com/rails-formhelper-codereading.html</guid><description>&lt;p>Railsのform helper周りのコードリーディングをしました。Railsのバージョンは5.1.5です。&lt;/p></description></item><item><title>compare_linker_wrapperコードリーディング</title><link>https://blog.freedom-man.com/compare_linker_wrapper-codereading.html</link><pubDate>Fri, 02 Mar 2018 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/compare_linker_wrapper-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/packsaddle/ruby-compare_linker_wrapper" target="_blank" rel="noopener">compare_linker_wraper&lt;/a> (v1.0.2)のコードリーディングをしました。&lt;/p></description></item><item><title>ActiveRecord::NoEnvironmentInSchemaErrorについて</title><link>https://blog.freedom-man.com/no-environment-in-schema-error.html</link><pubDate>Thu, 01 Mar 2018 07:30:41 +0000</pubDate><guid>https://blog.freedom-man.com/no-environment-in-schema-error.html</guid><description>&lt;p>Railsで&lt;code>ActiveRecord::NoEnvironmentInSchemaError&lt;/code>が出たときの原因と対応方法の備忘録。Railsのバージョンは5.1.5です。&lt;/p></description></item><item><title>DockerでSFTP開発環境を作る</title><link>https://blog.freedom-man.com/docker-sftp.html</link><pubDate>Wed, 28 Feb 2018 07:30:59 +0000</pubDate><guid>https://blog.freedom-man.com/docker-sftp.html</guid><description>&lt;p>サービス連携の用途でSFTPをプログラムから利用することがあると思いますが、今回はDockerコンテナを使ってSFTP開発環境の作り方を紹介します。&lt;/p></description></item><item><title>ActiveRecord::PendingMigrationErrorはどうやって発生するのか</title><link>https://blog.freedom-man.com/pending-migration-error.html</link><pubDate>Tue, 27 Feb 2018 07:30:03 +0000</pubDate><guid>https://blog.freedom-man.com/pending-migration-error.html</guid><description>&lt;p>開発中のエラーでよく出てくる&lt;code>ActiveRecord::PendingMigrationError&lt;/code>について調べてみました。Railsのバージョンは5.1.5です。&lt;/p></description></item><item><title>RailsのCSRF周りのコードリーディング</title><link>https://blog.freedom-man.com/rails-csrf-codereading.html</link><pubDate>Mon, 26 Feb 2018 07:30:47 +0000</pubDate><guid>https://blog.freedom-man.com/rails-csrf-codereading.html</guid><description>&lt;p>RailsのCSRF周りのコードリーディングをしました。&lt;/p></description></item><item><title>Railsのlogger周りのコードリーディング</title><link>https://blog.freedom-man.com/rails-logger-codereading.html</link><pubDate>Fri, 23 Feb 2018 07:30:51 +0000</pubDate><guid>https://blog.freedom-man.com/rails-logger-codereading.html</guid><description>&lt;p>Railsのlogger周りのコードリーディングをしました。&lt;/p></description></item><item><title>Railsのsession周りコードリーディング</title><link>https://blog.freedom-man.com/rails-session-codereading.html</link><pubDate>Thu, 22 Feb 2018 07:30:40 +0000</pubDate><guid>https://blog.freedom-man.com/rails-session-codereading.html</guid><description>&lt;p>Railsのsessionがどうやって設定されるのかをコードリーディングをして追ってみました。Railsのバージョンは5.1.4です。&lt;/p></description></item><item><title>I18nコードリーディング</title><link>https://blog.freedom-man.com/i18n-codereading.html</link><pubDate>Wed, 21 Feb 2018 07:30:10 +0000</pubDate><guid>https://blog.freedom-man.com/i18n-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/svenfuchs/i18n" target="_blank" rel="noopener">I18n&lt;/a>(0.9.3)のコードリーディングをしました。&lt;/p></description></item><item><title>seed-fuコードリーディング</title><link>https://blog.freedom-man.com/seed-fu-codereading.html</link><pubDate>Tue, 20 Feb 2018 07:30:10 +0000</pubDate><guid>https://blog.freedom-man.com/seed-fu-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/mbleigh/seed-fu" target="_blank" rel="noopener">seed-fu&lt;/a> (2.3.7)のコードリーディングをしました。&lt;/p></description></item><item><title>bundlerコードリーディング【exec編】</title><link>https://blog.freedom-man.com/bundler-codereading-exec.html</link><pubDate>Mon, 19 Feb 2018 07:30:27 +0000</pubDate><guid>https://blog.freedom-man.com/bundler-codereading-exec.html</guid><description>&lt;p>&lt;a href="https://github.com/bundler/bundler" target="_blank" rel="noopener">bundler&lt;/a> (1.16.1)のコードリーディングをしました。今回は &lt;code>bundle exec&lt;/code> のコードを追ってみます。&lt;/p></description></item><item><title>hirbコードリーディング</title><link>https://blog.freedom-man.com/hirb-codereading.html</link><pubDate>Fri, 16 Feb 2018 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/hirb-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/cldwalker/hirb" target="_blank" rel="noopener">hirb&lt;/a> (0.7.3)のコードリーディングをしました。&lt;/p></description></item><item><title>Railsはbin/railsが無いと起動できない</title><link>https://blog.freedom-man.com/rails_bin-rails.html</link><pubDate>Thu, 15 Feb 2018 07:30:12 +0000</pubDate><guid>https://blog.freedom-man.com/rails_bin-rails.html</guid><description>&lt;p>Railsはbin/railsが無いとnew以外のコマンドを実行できません。今回はコードレベルでその理由を追っていこうと思います。railsのバージョンは5.1.4です。&lt;/p></description></item><item><title>公式のRubyのDockerイメージのbundlerの挙動</title><link>https://blog.freedom-man.com/ruby-docker-bundler.html</link><pubDate>Wed, 14 Feb 2018 07:30:46 +0000</pubDate><guid>https://blog.freedom-man.com/ruby-docker-bundler.html</guid><description>&lt;p>少しハマったので備忘録。&lt;a href="https://github.com/docker-library/ruby" target="_blank" rel="noopener">公式のRubyのDockerイメージ&lt;/a>を使うとbundler経由でインストールしたものをボリューム用コンテナで永続化しても二回目以降の起動時でうまく反映されない事象が起きました。&lt;/p></description></item><item><title>annotateコードリーディング</title><link>https://blog.freedom-man.com/annotate-codereading.html</link><pubDate>Tue, 13 Feb 2018 07:30:27 +0000</pubDate><guid>https://blog.freedom-man.com/annotate-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/ctran/annotate_models" target="_blank" rel="noopener">annotate&lt;/a> (2.7.2)のコードリーディングをしました。&lt;/p></description></item><item><title>better_errorsコードリーディング</title><link>https://blog.freedom-man.com/better_errors-codereading.html</link><pubDate>Wed, 07 Feb 2018 07:30:31 +0000</pubDate><guid>https://blog.freedom-man.com/better_errors-codereading.html</guid><description>&lt;p>BetterErrorsのコードリーディングをしました。&lt;/p></description></item><item><title>Rakeタスクにおけるnamespace内でのメソッド定義</title><link>https://blog.freedom-man.com/rake-definemethod-namespace.html</link><pubDate>Tue, 06 Feb 2018 07:30:08 +0000</pubDate><guid>https://blog.freedom-man.com/rake-definemethod-namespace.html</guid><description>&lt;p>Rakeタスク内でメソッド定義するとObjectのprivateメソッドとして定義されます。なので下のような書き方は一見namespace配下にメソッドを定義しているように見えますがObjectのメソッドとして定義されてしまっています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">outside_method&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">puts&lt;/span> &lt;span style="color:#0a3069">&amp;#39;outside method&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>namespace &lt;span style="color:#032f62">:foo&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">inside_method&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">puts&lt;/span> &lt;span style="color:#0a3069">&amp;#39;inside method&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> desc &lt;span style="color:#0a3069">&amp;#34;bar&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> task &lt;span style="color:#032f62">:bar&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> outside_method &lt;span style="color:#57606a"># &amp;#34;outside_method&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> inside_method &lt;span style="color:#57606a"># &amp;#34;inside_method&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">puts&lt;/span> &lt;span style="color:#6639ba">method&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#032f62">:outside_method&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>owner &lt;span style="color:#57606a"># =&amp;gt; Object&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">puts&lt;/span> &lt;span style="color:#6639ba">method&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#032f62">:inside_method&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>owner &lt;span style="color:#57606a"># =&amp;gt; Object&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Rakeは各タスクの定義ファイルをKernel.loadしていて、namespaceはインスタンス変数の@scopeに名前空間を設定しつつ、与えられたブロックを普通にyieldしています↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">module&lt;/span> &lt;span style="color:#24292e">Rake&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">module&lt;/span> &lt;span style="color:#24292e">TaskManager&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">in_namespace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">name&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">name&lt;/span> &lt;span style="color:#0550ae">||=&lt;/span> generate_name
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">@scope&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">Scope&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">name&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">@scope&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ns &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">NameSpace&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">self&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">@scope&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">yield&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>ns&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ns
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">ensure&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">@scope&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#953800">@scope&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>tail
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>なので、block内のメソッド定義はnamespace外のメソッド定義と同じです。&lt;/p>
&lt;p>同様にCapistranoもRake::Applicationクラスを継承して作られているので、namespace内で記述されたメソッドはObjectのメソッドとして定義されます。&lt;/p>
&lt;p>ちなみにrspecのdescribeのブロックは動的に作成されるクラスのmodule_execメソッドの引数として渡されるので、そのクラスのメソッドを定義していることになります。なのでObjectのメソッド定義になりません。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">module&lt;/span> &lt;span style="color:#24292e">RSpec&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">module&lt;/span> &lt;span style="color:#24292e">Core&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">ExampleGroup&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#6639ba">define_example_group_method&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">name&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> metadata&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> idempotently_define_singleton_method&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">name&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">do&lt;/span> &lt;span style="color:#0550ae">|*&lt;/span>args&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>example_group_block&lt;span style="color:#0550ae">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> subclass&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">self&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> description&lt;span style="color:#1f2328">,&lt;/span> args&lt;span style="color:#1f2328">,&lt;/span> registration_collection&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>example_group_block&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">RSpec&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">Core&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">DSL&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>expose_example_group_alias&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">name&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#1f2328">self&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#6639ba">subclass&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>parent&lt;span style="color:#1f2328">,&lt;/span> description&lt;span style="color:#1f2328">,&lt;/span> args&lt;span style="color:#1f2328">,&lt;/span> registration_collection&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>example_group_block&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> subclass &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">Class&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>parent&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> subclass&lt;span style="color:#0550ae">.&lt;/span>set_it_up&lt;span style="color:#1f2328">(&lt;/span>description&lt;span style="color:#1f2328">,&lt;/span> args&lt;span style="color:#1f2328">,&lt;/span> registration_collection&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&lt;/span>example_group_block&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> subclass&lt;span style="color:#0550ae">.&lt;/span>module_exec&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">&amp;amp;&lt;/span>example_group_block&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> example_group_block
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">MemoizedHelpers&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>define_helpers_on&lt;span style="color:#1f2328">(&lt;/span>subclass&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> subclass
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Railsプラグイン開発のダミーアプリでrails restart</title><link>https://blog.freedom-man.com/rails-plugin-dummyapp.html</link><pubDate>Thu, 18 Jan 2018 23:52:40 +0000</pubDate><guid>https://blog.freedom-man.com/rails-plugin-dummyapp.html</guid><description>&lt;p>小ネタ。Railsプラグイン開発で{test, spec}/dummy内のダミーアプリを起動して確認する場合、プラグインのコード変更はダミーアプリが読み込むgemの変更になるので自動的にリロードされず、ダミーアプリを再起動する必要があります。&lt;/p>
&lt;p>また、ダミーアプリはpluginとpluginの依存ライブラリを除いてrailsのみrequireしてます。なので、 &lt;code>rails s&lt;/code>してもpumaではなくWEBrickが立ち上がります。&lt;/p>
&lt;p>&lt;code>rails restart&lt;/code>（あるいは&lt;code>rake restart&lt;/code>）はpumaの再起動方法になるので、このコマンドで再起動する場合は以下のようにpluginのGemfileにpumaを追加する必要があります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>source &lt;span style="color:#0a3069">&amp;#39;https://rubygems.org&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gemspec
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>gem &lt;span style="color:#0a3069">&amp;#39;puma&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これで &lt;code>bundle install&lt;/code>すれば&lt;code>rails s&lt;/code>で起動したpumaのアプリサーバを &lt;code>rails restart&lt;/code>で再起動できます。&lt;/p>
&lt;p>ちなみにこれだけだと毎回コマンド打たなきゃいけないのでそれも面倒です。なのでguardで自動化します。Guardfileはguard-shellを使うとこんな感じで書けます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>guard &lt;span style="color:#032f62">:shell&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> watch &lt;span style="color:#0a3069">/(app|lib)\/.*/&lt;/span> &lt;span style="color:#cf222e">do&lt;/span> &lt;span style="color:#0550ae">|&lt;/span>m&lt;span style="color:#0550ae">|&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">puts&lt;/span> &lt;span style="color:#0a3069">`cd spec/dummy; bundle exec rails restart`&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> m&lt;span style="color:#0550ae">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#0550ae">]&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34; has changed.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これでapp, libディレクトリ内のファイル変更を検知して自動的に rails restartしてくれます。まぁ自動化するんならpuma必須じゃないんですけどね…ｗ&lt;/p></description></item><item><title>AASMコードリーディング</title><link>https://blog.freedom-man.com/aasm-codereading.html</link><pubDate>Thu, 11 Jan 2018 07:30:02 +0000</pubDate><guid>https://blog.freedom-man.com/aasm-codereading.html</guid><description>&lt;p>状態遷移の管理を行う&lt;a href="https://github.com/aasm/aasm" target="_blank" rel="noopener">AASM&lt;/a>のコードリーディングをしました。バージョンは4.12.3です&lt;/p></description></item><item><title>wheneverコードリーディング</title><link>https://blog.freedom-man.com/whenever-codereading.html</link><pubDate>Sat, 06 Jan 2018 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/whenever-codereading.html</guid><description>&lt;p>RubyでDSL書いてcronの設定ができる&lt;a href="https://github.com/javan/whenever" target="_blank" rel="noopener">whenever&lt;/a>のコードリーディングをしました。バージョンは0.10.0です&lt;/p></description></item><item><title>figaroコードリーディング</title><link>https://blog.freedom-man.com/figaro-codereading.html</link><pubDate>Fri, 05 Jan 2018 07:30:09 +0000</pubDate><guid>https://blog.freedom-man.com/figaro-codereading.html</guid><description>&lt;p>設定ファイルから環境変数をセットする&lt;a href="https://github.com/laserlemon/figaro" target="_blank" rel="noopener">figaro&lt;/a>のコードリーディングをしました。バージョンは1.1.1です&lt;/p></description></item><item><title>2017年の振り返り</title><link>https://blog.freedom-man.com/2017-summary.html</link><pubDate>Sun, 31 Dec 2017 16:00:00 +0000</pubDate><guid>https://blog.freedom-man.com/2017-summary.html</guid><description>&lt;p>2017年を「仕事」「技術」の面で振り返ってみました。&lt;/p></description></item><item><title>2018</title><link>https://blog.freedom-man.com/2018.html</link><pubDate>Mon, 01 Jan 2018 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2018.html</guid><description/></item><item><title>Salesforceで技術は学べるのか？</title><link>https://blog.freedom-man.com/skillup-with-salesforce.html</link><pubDate>Thu, 21 Dec 2017 00:00:52 +0000</pubDate><guid>https://blog.freedom-man.com/skillup-with-salesforce.html</guid><description>&lt;p>本記事は&lt;a href="http://qiita.com/advent-calendar/2017/salesforce-platform" target="_blank" rel="noopener">Salesforce Platform Advent Calendar 2017&lt;/a>の21日目の記事です。&lt;/p>
&lt;p>前職ではSalesforce＋α（AWSとかHerokuとか）なSI業務を5年半くらいやっていて、昨年、事業会社のエンジニアとして転職してから1年ちょっとが経過しました。新卒エンジニアとしてのスタートがSalesforceというのは当時としてはレアな経歴だったと思うし、それが故にエンジニアとしての色々な悩みを抱えつつ仕事をしていました。&lt;/p>
&lt;p>ということで、本記事では「エンジニアとしてSalesforceで技術は学べるのか？スキルアップできるのか？」とか「潰しが効くのか？」とかそういった疑問に対する考えをダラダラと書いていきたいと思います。&lt;/p></description></item><item><title>Rails API開発におけるJSONレスポンス生成方法と内部実装について</title><link>https://blog.freedom-man.com/rails-api-json-implementation.html</link><pubDate>Tue, 19 Dec 2017 00:00:54 +0000</pubDate><guid>https://blog.freedom-man.com/rails-api-json-implementation.html</guid><description>&lt;p>&lt;a href="https://qiita.com/advent-calendar/2017/ruby_on_rails" target="_blank" rel="noopener">Ruby on Rails Advent Calendar 2017&lt;/a> 19日目の記事です。&lt;/p>
&lt;p>RailsでAPI開発するときのJSONレスポンスの生成方法についてまとめてみました。&lt;/p></description></item><item><title>RubyGemコードリーディングのすすめ</title><link>https://blog.freedom-man.com/try-rubygem-codereading.html</link><pubDate>Wed, 13 Dec 2017 00:00:24 +0000</pubDate><guid>https://blog.freedom-man.com/try-rubygem-codereading.html</guid><description>&lt;p>&lt;a href="https://qiita.com/advent-calendar/2017/ruby">Ruby Advent Calendar 2017&lt;/a> 13日目の記事になります。&lt;/p>
&lt;p>使っているRubyGemの挙動や仕組みを理解するためによくコードを読んでいるのですが、今回はコードリーディグについて記事を書いていこうと思います。&lt;/p></description></item><item><title>$ref のJSON Pointerを展開するrubygemを書いた</title><link>https://blog.freedom-man.com/ref-expand-rubygem.html</link><pubDate>Mon, 20 Nov 2017 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/ref-expand-rubygem.html</guid><description>&lt;p>JSON Schemaで記述される$refパラメータのリンクを展開するrubygemを書きました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://rubygems.org/gems/json_refs" target="_blank" rel="noopener">json_refs | RubyGems.org&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/json_refs" target="_blank" rel="noopener">tzmfreedom/json_refs: Dereference JSON reference&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>jbuilderより速いRails Viewハンドラーを書いた</title><link>https://blog.freedom-man.com/rails-json-view-handler.html</link><pubDate>Thu, 16 Nov 2017 07:30:04 +0000</pubDate><guid>https://blog.freedom-man.com/rails-json-view-handler.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/yj-railsview-handler/" target="_blank" rel="noopener">YAMLとERBでJSONを書けるハンドラを書いたものの遅くなってしまった&lt;/a>ので、一旦YAMLとERBのことは忘れ、evalとしては最速になるようにhashをJSONに変換するアプローチで再度書いてみました。&lt;/p>
&lt;p>また前回同様、&lt;/p>
&lt;ul>
 	&lt;li>モンキーパッチをしない&lt;/li>
 	&lt;li>N+1 find_template_pathsを避ける&lt;/li>
 	&lt;li>Railsのcollectionのパーシャルレンダリングの仕組みを使う&lt;/li>
&lt;/ul>
というのをコンセプトでやっています。
&lt;p>できあがったものはこれ↓&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/jv" target="_blank" rel="noopener">tzmfreedom/jv&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>draperコードリーディング</title><link>https://blog.freedom-man.com/draper-codereading.html</link><pubDate>Wed, 15 Nov 2017 07:30:53 +0000</pubDate><guid>https://blog.freedom-man.com/draper-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/drapergem/draper" target="_blank" rel="noopener">drapergem/draper&lt;/a>のコードリーディングの備忘録。&lt;/p></description></item><item><title>YAMLでJSONを返すRails Viewハンドラーを書いた</title><link>https://blog.freedom-man.com/yj-railsview-handler.html</link><pubDate>Tue, 14 Nov 2017 07:30:14 +0000</pubDate><guid>https://blog.freedom-man.com/yj-railsview-handler.html</guid><description>&lt;p>実用性皆無の勉強用でRailsのViewハンドラーを書いてみました。YAMLとERBで記述して、JSONを返すハンドラです。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/yj" target="_blank" rel="noopener">tzmfreedom/yj&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>RequestStoreコードリーディング</title><link>https://blog.freedom-man.com/requeststore-codereading.html</link><pubDate>Tue, 14 Nov 2017 00:55:58 +0000</pubDate><guid>https://blog.freedom-man.com/requeststore-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/steveklabnik/request_store" target="_blank" rel="noopener">steveklabnik/request_store&lt;/a>のコードリーディング。&lt;/p></description></item><item><title>rbenvコードリーディング</title><link>https://blog.freedom-man.com/rbenv-codereading.html</link><pubDate>Mon, 13 Nov 2017 07:30:06 +0000</pubDate><guid>https://blog.freedom-man.com/rbenv-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/rbenv/rbenv" target="_blank" rel="noopener">rbenv/rbenv&lt;/a>のコードリーディングの備忘録。バージョンは1.1.0-2-g4f8925a です。&lt;/p></description></item><item><title>jbuilderで無理矢理N+1 partial renderingを回避する方法</title><link>https://blog.freedom-man.com/jbuilder-n1render.html</link><pubDate>Fri, 10 Nov 2017 07:30:21 +0000</pubDate><guid>https://blog.freedom-man.com/jbuilder-n1render.html</guid><description>&lt;p>実務では絶対に使わないけどrails/jbuilderのpartialレンダリングを無理矢理早くする方法。&lt;/p></description></item><item><title>sidekiqコードリーディング</title><link>https://blog.freedom-man.com/sidekiq-codereading.html</link><pubDate>Tue, 07 Nov 2017 07:30:34 +0000</pubDate><guid>https://blog.freedom-man.com/sidekiq-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/mperham/sidekiq" target="_blank" rel="noopener noreferrer">sidekiq&lt;/a>のコードを読んだので備忘録。バージョンは5.0.5です&lt;/p></description></item><item><title>unicornコードリーディング</title><link>https://blog.freedom-man.com/unicorn-codereading.html</link><pubDate>Mon, 30 Oct 2017 07:30:31 +0000</pubDate><guid>https://blog.freedom-man.com/unicorn-codereading.html</guid><description>&lt;p>&lt;a href="https://bogomips.org/unicorn/" target="_blank" rel="noopener noreferrer">unicorn&lt;/a>を読んだので備忘録。非公式ですがミラーのリポジトリは &lt;a href="https://github.com/defunkt/unicorn" target="_blank" rel="noopener noreferrer">defunkt/unicorn&lt;/a>です。&lt;/p></description></item><item><title>WEBrickはシングルスレッドではない</title><link>https://blog.freedom-man.com/webrick-not-singlethread.html</link><pubDate>Wed, 25 Oct 2017 07:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/webrick-not-singlethread.html</guid><description>&lt;p>表題の通り、&lt;a href="https://github.com/ruby/webrick" target="_blank" rel="noopener noreferrer">WEBrick&lt;/a>はシングルスレッドなアプリサーバではなくマルチスレッドです。&lt;/p>
&lt;p>にも関わらず、Web上にはWEBrickがシングルスレッドであるかのような記事が多く、Wikipediaでも&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-default" data-lang="default">Unlike most of the servers that are used in production, 
WEBrick is not scalable since it is a single threaded web server by default.
&lt;/code>&lt;/pre>&lt;p>と記載があり、とても誤解をまねきやすいです（デフォルトで、と言っているので完全に間違っているとは言い難いけど）&lt;/p>
&lt;p>今回は、WEBrickがマルチスレッドサーバである根拠と、なぜシングルスレッドと誤解されているのかをRailsのバージョンの話も交えて書いていきます。&lt;/p></description></item><item><title>rails/springコードリーディング</title><link>https://blog.freedom-man.com/rails-spring-codereading.html</link><pubDate>Tue, 24 Oct 2017 07:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/rails-spring-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/rails/spring" target="_blank" rel="noopener noreferrer">rails/spring&lt;/a>のコードリーディングをしましたー。ということで備忘録。&lt;/p></description></item><item><title>OmniAuth::LineOpenidConnectを作った話</title><link>https://blog.freedom-man.com/omniauth-line-openid-connect.html</link><pubDate>Thu, 12 Oct 2017 07:30:40 +0000</pubDate><guid>https://blog.freedom-man.com/omniauth-line-openid-connect.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/omniauth-line-login/" target="_blank" rel="noopener noreferrer">omniauthでLINEでログインを実装する&lt;/a>の記事でOmniAuth::Lineを改変したのですが、そもそもOAuth認証じゃなくてOpenID Connectに対応したのだから、そっちにプラグイン作った方が良いなーと思い、勉強がてら作りました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://rubygems.org/gems/omniauth-line-openid-connect" target="_blank" rel="noopener noreferrer">omniauth-line-openid-connect | RubyGems.org&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/omniauth-line-openid-connect" target="_blank" rel="noopener noreferrer">tzmfreedom/omniauth-line-openid-connect: OmniAuth provier for Line with OpenID Connect&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>WEBrick::HTTPServerコードリーディング</title><link>https://blog.freedom-man.com/webrickhttpserver.html</link><pubDate>Wed, 11 Oct 2017 07:30:48 +0000</pubDate><guid>https://blog.freedom-man.com/webrickhttpserver.html</guid><description>&lt;p>WEBrick::HTTPServerのコードを読んだので備忘録。rackup時の挙動に関しても書きました。&lt;/p></description></item><item><title>omniauthコードリーディング</title><link>https://blog.freedom-man.com/omniauth-codereading.html</link><pubDate>Tue, 10 Oct 2017 07:30:35 +0000</pubDate><guid>https://blog.freedom-man.com/omniauth-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/omniauth/omniauth" target="_blank" rel="noopener noreferrer">omniauth&lt;/a>のコードリーディングをしてみたので備忘録。&lt;/p></description></item><item><title>omniauthでLINEでログインを実装する</title><link>https://blog.freedom-man.com/omniauth-line-login.html</link><pubDate>Tue, 10 Oct 2017 00:03:37 +0000</pubDate><guid>https://blog.freedom-man.com/omniauth-line-login.html</guid><description>&lt;p>&lt;del>&lt;a href="https://github.com/kazasiki/omniauth-line" target="_blank" rel="noopener noreferrer">kazasiki/omniauth-line&lt;/a>を使ってLINEでログインを実装しようと思ったものの、新しいバージョンに対応していなかったのでforkして改変してみました（本家にプルリク中）&lt;/del>&lt;/p>
&lt;ul>
 	&lt;li>&lt;del>&lt;a href="https://github.com/tzmfreedom/omniauth-line/tree/update_for_openid_connect" target="_blank" rel="noopener noreferrer">tzmfreedom/omniauth-line&lt;/a>&lt;/del>&lt;/li>
&lt;/ul>
マージいただきました！ありがとうございます！！
ということでLINE IDでログインしたい場合は、&lt;a href="https://rubygems.org/gems/omniauth-line" target="_blank" rel="noopener noreferrer">omniauth-line&lt;/a>のgemをそのままお使いください！
&lt;p>omniauthの設定はREADMEに書かれている通り、こんな感じで指定するだけ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">Rails&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>application&lt;span style="color:#0550ae">.&lt;/span>config&lt;span style="color:#0550ae">.&lt;/span>middleware&lt;span style="color:#0550ae">.&lt;/span>use &lt;span style="color:#0550ae">OmniAuth&lt;/span>&lt;span style="color:#0550ae">::&lt;/span>&lt;span style="color:#0550ae">Builder&lt;/span> &lt;span style="color:#cf222e">do&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> provider &lt;span style="color:#032f62">:line&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Channel_ID&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Channel_Secret&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>callbackパスは/auth/line/callbackになるのでよしなにログインするなりプロビジョニングするなりすればOKです。&lt;/p></description></item><item><title>5分で試すRackミドルウェア</title><link>https://blog.freedom-man.com/rack-middleware.html</link><pubDate>Thu, 05 Oct 2017 07:30:14 +0000</pubDate><guid>https://blog.freedom-man.com/rack-middleware.html</guid><description>&lt;p>5分でRailsでRackミドルウェアを試した備忘録。&lt;/p></description></item><item><title>FormクラスでラップしたActiveRecordのエラー内容をマージする</title><link>https://blog.freedom-man.com/form-activerecord-error.html</link><pubDate>Wed, 04 Oct 2017 07:30:52 +0000</pubDate><guid>https://blog.freedom-man.com/form-activerecord-error.html</guid><description>&lt;p>Formオブジェクトを使って、ActiveRecord経由でDBにレコードを保存する場合、エラー内容を適切にマージする必要があるよーということの備忘録。&lt;/p></description></item><item><title>RubyのModule#const_getについて調べてみた</title><link>https://blog.freedom-man.com/ruby-module-const_get.html</link><pubDate>Fri, 08 Sep 2017 07:30:52 +0000</pubDate><guid>https://blog.freedom-man.com/ruby-module-const_get.html</guid><description>&lt;p>&lt;code>Module#const_get&lt;/code>はそのモジュール内に定義されている定数を取得することができるメソッドです。動的にインスタンスを生成したり、定数を参照するときに利用しますが、今回は&lt;code>Module#const_get&lt;/code>のハマりポイントを紹介します。&lt;/p></description></item><item><title>ansibleを使ってCentOS 6にmysql5.6をインストール</title><link>https://blog.freedom-man.com/ansible-centos6-mysql56install.html</link><pubDate>Mon, 21 Aug 2017 07:30:07 +0000</pubDate><guid>https://blog.freedom-man.com/ansible-centos6-mysql56install.html</guid><description>&lt;p>ansibleを使ってCentOS 6にmysql5.6をインストールする方法についての備忘録。&lt;/p>
&lt;p>CentOS 6のデフォルトのリポジトリだとmysql5.1がインストールされるので、それ以上のバージョンをインストールする場合は、公式レポジトリからrpmを取ってきてインストールする必要があります。そこらへんの処理をansibleで書いて自動プロビジョニングできるようにしました。&lt;/p></description></item><item><title>RailtieでControllerを拡張する</title><link>https://blog.freedom-man.com/railtie-controller-extension.html</link><pubDate>Mon, 07 Aug 2017 07:30:17 +0000</pubDate><guid>https://blog.freedom-man.com/railtie-controller-extension.html</guid><description>&lt;p style="text-align: left;">勉強がてら、Controllerを拡張するRailtieを作ってみたので備忘録。基本的な作り方は&lt;a href="https://blog.freedom-man.com/railtie-actionmailer-extension/" target="_blank" rel="noopener noreferrer">こちらの記事&lt;/a>と記事内の参考URLを参考にすると良いです。&lt;/p></description></item><item><title>Railtieのinitializerが読み込まれる仕組み</title><link>https://blog.freedom-man.com/railtie-initializer.html</link><pubDate>Fri, 04 Aug 2017 07:30:50 +0000</pubDate><guid>https://blog.freedom-man.com/railtie-initializer.html</guid><description>&lt;p>Railtieのサブクラスで呼び出したinitializerブロックが読み込まれる仕組みをコードを読んで紐解いてみました。Railsは5.1.2です&lt;/p></description></item><item><title>ActiveSupport.on_loadとrun_load_hooksのコードリーディング</title><link>https://blog.freedom-man.com/activesupport-on_load-run_load_hooks.html</link><pubDate>Thu, 03 Aug 2017 07:30:28 +0000</pubDate><guid>https://blog.freedom-man.com/activesupport-on_load-run_load_hooks.html</guid><description>&lt;p>ActiveSupport.onload と ActiveSupport.run_load_hooks のコードを読んでみました。&lt;/p></description></item><item><title>RailtieでActionMailerを拡張する</title><link>https://blog.freedom-man.com/railtie-actionmailer-extension.html</link><pubDate>Wed, 02 Aug 2017 07:30:37 +0000</pubDate><guid>https://blog.freedom-man.com/railtie-actionmailer-extension.html</guid><description>&lt;p>Railtieを使ってActionMailerのdelivery_methodを拡張してみました。
サンプルで作ったgemはこちら↓&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://rubygems.org/gems/http_action_mailer" target="_blank" rel="noopener noreferrer">http_action_mailer | RubyGems.org | your community gem host&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/http_action_mailer" target="_blank" rel="noopener noreferrer">tzmfreedom/http_action_mailer: ActionMailer debugger with HTTP&lt;/a>&lt;/li>
&lt;/ul>
任意のURLにHTTP POSTするdelivery_methodを定義したgemになります。
&lt;p>ということで今回は作り方の備忘として残します。&lt;/p></description></item><item><title>ActiveJobの仕組みを読み解く</title><link>https://blog.freedom-man.com/activejob-codereading.html</link><pubDate>Tue, 01 Aug 2017 07:30:19 +0000</pubDate><guid>https://blog.freedom-man.com/activejob-codereading.html</guid><description>&lt;p>&lt;a href="https://github.com/rails/rails/tree/master/activejob" target="_blank" rel="noopener noreferrer">ActiveJob&lt;/a>の仕組みをざっくり読み解いてみました。Railsのバージョンは 5.1.2です。&lt;/p></description></item><item><title>do ... endと{ ... }の結合度</title><link>https://blog.freedom-man.com/do-end-brace-coupling.html</link><pubDate>Wed, 26 Jul 2017 23:07:43 +0000</pubDate><guid>https://blog.freedom-man.com/do-end-brace-coupling.html</guid><description>&lt;p>Rubyの&lt;code>do &amp;hellip; end&lt;/code>と &lt;code>{ &amp;hellip; }&lt;/code> はどちらもブロックを表すが、文法としての結合度が違う。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="display:flex;">&lt;span>hoge &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">123&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">hoge&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>fuga &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">nil&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">puts&lt;/span> fuga
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">yield&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#6639ba">block_given?&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hoge hoge &lt;span style="color:#cf222e">do&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span> &lt;span style="color:#cf222e">end&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># =&amp;gt; 123 &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hoge hoge &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># =&amp;gt; &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># hoge&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
 	&lt;li>&lt;code>do ... end&lt;/code>の方は結合度が弱いので&lt;code>hoge(hoge) do ... end&lt;/code>として解釈される
&lt;ul>
 	&lt;li>なのでputs hoge(=変数)するだけ&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>&lt;code>{ ... }&lt;/code>の方は結合度が強いので&lt;code>hoge(hoge() { ... })&lt;/code>として解釈される
&lt;ul>
 	&lt;li>内部のhoge呼び出しでputs nilして、yieldのreturnを外側のhogeでputsするのでputs "hoge"される&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2>参考URL&lt;/h2>
&lt;ul>
 	&lt;li>&lt;a href="http://qiita.com/riocampos/items/43e4431ddff93e01a18d" target="_blank" rel="noopener noreferrer">ブロックをdo…endで書くか{…}で書くかにより挙動が変わる例 - Qiita&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="http://mickey24.hatenablog.com/entry/20100914/1284475769" target="_blank" rel="noopener noreferrer">Rubyのブロック構文の書き分け(do end，{}) - ぬいぐるみライフ？&lt;/a>&lt;/li>
&lt;/ul>
&amp;nbsp;</description></item><item><title>ActiveRecordのパフォーマンス・チューニング</title><link>https://blog.freedom-man.com/activerecord-performance.html</link><pubDate>Wed, 19 Jul 2017 07:30:41 +0000</pubDate><guid>https://blog.freedom-man.com/activerecord-performance.html</guid><description>&lt;p>ActiveRecord周りのパフォーマンス・チューニングの備忘録。&lt;/p>
&lt;p>DBレベルのチューニングはしたものの、Railsアプリのレイヤーでパフォーマンスを上げたい、という人向けの記事です。
今回ベンチマークに使ったコードは&lt;a href="https://github.com/tzmfreedom/rails-performance/blob/master/lib/tasks/benchmark.rake" target="_blank" rel="noopener noreferrer">こちら&lt;/a>にあります。&lt;/p></description></item><item><title>N+1 partial renderingによるパフォーマンス問題</title><link>https://blog.freedom-man.com/n1_partial_rendering_performance.html</link><pubDate>Tue, 18 Jul 2017 07:30:11 +0000</pubDate><guid>https://blog.freedom-man.com/n1_partial_rendering_performance.html</guid><description>&lt;p>Ruby on RailsのN+1 partial renderingのパフォーマンス悪化を測定してみました。&lt;/p></description></item><item><title>コマンドラインからgitlabのファイルをダウンロードする</title><link>https://blog.freedom-man.com/gitlab-filedownload.html</link><pubDate>Thu, 15 Jun 2017 07:30:56 +0000</pubDate><guid>https://blog.freedom-man.com/gitlab-filedownload.html</guid><description>&lt;p>gitlabで wgetやcurlを使ってprivateなリポジトリのファイルをダウンロードしたいときの備忘録。&lt;/p></description></item><item><title>Ruby系のコマンドでits extensions are not built</title><link>https://blog.freedom-man.com/ruby-notbuilt-message.html</link><pubDate>Sun, 28 May 2017 16:02:06 +0000</pubDate><guid>https://blog.freedom-man.com/ruby-notbuilt-message.html</guid><description>&lt;p>あるときからruby系のコマンドを叩く度に以下のようなメッセージが表示されるようになった&lt;/p>
&lt;pre tabindex="0">&lt;code>Ignoring nokogiri-1.6.8 because its extensions are not built. Try: gem pristine nokogiri --version 1.6.8
Ignoring nokogiri-1.6.8.1 because its extensions are not built. Try: gem pristine nokogiri --version1.6.8.1
Ignoring bcrypt-3.1.11 because its extensions are not built. Try: gem pristine bcrypt --version 3.1.11
...
&lt;/code>&lt;/pre>&lt;p>以下のコマンドを叩けば解消されます。&lt;/p>
&lt;pre tabindex="0">&lt;code>gem pristine --all
&lt;/code>&lt;/pre>&lt;h2>参考URL&lt;/h2>
&lt;ul>
 	&lt;li>&lt;a href="https://stackoverflow.com/questions/39991410/bundle-error-on-macos-10-12-sierra" target="_blank" rel="noopener noreferrer">ruby on rails - Bundle Error on macOS 10.12 Sierra - Stack Overflow&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>SPMのPackageサイト作ってみた</title><link>https://blog.freedom-man.com/spm-package-site.html</link><pubDate>Thu, 25 May 2017 07:30:58 +0000</pubDate><guid>https://blog.freedom-man.com/spm-package-site.html</guid><description>&lt;p>&lt;a href="https://github.com/tzmfreedom/spm" target="_blank" rel="noopener noreferrer">Salesforce Package Manager&lt;/a>のpackageサイト作ってみました↓&lt;/p>
&lt;p>&lt;a href="https://spm-packages.herokuapp.com" target="_blank" rel="noopener noreferrer">SPM - Salesforce Package Manager -&lt;/a>&lt;/p></description></item><item><title>wordpressの前段にCloudFrontを置いたときの備忘録</title><link>https://blog.freedom-man.com/wordpress-cloudfront.html</link><pubDate>Sun, 14 May 2017 23:40:19 +0000</pubDate><guid>https://blog.freedom-man.com/wordpress-cloudfront.html</guid><description>&lt;p>このたび、wordpressのサーバの前段にCloudFrontを置いたので、ハマったところを備忘として残しておきます。基本的には参考URLのやり方で設定すればOKです。&lt;/p></description></item><item><title>Railsのコントローラでsendメソッドを定義すると起こること</title><link>https://blog.freedom-man.com/rails-sendmethod.html</link><pubDate>Sun, 14 May 2017 19:35:33 +0000</pubDate><guid>https://blog.freedom-man.com/rails-sendmethod.html</guid><description>&lt;p>かなり初心者的ミスをしたので備忘録。&lt;/p></description></item><item><title>Windowsユーザ向けワンラインインストール</title><link>https://blog.freedom-man.com/windows-online-install.html</link><pubDate>Mon, 08 May 2017 07:30:40 +0000</pubDate><guid>https://blog.freedom-man.com/windows-online-install.html</guid><description>&lt;p>Windowsでワンラインインストールするためには、コマンドプロンプトやPowershellを使う必要があります。今回はPowershellを使ったワンラインインストールの方法を紹介します。&lt;/p></description></item><item><title>Dockerを使ったCLIツール配布</title><link>https://blog.freedom-man.com/docker-cli-distribution.html</link><pubDate>Sun, 07 May 2017 22:58:51 +0000</pubDate><guid>https://blog.freedom-man.com/docker-cli-distribution.html</guid><description>&lt;p>homebrewや&lt;code>curl -sL {url} | sh&lt;/code>などの/usr/local/binに置く以外にもdockerを使って配布できますよ、という備忘録。&lt;/p></description></item><item><title>bashでCLIを作ってみる</title><link>https://blog.freedom-man.com/bash-cli.html</link><pubDate>Wed, 03 May 2017 20:29:39 +0000</pubDate><guid>https://blog.freedom-man.com/bash-cli.html</guid><description>&lt;p>シェルスクリプトでオプション解析もごりごりやるようなCLIツールの作り方の備忘録。シェルスクリプトだけでCLIツールを作るメリットとしては可搬性と、パイプや標準入出力を用いた他のコマンドとの連携がやりやすいことです。&lt;/p></description></item><item><title>PLYでプログラミング言語を作る【グローバル変数】</title><link>https://blog.freedom-man.com/ply-mylang-globalvar.html</link><pubDate>Tue, 02 May 2017 12:00:44 +0000</pubDate><guid>https://blog.freedom-man.com/ply-mylang-globalvar.html</guid><description>&lt;p>lex/yaccでプログラミング言語を作るにはC言語を使う必要があるため、メモリ管理等の面でなかなか敷居が高いです。一方、Pythonでは&lt;a href="http://www.dabeaz.com/ply/" target="_blank" rel="noopener noreferrer">PLY&lt;/a>というlex/yaccのPython実装のライブラリが存在し、簡単にプログラミング言語を作成することができます。ということで、PLYを使ってプログラミング言語を作ってみました。&lt;/p>
&lt;p>今回は以下の機能を作っていきます。サンプルコードは&lt;a href="https://github.com/tzmfreedom/mylang/tree/globalvar" target="_blank" rel="noopener noreferrer">こちら&lt;/a>。&lt;/p>
&lt;ul>
 	&lt;li>ステートメントの順次実行&lt;/li>
 	&lt;li>四則演算&lt;/li>
 	&lt;li>グローバル変数のセット&lt;/li>
&lt;/ul>
ちなみにプログラミング言語作成に関してはドシロートなので色々ご了承ください。</description></item><item><title>apex-mastodon作ってみた</title><link>https://blog.freedom-man.com/apex-mastodon.html</link><pubDate>Tue, 02 May 2017 07:30:22 +0000</pubDate><guid>https://blog.freedom-man.com/apex-mastodon.html</guid><description>&lt;p>久々に、Apexで外部サービスのAPI叩いてみるシリーズ！ということで、&lt;a href="https://github.com/tzmfreedom/apex-mastodon" target="_blank" rel="noopener noreferrer">apex-mastodon&lt;/a>というApexのライブラリを作ってみました。&lt;/p></description></item><item><title>シンプルクローラー gocrawsanを作ってみた</title><link>https://blog.freedom-man.com/gocrawsan.html</link><pubDate>Mon, 01 May 2017 07:30:25 +0000</pubDate><guid>https://blog.freedom-man.com/gocrawsan.html</guid><description>&lt;p>golangでシンプルクローラ &lt;a href="https://github.com/tzmfreedom/gocrawsan" target="_blank" rel="noopener noreferrer">gocrawsan&lt;/a>を作ってみました。ということでツールの紹介です。&lt;/p></description></item><item><title>force.com IDEで既存ディレクトリをプロジェクトとして追加する</title><link>https://blog.freedom-man.com/forcecomide-existed-directory.html</link><pubDate>Sun, 30 Apr 2017 15:08:33 +0000</pubDate><guid>https://blog.freedom-man.com/forcecomide-existed-directory.html</guid><description>&lt;p>antやgit cloneなどで作成したSalesforceのメタデータをforce.com IDEのプロジェクトとしてインポートをしたときの備忘録。retrieveしたモジュール一覧に対して開発を行いたい場合には参考にしていただければ！force.com IDEのバージョンは36.0.0.20160121512 です。&lt;/p></description></item><item><title>RailsでJOINしてORDERしてLIMITをかけたときの挙動</title><link>https://blog.freedom-man.com/activerecord-join-order-limit.html</link><pubDate>Tue, 25 Apr 2017 07:30:48 +0000</pubDate><guid>https://blog.freedom-man.com/activerecord-join-order-limit.html</guid><description>&lt;p>タイトルの通り、JOINしてORDERしてLIMITをかけたら、取得したレコードが期待した結果と違かった。ということで備忘録。Railsのバージョンは4系、5系両方で再現。&lt;/p></description></item><item><title>golangのnet/httpで自動リダイレクトしない方法</title><link>https://blog.freedom-man.com/golang-nethttp-redirect.html</link><pubDate>Tue, 25 Apr 2017 00:14:04 +0000</pubDate><guid>https://blog.freedom-man.com/golang-nethttp-redirect.html</guid><description>&lt;p>net/httpライブラリのhttp.ClientでHTTPレスポンスが3系だとデフォルトで自動リダイレクトする仕様になっている。リダイレクトしたくない場合は、CheckRedirect関数をオーバーライドしてhttp.ErrUseLastResponseを返せばOK。&lt;/p></description></item><item><title>Railsのviewとlayoutの評価順についてコードを読んで納得した</title><link>https://blog.freedom-man.com/rails-view-layout.html</link><pubDate>Mon, 24 Apr 2017 07:30:17 +0000</pubDate><guid>https://blog.freedom-man.com/rails-view-layout.html</guid><description>&lt;p>Railsのviewとlayoutの評価順序はview =&amp;gt; layoutとなっており、viewで定義したcontext_forやprovideはlayout側でyieldすることで利用できるようになっていたり、layout側で引数無しのyieldをすれば評価後のviewのレンダリングが出来るようになっています。&lt;/p>
&lt;p>今回、この挙動をコードレベルで理解したかったので関連する部分のコードリーディングをしてみました。&lt;/p>
&lt;p>Railsのバージョンは5.0.1です。&lt;/p></description></item><item><title>zshの補完関数を作ってみた</title><link>https://blog.freedom-man.com/zsh-completions.html</link><pubDate>Sat, 22 Apr 2017 17:30:58 +0000</pubDate><guid>https://blog.freedom-man.com/zsh-completions.html</guid><description>&lt;p>zshの補完関数を作ったときの備忘録&lt;/p></description></item><item><title>Capistranoコードリーディング [基本]</title><link>https://blog.freedom-man.com/capistrano.html</link><pubDate>Mon, 17 Apr 2017 07:30:28 +0000</pubDate><guid>https://blog.freedom-man.com/capistrano.html</guid><description>&lt;p>&lt;a href="https://github.com/capistrano/capistrano" target="_blank">Capistrano&lt;/a>のコードリーディングをしてみました。今回はCapistranoが利用しているRakeの基本部分の紹介をします。&lt;/p></description></item><item><title>find_each、find_in_batchesとprimary_key</title><link>https://blog.freedom-man.com/find_each-find_in_batches.html</link><pubDate>Mon, 17 Apr 2017 00:00:36 +0000</pubDate><guid>https://blog.freedom-man.com/find_each-find_in_batches.html</guid><description>&lt;p>RailsのActiveRecordのメソッドであるfind_each、find_in_batchesとprimary_keyの備忘録。両メソッドの詳しい説明に関しては参考URLを参照してくださいー。&lt;/p></description></item><item><title>read_fragmentとフラグメントキャッシュ</title><link>https://blog.freedom-man.com/read_fragment.html</link><pubDate>Sun, 16 Apr 2017 23:00:54 +0000</pubDate><guid>https://blog.freedom-man.com/read_fragment.html</guid><description>&lt;p>Railsのフラグメントキャッシュでビュー側にcacheメソッド、コントローラ側にread_fragmentメソッドを利用するように書かれている記事があるけど併用すると害があるケースがありそうだったので備忘録。&lt;/p></description></item><item><title>ダミーデータを大量に作成するCLIツールdmyを作ってみた</title><link>https://blog.freedom-man.com/dmy-cli.html</link><pubDate>Mon, 10 Apr 2017 07:30:25 +0000</pubDate><guid>https://blog.freedom-man.com/dmy-cli.html</guid><description>&lt;p>パフォーマンステスト等の用途でダミーデータを大量に作成しないといけない局面があり、今までシェルスクリプトで作ったりRubyスクリプト叩いたりしてたんですが、&lt;/p>
&lt;ul>
 	&lt;li>シェルスクリプトは他のコマンドを組み合わせるとコストが高くなりがち。
&lt;ul>
 	&lt;li>他のコマンドを組み合わせて利用できる柔軟性はあるものの、コマンド実行は別のシェル、プロセスを立ち上げることになるのでコストが高い&lt;/li>
&lt;/ul>
&lt;/li>
 	&lt;li>LLだと気軽かつそれなりの速度でデータを生成できるが、いちいちスニペットを作成する必要があるため面倒。&lt;/li>
 	&lt;li>ダミーデータを作成するWebサービスはたくさんあるのですが、CLIツールはあまり無く、手元で作れたほうが効率的な場面がある&lt;/li>
&lt;/ul>
ということで、手軽にダミーデータを作成するCLIツールの"dmy"をgolangで作ってみました。
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/dmy" target="_blank">tzmfreedom/dmy: Command line interface to create dummy data&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>ActiveRecordのint型項目の最大値超過エラーについて</title><link>https://blog.freedom-man.com/activerecord-maxint.html</link><pubDate>Thu, 06 Apr 2017 07:30:45 +0000</pubDate><guid>https://blog.freedom-man.com/activerecord-maxint.html</guid><description>&lt;p>ActiveRecordでinteger型の項目をマイグレして、int型の最大値以上の数を入れて保存しようとすると、モデル側で以下のエラーが出ます。&lt;/p>
&lt;pre tabindex="0">&lt;code>ActiveModel::RangeError: 2147483648 is out of range for ActiveModel::Type::Integer with limit 4
&lt;/code>&lt;/pre>&lt;p>最大値のエラーなのでエラー自体には納得なんですが、この手のエラーはバリデーションでerrorsに格納してほしいなーと思い、ソースコードを読んでみました。&lt;/p></description></item><item><title>golang標準ライブラリから学ぶタイムゾーンファイルの構造</title><link>https://blog.freedom-man.com/golang-timezonefile.html</link><pubDate>Wed, 05 Apr 2017 07:30:03 +0000</pubDate><guid>https://blog.freedom-man.com/golang-timezonefile.html</guid><description>&lt;p>今回はタイムゾーンファイルの構造をgolang標準ライブラリのloadZoneData関数から勉強してみました。&lt;/p></description></item><item><title>乃木坂46/欅坂46のCLIツールを作ってみた</title><link>https://blog.freedom-man.com/nogi-keyaki-cli.html</link><pubDate>Tue, 04 Apr 2017 07:30:19 +0000</pubDate><guid>https://blog.freedom-man.com/nogi-keyaki-cli.html</guid><description>&lt;p>乃木坂46/欅坂46のCLIツールを作ってみました。&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/nogi" target="_blank">tzmfreedom/nogi: Nogizaka 46 Command Line Interface&lt;/a>&lt;/li>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/keyaki" target="_blank">tzmfreedom/keyaki: Keyakizaka 46 Command Line Interface&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Rubyプロセスの使用メモリ量の計測</title><link>https://blog.freedom-man.com/measure-ruby-memory-usage.html</link><pubDate>Tue, 04 Apr 2017 00:30:21 +0000</pubDate><guid>https://blog.freedom-man.com/measure-ruby-memory-usage.html</guid><description>&lt;p>Rubyプロセスの使用メモリ量を計測したときの備忘録&lt;/p></description></item><item><title>golangでgaroonのCLIツールgoroonを作ってみた</title><link>https://blog.freedom-man.com/garoon-cli-goroon.html</link><pubDate>Mon, 03 Apr 2017 07:30:24 +0000</pubDate><guid>https://blog.freedom-man.com/garoon-cli-goroon.html</guid><description>&lt;p>Garoonのスケジュール通知がmacOSではデフォルトで付いていなかったりして個人的に不便だったので、garoonのCLIツールをgolangで作ってみました。&lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/goroon" target="_blank">tzmfreedom/goroon: Cybozu garoon library and command line interface by golang&lt;/a>&lt;/p></description></item><item><title>golangのtimeライブラリでタイムゾーン変換</title><link>https://blog.freedom-man.com/golang-time-zone.html</link><pubDate>Sun, 02 Apr 2017 13:30:32 +0000</pubDate><guid>https://blog.freedom-man.com/golang-time-zone.html</guid><description>&lt;p>自分用メモ。&lt;/p></description></item><item><title>Homebrewの独自リポジトリをGithub Contents APIで自動更新する</title><link>https://blog.freedom-man.com/homebrew-autoupdate-githubapi.html</link><pubDate>Mon, 27 Mar 2017 07:30:55 +0000</pubDate><guid>https://blog.freedom-man.com/homebrew-autoupdate-githubapi.html</guid><description>&lt;p>HomebrewのFormulaを更新する場合&lt;/p>
&lt;ul>
 	&lt;li>Formulaのバージョン&lt;/li>
 	&lt;li>ダウンロードするファイルのSHA256&lt;/li>
&lt;/ul>
&lt;p>を変更する必要があります。毎回手作業でやるには面倒な上に、Travis CIなどでバイナリをビルドしてGithubのReleasesページに自動アップロードする処理を書いていたりすると、tarコマンド（GNU or BSD）やアーカイブ時間、UID/GIDの差異によって、tar.gzのバイナリが変わってしまうためハッシュ値取得のところでハマりやすいです。例えば、macOSで作成したtar.gzのハッシュ値とTravisの環境で作成したハッシュ値が異なるので、macOSからFormulaをgit commit/pushで更新する場合は、GithubのReleasesページからダウンロードしてきたものに対してハッシュ値を取る必要があります。&lt;/p>
&lt;p>ということで今回はTravis CIでHomebrewの独自リポジトリを&lt;a href="https://developer.github.com/v3/repos/contents/" target="_blank">Github Contents API&lt;/a>を使って自動更新する方法を紹介します。&lt;/p>
&lt;p>Makefileや.travis.ymlの設定はこちらのリポジトリも参考にしてもらえればと思います↓
&lt;a href="https://github.com/tzmfreedom/goroon" target="_blank">tzmfreedom/goroon: Cybozu garoon library and command line interface by golang&lt;/a>&lt;/p></description></item><item><title>Vagrantでawait_response_stateエラー</title><link>https://blog.freedom-man.com/vagrant-await_response_state.html</link><pubDate>Sun, 26 Mar 2017 22:25:27 +0000</pubDate><guid>https://blog.freedom-man.com/vagrant-await_response_state.html</guid><description>&lt;p>vagrant upしたら以下のネットワークエラーが発生し、仮想OS自体は立ち上がるものの共有フォルダの機能が利用できなくなりました。&lt;/p>
&lt;pre tabindex="0">&lt;code>==&amp;gt; default: Configuring and enabling network interfaces...
/opt/vagrant/embedded/gems/gems/net-scp-1.1.2/lib/net/scp.rb:392:in `await_response_state&amp;#39;: hogehoge (RuntimeError)
&lt;/code>&lt;/pre></description></item><item><title>sshrcコードリーディング</title><link>https://blog.freedom-man.com/sshrc.html</link><pubDate>Mon, 13 Mar 2017 07:30:19 +0000</pubDate><guid>https://blog.freedom-man.com/sshrc.html</guid><description>&lt;p>&lt;a href="https://github.com/Russell91/sshrc" target="_blank">sshrc&lt;/a>のコードリーディングをしてみました。&lt;/p></description></item><item><title>HammerSpoonでアプリのフォーカス切り替えをHotKeyで実現する</title><link>https://blog.freedom-man.com/hammerspoon-hotkey.html</link><pubDate>Wed, 08 Mar 2017 00:24:03 +0000</pubDate><guid>https://blog.freedom-man.com/hammerspoon-hotkey.html</guid><description>&lt;p>HotKeyでのアクションはmacOSの場合はAutomatorを使うことが多いと思いますが、&lt;a href="http://www.hammerspoon.org/" target="_blank">HammerSpoon&lt;/a>でアプリのフォーカル切り替えを実現するには、init.luaにこんな感じで書けばOK。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-lua" data-lang="lua">&lt;span style="display:flex;">&lt;span>hs.hotkey&lt;span style="color:#1f2328">.&lt;/span>bind&lt;span style="color:#1f2328">({&lt;/span>&lt;span style="color:#0a3069">&amp;#34;alt&amp;#34;&lt;/span>&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#0a3069">&amp;#34;J&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hs.application&lt;span style="color:#1f2328">.&lt;/span>launchOrFocus&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;IntelliJ IDEA 15&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey&lt;span style="color:#1f2328">.&lt;/span>bind&lt;span style="color:#1f2328">({&lt;/span>&lt;span style="color:#0a3069">&amp;#34;alt&amp;#34;&lt;/span>&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#0a3069">&amp;#34;E&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hs.application&lt;span style="color:#1f2328">.&lt;/span>launchOrFocus&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Evernote&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey&lt;span style="color:#1f2328">.&lt;/span>bind&lt;span style="color:#1f2328">({&lt;/span>&lt;span style="color:#0a3069">&amp;#34;alt&amp;#34;&lt;/span>&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#0a3069">&amp;#34;C&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hs.application&lt;span style="color:#1f2328">.&lt;/span>launchOrFocus&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Google Chrome&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hs.hotkey&lt;span style="color:#1f2328">.&lt;/span>bind&lt;span style="color:#1f2328">({&lt;/span>&lt;span style="color:#0a3069">&amp;#34;alt&amp;#34;&lt;/span>&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#0a3069">&amp;#34;S&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> hs.application&lt;span style="color:#1f2328">.&lt;/span>launchOrFocus&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Slack&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">end&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>個人的にはHammerSpoonの方がスクリプト一発で書けるので好み。&lt;/p></description></item><item><title>golang標準ライブラリから学ぶzipファイルの構造</title><link>https://blog.freedom-man.com/zip-structure-golang.html</link><pubDate>Mon, 27 Feb 2017 07:30:54 +0000</pubDate><guid>https://blog.freedom-man.com/zip-structure-golang.html</guid><description>&lt;p>zipファイルの構造をgolangの標準ライブラリから勉強してみました。&lt;/p></description></item><item><title>Travis CIでgolangのテストを行う</title><link>https://blog.freedom-man.com/travis-ci-golang.html</link><pubDate>Sun, 26 Feb 2017 21:32:55 +0000</pubDate><guid>https://blog.freedom-man.com/travis-ci-golang.html</guid><description>&lt;p>Travis CIでgolangのテストを回したいときの.travis.ymlの設定についての備忘録。&lt;/p></description></item><item><title>Expeditorコードリーディング</title><link>https://blog.freedom-man.com/expeditor-codereading.html</link><pubDate>Tue, 31 Jan 2017 07:30:02 +0000</pubDate><guid>https://blog.freedom-man.com/expeditor-codereading.html</guid><description>&lt;p>cookpadさんの&lt;a href="https://github.com/cookpad/expeditor" target="_blank">Expeditor&lt;/a>のコードリーディングをしてみました。&lt;/p></description></item><item><title>macOSで起動時にvagrant upする</title><link>https://blog.freedom-man.com/macosx-vagrantup.html</link><pubDate>Thu, 26 Jan 2017 22:00:12 +0000</pubDate><guid>https://blog.freedom-man.com/macosx-vagrantup.html</guid><description>&lt;p>開発環境のvagrantを毎回vagrant upするのが面倒だったのでlaunchctlでOS X起動時にvagrant upしてみました。&lt;/p></description></item><item><title>Herokuの静的ファイルホスティングのベンチマーク</title><link>https://blog.freedom-man.com/heroku-static-benchmark.html</link><pubDate>Thu, 26 Jan 2017 21:30:15 +0000</pubDate><guid>https://blog.freedom-man.com/heroku-static-benchmark.html</guid><description>&lt;p>Free Dynoで静的ファイルホスティングのベンチマークを取ってみました。&lt;/p></description></item><item><title>Arproxyコードリーディング</title><link>https://blog.freedom-man.com/arproxy-codereading.html</link><pubDate>Thu, 26 Jan 2017 07:30:15 +0000</pubDate><guid>https://blog.freedom-man.com/arproxy-codereading.html</guid><description>&lt;p>cookpadさんの&lt;a href="https://github.com/cookpad/arproxy" target="_blank">Arproxy&lt;/a>のソースコードリーディングをしました。&lt;/p></description></item><item><title>zshとか便利コマンドあれこれ</title><link>https://blog.freedom-man.com/zsh-command.html</link><pubDate>Tue, 24 Jan 2017 07:30:56 +0000</pubDate><guid>https://blog.freedom-man.com/zsh-command.html</guid><description>&lt;p>zshやら便利コマンドのあれこれ備忘録。alias書いたり.zshrc読み書きする用。&lt;/p></description></item><item><title>macOS Sierraでキーリマップする</title><link>https://blog.freedom-man.com/macos-sierra-keyremap.html</link><pubDate>Mon, 23 Jan 2017 07:30:36 +0000</pubDate><guid>https://blog.freedom-man.com/macos-sierra-keyremap.html</guid><description>&lt;p>macOS Sierraでvimで Ctrl-[ でコマンドモードに抜けるときにIMEを無効化する処理を&lt;a href="http://www.hammerspoon.org/" target="_blank">Hammerspoon&lt;/a>を使って設定してみました。&lt;/p></description></item><item><title>macOSでGNU dateを使う</title><link>https://blog.freedom-man.com/macos-gnudate.html</link><pubDate>Sat, 21 Jan 2017 07:30:19 +0000</pubDate><guid>https://blog.freedom-man.com/macos-gnudate.html</guid><description>&lt;p>macOSで初期にインストールされているdateコマンドはBSDバージョンなので、GNUバージョンを使うには以下のコマンドでインストールすればOK。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span> $ brew install coreutils
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>このままだとgdateと打たないといけないので、dateコマンドとして使いたい場合はrcスクリプトに以下のaliasを張っておけば良い。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">alias&lt;/span> &lt;span style="color:#953800">date&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;gdate&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>ActiveModelのバリデーションメッセージのキー値を日本語化する</title><link>https://blog.freedom-man.com/activemodel-validation-message.html</link><pubDate>Tue, 10 Jan 2017 07:30:37 +0000</pubDate><guid>https://blog.freedom-man.com/activemodel-validation-message.html</guid><description>&lt;p>ActiveModelをインクルードしたクラスでvalidationでエラーにする場合、項目の名前をconfig/locales/**.ymlに設定してあげないとキーの値がそのまま出てしまう（正確にはアンダースコアがスペースに置換される）&lt;/p></description></item><item><title>lastpass-cli触ってみた</title><link>https://blog.freedom-man.com/lastpass-cli.html</link><pubDate>Thu, 05 Jan 2017 07:30:52 +0000</pubDate><guid>https://blog.freedom-man.com/lastpass-cli.html</guid><description>&lt;p>&lt;a href="https://www.lastpass.com/" target="_blank">Lastpass&lt;/a>が公開している公式のコマンドラインツールである&lt;a href="https://github.com/lastpass/lastpass-cli" target="_blank">lastpass-cli&lt;/a>を試してみました！&lt;/p></description></item><item><title>2017</title><link>https://blog.freedom-man.com/2017.html</link><pubDate>Sun, 01 Jan 2017 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2017.html</guid><description/></item><item><title>今年の振り返り〜2016年〜</title><link>https://blog.freedom-man.com/2016-summary.html</link><pubDate>Sat, 31 Dec 2016 14:00:29 +0000</pubDate><guid>https://blog.freedom-man.com/2016-summary.html</guid><description>&lt;p>&amp;ldquo;技術&amp;quot;とか&amp;quot;仕事&amp;quot;とかそういった文脈で2016年を振り返ってみたり。&lt;/p></description></item><item><title>golangでCLIを作ったときの備忘録</title><link>https://blog.freedom-man.com/golang-cli.html</link><pubDate>Thu, 22 Dec 2016 07:30:50 +0000</pubDate><guid>https://blog.freedom-man.com/golang-cli.html</guid><description>&lt;p>先日、&lt;a href="https://blog.freedom-man.com/gowsdl-salesforce-soap-api/" target="_blank">SPM&lt;/a>というコマンドラインツールをリリースしましたが、golangでコマンドラインツールを作成する上で便利だったツールや考え方等を備忘として残します。&lt;/p></description></item><item><title>SourceTreeで隠しディレクトリ内のパスを指定して新規リポジトリを作成する方法</title><link>https://blog.freedom-man.com/sourcetree-hiddenpath.html</link><pubDate>Wed, 21 Dec 2016 07:30:11 +0000</pubDate><guid>https://blog.freedom-man.com/sourcetree-hiddenpath.html</guid><description>&lt;p>タイトルの通り、隠しディレクトリ内のパスを指定したい、というときの方法について。&lt;/p></description></item><item><title>gowsdlでSalesforceのSOAP APIを叩く</title><link>https://blog.freedom-man.com/gowsdl-salesforce-soap-api.html</link><pubDate>Tue, 20 Dec 2016 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/gowsdl-salesforce-soap-api.html</guid><description>&lt;p>今回はgowsdlを使ってSalesforceのSOAP APIを叩いてみます。&lt;/p>
&lt;h2 id="gowsdlの使い方">gowsdlの使い方&lt;/h2>
&lt;p>こんな感じでコマンドを叩けばOK&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ gowsdl &lt;span style="color:#0550ae">{&lt;/span>URL&lt;span style="color:#0550ae">}&lt;/span> // -p で出力先ディレクトリを変更する
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ローカルファイルは読み込んでくれないので、Web上に置く必要があります。Salesforceの各種WSDLはWeb上にあるものの、いずれも認証を必要とするので、ダウンロードしたWSDLをS3にPublicなオブジェクトとしてデータをアップロードしたりする必要があります。ただし、Enterprise WSDLはスキーマ情報がそのまま乗るので取扱には注意です。試してませんがローカルにサーバ立てて、そこで配信するのが手軽でセキュアかも。&lt;/p>
&lt;p>partner.wsdlでやってみるとこんな感じでエラーが出ます。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ gowsdl -p partner https://s3-ap-northeast-1.amazonaws.com/{BUCKET}/partner.wsdl

　　Downloading file https://s3-ap-northeast-1.amazonaws.com/{BUCKET}partner.wsdl
　　Downloading external schema location 
　　https://s3-ap-northeast-1.amazonaws.com/{BUCKET}/partner.wsdl
　　expected element type schema but have definitions
&lt;/code>&lt;/pre>&lt;p>gowsdlはシングルバイナリなので、デバッグ仕込んだりすることは出来ませんが、ベースとなっているソースコードを直接いじることで原因を調査することができます。&lt;/p>
&lt;pre tabindex="0">&lt;code>$ go run $GOPATH/src/github.com/hooklift/gowsdl/cmd/gowsdl/main.go \
 https://s3-ap-northeast-1.amazonaws.com/{BUCKET}/partner.wsdl
&lt;/code>&lt;/pre>&lt;p>ということで、ここらへんをコメントアウトして無理矢理動かします（白目）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-diff" data-lang="diff">&lt;span style="display:flex;">&lt;span>diff --git a/gowsdl.go b/gowsdl.go
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>index e136e27..6464a7d 100644
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#82071e;background-color:#ffebe9">--- a/gowsdl.go
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#82071e;background-color:#ffebe9">&lt;/span>&lt;span style="color:#116329;background-color:#dafbe1">+++ b/gowsdl.go
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#116329;background-color:#dafbe1">&lt;/span>@@ -176,9 +176,9 @@ func (g *GoWSDL) unmarshal() error {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> for _, schema := range g.wsdl.Types.Schemas {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> err = g.resolveXSDExternals(schema, parsedURL)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#82071e;background-color:#ffebe9">- if err != nil {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#82071e;background-color:#ffebe9">- return err
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#82071e;background-color:#ffebe9">- }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#82071e;background-color:#ffebe9">&lt;/span>&lt;span style="color:#116329;background-color:#dafbe1">+ // if err != nil {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#116329;background-color:#dafbe1">+ // return err
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#116329;background-color:#dafbe1">+ // }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#116329;background-color:#dafbe1">&lt;/span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> return nil
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これでとりあえずクライアントは自動生成できます。自動生成されたパッケージを少し修正して動かしてみます。
まずはパッケージ名をmainに変更します。&lt;/p></description></item><item><title>ログインシェル変更時にSSHでPermission deniedと言われたときの対処法</title><link>https://blog.freedom-man.com/ssh-permission-denied.html</link><pubDate>Mon, 19 Dec 2016 07:30:13 +0000</pubDate><guid>https://blog.freedom-man.com/ssh-permission-denied.html</guid><description>&lt;p>仮想環境上のzshのバージョンを上げるために、ソースコードからインストールし、再度SSHでログインしようとしたときに以下のエラーが発生した。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ vagrant ssh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Permission denied &lt;span style="color:#0550ae">(&lt;/span>publickey,gssapi-keyex,gssapi-with-mic,password&lt;span style="color:#0550ae">)&lt;/span>.
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Salesforce Package Manager "SPM"を作ってみた</title><link>https://blog.freedom-man.com/salesforce-package-manager-spm.html</link><pubDate>Mon, 12 Dec 2016 00:05:02 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-package-manager-spm.html</guid><description>&lt;p>Salesforceのパッケージ管理システム&amp;quot;SPM&amp;quot;をリリースしましたー&lt;/p>
&lt;ul>
 	&lt;li>&lt;a href="https://github.com/tzmfreedom/spm" target="_blank">tzmfreedom/spm: Salesforce Package Manager&lt;/a>&lt;/li>
&lt;/ul>
一応マルチプラットフォーム対応で、バイナリも配布しているので是非お試しください。マルチプラットフォーム対応を謳っておきながらwindowsでの動作は全くの未確認（！）なので、不具合があればissueやらPRやらお願い致しますー。</description></item><item><title>LINE Messaging APIを触ってみた</title><link>https://blog.freedom-man.com/line-messaging-api.html</link><pubDate>Tue, 15 Nov 2016 07:30:20 +0000</pubDate><guid>https://blog.freedom-man.com/line-messaging-api.html</guid><description>&lt;p>&lt;a href="https://business.line.me/ja/services/bot" target="_blank">LINE Messaging API&lt;/a>を触ってみました。ということで備忘録。&lt;/p></description></item><item><title>UNIX V6コードリーディング備忘録　その１</title><link>https://blog.freedom-man.com/unix-v6-1.html</link><pubDate>Mon, 14 Nov 2016 07:30:26 +0000</pubDate><guid>https://blog.freedom-man.com/unix-v6-1.html</guid><description>&lt;p>&lt;a href="https://www.amazon.co.jp/dp/4774154644" target="_blank">はじめてのOSコードリーディング UNIX V6で学ぶカーネルのしくみ&lt;/a>が面白すぎたので備忘録。&lt;/p>
&lt;p>今回は2章 プロセス、3章 プロセスの制御、7章 ブロックデバイスサブシステム、9章ファイルシステムを対象に書いていきます。&lt;/p></description></item><item><title>HomeBrewのFormulaを作ってみた</title><link>https://blog.freedom-man.com/homebrew-formula.html</link><pubDate>Fri, 11 Nov 2016 07:30:19 +0000</pubDate><guid>https://blog.freedom-man.com/homebrew-formula.html</guid><description>&lt;p>HomeBrewのFormulaを作ってみました。ということで備忘録。&lt;/p></description></item><item><title>PHPのextensionを作ってみた</title><link>https://blog.freedom-man.com/php-extension.html</link><pubDate>Thu, 10 Nov 2016 07:30:13 +0000</pubDate><guid>https://blog.freedom-man.com/php-extension.html</guid><description>&lt;p>PHPのextensionをCで直接書く方法（公式）と&lt;a href="https://zephir-lang.com/" target="_blank">Zephir&lt;/a>で書く方法の２パターンで作ってみました。&lt;/p></description></item><item><title>phpのセッション管理あれこれ</title><link>https://blog.freedom-man.com/php-session.html</link><pubDate>Tue, 08 Nov 2016 07:30:42 +0000</pubDate><guid>https://blog.freedom-man.com/php-session.html</guid><description>&lt;p>PHPのセッションの管理方法に関する備忘録。&lt;/p></description></item><item><title>俺のためのtmuxまとめ</title><link>https://blog.freedom-man.com/tmux.html</link><pubDate>Mon, 07 Nov 2016 07:30:41 +0000</pubDate><guid>https://blog.freedom-man.com/tmux.html</guid><description>&lt;p>俺のためにtmuxの操作方法と設定方法をまとめました。tmuxはバージョン2.3を使用。&lt;/p></description></item><item><title>IntelliJのDatabaseビューの便利機能</title><link>https://blog.freedom-man.com/intellij-databaseview.html</link><pubDate>Fri, 04 Nov 2016 07:30:43 +0000</pubDate><guid>https://blog.freedom-man.com/intellij-databaseview.html</guid><description>&lt;p>IntelliJのDatabaseビューが便利すぎたという備忘録&lt;/p></description></item><item><title>DigitalOceanのUbuntuでphp5.6-fpmを入れる</title><link>https://blog.freedom-man.com/ubuntu-php56-fpm.html</link><pubDate>Thu, 03 Nov 2016 07:30:58 +0000</pubDate><guid>https://blog.freedom-man.com/ubuntu-php56-fpm.html</guid><description>&lt;p>DigitalOceanのUbuntu 14.04やUbuntu 16.04でphp5.6のphp-fpmをインストールするときの備忘録。&lt;/p></description></item><item><title>Apache+mod_phpなwordpressをh2o+php-fpmに置き換えた</title><link>https://blog.freedom-man.com/wordpress-h2o-phpfpm.html</link><pubDate>Wed, 02 Nov 2016 07:30:15 +0000</pubDate><guid>https://blog.freedom-man.com/wordpress-h2o-phpfpm.html</guid><description>&lt;p>H2Oの勉強がてらブログのアーキテクチャをApache + mod_phpからH2O + php-fpmの構成に変えてみました。ということで今回は移行に関する備忘録。&lt;/p></description></item><item><title>初心者がRails+DeviseでTodoアプリ作る【Omniauth編】</title><link>https://blog.freedom-man.com/rails-devise-omniauth.html</link><pubDate>Tue, 01 Nov 2016 07:30:13 +0000</pubDate><guid>https://blog.freedom-man.com/rails-devise-omniauth.html</guid><description>&lt;p>&lt;a href="https://github.com/omniauth/omniauth" target="_blank">Omuniauth&lt;/a>を使ってRailsアプリにソーシャルサインオンの機能を追加してみました。&lt;/p></description></item><item><title>H2OでHTTP/2を体感する</title><link>https://blog.freedom-man.com/h2o-http2.html</link><pubDate>Fri, 28 Oct 2016 07:30:36 +0000</pubDate><guid>https://blog.freedom-man.com/h2o-http2.html</guid><description>&lt;p>HTTP/2対応のWebサーバソフトウェアである&lt;a href="https://github.com/h2o/h2o" target="_blank">h2o&lt;/a>を試してみました。&lt;/p></description></item><item><title>よく使うHerokuコマンドまとめ</title><link>https://blog.freedom-man.com/herokucommand.html</link><pubDate>Thu, 27 Oct 2016 07:30:32 +0000</pubDate><guid>https://blog.freedom-man.com/herokucommand.html</guid><description>&lt;p>よく使うHerokuコマンドの備忘録&lt;/p></description></item><item><title>launchdでデーモンやスケジュールタスクを管理する</title><link>https://blog.freedom-man.com/launchd-daemon-task.html</link><pubDate>Wed, 26 Oct 2016 07:30:24 +0000</pubDate><guid>https://blog.freedom-man.com/launchd-daemon-task.html</guid><description>&lt;p>Linuxだとserviceやcronを使いますが、OSXだとlaunchctlを使うようです。ということで、launchctl（launchd）の使い方を備忘としてまとめました。&lt;/p></description></item><item><title>MetaMindのRuby Clientをリリースしました</title><link>https://blog.freedom-man.com/metamind-ruby-client.html</link><pubDate>Tue, 25 Oct 2016 07:30:45 +0000</pubDate><guid>https://blog.freedom-man.com/metamind-ruby-client.html</guid><description>&lt;p>&lt;a href="http://metamind.io/" target="_blank">MetaMind&lt;/a>のRuby Clientが無かったので作っちゃいました。&lt;/p>
&lt;ul>
	&lt;li>&lt;a href="https://rubygems.org/gems/metamind" target="_blank">metamind | RubyGems.org | your community gem host
&lt;/a>&lt;/li>
	&lt;li>&lt;a href="https://github.com/tzmfreedom/metamind-ruby" target="_blank">tzmfreedom/metamind-ruby: API Client for Salesforce MetaMind&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>秘密鍵、公開鍵、証明書、CSR生成のOpenSSLコマンドまとめ</title><link>https://blog.freedom-man.com/openssl-command.html</link><pubDate>Mon, 24 Oct 2016 07:30:34 +0000</pubDate><guid>https://blog.freedom-man.com/openssl-command.html</guid><description>&lt;p>よくある秘密鍵生成のコマンドまとめ&lt;/p>
&lt;p>なお、OpenSSLのコマンドの使い方はサブコマンドのmanページを見るのが手っ取り早いです。&lt;/p></description></item><item><title>Apache BenchでConnection Refusedエラー</title><link>https://blog.freedom-man.com/apache-bench-connection-refused.html</link><pubDate>Thu, 13 Oct 2016 07:30:38 +0000</pubDate><guid>https://blog.freedom-man.com/apache-bench-connection-refused.html</guid><description>&lt;p>Apache Benchで以下のコマンドを入力したらエラーになった。&lt;/p></description></item><item><title>初心者がRails+DeviseでTodoアプリ作る【RSpec・Travis CI・Rubocop】</title><link>https://blog.freedom-man.com/rails-rspec-travis-rubocop.html</link><pubDate>Wed, 12 Oct 2016 07:30:39 +0000</pubDate><guid>https://blog.freedom-man.com/rails-rspec-travis-rubocop.html</guid><description>&lt;p>前回は認証までだったので、今回はテストコード関連の以下のタスクをやっていきます。&lt;/p>
&lt;ul>
	&lt;li>Rubocopによる静的コードチェック&lt;/li>
	&lt;li>RSpecによるテストコード作成&lt;/li>
	&lt;li>TravisCIによるCI&lt;/li>
&lt;/ul></description></item><item><title>ActiveRecordのpreload, includes, eager_load</title><link>https://blog.freedom-man.com/preload-includes-eager_load.html</link><pubDate>Tue, 11 Oct 2016 07:30:08 +0000</pubDate><guid>https://blog.freedom-man.com/preload-includes-eager_load.html</guid><description>&lt;p>よくあるpreload, includes, eager_loadの違いについて実際に打ってみて確認してみた。今回はuserレコードがtaskレコードに対して1対多のERにおいてuserとそれに紐づくtaskを取得するようなクエリの挙動を確認します。&lt;/p></description></item><item><title>Salesforce MetaMind試してみた【QUICK START編】</title><link>https://blog.freedom-man.com/salesforce-metamind.html</link><pubDate>Thu, 06 Oct 2016 07:30:56 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-metamind.html</guid><description>&lt;p>今年もDreamforceが始まりましたね！今年は現地には居ませんが、タイムラインを見て気になったサービスを試してみたいと思います。ということで、今回は&lt;a href="http://metamind.io/" target="_blank">Salesforce MetaMind&lt;/a>を試してみました。&lt;/p></description></item><item><title>IntelliJからHeroku Postgresに接続する</title><link>https://blog.freedom-man.com/intellij-heroku-postgres.html</link><pubDate>Wed, 05 Oct 2016 07:30:20 +0000</pubDate><guid>https://blog.freedom-man.com/intellij-heroku-postgres.html</guid><description>&lt;p>IntelliJのDatabase ConsoleでHeroku Postgresに接続するときの備忘録&lt;/p></description></item><item><title>RubyでPostgreSQLのレコードをCSV出力してみた</title><link>https://blog.freedom-man.com/ruby-postgresql-csv.html</link><pubDate>Tue, 04 Oct 2016 07:30:54 +0000</pubDate><guid>https://blog.freedom-man.com/ruby-postgresql-csv.html</guid><description>&lt;p>RubyでPostgreSQLのレコードをCSV出力したときの備忘録。PostgreSQLの場合、psqlでCOPY文を投げればCSV化してくれますが、一部を変数に置き換えたり、条件を柔軟に切り替えたり、自動化するにはやはりプログラムからSQLを投げるのが良かったりします。&lt;/p></description></item><item><title>Soapforce使ってみた</title><link>https://blog.freedom-man.com/soapforce-ruby.html</link><pubDate>Sun, 02 Oct 2016 07:30:17 +0000</pubDate><guid>https://blog.freedom-man.com/soapforce-ruby.html</guid><description>&lt;p>Ruby製のSalesforce APIクライアントの&lt;a href="https://github.com/TinderBox/soapforce" target="_blank">Soapforce&lt;/a>を使ってみました。名前の通り、SOAP APIで実装されています。&lt;/p>
&lt;p>Ruby製の APIクライアントだと&lt;a href="https://github.com/ejholmes/restforce" target="_blank">restforce&lt;/a>が有名だと思いますが、今回はバルク処理をどうしても行いたかったため、Soapforceを使ってみました。winter16でREST APIの&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobject_tree.htm" target="_blank">SObject Tree&lt;/a>が正式リリースされたので、そっちを使ってもOKですが…。&lt;/p></description></item><item><title>ActiveAdmin触ってみた</title><link>https://blog.freedom-man.com/activeadmin.html</link><pubDate>Thu, 29 Sep 2016 07:30:43 +0000</pubDate><guid>https://blog.freedom-man.com/activeadmin.html</guid><description>&lt;p>Railsのお勉強シリーズ。今回は管理用の画面を簡単に作成できちゃう&lt;a href="https://github.com/activeadmin/activeadmin" target="_blank">Active Admin&lt;/a>を試してみます。
詳細な使い方は&lt;a href="http://activeadmin.info/" target="_blank">activeadmin.info&lt;/a>はout of dateなので&lt;a href="https://github.com/activeadmin/activeadmin/tree/master/docs" target="_blank">githubのdoc&lt;/a>を見ることになります。
今回は、Rubyは2.2.4、Railsは5系を使いました。&lt;/p></description></item><item><title>Settingslogicコードリーディング</title><link>https://blog.freedom-man.com/settingslogic-codereading.html</link><pubDate>Wed, 28 Sep 2016 07:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/settingslogic-codereading.html</guid><description>&lt;p>Rubyのお勉強がてら、&lt;a href="https://github.com/binarylogic/settingslogic" target="_blank">Settingslogic&lt;/a>のコードリーディングをしてみました。&lt;/p></description></item><item><title>gRPCを触ってみた</title><link>https://blog.freedom-man.com/grpc.html</link><pubDate>Tue, 27 Sep 2016 07:30:18 +0000</pubDate><guid>https://blog.freedom-man.com/grpc.html</guid><description>&lt;p>&lt;a href="http://www.grpc.io/" target="_blank">gRPC&lt;/a>はRPCのフレームワークの一つです。SOAPと同じ分類になりますが、SOAPとの違いは以下になります。&lt;/p>
&lt;ul>
	&lt;li>IDLの記述が容易（かつ人間が読める）&lt;/li>
	&lt;li>コードジェネレータにより様々な言語に対応&lt;/li>
	&lt;li>プロトコルはHTTP/2&lt;/li>
	&lt;li>デフォルトではメッセージフォーマットとして&lt;a href="https://developers.google.com/protocol-buffers/" target="_blank">ProtocolBuffers&lt;/a>を利用するため、シリアライズ、デシリアライズが高速&lt;/li>
&lt;/ul>
ということで今回はRubyとPythonでgRPCなサーバ、クライアントを作成してみました。</description></item><item><title>GrapeでTodoアプリなAPIを作ってみた【OAuth2.0対応まで】</title><link>https://blog.freedom-man.com/grape-todo-api.html</link><pubDate>Mon, 26 Sep 2016 07:30:16 +0000</pubDate><guid>https://blog.freedom-man.com/grape-todo-api.html</guid><description>&lt;p>TodoアプリなAPIサーバをRubyのWAFである&lt;a href="https://github.com/ruby-grape/grape" target="_blank">Grape&lt;/a>で作ってみました。&lt;/p>
&lt;p>利用技術はこんな感じ↓&lt;/p>
&lt;ul>
	&lt;li>APIフレームワーク => &lt;a href="https://github.com/ruby-grape/grape" target="_blank">Grape&lt;/a>（Railsにマウント）&lt;/li>
	&lt;li>認証用の画面 => Rails + &lt;a href="https://github.com/plataformatec/devise" target="_blank">Devise&lt;/a>&lt;/li>
	&lt;li>OAuth2.0 => &lt;a href="https://github.com/doorkeeper-gem/doorkeeper" target="_blank">doorkeeper
&lt;/a>&lt;/li>
&lt;/ul>
Rubyは2.2.4、Railsは5.0.0.1です。</description></item><item><title>MessagePackを触ってみた</title><link>https://blog.freedom-man.com/messagepack.html</link><pubDate>Fri, 23 Sep 2016 07:30:16 +0000</pubDate><guid>https://blog.freedom-man.com/messagepack.html</guid><description>&lt;p>&lt;a href="http://msgpack.org/" target="_blank">MessagePack&lt;/a>とはシリアライズ（バイナリエンコード）の方法の一つで&lt;/p>
&lt;ul>
	&lt;li>シリアライズ/デシリアライズが高速&lt;/li>
	&lt;li>シリアライズされたサイズが小さい&lt;/li>
&lt;/ul>
と&lt;a href="https://developers.google.com/protocol-buffers/" target="_blank">ProtocolBuffers&lt;/a>と似たような性質を持ちますが、ProtocolBuffersと違って
&lt;ul>
	&lt;li>IDLが不要で汎用的&lt;/li>
	&lt;li>ストリーム処理が可能（ProtocolBuffersでも出来るのかもしれませんが）&lt;/li>
&lt;/ul>
という特徴を持ちます。TreasureDataのバックエンドであるPlazmaDBやfluentdでも利用されている技術になります。
&lt;p>ということで今回はMessagePackを触ってみました。&lt;/p></description></item><item><title>Clockworkを使ってHerokuでバッチ処理</title><link>https://blog.freedom-man.com/clockwork-heroku.html</link><pubDate>Thu, 22 Sep 2016 07:30:45 +0000</pubDate><guid>https://blog.freedom-man.com/clockwork-heroku.html</guid><description>&lt;p>Herokuでプログラムをスケジュール起動する場合は、&lt;a href="https://elements.heroku.com/addons/scheduler" target="_blank">Heroku Scheduler&lt;/a>が主に使われると思いますが、Heroku Scheduler自体はベストエフォート型のサービスだったり、細かい時間の制御ができなかったり色々と融通が利かない部分があります。ということで今回は&lt;a href="https://github.com/tomykaira/clockwork" target="_blank">Clockwork&lt;/a> + &lt;a href="https://github.com/resque/resque" target="_blank">Resque&lt;/a>でバッチ処理を作ってみます。&lt;/p></description></item><item><title>Protocol Buffersを触ってみた</title><link>https://blog.freedom-man.com/protocolbuffers.html</link><pubDate>Wed, 21 Sep 2016 07:30:11 +0000</pubDate><guid>https://blog.freedom-man.com/protocolbuffers.html</guid><description>&lt;p>&lt;a href="https://developers.google.com/protocol-buffers/" target="_blank">Protocol Buffers&lt;/a>はデータ構造をシリアライズする技術になります。いわゆるXMLやJSONみたいなものではありますが、バイナリ形式なので「サイズが小さい」「シリアライズ、デシリアライズが高速」でprotoファイルによってメッセージ定義を「シンプルに記述可能」なのが売りです。またメッセージ定義はプログラムにコンパイルされるため、プログラムから利用しやすいのも利点です。&lt;/p>
&lt;p>ということで今回はProtocol Buffersを触ってみました。&lt;/p></description></item><item><title>初心者がRails+DeviseでTodoアプリを作ってみた【Herokuにデプロイするまで】</title><link>https://blog.freedom-man.com/rails-devise-todoapp.html</link><pubDate>Tue, 20 Sep 2016 07:30:24 +0000</pubDate><guid>https://blog.freedom-man.com/rails-devise-todoapp.html</guid><description>&lt;p>2番煎じどころか100番煎じくらいだと思いますが、Ruby on Rails+Deviseで認証機能付きTodoアプリを作ってみました。&lt;/p>
&lt;p>今回やることは以下です。&lt;/p>
&lt;ul>
	&lt;li>Railsアプリのプロジェクトを作成&lt;/li>
	&lt;li>Deviseインストール＆設定&lt;/li>
	&lt;li>各種モデル作成＋マイグレーション&lt;/li>
	&lt;li>ルーティング設定&lt;/li>
	&lt;li>コントローラ作成&lt;/li>
	&lt;li>メール送信設定&lt;/li>
	&lt;li>Herokuアプリ作成＋設定＋デプロイ&lt;/li>
&lt;/ul>
Rubyのバージョンは2.2.4、Railsは5.0.0.1です。</description></item><item><title>EmbulkのAnalytics Cloudのプラグインをリリースしました</title><link>https://blog.freedom-man.com/embulk-analytics-cloud.html</link><pubDate>Mon, 13 Jun 2016 07:30:54 +0000</pubDate><guid>https://blog.freedom-man.com/embulk-analytics-cloud.html</guid><description>&lt;p>EmbulkのAnalytics Cloudのプラグインを作成、リリースしましたー。&lt;/p>
&lt;ul>
	&lt;li>&lt;a href="https://github.com/tzmfreedom/embulk-output-analytics_cloud" target="_blank">tzmfreedom/embulk-output-analytics_cloud&lt;/a>&lt;/li>
	&lt;li>&lt;a href="https://rubygems.org/gems/embulk-output-analytics_cloud" target="_blank">embulk-output-analytics_cloud | RubyGems.org&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>jsforceを使ったSalesforce便利TIPS</title><link>https://blog.freedom-man.com/jsforce-salesforce-tips.html</link><pubDate>Wed, 25 May 2016 07:30:21 +0000</pubDate><guid>https://blog.freedom-man.com/jsforce-salesforce-tips.html</guid><description>&lt;p>&lt;a href="https://jsforce.github.io/" target="_blank">jsforce&lt;/a>はメタデータ操作が他の言語のライブラリよりも扱いやすいので、手軽に高度なことができちゃいます。ということで便利なオレオレTIPSを備忘として残しておきますー&lt;/p></description></item><item><title>PowerShellに入門してみた</title><link>https://blog.freedom-man.com/powershell-beginner.html</link><pubDate>Tue, 24 May 2016 07:30:32 +0000</pubDate><guid>https://blog.freedom-man.com/powershell-beginner.html</guid><description>&lt;p>PowerShellが便利だということに今さら気づいたので、使い方をざっとまとめましたー&lt;/p></description></item><item><title>Elastic SearchでToo many open filesが出た時の対処法</title><link>https://blog.freedom-man.com/es-too-many-open-files.html</link><pubDate>Mon, 23 May 2016 07:30:27 +0000</pubDate><guid>https://blog.freedom-man.com/es-too-many-open-files.html</guid><description>&lt;p class="p1">&lt;a href="https://blog.freedom-man.com/fluentd-elasticsearch-kibana-idle/" target="_blank">アイドルEFKスタック&lt;/a>が止まっていたので、{elastic search path}/logsディレクトリ内のログを確認したところ、以下のようなエラーが発生してました。&lt;/p>
&lt;p class="p1"></description></item><item><title>Let's Encryptの証明書を更新してみた</title><link>https://blog.freedom-man.com/lets-encrypt-renew.html</link><pubDate>Fri, 20 May 2016 07:30:40 +0000</pubDate><guid>https://blog.freedom-man.com/lets-encrypt-renew.html</guid><description>&lt;p>Let&amp;rsquo;s Encryptから「もうすぐ期限切れになるよー」メールが届いたので対応しました。&lt;/p></description></item><item><title>Treasure DataのAPIを叩いてみた</title><link>https://blog.freedom-man.com/treasuredata-api.html</link><pubDate>Thu, 19 May 2016 07:30:47 +0000</pubDate><guid>https://blog.freedom-man.com/treasuredata-api.html</guid><description>&lt;p>&lt;a href="https://docs.treasuredata.com/articles/rest-api" target="_blank">Treasure DataのAPI&lt;/a>を叩くときは各種言語のライブラリを利用するのがほとんどだと思いますが、REST APIを実際に叩いて何が出来るのか確認してみましたー&lt;/p></description></item><item><title>embulkを使ってTreasure Dataにjsonl形式のデータを流し込む</title><link>https://blog.freedom-man.com/embulk-td-jsonl.html</link><pubDate>Mon, 16 May 2016 07:30:57 +0000</pubDate><guid>https://blog.freedom-man.com/embulk-td-jsonl.html</guid><description>&lt;p>&lt;a href="http://www.embulk.org/docs/" target="_blank">embulk&lt;/a>を使って&lt;a href="https://www.treasuredata.com/" target="_blank">Treasure Data&lt;/a>にjsonl形式のデータを流し込んでみました。&lt;/p></description></item><item><title>ElixirでforceのAPIを叩いてみた</title><link>https://blog.freedom-man.com/elixir-force-api.html</link><pubDate>Wed, 11 May 2016 07:30:41 +0000</pubDate><guid>https://blog.freedom-man.com/elixir-force-api.html</guid><description>&lt;p>Elixirのforce.com用ライブラリの&lt;a href="https://github.com/jeffweiss/forcex" target="_blank">forcex&lt;/a>を使ってforce.comのAPIを叩いてみました。&lt;/p></description></item><item><title>Heroku ConnectのAPI叩いてみた</title><link>https://blog.freedom-man.com/heroku-connect-api.html</link><pubDate>Tue, 10 May 2016 07:30:25 +0000</pubDate><guid>https://blog.freedom-man.com/heroku-connect-api.html</guid><description>&lt;p>Heroku Conncect APIを叩いてみましたー。ということで、いつもどおり備忘録&lt;/p></description></item><item><title>bit.lyとGoogle URL ShortenerのAPI叩いてみた</title><link>https://blog.freedom-man.com/bitly-google-shortener-api.html</link><pubDate>Mon, 09 May 2016 07:30:38 +0000</pubDate><guid>https://blog.freedom-man.com/bitly-google-shortener-api.html</guid><description>&lt;div>今更ながらURL短縮サービスの&lt;a href="https://bitly.com/" target="_blank">bit.ly&lt;/a>と&lt;a href="https://goo.gl/" target="_blank">Google URL Shortener&lt;/a>のAPIを叩いてみましたーということで備忘録&lt;/div></description></item><item><title>PythonのWebアプリフレームワークFalcon試してみた</title><link>https://blog.freedom-man.com/python-falcon.html</link><pubDate>Tue, 26 Apr 2016 07:30:38 +0000</pubDate><guid>https://blog.freedom-man.com/python-falcon.html</guid><description>&lt;p>&lt;a href="http://falconframework.org/" target="_blank">Falcon&lt;/a>という高速・シンプルなWebアプリフレームワークを触ってみましたー&lt;/p>
&lt;p>PHPの高速Webアプリフレームワークで&lt;a href="https://phalconphp.com/ja/" target="_blank">Phalcon&lt;/a>というのがありますが、PythonはFalconになります。&lt;/p></description></item><item><title>PointDNSのAPIをforce.comから叩く</title><link>https://blog.freedom-man.com/pointdns-api-force.html</link><pubDate>Mon, 25 Apr 2016 07:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/pointdns-api-force.html</guid><description>&lt;p>PointDNSはDNSのサービスで、HerokuでAddonとしても提供されています。
今回は、ApexからPointDNSのAPIを叩いてDNSレコードの追加、変更を自動化できるようにします。&lt;/p></description></item><item><title>技術ブログあれこれ</title><link>https://blog.freedom-man.com/tech-blog.html</link><pubDate>Fri, 22 Apr 2016 07:30:15 +0000</pubDate><guid>https://blog.freedom-man.com/tech-blog.html</guid><description>&lt;p>祝200記事！ということで技術ブログに関する考えをざっくばらんに。伝えたい、というよりは自分の考えを整理したいっていうモチベーションで書いているので、あんまり参考にならないかもですが…。&lt;/p></description></item><item><title>Apexでコミュニティユーザを作成する</title><link>https://blog.freedom-man.com/create-community-user.html</link><pubDate>Thu, 21 Apr 2016 07:30:30 +0000</pubDate><guid>https://blog.freedom-man.com/create-community-user.html</guid><description>&lt;p>Apexでコミュニティユーザを作成する方法の備忘録&lt;/p></description></item><item><title>Salesforce to Salesforce試してみた</title><link>https://blog.freedom-man.com/salesforce-to-salesforce.html</link><pubDate>Wed, 20 Apr 2016 07:30:44 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-to-salesforce.html</guid><description>&lt;p>Salesforce to Salesforceを試してみましたーということで備忘録。手順や詳細は参考URLのPDFの方が詳しいので併せて確認すると良いです。&lt;/p></description></item><item><title>FIFO試してみた</title><link>https://blog.freedom-man.com/linux-fifo.html</link><pubDate>Tue, 19 Apr 2016 07:30:16 +0000</pubDate><guid>https://blog.freedom-man.com/linux-fifo.html</guid><description>&lt;p>名前付きパイプのFIFOに関する備忘録&lt;/p></description></item><item><title>Apexでコミュニティロールの共有設定</title><link>https://blog.freedom-man.com/community-role-sharing.html</link><pubDate>Mon, 18 Apr 2016 07:30:35 +0000</pubDate><guid>https://blog.freedom-man.com/community-role-sharing.html</guid><description>&lt;p>Apexを使って、コミュニティのロールに対して共有レコードを割り当てる時の備忘録。&lt;/p></description></item><item><title>Pythonでselect, poll, epoll, kqueue試してみた</title><link>https://blog.freedom-man.com/select-poll-epoll.html</link><pubDate>Fri, 15 Apr 2016 07:30:06 +0000</pubDate><guid>https://blog.freedom-man.com/select-poll-epoll.html</guid><description>&lt;p>I/O多重化のシステムコールのselect, poll, epoll, kqueueをPythonで試してみましたー。Pythonは2.7系を利用しました。&lt;/p></description></item><item><title>FacebookのMessenger用Botをforce.comで作ってみた</title><link>https://blog.freedom-man.com/facebook-bot-force.html</link><pubDate>Thu, 14 Apr 2016 07:30:51 +0000</pubDate><guid>https://blog.freedom-man.com/facebook-bot-force.html</guid><description>&lt;p>今度は&lt;a href="https://developers.facebook.com/blog/post/2016/04/12/bots-for-messenger/" target="_blank">FacebookのMessanger用Bot&lt;/a>が出たようなので例の通り、force.comで試してみましたー&lt;/p></description></item><item><title>Webサーバのチューニングを体感する</title><link>https://blog.freedom-man.com/web-tuning.html</link><pubDate>Wed, 13 Apr 2016 07:30:12 +0000</pubDate><guid>https://blog.freedom-man.com/web-tuning.html</guid><description>&lt;p>Webサーバのアプリ／DB以外での一般的なチューニングに関して体感してみましたー&lt;/p></description></item><item><title>Spark/PySparkでツイート分析してみた</title><link>https://blog.freedom-man.com/spark-tweet-analysis.html</link><pubDate>Tue, 12 Apr 2016 07:30:51 +0000</pubDate><guid>https://blog.freedom-man.com/spark-tweet-analysis.html</guid><description>&lt;p>Twitter Streaming APIでかき集めたツイートを&lt;a href="http://spark.apache.org/" target="_blank">Spark&lt;/a>で分析してみました。&lt;/p>
&lt;p>Hadoop版はこちら→&lt;a href="https://blog.freedom-man.com/hadoop-streaming-idle/" target="_blank">Hadoop Streamingでアイドルツイート分析&lt;/a>&lt;/p>
&lt;p>Hive版はこちら→&lt;a href="https://blog.freedom-man.com/hive-tweet-analysis/" target="_blank">Hiveでツイート分析&lt;/a>&lt;/p></description></item><item><title>LINE BOT APIをforce.comで試してみた</title><link>https://blog.freedom-man.com/line-bot-api-force.html</link><pubDate>Mon, 11 Apr 2016 07:30:09 +0000</pubDate><guid>https://blog.freedom-man.com/line-bot-api-force.html</guid><description>&lt;p>巷で話題の&lt;a href="https://business.line.me/services/products/4/introduction" target="_blank">LINE BOT API&lt;/a>をforce.comで試してみましたー&lt;/p></description></item><item><title>Hiveでツイート分析</title><link>https://blog.freedom-man.com/hive-tweet-analysis.html</link><pubDate>Mon, 28 Mar 2016 07:30:22 +0000</pubDate><guid>https://blog.freedom-man.com/hive-tweet-analysis.html</guid><description>&lt;p>今度は&lt;a href="https://hive.apache.org/" target="_blank">Hive&lt;/a>を使ってツイートを分析しました。１行１JSONのファイル（Fluentd＋Twitter Streaming API）がS3にGZIP形式で格納されているので、このファイルをHiveで処理していきます。環境はMac OS Xです。&lt;/p>
&lt;p>Hadoopバージョンはこちら→&lt;a href="https://blog.freedom-man.com/hadoop-streaming-idle/" target="_blank">Hadoop Streamingでアイドルツイート分析&lt;/a>&lt;/p></description></item><item><title>Let's EncryptでHerokuアプリを独自ドメインSSL化</title><link>https://blog.freedom-man.com/letsencrypt-heroku.html</link><pubDate>Thu, 24 Mar 2016 07:30:35 +0000</pubDate><guid>https://blog.freedom-man.com/letsencrypt-heroku.html</guid><description>&lt;p>&lt;a href="https://letsencrypt.org/" target="_blank">Let&amp;rsquo;s Encrypt&lt;/a>をHerokuアプリに適用して、独自ドメインSSL化してみました。言語はPHPで。&lt;/p></description></item><item><title>start-stop-daemonいじってみた</title><link>https://blog.freedom-man.com/start-stop-daemon.html</link><pubDate>Wed, 23 Mar 2016 07:30:29 +0000</pubDate><guid>https://blog.freedom-man.com/start-stop-daemon.html</guid><description>&lt;p>Ubuntuとかでnginxのinitscript見るとstart-stop-daemon使ってデーモン化していて、デーモン化する手段として覚えておいた方が良さそうだなーと思ったので触ってみました。&lt;/p></description></item><item><title>Hadoop Streamingでアイドルツイート分析</title><link>https://blog.freedom-man.com/hadoop-streaming-idle.html</link><pubDate>Tue, 22 Mar 2016 07:30:28 +0000</pubDate><guid>https://blog.freedom-man.com/hadoop-streaming-idle.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/fluentd-elasticsearch-kibana-idle/" target="_blank">Fluentd+ElasticSearch+Kibanaでアイドルデータ分析基盤を作ってみた&lt;/a>の回で、FluentdとTwitter Streaming APIを使ってS3にツイートデータを保存したので、このデータをHadoopを使って解析してみます。&lt;/p>
&lt;p>今回はMeCabを使って形態素解析してワードカウントを取るような教科書的なMapReduceを試してみました。Hadoop Streamingを使ってPythonでMapper、Reducerを書いていきます。&lt;/p></description></item><item><title>ElasticSearchの設定あれこれ</title><link>https://blog.freedom-man.com/elasticsearch-settings.html</link><pubDate>Tue, 15 Mar 2016 07:30:32 +0000</pubDate><guid>https://blog.freedom-man.com/elasticsearch-settings.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/fluentd-elasticsearch-kibana-idle/" target="_blank">前回の記事&lt;/a>のElasticSearchの設定に関する補足。&lt;/p></description></item><item><title>Google Analytics APIとD3.jsでアクセス数をビジュアライズ</title><link>https://blog.freedom-man.com/google-analytics-api-d3.html</link><pubDate>Mon, 14 Mar 2016 07:30:56 +0000</pubDate><guid>https://blog.freedom-man.com/google-analytics-api-d3.html</guid><description>&lt;p>&lt;a href="https://developers.google.com/analytics/?csw=1" target="_blank">Google Analytics API&lt;/a>＋&lt;a href="https://d3js.org/" target="_blank">D3.js&lt;/a>でブログ記事ごとのアクセス数をビジュアライズしてみました。&lt;/p></description></item><item><title>FuelSDK-NodeとExactTarget APIあれこれ</title><link>https://blog.freedom-man.com/fuelsdk-node.html</link><pubDate>Wed, 09 Mar 2016 07:30:13 +0000</pubDate><guid>https://blog.freedom-man.com/fuelsdk-node.html</guid><description>&lt;p>ExactTargetのNode.js用SDKである&lt;a href="https://github.com/salesforce-marketingcloud/fuelsdk-node" target="_blank">FuelSDK-Node&lt;/a>とExactTarget APIに関する備忘録&lt;/p></description></item><item><title>Ubuntu 14.04@DigitalOceanのオレオレ初期セットアップ</title><link>https://blog.freedom-man.com/digitalocean-ubuntu-setup.html</link><pubDate>Tue, 08 Mar 2016 07:30:12 +0000</pubDate><guid>https://blog.freedom-man.com/digitalocean-ubuntu-setup.html</guid><description>&lt;p>DigitalOceanのVPSを検証用によく利用しているんですが、基本的な設定は全て自分で行う必要があります。特にsshd、iptables、ユーザの作成の部分は基本的には絶対にやらないといけない共通設定なので、備忘として残しておきます。OSはUbuntu 14.04です。&lt;/p></description></item><item><title>Fluentd+ElasticSearch+Kibanaでアイドルデータ分析基盤を作ってみた</title><link>https://blog.freedom-man.com/fluentd-elasticsearch-kibana-idle.html</link><pubDate>Mon, 07 Mar 2016 07:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/fluentd-elasticsearch-kibana-idle.html</guid><description>&lt;p>俺もビッグデータの分析とかやってみたいなー
→Twitterとか身近なビッグデータっぽくて扱いやすそう
→よし、アイドル（坂道シリーズ）に関するツイート集めて分析してみよう&lt;/p>
&lt;p>という軽いノリでFluentd + ElasticSearch + Kibanaというよくある構成で分析基盤（？）を作ってみました。&lt;/p>
&lt;p>今回は基盤作るまでのインストール＆設定地獄の備忘録。（自力でやんなくてもDockerやChefで一発で構築できるモノが出回ってそうですが…）&lt;/p></description></item><item><title>ElectronでExactTargetのGUIツール作ってみた</title><link>https://blog.freedom-man.com/electron-exacttarget-gui.html</link><pubDate>Mon, 22 Feb 2016 07:30:15 +0000</pubDate><guid>https://blog.freedom-man.com/electron-exacttarget-gui.html</guid><description>&lt;p>ElectronでExactTargetのGUIツール作ってみました↓
&lt;a href="https://github.com/tzmfreedom/ET_Tool/releases" target="_blank">Releases · tzmfreedom/ET_Tool&lt;/a>&lt;/p>
&lt;p>リファクタリングとかアイコンとか細かいところは完全無視してとりあえずリリース。&lt;/p></description></item><item><title>ExactTargetでSalesforce連携</title><link>https://blog.freedom-man.com/exacttarget-salesforce-integration.html</link><pubDate>Mon, 15 Feb 2016 10:00:20 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-salesforce-integration.html</guid><description>&lt;p>ExactTargetのSalesforce連携を利用すると、ExactTargetの画面からSalesforceのオブジェクトやレポートデータをインポートしたり、そのデータを使って一括メール送信をすることが可能です。&lt;/p></description></item><item><title>Pythonのargparseをテストする</title><link>https://blog.freedom-man.com/python-argparse.html</link><pubDate>Sun, 14 Feb 2016 10:00:46 +0000</pubDate><guid>https://blog.freedom-man.com/python-argparse.html</guid><description>&lt;p>Pythonのargparseモジュールを利用するとPythonスクリプトに渡された引数のチェックを良い感じにやってくれます。自動的にヘルプコマンドも作ってくれたりするので、コマンドラインツールを作るときにはかなり便利です。&lt;/p>
&lt;p>今回はargparseによるコマンドライン引数のパースをunittests + Mockでテストしてみました。Pythonのバージョンは２系です。&lt;/p></description></item><item><title>Angular.jsでBrowserify</title><link>https://blog.freedom-man.com/angularjs-browserify.html</link><pubDate>Fri, 12 Feb 2016 10:00:56 +0000</pubDate><guid>https://blog.freedom-man.com/angularjs-browserify.html</guid><description>&lt;p>Angular.jsでBrowserify対応するときに色々ハマったので、その備忘録。&lt;/p></description></item><item><title>Marketing Cloud Connector(v5)触ってみた【メール送信編】</title><link>https://blog.freedom-man.com/marketingcloud-connector-emailsend.html</link><pubDate>Thu, 07 Jan 2016 07:30:25 +0000</pubDate><guid>https://blog.freedom-man.com/marketingcloud-connector-emailsend.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/marketingcloud-connector-installation/" target="_blank">前回&lt;/a>はインストールまでやったので今回は実際のメール送信の部分をやっていきます。メール送信方法には、Contact・Leadに対して一件ずつメールを送信する方法、レポートやキャンペーンを使って一括でメール送信をする方法、ContactやLeadに紐づくオブジェクトが作成、更新された際にリアルタイムにメールを送信する方法の３パターンあります。&lt;/p></description></item><item><title>Python初心者がPyPIにコマンドラインツールを登録してみた</title><link>https://blog.freedom-man.com/python-pypi-cli.html</link><pubDate>Wed, 06 Jan 2016 07:30:05 +0000</pubDate><guid>https://blog.freedom-man.com/python-pypi-cli.html</guid><description>&lt;p>ExactTargetのCLIを仕事の便利ツール的な感じで作っていたのをPyPIに公開してみました。↓&lt;/p>
&lt;p>&lt;a href="https://pypi.python.org/pypi/et-cli" target="_blank">et-cli Python Package Index&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ pip install et-cli
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>でインストールできるようになってますので、ExactTarget導入している開発者の方は良ければお使いください（日本ではほとんど居ないと思いますが…）。ツールの説明は別の記事として書こうと思います。まだまだ機能不全＋クソコードな感じなのでもうちょい時間作って書いていかないとなー。&lt;/p>
&lt;p>ということで、今回はコマンドラインツールをPyPIにパッケージ登録するやり方を書いていきます。&lt;/p></description></item><item><title>AWS CLIのHTTPキャプチャ</title><link>https://blog.freedom-man.com/awscli-httpcapture.html</link><pubDate>Sun, 03 Jan 2016 16:40:47 +0000</pubDate><guid>https://blog.freedom-man.com/awscli-httpcapture.html</guid><description>&lt;p>AWSのREST APIはリファレンスもあるしSignatureの生成方法も載っているので、SDKが無いような言語でAPI叩きたい場合でも大抵問題ないんですが、それでも仕様が謎でどういうリクエスト投げれば良いんだ！？っていうケースもあると思います。&lt;/p>
&lt;p>そんなときは各種SDKのコードを読むか、SDKを使ってAPIコールしてHTTPの中身を見るかして仕様を把握する感じになりますが、今回は後者のSDKを使ってAPIコールの中身を見る、というのをやっていきます。&lt;/p></description></item><item><title>レポート通知のカスタムアクション試してみた</title><link>https://blog.freedom-man.com/sfdc-report-customaction.html</link><pubDate>Sun, 03 Jan 2016 13:50:26 +0000</pubDate><guid>https://blog.freedom-man.com/sfdc-report-customaction.html</guid><description>&lt;p>Spring ’15からレポート通知の機能が利用できるようになっています。
任意のレポートがある条件を満たした時に特定のアクションを実行させることができる機能で、ログインユーザレベルで設定できるものになります。具体的には「毎日午前10時に未解決のケースが100個以上溜まっている状態であれば、登録者に対してChatterやメール通知する」といったことが出来るようになります。&lt;/p></description></item><item><title>PythonのSalesforceライブラリ調べてみた</title><link>https://blog.freedom-man.com/python-salesforce.html</link><pubDate>Sun, 03 Jan 2016 13:05:09 +0000</pubDate><guid>https://blog.freedom-man.com/python-salesforce.html</guid><description>&lt;p>Salesforce触っていると、アドホックにデータを操作したいときが結構あるんですが、Pythonってそういうのないのかなーと思って、ちょっくら調べてみましたので備忘として残しておきます。&lt;/p></description></item><item><title>Apex Batchで既存レコードを使わずに回してみる</title><link>https://blog.freedom-man.com/apexbatch-iterable.html</link><pubDate>Thu, 31 Dec 2015 16:00:45 +0000</pubDate><guid>https://blog.freedom-man.com/apexbatch-iterable.html</guid><description>&lt;p>普通に知らなかったので備忘録として…。&lt;/p>
&lt;p>&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_interface_database_batchable.htm" target="_blank">Batchable&lt;/a>なInterfaceを実装するApex Batchですがexecuteに入ってくるレコードは実在するSObjectじゃなくても良いし、そもそもSObjectである必要もなく、プリミティブやカスタムなApexClassも入れられちゃいます。&lt;/p>
&lt;p>つまり、startの戻り値はDatabase.QueryLocatorではなくSytem.InterableなものもOK、ということです。（リファレンスに思いっきりstartメソッドが2つ定義されています）&lt;/p></description></item><item><title>2016</title><link>https://blog.freedom-man.com/2016.html</link><pubDate>Fri, 01 Jan 2016 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2016.html</guid><description/></item><item><title>Heroku Postgresからのエクスポート</title><link>https://blog.freedom-man.com/heroku-postgres-export.html</link><pubDate>Wed, 30 Dec 2015 23:00:22 +0000</pubDate><guid>https://blog.freedom-man.com/heroku-postgres-export.html</guid><description>&lt;p>Heroku Postgresからのエクスポートの備忘録（今更感ありますが…）&lt;/p></description></item><item><title>Marketing Cloud Connector(v5)触ってみた【インストール・設定編】</title><link>https://blog.freedom-man.com/marketingcloud-connector-installation.html</link><pubDate>Wed, 30 Dec 2015 19:00:38 +0000</pubDate><guid>https://blog.freedom-man.com/marketingcloud-connector-installation.html</guid><description>&lt;p>Salesforce Marketing CloudのExactTargetではSalesforceと連携することが出来ます。具体的には以下のような連携をすることができます。&lt;/p>
&lt;ul>
	&lt;li>ExactTargetの画面からSalesforceのレポート、キャンペーンを使ってメールを送信する&lt;/li>
	&lt;li>ExactTargetの画面からSalesforceのレポートのレコードをDataExtensionに格納する&lt;/li>
	&lt;li>Salesforceの画面からExactTargetの機能を使ってメールを送信する（ログもSalesforce側にレコードとして格納）&lt;/li>
&lt;/ul>
これらのうち３番目のSalesforce画面から起動するタイプのものはSalesforceのパッケージの&lt;a href="http://help.exacttarget.com/en/documentation/integrated_products__crm_and_web_analytic_solutions/marketing_cloud_connector_v5/connecting_the_clouds/" target="_blank">Marketing Cloud Connector&lt;/a>を利用する必要があります。今回はこのConnectorのインストール、設定からメール送信までやっていきます。</description></item><item><title>ExactTargetのMobilePush試してみた【iOS編】</title><link>https://blog.freedom-man.com/exacttarget-mobilepush-ios.html</link><pubDate>Wed, 30 Dec 2015 19:00:23 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-mobilepush-ios.html</guid><description>&lt;p>今回はiOSアプリに対してExactTargetのPush通知機能を実装してみます。&lt;/p>
&lt;p>参考URL&lt;/p>
&lt;ul>
	&lt;li>&lt;a href="http://salesforce-marketingcloud.github.io/JB4A-SDK-iOS/" target="_blank">Journey Builder for Apps iOS SDK &lt;/a>&lt;/li>
&lt;/ul>
Androidの実装に関しては過去記事を参照してください↓
&lt;ul>
	&lt;li>&lt;a href="https://blog.freedom-man.com/exacttarget-push-android1/" target="_blank">ExactTargetのMobilePush試してみた【Android・前編】&lt;/a>&lt;/li>
	&lt;li>&lt;a href="https://blog.freedom-man.com/exacttarget-push-android2/" target="_blank">ExactTargetのMobilePush試してみた【Android・後編】&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>MobilePush Demographicsの確認方法</title><link>https://blog.freedom-man.com/mobilepush-demographics-confirm.html</link><pubDate>Wed, 30 Dec 2015 19:00:03 +0000</pubDate><guid>https://blog.freedom-man.com/mobilepush-demographics-confirm.html</guid><description>&lt;p>ExactTarget(Marketing Cloud)のMobile Push Contactの属性情報の確認方法についての備忘録。&lt;/p></description></item><item><title>Heroku Postgresのスキーマをローカルに落として開発する</title><link>https://blog.freedom-man.com/heroku-postgres-local-dev.html</link><pubDate>Tue, 29 Dec 2015 13:50:31 +0000</pubDate><guid>https://blog.freedom-man.com/heroku-postgres-local-dev.html</guid><description>&lt;p>&lt;a href="https://www.heroku.com/connect" target="_blank">Heroku Connect&lt;/a>を使うとHeroku Postgres側に自動的にスキーマが生成される感じになるので、開発する場合は&lt;/p>
&lt;ul>
	&lt;li>ローカル開発環境からHeroku PostgresのDBに直接接続する&lt;/li>
	&lt;li>Heroku Postgresのスキーマをローカル環境に持っていく&lt;/li>
&lt;/ul>
の２パターンで開発することになります。ただ、前者の場合は同一DBに複数人が開発用として接続することになるので、ミスってデータやテーブルを削除したときや、ユニークなデータを格納したつもりがバッティングしてダメとか、開発上色々と問題があります。さらに東京-US間のレイテンシがあるのでDB接続も低速です。
&lt;p>ということで、実際に開発する場合は後者のパターンになるのですが、この「Heroku Postgresのスキーマをローカルに持っていく」やり方を備忘として残しておきます。&lt;/p></description></item><item><title>ExactTargetのMobilePush Contactにカスタム属性を追加する</title><link>https://blog.freedom-man.com/exacttarget-mobilepush-attributes.html</link><pubDate>Sun, 27 Dec 2015 17:30:34 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-mobilepush-attributes.html</guid><description>&lt;p>ExactTargetのMobilePushのContactにはカスタム属性を追加することができ、独自の属性情報によりパーソナライズやセグメンテーションが出来るようになります。&lt;/p></description></item><item><title>FuelSDK-Python触ってみた</title><link>https://blog.freedom-man.com/fuelsdk-python.html</link><pubDate>Sun, 27 Dec 2015 17:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/fuelsdk-python.html</guid><description>&lt;p>&lt;a href="http://www.exacttarget.com/jp" target="_blank">ExactTarget(Marketing Cloud)&lt;/a>のpythonのSDKである&lt;a href="https://github.com/salesforce-marketingcloud/FuelSDK-Python" target="_blank">FuelSDK-Python&lt;/a>を触ってみたのでメモっておきます。pythonのバージョンは2.7.xを使用してください。&lt;/p></description></item><item><title>Phalconあれこれ2</title><link>https://blog.freedom-man.com/phalcon-tips2.html</link><pubDate>Sun, 27 Dec 2015 13:00:36 +0000</pubDate><guid>https://blog.freedom-man.com/phalcon-tips2.html</guid><description>&lt;p>phpのWebアプリケーションフレームワーク&lt;a href="https://phalconphp.com/" target="_blank">phalcon&lt;/a>のあれこれ第二弾。バージョンは2系です。&lt;/p></description></item><item><title>phalconのレスポンスの挙動について調べてみた</title><link>https://blog.freedom-man.com/phalcon-response.html</link><pubDate>Mon, 21 Dec 2015 07:30:39 +0000</pubDate><guid>https://blog.freedom-man.com/phalcon-response.html</guid><description>&lt;p>今回はphalconのレスポンスの書き方と挙動について書いていきます。サンプルは全てコントローラのアクションメソッド内での処理を想定しています。また、&lt;a href="https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/application.zep" target="_blank">Phalcon\Mvc\Application&lt;/a>のuseImplicitViewがtrueの前提で記載していきます。&lt;/p></description></item><item><title>phalconのdispatch内のイベント</title><link>https://blog.freedom-man.com/phalcon-dispatch-event.html</link><pubDate>Sun, 20 Dec 2015 07:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/phalcon-dispatch-event.html</guid><description>&lt;p>phalconの&lt;a href="https://github.com/phalcon/cphalcon/blob/master/phalcon/dispatcher.zep" target="_blank">dispatcher&lt;/a>内のイベントについて備忘として残しておきます。&lt;/p></description></item><item><title>ExactTargetのJourneyBuilder試してみた【MobilePush編】</title><link>https://blog.freedom-man.com/exacttarget-jb-mobilepush.html</link><pubDate>Fri, 18 Dec 2015 07:30:19 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-jb-mobilepush.html</guid><description>&lt;p>ExactTarget(SalesforceMarketingCloud)の&lt;a href="http://www.exacttarget.com/products/journey-management/journey-builder" target="_blank">JourneyBuilder&lt;/a>でMobilePushをやってみました。&lt;/p>
&lt;p>今回の参考URL→&lt;a href="https://github.com/mattcam/Salesforce-Marketing-Cloud-Developer-Edition-Recipes/blob/master/firing-events.md" target="_blank">Salesforce-Marketing-Cloud-Developer-Edition-Recipes/firing-events.md&lt;/a>&lt;/p>
&lt;p>また、MobilePushのSDK組み込みやアプリケーション設定に関しては以下の記事を参考にしてください。&lt;/p>
&lt;ul>
	&lt;li>&lt;a href="https://blog.freedom-man.com/exacttarget-push-android1/" target="_blank">ExactTargetのMobilePush試してみた【Android・前編】&lt;/a>&lt;/li>
	&lt;li>&lt;a href="https://blog.freedom-man.com/exacttarget-push-android2/" target="_blank">ExactTargetのMobilePush試してみた【Android・後編】&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>phpのxdebugでハマった話</title><link>https://blog.freedom-man.com/php-xdebug.html</link><pubDate>Thu, 17 Dec 2015 07:30:55 +0000</pubDate><guid>https://blog.freedom-man.com/php-xdebug.html</guid><description>&lt;p>phpのデバッグでNetBeans＋xdebugを使おうとしたのですが&lt;/p>
&lt;ul>
	&lt;li>ポート（9000）は開いているしtcpdumpした感じはちゃんと通ってる。&lt;/li>
	&lt;li>phpinfo()でもちゃんとxdebugがenableになっているし、設定もうまくいっているように見える。&lt;/li>
	&lt;li>NetBeansで「最初の行で停止」にチェックをつけると、最初の行では止まってくれる。&lt;/li>
	&lt;li>ブレークポイントで止まってくれない。デバッグ文でコード自体は通っていることは確認済み。&lt;/li>
&lt;/ul>
という感じで、デバッグできない状況になりました。</description></item><item><title>カスタム接続アプリケーションハンドラ試してみた</title><link>https://blog.freedom-man.com/sfdc-customconnectedapp.html</link><pubDate>Wed, 16 Dec 2015 07:30:53 +0000</pubDate><guid>https://blog.freedom-man.com/sfdc-customconnectedapp.html</guid><description>&lt;p>Winter &amp;lsquo;16で&lt;a href="https://releasenotes.docs.salesforce.com/ja-jp/winter16/release-notes/rn_security_identity_connapp_custom_handler.htm" target="_blank">カスタム接続アプリケーションハンドラ&lt;/a>なるものがリリースされたので、こちらの機能を試してみました。&lt;/p>
&lt;p>この機能は接続アプリケーション(OAuth, SAML)の振る舞いを変更することができます。
具体的には以下の振る舞いを変更することができます。&lt;/p>
&lt;ul>
	&lt;li>「管理者が承認したユーザは事前承認済み」のポリシーにおけるauthorize処理&lt;/li>
	&lt;li>refresh tokenによるrefresh処理&lt;/li>
	&lt;li>userinfoやSAMLアサーションに利用されるカスタム属性の動的生成&lt;/li>
&lt;/ul>
カスタム接続アプリケーションハンドラ自体はAuth.ConnectedAppPluginクラスを継承して実装することになります。
詳細はこちらを参照→&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_class_Auth_ConnectedAppPlugin.htm" target="_blank">ConnectedAppPlugin Class | Force.com Apex Code Developer's Guide | Salesforce Developers&lt;/a></description></item><item><title>codeceptionでphalconの単体テストしてみた【FunctionalTests編】</title><link>https://blog.freedom-man.com/codeception-phalcon-functionaltests.html</link><pubDate>Mon, 14 Dec 2015 07:30:08 +0000</pubDate><guid>https://blog.freedom-man.com/codeception-phalcon-functionaltests.html</guid><description>&lt;p>前回は&lt;a href="https://github.com/phalcon/incubator" target="_blank">incubator&lt;/a>で&lt;a href="http://codeception.com/docs/05-UnitTests" target="_blank">UnitTests&lt;/a>な単体テストをしましたが、今回は&lt;a href="http://codeception.com/docs/04-FunctionalTests" target="_blank">FunctionalTests&lt;/a>の方でトライしてみます。
&lt;a href="http://codeception.com/" target="_blank">codeception&lt;/a>のインストールは&lt;a href="https://blog.freedom-man.com/codeception-phalcon/" target="_blank">前回の記事&lt;/a>を参照してください。&lt;/p></description></item><item><title>phalconあれこれ</title><link>https://blog.freedom-man.com/phalcon-tips.html</link><pubDate>Sun, 13 Dec 2015 07:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/phalcon-tips.html</guid><description>&lt;p>phalconの細かすぎず、伝わりやすい話。2系の話です（1系でもそうかもしれないけど未検証）。&lt;/p></description></item><item><title>codeceptionでphalconの単体テストしてみた【incubator編】</title><link>https://blog.freedom-man.com/codeception-phalcon.html</link><pubDate>Mon, 07 Dec 2015 07:30:27 +0000</pubDate><guid>https://blog.freedom-man.com/codeception-phalcon.html</guid><description>&lt;p>&lt;a href="http://codeception.com/" target="_blank">codeception&lt;/a>＋&lt;a href="https://github.com/phalcon/incubator" target="_blank">phalcon/incubator&lt;/a>で&lt;a href="https://phalconphp.com/ja/" target="_blank">phalcon&lt;/a>の単体テストをやってみました。&lt;/p>
&lt;p>codeceptionではブラウザと実際に稼働しているアプリケーションを使った&lt;a href="http://codeception.com/docs/03-AcceptanceTests" target="_blank">AcceptanceTest&lt;/a>、アプリケーション（各フレームワーク対応）をテスト実行時に内部で動かす&lt;a href="http://codeception.com/docs/04-FunctionalTests" target="_blank">FunctionalTest&lt;/a>、従来型の単体テストを行う&lt;a href="http://codeception.com/docs/05-UnitTests" target="_blank">UnitTest&lt;/a>があります。今回はUnitTestでの単体テストの方法を書いていきます。&lt;/p></description></item><item><title>ApexからAWS IoTのAPI叩いてみた</title><link>https://blog.freedom-man.com/apex-awsiot.html</link><pubDate>Thu, 03 Dec 2015 00:05:12 +0000</pubDate><guid>https://blog.freedom-man.com/apex-awsiot.html</guid><description>&lt;p>&lt;del>&lt;a href="http://www.salesforce.com/iot-cloud/" target="_blank">IoT Cloud&lt;/a>がいつまで経っても利用できそうにないので&lt;/del>&lt;a href="https://aws.amazon.com/jp/iot/" target="_blank">AWS IoT&lt;/a>が面白そうなので
Apexから触ってみました。今回はThingは利用せずに、&lt;a href="http://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-message-broker.html" target="_blank">Message Broker&lt;/a>にHTTPで送って&lt;a href="http://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-rules.html" target="_blank">Rules&lt;/a>で処理をさせるという構成でやってみました。&lt;/p></description></item><item><title>ExactTargetのAPI叩いてみた【Triggered Email編】</title><link>https://blog.freedom-man.com/exacttarget-api-triggeredemail.html</link><pubDate>Tue, 06 Oct 2015 07:30:05 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-api-triggeredemail.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/exacttarget-soapapi-bulkmail/" target="_blank">前回&lt;/a>は&lt;a href="https://help.exacttarget.com/en/technical_library/web_service_guide/technical_articles/creating_email_send_definition/" target="_blank">EmailSendDefinition&lt;/a>を使ってメールを送信したので、今回はTriggered Emailを使ってメールを送信したいと思います。EmailSendDefinitionの方法はあるユーザ（＝Subscriber）の集団に対して一括でメールを送信するユースケースに利用するのに対し、Triggered EmailはSubscriberの任意のアクションに対して、メールを送信するようなユースケースで利用することになります。具体的には、「問い合わせフォームで問い合わせを完了した時に、確認メールをユーザ宛に送信する」といったWebサイトのアクションに対するメール送信等に利用します。&lt;/p></description></item><item><title>ExactTargetのMobilePush試してみた【Android・後編】</title><link>https://blog.freedom-man.com/exacttarget-push-android2.html</link><pubDate>Mon, 05 Oct 2015 07:30:43 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-push-android2.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/exacttarget-push-android1/" target="_blank">前回&lt;/a>はWebのUI上からPush通知をしましたが、今回はAPIで送信してみます。
APIで送信するには事前に&lt;a href="https://appcenter-auth.exacttargetapps.com/" target="_blank">App Center&lt;/a>のアプリケーション登録が必要です。
&lt;a href="https://blog.freedom-man.com/exacttarget-soapapi-bulkmail/" target="_blank">こちらの記事&lt;/a>を参照して事前にセットアップしてください。&lt;/p>
&lt;p>参考URL&lt;/p>
&lt;ul>
 &lt;li>&lt;a href="https://code.exacttarget.com/apis-sdks/rest-api/v1/routes.html" target="_blank">REST API v1 Reference | Code@&lt;/a>&lt;/li>
 &lt;li>&lt;a href="http://salesforcefuel.github.io/JB4A-SDK-Android/" target="_blank">Journey Builder for Apps Android SDK (v4.0.7) : README&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Analytics Cloud External Data API試してみた</title><link>https://blog.freedom-man.com/analyticscloud-externaldataapi.html</link><pubDate>Wed, 30 Sep 2015 07:30:03 +0000</pubDate><guid>https://blog.freedom-man.com/analyticscloud-externaldataapi.html</guid><description>&lt;p>&lt;a href="http://www.salesforce.com/jp/analytics-cloud/overview/" target="_blank">Analytics Cloud&lt;/a>ではSalesforceのオブジェクトだけでなく、CSVを外部データとして取り込むことができます。今回はCSVによるデータ取り込みをExternal Data APIを使って取り込んでみます。External Data APIといっても、やることはロード用のオブジェクトにデータを格納するだけで、あとは勝手にAnalytics Cloud側がデータ取り込みと変換をやってくれます。&lt;/p>
&lt;p>参考URLは以下になります。&lt;/p>
&lt;ul>
 &lt;li>&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.bi_dev_guide_ext_data.meta/bi_dev_guide_ext_data/" target="_blank">External Data | Analytics Cloud External Data API Developer's Guide | Salesforce Developers&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.bi_dev_guide_ext_data_format.meta/bi_dev_guide_ext_data_format/" target="_blank">External Data Metadata Overview | Analytics Cloud External Data Format Reference | Salesforce Developers&lt;/a>&lt;/li>
 &lt;li>&lt;a href="http://appirio.co.jp/category/tech-blog/2015/09/whatisanalyticscloud3/" target="_blank">Salesforce Analytics Cloud入門（3）～データセット ～ - Appirio Japan&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Lightning Process BuilderでInvokableMethod試してみた</title><link>https://blog.freedom-man.com/lightning-process-builder-invokablemethod.html</link><pubDate>Tue, 29 Sep 2015 07:30:43 +0000</pubDate><guid>https://blog.freedom-man.com/lightning-process-builder-invokablemethod.html</guid><description>&lt;p>SalesforceのLightning Process BuilderはGUIでワークフローを構成することができる機能ですが、Apexコードを呼び出せるのが一つの特徴となっています。そこで、今回はApexコード呼び出し（&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_InvocableMethod.htm" target="_blank">InvokableMethod&lt;/a>）を試してみました。&lt;/p></description></item><item><title>ExactTargetのMobilePush試してみた【Android・前編】</title><link>https://blog.freedom-man.com/exacttarget-push-android1.html</link><pubDate>Mon, 28 Sep 2015 07:30:56 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-push-android1.html</guid><description>&lt;p>ExactTargetのMobilePush(Android)を試してみたので備忘として残しておきます！&lt;/p>
&lt;p>参考URL：&lt;a href="http://salesforcefuel.github.io/JB4A-SDK-Android/" target="_blank">Journey Builder for Apps Android SDK (v4.0.6) : README&lt;/a>&lt;/p></description></item><item><title>Salesforce Mobile SDKでAndroidのPush通知やってみた</title><link>https://blog.freedom-man.com/salesforce-android-push.html</link><pubDate>Fri, 25 Sep 2015 07:30:17 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-android-push.html</guid><description>&lt;p>SalesforceのMobile SDKを使ってPush通知が出来るようなので、Androidで試してみました。JDKやAndroid Studioのインストールは完了済みとして、そこからの構築工程を備忘として残しておきます。環境はwindows 8 です。&lt;/p>
&lt;p>参考URLはこちら&lt;/p>
&lt;ul>
 &lt;li>&lt;a href="http://qiita.com/a_kuratani/items/474a18c66374c41e1daf" target="_blank">AndroidStudio+SalesforceMobileSDKによるAndroid開発環境構築 - Qiita&lt;/a>&lt;/li>
 &lt;li>&lt;a href="http://appirio.co.jp/category/tech-blog/2012/07/salesforce-mobile-sdk%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6android%E3%83%8D%E3%82%A4%E3%83%86%E3%82%A3%E3%83%96%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%92%E5%8B%95/" target="_blank">Salesforce Mobile SDKを使ってAndroidネイティブアプリのサンプルを動かしてみよう - Appirio Japan&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.pushImplGuide.meta/pushImplGuide/pns_overview.htm" target="_blank">Mobile Push Notifications Overview | Salesforce Mobile Push Notifications Implementation Guide | Salesforce Developers&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Dreamforce '15 行ってきた。</title><link>https://blog.freedom-man.com/dreamforce-15.html</link><pubDate>Thu, 24 Sep 2015 07:30:37 +0000</pubDate><guid>https://blog.freedom-man.com/dreamforce-15.html</guid><description>&lt;p>会社のお金で&lt;a href="http://www.salesforce.com/dreamforce/DF15/" target="_blank">Dreamforce &amp;lsquo;15&lt;/a>行ってきました。
最高のイベントでした。まさに夢のforceでした。
Salesforce好きな人なら一生に一回は自腹切ってでも行くべきだと思いました。
Salesforce嫌いな人でもラテン系な熱気が相まって化学反応が起こるかもしれないので行ってみることをオススメします。
人によりますが、一生に一回で50万円の自己投資は安いと思えるくらいの衝撃は味わえると思います。&lt;/p></description></item><item><title>Windowsのファイル共有自動化のためのコマンドまとめ</title><link>https://blog.freedom-man.com/windows-fileshare-command.html</link><pubDate>Thu, 03 Sep 2015 07:30:33 +0000</pubDate><guid>https://blog.freedom-man.com/windows-fileshare-command.html</guid><description>&lt;p>Windowsのファイル共有に関して、コマンドで自動化するための情報を備忘として残しておきます！&lt;/p></description></item><item><title>ExactTargetのSOAP API叩いてみた【一括メール送信編】</title><link>https://blog.freedom-man.com/exacttarget-soapapi-bulkmail.html</link><pubDate>Tue, 01 Sep 2015 07:30:41 +0000</pubDate><guid>https://blog.freedom-man.com/exacttarget-soapapi-bulkmail.html</guid><description>&lt;p>&lt;a href="http://www.exacttarget.com/jp" target="_blank">ExactTarget&lt;/a>のAPIを叩いてみたので備忘として残しておきます。&lt;a href="https://code.exacttarget.com/apis-sdks/rest-api/v1/routes.html" target="_blank">REST API&lt;/a>と&lt;a href="https://code.exacttarget.com/apis-sdks/soap-api/" target="_blank">SOAP API&lt;/a>がありますが、今回はSOAP APIを使ってメール送信をしてみます。（現時点ではSOAP APIの方ができることが多いイメージ）&lt;/p>
&lt;p>ExactTargetのSOAP APIのリファレンスは以下がオススメです。&lt;/p>
&lt;ul>
 &lt;li>&lt;a href="https://help.exacttarget.com/en/technical_library/web_service_guide/working_with_soap_web_service_api/" target="_blank">Working with SOAP Web Service API&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://help.exacttarget.com/en/technical_library/web_service_guide/soap_api_best_practices/" target="_blank">SOAP API Best Practices&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://help.exacttarget.com/en/technical_library/web_service_guide/methods/" target="_blank">Methods&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://help.exacttarget.com/en/technical_library/web_service_guide/objects/" target="_blank">Objects&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://help.exacttarget.com/en/technical_library/web_service_guide/technical_articles/" target="_blank">Technical Articles&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>herokuでRabbitMQ Bigwig試してみた</title><link>https://blog.freedom-man.com/heroku-rabbitmq-bigwig.html</link><pubDate>Tue, 01 Sep 2015 07:30:11 +0000</pubDate><guid>https://blog.freedom-man.com/heroku-rabbitmq-bigwig.html</guid><description>&lt;p>&lt;a href="https://www.amqp.org/" target="_blank">AMQP&lt;/a>とかよくわかりませんが、herokuで&lt;a href="http://bigwig.io/" target="_blank">RabbitMQ BigWig&lt;/a>を試してみましたー。
今回はPHPで&lt;a href="https://www.rabbitmq.com/tutorials/tutorial-one-php.html">RabbitMQのチュートリアル&lt;/a>を試してみました。&lt;/p>
&lt;p>AMQPに関しては以下のサイトが詳しいです。&lt;/p>
&lt;ul>
 &lt;li>&lt;a href="http://www.slideshare.net/terurou/mqttamqpnet" target="_blank">MQTTとAMQPと.NET&lt;/a>&lt;/li>
 &lt;li>&lt;a href="http://labs.gree.jp/blog/2010/06/262/" target="_blank">AMQPによるメッセージング | GREE Engineers' Blog&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>AzureADのGraph API触ってみた</title><link>https://blog.freedom-man.com/azuread-graph.html</link><pubDate>Mon, 31 Aug 2015 07:30:28 +0000</pubDate><guid>https://blog.freedom-man.com/azuread-graph.html</guid><description>&lt;p>&lt;a href="http://azure.microsoft.com/ja-jp/services/active-directory/" target="_blank">Azure Active Directory&lt;/a>の&lt;a href="https://msdn.microsoft.com/ja-jp/library/azure/Hh974476.aspx?f=255&amp;MSPPError=-2147217396" target="_blank">GraphAPI&lt;/a>を触る機会があったので、備忘として残しておきます。&lt;/p>
&lt;p>Graph APIの利用にあたって、以下のサイトを参考にしました。&lt;/p>
&lt;ul>
 &lt;li>&lt;a href="https://msdn.microsoft.com/ja-jp/library/azure/Hh974478.aspx" target="_blank">Azure AD Graph REST API リファレンス&lt;/a>&lt;/li>
 &lt;li>&lt;a href="http://blogs.msdn.com/b/tsmatsuz/archive/2012/09/10/windows-azure-active-directory-aad-graph-api-oauth2.aspx" target="_blank">Azure Active Directory の Graph API の活用&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://msdn.microsoft.com/ja-jp/library/azure/dn645545.aspx" target="_blank">Azure AD での OAuth 2.0&lt;/a>&lt;/li>
 &lt;li>&lt;a href="https://msdn.microsoft.com/ja-jp/library/azure/hh974476.aspx" target="_blank">Azure AD Graph API&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Salesforceのログインフロー試してみた</title><link>https://blog.freedom-man.com/salesforce-loginflow.html</link><pubDate>Mon, 31 Aug 2015 07:30:16 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-loginflow.html</guid><description>&lt;p>Salesforceの認証プロセスとして独自のログインフローを構築できるということで、Salesforceが公開している&lt;a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04to0000000WA6J" target="_blank">パッケージ&lt;/a>を使って以下のチュートリアル（TOTPの2要素認証）に従って検証してみました。
&lt;a href="https://developer.salesforce.com/page/Login-Flows" target="_blank">Login-Flows - developer.force.com&lt;/a>&lt;/p>
&lt;p>ログインフローは以下のスライドも詳しいです！
&lt;a href="http://www.slideshare.net/TerraSky/7-power-night2014kanbayashi" target="_blank">7 power night2014_kanbayashi&lt;/a>&lt;/p></description></item><item><title>Salesforceを認証プロバイダとしてCognitoを使ってみる</title><link>https://blog.freedom-man.com/cognito-salesforce.html</link><pubDate>Thu, 27 Aug 2015 07:30:49 +0000</pubDate><guid>https://blog.freedom-man.com/cognito-salesforce.html</guid><description>&lt;p>Salesforceを認証プロバイダとして&lt;a href="https://aws.amazon.com/jp/cognito/" target="_blank">Amazon Cognito&lt;/a>でAWSのAPIを叩く方法を書いていきます！
参考URLは以下。今回のソースやら設定方法は、ほぼこちらのパクリです。
&lt;a href="https://blogs.aws.amazon.com/security/post/Tx3LP54JOGBE0AY/Building-an-App-using-Amazon-Cognito-and-an-OpenID-Connect-Identity-Provider" target="_blank">Building an App Using Amazon Cognito and an OpenID Connect Identity Provider&lt;/a>&lt;/p></description></item><item><title>Perlド初心者がYAPC gihyoレポーターをやってみた話</title><link>https://blog.freedom-man.com/yapc-reporter-2015.html</link><pubDate>Tue, 25 Aug 2015 07:30:42 +0000</pubDate><guid>https://blog.freedom-man.com/yapc-reporter-2015.html</guid><description>&lt;p>僭越ながら、&lt;a href="http://yapcasia.org/2015/" target="_blank">YAPC::Asia Tokyo 2015&lt;/a>の&lt;a href="http://gihyo.jp/news/report/01/yapcasia2015/" target="_blank">gihyoレポーター&lt;/a>として8/20, 21の2日間だけ参加させていただきました。「ブログを書くまでがYAPC」ということなので、ブログに書かせていただきます！&lt;/p></description></item><item><title>Mailgun触ってみた</title><link>https://blog.freedom-man.com/mailgun.html</link><pubDate>Mon, 24 Aug 2015 08:30:35 +0000</pubDate><guid>https://blog.freedom-man.com/mailgun.html</guid><description>&lt;p>今回は&lt;a href="https://sendgrid.kke.co.jp/" target="_blank">SendGrid&lt;/a>と並んで有名なメール系サービスの&lt;a href="http://www.mailgun.com/" target="_blank">Mailgun&lt;/a>に関して書いていきます！&lt;/p></description></item><item><title>SalesforceのSCIM叩いてみた</title><link>https://blog.freedom-man.com/salesforce-scim.html</link><pubDate>Mon, 24 Aug 2015 08:30:26 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-scim.html</guid><description>&lt;p>SalesforceがSCIMに対応しているということで試してみました！
SCIMの説明はこちらが詳しいです↓
&lt;a href="http://www.slideshare.net/matake/idit-2014/47" target="_blank">SAML / OpenID Connect / OAuth / SCIM 技術解説 - ID&amp;amp;IT 2014 #idit2014&lt;/a>&lt;/p>
&lt;p>SalesforceのSCIMのリファレンスはこちら↓
&lt;a href="https://help.salesforce.com/apex/HTViewHelpDoc?id=identity_scim_overview.htm&amp;language=ja" target="_blank">System for Cross-domain Identity Management (SCIM) の使用&lt;/a>&lt;/p></description></item><item><title>RequestBin使ってみた</title><link>https://blog.freedom-man.com/requestbin.html</link><pubDate>Thu, 20 Aug 2015 00:54:53 +0000</pubDate><guid>https://blog.freedom-man.com/requestbin.html</guid><description>&lt;p>最近Webhookの機能があるAPIを叩くことが多く、その都度、&lt;a href="https://www.heroku.com/" target="_blank">heroku&lt;/a>で立てるか、&lt;a href="https://ngrok.com/" target="_blank">ngrok&lt;/a>でローカルアプリを持っていくか、&lt;a href="https://ifttt.com/" target="_blank">IFTTT&lt;/a>使うか、とか色々と検討していたのですが、&lt;a href="http://requestb.in/" target="_blank">RequestBin&lt;/a>という便利そうなサービスを見つけたので使ってみました。&lt;/p></description></item><item><title>SendGrid触ってみた【Webhook編】</title><link>https://blog.freedom-man.com/sendgrid-webhook.html</link><pubDate>Thu, 20 Aug 2015 00:42:33 +0000</pubDate><guid>https://blog.freedom-man.com/sendgrid-webhook.html</guid><description>&lt;p>&lt;a href="https://sendgrid.kke.co.jp/" target="_blank">SendGrid&lt;/a>では、メール送信だけでなく、受信メールを処理することも可能です。
また、バウンスやUnsubscribe等のイベントに関する処理をすることも可能です。
これらの処理をするのにメール受信やイベントが発生したときに、任意のエンドポイントにHTTPでデータを送信する&lt;a href="https://sendgrid.com/docs/API_Reference/Webhooks/index.html" target="_blank">Webhook&lt;/a>の仕組みを使います。&lt;/p></description></item><item><title>SendGrid触ってみた【メール送信編】</title><link>https://blog.freedom-man.com/sendgrid-send.html</link><pubDate>Thu, 20 Aug 2015 00:27:42 +0000</pubDate><guid>https://blog.freedom-man.com/sendgrid-send.html</guid><description>&lt;p>メールサービスの&lt;a href="https://sendgrid.kke.co.jp/" target="_blank">SendGrid&lt;/a>を触ってみました。今回はSendGridのメール送信の機能について書いていきます。&lt;/p>
&lt;p>SendGridでメールを送信するにはSMTPを使うSMTP APIとHTTPを使うWeb APIの2つの方法があります。&lt;/p></description></item><item><title>Yahoo!ウォレット FastPay触ってみた</title><link>https://blog.freedom-man.com/yahoo-wallet-fastpay.html</link><pubDate>Mon, 17 Aug 2015 00:46:30 +0000</pubDate><guid>https://blog.freedom-man.com/yahoo-wallet-fastpay.html</guid><description>&lt;p>Web決済サービスである&lt;a href="https://fastpay.yahoo.co.jp/" target="_blank">Yahoo!ウォレット FastPay&lt;/a>を触ってみたので備忘として残しておきます！
サービスの利用（開発者側）にはYahoo!IDが必要になります。&lt;/p>
&lt;p>課金・決済方法には都度の決済と、継続課金の2つの方式があります。&lt;/p></description></item><item><title>ExecuteAnonymousによるデバッグログの取得</title><link>https://blog.freedom-man.com/debug-executeanonymous.html</link><pubDate>Sun, 16 Aug 2015 22:52:42 +0000</pubDate><guid>https://blog.freedom-man.com/debug-executeanonymous.html</guid><description>&lt;p>Salesforceで検証用途等で任意のコードを実行させたい場合は、&lt;a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/sforce_api_calls_executeanonymous.htm" target="_blank">ExecuteAnonymous&lt;/a>のAPIを使うことになりますが、SOAP APIだとHTTPリクエストのボディを以下のようにして呼び出すことが出来ます。&lt;/p></description></item><item><title>Talend触ってみた【Salesforceからエクスポート編】</title><link>https://blog.freedom-man.com/talend-export-salesforce.html</link><pubDate>Fri, 14 Aug 2015 10:42:19 +0000</pubDate><guid>https://blog.freedom-man.com/talend-export-salesforce.html</guid><description>&lt;p>&lt;a href="https://blog.freedom-man.com/talend-import-salesforce-basic/" target="_blank">前回&lt;/a>はローカルのExcelファイルからSalesforceへインポートしてみたので
今回はSalesforceからデータをエクスポートして、Excelファイルに格納してみます。&lt;/p></description></item><item><title>Talend触ってみた【Salesforceにインポート・基本編】</title><link>https://blog.freedom-man.com/talend-import-salesforce-basic.html</link><pubDate>Thu, 06 Aug 2015 10:42:39 +0000</pubDate><guid>https://blog.freedom-man.com/talend-import-salesforce-basic.html</guid><description>&lt;p>今更感ありますが、ETLツールの&lt;a href="https://jp.talend.com/" target="_blank">Talend&lt;/a>が気になったので触ってみましたー&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はExcelのファイルを読み込んで、Salesforceに&lt;/p>
&lt;p>INSERT, UPDATE, DELETE, UPSERTする基本的なフローを試してみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Talendのインストール方法や基本的な使い方は以下のサイトが詳しいです。&lt;/p>
&lt;p>&lt;a href="http://talend-jp.jinaka.com/" target="_blank">Talendのススメ：無償で使えるオープンソースETL:Talend Open Studio の使い方&lt;/a>&lt;/p>
&lt;h2>1. ジョブの作成&lt;/h2>
リポジトリタブのJob Designsを右クリック→ジョブの作成をクリックします。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-sidebar-repository.jpg">&lt;img class="alignnone size-medium wp-image-1875" src="https://blog.freedom-man.com/img/2015/08/talend-sidebar-repository-300x177.jpg" alt="talend-sidebar-repository" width="300" height="177" />&lt;/a>&lt;/p>
&lt;p>テキトーな名前でジョブを作成します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-newjob.jpg">&lt;img class="alignnone size-medium wp-image-1866" src="https://blog.freedom-man.com/img/2015/08/talend-newjob-300x146.jpg" alt="talend-newjob" width="300" height="146" />&lt;/a>&lt;/p>
&lt;h2>2. Excelのメタデータの定義&lt;/h2>
リポジトリタブのExcelファイルを右クリック→Excelファイルの作成をクリックします。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-sidebar.jpg">&lt;img class="alignnone size-medium wp-image-1865" src="https://blog.freedom-man.com/img/2015/08/talend-sidebar-235x300.jpg" alt="talend-sidebar" width="235" height="300" />&lt;/a>&lt;/p>
&lt;p>テキトーな名前を設定して、「Next」をクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format1.jpg">&lt;img class="alignnone size-medium wp-image-1864" src="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format1-300x211.jpg" alt="talend-excel-metadata-format1" width="300" height="211" />&lt;/a>&lt;/p>
&lt;p>読み込むExcelファイルを選択して、シートパラメータの設定で&lt;/p>
&lt;p>任意のシートを選択します。読み込まれると右下に読込結果がプレビューされます。&lt;/p>
&lt;p>設定が完了したら、「Next」をクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format2.jpg">&lt;img class="alignnone size-medium wp-image-1888" src="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format2-300x248.jpg" alt="talend-excel-metadata-format2" width="300" height="248" />&lt;/a>&lt;/p>
&lt;p>列名として先頭行を設定にチェックをいれて、「Next」をクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format3.jpg">&lt;img class="alignnone size-medium wp-image-1862" src="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format3-300x164.jpg" alt="talend-excel-metadata-format3" width="300" height="164" />&lt;/a>&lt;/p>
&lt;p>全てStringにしてFinishをクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format4.jpg">&lt;img class="alignnone size-medium wp-image-1871" src="https://blog.freedom-man.com/img/2015/08/talend-excel-metadata-format4-300x164.jpg" alt="talend-excel-metadata-format4" width="300" height="164" />&lt;/a>&lt;/p>
&lt;h2>3. コンポーネントを設置&lt;/h2>
まず、作成したExcelメタデータをJobDesigner上に、ドラッグアンドドロップします。
&lt;p>作成するコンポーネントの種類を聞かれるので&amp;quot;tFileInputExcel&amp;quot;を選択します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-excel-component-select.jpg">&lt;img class="alignnone size-medium wp-image-1876" src="https://blog.freedom-man.com/img/2015/08/talend-excel-component-select-300x102.jpg" alt="talend-excel-component-select" width="300" height="102" />&lt;/a>&lt;/p>
&lt;p>そうすると、tFileInputExcelのコンポーネントが作成されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-excel-component.jpg">&lt;img class="alignnone size-medium wp-image-1861" src="https://blog.freedom-man.com/img/2015/08/talend-excel-component-300x234.jpg" alt="talend-excel-component" width="300" height="234" />&lt;/a>&lt;/p>
&lt;p>次にSalesforceのコンポーネントを設置します。&lt;/p>
&lt;p>PaletteからtSalesforceOutputを選択してドラッグアンドドロップでコンポーネントを作成します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/08/talend-salesforce-component.jpg">&lt;img class="alignnone size-medium wp-image-1860" src="https://blog.freedom-man.com/img/2015/08/talend-salesforce-component-300x138.jpg" alt="talend-salesforce-component" width="300" height="138" />&lt;/a>&lt;/p></description></item><item><title>Apexで文字コード変換</title><link>https://blog.freedom-man.com/apex-charcode-transfer.html</link><pubDate>Sun, 02 Aug 2015 21:16:28 +0000</pubDate><guid>https://blog.freedom-man.com/apex-charcode-transfer.html</guid><description>&lt;p>Apex内で生成した文字列は文字コードがUTF-8であるため&lt;/p>
&lt;p>以下のようなコードだと添付ファイルは全てUTF-8で作成されます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>String&lt;span style="color:#fff"> &lt;/span>result&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>あいうえお漢字カタカナ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>Attachment&lt;span style="color:#fff"> &lt;/span>att&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Attachment&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>att&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Body&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>result&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>att&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Name&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hoge&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">txt&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>att&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parentId&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>001A000000rJ9he&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>insert&lt;span style="color:#fff"> &lt;/span>att&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>そこで、Apexのみを使ってUTF-8以外の文字コードのファイルを作成するには&lt;/p>
&lt;p>以下のように書くことで実装できます。&lt;/p>
&lt;p>※パーセントエンコーディングされる文字列のみ含む前提です。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>String&lt;span style="color:#fff"> &lt;/span>result&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>あいうえお漢字カタカナ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>encodedResult&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>result&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Shift&lt;span style="color:#0550ae">-&lt;/span>JIS&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">replaceAll&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;%&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>Attachment&lt;span style="color:#fff"> &lt;/span>att&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Attachment&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>att&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Body&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertFromHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>encodedResult&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>att&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Name&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hoge&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">txt&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>att&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parentId&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>001A000000rJ9he&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>insert&lt;span style="color:#fff"> &lt;/span>att&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ポイントとしては以下のとおりです。&lt;/p>
&lt;ul>
	&lt;li>Apexで任意の文字コードのバイト列を直接取得するメソッドがない。&lt;/li>
	&lt;li>EncodingUtil.urlEncodeを使えばASCII等のURIとして利用できる文字種以外は
指定の文字コードでパーセントエンコーディングされた文字列を取得できる。&lt;/li>
	&lt;li>パーセントエンコーディングされた文字列はバイト列の16進数表記なので
convertFromHexでバイト列に戻せる。&lt;/li>
&lt;/ul>
利用出来る文字コードですが、おそらくJavaで利用できるものはOKだと思われます。
&lt;p>&lt;a href="https://docs.oracle.com/javase/jp/7/technotes/guides/intl/encoding.doc.html" target="_blank">サポートされているエンコーディング&lt;/a>&lt;/p>
&lt;p>パーセントエンコーディングされない文字列は予め正規表現等で処理しておく必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、エンコーディングに失敗すると、失敗した文字列が「？」に変換されるようなので&lt;/p>
&lt;p>任意の文字列が文字コード変換後に任意のエンコーディングに&lt;/p>
&lt;p>対応しているかどうかの確認も可能です。&lt;/p>
&lt;p>（予め「？」自体の文字列を取り除いてからEncodingUtil.urlEncodeでバイト列取得する感じ）&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URLはコチラ↓&lt;/p>
&lt;p>&lt;a href="http://vaindespair.blogspot.jp/2012/07/blog-post_26.html" target="_blank">memo: Force.com ： VF 画面から CSV ファイルをアップロードし、内容を画面に表示したい （ファイル文字コード Shift_JIS 編）&lt;/a>&lt;/p></description></item><item><title>oauth2-server-phpでOAuth2.0 Providerを実装してみた。</title><link>https://blog.freedom-man.com/oauth2-provider-dev.html</link><pubDate>Sun, 02 Aug 2015 20:07:08 +0000</pubDate><guid>https://blog.freedom-man.com/oauth2-provider-dev.html</guid><description>&lt;p>OAuth2.0 Providerを実装したく、OSSを色々と巡ってみて&lt;/p>
&lt;p>&lt;a href="https://github.com/bshaffer/oauth2-server-php" target="_blank" rel="noopener noreferrer">bshaffer/oauth2-server-php&lt;/a>が使いやすそうだったので触ってみましたー。&lt;/p></description></item><item><title>Box API叩いてみる【Webアプリ統合編】</title><link>https://blog.freedom-man.com/box-api-webapp-integration.html</link><pubDate>Sat, 01 Aug 2015 22:07:19 +0000</pubDate><guid>https://blog.freedom-man.com/box-api-webapp-integration.html</guid><description>&lt;p>今回はBox APIのWebアプリ統合機能を試してみます。&lt;/p>
&lt;p>Webアプリ統合とは、BoxのWebアプリに対する拡張機能になります。&lt;/p>
&lt;p>BoxのWebアプリ上で任意のファイルで　[その他オプション＞その他の操作]　から&lt;/p>
&lt;p>ファイルに応じたアクションをすることが可能になります。&lt;/p>
&lt;p>Salesforceだと&lt;a href="https://app.box.com/services/browse/official/box_for_chatter" target="_blank">Send To Chatter&lt;/a>という、BoxのファイルリンクをChatter投稿するような&lt;/p>
&lt;p>アプリケーションが公開されています。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URL→&lt;a href="https://box-content.readme.io/docs/box-web-application-integrations" target="_blank">&lt;a href="https://box-content.readme.io/docs/box-web-application-integrations">https://box-content.readme.io/docs/box-web-application-integrations&lt;/a>&lt;/a>&lt;/p>
&lt;h2>0. Webアプリ統合の仕組み&lt;/h2>
BoxのWebアプリで、[その他オプション＞その他の操作]　からアプリを選択すると
&lt;p>以下のようなプロンプトが表示されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-prompt-view.jpg">&lt;img class="alignnone size-medium wp-image-1790" src="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-prompt-view-300x256.jpg" alt="box-api-webapp-integration-prompt-view" width="300" height="256" />&lt;/a>&lt;/p>
&lt;p>このプロンプトでOKを押下すると任意のエンドポイントにHTTPリクエストが飛ばされ&lt;/p>
&lt;p>エンドポイント側でHTTPリクエストに応じた処理を行うことで&lt;/p>
&lt;p>Boxのファイル情報を使って外部Webアプリ連携が出来るようになる仕組みです。&lt;/p>
&lt;h2>1. アプリケーションの設定&lt;/h2>
Boxのアプリケーションで「新しいWebアプリ統合を作成」ボタンをクリックします。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-new-webapp-integration.jpg">&lt;img class="alignnone size-medium wp-image-1789" src="https://blog.freedom-man.com/img/2015/07/box-api-new-webapp-integration-300x63.jpg" alt="box-api-new-webapp-integration" width="300" height="63" />&lt;/a>&lt;/p>
&lt;p>名前と説明は必須なので適当に入力します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-info.jpg">&lt;img class="alignnone size-medium wp-image-1788" src="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-info-300x84.jpg" alt="box-api-webapp-integration-info" width="300" height="84" />&lt;/a>&lt;/p>
&lt;p>プロンプトのメッセージとプロンプトで入力する項目を設定します。&lt;/p>
&lt;p>入力項目は必須ではないですが、入力値をコールバックのパラメータとして含めることができるため&lt;/p>
&lt;p>入力項目を利用することで処理に柔軟性を持たせることが出来ます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-prompt.jpg">&lt;img class="alignnone size-medium wp-image-1787" src="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-prompt-300x92.jpg" alt="box-api-webapp-integration-prompt" width="300" height="92" />&lt;/a>&lt;/p>
&lt;p>コールバック構成ではコールバック先のエンドポイントやコールバックの方式を指定します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-callback-info.jpg">&lt;img class="alignnone size-medium wp-image-1784" src="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-callback-info-300x120.jpg" alt="box-api-webapp-integration-callback-info" width="300" height="120" />&lt;/a>&lt;/p>
&lt;p>また、ユーザ体験の項目で「ポップアップが表示されます」を選択すると&lt;/p>
&lt;p>プロンプトでOKを押したあとの処理が別ウィンドウ（or別タブ）を立ち上げて&lt;/p>
&lt;p>そのウィンドウ内でiframe読み込み（ホスト側はboxのWebアプリ）で呼び出されます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>現時点ではiframe読み込みではGETリクエストになる仕様のようなので&lt;/p>
&lt;p>RESTのURLパラメータ（Get）でしかパラメータを渡すことが出来ません。&lt;/p>
&lt;p>「サーバ側でのみ実行されます」はBoxがサーバ間で通信をしてくれる方式になり&lt;/p>
&lt;p>この場合はRESTのPostパラメータとXML, SOAPが利用できます。&lt;/p>
&lt;p>※ポップアップでもPOSTリクエストをする、という記述があるのですが確認できず…&lt;/p>
&lt;p> &lt;/p>
&lt;p>コールバックパラメータの指定の方法は&lt;a href="https://blog.freedom-man.com/box-api-event-webhook/" target="_blank">Webhookのとき&lt;/a>と同じです。&lt;/p>
&lt;p>パラメータの値にOAuth2.0のAuthorization Code（scopeは対象のファイルアクセス権限のみ）&lt;/p>
&lt;p>やfileのBase64値を含めることができます。&lt;/p>
&lt;p>Authorization Codeを含める場合は、リクエストを受け取ったコールバック先が&lt;/p>
&lt;p>code値をaccess_token, refresh_tokenに変換する必要があります。&lt;/p>
&lt;p>（仕組み上、State値を使ったCSRF対策が出来なさそうなのが、すこし不安）&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-callbackparams.jpg">&lt;img class="alignnone size-medium wp-image-1786" src="https://blog.freedom-man.com/img/2015/07/box-api-webapp-integration-callbackparams-300x73.jpg" alt="box-api-webapp-integration-callbackparams" width="300" height="73" />&lt;/a>&lt;/p></description></item><item><title>Box API叩いてみる【ViewAPI編】</title><link>https://blog.freedom-man.com/box-api-view.html</link><pubDate>Fri, 31 Jul 2015 15:49:00 +0000</pubDate><guid>https://blog.freedom-man.com/box-api-view.html</guid><description>&lt;p>今回は&lt;a href="https://www.box.com/ja_JP/home/" target="_blank">Box&lt;/a>の&lt;a href="https://box-view.readme.io/reference" target="_blank">View API&lt;/a>を叩いてみます。&lt;/p>
&lt;p>View APIとはPDFやOfficeドキュメントをHTMLに埋め込んで表示するためのAPIになります。&lt;/p>
&lt;p>HTMLに埋め込むためにはPDFやOfficeドキュメントをHTMLにコンバートする必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ドキュメントのアップロード（＆コンバート@バックエンド）&lt;/p>
&lt;p>→ドキュメントを閲覧するためのセッション（有効期限）を作成&lt;/p>
&lt;p>→発行されたセッションIDを使ってURLを生成し、iframe等で表示&lt;/p>
&lt;p>というフローで実装することになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はApexでSalesforceの添付ファイルをコンバートし、外部公開用のURLを発行してみます。&lt;/p>
&lt;p>参考URL→&lt;a href="https://box-content.readme.io/docs/viewing-your-first-document" target="_blank">&lt;a href="https://box-content.readme.io/docs/viewing-your-first-document">https://box-content.readme.io/docs/viewing-your-first-document&lt;/a>&lt;/a>&lt;/p>
&lt;h2>1. アプリケーションの作成&lt;/h2>
View API用のアプリケーションを作成します（Content APIとは別）
&lt;p>&lt;a href="https://app.box.com/developers/services" target="_blank">&lt;a href="https://app.box.com/developers/services">https://app.box.com/developers/services&lt;/a>&lt;/a> にアクセスして&lt;/p>
&lt;p>「Boxアプリケーションの作成」をクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-view-api-create-app.jpg">&lt;img class="alignnone size-medium wp-image-1775" src="https://blog.freedom-man.com/img/2015/07/box-view-api-create-app-300x61.jpg" alt="box-view-api-create-app" width="300" height="61" />&lt;/a>&lt;/p>
&lt;p>テキトーに入力して、アプリケーションを作成します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-view-api-create-app2.jpg">&lt;img class="alignnone size-medium wp-image-1776" src="https://blog.freedom-man.com/img/2015/07/box-view-api-create-app2-210x300.jpg" alt="box-view-api-create-app2" width="210" height="300" />&lt;/a>&lt;/p>
&lt;p>アプリケーションの詳細を開くと、View APIキーというのがあるのでコレをコピります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-view-api-app-info.jpg">&lt;img class="alignnone size-medium wp-image-1777" src="https://blog.freedom-man.com/img/2015/07/box-view-api-app-info-300x232.jpg" alt="box-view-api-app-info" width="300" height="232" />&lt;/a>&lt;/p>
&lt;h2>2. ドキュメントのアップロード&lt;/h2>
アップロードにはファイルそのものをアップロードするスタイルと
&lt;p>外部公開されているURLを指定するスタイルの2種類があります。&lt;/p>
&lt;p>今回はファイルそのものをアップロードしてみます。&lt;/p>
&lt;p>ファイルそのものをアップロードする場合はContent-Type: multipart/form-dataで&lt;/p>
&lt;p>送信する必要があります。&lt;/p>
&lt;p>Apexからバイナリデータをmultipart/form-dataで送る方法は以下の記事を参照。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/apex-multipartform-data/" target="_blank">Apexからmultipart/form-data形式で送信してみる。&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>サンプルはこちら↓。Authorizationヘッダには1のView APIキーを入れてください。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>Attachment&lt;span style="color:#fff"> &lt;/span>atch&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">[&lt;/span>SELECT&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Body&lt;span style="color:#fff"> &lt;/span>FROM&lt;span style="color:#fff"> &lt;/span>Attachment&lt;span style="color:#fff"> &lt;/span>WHERE&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>00PA000000gBAiI&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">]&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>tokenKey&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Input&lt;span style="color:#fff"> &lt;/span>Your&lt;span style="color:#fff"> &lt;/span>Token&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>boundary&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Authorization&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>tokenKey&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>multipart&lt;span style="color:#0550ae">/&lt;/span>form&lt;span style="color:#0550ae">-&lt;/span>data&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//upload.view-api.box.com/1/documents&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>body&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">--&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>boundary&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>nContent&lt;span style="color:#0550ae">-&lt;/span>Disposition&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>form&lt;span style="color:#0550ae">-&lt;/span>data&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>filename&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge.pdf&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>nContent&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>application&lt;span style="color:#0550ae">/&lt;/span>pdf&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>nContent&lt;span style="color:#0550ae">-&lt;/span>Transfer&lt;span style="color:#0550ae">-&lt;/span>Encoding&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>base64&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>n&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>n&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">base64Encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>atch&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Body&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>n&lt;span style="color:#0550ae">--&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">--&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>body&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setTimeout&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>120000&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>System&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>curlだとこんな感じ&lt;/p></description></item><item><title>Apexからmultipart/form-data形式で送信してみる。</title><link>https://blog.freedom-man.com/apex-multipartform-data.html</link><pubDate>Fri, 31 Jul 2015 15:00:46 +0000</pubDate><guid>https://blog.freedom-man.com/apex-multipartform-data.html</guid><description>&lt;p>Apexからmultipart/form-data形式でHTTPリクエストを行うときは&lt;/p>
&lt;p>自前でBodyをゴリゴリ書いていく必要があるのですが、その際にファイルなどのバイナリデータを&lt;/p>
&lt;p>含めるときの対応に関して書いていきます。&lt;/p>
&lt;h2>パターン1: HTTP Request Bodyをテキストで送信&lt;/h2>
受信側（API提供側）でContent-Transfer-Encoding: base64に対応しているケースで利用可能です。
&lt;p>Apexだと以下のようなコードになります（Boxのサンプル）&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>Attachment&lt;span style="color:#fff"> &lt;/span>atch&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">[&lt;/span>SELECT&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Body&lt;span style="color:#fff"> &lt;/span>FROM&lt;span style="color:#fff"> &lt;/span>Attachment&lt;span style="color:#fff"> &lt;/span>WHERE&lt;span style="color:#fff"> &lt;/span>id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>00PA000000gBAiI&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">]&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>tokenKey&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Input&lt;span style="color:#fff"> &lt;/span>Your&lt;span style="color:#fff"> &lt;/span>Token&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>boundary&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Authorization&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Token&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>tokenKey&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>multipart&lt;span style="color:#0550ae">/&lt;/span>form&lt;span style="color:#0550ae">-&lt;/span>data&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//upload.view-api.box.com/1/documents&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>body&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">--&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>boundary&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>nContent&lt;span style="color:#0550ae">-&lt;/span>Disposition&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>form&lt;span style="color:#0550ae">-&lt;/span>data&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;file&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>filename&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge.pdf&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>nContent&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>application&lt;span style="color:#0550ae">/&lt;/span>pdf&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>nContent&lt;span style="color:#0550ae">-&lt;/span>Transfer&lt;span style="color:#0550ae">-&lt;/span>Encoding&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>base64&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>n&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>n&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">base64Encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>atch&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Body&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;\&lt;/span>r&lt;span style="color:#f6f8fa;background-color:#82071e">\&lt;/span>n&lt;span style="color:#0550ae">--&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>boundary&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">--&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>body&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setTimeout&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>120000&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>System&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>multipart/form-dataの形式でBase64エンコードしたバイナリデータをBodyに載せただけで&lt;/p></description></item><item><title>Apex Connector Framework触ってみた。</title><link>https://blog.freedom-man.com/apex-connector-framework.html</link><pubDate>Fri, 31 Jul 2015 11:46:04 +0000</pubDate><guid>https://blog.freedom-man.com/apex-connector-framework.html</guid><description>&lt;p>いつの間にか、&lt;a href="http://docs.releasenotes.salesforce.com/en-us/summer15/release-notes/rn_forcecom_external_data_apex_adapter.htm" target="_blank">Apex Connector Framework(Custom Adapter)&lt;/a>が&lt;/p>
&lt;p>Dev組織で利用できるようになっていたので触ってみました！&lt;/p>
&lt;p> &lt;/p>
&lt;p>Lightning ConnectはSalesforce環境から外部のデータにアクセスする機能で&lt;/p>
&lt;p>別Salesforce組織のデータや、ODataに対応したAPI経由でデータを取得し&lt;/p>
&lt;p>あたかもSalesforceのオブジェクトであるかのように扱うことが出来ます。&lt;/p>
&lt;p>今回のリリースではApex Connector Framework(Custom Adapter)が利用できるようになりました。&lt;/p>
&lt;p>これを使うと、閲覧するデータが別Salesforce組織のデータだったり、ODataに対応していなくても&lt;/p>
&lt;p>Apexから取得できる手段であればガバナを超えない範囲において&lt;/p>
&lt;p>様々なデータでも取得できるようになり、Salesforceのオブジェクトのような&lt;/p>
&lt;p>振る舞いを持たせることができます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はBoxのファイルデータを閲覧する外部データソースをApex Connector Frameworkを使って&lt;/p>
&lt;p>定義し、SalesforceからBoxのファイル一覧を取得してみます。&lt;/p>
&lt;p>参考URL→&lt;a href="https://developer.salesforce.com/blogs/engineering/2015/05/introducing-lightning-connect-custom-adapters.html" target="_blank">&lt;a href="https://developer.salesforce.com/blogs/engineering/2015/05/introducing-lightning-connect-custom-adapters.html">https://developer.salesforce.com/blogs/engineering/2015/05/introducing-lightning-connect-custom-adapters.html&lt;/a>&lt;/a>&lt;/p>
&lt;h2>1. Connectionクラスを作成&lt;/h2>
サンプルは以下の通り。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>global&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">BoxDataSourceConnection&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">extends&lt;/span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Connection&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ConnectionParams&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">BoxDataSourceConnection&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ConnectionParams&lt;/span>&lt;span style="color:#fff"> &lt;/span>connectionParams&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">params&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>connectionParams&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>override&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Table&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">sync&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Table&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>tables&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Table&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Name&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>255&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>255&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ExternalId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>255&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>DisplayUrl&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>255&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">number&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Size&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>18&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>0&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Column&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>CreatedAt&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>20&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>tables&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Table&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Entries&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Name&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>columns&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>tables&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>override&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">query&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">QueryContext&lt;/span>&lt;span style="color:#fff"> &lt;/span>context&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">tableSelection&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">columnsSelected&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">size&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>1&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>context&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">tableSelection&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">columnsSelected&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>0&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">aggregation&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">QueryAggregation&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">COUNT&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>rows&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>getRows&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>response&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">QueryUtils&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">filter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>getRows&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>countResponse&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>countRow&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>countRow&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>context&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">tableSelection&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">columnsSelected&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>0&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">columnName&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>response&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">size&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>countResponse&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>countRow&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>countResponse&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>filteredRows&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">QueryUtils&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">filter&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>getRows&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedRows&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">QueryUtils&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sort&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>filteredRows&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>limitedRows&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">QueryUtils&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">applyLimitAndOffset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>sortedRows&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>limitedRows&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>override&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">search&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">SearchContext&lt;/span>&lt;span style="color:#fff"> &lt;/span>context&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>results&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableSelection&lt;/span>&lt;span style="color:#fff"> &lt;/span>tableSelection&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>context&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">tableSelections&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>results&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">TableResult&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>tableSelection&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>getRows&lt;span style="color:#1f2328">(&lt;/span>context&lt;span style="color:#1f2328">)));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>results&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">getRows&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DataSource&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ReadContext&lt;/span>&lt;span style="color:#fff"> &lt;/span>context&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>application&lt;span style="color:#0550ae">/&lt;/span>json&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>charset&lt;span style="color:#0550ae">=&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>callout&lt;span style="color:#1f2328">:&lt;/span>Box&lt;span style="color:#0550ae">/&lt;/span>2&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">0&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>folders&lt;span style="color:#0550ae">/&lt;/span>0&lt;span style="color:#0550ae">/&lt;/span>items&lt;span style="color:#0550ae">?&lt;/span>fields&lt;span style="color:#0550ae">=&lt;/span>name&lt;span style="color:#1f2328">,&lt;/span>created_at&lt;span style="color:#1f2328">,&lt;/span>size&lt;span style="color:#1f2328">,&lt;/span>type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>GET&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sendErrorMail&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>results&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>response&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>JSON&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">deserializeUntyped&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Object&lt;span style="color:#fff"> &lt;/span>item_obj&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>response&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>entries&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>item&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>item_obj&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Name&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>item&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>name&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>item&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>CreatedAt&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>item&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>created_at&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Size&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>item&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>size&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ExternalId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>item&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>id&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>row&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>DisplayUrl&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//hoge.example.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>results&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>row&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>results&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>sync, query, searchを実装すればOKで、&lt;/p></description></item><item><title>Box API叩いてみた【イベント通知編】</title><link>https://blog.freedom-man.com/box-api-event-webhook.html</link><pubDate>Mon, 27 Jul 2015 00:54:21 +0000</pubDate><guid>https://blog.freedom-man.com/box-api-event-webhook.html</guid><description>&lt;p>前回に引き続きBox APIを叩いていきます。&lt;/p>
&lt;p>今回はBox Content APIのイベント通知機能について説明していきます。&lt;/p>
&lt;p>Box Content APIではファイルのアップロードや削除等の各イベントの発生に対して&lt;/p>
&lt;p>任意の処理を実行することが出来ます。&lt;/p>
&lt;p>イベント発生の都度、任意のエンドポイントに通知するWebhookの方法と&lt;/p>
&lt;p>イベントのストリームをロングポーリングして取得する方法の2つを利用することが出来ます。&lt;/p></description></item><item><title>Box API叩いてみた【ContentAPI編】</title><link>https://blog.freedom-man.com/box-api-oauth2-app.html</link><pubDate>Sun, 26 Jul 2015 18:32:30 +0000</pubDate><guid>https://blog.freedom-man.com/box-api-oauth2-app.html</guid><description>&lt;p>&lt;a href="https://www.box.com/ja_JP/home/" target="_blank">Box&lt;/a>はDropbox的なストレージサービスで、Businessプラン以上は容量無制限だったり&lt;/p>
&lt;p>文書の暗号化が標準サポートだったりする、エンプラ向けなサービスになります。&lt;/p>
&lt;p>ということで、今回はBoxのAPI（ContentAPI）の使い方を説明していきます！&lt;/p>
&lt;p>SalesforceからBox APIを叩くサンプルを作っていきます。&lt;/p>
&lt;h2>&lt;strong>1. アプリケーションの設定&lt;/strong>&lt;/h2>
OAuth2.0を利用するので、twitterやfacebook等のようにアプリケーションを設定します。
&lt;p>&lt;a href="https://developers.box.com/" target="_blank">developersのサイト&lt;/a>でログインします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-developer-login.jpg">&lt;img class="alignnone size-medium wp-image-1700" src="https://blog.freedom-man.com/img/2015/07/box-developer-login-300x151.jpg" alt="box-developer-login" width="300" height="151" />&lt;/a>&lt;/p>
&lt;p>boxアカウント持っている場合は、MyAppsからログインして&lt;/p>
&lt;p>持っていない場合はSignUpで&lt;a href="https://box-content.readme.io/docs/developer-account-faq" target="_blank">無料の開発者用のアカウント&lt;/a>を作成する必要があります。&lt;/p>
&lt;p>ログイン後、初めてアプリケーションを作成する場合は以下の画面が表示されるので、&lt;/p>
&lt;p>そのまま「はじめに」をクリックします。（これ日本語訳が…）&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-app-firstapp.jpg">&lt;img class="alignnone size-medium wp-image-1702" src="https://blog.freedom-man.com/img/2015/07/box-api-app-firstapp-300x230.jpg" alt="box-api-app-firstapp" width="300" height="230" />&lt;/a>&lt;/p>
&lt;p>アプリケーション名を設定して、「アプリケーションの作成」をクリックします。&lt;/p>
&lt;p>ラジオボタンは「Boxコンテンツ」のままでOK。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-app-create.jpg">&lt;img class="alignnone size-medium wp-image-1701" src="https://blog.freedom-man.com/img/2015/07/box-api-app-create-300x192.jpg" alt="box-api-app-create" width="300" height="192" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>完了すると以下の画面になるので、そのまま「アプリケーションの構成」をクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-app-complete.jpg">&lt;img class="alignnone size-medium wp-image-1698" src="https://blog.freedom-man.com/img/2015/07/box-api-app-complete-300x150.jpg" alt="box-api-app-complete" width="300" height="150" />&lt;/a>&lt;/p>
&lt;p>そうすると、アプリケーションの詳細画面が表示されます。&lt;/p>
&lt;p>色々と設定できるのですが、大事なところはOAuth2パラメータの部分になります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-app-oauth2.jpg">&lt;img class="alignnone size-medium wp-image-1697" src="https://blog.freedom-man.com/img/2015/07/box-api-app-oauth2-300x156.jpg" alt="box-api-app-oauth2" width="300" height="156" />&lt;/a>&lt;/p>
&lt;p>BoxのAPIの認証はOAuth2.0のAuthorization Code Grantになるので&lt;/p>
&lt;p>redirect_uriを設定し、client_id、client_secretをメモっておきます。&lt;/p>
&lt;p>redirect_uriに関しては必須項目になりますがURI形式であればOKなので&lt;/p>
&lt;p>https://localhostとかを入力して「アプリケーションの保存」で設定を保存します。&lt;/p>
&lt;h2>2. Salesforceの設定&lt;/h2>
ApexのSDKもあるみたいですが（&lt;a href="https://github.com/dhoechst/ApexBox" target="_blank">dhoechst/ApexBox&lt;/a>）、今回はNamed Credentialを使って叩いてみます。
&lt;p>OAuth danceをイチから実装しなくて良いから楽なんですよねー。&lt;/p>
&lt;p>ということで、以下のように認証プロバイダを設定します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-sfdc-connect-app.png">&lt;img class="alignnone size-medium wp-image-1703" src="https://blog.freedom-man.com/img/2015/07/box-api-sfdc-connect-app-300x217.png" alt="box-api-sfdc-connect-app" width="300" height="217" />&lt;/a>&lt;/p>
&lt;ul>
	&lt;li>承認エンドポイントURL　→　https://app.box.com/api/oauth2/authorize&lt;/li>
	&lt;li>トークンエンドポイントURL　→　https://app.box.com/api/oauth2/token&lt;/li>
	&lt;li>コンシューマ鍵と、コンシューマの秘密
→　それぞれ1のアプリ作成時にメモったclient_id, client_secret&lt;/li>
&lt;/ul>
と、それぞれ値をセットします。
&lt;p> &lt;/p>
&lt;p>発行された「コールバックURL」はBoxのアプリケーションのredirect_uriにセットしておきます。&lt;/p>
&lt;p>Named Credentialは以下のように設定。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/07/box-api-sfdc-named-credential.jpg">&lt;img class="alignnone size-medium wp-image-1705" src="https://blog.freedom-man.com/img/2015/07/box-api-sfdc-named-credential-300x226.jpg" alt="box-api-sfdc-named-credential" width="300" height="226" />&lt;/a>&lt;/p></description></item><item><title>onelogin/php-samlを触ってみた</title><link>https://blog.freedom-man.com/onelogin_php-saml.html</link><pubDate>Sun, 28 Jun 2015 16:31:22 +0000</pubDate><guid>https://blog.freedom-man.com/onelogin_php-saml.html</guid><description>&lt;p>SAMLのSPとなるようなアプリケーションが簡単に作れるかどうか、という技術検証で&lt;/p>
&lt;p>&lt;a href="https://github.com/onelogin/php-saml" target="_blank">onelogin/php-saml&lt;/a>を触ったので使い方をメモってみましたー。&lt;/p>
&lt;p>今回はSalesforceをIdP、phpのアプリをSP（ローカル環境）として&lt;/p>
&lt;p>ソースに付随されているサンプルのアプリを動かしてみます。&lt;/p>
&lt;h2>1.  インストール&lt;/h2>
php使いの人にはお馴染みの&lt;a href="https://getcomposer.org/" target="_blank">Composer&lt;/a>を使ってインストールします。
&lt;p>Windowsの場合は&lt;a href="https://chocolatey.org/" target="_blank">Chocolatey&lt;/a>だと何故か上手く行かなかったので、&lt;/p>
&lt;p>&lt;a href="https://getcomposer.org/doc/00-intro.md#installation-windows" target="_blank">本家&lt;/a>からインストーラでインストールした方が良いかもしれないです。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ composer init
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>からの　composer.jsonに&amp;quot;onelogin/php-saml&amp;quot;: &amp;ldquo;master-dev&amp;rdquo; を追加&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge/php&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;authors&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;email&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge@example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;require&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;onelogin/php-saml&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#0a3069">&amp;#34;master-dev&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>からの&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ composer install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>でvenderディレクトリ配下にインストールされます。&lt;/p>
&lt;h2>2. 証明書の設定&lt;/h2>
SP側の証明書を設定します。
&lt;p>certsフォルダに秘密鍵と証明書を作成します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> php-saml/certs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ openssl genrsa &lt;span style="color:#0550ae">2048&lt;/span> &amp;gt; sp.key
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ openssl req -new -key sp.key &amp;gt; sp.csr
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ openssl x509 -days &lt;span style="color:#0550ae">3650&lt;/span> -req -signkey sp.key &amp;lt; sp.csr &amp;gt; sp.crt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2>3. settings.phpの設定&lt;/h2>
まずdemo1ディレクトリ配下のsettings_example.phpをコピーしてsettings.phpを作成します。
&lt;p>settings.phpの中身は以下の通り。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;?&lt;/span>&lt;span style="color:#1f2328">php&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$spBaseUrl&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https://localhost/php-work/vendor/onelogin/php-saml&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#57606a">//php-samlへのURLをセット
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$settingsInfo&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#0a3069">&amp;#39;strict&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 	&lt;span style="color:#0a3069">&amp;#39;debug&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;sp&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;entityId&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$spBaseUrl&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/demo1/metadata.php&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;assertionConsumerService&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;url&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$spBaseUrl&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/demo1/index.php?acs&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;singleLogoutService&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;url&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$spBaseUrl&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/demo1/index.php?sls&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;NameIDFormat&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;idp&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;entityId&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https://hoge.my.salesforce.com&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;singleSignOnService&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;url&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https://hoge.my.salesforce.com/idp/endpoint/HttpRedirect&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;singleLogoutService&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;url&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;x509cert&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a">//現時点では未設定でOK
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;security&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">array&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>  &lt;span style="color:#0a3069">&amp;#39;authnRequestsSigned&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>$spBaseUrlにはphp-samlへのURLをセット。&lt;/p></description></item><item><title>EmbulkのSalesforce outputプラグインを作ってみた。</title><link>https://blog.freedom-man.com/embulk-output-salesforce.html</link><pubDate>Tue, 23 Jun 2015 00:26:49 +0000</pubDate><guid>https://blog.freedom-man.com/embulk-output-salesforce.html</guid><description>&lt;p>&lt;a href="https://github.com/embulk/embulk" target="_blank">Embulk&lt;/a>というOSSが非常に気になっていた＆Salesforceのoutputプラグインが無かったので、勉強がてら作ってみました。↓&lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/embulk-output-salesforce" target="_blank">tzmfreedom/embulk-output-salesforce&lt;/a>&lt;/p>
&lt;p>今回は備忘としてoutputプラグインの作り方と、&lt;a href="https://rubygems.org/gems/embulk-output-salesforce" target="_blank">embulk-output-salesforce&lt;/a>の使い方を書いていきます！
Output Pluginの作成は以下のURLを参考にしました。&lt;/p>
&lt;p>&lt;a href="http://qiita.com/muga_nishizawa/items/427c933aaa0e5e437063" target="_blank">Java で Embulk Output Plugin を書く - Qiita&lt;/a>&lt;/p>
&lt;p>ちなみに、ソースコードを全て読んだわけではない＆読んだところも合っているか怪しいので、多少間違いが有ると思いますがご了承願います。&lt;/p>
&lt;h2>outputプラグインの作り方&lt;/h2>
&lt;h2>テンプレートの作成&lt;/h2>
&lt;p>プラグインはJavaかRubyで書くことが出来ます。今回はJavaを使いました。
プラグインのテンプレートは以下のコマンドで作成できます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>embulk new java-output &lt;span style="color:#0550ae">{&lt;/span>プラグイン名&lt;span style="color:#0550ae">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これでGradleベースのプロジェクトが自動生成されます。あとはsrc/main/java/org/embulk/outputにあるJavaファイルを書いていけばOK。&lt;/p>
&lt;h2>設定ファイルのキー値の設定&lt;/h2>
&lt;p>Taskクラスを継承したPluginTaskクラスにキー値と属性を指定し&lt;/p>
&lt;p>ConfigSource#loadConfig(PluginTask.class)&lt;/p>
&lt;p>で実際の設定を取得します。&lt;/p>
&lt;p>PluginTaskにはannotationで属性を指定します。任意入力の項目の場合はOptional型で定義します。未指定時のデフォルト設定値はConfigDefaultアノテーションで定義します。文字列のデフォルトを定義する場合は@ConfigDefault(&amp;quot;&amp;quot;hoge&amp;quot;&amp;quot;)のようにエスケープが必要。&lt;/p>
&lt;h2>処理の流れ&lt;/h2>
&lt;p>OutputPluginの処理の流れだけに着目すると&lt;/p>
&lt;p>OutputPlugin#transaction&lt;/p>
&lt;p>→OutputPlugin#open（→TransactionalPageOutput#add &amp;hellip;）&lt;/p>
&lt;p>→OutputPlugin#cleanup&lt;/p>
&lt;p>といったフローになります（自信なし）&lt;/p>
&lt;h2>TransactionalPageOutput&lt;/h2>
&lt;p>OutputPlugin#openではTransactionalPageOutputを継承したクラスを戻り値とします。
openはタスクの数だけ呼ばれるっぽいので、fileのinputプラグインを使って2つのファイルを処理する場合は、openが2回呼ばれて、TransactionalPageOutputのサブクラスのインスタンスが2つ作成されます。&lt;/p>
&lt;p>TransactionalPageOutput#addでは引数のPageに実際のレコードが渡されるので、PageをPageReaderに読ませて、PageReaderではスキーマに応じた全カラムに対して処理を行うことになります。100桁くらいの3000行のデータを入れたら、一回のadd呼び出しで110件ちょっとのレコードが格納されていました。&lt;/p>
&lt;p>pageReader.getSchema().visitColumns(&amp;hellip;)の部分が全カラムに関する処理になり、引数にはColumnVisitorを継承したクラスを入れます（利用がワンタイムなので匿名クラスにしてます）。ColumnVisitorではカラムのデータ型に応じた処理を記載していきます。&lt;/p>
&lt;p>Salesforceの場合はTimeStampだけ注意しておけばOKで、pageReaderで取得できるTimeStampの型はorg.joda.time.DateTime型であるため、&lt;a href="https://github.com/forcedotcom/wsc/" target="_blank">wsc&lt;/a>を利用する場合は、データ型をjava.util.Calendar型やjava.util.Date型に変換する必要があります。wscはデータ型によってSOAPのxsi:typeを書き換えるので、SObject#addFieldで入れるObject型は注意が必要です。&lt;/p>
&lt;h2>テストの方法&lt;/h2>
&lt;p>pluginのテストの方法としては大きく2つあり、1つ目は実際のembulkコマンドに作ったプラグインを食わせる方法、もう1つはembulkのクラスを使ってJava内で実行するやり方です。&lt;/p>
&lt;p>1つ目は&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>gradlew classpath
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>からの&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>embulk run -I ./embulk-output-salesforce/lib config.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>を実行すればプラグインの挙動を確認できます。&lt;/p>
&lt;p>2つ目はembulk runでやってることをJavaのコードを書いて実現するやり方です。&lt;/p>
&lt;p>参考URLはこちら→&lt;a href="http://hito4-t.hatenablog.com/entry/2015/03/10/191225" target="_blank">Embulkプラグインのテストを楽にやりたい - 今日もプログラミング&lt;/a>&lt;/p>
&lt;h2>embulk-output-salesforceの使い方&lt;/h2>
&lt;p>基本的には以下のようなoutputの定義を設定ファイルに書けばOKです。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>out:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> type: salesforce
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> username: hoge@example.com
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> password: fuga
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> sobject: Account
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ログインからデータ入力まで全てSOAP APIを使ってます。
内部的にはカラム名＝API参照名としてデータを格納しているので、inputプラグインのfileを使う場合、inputには以下のように記述します。&lt;/p></description></item><item><title>Fiddlerを使ってEclipseとData Loaderをトラッキング</title><link>https://blog.freedom-man.com/fiddler-eclipse-dataloader.html</link><pubDate>Sun, 21 Jun 2015 23:01:46 +0000</pubDate><guid>https://blog.freedom-man.com/fiddler-eclipse-dataloader.html</guid><description>&lt;p>今更ながらEclipseのforce.com IDEやData Loaderが&lt;/p>
&lt;p>どのAPIをどのタイミングで叩いているかが気になったので&lt;/p>
&lt;p>Fiddlerのプロキシを噛ませてネットワーク通信をトラッキングしてみました。&lt;/p>
&lt;h2>Fiddlerの証明書のインストール&lt;/h2>
JavaのキーストアにFiddlerのルート証明書をインストールします。
&lt;p>まず、Fiddlerのルート証明書をFiddlerからエクスポートします。&lt;/p>
&lt;p>Fiddlerを起動し、メニューのTools＞Fiddler Optionsをクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/06/Fiddler_top.jpg">&lt;img class="alignnone size-medium wp-image-1654" src="https://blog.freedom-man.com/img/2015/06/Fiddler_top-300x99.jpg" alt="Fiddler_top" width="300" height="99" />&lt;/a>&lt;/p>
&lt;p>HTTPSのタブでExport Root Certificate to Desktopボタンをクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/06/Fiddler_tool.jpg">&lt;img class="alignnone size-medium wp-image-1655" src="https://blog.freedom-man.com/img/2015/06/Fiddler_tool-300x201.jpg" alt="Fiddler_tool" width="300" height="201" />&lt;/a>&lt;/p>
&lt;p>そうすると、デスクトップにFiddlerRoot.cerの名前で証明書がエクスポートされます。&lt;/p>
&lt;p>これを以下のコマンドでJavaのキーストアにインポートします。&lt;/p>
&lt;p>&amp;lt;JDK_Home&amp;gt;\bin\keytool.exe -import -file C:\Users&amp;lt;Username&amp;gt;\Desktop\FiddlerRoot.cer -keystore FiddlerKeystore -alias Fiddler&lt;/p>
&lt;p>パスワードを聞かれるので、適当なパスワードをセットします。&lt;/p>
&lt;h2>Eclipseの設定&lt;/h2>
eclipse.iniの行末に以下の2行を追記します。pathはFiddlerKeyStoreを作った場所をセット。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>-Djavax.net.ssl.trustStore=C:/path/to/FiddlerKeystore
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-Djavax.net.ssl.trustStorePassword=hogefuga
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これでeclipse.exeを起動し、プロキシの設定をします。&lt;/p>
&lt;p>ツールバーのWindow＞Preferencesをクリックして&lt;/p>
&lt;p>GeneralのNetwork Connectionsを開きます。&lt;/p>
&lt;p>Fiddlerが起動している状態でNativeを選択すると&lt;/p>
&lt;p>以下のように127.0.0.1:8888を向いている状態になります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/06/eclipse_proxysetting.jpg">&lt;img class="alignnone size-medium wp-image-1656" src="https://blog.freedom-man.com/img/2015/06/eclipse_proxysetting-300x270.jpg" alt="eclipse_proxysetting" width="300" height="270" />&lt;/a>&lt;/p>
&lt;p>これでEclipseのHTTP/HTTPS通信をFiddlerでトラッキングできます。&lt;/p>
&lt;h2>Data Loaderの設定&lt;/h2>
以下のコマンドでData Loaderを起動します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;#34;C:\Program Files (x86)\salesforce.com\Data Loader\Java\bin\javaw.exe&amp;#34;&lt;/span> ^
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-Djavax.net.ssl.trustStore&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;C:/path/to/FiddlerKeyStore&amp;#34;&lt;/span> ^
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-Djavax.net.ssl.trustStorePassword&lt;span style="color:#0550ae">=&lt;/span>hogefuga ^
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>-jar &lt;span style="color:#0a3069">&amp;#34;C:\Program Files (x86)\salesforce.com\Data Loader\dataloader-30.0.0-uber.jar&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Data Loaderに同梱されているJavaを使わないとバージョンの差異等でエラーになる可能性があります。&lt;/p>
&lt;p>あとは、起動後のData Loaderのプロキシ設定をすればOK。&lt;/p></description></item><item><title>Olingo + Lightning ConnectでODataに触れてみた</title><link>https://blog.freedom-man.com/olingo-lightning-connect.html</link><pubDate>Sun, 24 May 2015 09:50:14 +0000</pubDate><guid>https://blog.freedom-man.com/olingo-lightning-connect.html</guid><description>&lt;p>SalesforceのSummer15のリリースで&lt;a href="https://help.salesforce.com/apex/HTViewHelpDoc?id=platform_connect_about.htm&amp;language=ja" target="_blank">Lightning Connect&lt;/a>が利用できるようになったようなので&lt;/p>
&lt;p>&lt;a href="http://www.odata.org/" target="_blank">OData&lt;/a>の勉強がてら触ってみましたー。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Lightning Connectは任意のOData Providerが提供するODataサービスを使って&lt;/p>
&lt;p>Salesforceから外部データをCRUDできますよーっていう機能。&lt;/p>
&lt;p>OData自体はインターフェースが仕様に準拠していれば裏はなんでもOKっていう&lt;/p>
&lt;p>HTTP版ODBC的なプロトコルです。&lt;/p>
&lt;p>ODataに関しては以下のリンクが詳しいです。&lt;/p>
&lt;p>&lt;a href="http://www.slideshare.net/seosoft/odata-12997958" target="_blank">OData って何？&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>SFDCでのLightning Connectの設定に関しては以下のリンクが詳しいです。&lt;/p>
&lt;p>&lt;a href="http://www.terrasky.co.jp/blog/?p=10602" target="_blank">Lightning Connectを手軽に試してみる « TerraSky Tech Blog&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://www.slideshare.net/shunjikonishi/salesforceodata" target="_blank">Salesforce連携のためのOData入門&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は自前でOData Providerを作って、それに対してSFDCから接続してみます。&lt;/p>
&lt;p>以下のリンクが自前でクライアント、サーバ側を構築する際のライブラリになります。&lt;/p>
&lt;p>&lt;a href="http://www.odata.org/libraries/" target="_blank">Libraries · OData - the Best Way to REST&lt;/a>&lt;/p>
&lt;p>今回はJavaの&lt;a href="http://olingo.apache.org/" target="_blank">Apache Olingo Library&lt;/a>を使ってサンプルをベースにOData Providerを作っていきます。&lt;/p>
&lt;p>※ちなみにOData全然知らないので解説で所々間違いが有ると思いますのでご注意を！&lt;/p>
&lt;h2>0. 準備&lt;/h2>
JDKとかmavenとかインストールしておきます。
&lt;h2>1. サンプルのmavenプロジェクトを作成&lt;/h2>
SFDCでは現時点(2015/05/15)ではOData v2.0にしか対応していないので
&lt;p>v2.0のチュートリアルに従って進めていきます。&lt;/p>
&lt;p>まず、&lt;a href="http://olingo.apache.org/doc/odata2/sample-setup.html" target="_blank">Sample Project Setup&lt;/a>に従って以下のmvnコマンドを実行します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>mvn archetype:generate &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -DinteractiveMode&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#6639ba">false&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -Dversion&lt;span style="color:#0550ae">=&lt;/span>1.0.0-SNAPSHOT &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -DgroupId&lt;span style="color:#0550ae">=&lt;/span>com.sample &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -DartifactId&lt;span style="color:#0550ae">=&lt;/span>my-car-service &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -DarchetypeGroupId&lt;span style="color:#0550ae">=&lt;/span>org.apache.olingo &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -DarchetypeArtifactId&lt;span style="color:#0550ae">=&lt;/span>olingo-odata2-sample-cars-service-archetype &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -DarchetypeVersion&lt;span style="color:#0550ae">=&lt;/span>RELEASE
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>プロジェクトがいい感じに作成されたら、ビルドします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">cd&lt;/span> my-car-service
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mvn clean install
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>そうするといい感じにtarget内にwarが出来上がるので&lt;/p></description></item><item><title>Cocos2d-JSを触ってみた【BGM再生・キー入力・アニメーション・衝突判定】</title><link>https://blog.freedom-man.com/cocos2d-js-etc1.html</link><pubDate>Sat, 14 Mar 2015 12:28:21 +0000</pubDate><guid>https://blog.freedom-man.com/cocos2d-js-etc1.html</guid><description>&lt;p>今回もCocos2d-JSを色々と弄ってみます。&lt;/p>
&lt;h2>1. BGM再生&lt;/h2>
いつも通りresディレクトリ内に音声ファイルをぶちこんで、src/resource.jsを修正します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>  &lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>  &lt;span style="color:#1f2328">hoge_mp3&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;res/hoge.mp3&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>  &lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>あとはsrc/app.jsのLayerのctorに以下のコードを追記するだけで音楽が再生されます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">audioEngine&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">playMusic&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">hoge_mp3&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">//BGM
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">audioEngine&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMusicVolume&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0.5&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">//音量の調整
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ちなみに、効果音再生は&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">audioEngine&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">playEffect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">se01_wav&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>って感じで行けます。&lt;/p>
&lt;h2>2. キー入力受付け&lt;/h2>
以下のようにcc.eventManagerにキーボード入力に対するイベントリスナーを追加するだけ。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">eventManager&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addListener&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">EventListener&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">KEYBOARD&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//キー入力したとき
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">onKeyPressed&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">37&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//左
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">38&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//上
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">39&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//右
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">40&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//下
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//キーを離したとき
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">onKeyReleased&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">keyCode&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>あとは各キーコードに応じた処理をfunction内で定義すればOK。&lt;/p>
&lt;h2>3. アニメーション&lt;/h2>
RPGの歩行アニメーション的な永続的なアニメーションの場合は以下のようにして処理を書きます。
&lt;p>画像一枚32px * 32pxで横3縦4で配置されるキャラチップ画像を想定しています。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">sprites&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">sprites&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">SpriteFrame&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">actor_png&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">sprites&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">SpriteFrame&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">actor_png&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">sprites&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">SpriteFrame&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">actor_png&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">64&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">sprites&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">SpriteFrame&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">actor_png&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">action_down&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">RepeatForever&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Animate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Animation&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">sprites&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0.2&lt;/span>&lt;span style="color:#1f2328">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sprite&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">runAction&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">action_down&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>永続的なアニメーションなので、ループする画像のパターンを定義する必要があって&lt;/p>
&lt;p>それがspritesの配列部分になります。&lt;/p>
&lt;p>1→2→3→2→1→2→&amp;hellip;と続くので1→2→3→2のループを定義しています。&lt;/p>
&lt;p>キー入力とうまく組み合わせて、キャラの方向を検知して&lt;/p>
&lt;p>アニメーションパターンを都度runActionで変更してあげればRPGっぽいキャラ移動が出来るようになります。&lt;/p>
&lt;h2>4. 衝突判定&lt;/h2>
前回やったタイルマップを使えば衝突判定を簡単に実装できます。
&lt;p>&amp;ldquo;レイヤー＞タイル・レイヤーの追加&amp;quot;からレイヤーを追加します。&lt;/p>
&lt;p>レイヤーの名前はcollisionとかにしてください。&lt;/p>
&lt;p>collisionレイヤーの衝突判定を付けたいところに適当なタイルセットで塗っていきます。&lt;/p>
&lt;p>わかりやすくするために黒とかの単色タイルセットを作って塗っていくと&lt;/p>
&lt;p>後で衝突設定した場所がわかりやすいです。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/cocos2djs-tmx-collision2.jpg">&lt;img class="alignnone size-medium wp-image-1597" src="https://blog.freedom-man.com/img/2015/03/cocos2djs-tmx-collision2-300x221.jpg" alt="cocos2djs-tmx-collision2" width="300" height="221" />&lt;/a>&lt;/p>
&lt;p>塗り終わったらレイヤーの透過度を0にします。&lt;/p></description></item><item><title>Salesforce Communityでカスタムドメイン使ってみる。</title><link>https://blog.freedom-man.com/sf-community-customdomain.html</link><pubDate>Sat, 14 Mar 2015 12:14:44 +0000</pubDate><guid>https://blog.freedom-man.com/sf-community-customdomain.html</guid><description>&lt;p>Salesforce Communityのカスタムドメインがいつの間にかSSL対応出来るっぽかったので試してみました。&lt;/p>
&lt;h2>1. Communityの作成&lt;/h2>
テキトーにドメインを決めて作成します。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/create_community.jpg">&lt;img class="alignnone size-medium wp-image-1614" src="https://blog.freedom-man.com/img/2015/03/create_community-300x51.jpg" alt="create_community" width="300" height="51" />&lt;/a>&lt;/p>
&lt;h2>2. CSRを発行&lt;/h2>
セキュリティのコントロール＞証明書と鍵の管理　から証明機関署名証明書の作成をクリックして
&lt;p>証明書の情報を入力。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/create_certificate_setting.jpg">&lt;img class="alignnone size-medium wp-image-1606" src="https://blog.freedom-man.com/img/2015/03/create_certificate_setting-300x118.jpg" alt="create_certificate_setting" width="300" height="118" />&lt;/a>&lt;/p>
&lt;p>保存後に「証明書署名要求のダウンロード」でCSRをダウンロード&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/display_certificate_setting.jpg">&lt;img class="alignnone size-medium wp-image-1608" src="https://blog.freedom-man.com/img/2015/03/display_certificate_setting-300x78.jpg" alt="display_certificate_setting" width="300" height="78" />&lt;/a>&lt;/p>
&lt;h2>3. 認証局の署名付きSSL証明書を発行&lt;/h2>
ここは各認証局毎の手順が異なるので、詳細は各認証局のサイトを参照してください。
&lt;h2>4. 認証局に発行してもらった証明書をSFDCに取り込む&lt;/h2>
2で登録した証明書の「署名済み証明書の更新」から発行してもらった証明書を取り込みます。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/display_certificate_setting2.jpg">&lt;img class="alignnone size-medium wp-image-1607" src="https://blog.freedom-man.com/img/2015/03/display_certificate_setting2-300x78.jpg" alt="display_certificate_setting2" width="300" height="78" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/upload_certificate.jpg">&lt;img class="alignnone size-medium wp-image-1604" src="https://blog.freedom-man.com/img/2015/03/upload_certificate-300x67.jpg" alt="upload_certificate" width="300" height="67" />&lt;/a>&lt;/p>
&lt;h2>5. ドメインの追加&lt;/h2>
ドメイン管理＞ドメイン　でカスタムドメインを登録します。
&lt;p>証明書は1-4で登録したものを選択。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/create_domain.jpg">&lt;img class="alignnone size-medium wp-image-1603" src="https://blog.freedom-man.com/img/2015/03/create_domain-300x92.jpg" alt="create_domain" width="300" height="92" />&lt;/a>&lt;/p>
&lt;p>DNSのCNAMEレコードで&lt;/p>
&lt;p>{カスタムドメイン}→{カスタムドメイン}.{組織IDのLowerCase}.live.siteforce.com&lt;/p>
&lt;p>を作成するのもお忘れなく（これ作んないとドメイン登録できないです）&lt;/p>
&lt;h2>6. カスタムURLの追加&lt;/h2>
新規カスタムURLから登録を行います。
&lt;p>サイトはCommunityを選択。パスはそのままで。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/create_cutom_url.jpg">&lt;img class="alignnone size-medium wp-image-1602" src="https://blog.freedom-man.com/img/2015/03/create_cutom_url-300x67.jpg" alt="create_cutom_url" width="300" height="67" />&lt;/a>&lt;/p>
&lt;p>これで、コミュニティのカスタムドメイン対応が完了します。&lt;/p>
&lt;p>反映は少し時間がかかるかも？&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/03/community_certificate.jpg">&lt;img class="alignnone size-medium wp-image-1612" src="https://blog.freedom-man.com/img/2015/03/community_certificate-300x296.jpg" alt="community_certificate" width="300" height="296" />&lt;/a>&lt;/p></description></item><item><title>Cocos2d-JSを触ってみた【画像表示・タイルマップ表示編】</title><link>https://blog.freedom-man.com/cocos2d-js-image.html</link><pubDate>Sun, 01 Mar 2015 20:12:09 +0000</pubDate><guid>https://blog.freedom-man.com/cocos2d-js-image.html</guid><description>&lt;p>&lt;a title="Cocos2d-JSを触ってみた【環境構築編】" href="https://blog.freedom-man.com/cocos2d-js-environment/" target="_blank">前回&lt;/a>は環境構築を行ったので今回は画像を表示したり、タイルマップを表示したりしてみます。&lt;/p>
&lt;h2>1. ディレクトリ構成&lt;/h2>
プロジェクトを作成すると、こんな感じでファイル展開されます。
```
CMakeLists.txt
frameworks
index.html
main.js
project.json
res
src
tools
```
CMakeLists.txt→ビルドの設定ファイル
&lt;p>frameworks, tools→Cocos2d-JSのAPIとかそういうのが格納されてるディレクトリ&lt;/p>
&lt;p>res→リソース（画像とか音声ファイルとか）を格納するディレクトリ&lt;/p>
&lt;p>src→プログラムのソースコードが格納されているディレクトリ&lt;/p>
&lt;p>index.html→ゲームのHTMLファイル&lt;/p>
&lt;p>project.json→ゲームのエンジンとかフレームレートとかの設定を行うJSONファイル&lt;/p>
&lt;p>main.js→index.htmlから呼び出されるJSファイル。このJSファイルを起点にゲームが開始される。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、基本的にはresディレクトリの中にリソースファイルを追加したり&lt;/p>
&lt;p>src内でJavaScriptのソースコード書いたりするのが開発の基本的な流れになります。&lt;/p>
&lt;h2>2. 画像の表示&lt;/h2>
実際に画像を表示してみます！
&lt;p>まずは適当な画像を入手します。&lt;/p>
&lt;p>今回はRPG的なモノを意識して↓からキャラチップ画像をダウンロードさせていただきました！&lt;/p>
&lt;p>&lt;a title="http://usui.moo.jp/rpg_tukuru.html" href="http://usui.moo.jp/rpg_tukuru.html" target="_blank">RPGツクール素材支部|臼井の会&lt;/a>&lt;/p>
&lt;p>用意した画像（今回はactor.png）をresディレクトリに格納します。&lt;/p>
&lt;p>res/resource.jsに用意した画像のファイル名を追記します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">actor_png&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;res/actor.png&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">g_resources&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">for&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">i&lt;/span> &lt;span style="color:#cf222e">in&lt;/span> &lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">g_resources&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">i&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>画像の設定が完了したので、画像を表示するコードをsrc/app.jsに書きます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">HelloWorldLayer&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Layer&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">extend&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">sprite&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">ctor&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">_super&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//画面サイズの取得
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">size&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">winSize&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//画像の表示
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sprite&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Sprite&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">actor_png&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">));&lt;/span> &lt;span style="color:#57606a">//左上から32px*32pxで画像切り出し
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sprite&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">attr&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>&lt;span style="color:#1f2328">x&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">size&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">width&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>&lt;span style="color:#0550ae">2&lt;/span> &lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">y&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">size&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">height&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">});&lt;/span> &lt;span style="color:#57606a">//画像位置の設定
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addChild&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sprite&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">HelloWorldScene&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Scene&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">extend&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">onEnter&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">_super&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">layer&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">HelloWorldLayer&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addChild&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">layer&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ルートディレクトリのmain.jsは以下のように書き換えます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">game&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">onStart&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">view&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">adjustViewPort&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">view&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setDesignResolutionSize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">640&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">480&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ResolutionPolicy&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">SHOW_ALL&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">view&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">resizeWithBrowserSize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//load resources
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LoaderScene&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">preload&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">g_resources&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">director&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">runScene&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">HelloWorldScene&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">cc&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">game&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">run&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>index.htmlを叩くと、インクルードされているmain.jsが呼び出され&lt;/p></description></item><item><title>Salesforceのデータバックアップ用Dockerfile作ったので公開してみた</title><link>https://blog.freedom-man.com/dockerfile-exportjs.html</link><pubDate>Sun, 15 Feb 2015 13:16:37 +0000</pubDate><guid>https://blog.freedom-man.com/dockerfile-exportjs.html</guid><description>&lt;p>&lt;del>Apex書くのに飽きたため&lt;/del>業務の効率を上げるため、Salesforceの各オブジェクトごとの&lt;/p>
&lt;p>レコードをCSVでフルバックアップするスクリプト書いてDockerfileにしてみました。&lt;/p>
&lt;p>S3の設定をすれば各csvをgzip化して、S3にアップロードするようにもなっていたり。&lt;/p>
&lt;p>DataLoader使えば良いじゃん説がありますがJavaとXMLの設定がめんどかった&lt;/p>
&lt;p>＋herokuみたいなone offでクリーンなエクスポートをしてみたかったってのが動機っす。&lt;/p>
&lt;p> &lt;/p>
&lt;p>完成品は&lt;a title="https://github.com/tzmfreedom/sfdc-exportjs" href="https://github.com/tzmfreedom/sfdc-exportjs" target="_blank">こちら&lt;/a>。&lt;/p>
&lt;p>&lt;a title="https://hub.docker.com/" href="https://hub.docker.com/" target="_blank">Dockerhub&lt;/a>にも登録してます→&lt;a title="https://registry.hub.docker.com/u/tzmfree/sfdc-exportjs/" href="https://registry.hub.docker.com/u/tzmfree/sfdc-exportjs/" target="_blank">tzmfree/sfdc-exportjs&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>使い方は、ログ用のディレクトリを作成して&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>mkdir /var/log/sfdc-exportjs
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>環境変数セットしたDocker走らせるだけ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker run --rm -t &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">SFDC_USERNAME&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge@example.com&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">SFDC_PASSWORD&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;fuga123&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">SFDC_LOGINURL&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;https://login.salesforce.com&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">SFDC_TARGETOBJECT&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Account;Contact&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">SFDC_LIMIT&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;500000&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">S3_BUCKET&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;backup&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">AWS_ACCESS_KEY_ID&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;AKI***************&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">AWS_SECRET_ACCESS_KEY&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;********************&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-e &lt;span style="color:#953800">MODE&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;parallel&amp;#34;&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-v /var/log/sfdc-exportjs:/var/log/sfdc-exportjs &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>tzmfree/sfdc-exportjs /sbin/my_init -- ./export.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>ボリュームで指定したディレクトリ（ホスト側に作ったディレクトリ）にログとかCSVファイルが格納される仕様っす。&lt;/p>
&lt;p>CSVファイルをごにょりたい場合はdocker run後の処理でそのCSVを煮るなり焼くなりすればOK。&lt;/p>
&lt;p>スケジュール起動したい場合はホスト側のcrondでdocker runごとブン回してください。&lt;/p>
&lt;p>以下はDockerfileの備忘っす。&lt;/p>
&lt;h2>Dockerfileの書き方&lt;/h2>
MAINTAINERは作った人の名前。
&lt;p>FROMはベースとなるDockerイメージ。&lt;/p>
&lt;p>今回ベースとしている&lt;a title="https://github.com/phusion/baseimage-docker" href="https://github.com/phusion/baseimage-docker" target="_blank">phusion/baseimage&lt;/a>はDocker使う時のハマりどころを色々と回避してくれてる&lt;/p>
&lt;p>ベースイメージで、sshdとかcrondとかも初期装備されてる便利なDockerイメージ。&lt;/p>
&lt;p>Dockerfileでよく使うのはRUNとADD。&lt;/p>
&lt;p>RUNは実行するコマンドで大体パッケージインストールやgit clone等のセットアップ系を行います。&lt;/p>
&lt;p>ADDは実行ディレクトリ配下にある特定のファイルをアップロードする操作で&lt;/p>
&lt;p>今回はエクスポート担当のNode.jsスクリプトをアップロードしてます。&lt;/p>
&lt;h2>Dockerhubへの登録とか&lt;/h2>
今回はgithubやbitbucketにpushしたら自動的にビルドしてDockerhubにアップロードしてくれる
&lt;p>Automated Buildという機能を利用しました。&lt;/p>
&lt;p>設定は超簡単で、Dockerhubにログイン後にAdd Repositoryのボタンから&lt;/p>
&lt;p>Automated Buildを選択して&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/02/dockerhub_automatedbuild1.jpg">&lt;img class="alignnone size-medium wp-image-1577" src="https://blog.freedom-man.com/img/2015/02/dockerhub_automatedbuild1-300x116.jpg" alt="dockerhub_automatedbuild1" width="300" height="116" />&lt;/a>&lt;/p>
&lt;p>gitのサービス選んで&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/02/dockerhub_automatedbuild2.jpg">&lt;img class="alignnone size-medium wp-image-1576" src="https://blog.freedom-man.com/img/2015/02/dockerhub_automatedbuild2-300x180.jpg" alt="dockerhub_automatedbuild2" width="300" height="180" />&lt;/a>&lt;/p>
&lt;p>リポジトリ選んで&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/02/dockerhub_automatedbuild3.jpg">&lt;img class="alignnone size-medium wp-image-1575" src="https://blog.freedom-man.com/img/2015/02/dockerhub_automatedbuild3-300x136.jpg" alt="dockerhub_automatedbuild3" width="300" height="136" />&lt;/a>&lt;/p></description></item><item><title>Cocos2d-JSを触ってみた【環境構築編】</title><link>https://blog.freedom-man.com/cocos2d-js-environment.html</link><pubDate>Wed, 21 Jan 2015 00:50:57 +0000</pubDate><guid>https://blog.freedom-man.com/cocos2d-js-environment.html</guid><description>&lt;p>&lt;a title="http://cocos2d-x.org/" href="http://cocos2d-x.org/" target="_blank">Cocos2d-x&lt;/a>というクロスプラットフォームなゲーム開発が可能な&lt;/p>
&lt;p>フレームワークがあるということで色々と触ってみました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>プロダクトとしてCocos2d-xとCocos2d-JSの２つありますが、&lt;/p>
&lt;p>C++, Luaで書けるのがCocos2d-x&lt;/p>
&lt;p>JavaScriptで書けるのがCocos2d-JS&lt;/p>
&lt;p>という棲み分けになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>どの実行環境向けにコンパイルできるかにも違いが有り、&lt;/p>
&lt;p>Webゲームを作りたい場合はCocos2d-JSを選択することになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はみんな大好きJavaScriptで書けるCocos2d-JSで&lt;/p>
&lt;p>環境構築＋プロジェクト作成＋コンパイルまでやってみます！&lt;/p>
&lt;p>実行環境はWindows7です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回の参考URLはこちら↓&lt;/p>
&lt;p>&lt;a title="http://staffblog.yumemi.jp/cocos2d-js%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99%E3%81%BE%E3%81%A7%E3%81%AE%E6%89%8B%E9%A0%86/" href="http://staffblog.yumemi.jp/cocos2d-js%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99%E3%81%BE%E3%81%A7%E3%81%AE%E6%89%8B%E9%A0%86/" target="_blank">Cocos2d-JSを動かすまでの手順 | ゆめみ スタッフブログ -ゆめログ-&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://qiita.com/oggata/items/e7174d8800214b5000f7" href="http://qiita.com/oggata/items/e7174d8800214b5000f7" target="_blank">Cocos2d-x / Cocos2d-JS のインストール〜起動まで - Qiita&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://qiita.com/hkusu/items/54add3292d568bd7ac36" href="http://qiita.com/hkusu/items/54add3292d568bd7ac36" target="_blank">cocos2d-x - Cocos2d-JS を触ってみた - Qiita&lt;/a>&lt;/p>
&lt;h2>1. 環境構築&lt;/h2>
&lt;a title="http://cocos2d-x.org/download" href="http://cocos2d-x.org/download" target="_blank">公式サイト&lt;/a>からCocos2d-JSの最新版（現在v3.2）をダウンロードします。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/Cocos2d-x-download.png">&lt;img class="alignnone size-medium wp-image-1525" src="https://blog.freedom-man.com/img/2015/01/Cocos2d-x-download-300x254.png" alt="Cocos2d-x-download" width="300" height="254" />&lt;/a>&lt;/p>
&lt;p>ダウンロードしたら展開して、適当なフォルダに展開します。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Python 2.7も必要なのでこちらもインストールします。&lt;/p>
&lt;p>Windowsの場合は&lt;a title="https://www.python.org/downloads/" href="https://www.python.org/downloads/" target="_blank">本家&lt;/a>から2系の方をダウンロードして実行して適当に場所にインストール。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/python-home.jpg">&lt;img class="alignnone size-medium wp-image-1527" src="https://blog.freedom-man.com/img/2015/01/python-home-300x182.jpg" alt="python-home" width="300" height="182" />&lt;/a>&lt;/p>
&lt;p>インストール後はPythonのインストールディレクトリにパスを通しておきます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Cocos2d-JSの実行スクリプトにもパスを通す必要があるので&lt;/p>
&lt;p>&amp;lt;Cocos2d-JSをインストールしたPATH&amp;gt;\tools\cocos2d-console\binを環境変数PATHに追加します。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、プログラムのコンパイルを行う為にCocos2d-JSの設定をする必要があります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> &lt;span style="color:#0550ae">{&lt;/span>Cocos2d-JSをインストールしたPATH&lt;span style="color:#0550ae">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ python setup.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>を実行すると対話式で設定をすることが出来ます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Androidのコンパイルをする場合はNDKとAndroid SDKのルートディレクトリをそれぞれ指定します。&lt;/p>
&lt;p>コンパイルする場合（Web版だとリリースバージョン作る場合）は&lt;/p>
&lt;p>antのルートディレクトリを指定する必要があります。つまり、コンパイルする場合はantも必須です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これで環境構築が完了しました！&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ cocos
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>と叩いて、コマンドが動かない場合はPythonやCocos2d-JSへのPATHが通ってない可能性が高いです。&lt;/p>
&lt;h2>2. プロジェクト作成&lt;/h2>
cocosコマンドで新しいプロジェクトを作成することができます。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ cocos new &lt;span style="color:#0550ae">{&lt;/span>アプリ名&lt;span style="color:#0550ae">}&lt;/span> -l js -d .
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>作成するとこんな感じでファイルが作成されます。&lt;/p></description></item><item><title>Dokku Alternative触ってみる。</title><link>https://blog.freedom-man.com/dokku-alternative.html</link><pubDate>Tue, 20 Jan 2015 01:47:49 +0000</pubDate><guid>https://blog.freedom-man.com/dokku-alternative.html</guid><description>&lt;p>&lt;a title="https://github.com/dokku-alt/dokku-alt" href="https://github.com/dokku-alt/dokku-alt" target="_blank">Dokku Alternative&lt;/a>というOSSを使うと、&lt;a title="https://www.docker.com/" href="https://www.docker.com/">Docker&lt;/a>を利用して&lt;/p>
&lt;p>&lt;a title="https://www.heroku.com/" href="https://www.heroku.com/" target="_blank">heroku&lt;/a>みたいなPaaSを作れるということなので試してみましたー。&lt;/p>
&lt;p>Dokku Alternativeは本家の&lt;a title="https://github.com/progrium/dokku" href="https://github.com/progrium/dokku" target="_blank">Dokku&lt;/a>に色々と機能を追加したOSSみたいです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URLはこちら↓&lt;/p>
&lt;p>&lt;a title="http://www.moongift.jp/2014/10/dokku-alternative-%E5%80%8B%E4%BA%BA%E7%94%A8paas%E3%81%AB%E3%81%A9%E3%81%86%E3%81%9E%E3%80%82dokku%E3%81%AB%E4%BE%BF%E5%88%A9%E3%81%AA%E6%A9%9F%E8%83%BD%E3%82%92%E8%BF%BD%E5%8A%A0/" href="http://www.moongift.jp/2014/10/dokku-alternative-%E5%80%8B%E4%BA%BA%E7%94%A8paas%E3%81%AB%E3%81%A9%E3%81%86%E3%81%9E%E3%80%82dokku%E3%81%AB%E4%BE%BF%E5%88%A9%E3%81%AA%E6%A9%9F%E8%83%BD%E3%82%92%E8%BF%BD%E5%8A%A0/" target="_blank">Dokku Alternative·個人用PaaSにどうぞ。Dokkuに便利な機能を追加 MOONGIFT&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://kray.jp/blog/dokku-alternative/" href="http://kray.jp/blog/dokku-alternative/" target="_blank">Herokuのように簡単に使えるDockerベースのPaaS | KRAY Inc&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://knowledge.sakura.ad.jp/tech/2545/" href="http://knowledge.sakura.ad.jp/tech/2545/" target="_blank">Dockerを使ったミニPaaSのdokkuをパワーアップさせた「Dokku Alternative」を試す - さくらのナレッジ&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はまっさらなVMに入れてみます。&lt;/p>
&lt;h2>1. Ubuntuインスタンスを立ち上げる&lt;/h2>
今回は&lt;a title="https://www.digitalocean.com/" href="https://www.digitalocean.com/" target="_blank">DigitalOcean&lt;/a>で立ち上げました。
&lt;p>スペックはメモリ512MBの一番安いプランで、OSはUbuntu 14.04x64を選択。&lt;/p>
&lt;p>Dokku-altはUbuntu 14.04 LTSにしか対応してないっぽいです。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/dokku-ubuntu-digitalocean.jpg">&lt;img class="alignnone size-medium wp-image-1544" src="https://blog.freedom-man.com/img/2015/01/dokku-ubuntu-digitalocean-300x25.jpg" alt="dokku-ubuntu-digitalocean" width="300" height="25" />&lt;/a>&lt;/p>
&lt;p>立ち上げたら、セキュリティ系の諸々の初期設定をした後、スワップファイルの設定をしてください。&lt;/p>
&lt;p>これをしないとメモリ不足でインストールがコケます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo dd &lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>/dev/zero &lt;span style="color:#953800">of&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>/swap &lt;span style="color:#953800">bs&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>1M &lt;span style="color:#953800">count&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">2048&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo mkswap /swap
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo swapon /swap
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>設定したら、以下のコマンドでswap領域が有効になっているかを確認&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ cat /proc/swap
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>/etc/fstabにも登録しておきます&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/swap swap   swap    defaults   &lt;span style="color:#0550ae">0&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2>2. Dokkuのインストール&lt;/h2>
インストールは超簡単で以下のコマンドを実行するだけ。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo bash -c &lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#cf222e">$(&lt;/span>curl -fsSL https://raw.githubusercontent.com/dokku-alt/dokku-alt/master/bootstrap.sh&lt;span style="color:#cf222e">)&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>インストールが成功すると初期設定用のサーバが立ち上がるので&lt;/p>
&lt;p>http://{サーバーのIP or ホスト名}:2000にアクセスして設定を行います。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/dokku-setup.jpg">&lt;img class="alignnone size-medium wp-image-1543" src="https://blog.freedom-man.com/img/2015/01/dokku-setup-300x256.jpg" alt="dokku-setup" width="300" height="256" />&lt;/a>&lt;/p>
&lt;p>IPアドレスだとアプリに対してサブドメイン形式のURLをアサインできません。&lt;/p></description></item><item><title>Rapiroで遊ぶ【Chatterで操作編】</title><link>https://blog.freedom-man.com/rapiro-chatter.html</link><pubDate>Sat, 17 Jan 2015 22:20:38 +0000</pubDate><guid>https://blog.freedom-man.com/rapiro-chatter.html</guid><description>&lt;p>&lt;a title="Rapiroで遊ぶ【カスタマイズ編】" href="https://blog.freedom-man.com/rapiro-customize/" target="_blank">前回&lt;/a>はRapiroをカスタマイズして無線LAN対応させたので&lt;/p>
&lt;p>今回は実際にWebと接続して任意のクライアントからRapiroを操作できるようにします！&lt;/p>
&lt;p> &lt;/p>
&lt;p>方法としてはRapiro（Raspberry Pi）を起点にPush型にするか（RapiroをWebサーバ化する）&lt;/p>
&lt;p>Pull型でRapiro側からWebにデータを取りに行くかの2パターンがありますが、&lt;/p>
&lt;p>今回はPull型でデータ取得先にコマンド入力のデータがあれば&lt;/p>
&lt;p>シリアル経由でRapiroを操作するフローで構築してみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>cron使えば言語／フレームワーク問わないのですが&lt;/p>
&lt;p>入出力がプラガブルで拡張性の高いhubot使えば色々便利そうだったので今回はコレを使います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>hubotと言えば以前に&lt;a title="hubotのchatterアダプタを作ってみた。" href="https://blog.freedom-man.com/hubot-chatter/">hubot-chatter&lt;/a>を作ったのでChatter使ってRapiroを操作してみます！&lt;/p>
&lt;p>Chatterに命令文書いたらrapiroが動く感じです。&lt;/p>
&lt;h2>1. Node.jsをRaspberry Piにインストール&lt;/h2>
Raspberry Piでapt-getでパッケージインストールしたら、yaomanインストールあたりの
&lt;p>エラーでハマったのでPi用のバイナリを使ってインストールします。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ curl -O http://nodejs.org/dist/v0.10.28/node-v0.10.28-linux-arm-pi.tar.gz
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ sudo tar --strip-components &lt;span style="color:#0550ae">1&lt;/span> -xzvf node-v0.10.28-linux-arm-pi.tar.gz -C /usr/local
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2>2. hubotのインストール&amp;ボット作成&lt;/h2>
まずはhubotのインストール
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo npm install -g yo generator-hubot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>hubotの作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir hubot
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> hubot
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ yo hubot
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ npm install hubot-chatter
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2>3. hubotスクリプトの作成&lt;/h2>
こんな感じのスクリプトをscripts/test.coffeeに設置
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>SerialPort = require(&amp;#34;serialport&amp;#34;).SerialPort
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>serialPort = new SerialPort(&amp;#34;/dev/ttyAMA0&amp;#34;, {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> baudrate: 57600
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}, false)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>serialPort.open (error)-&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> if error
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(&amp;#39;failed to open: #{error}&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> else
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> console.log(&amp;#39;open&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>module.exports = (robot) -&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> robot.respond /RAPIRO (.*)$/i, (msg) -&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> command = msg.match[1]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> switch command
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;stop&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M0&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;forward&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M1&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;back&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M2&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;right&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M3&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;left&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M4&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;green&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M5&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;yellow&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M6&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;blue&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M7&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;red&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M8&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> when &amp;#34;push&amp;#34;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M9&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> else
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> serialPort.write(&amp;#34;#M0&amp;#34;)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>さらに起動用のシェルファイルも作成&lt;/p></description></item><item><title>Rapiroで遊ぶ【カスタマイズ編】</title><link>https://blog.freedom-man.com/rapiro-customize.html</link><pubDate>Sun, 04 Jan 2015 19:25:04 +0000</pubDate><guid>https://blog.freedom-man.com/rapiro-customize.html</guid><description>&lt;p>今回はRapiroをRaspberry Piでさらにカスタマイズしていきます！&lt;/p>
&lt;p> &lt;/p>
&lt;p>Rapiroの拡張というよりは、機能拡張したRaspberry PiをRapiroに載せる感じです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回の参考サイトは以下になります↓&lt;/p>
&lt;p>[Raspberry Pi搭載系]&lt;/p>
&lt;p>&lt;a title="http://android.ohwada.jp/archives/4538" href="http://android.ohwada.jp/archives/4538" target="_blank">RAPIRO に Raspberry Pi を搭載する | アンドロイドな日々&lt;/a>&lt;/p>
&lt;p>&lt;a title="https://www.kickstarter.com/projects/shota/rapiro-the-humanoid-robot-kit-for-your-raspberry-p/posts/743582" href="https://www.kickstarter.com/projects/shota/rapiro-the-humanoid-robot-kit-for-your-raspberry-p/posts/743582" target="_blank">RAPIRO: The Humanoid Robot Kit for your Raspberry Pi by Shota Ishiwatari — Kickstarter&lt;/a>&lt;/p>
&lt;p>[Bluetooth&amp;amp;PS3コントローラで遠隔操作系]&lt;/p>
&lt;p>&lt;a title="http://www.makuake.com/blog/crowdfunding/rapiro-dualshock/" href="http://www.makuake.com/blog/crowdfunding/rapiro-dualshock/" target="_blank">RapiroをPS3のDUALSHOCK3で動かしてみる | Makuake（マクアケ）NOTE クラウドファンディングブログ&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://blog.siliconhouse.jp/archives/52044525.html" href="http://blog.siliconhouse.jp/archives/52044525.html" target="_blank">シリコンハウスへようこそ:RAPIRO製作日誌 ～無線化への道～ Raspberry pi 搭載編 続章 bluetooth設定&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://junkroom2cyberrobotics.blogspot.jp/2013/03/raspberry-pi-dualshock3-bluetooth.html" href="http://junkroom2cyberrobotics.blogspot.jp/2013/03/raspberry-pi-dualshock3-bluetooth.html" target="_blank">工作と小物のがらくた部屋: Raspberry Pi で Dualshock3 (Bluetooth接続ゲームコントローラ）&lt;/a>&lt;/p>
&lt;p>[カメラモジュール系]&lt;/p>
&lt;p>&lt;a title="http://thepihut.com/blogs/raspberry-pi-tutorials/16021420-how-to-install-use-the-raspberry-pi-camera" href="http://thepihut.com/blogs/raspberry-pi-tutorials/16021420-how-to-install-use-the-raspberry-pi-camera" target="_blank">How to install / use the Raspberry Pi Camera | The Pi Hut&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://www.mztn.org/rpi/rpi23.html" href="http://www.mztn.org/rpi/rpi23.html" target="_blank">Raspberry Pi メモ (23) - カメラモジュールの使い方&lt;/a>&lt;/p>
&lt;h2>無線LAN対応&lt;/h2>
Webに接続できるようにしないと、外部から遠隔操作したり
&lt;p>Webサービスとつないだりできないので、まずは無線LANに対応させます。&lt;/p>
&lt;p>Raspberry PiにUSBの無線LANのドングルを繋いで色々と設定すればOKです。&lt;/p></description></item><item><title>Rapiroで遊ぶ【組み立て編】</title><link>https://blog.freedom-man.com/rapiro-build.html</link><pubDate>Sat, 03 Jan 2015 16:11:33 +0000</pubDate><guid>https://blog.freedom-man.com/rapiro-build.html</guid><description>&lt;p>&lt;a title="http://www.rapiro.com/ja/" href="http://www.rapiro.com/ja/" target="_blank">Rapiro&lt;/a>という&lt;a title="http://www.arduino.cc/" href="http://www.arduino.cc/" target="_blank">Arduino&lt;/a>互換の基板が搭載されたロボットを購入したので組み立ててみました！&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/rapiro-complete.jpg">&lt;img class="alignnone size-medium wp-image-1491" src="https://blog.freedom-man.com/img/2015/01/rapiro-complete-195x300.jpg" alt="rapiro-complete" width="195" height="300" />&lt;/a>&lt;/p>
&lt;p>Rapiroは、Arduino互換の基板とRaspberry piに接続できるインタフェースを持つため&lt;/p>
&lt;p>拡張性が高く、組み立てもドライバーだけで出来るお手軽なロボットキットです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>組み立て方に関しては&lt;a title="http://www.rapiro.com/ja/assembly-manual/" href="http://www.rapiro.com/ja/assembly-manual/" target="_blank">公式のドキュメント&lt;/a>を参考にしましたが、&lt;/p>
&lt;p>個人的にここは注意したほうが良い！という点を備忘録として記載します。&lt;/p>
&lt;h2>準備&lt;/h2>
Rapiro自体は45,000円で手に入りますが、
&lt;p>動力源となる単三型のニッケル水素充電池やACアダプタは別途用意する必要があります。&lt;/p>
&lt;p>公式ドキュメントではeneloopやEnergizer Rechargeを利用するように記載されていますが&lt;/p>
&lt;p>evoltaでも一応動きました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>色んなところ歩かせたいとかの機動力重視の場合は乾電池一択になるんですが&lt;/p>
&lt;p>電池の消費が激しく（満充電状態で45-90分稼働）、充電もそれなりに時間がかかるので&lt;/p>
&lt;p>ACアダプタの方が手軽で良いです。&lt;/p>
&lt;p>Raspberry Pi + カメラモジュールで監視するとか、音声読み上げたり音声認識させたり等の&lt;/p>
&lt;p>据え置き系重量級ロボにする場合は、ACアダプタ一択ですかね。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、組み立てにはドライバが必要です。&lt;/p>
&lt;p>ドライバは軸が長く（全長15cmくらい？）トルクをかけやすい（＝グリップが太い）ものを使ってください。&lt;/p>
&lt;p>Rapiroのネジは全てプラスのネジになるので&lt;/p>
&lt;p>それなりに精密なドライバを利用したほうが良いと思います。&lt;/p>
&lt;h2>サーボモータのキャリブレーション&lt;/h2>
公式マニュアルの&lt;a title="http://www.rapiro.com/ja/assembly-manual/#53" href="http://www.rapiro.com/ja/assembly-manual/#53" target="_blank">工程53&lt;/a>でサーボモータの位置を初期位置にしますが、
&lt;p>こちらの作業は必ず満充電での乾電池 or ACアダプタで行ってください。&lt;/p>
&lt;p> &lt;/p>
&lt;p>購入した直後の電池でも&amp;quot;充電済み&amp;quot;と一応書いてありますが&lt;/p>
&lt;p>満充電状態ではなく、そのままでは正しく動かない可能性が有るので、充電する必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>満充電状態であれば、工程53で軸がしっかり動いてサーバモータの初期位置が決まります。&lt;/p>
&lt;p>私は満充電状態じゃない電池で動かしてしまったのですが&lt;/p>
&lt;p>その状態でも一応モーターの駆動音がしたので&lt;/p>
&lt;p>てっきり初期位置が決まったものだと勘違いしてました（実は軸が全く回っていなかったっぽい）。&lt;/p>
&lt;p>初期位置決めがうまく行っていなくても、&lt;a title="http://www.rapiro.com/ja/assembly-manual/#209" href="http://www.rapiro.com/ja/assembly-manual/#209" target="_blank">工程209&lt;/a>のキャリブレーションで無理矢理調整できますが&lt;/p>
&lt;p>大きな調整（例えば180度軸を回転させて初期位置を調整する等）はできません。&lt;/p>
&lt;p> &lt;/p>
&lt;p>53以降の取り付け時には極力軸を回さないように組み立てていきますが&lt;/p>
&lt;p>後で10-20度くらいの初期位置調整は可能なので&lt;/p>
&lt;p>ちょっとぐらい軸が回ってもあまり気にしなくても良いです。&lt;/p>
&lt;p>特に脚（2箇所）や指あたりは組み立て終わった後に、再度組み直すのが容易な箇所だったりするので。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみに初期位置調整がうまくいってないと、以下のような残念な状態になりますｗ&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/rapiro-nejire.jpg">&lt;img class="alignnone size-medium wp-image-1490" src="https://blog.freedom-man.com/img/2015/01/rapiro-nejire-202x300.jpg" alt="rapiro-nejire" width="202" height="300" />&lt;/a>&lt;/p>
&lt;p>頭が…。&lt;/p>
&lt;h2>電池が足りなくなってくるとRapiroが捻れる&lt;/h2>
乾電池の場合は電池が足りなくなってくると、電源を入れた瞬間にRapiroが急に捻れ始めます。
&lt;p>キャリブレーション中に電池不足で捻れると、調整がうまくいっていないのか&lt;/p>
&lt;p>電池に問題があるのか切り分けづらいので、キャリブレーション中も満充電の状態で行ってください。&lt;/p>
&lt;h2>Rapiroの操作方法&lt;/h2>
キャリブレーション時に&lt;a title="https://github.com/Ishiwatari/RAPIRO/blob/master/RAPIRO_ver0_0/RAPIRO_ver0_0.ino" href="https://github.com/Ishiwatari/RAPIRO/blob/master/RAPIRO_ver0_0/RAPIRO_ver0_0.ino" target="_blank">標準ファームウェア&lt;/a>をインストールしますが、
&lt;p>このファームウェアに前進、後退、旋回、目を光らせる等の基本動作が入っているので&lt;/p>
&lt;p>ファームウェアを書き換えることなくRapiroを操作することが可能です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Arduino互換なのでArduino IDEで独自のファームウェアを書いてインストールすることも可能です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>標準ファームウェアを利用した操作では、シリアル通信でRapiroに命令（コマンド）を送って&lt;/p>
&lt;p>操作するのが基本になります。&lt;/p>
&lt;p>Rapiro単体の場合（Raspberry Piなし）はPCとRapiroをUSBでつないでシリアル通信を行います。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2015/01/rapiro-serial.jpg">&lt;img class="alignnone size-medium wp-image-1496" src="https://blog.freedom-man.com/img/2015/01/rapiro-serial-193x300.jpg" alt="rapiro-serial" width="193" height="300" />&lt;/a>&lt;/p>
&lt;h2>Rapiroのカスタマイズ&lt;/h2>
Raspberry PiとRapiroのArduino互換の基板をシリアル接続できるように設計されているので
&lt;p>Raspberry Piを使った拡張が容易です。&lt;/p></description></item><item><title>2015</title><link>https://blog.freedom-man.com/2015.html</link><pubDate>Thu, 01 Jan 2015 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2015.html</guid><description/></item><item><title>ApexからAmazon Lambda叩いてみる。</title><link>https://blog.freedom-man.com/amazon_lambda_using_apex.html</link><pubDate>Sun, 14 Dec 2014 01:02:43 +0000</pubDate><guid>https://blog.freedom-man.com/amazon_lambda_using_apex.html</guid><description>&lt;p>&lt;a title="http://aws.amazon.com/jp/lambda/" href="http://aws.amazon.com/jp/lambda/" target="_blank">Amazon Lambda&lt;/a>というすんばらしいサービスがプレビュー提供されたということでApexから触ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>1. Lambda側のfunctionを書く&lt;/h2>
今回はChatter投稿するようなスクリプトを書いてみた。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">jsforce&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;jsforce&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">username&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;test@example.com&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">password&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hogefuga&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">loginUrl&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://login.salesforce.com&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">exports&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">handler&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">conn&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">jsforce&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Connection&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">loginUrl&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">loginUrl&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">chatter_body&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">body&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">messageSegments&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Text&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">text&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hello &amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">content&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">conn&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">login&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">username&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">password&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">conn&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">chatter&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">resource&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/feeds/record/&amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parent_id&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/feed-items&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">chatter_body&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">done&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;chatter de lambda&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>上記スクリプトをindex.jsとして保存する。&lt;/p>
&lt;p>必要なパッケージもローカルインストールしておく。今回は&lt;a title="https://jsforce.github.io/" href="https://jsforce.github.io/" target="_blank">jsforce&lt;/a>のみ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>npm install jsforce
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2>2. 作成したLambda functionをアップロードする&lt;/h2>
node_modulesと対象のスクリプトファイルをまとめてzipファイルにする。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ zip -r lambda.zip index.js node_modules
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>で、アップロードする。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/12/AWS-Lambda1.png">&lt;img class="alignnone size-medium wp-image-1463" src="https://blog.freedom-man.com/img/2014/12/AWS-Lambda1-300x253.png" alt="AWS Lambda" width="300" height="253" />&lt;/a>&lt;/p>
&lt;p>Function Name, Description→適当に&lt;/p>
&lt;p>Function Code→生成したZipファイルをアップロード。File nameとHandler nameはそのまま。&lt;/p>
&lt;p>Role name→Functionの実行コンテキストになるロールを指定する。Create/Select Roleで作成・指定すればOK。&lt;/p>
&lt;p>Advanced Settings→一回あたりのFunction実行の利用可能なメモリやタイムアウト時間を適当にセット。&lt;/p>
&lt;h2>3. 動作確認&lt;/h2>
作成したLambda Functionが正しく動作するかを確認する。
&lt;p>まずは確認対象のLambda Functionを選択してEdit/Testをクリック。&lt;/p></description></item><item><title>CasperJSでSalesforceのレコード詳細画面を自動キャプチャ</title><link>https://blog.freedom-man.com/casperjs-sf-record.html</link><pubDate>Sun, 02 Nov 2014 22:39:55 +0000</pubDate><guid>https://blog.freedom-man.com/casperjs-sf-record.html</guid><description>&lt;p>プロファイルのキャプチャを取るのにChromeExtensionとかでキャプチャを手動で取っていたのを&lt;/p>
&lt;p>何とかしたかったので&lt;a title="http://casperjs.org/" href="http://casperjs.org/" target="_blank">CasperJS&lt;/a>で自動化してみました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>CasperJSは&lt;a title="http://phantomjs.org/" href="http://phantomjs.org/" target="_blank">PhantomJS&lt;/a>のユーティリティで、ヘッドレスなブラウザをAPI経由で操ってテストしたり&lt;/p>
&lt;p>キャプチャを取ったりすることが出来るツールになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は&lt;/p>
&lt;ol>
&lt;li>
&lt;p>SOQLを発行してレコードの一覧を取得&lt;/p>
&lt;/li>
&lt;li>
&lt;p>1で取得したレコードIDを元に各レコード詳細画面に遷移後、キャプチャを取得&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>という流れでキャプチャを取ってみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>作成物は&lt;a title="https://github.com/tzmfreedom/sfdc-capturejs" href="https://github.com/tzmfreedom/sfdc-capturejs" target="_blank">こちら&lt;/a>。&lt;/p>
&lt;p>ちなみにSOQLで取得できて、取得したIDを使ってhttps://{ドメイン}/{取得したID}のURLで&lt;/p>
&lt;p>アクセスできるオブジェクトであれば何でも取得できます（プロファイルのキャプチャもOKです）。&lt;/p>
&lt;h2>1. 指定オブジェクトのSalesforceIDの一覧を取得&lt;/h2>
nodejsで&lt;a title="https://jsforce.github.io/" href="https://jsforce.github.io/" target="_blank">jsforce&lt;/a>使って指定のレコードIDの一覧を取得します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span># レコード一覧を取得するcoffeescript
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>program = require(&amp;#34;commander&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>program
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .version(&amp;#39;0.0.1&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .option(&amp;#39;-u, --username &amp;lt;username&amp;gt;&amp;#39;, &amp;#39;Salesforce Username&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .option(&amp;#39;-p, --password &amp;lt;password&amp;gt;&amp;#39;, &amp;#39;Salesforce Password&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .option(&amp;#39;-e, --env [env_type]&amp;#39;, &amp;#39;Salesforce Environment&amp;#39;, &amp;#39;prod&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .option(&amp;#39;-o, --output [outputfile]&amp;#39;, &amp;#39;OutputFile&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .option(&amp;#39;-q, --query [soql]&amp;#39;, &amp;#39;Query&amp;#39;, &amp;#39;SELECT id FROM Profile&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .parse(process.argv);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>fs = require(&amp;#34;fs&amp;#34;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>jsforce = require(&amp;#39;jsforce&amp;#39;)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>endpoint = if program.env ==&amp;#39;test&amp;#39; then &amp;#39;https://test.salesforce.com&amp;#39; else &amp;#39;https://login.salesforce.com&amp;#39;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>connectOptions = {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> loginUrl : endpoint
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conn = new jsforce.Connection(connectOptions)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>conn.login program.username, program.password, (err, res) =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> if err
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> return console.error(err)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> conn.query(program.query)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .stream()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .pipe(process.stdout)
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>クレデンシャルや実行SOQLをパラメータで与えるため&lt;a title="https://github.com/tj/commander.js" href="https://github.com/tj/commander.js" target="_blank">commander&lt;/a>を利用。&lt;/p></description></item><item><title>Azure Active DirectoryでTwitterにシングルサインオンしてみる。</title><link>https://blog.freedom-man.com/aad-twitter-sso.html</link><pubDate>Sun, 02 Nov 2014 13:47:56 +0000</pubDate><guid>https://blog.freedom-man.com/aad-twitter-sso.html</guid><description>&lt;p>&lt;a title="http://azure.microsoft.com/ja-jp/services/active-directory/" href="http://azure.microsoft.com/ja-jp/services/active-directory/" target="_blank">Azure Active Directory&lt;/a>ネタです。&lt;/p>
&lt;p>今回はAzure Active DirectoryでTwitterにシングルサインオンをしてみます。&lt;/p>
&lt;p>通常、Twitterやfacebookなどサービスにシングルサインオンというと&lt;/p>
&lt;p>これらのWebサービスをIdP(OP)としてOAuth、OpenID Connectによる認証連携をイメージしますが&lt;/p>
&lt;p>Azure Active Directoryの場合は、AzureAD自体がIdPになり&lt;/p>
&lt;p>TwitterなどのWebサービスがSPとなるような構成になります。&lt;/p>
&lt;h2>1. TwitterのギャラリーアプリをAADに追加&lt;/h2>
まずは対象のDirectoryを選択
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-select-directory.jpg">&lt;img class="alignnone size-medium wp-image-1430" src="https://blog.freedom-man.com/img/2014/11/aad-sso-select-directory-300x164.jpg" alt="aad-sso-select-directory" width="300" height="164" />&lt;/a>&lt;/p>
&lt;p>アプリケーションを選択して、追加をクリック&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-select-application.jpg">&lt;img class="alignnone size-medium wp-image-1429" src="https://blog.freedom-man.com/img/2014/11/aad-sso-select-application-300x180.jpg" alt="aad-sso-select-application" width="300" height="180" />&lt;/a>&lt;/p>
&lt;p>今回はギャラリーからアプリを追加&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-addapp.jpg">&lt;img class="alignnone size-medium wp-image-1439" src="https://blog.freedom-man.com/img/2014/11/aad-sso-addapp-300x221.jpg" alt="aad-sso-addapp" width="300" height="221" />&lt;/a>&lt;/p>
&lt;p>Twitterのアプリケーションを選択&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-twitter-gallery.jpg">&lt;img class="alignnone size-medium wp-image-1434" src="https://blog.freedom-man.com/img/2014/11/aad-sso-twitter-gallery-300x140.jpg" alt="aad-sso-twitter-gallery" width="300" height="140" />&lt;/a>&lt;/p>
&lt;p>追加するとこんな画面が表示される&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-twitter-settings.jpg">&lt;img class="alignnone size-medium wp-image-1433" src="https://blog.freedom-man.com/img/2014/11/aad-sso-twitter-settings-300x155.jpg" alt="aad-sso-twitter-settings" width="300" height="155" />&lt;/a>&lt;/p>
&lt;p>シングルサインオンの構成をクリックしてパスワードシングルサインオンになっていることを確認&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-settings.jpg">&lt;img class="alignnone size-medium wp-image-1438" src="https://blog.freedom-man.com/img/2014/11/aad-sso-settings-300x258.jpg" alt="aad-sso-settings" width="300" height="258" />&lt;/a>&lt;/p>
&lt;h2>2. ユーザの割り当てを実行&lt;/h2>
Twitterのギャラリーアプリ設定画面から、「ユーザの割り当て」を選択してユーザ一覧にアクセスし
&lt;p>対象のAzureADユーザに対して割り当てを行う。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-userlist.jpg">&lt;img class="alignnone size-medium wp-image-1437" src="https://blog.freedom-man.com/img/2014/11/aad-sso-userlist-300x90.jpg" alt="aad-sso-userlist" width="300" height="90" />&lt;/a>&lt;/p>
&lt;p>割り当てでは「ユーザの代わりにTwitter資格情報を入力する」にチェックを付けて&lt;/p>
&lt;p>紐付けるTwitterのユーザ名／パスワードを入力する。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-sso-userassignment.jpg">&lt;img class="alignnone size-medium wp-image-1432" src="https://blog.freedom-man.com/img/2014/11/aad-sso-userassignment-300x226.jpg" alt="aad-sso-userassignment" width="300" height="226" />&lt;/a>&lt;/p>
&lt;p>これで、AzureAD側の設定は完了です。&lt;/p>
&lt;h2>3. アクセスパネルからシングルサインオンを行う&lt;/h2>
&lt;a title="https://myapps.microsoft.com" href="https://myapps.microsoft.com" target="_blank">https://myapps.microsoft.com&lt;/a>にアクセスしてAzureADユーザでログインを行うと
&lt;p>以下のようにシングルサインオン用のパネルが表示されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/11/aad-accesspanel.jpg">&lt;img class="alignnone size-medium wp-image-1436" src="https://blog.freedom-man.com/img/2014/11/aad-accesspanel-300x119.jpg" alt="aad-accesspanel" width="300" height="119" />&lt;/a>&lt;/p>
&lt;p>複数のディレクトリに属すAzureADユーザの場合は右上のメニューからディレクトリを選択することが可能。&lt;/p>
&lt;p>また、各ブラウザのAzureAD用のプラグインがインストールされていない場合は&lt;/p>
&lt;p>パネルをクリックするとプラグインのインストール画面に遷移します。&lt;/p></description></item><item><title>hubotのchatterアダプタを作ってみた。</title><link>https://blog.freedom-man.com/hubot-chatter.html</link><pubDate>Sun, 26 Oct 2014 18:15:38 +0000</pubDate><guid>https://blog.freedom-man.com/hubot-chatter.html</guid><description>&lt;p>Web+DB PRESSとか読んでて&lt;a title="https://hubot.github.com/" href="https://hubot.github.com/" target="_blank">hubot&lt;/a>を使った&lt;a title="https://speakerdeck.com/jnewland/chatops-at-github" href="https://speakerdeck.com/jnewland/chatops-at-github" target="_blank">ChatOps&lt;/a>的なところが非常に興味深かったので&lt;/p>
&lt;p>chatterで出来ないかなーと思って&lt;a title="https://github.com/github/hubot/blob/master/docs/adapters.md" href="https://github.com/github/hubot/blob/master/docs/adapters.md" target="_blank">adapter&lt;/a>を探したものの&lt;/p>
&lt;p>用途にマッチしたものが無かったので自分で作ってみました。（npmデビュー作ｗ）&lt;/p>
&lt;p>↓↓↓&lt;/p>
&lt;p>&lt;a title="https://github.com/tzmfreedom/hubot-chatter" href="https://github.com/tzmfreedom/hubot-chatter" target="_blank">tzmfreedom/hubot-chatter&lt;/a>&lt;/p>
&lt;h2>hubotとは&lt;/h2>
hubotとはgithub社が開発したボットのフレームワークで
&lt;p>外部サービス／インターフェースと連携可能なadapterと呼ばれるプラガブルなモジュールと&lt;/p>
&lt;p>ボットの動作を規定するスクリプトによって様々なボットを簡単に開発することができます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>hubotに関してはこちらが詳しいので、ご参考ください↓&lt;/p>
&lt;p>&lt;a title="http://gihyo.jp/dev/serial/01/hubot/0001" href="http://gihyo.jp/dev/serial/01/hubot/0001" target="_blank">第1回 Hubotとは何か：GitHub社謹製！ bot開発・実行フレームワーク「Hubot」｜gihyo.jp … 技術評論社&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://www.atmarkit.co.jp/ait/articles/1408/20/news035.html" href="http://www.atmarkit.co.jp/ait/articles/1408/20/news035.html" target="_blank">チャットボットでチーム開発効率化入門（1）：GitHub製フレームワークHubotの概要とインストール、チャットアプリと連携する基本的な使い方 (1/2) - ＠IT&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、今回はこのhubotのadapterを作り方とhubot-chatterの使い方を簡単に紹介します。&lt;/p>
&lt;p>作り方の参考サイトはこちらが詳しいです↓&lt;/p>
&lt;p>&lt;a title="http://akiomik.hatenablog.jp/entry/2014/02/12/052703" href="http://akiomik.hatenablog.jp/entry/2014/02/12/052703" target="_blank">hubot adapterの作り方 - おみブロZ&lt;/a>&lt;/p>
&lt;h2>adapterの作成方法&lt;/h2>
hubotのadapterの作成方法ですが上記リンクの通り
&lt;p>現時点(2014/10/26)では作成方法のドキュメント等がありません。&lt;/p>
&lt;p>&lt;a title="https://github.com/github/hubot/blob/master/docs/adapters.md" href="https://github.com/github/hubot/blob/master/docs/adapters.md" target="_blank">README&lt;/a>の記載通り、ソースコードを読んで作っていく必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>とはいえ、作り方は超簡単でsrcディレクトリ内にcoffeescriptでアダプタを書いてあげればOKです。&lt;/p>
&lt;p>ざっくり書くとこんな感じ↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>{Robot, Adapter, TextMessage, Response} = require &amp;#39;hubot&amp;#39;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span># アダプターを継承
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>class HogeAdapter extends Adapter
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> run: -&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #ここで外部からデータを受け取ってscriptにデータを渡す。
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> send: (envelope, strings...) =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> #scriptからのレスポンスはここで受け取って、処理を行う。
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> reply: (envelope, strings...) -&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>exports.use = (robot) -&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> new HogeAdapter robot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>hubotを起動すると指定したadapterのrunメソッドが実行されるので、&lt;/p></description></item><item><title>Azure Active DirectoryとSalesforceのSSO【ギャラリーアプリ編】</title><link>https://blog.freedom-man.com/aad-salesforce-sso.html</link><pubDate>Sat, 27 Sep 2014 12:44:10 +0000</pubDate><guid>https://blog.freedom-man.com/aad-salesforce-sso.html</guid><description>&lt;p>IDMaaSシリーズ第三弾として今回は&lt;a title="http://azure.microsoft.com/ja-jp/services/active-directory/" href="http://azure.microsoft.com/ja-jp/services/active-directory/" target="_blank">Azure Active Directory(AAD)&lt;/a>をやってみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>AADはざっくり言うと認証連携のIdPのクラウドサービスで&lt;/p>
&lt;p>任意のアプリケーションに対してOpenID ConnectやSAML、WS-Federation等の&lt;/p>
&lt;p>認証連携プロトコルを使ってシングルサインオンができるようになるサービスです。&lt;/p>
&lt;p>また、これらの認証連携プロトコルのRP/SPとして対応していない特定のサービスに対しても&lt;/p>
&lt;p>シングルサインオンができるような仕組みを持っています。&lt;/p>
&lt;p>既存のActive DirectoryからAADに同期することで既存のActive Directoryを&lt;/p>
&lt;p>ユーザーリポジトリとして利用することも可能です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、今回はAADを使ってSalesforceとのシングルサインオンをやってみます！&lt;/p>
&lt;p> &lt;/p>
&lt;p>Azure Active Directoryに関する説明は以下のサイトが詳しいです↓&lt;/p>
&lt;p>&lt;a title="http://codezine.jp/article/detail/7608" href="http://codezine.jp/article/detail/7608" target="_blank">Windows Azure Active Directoryことはじめ （1/8）：CodeZine&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://www.slideshare.net/naohiro.fujie/azure-adidentity" href="http://www.slideshare.net/naohiro.fujie/azure-adidentity" target="_blank">Azure ADとIdentity管理&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://www.keyman.or.jp/at/30006492/" href="http://www.keyman.or.jp/at/30006492/" target="_blank">クラウド時代のActive Directoryの使い方 - IT、IT製品の情報なら【キーマンズネット】&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://social.technet.microsoft.com/wiki/contents/articles/26343.tutorial-azure-ad-integration-with-salesforce.aspx" href="http://social.technet.microsoft.com/wiki/contents/articles/26343.tutorial-azure-ad-integration-with-salesforce.aspx" target="_blank">Tutorial: Azure AD Integration with Salesforce - TechNet Articles - United States (English) - TechNet Wiki &lt;/a>&lt;/p>
&lt;h2>1. Microsoft Azureポータルで対象のAADを選択&lt;/h2>
まずはアカウントにログインしてポータルトップへアクセスし
&lt;p>Active Directory＞既定のディレクトリを選択します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/azure-main.jpg">&lt;img class="alignnone size-medium wp-image-1343" src="https://blog.freedom-man.com/img/2014/09/azure-main-300x162.jpg" alt="azure-main" width="300" height="162" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ドメイン変更等の理由で規定のディレクトリを利用しない場合は&lt;/p>
&lt;p>下メニューの”新規”からAzure Active Directoryを新規に追加します。&lt;/p>
&lt;p>Auth0だとドメイン名の32文字の文字数制限があったりするので&lt;/p>
&lt;p>外部アプリの制限に引っかかった等の場合は新しくAADを作成してください。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/aad-new.jpg">&lt;img class="alignnone size-medium wp-image-1342" src="https://blog.freedom-man.com/img/2014/09/aad-new-300x148.jpg" alt="aad-new" width="300" height="148" />&lt;/a>&lt;/p>
&lt;h2>2. 作成したディレクトリにユーザを追加&lt;/h2>
Azure Active Directory用のユーザを作成します。
&lt;p>このユーザに対してログインすることで他のサービスにシングルサインオンすることができます。&lt;/p></description></item><item><title>werckerでforce.comなアプリをCIする。</title><link>https://blog.freedom-man.com/wercker-forcecom-ci.html</link><pubDate>Sat, 27 Sep 2014 11:59:49 +0000</pubDate><guid>https://blog.freedom-man.com/wercker-forcecom-ci.html</guid><description>&lt;p>&lt;a title="werckerでPython/FlaskなアプリをCIする。" href="https://blog.freedom-man.com/wercker-pythonflask-ci/" target="_blank">前回&lt;/a>はスタンダードにpythonなアプリをwerckerを使ってCIしましたが、&lt;/p>
&lt;p>今回はforce.comなアプリをCIしたいと思います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>pushからwerckerが動き出すまでは前回と同様。&lt;/p>
&lt;p>werckerが動き出すとantでテスト走らせるっていうだけのシンプル構成。&lt;/p>
&lt;h2>1. リポジトリの構成&lt;/h2>
treeするとこんな感じ。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>├── build.properties
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── build.xml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── lib
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   └── ant-salesforce.jar
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── src
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   ├── classes
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   │   ├── S3Common.cls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   │   ├── S3Common.cls-meta.xml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   │   ├── S3CommonTest.cls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   │   └── S3CommonTest.cls-meta.xml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   ├── objects
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   │   └── Account.object
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│   └── package.xml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>└── wercker.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>リポジトリ内にant-salesforce.jarを入れてますがこれだとリポジトリが大きくなるので&lt;/p>
&lt;p>jarは別サーバに置いておいて、wercker.ymlの設定でビルド時に取ってくる構成の方が効率的かと思います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>build.properties&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>sf.serverurl = https://login.salesforce.com
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>build.xml&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;project&lt;/span> &lt;span style="color:#1f2328">name=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Sample usage of Salesforce-CI Ant tasks&amp;#34;&lt;/span> &lt;span style="color:#1f2328">default=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;checkDeploy&amp;#34;&lt;/span> &lt;span style="color:#1f2328">basedir=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span> &lt;span style="color:#1f2328">xmlns:sf=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;antlib:com.salesforce&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;property&lt;/span> &lt;span style="color:#1f2328">file=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;build.properties&amp;#34;&lt;/span> &lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;property&lt;/span> &lt;span style="color:#1f2328">environment=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;env&amp;#34;&lt;/span> &lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">&amp;lt;!-- Build / TestResult never actually saves to the server --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;target&lt;/span> &lt;span style="color:#1f2328">name=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;checkDeploy&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;sf:deploy&lt;/span> &lt;span style="color:#1f2328">username=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;${env.USERNAME}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">password=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;${env.PASSWORD}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">serverurl=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;${sf.serverurl}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">deployRoot=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;src&amp;#34;&lt;/span> &lt;span style="color:#1f2328">checkOnly=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#1f2328">runAllTests=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;/project&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ユーザ名やパスワードはうっかりgitに上げると面倒なことになるので環境変数を使うようにします。&lt;/p></description></item><item><title>werckerでPython/FlaskなアプリをCIする。</title><link>https://blog.freedom-man.com/wercker-pythonflask-ci.html</link><pubDate>Thu, 25 Sep 2014 23:45:44 +0000</pubDate><guid>https://blog.freedom-man.com/wercker-pythonflask-ci.html</guid><description>&lt;p>CI as a Serviceに触れてみよう第一弾として今回は&lt;a title="http://wercker.com/" href="http://wercker.com/" target="_blank">wercker&lt;/a>を触ってみます。&lt;/p>
&lt;p>巷では&lt;a title="https://travis-ci.org/" href="https://travis-ci.org/" target="_blank">TravisCI&lt;/a>や&lt;a title="https://circleci.com/" href="https://circleci.com/" target="_blank">CircleCI&lt;/a>が有名ですが、privateでフリーなgitリポジトリを利用したかったので&lt;/p>
&lt;p>&lt;a title="https://bitbucket.org/" href="https://bitbucket.org/" target="_blank">bitbucket&lt;/a>が利用できるwerckerを選択！&lt;/p>
&lt;p> &lt;/p>
&lt;p>werckerを使うと…&lt;/p>
&lt;p>リモートリポジトリにソースをpush&lt;/p>
&lt;p>→リモートリポジトリがwerckerに対してWebフック&lt;/p>
&lt;p>→werckerが対象のgitリポジトリからソースをダウンロード&lt;/p>
&lt;p>→werckerがgitリポジトリ内にある設定ファイル（wercker.ymlなど）からCI用のVMを作成し&lt;/p>
&lt;p>必要なモジュールインストール及びビルド、テストを自動実行&lt;/p>
&lt;p>→必要に応じて自動デプロイを実施&lt;/p>
&lt;p>というフローでCIしてくれます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はbitbucketに対してソースをpushすると自動的にwerckerでテストを走らせて&lt;/p>
&lt;p>通ったら&lt;a title="https://www.openshift.com/" href="https://www.openshift.com/" target="_blank">OpenShift&lt;/a>に自動デプロイをする、というのをやってみます。&lt;/p>
&lt;h2>1. Webアプリを準備&lt;/h2>
今回は（も？）Python/Flaskでやってみます。
&lt;p>ソースをtreeした結果はこんな感じ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>├── requirements.txt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── wercker.yml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>└── wsgi
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ├── __init__.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ├── application
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ├── ciapp.py
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ├── templates
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │   ├── _index.html
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> │   └── _login.html
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> └── test_ciapp.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>対象のFlaskアプリのciapp.py↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># -*- coding: utf-8 -*-&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">flask&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> Flask&lt;span style="color:#1f2328">,&lt;/span> request&lt;span style="color:#1f2328">,&lt;/span> render_template
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app &lt;span style="color:#0550ae">=&lt;/span> Flask&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">__name__&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">@app.route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">index&lt;/span>&lt;span style="color:#1f2328">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render_template&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;_index.html&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">@app.route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/login&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> methods&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;GET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;POST&amp;#34;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">login&lt;/span>&lt;span style="color:#1f2328">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>method &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;GET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render_template&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;_login.html&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">elif&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>method &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;POST&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>form&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;username&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hoge&amp;#34;&lt;/span> &lt;span style="color:#0550ae">and&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>form&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;password&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;fuga&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;you are authorized&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;bad request&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#953800">__name__&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#39;__main__&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app&lt;span style="color:#0550ae">.&lt;/span>debug &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">True&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app&lt;span style="color:#0550ae">.&lt;/span>run&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Auth0でSocialSignOnやってみる。</title><link>https://blog.freedom-man.com/auth0-socialsignon.html</link><pubDate>Fri, 19 Sep 2014 00:14:56 +0000</pubDate><guid>https://blog.freedom-man.com/auth0-socialsignon.html</guid><description>&lt;p>&lt;a title="https://auth0.com/" href="https://auth0.com/" target="_blank">Auth0&lt;/a>とは認証基盤のクラウドサービスであるIDMaaSのサービスです（多分）&lt;/p>
&lt;p> &lt;/p>
&lt;p>Auth0自体がRDBMSやLDAP、AD、SocialSignOn（OAuthやらOpenID Connect）やSAMLの&lt;/p>
&lt;p>認証基盤のハブとなることで、利用アプリ側はプロトコル間の差異を気にすることなく&lt;/p>
&lt;p>同一の方法で複数サービス、多様なプロトコルの認証基盤を利用することができます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、外部サービスをIdPとする以外にもAuth0自体にユーザリポジトリを持つことができたり&lt;/p>
&lt;p>自分がホスティングしているDBサーバを認証基盤として利用することができます。&lt;/p>
&lt;p>サーバサイドのソフトウェアインストールが必要になりますが、LDAP、ActiveDirectoryも利用可能です。&lt;/p>
&lt;p>それ以外にもIPアドレスで認証できたりMicrosoftのIDMaaSであるWindows Azure Active Directoryを利用して&lt;/p>
&lt;p>認証連携をすることも可能です。&lt;/p>
&lt;p>また、ベータ版ですが&lt;a title="https://docs.auth0.com/mfa" href="https://docs.auth0.com/mfa" target="_blank">MFAにも対応してるっぽい&lt;/a>です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、今回はAuth0でSocialSignOnをやってみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考サイトはこちら↓&lt;/p>
&lt;p>&lt;a title="http://blog.flect.co.jp/labo/2014/07/auth0-3b49.html" href="http://blog.flect.co.jp/labo/2014/07/auth0-3b49.html" target="_blank">Auth0で簡単ソーシャルログイン - フレクトのHeroku Lab &lt;/a>&lt;/p>
&lt;p>&lt;a title="http://flect-heroku-sample.herokuapp.com/auth" href="http://flect-heroku-sample.herokuapp.com/auth" target="_blank">Herokuサンプル - ソーシャルログイン サンプル&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>1. アカウント登録&lt;/h2>
&lt;a title="https://auth0.com/ " href="https://auth0.com/" target="_blank">https://auth0.com/ &lt;/a>にアクセスして、アカウントを登録します。
&lt;p>github、Microsoft、Google+のアカウントでSignUpもできます。（こういうのなんて言うんだろ？SocialSignUp？）&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/auth0-index.jpg">&lt;img class="alignnone size-medium wp-image-1322" src="https://blog.freedom-man.com/img/2014/09/auth0-index-300x153.jpg" alt="auth0-index" width="300" height="153" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>2. アプリを作成&lt;/h2>
Apps/APIsで新しいアプリを作成します。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/auth0-newapp.jpg">&lt;img class="alignnone size-medium wp-image-1323" src="https://blog.freedom-man.com/img/2014/09/auth0-newapp-300x123.jpg" alt="auth0-newapp" width="300" height="123" />&lt;/a>&lt;/p>
&lt;p>※後述のサンプルコードにClientIDやClientSecretが丸ごと記載されているので、ここでメモらなくてもOK。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>3. SocialSignOnの設定&lt;/h2>
Connection＞Social からSocialSignOn対象のサービスを選択して設定を行います。
&lt;p>Auth0では各Webサービスに対する設定方法が非常にわかりやすくなっているので&lt;/p>
&lt;p>対象のWebサービスを使ったこと無い人でも比較的簡単に設定できるのがGoodなところです！&lt;/p>
&lt;p>以下はTwitterの設定画面で”How to obtain a Consumer Key?”のリンク先に設定方法が記載されています。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/auth0-twitter.jpg">&lt;img class="alignnone size-medium wp-image-1324" src="https://blog.freedom-man.com/img/2014/09/auth0-twitter-300x95.jpg" alt="auth0-twitter" width="300" height="95" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ここでは具体的な設定方法は割愛しますが、基本的にどのサービスでも&lt;/p>
&lt;p>Webサービス側のアプリケーションに対してコールバックURLを設定して&lt;/p>
&lt;p>Auth0でWebサービスのClientIDとClientSecretを設定する、という流れになります。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>4. 認証基盤を利用するアプリケーションを設置する&lt;/h2>
SocialSignOnの設定が終わったら、あとはコードを書くだけ。
&lt;p>Auth0は各言語、各JSフレームワークでのサンプルが豊富で基本的にコピペして使い回せます。&lt;/p>
&lt;p>2で作成したアプリケーションのQuickStartリンクを押下すると以下の画面に遷移します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/auth0-createapp.jpg">&lt;img class="alignnone size-medium wp-image-1321" src="https://blog.freedom-man.com/img/2014/09/auth0-createapp-300x149.jpg" alt="auth0-createapp" width="300" height="149" />&lt;/a>&lt;/p>
&lt;p>ApplicationTypeとPlatformをそれぞれ選択すると超親切なサンプルコードが表示されるので&lt;/p></description></item><item><title>無限リストビュー</title><link>https://blog.freedom-man.com/sfdc_infinite-listview.html</link><pubDate>Tue, 16 Sep 2014 23:45:12 +0000</pubDate><guid>https://blog.freedom-man.com/sfdc_infinite-listview.html</guid><description>&lt;p>ここでクイズ。&lt;/p>
&lt;p>Salesforceのリストビューは1オブジェクトにつき最大何件まで保持することができるでしょうか？？&lt;/p>
&lt;ol>
&lt;li>
&lt;p>1,000&lt;/p>
&lt;/li>
&lt;li>
&lt;p>10,000&lt;/p>
&lt;/li>
&lt;li>
&lt;p>100,000&lt;/p>
&lt;/li>
&lt;li>
&lt;p>根性が続くまで&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Salesforceに怒られるまで&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>ということで検証してみました。&lt;/p>
&lt;p>ちなみにリストビューの件数制限に関してはSFDCのhelpには記載されておりません（多分）&lt;/p>
&lt;p> &lt;/p>
&lt;h2>検証方法1. Eclipseでメタデータ直接いじる&lt;/h2>
Eclipseで対象オブジェクトのメタデータを抽出
&lt;p>→適当なスクリプトでリストビューのXMLをガツっと入れて保存&lt;/p>
&lt;p>と最も手軽に試せる方法。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Pythonだとこんな感じのスクリプトを書く&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">for&lt;/span> num &lt;span style="color:#0550ae">in&lt;/span> &lt;span style="color:#6639ba">range&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">10&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;&amp;lt;listViews&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;fullName&amp;gt;TestView&lt;/span>&lt;span style="color:#0a3069">%09d&lt;/span>&lt;span style="color:#0a3069">&amp;lt;/fullName&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;filterScope&amp;gt;Everything&amp;lt;/filterScope&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;label&amp;gt;TestView_&lt;/span>&lt;span style="color:#0a3069">%09d&lt;/span>&lt;span style="color:#0a3069">&amp;lt;/label&amp;gt;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&amp;lt;/listViews&amp;gt;&amp;#34;&amp;#34;&amp;#34;&lt;/span> &lt;span style="color:#0550ae">%&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>num&lt;span style="color:#1f2328">,&lt;/span> num&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>これを使って生成したテキストを***.objectの中にガツっと入れてSave to Serverする。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/09/inf-listview-eclipse-flow.jpg">&lt;img class="alignnone size-medium wp-image-1305" src="https://blog.freedom-man.com/img/2014/09/inf-listview-eclipse-flow-300x131.jpg" alt="inf-listview-eclipse-flow" width="300" height="131" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;p>1万件くらいの保存だと5-10分程度で保存可能。&lt;/p>
&lt;p>ただし10万件とかになるとEclipseのヒープサイズの方でエラーになってくるので&lt;/p>
&lt;p>この方法ではリストビューの限界を調査するのが難しそう。ということで一旦別の方法を検討。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>検証方法2. CRUDベースのMetadataAPIを使ってチマチマ入れる&lt;/h2>
CRUDベースのMetadataAPI使って最大10件ずつこまめに作成する方法です。
&lt;p> &lt;/p>
&lt;p>Pythonだとこんな感じのスクリプトを組めばOK。&lt;/p>
&lt;p>SessionIDはログイン状態のCookieから奪うなり何なりして取得してください。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#!/usr/bin/env python&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># -*- coding: utf-8 -*-&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">urllib.request&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">urllib.error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BASE_URL &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://na12.salesforce.com&amp;#34;&lt;/span> &lt;span style="color:#57606a">#対象の環境のベースURLを入力&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>f &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">open&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;create_metadata_base.xml&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>payload &lt;span style="color:#0550ae">=&lt;/span> f&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>replace&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{{sessionId}}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input SessionID&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>f&lt;span style="color:#0550ae">.&lt;/span>close&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>f &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">open&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;listview_base.xml&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>base &lt;span style="color:#0550ae">=&lt;/span> f&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>f&lt;span style="color:#0550ae">.&lt;/span>close&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#ユーザ属性の取得&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">try&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> max_size &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">100000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temp_lists &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> i &lt;span style="color:#0550ae">in&lt;/span> &lt;span style="color:#6639ba">range&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>max_size&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temp_lists&lt;span style="color:#0550ae">.&lt;/span>append&lt;span style="color:#1f2328">(&lt;/span>base&lt;span style="color:#0550ae">.&lt;/span>replace&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;{{number}}&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&lt;/span>&lt;span style="color:#0a3069">%09d&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&lt;/span> &lt;span style="color:#0550ae">%&lt;/span> i&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> i&lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#0550ae">6&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">5&lt;/span> &lt;span style="color:#0550ae">or&lt;/span> i &lt;span style="color:#0550ae">==&lt;/span> max_size&lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> req &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>Request&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#0550ae">=&lt;/span>BASE_URL &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/services/Soap/m/28.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> headers&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;SOAPAction&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#34;&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;Content-Type&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;text/xml&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> data&lt;span style="color:#0550ae">=&lt;/span>payload&lt;span style="color:#0550ae">.&lt;/span>replace&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{{body}}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>join&lt;span style="color:#1f2328">(&lt;/span>temp_lists&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> method&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;POST&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>urlopen&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> temp_lists &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">except&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>error&lt;span style="color:#0550ae">.&lt;/span>HTTPError &lt;span style="color:#cf222e">as&lt;/span> e&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>e&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>e&lt;span style="color:#0550ae">.&lt;/span>reason&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>OpenAMでHOTP認証してみる【GoogleAuthenticator編】</title><link>https://blog.freedom-man.com/openam-hotp-googleauthenticator.html</link><pubDate>Thu, 24 Jul 2014 22:29:26 +0000</pubDate><guid>https://blog.freedom-man.com/openam-hotp-googleauthenticator.html</guid><description>&lt;p>&lt;a title="OpenAMでTOTP認証してみる。" href="https://blog.freedom-man.com/openam-totp/" target="_blank">前回&lt;/a>はOpenAMでOATHのTOTP認証をやりました。&lt;/p>
&lt;p>今回はGoogleAuthenticatorでHOTP認証をやってみます。&lt;/p>
&lt;p>※設定は前回とほとんど同じなので省略しまくってます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>HOTPの仕組みに関しては以下のリンクが詳しいです。&lt;/p>
&lt;p>&lt;a title="http://www.atmarkit.co.jp/ait/articles/1310/17/news003_2.html" href="http://www.atmarkit.co.jp/ait/articles/1310/17/news003_2.html" target="_blank">OSSによるアイデンティティ管理（2）：不正ログインを食い止めろ！ OpenAMで認証強化 (2/2) - ＠IT&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URL↓&lt;/p>
&lt;p>&lt;a title="https://wikis.forgerock.org/confluence/display/openam/Configure+OpenAM+to+use+OATH+for+Strong+Authentication" href="https://wikis.forgerock.org/confluence/display/openam/Configure+OpenAM+to+use+OATH+for+Strong+Authentication" target="_blank">Configure OpenAM to use OATH for Strong Authentication - OpenAM - Confluence &lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>1. SecretKeyの生成&lt;/h2>
任意の秘密鍵を生成し、それぞれのbase16エンコード、base32エンコードの値を取得します。
&lt;p> &lt;/p>
&lt;h2>2. OpenAMの設定&lt;/h2>
アクセス制御＞対象のレルム＞データストア＞embedded　を選択して
&lt;p>LDAPユーザ属性のroomNumberを追加します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-ldapsetting4.jpg">&lt;img class="alignnone size-medium wp-image-1275" src="https://blog.freedom-man.com/img/2014/07/openam-ldapsetting4-300x117.jpg" alt="openam-ldapsetting4" width="300" height="117" />&lt;/a>&lt;/p>
&lt;p>アクセス制御＞対象のレルム＞認証　のモジュールインスタンスでOATHの設定を変更&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-hotp-setting.jpg">&lt;img class="alignnone size-medium wp-image-1270" src="https://blog.freedom-man.com/img/2014/07/openam-hotp-setting-300x290.jpg" alt="openam-hotp-setting" width="300" height="290" />&lt;/a>&lt;/p>
&lt;p>前回からの変更点は&lt;/p>
&lt;p>使用するアルゴリズム→HOTP&lt;/p>
&lt;p>カウンタ属性名→roomNumber&lt;/p>
&lt;p>の部分です。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>3. LDAPの設定&lt;/h2>
前回同様にLDAPサーバに接続して対象のユーザのtitle属性とroomNumber属性を追加・変更します。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/ads-ldap-hotp.jpg">&lt;img class="alignnone size-medium wp-image-1271" src="https://blog.freedom-man.com/img/2014/07/ads-ldap-hotp-300x216.jpg" alt="ads-ldap-hotp" width="300" height="216" />&lt;/a>&lt;/p>
&lt;p>秘密鍵のbase16エンコード値をtitleに入力して、roomNumberは0を入力してください。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>4. Google Authenticatorの設定&lt;/h2>
今回のQRコードのURL値は以下の形式になります。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>otpauth://hotp/{適当なユーザ名}@{適当なドメイン}?secret={1で作成したbase32エンコードした秘密鍵}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これをGoogle AuthenticatorのQRコードリーダで読み込ませるか、以下のように手入力でセットします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/googleauthenticator-hotp-manual.png">&lt;img class="alignnone size-medium wp-image-1272" src="https://blog.freedom-man.com/img/2014/07/googleauthenticator-hotp-manual-300x290.png" alt="googleauthenticator-hotp-manual" width="300" height="290" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>あとは前回同様、ログイン画面でOTPコードを送信すれば認証完了となります。&lt;/p></description></item><item><title>OpenAMでTOTP認証してみる。</title><link>https://blog.freedom-man.com/openam-totp.html</link><pubDate>Wed, 23 Jul 2014 21:51:50 +0000</pubDate><guid>https://blog.freedom-man.com/openam-totp.html</guid><description>&lt;p>OpenAMの多要素認証シリーズとしてTOTP認証をやってみます。&lt;/p>
&lt;p>TOTP認証に関しては以下のサイトが詳しいです。&lt;/p>
&lt;p>&lt;a title="http://www.atmarkit.co.jp/ait/articles/1310/17/news003_2.html" href="http://www.atmarkit.co.jp/ait/articles/1310/17/news003_2.html" target="_blank">OSSによるアイデンティティ管理（2）：不正ログインを食い止めろ！ OpenAMで認証強化 (2/2) - ＠IT&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は以下のサイトに従って設定していきます。&lt;/p>
&lt;p>&lt;a title="https://wikis.forgerock.org/confluence/display/openam/Google+Authenticator+and+OpenAM" href="https://wikis.forgerock.org/confluence/display/openam/Google+Authenticator+and+OpenAM" target="_blank">Google Authenticator and OpenAM - OpenAM - Confluence&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>1. SecretKeyの生成&lt;/h2>
適当なSecretKeyを決めてbase16エンコード、base32エンコードした値を生成します。
&lt;p>例えば&amp;quot;test12345abcdefg&amp;quot;というキーであれば&lt;/p>
&lt;p>base16エンコード値→74657374313233343561626364656667&lt;/p>
&lt;p>base32エンコード値→ORSXG5BRGIZTINLBMJRWIZLGM4======&lt;/p>
&lt;p>となります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>各エンコード値は以下のサイトで簡単に生成できます。&lt;/p>
&lt;p>&lt;a title="http://online-calculators.appspot.com/base16/" href="http://online-calculators.appspot.com/base16/" target="_blank">&lt;a href="http://online-calculators.appspot.com/base16/">http://online-calculators.appspot.com/base16/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://online-calculators.appspot.com/base32/" href="http://online-calculators.appspot.com/base32/" target="_blank">&lt;a href="http://online-calculators.appspot.com/base32/">http://online-calculators.appspot.com/base32/&lt;/a>&lt;/a>&lt;/p>
&lt;p>※秘密鍵を第三者に渡すことになるので検証用にお使いください。&lt;/p>
&lt;h2>2. OpenAMの設定&lt;/h2>
アクセス制御＞対象のレルム＞データストア＞embedded　を選択し
&lt;p>LDAPユーザ属性にtitleとdescriptionを追加します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-ldapsetting2.jpg">&lt;img class="alignnone size-medium wp-image-1218" src="https://blog.freedom-man.com/img/2014/07/openam-ldapsetting2-300x117.jpg" alt="openam-ldapsetting2" width="300" height="117" />&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-ldapsetting31.jpg">&lt;img class="alignnone size-medium wp-image-1246" src="https://blog.freedom-man.com/img/2014/07/openam-ldapsetting31-300x115.jpg" alt="openam-ldapsetting3" width="300" height="115" />&lt;/a>&lt;/p>
&lt;p>次に　アクセス制御＞対象のレルム＞認証　のモジュールインスタンスでOATHをクリックします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-totp-authmodules.jpg">&lt;img class="alignnone size-medium wp-image-1244" src="https://blog.freedom-man.com/img/2014/07/openam-totp-authmodules-300x126.jpg" alt="openam-totp-authmodules" width="300" height="126" />&lt;/a>&lt;/p>
&lt;p>OATHを以下のように設定します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oathsetting.png">&lt;img class="alignnone size-medium wp-image-1211" src="https://blog.freedom-man.com/img/2014/07/openam-oathsetting-300x281.png" alt="openam-oathsetting" width="300" height="281" />&lt;/a>&lt;/p>
&lt;p>今回は検証用なので秘密鍵は8桁にしちゃってますが、本番用はもっと大きい桁数（デフォルト32桁）にしてください。&lt;/p>
&lt;p>秘密鍵の属性にtitle、最終ログイン時間属性にはdescriptionを割り当てます。あとはデフォルト通り。&lt;/p>
&lt;p>※検証用なので属性はテキトーです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、TOTPのタイムステップ感覚とタイムステップ数ですが&lt;/p>
&lt;p>今回利用するGoogle Authenticatorはトークンの生成間隔が30秒なのでデフォルト通りでOKです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>最後に認証連鎖を設定します。&lt;/p>
&lt;p>こんな感じの認証連鎖を作成↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-totp-authchain.jpg">&lt;img class="alignnone size-medium wp-image-1264" src="https://blog.freedom-man.com/img/2014/07/openam-totp-authchain-300x114.jpg" alt="openam-totp-authchain" width="300" height="114" />&lt;/a>&lt;/p>
&lt;p>組織認証設定を変更&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-totp-orgsetting.jpg">&lt;img class="alignnone size-medium wp-image-1263" src="https://blog.freedom-man.com/img/2014/07/openam-totp-orgsetting-300x99.jpg" alt="openam-totp-orgsetting" width="300" height="99" />&lt;/a>&lt;/p>
&lt;h2>3. LDAPの設定&lt;/h2>
OpenAMのデータストア（LDAP）にアクセスしてtitle属性に秘密鍵を格納します。
&lt;p>LDAPにアクセスする手段としてGUIツールの&lt;a title="http://directory.apache.org/studio/" href="http://directory.apache.org/studio/" target="_blank">Apache Directory Studio&lt;/a>を利用します。&lt;/p></description></item><item><title>OpenAMでHOTP認証してみる【メール送信編】</title><link>https://blog.freedom-man.com/openam-hotpauth-mail.html</link><pubDate>Tue, 22 Jul 2014 00:35:25 +0000</pubDate><guid>https://blog.freedom-man.com/openam-hotpauth-mail.html</guid><description>&lt;p>これまでOpenAMでシングルサインオンをするためのパターンをいくつか紹介しました。&lt;/p>
&lt;p>シングルサインオンは「一回ログインすれば複数のサービスを利用できる」ことが利点ですが&lt;/p>
&lt;p>反面、「攻撃者にログインされると複数サービスを利用されてしまう」という欠点もあります。&lt;/p>
&lt;p>この欠点を補うのが「多要素認証」になります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は多要素認証の一つであるHOTP認証をOpenAMでやってみたいと思います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URLはこちら&lt;/p>
&lt;p>&lt;a title="http://www.atmarkit.co.jp/ait/articles/1310/17/news003.html" href="http://www.atmarkit.co.jp/ait/articles/1310/17/news003.html" target="_blank">OSSによるアイデンティティ管理（2）：不正ログインを食い止めろ！ OpenAMで認証強化 (1/2) - ＠IT&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://codezine.jp/article/detail/6853" href="http://codezine.jp/article/detail/6853" target="_blank">OpenAMが提供する様々な認証方式 （1/4）：CodeZine&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://netforestdevnote.blog26.fc2.com/blog-entry-27.html" href="http://netforestdevnote.blog26.fc2.com/blog-entry-27.html" target="_blank">Netforest Developer&amp;rsquo;s Note - OpenSSOでワンタイムパスワード&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index/chap-auth-services.html" href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index/chap-auth-services.html" target="_blank">Chapter 2. Defining Authentication Services &lt;/a>&lt;/p>
&lt;p>&lt;a title="https://www.osstech.co.jp/_media/techinfo/seminar/openam-shibboleth.pdf" href="https://www.osstech.co.jp/_media/techinfo/seminar/openam-shibboleth.pdf" target="_blank">&lt;a href="https://www.osstech.co.jp/_media/techinfo/seminar/openam-shibboleth.pdf">https://www.osstech.co.jp/_media/techinfo/seminar/openam-shibboleth.pdf&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>OpenAMの設定&lt;/h2>
アクセス制御＞対象のレルム＞認証　のモジュールインスタンスでHOTPをクリック。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-hotp-authmodules.jpg">&lt;img class="alignnone size-medium wp-image-1222" src="https://blog.freedom-man.com/img/2014/07/openam-hotp-authmodules-300x145.jpg" alt="openam-hotp-authmodules" width="300" height="145" />&lt;/a>&lt;/p>
&lt;p>今回はGmailのSMTPサーバを使うので以下のように編集。&lt;/p>
&lt;p>ユーザ名/パスワードはそれぞれGmailのユーザ名/パスワードを入力する。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-hotpsetting.png">&lt;img class="alignnone size-medium wp-image-1212" src="https://blog.freedom-man.com/img/2014/07/openam-hotpsetting-243x300.png" alt="openam-hotpsetting" width="243" height="300" />&lt;/a>&lt;/p>
&lt;p>アクセス制御＞対象のレルム＞認証　の認証連鎖で新規の認証連鎖を作成&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-authchain1.jpg">&lt;img class="alignnone size-medium wp-image-1235" src="https://blog.freedom-man.com/img/2014/07/openam-authchain1-300x100.jpg" alt="openam-authchain1" width="300" height="100" />&lt;/a>&lt;/p>
&lt;p>対象の認証連鎖の設定を以下のように編集します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-hotp-authchain1.jpg">&lt;img class="alignnone size-medium wp-image-1236" src="https://blog.freedom-man.com/img/2014/07/openam-hotp-authchain1-300x113.jpg" alt="openam-hotp-authchain1" width="300" height="113" />&lt;/a>&lt;/p>
&lt;p>認証設定を以下のように変更します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-hotp-core.jpg">&lt;img class="alignnone size-medium wp-image-1234" src="https://blog.freedom-man.com/img/2014/07/openam-hotp-core-300x132.jpg" alt="openam-hotp-core" width="300" height="132" />&lt;/a>&lt;/p>
&lt;p>上記設定で/openam/UI/LoginでログインするときにはHOTPの認証連鎖設定が適用され&lt;/p>
&lt;p>/openam/consoleでログインすると きには通常のID/パスワード認証のみの設定が適用されます。&lt;/p>
&lt;p>これにより、設定ミスによってadminがログインできない状態になることを防ぎます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>最後に　アクセス制御＞対象のレルム＞対象＞対象のユーザ　でメールアドレスを設定&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-usermailsetting.jpg">&lt;img class="alignnone size-medium wp-image-1225" src="https://blog.freedom-man.com/img/2014/07/openam-usermailsetting-300x133.jpg" alt="openam-usermailsetting" width="300" height="133" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>動作確認&lt;/h2>
ログイン画面（/openam/UI/Login）でID/パスワード認証後、以下の画面が出てきます。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-hotp-authpage.jpg">&lt;img class="alignnone size-medium wp-image-1227" src="https://blog.freedom-man.com/img/2014/07/openam-hotp-authpage-300x118.jpg" alt="openam-hotp-authpage" width="300" height="118" />&lt;/a>&lt;/p>
&lt;p>OTPコードの要求をすると対象のユーザ（ログイン失敗したユーザ）のメールアドレスに&lt;/p></description></item><item><title>OpenAMでSSO【OpenIG編】</title><link>https://blog.freedom-man.com/openam-sso-openig.html</link><pubDate>Mon, 21 Jul 2014 00:07:26 +0000</pubDate><guid>https://blog.freedom-man.com/openam-sso-openig.html</guid><description>&lt;p>今回はOpenAM+OpenIG+PolicyAgentなSSOをやってみます。&lt;/p>
&lt;p>以下のような構成になります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openig-architecture.png">&lt;img class="alignnone size-medium wp-image-1186" src="https://blog.freedom-man.com/img/2014/07/openig-architecture-300x284.png" alt="openig-architecture" width="300" height="284" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;p>フローを簡単に説明すると&lt;/p>
&lt;ol>
&lt;li>
&lt;p>UserAgentがWebサーバにアクセス（初回）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Policy Agentがリクエストをインタラプト、Cookieが入っていないのでOpenAMに認証要求リダイレクト&lt;/p>
&lt;/li>
&lt;li>
&lt;p>OpenAMで認証後、Webサーバにリダイレクト&lt;/p>
&lt;/li>
&lt;li>
&lt;p>認証されている(=Cookieが入っている)のでPolicy AgentはCookie値をOpenAMに問い合わせて&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>ユーザ名/パスワードを取得&lt;/p>
&lt;ol start="5">
&lt;li>Policy Agentが取得したユーザ名/パスワードをヘッダに入れてOpenIGにリクエスト&lt;/li>
&lt;/ol>
&lt;p>（パスワードは暗号化されている）&lt;/p>
&lt;ol start="6">
&lt;li>OpenIGはログイン画面がリクエストされた時のみヘッダからユーザ情報を取得し、認証リクエストを行う&lt;/li>
&lt;/ol>
&lt;p>（通常のフォームPOSTを模倣する）&lt;/p>
&lt;ol start="7">
&lt;li>Webアプリは認証リクエストを受け取り、ユーザ認証実行後OpenIG・Policy Agent経由で&lt;/li>
&lt;/ol>
&lt;p>UserAgentにレスポンスを返して認証終了&lt;/p>
&lt;p>といった感じです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>OpenIGはリクエストのプロトコルやURI、ヘッダ等の情報やフォワードしたHTTPリクエストに対する&lt;/p>
&lt;p>レスポンスの正規表現マッチングを使って処理を分岐させたり&lt;/p>
&lt;p>HTTPクライアントとして動かしたりできるリバースプロキシソフトウェアになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はOpenIGを使ってOpenAMで認証されたユーザ名/パスワードでWebアプリにSSOするフローをやってみます。&lt;/p>
&lt;p>※本記事ではOpenAMのユーザ名/パスワード＝Webサイトのユーザ名/パスワードになることを想定しています。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URLは以下になります。&lt;/p>
&lt;p>&lt;a title="http://tech-sketch.jp/2013/06/openam-1.html" href="http://tech-sketch.jp/2013/06/openam-1.html" target="_blank">OpenAMによるシングルサインオン（２）リバースプロキシー編 - Tech-Sketch&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://www.la-j.com/tech-blog/?tag=openig" href="http://www.la-j.com/tech-blog/?tag=openig" target="_blank">OpenIG | LAJ技術ブログ&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openig.forgerock.org/doc/gateway-guide/index/chap-usecases.html" href="http://docs.forgerock.org/en/openig/3.0.0/gateway-guide/index/chap-usecases.html" target="_blank">Chapter 5. Detailed Use Cases&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openig.forgerock.org/doc/gateway-guide/index/chap-password-capture-replay-tutorial.html" href="http://docs.forgerock.org/en/openig/3.0.0/gateway-guide/index/chap-password-capture-replay-tutorial.html" target="_blank">Chapter 7. Tutorial On OpenAM Password Capture &amp;amp; Replay&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openig.forgerock.org/doc/gateway-guide/index/chap-gateway-templates.html" href="http://docs.forgerock.org/en/openig/3.0.0/gateway-guide/index/chap-gateway-templates.html" target="_blank">Chapter 11. Configuration Templates&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>1. OpenIGのインストール&lt;/h2>
Javaのアプリケーションサーバで動作するらしいのでtomcat使ってやってみます。
&lt;p>ダウンロードはここから→&lt;a title="https://forgerock.org/downloads/openig-builds/" href="https://forgerock.org/downloads/openig-builds/" target="_blank">&lt;a href="https://forgerock.org/downloads/openig-builds/">https://forgerock.org/downloads/openig-builds/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>展開したwarファイルをtomcatのルートに設置&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mv &lt;span style="color:#0550ae">{&lt;/span>展開したwar&lt;span style="color:#0550ae">}&lt;/span> /var/lib/tomcat7/webapps/ROOT.war
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>tomcat実行ユーザのホームを/etc/passwdで調べて以下のディレクトリに設定ファイルを作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ touch &lt;span style="color:#0550ae">{&lt;/span>tomcat実行ユーザのホーム&lt;span style="color:#0550ae">}&lt;/span>/.openig/config/config.json
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>あとはconfig.jsonの設定ファイルを書き換えていくだけでOK。(3を参照)&lt;/p>
&lt;p> &lt;/p>
&lt;h2>2. OpenAMの設定&lt;/h2>
&lt;a title="OpenAMでSSO【Policy Agent編】" href="https://blog.freedom-man.com/openam-sso-policyagent/" target="_blank">Policy Agent編&lt;/a>でのPolicy Agentの仕事はトークンの検証のみで良かったのですが
&lt;p>今回はユーザ情報をOpenIGに送る必要がある（OpenIGからOpenAMのユーザ情報を取得できない）ことから&lt;/p></description></item><item><title>OpenAMでSSO【OpenID Connect編】</title><link>https://blog.freedom-man.com/openam-sso-oidc-op.html</link><pubDate>Sun, 20 Jul 2014 16:20:03 +0000</pubDate><guid>https://blog.freedom-man.com/openam-sso-oidc-op.html</guid><description>&lt;p>今回はOpenAMを使ってOpenID ConnectでSSOを実現したいと思います。&lt;/p>
&lt;p>この方法だとPolicy Agentと同様にWebアプリの改修が必要になりますが&lt;/p>
&lt;p>OpenID Connect準拠なのでセキュリティ等が担保されているのが利点です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>以下、参考URLになります。&lt;/p>
&lt;p>&lt;a title="http://kirimanjirou.com/blog/?p=160" href="http://kirimanjirou.com/blog/?p=160" target="_blank">最新のOpenAMを導入してOpenID Connect ServerとClientを実装する(IdP編)&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://www.atmarkit.co.jp/ait/articles/1406/13/news004_3.html" href="http://www.atmarkit.co.jp/ait/articles/1406/13/news004_3.html" target="_blank">OSSによるアイデンティティ管理（4）：OpenAMのOpenID Connectへの対応 (3/3) - ＠IT&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/dev-guide/index/chap-rest.html" href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/dev-guide/index/chap-rest.html" target="_blank">Chapter 3. Using RESTful Web Services &lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index/chap-agents.html#configure-oauth2-client" href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index/chap-agents.html#configure-oauth2-client" target="_blank">Chapter 6. Configuring Policy Agent Profiles&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index/chap-oauth2.html#configure-oauth2-authz" href="http://openam.forgerock.org/openam-documentation/openam-doc-source/doc/admin-guide/index/chap-oauth2.html#configure-oauth2-authz" target="_blank">Chapter 12. Managing OAuth 2.0 Authorization&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>SFDCにはOpenID ConnectのRP側の機能もあるので、SFDCとOpenAMをOpenID ConnectでSSOしてみます。&lt;/p>
&lt;p> &lt;/p>
&lt;h2>1. OpenAM側の設定&lt;/h2>
基本的に参考URL通りにやっておけばOKで
&lt;p>トップページからOAuth2の設定をクリックして作成&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oauth2setting.jpg">&lt;img class="alignnone size-medium wp-image-1155" src="https://blog.freedom-man.com/img/2014/07/openam-oauth2setting-300x200.jpg" alt="openam-oauth2setting" width="300" height="200" />&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oauth2-create.jpg">&lt;img class="alignnone size-medium wp-image-1157" src="https://blog.freedom-man.com/img/2014/07/openam-oauth2-create-300x212.jpg" alt="openam-oauth2-create" width="300" height="212" />&lt;/a>&lt;/p>
&lt;p>で、アクセス制御＞対象のレルム＞エージェント＞OAuth2.0クライアントでエージェントを作成&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oauth2-agent.jpg">&lt;img class="alignnone size-medium wp-image-1158" src="https://blog.freedom-man.com/img/2014/07/openam-oauth2-agent-300x135.jpg" alt="openam-oauth2-agent" width="300" height="135" />&lt;/a>&lt;/p>
&lt;p>エージェントの名前がClientID、パスワードがClientSecretになります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oauth2-createagent.jpg">&lt;img class="alignnone size-medium wp-image-1159" src="https://blog.freedom-man.com/img/2014/07/openam-oauth2-createagent-300x113.jpg" alt="openam-oauth2-createagent" width="300" height="113" />&lt;/a>&lt;/p>
&lt;p>作成後に細かい設定ができます。&lt;/p>
&lt;p>リダイレクトURI↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oauth2-redirecturi.jpg">&lt;img class="alignnone size-medium wp-image-1162" src="https://blog.freedom-man.com/img/2014/07/openam-oauth2-redirecturi-300x147.jpg" alt="openam-oauth2-redirecturi" width="300" height="147" />&lt;/a>&lt;/p>
&lt;p>スコープ↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/openam-oauth2-scope.jpg">&lt;img class="alignnone size-medium wp-image-1161" src="https://blog.freedom-man.com/img/2014/07/openam-oauth2-scope-300x141.jpg" alt="openam-oauth2-scope" width="300" height="141" />&lt;/a>&lt;/p>
&lt;p>デフォルトのスコープ↓&lt;/p></description></item><item><title>OpenAMでSSO【Policy Agent編】</title><link>https://blog.freedom-man.com/openam-sso-policyagent.html</link><pubDate>Sat, 19 Jul 2014 14:57:22 +0000</pubDate><guid>https://blog.freedom-man.com/openam-sso-policyagent.html</guid><description>&lt;p>以前、&lt;a title="SalesforceとOpenAMでSSOやってみる。" href="https://blog.freedom-man.com/openam_salesforce_sso/" target="_blank">OpenAMを使ってSAML2.0でSSOをする記事&lt;/a>を書きましたが、SAML2.0を使ったSSOだとWebアプリケーション側が対応してないケースが多く、実装も困難であるため任意のWebアプリケーションに対するSSOの手段としてあまり適用できません。&lt;/p>
&lt;p>ということで、今回から「OpenAMを認証プロバイダにして任意のWebアプリに対してシングルサインオン」をする方法に関して書いてみます！&lt;/p></description></item><item><title>Salesforceの代理認証SSOやってみる</title><link>https://blog.freedom-man.com/salesforce-sso-authproxy.html</link><pubDate>Sun, 13 Jul 2014 23:33:38 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-sso-authproxy.html</guid><description>&lt;p>SalesforceにはSalesforceへの認証を任意の認証サーバが行えるようになる代理認証機能があります。&lt;/p>
&lt;p>これによって、Salesforceのパスワードではなく独自で認証基盤を運用することが可能になります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、代理認証SSOをやってみます！&lt;/p>
&lt;p>今回はJava + tomcat + axisな代理認証SOAPサーバを立ててみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考URL：&lt;/p>
&lt;p>&lt;a title="http://www.ibm.com/developerworks/jp/webservices/library/ws-devaxis2part1/" href="http://www.ibm.com/developerworks/jp/webservices/library/ws-devaxis2part1/" target="_blank">Web サービスを開発する: 第 1 回 Axis2 を使用して、コード・ファースト手法とコントラクト・ファースト手法で Web サービスを開発する&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. tomcat、axis、antのセットアップ&lt;/strong>&lt;/h3>
&lt;a title="http://tomcat.apache.org/" href="http://tomcat.apache.org/" target="_blank">tomcat&lt;/a>をインストールして&lt;a title="http://axis.apache.org/axis2/java/core/download.cgi" href="http://axis.apache.org/axis2/java/core/download.cgi" target="_blank">axis2&lt;/a>をダウンロード。
&lt;p>Binary DistributionとWAR Distributionの両方をダウンロードしてください。&lt;/p>
&lt;p>WARの方はzip展開してtomcatのwebappsディレクトリに入れてインストールは完了。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Binaryの方はSalesforceのwsdlからjavaに変換するために利用します。&lt;/p>
&lt;p>antはaarファイルの作成に利用します。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. wsdlからサーバースタブを作成&lt;/strong>&lt;/h3>
Salesforceから代理認証用のwsdlを取得（設定＞開発＞API）
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/download-auth-wsdl.jpg">&lt;img class="alignnone size-medium wp-image-1089" src="https://blog.freedom-man.com/img/2014/07/download-auth-wsdl-300x166.jpg" alt="download-auth-wsdl" width="300" height="166" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>任意のディレクトリで以下のコマンドを実行。&lt;/p>
&lt;p>{AXIS2_HOME}にはBinary Distributionのaxis2のパスを入れてください。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#0550ae">{&lt;/span>Binary Distributionのaxis2のパス&lt;span style="color:#0550ae">}&lt;/span>&lt;span style="color:#0a3069">\b&lt;/span>in&lt;span style="color:#0a3069">\w&lt;/span>sdl2java.bat &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span> -uri &lt;span style="color:#0550ae">{&lt;/span>wsdlへのパス&lt;span style="color:#0550ae">}&lt;/span>/AuthenticateService.wsdl -d adb -s -ss -sd -ssi -o .
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>これでサーバースタブが作成されます。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. スケルトンクラスにロジックを追加&lt;/strong>&lt;/h3>
src\com\sforce\soap\authenticationディレクトリのSforceAuthenticationServiceSkeleton.java内の
&lt;p>ToDo: fill this with&amp;hellip;のところにロジックを追加します。&lt;/p>
&lt;p>今回はテキトーに認証してみます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SforceAuthenticationServiceSkeleton.java
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> *
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * This file was auto-generated from WSDL
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * by the Apache Axis2 version: 1.6.2 Built on : Apr 17, 2012 (05:33:49 IST)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">package&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#24292e">com.sforce.soap.authentication&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SforceAuthenticationServiceSkeleton java skeleton for the axisService
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">SforceAuthenticationServiceSkeleton&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">implements&lt;/span>&lt;span style="color:#fff"> &lt;/span>SforceAuthenticationServiceSkeletonInterface&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Auto generated method signature
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Are the supplied saleforce.com userId and password valid ?
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param authenticate0 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @return authenticateResult1 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>com&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sforce&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">soap&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">authentication&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AuthenticateResultE&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">authenticate&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>com&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sforce&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">soap&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">authentication&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AuthenticateE&lt;/span>&lt;span style="color:#fff"> &lt;/span>authenticate0&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">//TODO : fill this with the necessary business logic&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>AuthenticateResult&lt;span style="color:#fff"> &lt;/span>result&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>AuthenticateResult&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Authenticate&lt;span style="color:#fff"> &lt;/span>auth&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>authenticate0&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getAuthenticate&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Boolean&lt;span style="color:#fff"> &lt;/span>isAuth&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>auth&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getUsername&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">equals&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;hoge@fuga.com&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>auth&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getPassword&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">equals&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;abcdef&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>result&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setAuthenticated&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>isAuth&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>AuthenticateResultE&lt;span style="color:#fff"> &lt;/span>resulte&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>AuthenticateResultE&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>resulte&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setAuthenticateResult&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>result&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>resulte&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>パラメータのAuthenticateEクラスからユーザ名とパスワードとログイン要求元IPアドレスを取得して&lt;/p></description></item><item><title>SalesforceコミュニティでOpenID Connectやってみる【Authorization Code Flow編】</title><link>https://blog.freedom-man.com/sf-community-oidc-acf.html</link><pubDate>Thu, 10 Jul 2014 00:33:51 +0000</pubDate><guid>https://blog.freedom-man.com/sf-community-oidc-acf.html</guid><description>&lt;p>SalesforceをOPにして&lt;a title="http://openid.net/connect/" href="http://openid.net/connect/" target="_blank">OpenID Connect&lt;/a>によるソーシャルログインが出来るということなので試してみた。&lt;/p>
&lt;p>せっかくなのでSalesforceユーザではなく、コミュニティユーザでソーシャルサインオンをやってみます。&lt;/p>
&lt;p>RP側はPython/Flaskで。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. 接続アプリケーションの設定&lt;/strong>&lt;/h3>
いつもの接続アプリケーション。
&lt;p>今回はaccess_tokenを使ってUserInfo以外のAPIを叩かないのでid openid refresh_tokenをscopeに入れました。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/connectapp-oidc.jpg">&lt;img class="alignnone size-medium wp-image-1061" src="https://blog.freedom-man.com/img/2014/07/connectapp-oidc-300x126.jpg" alt="connectapp-oidc" width="300" height="126" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. RP側プログラムの作成
&lt;/strong>&lt;/h3>
pythonのバージョンは3.3系。暗号化ライブラリとして&lt;a title="https://www.dlitz.net/software/pycrypto/" href="https://www.dlitz.net/software/pycrypto/" target="_blank">PyCrypto&lt;/a>を使ってます。
&lt;p> &lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># -*- coding: utf-8 -*- &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">Crypto.Hash&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> SHA256
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">Crypto.PublicKey&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> RSA
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">Crypto.Signature&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> PKCS1_v1_5
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">Crypto.Util.number&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> bytes_to_long
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">flask&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> Flask&lt;span style="color:#1f2328">,&lt;/span> request&lt;span style="color:#1f2328">,&lt;/span> session&lt;span style="color:#1f2328">,&lt;/span> render_template
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">urllib.error&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> HTTPError
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">urllib.request&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">base64&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">time&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">random&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">hmac&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>BASE_URL &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://{community domain}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>CLIENT_ID &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;input your client_id&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>CLIENT_SECRET &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;input your client_secret&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>REDIRECT_URI &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;input your redirect_uri&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">get_random_string&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>length&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> ランダムな文字列を生成する
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> source_str &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>join&lt;span style="color:#1f2328">([&lt;/span>random&lt;span style="color:#0550ae">.&lt;/span>choice&lt;span style="color:#1f2328">(&lt;/span>source_str&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#cf222e">for&lt;/span> x &lt;span style="color:#0550ae">in&lt;/span> &lt;span style="color:#6639ba">range&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>length&lt;span style="color:#1f2328">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">b64d&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> base64urlデコード
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> b &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;=&amp;#34;&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#1f2328">((&lt;/span>&lt;span style="color:#0550ae">4&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#6639ba">len&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#0550ae">%&lt;/span> &lt;span style="color:#0550ae">4&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> base64&lt;span style="color:#0550ae">.&lt;/span>urlsafe_b64decode&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">b64e&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> base64urlエンコード
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> base64&lt;span style="color:#0550ae">.&lt;/span>urlsafe_b64encode&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>replace&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;=&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">b64_to_long&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> base64エンコードした文字列をロング型に変換
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> bytes_to_long&lt;span style="color:#1f2328">(&lt;/span>b64d&lt;span style="color:#1f2328">(&lt;/span>b&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">get_rsa_publickey&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jwt_header&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> https://&lt;/span>&lt;span style="color:#0a3069">{sfdcドメイン}&lt;/span>&lt;span style="color:#0a3069">/id/keysから公開鍵を取得する。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> kid &lt;span style="color:#0550ae">=&lt;/span> json&lt;span style="color:#0550ae">.&lt;/span>loads&lt;span style="color:#1f2328">(&lt;/span>b64d&lt;span style="color:#1f2328">(&lt;/span>jwt_header&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">())[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;kid&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> req &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>Request&lt;span style="color:#1f2328">(&lt;/span>url&lt;span style="color:#0550ae">=&lt;/span>BASE_URL &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/id/keys&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>urlopen&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jsonMap &lt;span style="color:#0550ae">=&lt;/span> json&lt;span style="color:#0550ae">.&lt;/span>loads&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> target_key &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">for&lt;/span> key &lt;span style="color:#0550ae">in&lt;/span> jsonMap&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;keys&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> key&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;kid&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> kid&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> target_key &lt;span style="color:#0550ae">=&lt;/span> key
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> modulus &lt;span style="color:#0550ae">=&lt;/span> b64_to_long&lt;span style="color:#1f2328">(&lt;/span>target_key&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;n&amp;#34;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exponent &lt;span style="color:#0550ae">=&lt;/span> b64_to_long&lt;span style="color:#1f2328">(&lt;/span>target_key&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;e&amp;#34;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> RSA&lt;span style="color:#0550ae">.&lt;/span>construct&lt;span style="color:#1f2328">((&lt;/span>modulus&lt;span style="color:#1f2328">,&lt;/span> exponent&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">validate_idtoken&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jwt&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> JWSの署名検証
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jwt_array &lt;span style="color:#0550ae">=&lt;/span> jwt&lt;span style="color:#0550ae">.&lt;/span>split&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jws_payload &lt;span style="color:#0550ae">=&lt;/span> jwt_array&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> jwt_array&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#https://{sfdcドメイン}/id/keysから公開鍵の情報を取得&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> key &lt;span style="color:#0550ae">=&lt;/span> get_rsa_publickey&lt;span style="color:#1f2328">(&lt;/span>jwt_array&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#jws_payloadのSHA-256ハッシュ値と復号化した署名が一致しているかどうかを検証&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> signer &lt;span style="color:#0550ae">=&lt;/span> PKCS1_v1_5&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> local_hash &lt;span style="color:#0550ae">=&lt;/span> SHA256&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>jws_payload&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> signer&lt;span style="color:#0550ae">.&lt;/span>verify&lt;span style="color:#1f2328">(&lt;/span>local_hash&lt;span style="color:#1f2328">,&lt;/span> b64d&lt;span style="color:#1f2328">(&lt;/span>jwt_array&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">]))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">create_signature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>json_map&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> id,issued_atからSignatureを生成し署名を検証する
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> payload &lt;span style="color:#0550ae">=&lt;/span> json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;issued_at&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> signature &lt;span style="color:#0550ae">=&lt;/span> hmac&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>CLIENT_SECRET&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">(),&lt;/span> payload&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">(),&lt;/span> SHA256&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>digest&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> base64&lt;span style="color:#0550ae">.&lt;/span>b64encode&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">get_idtoken&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>code&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> id_token+access_tokenの取得
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#access_tokenの取得&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> token_req_param &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;grant_type&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;authorization_code&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_id&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> CLIENT_ID&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_secret&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> CLIENT_SECRET&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;redirect_uri&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> REDIRECT_URI&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;code&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> code
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> req &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>Request&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#0550ae">=&lt;/span>BASE_URL &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/services/oauth2/token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> data&lt;span style="color:#0550ae">=&lt;/span>urllib&lt;span style="color:#0550ae">.&lt;/span>parse&lt;span style="color:#0550ae">.&lt;/span>urlencode&lt;span style="color:#1f2328">(&lt;/span>token_req_param&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> headers&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Content-Type&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;application/x-www-form-urlencoded&amp;#34;&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>urlopen&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> json&lt;span style="color:#0550ae">.&lt;/span>loads&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">except&lt;/span> HTTPError &lt;span style="color:#cf222e">as&lt;/span> error&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>error&lt;span style="color:#0550ae">.&lt;/span>reason&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">get_userinfo&lt;/span>&lt;span style="color:#1f2328">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> ユーザ情報の取得
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#access_tokenの取得&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> req &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>Request&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#0550ae">=&lt;/span>session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;instance_url&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/services/oauth2/userinfo&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> headers&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Authorization&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Bearer &amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;access_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> res &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>urlopen&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> json&lt;span style="color:#0550ae">.&lt;/span>loads&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">except&lt;/span> HTTPError &lt;span style="color:#cf222e">as&lt;/span> error&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>error&lt;span style="color:#0550ae">.&lt;/span>reason&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app &lt;span style="color:#0550ae">=&lt;/span> Flask&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">__name__&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app&lt;span style="color:#0550ae">.&lt;/span>debug &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">True&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app&lt;span style="color:#0550ae">.&lt;/span>secret_key &lt;span style="color:#0550ae">=&lt;/span> get_random_string&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">@app.route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">index&lt;/span>&lt;span style="color:#1f2328">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> Authorization Requestの為の初期ページ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> request_param &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;response_type&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;code&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_id&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> CLIENT_ID&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;redirect_uri&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> REDIRECT_URI&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;scope&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;id openid refresh_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;state&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> get_random_string&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;nonce&amp;#34;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> get_random_string&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">32&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;state&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> request_param&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;state&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;nonce&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> request_param&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;nonce&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> authorization_url &lt;span style="color:#0550ae">=&lt;/span> BASE_URL &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/services/oauth2/authorize?&amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>parse&lt;span style="color:#0550ae">.&lt;/span>urlencode&lt;span style="color:#1f2328">(&lt;/span>request_param&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render_template&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> authorization_url&lt;span style="color:#0550ae">=&lt;/span>authorization_url&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">@app.route&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/callback&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">callback&lt;/span>&lt;span style="color:#1f2328">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> Authorization Requestに対するコールバックを受け取る
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#state値が正しいかどうか確認&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;state&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>args&lt;span style="color:#0550ae">.&lt;/span>get&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;state&amp;#34;&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;invalid parameter error!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#id_token(+access_token)の取得&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> json_map &lt;span style="color:#0550ae">=&lt;/span> get_idtoken&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>args&lt;span style="color:#0550ae">.&lt;/span>get&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;code&amp;#34;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#signature検証&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;signature&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> create_signature&lt;span style="color:#1f2328">(&lt;/span>json_map&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;invalid parameter error!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#id_tokenの検証&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> validate_idtoken&lt;span style="color:#1f2328">(&lt;/span>json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;id_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jwt_array &lt;span style="color:#0550ae">=&lt;/span> json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;id_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>split&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> jwt_claim &lt;span style="color:#0550ae">=&lt;/span> json&lt;span style="color:#0550ae">.&lt;/span>loads&lt;span style="color:#1f2328">(&lt;/span>b64d&lt;span style="color:#1f2328">(&lt;/span>jwt_array&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> now &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>time&lt;span style="color:#0550ae">.&lt;/span>mktime&lt;span style="color:#1f2328">(&lt;/span>datetime&lt;span style="color:#0550ae">.&lt;/span>datetime&lt;span style="color:#0550ae">.&lt;/span>now&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>utctimetuple&lt;span style="color:#1f2328">()))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> exp &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jwt_claim&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;exp&amp;#34;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#token有効期限の確認&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> now &lt;span style="color:#0550ae">&amp;gt;&lt;/span> exp&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;code is expired!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> jwt_claim&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;nonce&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">!=&lt;/span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;nonce&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;invalid parameter error!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> signature &lt;span style="color:#0550ae">=&lt;/span> SHA256&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;refresh_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>digest&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#signature = SHA256.new(json_map[&amp;#34;access_token&amp;#34;].encode()).digest() #at_hash&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#signature = SHA256.new(request.args.get(&amp;#34;code&amp;#34;).encode()).digest() #c_hash&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>json_map&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jwt_claim&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> signature &lt;span style="color:#0550ae">=&lt;/span> b64e&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">[:&lt;/span>&lt;span style="color:#6639ba">int&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">len&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">)])&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>replace&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;=&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#hash, issuer, audienceの確認&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> signature &lt;span style="color:#0550ae">==&lt;/span> jwt_claim&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;c_hash&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">and&lt;/span> jwt_claim&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;iss&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://login.salesforce.com&amp;#34;&lt;/span> &lt;span style="color:#0550ae">and&lt;/span> jwt_claim&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;aud&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> CLIENT_ID&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;id&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> jwt_claim&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;sub&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;access_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;access_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> session&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;instance_url&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> json_map&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;instance_url&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> userinfo &lt;span style="color:#0550ae">=&lt;/span> get_userinfo&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;hello &amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> userinfo&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;lt;br/&amp;gt;login is successful!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#0a3069">&amp;#34;validation error!!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#953800">__name__&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app&lt;span style="color:#0550ae">.&lt;/span>run&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>ArduinoからChatter投稿してみる【シリアル通信編】</title><link>https://blog.freedom-man.com/arduino-chatter-serial.html</link><pubDate>Thu, 03 Jul 2014 00:08:23 +0000</pubDate><guid>https://blog.freedom-man.com/arduino-chatter-serial.html</guid><description>&lt;p>&lt;a title="ArduinoからChatter投稿してみる【Web proxy編】" href="https://blog.freedom-man.com/arduino-chatter-webproxy/" target="_blank">前回&lt;/a>はWeb proxyを介してChatter投稿しましたが、&lt;/p>
&lt;p>今回はWebではなくシリアル通信でproxyとやりとりしたいと思います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>フローとしては&lt;/p>
&lt;p>Arduinoから出力したデータをシリアル通信でPCにデータ転送&lt;/p>
&lt;p>→データを受け取ったPC側のプログラムがデータを検知したらChatterに投稿&lt;/p>
&lt;p>って感じです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は光センサ（CdSセンサ）を使って、電気を消したらChatterに自動投稿されるというモノを作ってみます。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>0. 準備&lt;/strong>&lt;/h3>
必要な物は以下になります。イーサネット関連がいらなくなるので前回より手軽です。
&lt;p>・&lt;a title="http://www.switch-science.com/catalog/789/" href="http://www.switch-science.com/catalog/789/" target="_blank">Arduino Uno R3&lt;/a>&lt;/p>
&lt;p>・&lt;a title="http://akizukidenshi.com/catalog/g/gI-00110/" href="http://akizukidenshi.com/catalog/g/gI-00110/" target="_blank">CdSセンサ&lt;/a>&lt;/p>
&lt;p>・ジャンプワイヤ、抵抗、ブレッドボード&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. 電子回路組み立て&lt;/strong>&lt;/h3>
回路は以下のようになります。今回はアナログ入力ピンを使ってます。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/cds.png">&lt;img class="alignnone size-medium wp-image-1046" src="https://blog.freedom-man.com/img/2014/07/cds-215x300.png" alt="cds" width="215" height="300" />&lt;/a>&lt;/p>
&lt;p>CdSセンサには光を当てると抵抗値が下がるという特徴があります。&lt;/p>
&lt;p>また、V = R * I のオームの法則から&lt;/p>
&lt;p>5(V) = (R1[CdSセンサの抵抗値:] + R2[右の抵抗値]) * I&lt;/p>
&lt;p>となります。&lt;/p>
&lt;p>CdSセンサの抵抗値によって電流値(I)が変わってきますが、全体としての電圧は5Vで固定です。&lt;/p>
&lt;p>アナログ入力値は R2 * I でR2の値は固定なので、電流の値が大きい＝全体の抵抗値が少ないということから&lt;/p>
&lt;p>センサに光を当てるとアナログ入力値が高くなり、光を当てないとアナログ入力値が低くなります。&lt;/p>
&lt;p>今回はこの電気を消した時、つまりアナログ値が低くなったタイミングでArduinoからPCにシリアル通信をします。&lt;/p>
&lt;p> &lt;/p>
&lt;p>実際につなぐとこんな感じ&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/arduino-cds.jpg">&lt;img class="alignnone size-medium wp-image-1054" src="https://blog.freedom-man.com/img/2014/07/arduino-cds-300x186.jpg" alt="arduino-cds" width="300" height="186" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. Arduinoにプログラムを書き込む&lt;/strong>&lt;/h3>
アナログ入力値を読み込んで、しきい値を越えたらシリアル通信をするだけのシンプルなプログラム。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">int&lt;/span> val &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">void&lt;/span> &lt;span style="color:#6639ba">setup&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">begin&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">9600&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">void&lt;/span> &lt;span style="color:#6639ba">loop&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> val &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">analogRead&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>val &lt;span style="color:#0550ae">&amp;lt;&lt;/span> &lt;span style="color:#0550ae">10&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>val&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">delay&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">5000&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">delay&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">10&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>ArduinoからChatter投稿してみる【Web proxy編】</title><link>https://blog.freedom-man.com/arduino-chatter-webproxy.html</link><pubDate>Tue, 01 Jul 2014 00:31:33 +0000</pubDate><guid>https://blog.freedom-man.com/arduino-chatter-webproxy.html</guid><description>&lt;p>今回は、&lt;a title="http://www.arduino.cc/" href="http://www.arduino.cc/" target="_blank">Arduino&lt;/a>使ってWebにデータ飛ばしてみます！&lt;/p>
&lt;p> &lt;/p>
&lt;p>ArduinoでWebにデータ飛ばす、となるとだいたい&lt;a title="http://www.fluentd.org/" href="http://www.fluentd.org/" target="_blank">fluentd&lt;/a>に投げて&lt;/p>
&lt;p>&lt;a title="http://elasticsearch.org/" href="http://elasticsearch.org/" target="_blank">elastic search&lt;/a>と&lt;a title="http://www.elasticsearch.org/overview/kibana/" href="http://www.elasticsearch.org/overview/kibana/" target="_blank">kibana&lt;/a>でビジュアライゼーションみたいな感じの構成を取ることが多いと思いますが&lt;/p>
&lt;p>今回はSalesforceに直接投げます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>直接投げると言っても、Arduino自体はSSLサポートしていないので&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Web経由でプロキシを介して通信をする&lt;/p>
&lt;/li>
&lt;li>
&lt;p>シリアル通信経由でArduinoと直接つないでいるPCから通信をする&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Arduino yunを使ってyunのLinux側のcurlで通信をする（ことが出来るらしい）&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>といった手段を取る必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は1の方法で”ボタンを押すとArduinoからChatterに投稿する”というモノを作ります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>参考サイト：&lt;/p>
&lt;p>&lt;a title="https://www.qoosky.net/references/99/" href="https://www.qoosky.net/references/99/" target="_blank"> Qoosky - 電子工作でインターネットに無線接続して通信を行う (Arduino)&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>0. 準備&lt;/strong>&lt;/h3>
必要な物は以下になります。
&lt;p>・Arduino Uno R3&lt;/p>
&lt;p>・&lt;a title="http://www.switch-science.com/catalog/838/" href="http://www.switch-science.com/catalog/838/" target="_blank">Ethernet Shield&lt;/a>&lt;/p>
&lt;p>・&lt;a title="http://www.planex.co.jp/product/router/mzk-rp150n/" href="http://www.planex.co.jp/product/router/mzk-rp150n/" target="_blank">ちびファイ（無線LANコンバータ）&lt;/a>&lt;/p>
&lt;p>・タクトスイッチ&lt;/p>
&lt;p>・ジャンプワイヤとか抵抗とかブレッドボード&lt;/p>
&lt;p> &lt;/p>
&lt;p>Arduino単体ではWebに飛ばせないのでEthenet Shieldを装着してください。&lt;/p>
&lt;p>ちびファイは無くてもOKですが、無いとLANケーブルをArduinoに繋げるハメになり&lt;/p>
&lt;p>配線がもどかしいので無線LANコンバータがあると非常に便利です。&lt;/p>
&lt;p>電子回路関連はArduinoのスターターキットを買うと一式まとめて買えるのでオススメ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. 回路等の組み立て&lt;/strong>&lt;/h3>
回路は以下のようになります。スイッチ押したら電気通るだけの超シンプル構造です。
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/07/arduino-fig.png">&lt;img class="alignnone size-medium wp-image-1042" src="https://blog.freedom-man.com/img/2014/07/arduino-fig-219x300.png" alt="arduino-fig" width="219" height="300" />&lt;/a>&lt;/p>
&lt;p>ちなみに、この図は&lt;a title="http://fritzing.org/home/" href="http://fritzing.org/home/" target="_blank">fritzing&lt;/a>を使ってます。回路図とか書くときは便利らしい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>実際はこんな感じになります。上のLANケーブルはちびファイに繋がってて、下はPCと繋がってます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/06/arduino.jpg">&lt;img class="alignnone size-medium wp-image-1035" src="https://blog.freedom-man.com/img/2014/06/arduino-300x169.jpg" alt="arduino-sample" width="300" height="169" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. Arduinoにプログラムを書き込む&lt;/strong>&lt;/h3>
Arduinoのマイコンボードに以下のプログラムを書き込みます。
&lt;p>スイッチ押すとWeb ProxyにGETリクエストが飛びます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c" data-lang="c">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#include&lt;/span> &lt;span style="color:#57606a">&amp;lt;SPI.h&amp;gt;&lt;/span>&lt;span style="color:#57606a">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#include&lt;/span> &lt;span style="color:#57606a">&amp;lt;Ethernet.h&amp;gt;&lt;/span>&lt;span style="color:#57606a">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">const&lt;/span> &lt;span style="color:#cf222e">int&lt;/span> BUTTON &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">7&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">int&lt;/span> val &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">int&lt;/span> old_val &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">//ethernetシールドのmacアドレス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>byte mac&lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>x&lt;span style="color:#0550ae">**&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>x&lt;span style="color:#0550ae">**&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>x&lt;span style="color:#0550ae">**&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0x0F&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0x8B&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0x8A&lt;/span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">//Web proxyのIPアドレス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>IPAddress &lt;span style="color:#6639ba">server&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">192&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">168&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>EthernetClient client&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">//http接続がclose状態であればtrue
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>boolean isClose &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">void&lt;/span> &lt;span style="color:#6639ba">setup&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">pinMode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>BUTTON&lt;span style="color:#1f2328">,&lt;/span> INPUT&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">begin&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">9600&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> &lt;span style="color:#57606a">//シリアル通信はデバッグ用
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> Ethernet&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">begin&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>mac&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">void&lt;/span> &lt;span style="color:#6639ba">loop&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> val &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">digitalRead&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>BUTTON&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>val &lt;span style="color:#0550ae">==&lt;/span> HIGH &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> old_val &lt;span style="color:#0550ae">!=&lt;/span> val &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> isClose&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">connect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>server&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">80&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;connect&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">sendHttpRequest&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">delay&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">10&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> old_val &lt;span style="color:#0550ae">=&lt;/span> val&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">available&lt;/span>&lt;span style="color:#1f2328">())&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">char&lt;/span> c &lt;span style="color:#0550ae">=&lt;/span> client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">read&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>c&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">// if the server&amp;#39;s disconnected, stop the client:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">!&lt;/span>client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">connected&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#0550ae">!&lt;/span>isClose&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Serial&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;disconnecting.&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">stop&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> isClose &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">//Web Proxyにデータを送信
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">void&lt;/span> &lt;span style="color:#6639ba">sendHttpRequest&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> isClose &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">false&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;GET /salesforce/arduino-proxy.php HTTP/1.1&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Host: 192.168.1.2&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Connection: close&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#6639ba">println&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Google Apps ScriptからSalesforceのAPIを叩いてみる。【色々イジる編】</title><link>https://blog.freedom-man.com/google-apps-script-salesforce-sample.html</link><pubDate>Sat, 21 Jun 2014 18:32:18 +0000</pubDate><guid>https://blog.freedom-man.com/google-apps-script-salesforce-sample.html</guid><description>&lt;p>&lt;a title="Google Apps ScriptからSalesforceのAPIを叩いてみる。【access_token取得まで】" href="https://blog.freedom-man.com/google-apps-script-salesforce/" target="_blank">前回&lt;/a>はGoogleAppsScriptを使ってSalesforceのaccess_token取得まで行いました。&lt;/p>
&lt;p>今回は実際にレコード取得してセルに入れたり、データを更新したり&lt;/p>
&lt;p>MetadataAPI使ってカスタムオブジェクト作っちゃったりと色々とやってみます！&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. レコード取得してデータを格納&lt;/strong>&lt;/h3>
コードはこんな感じ。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * クエリ発行してスプレッドシートに書き込み
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">query&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">q&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">checkAuthorization&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//クエリ発行
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">prop&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">PropertiesService&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getUserProperties&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">sessionInfo&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">JSON&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">prop&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getProperty&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;session_info&amp;#34;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">UrlFetchApp&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">fetch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">sessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">instance_url&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/services/data/v30.0/query/?q=&amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">q&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;method&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;GET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;headers&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;Authorization&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Bearer &amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">sessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">access_token&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//レスポンスをパースして変数に格納
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">queryResult&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">JSON&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getContentText&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">fieldsArray&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">getFieldsFromQueryResult&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">queryResult&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">records&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">fieldsArray&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">queryResult&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forEach&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">record&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">pushRecord&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">[];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fieldsArray&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forEach&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">field&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">pushRecord&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">record&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">field&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">push&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">pushRecord&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//シートに書きこみ 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">sheet&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">SpreadsheetApp&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getActiveSpreadsheet&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">getActiveSheet&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">range&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">SpreadsheetApp&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getActiveRange&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">sheet&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getRange&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">range&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getRow&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#1f2328">range&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getColumn&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span> &lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">fieldsArray&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">setValues&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * QueryResultから項目リストを取得
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">getFieldsFromQueryResult&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">qr&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">fields&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">Object&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keys&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">qr&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">records&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">]);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fields&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forEach&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">field&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">i&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">field&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#34;attributes&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fields&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">splice&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">i&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">fields&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * 認証状態を確認し、access_tokenの有効期限が切れていたら
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * refresh_tokenでaccess_tokenを再取得する。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">checkAuthorization&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">prop&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">PropertiesService&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getUserProperties&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">sessionInfo&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">JSON&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">prop&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getProperty&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;session_info&amp;#34;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">UrlFetchApp&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">fetch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">sessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">instance_url&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/services/data/v30.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;method&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;GET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;headers&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;Authorization&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Bearer &amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">sessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">access_token&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;muteHttpExceptions&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getResponseCode&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0550ae">401&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">UrlFetchApp&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">fetch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">ACCESS_TOKEN_URL&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;method&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;POST&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;payload&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;grant_type&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;refresh_token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_id&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">CLIENT_ID&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_secret&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">CLIENT_SECRET&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;refresh_token&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">sessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">refresh_token&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;muteHttpExceptions&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getResponseCode&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0550ae">200&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">newSessionInfo&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">JSON&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parse&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getContentText&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">newSessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">refresh_token&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">sessionInfo&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">refresh_token&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">prop&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setProperty&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;session_info&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getContentText&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>UserPropertyの&amp;quot;session_info&amp;quot;にはaccess_token等を格納しています。&lt;/p></description></item><item><title>Google Apps ScriptからSalesforceのAPIを叩く【access_token取得まで】</title><link>https://blog.freedom-man.com/google-apps-script-salesforce.html</link><pubDate>Fri, 13 Jun 2014 00:19:36 +0000</pubDate><guid>https://blog.freedom-man.com/google-apps-script-salesforce.html</guid><description>&lt;p>&lt;a title="VBAからSalesforceのAPI叩いてみる。" href="https://blog.freedom-man.com/vba-salesforce-api/" target="_blank">前回&lt;/a>はVBAでSalesforceの環境を弄りましたが、VBAだとローカル環境なスクリプト言語なので、操作性やパフォーマンスの良さ等のネイティブな良さを活かせる一方で、ネットに繋がっている環境でいつでも、どこでも、どんな端末でも動かしたいという要件は満たせません。&lt;/p>
&lt;p>そんなときにはGoggle Apps Scriptが便利です。&lt;a title="Google Apps Script" href="https://developers.google.com/apps-script/?hl=ja" target="_blank">Google Apps Script&lt;/a>はGoogleのサービスを拡張できたり、Webサービス作れたりするPaaSなスクリプト言語になります。&lt;/p></description></item><item><title>VBAからSalesforceのAPI叩いてみる。</title><link>https://blog.freedom-man.com/vba-salesforce-api.html</link><pubDate>Sat, 24 May 2014 18:54:40 +0000</pubDate><guid>https://blog.freedom-man.com/vba-salesforce-api.html</guid><description>&lt;p>Salesforceの導入支援とかしてると、VBAを使ってSalesforceのAPIを叩きたくなることは多々あります。&lt;/p>
&lt;ul>
 &lt;li>Excelでちょっとデータ加工してExcelから直でデータインポートしたいんだよなー、とか&lt;/li>
 &lt;li>Excelで作ったオブジェクト定義書からSalesforceにオブジェクト作りたいんだよなー、とか&lt;/li>
 &lt;li>ちょっとデータ見たいんだけど、データローダ使ってCSVインポートして…てやってられるか！とか&lt;/li>
 &lt;li>プロトタイプでガーってオブジェクト作ったけどオブジェクト定義書作ってない！Salesforceから一気に定義書作れたら良いのに！とか&lt;/li>
&lt;/ul></description></item><item><title>fiddler使ってSOAPとお友達になる。</title><link>https://blog.freedom-man.com/soap-fiddler.html</link><pubDate>Wed, 21 May 2014 23:46:00 +0000</pubDate><guid>https://blog.freedom-man.com/soap-fiddler.html</guid><description>&lt;p>時代はRESTですがSalesforceはSOAPでメタデータとか弄ったりするんで、&lt;/p>
&lt;p>作成したいモノによってはSOAPとお友達にならないといけません。&lt;/p>
&lt;p> &lt;/p>
&lt;p>がしかし&lt;/p>
&lt;p>「SOAPってHTTPでXMLやりとりして、仕様拡張出来たりするやつっしょ？」&lt;/p>
&lt;p>「C#でWebサービス参照して追加すると勝手にクラスとか追加されて簡単に使えるやつだよね？」&lt;/p>
&lt;p>程度の理解であるSOAPレベル1のスライムな私としてはお友達になるまでちょっと時間がかかりそうなので&lt;/p>
&lt;p>fiddlerというHTTP通信を監視できる&lt;del>ストーキング&lt;/del>スーパープログラムを使って&lt;/p>
&lt;p>SOAPメッセージを見てみることにしましたとさ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はSalesforceのMetadataAPIのSOAPメッセージを見てみました。&lt;/p>
&lt;h3>&lt;strong>1. fiddlerのインストール&lt;/strong>&lt;/h3>
&lt;a title="http://www.telerik.com/download/fiddler" href="http://www.telerik.com/download/fiddler">ここ&lt;/a>からダウンロードして、インストール。
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. C#とか使って提供されているWSDLからスタブクラスを作成&lt;/strong>&lt;/h3>
C#の場合は以下のようにしてWebサービス参照を追加してスタブクラスを作成します。
&lt;p> &lt;/p>
&lt;p>2-1. ソリューションエクスプローラーの参照設定を右クリックして[サービス参照の追加]をクリック&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/05/CSharp-ref.jpg">&lt;img class="alignnone size-medium wp-image-979" src="https://blog.freedom-man.com/img/2014/05/CSharp-ref-300x201.jpg" alt="CSharp-ref" width="300" height="201" />&lt;/a>&lt;/p>
&lt;p>2-2. 詳細設定をクリック&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/05/CSharp-ref2.jpg">&lt;img class="alignnone size-medium wp-image-978" src="https://blog.freedom-man.com/img/2014/05/CSharp-ref2-300x287.jpg" alt="CSharp-ref2" width="300" height="287" />&lt;/a>&lt;/p>
&lt;p>2-3. [Web参照の追加]をクリック&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/05/CSharp-ref3.jpg">&lt;img class="alignnone size-medium wp-image-977" src="https://blog.freedom-man.com/img/2014/05/CSharp-ref3-272x300.jpg" alt="CSharp-ref3" width="272" height="300" />&lt;/a>&lt;/p>
&lt;p>2-4. URLにWSDLファイルが置いてある場所を指定してWeb参照名を入力後、[参照の追加]をクリック&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/05/CSharp-ref4.jpg">&lt;img class="alignnone size-medium wp-image-976" src="https://blog.freedom-man.com/img/2014/05/CSharp-ref4-300x248.jpg" alt="CSharp-ref4" width="300" height="248" />&lt;/a>&lt;/p>
&lt;p>これでWSDLからのスタブ作成は完了。&lt;/p>
&lt;p> &lt;/p>
&lt;p>実際にC#で使う場合はこんな感じ(partner.wsdlもインポート済み)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-c#" data-lang="c#">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Program&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">//カスタムオブジェクトをCRUDで作成するサンプル&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">static&lt;/span> &lt;span style="color:#cf222e">void&lt;/span> Main&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">string&lt;/span>&lt;span style="color:#1f2328">[]&lt;/span> args&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Partner&lt;span style="color:#1f2328">.&lt;/span>SforceService service &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> Partner&lt;span style="color:#1f2328">.&lt;/span>SforceService&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Partner&lt;span style="color:#1f2328">.&lt;/span>LoginResult lr &lt;span style="color:#1f2328">=&lt;/span> service&lt;span style="color:#1f2328">.&lt;/span>login&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;input your name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;input your password&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service&lt;span style="color:#1f2328">.&lt;/span>Url &lt;span style="color:#1f2328">=&lt;/span> lr&lt;span style="color:#1f2328">.&lt;/span>serverUrl&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service&lt;span style="color:#1f2328">.&lt;/span>SessionHeaderValue &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> Partner&lt;span style="color:#1f2328">.&lt;/span>SessionHeader&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> service&lt;span style="color:#1f2328">.&lt;/span>SessionHeaderValue&lt;span style="color:#1f2328">.&lt;/span>sessionId &lt;span style="color:#1f2328">=&lt;/span> lr&lt;span style="color:#1f2328">.&lt;/span>sessionId&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Metadata&lt;span style="color:#1f2328">.&lt;/span>MetadataService meta_service &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>MetadataService&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> meta_service&lt;span style="color:#1f2328">.&lt;/span>Url &lt;span style="color:#1f2328">=&lt;/span> lr&lt;span style="color:#1f2328">.&lt;/span>metadataServerUrl&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> meta_service&lt;span style="color:#1f2328">.&lt;/span>SessionHeaderValue &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>SessionHeader&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> meta_service&lt;span style="color:#1f2328">.&lt;/span>SessionHeaderValue&lt;span style="color:#1f2328">.&lt;/span>sessionId &lt;span style="color:#1f2328">=&lt;/span> lr&lt;span style="color:#1f2328">.&lt;/span>sessionId&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CustomObject co &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> CustomObject&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>deploymentStatus &lt;span style="color:#1f2328">=&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>DeploymentStatus&lt;span style="color:#1f2328">.&lt;/span>Deployed&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>deploymentStatusSpecified &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>description &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;このオブジェクトはC#から作ってます&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>fullName &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;CSH__c&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>label &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;DotNet Custom Object&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>pluralLabel &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;DotNet Custom Objects&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>sharingModel &lt;span style="color:#1f2328">=&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>SharingModel&lt;span style="color:#1f2328">.&lt;/span>ReadWrite&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>sharingModelSpecified &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>nameField &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>CustomField&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>nameField&lt;span style="color:#1f2328">.&lt;/span>type &lt;span style="color:#1f2328">=&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>FieldType&lt;span style="color:#1f2328">.&lt;/span>Text&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>nameField&lt;span style="color:#1f2328">.&lt;/span>label &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;The Name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>nameField&lt;span style="color:#1f2328">.&lt;/span>length &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#0550ae">100&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> co&lt;span style="color:#1f2328">.&lt;/span>nameField&lt;span style="color:#1f2328">.&lt;/span>lengthSpecified &lt;span style="color:#1f2328">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> meta_service&lt;span style="color:#1f2328">.&lt;/span>create&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span> Metadata&lt;span style="color:#1f2328">.&lt;/span>Metadata&lt;span style="color:#1f2328">[]&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> co &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>elasticsearchに閲覧履歴を入力するchrome extension作ってみた。</title><link>https://blog.freedom-man.com/elasticsearch-chrome-extension.html</link><pubDate>Sun, 11 May 2014 20:35:56 +0000</pubDate><guid>https://blog.freedom-man.com/elasticsearch-chrome-extension.html</guid><description>&lt;p>記事にしたのは良いもののの&lt;a title="http://www.elasticsearch.org/" href="http://www.elasticsearch.org/" target="_blank">elasticsearch&lt;/a>+&lt;a title="http://www.elasticsearch.org/overview/kibana/" href="http://www.elasticsearch.org/overview/kibana/" target="_blank">kibana&lt;/a>の使い方がイマイチわかんないですが&lt;/p>
&lt;p>今回はWebの閲覧履歴をelasticsearchに送るようなchrome extensionを作ってみました！&lt;/p>
&lt;p>これで、自分のWeb閲覧履歴を分析できるぜ！（目的は謎）&lt;/p>
&lt;p> &lt;/p>
&lt;p>chrome extensionは一年前に&lt;a title="http://dotinstall.com/lessons/basic_chrome_v2" href="http://dotinstall.com/lessons/basic_chrome_v2" target="_blank">ドットインストール&lt;/a>で勉強したくらいのスーパー初心者っす。&lt;/p>
&lt;p>ということで、開発物を&lt;a title="https://github.com/tzmfreedom/chrome-ex_elasticsearch" href="https://github.com/tzmfreedom/chrome-ex_elasticsearch" target="_blank">github&lt;/a>にアップしてみました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>extensionのリファレンスは&lt;a title="https://developer.chrome.com/extensions" href="https://developer.chrome.com/extensions" target="_blank">こちらから&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>以下はchrome extensionの備忘録。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. chrome extensionのファイル構成&lt;/strong>&lt;/h3>
●　manifest.json　→　chrome extensionのメタデータファイル
&lt;p>●　jquery.min.js　→　みんな大好きjQuery。DOMとかajaxで使ってます。&lt;/p>
&lt;p>●　background.html →　chrome extensionをインストールするとbackground pageが裏で動くという&lt;/p>
&lt;p>構成になっていて、主にイベントハンドラとして利用するらしい。&lt;/p>
&lt;p>●　background.js　→　background.htmlで利用するjsファイル。&lt;/p>
&lt;p>本当はhtmlファイルにベタ書きしたかったんだけどscriptファイルは別ファイルにしないといけない決まりがあるらしいっす。&lt;/p>
&lt;p>●　options.html　→　設定画面用のhtmlファイル&lt;/p>
&lt;p>●　options.js　→　options.htmlで利用するjsファイル。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. manifest.jsonについて&lt;/strong>&lt;/h3>
chrome extensionの名前とか説明とかbackgroundページのhtmlやoptionページのhtmlを指定するファイル。
&lt;p>extensionが扱うAPIのパーミッションもここで指定する。&lt;/p>
&lt;p>XMLHttpRequestでCrossOriginに対して通信を行う場合は&amp;quot;https://&lt;em>/&lt;/em>&amp;ldquo;とかの形式で権限を与える必要がある。&lt;/p>
&lt;p>今回は以下のようなmanifest.jsonを作成。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;chrome client for elasticsearch&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;version&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;manifest_version&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;description&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;elasticesearchに履歴データを突っ込むんで自分のWeb閲覧履歴を解析するchrome extension&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;background&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;page&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;background.html&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;options_page&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;options.html&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;permissions&amp;#34;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;*://*/*&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;history&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;webRequest&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;storage&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;notifications&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Web閲覧履歴はhistory、XMLHttpRequestはwebRequest、localstorageはstorage&lt;/p></description></item><item><title>elasticsearch+kibanaでSFDCのアクセスログ取ってみる。</title><link>https://blog.freedom-man.com/fluentd-elasticsearch-kibana-sfdc.html</link><pubDate>Thu, 08 May 2014 22:39:22 +0000</pubDate><guid>https://blog.freedom-man.com/fluentd-elasticsearch-kibana-sfdc.html</guid><description>&lt;p>&lt;a title="http://fluentd.org/" href="http://fluentd.org/">fluentd&lt;/a>+&lt;a title="http://www.elasticsearch.org/" href="http://www.elasticsearch.org/">elasticsearch&lt;/a>+&lt;a title="http://www.elasticsearch.org/overview/kibana/" href="http://www.elasticsearch.org/overview/kibana/">kibana&lt;/a>の構成でログ解析をすることが流行っているらしい！&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、今回はSFDCの画面からアクセスログを取ってelasticsearch+kibanaで&lt;/p>
&lt;p>ビジュアライゼーション＆解析するっていうことをやってみました。&lt;/p>
&lt;p>（個人的に一般ユーザのアクセスログだけじゃなく、管理する側のアクセスログとか取って解析して&lt;/p>
&lt;p>何か面白いもの見れないかなーなんて思ってます。）&lt;/p>
&lt;p> &lt;/p>
&lt;p>流れとしては&lt;/p>
&lt;p>SFDCからelasticsearchにデータを登録する&lt;/p>
&lt;p>→elasticsearchのデータをkibanaで見る&lt;/p>
&lt;p>って感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>elasticsearchとkibanaのインストール・セットアップ方法に関しては以下を参照ください！&lt;/p>
&lt;p>&lt;a title="fluentd + Elasticsearch + Kibanaで始めるログ解析 (セットアップ編)" href="http://blog.excale.net/index.php/archives/1929" target="_blank">fluentd + Elasticsearch + Kibanaで始めるログ解析 (セットアップ編)&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>0. SFDCからデータ登録をする際の方針&lt;/strong>&lt;/h3>
SFDCのお知らせ等のサイドバーコンポーネントにデータ登録用のスクリプトか何かを
&lt;p>埋め込むという方式で行いますが、方法としては&lt;/p>
&lt;p> &lt;/p>
&lt;p>a. お知らせにJavaScriptを埋め込んでajaxでelasticsearchにデータを飛ばす&lt;/p>
&lt;p>b. お知らせに埋め込んだJavaScriptでVFを呼び出すscriptタグあるいはiframeタグを動的に生成して、&lt;/p>
&lt;p>そのVFページ(Apex)からelasticsearchに対してコールアウトする。&lt;/p>
&lt;p> &lt;/p>
&lt;p>の2パターンがありそうですが、aはCORSの対応が必要が面倒そう（っていうかハマった…orz）なので&lt;/p>
&lt;p>今回はbのApexからコールアウトする方式で！&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. Visualforceページ + Apexクラスの作成&lt;/strong>&lt;/h3>
こんな感じで
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f6f8fa;background-color:#82071e">#&lt;/span>LoggerES&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">cls&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">LoggerES&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">LoggerES&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>ApexPages&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">currentPage&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">getParameters&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>JSON&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">serialize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>user&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>UserInfo&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getUserId&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>url&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>url&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ref&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ref&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">});&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>application&lt;span style="color:#0550ae">/&lt;/span>json&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>charset&lt;span style="color:#0550ae">=&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Length&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jsonBody&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>http&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//{domain}:9200/sfdc/access_log&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jsonBody&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>System&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Bitbucket + JenkinsでSalesforceのCI</title><link>https://blog.freedom-man.com/bitbucket-jenkins-salesforce.html</link><pubDate>Tue, 29 Apr 2014 20:16:30 +0000</pubDate><guid>https://blog.freedom-man.com/bitbucket-jenkins-salesforce.html</guid><description>&lt;p>&lt;a title="Jenkinsを使ってSalesforceのCIにトライ" href="https://blog.freedom-man.com/jenkins-salesforce-ci/" target="_blank">前回&lt;/a>はJenkinsで手動デプロイをするところまでやったので、今回は&lt;a title="BitbucketでGitとMercurialの無料ソースコードホスティングを" href="https://bitbucket.org/" target="_blank">bitbucket&lt;/a>と連携させてみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>仕組みとしては&lt;/p>
&lt;p>bitbucketにコミット&lt;/p>
&lt;p>→コミットをトリガとしてhook(HTTP POST)が起動し、jenkinsに通知する。&lt;/p>
&lt;p>→jenkinsは通知されたタイミングでbitbucketからデータを取得して、取得したデータでantを走らせる。&lt;/p>
&lt;p>って感じです。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. Jenkinsにgitのプラグインをインストール&lt;/strong>&lt;/h3>
Jenkinsの管理＞プラグインの管理　から&lt;a title="Git Plugin - Jenkins - Jenkins Wiki" href="https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin" target="_blank">GIT plugin&lt;/a>をインストール。
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. jenkinsユーザのssh設定&lt;/strong>&lt;/h3>
まずjenkinsユーザでsshキーを作成します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ su - jenkins
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ ssh-keygen
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>生成された公開鍵(${JENKINS_HOME}/.ssh/id_rsa.pub)をbitbucketに設定します。&lt;/p>
&lt;p> &lt;/p>
&lt;p>初回はknown_hostsにbitbucketが登録されていないので&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ git ls-remote -h git@bitbucket.org:&lt;span style="color:#0550ae">{&lt;/span>bitbucket_user&lt;span style="color:#0550ae">}&lt;/span>/&lt;span style="color:#0550ae">{&lt;/span>bitbucket-repository&lt;span style="color:#0550ae">}&lt;/span>.git
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>とかで登録しておきます。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. 新しいJobを作成&lt;/strong>&lt;/h3>
ソースコード管理にbitbucketのリポジトリを設定
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-git.jpg">&lt;img class="alignnone size-medium wp-image-952" src="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-git-300x189.jpg" alt="sf-bitbucket-git" width="300" height="189" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ビルド・トリガはSCMポーリング。スケジュールは空白で。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-build-trigger.jpg">&lt;img class="alignnone size-medium wp-image-945" src="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-build-trigger-300x99.jpg" alt="sf-bitbucket-build-trigger" width="300" height="99" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>bitbucketにID/Passwordを保持したくなかったので&lt;/p>
&lt;p>適当なディレクトリにbuild.xmlとbuild.propertiesを入れる。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-build.jpg">&lt;img class="alignnone size-medium wp-image-948" src="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-build-300x97.jpg" alt="sf-bitbucket-build" width="300" height="97" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>あとは同じ&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-afterbuild.jpg">&lt;img class="alignnone size-medium wp-image-947" src="https://blog.freedom-man.com/img/2014/04/sf-bitbucket-afterbuild-300x151.jpg" alt="sf-bitbucket-afterbuild" width="300" height="151" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>4. antの設定ファイルを編集&lt;/strong>&lt;/h3>
今回はbuild.xmlやbuild.propertiesが別の場所にあるので相対パスは使ってません。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span># /home/jenkins/build_properties/build.xml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;project&lt;/span> &lt;span style="color:#1f2328">name=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Sample usage of Salesforce-CI Ant tasks&amp;#34;&lt;/span> &lt;span style="color:#1f2328">default=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;deployForCI&amp;#34;&lt;/span> &lt;span style="color:#1f2328">basedir=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span> &lt;span style="color:#1f2328">xmlns:sfc=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;antlib:com.yutagithub.sforce.ci&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;property&lt;/span> &lt;span style="color:#1f2328">file=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;build.properties&amp;#34;&lt;/span> &lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;property&lt;/span> &lt;span style="color:#1f2328">environment=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;env&amp;#34;&lt;/span> &lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">&amp;lt;!-- Build / TestResult never actually saves to the server --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;target&lt;/span> &lt;span style="color:#1f2328">name=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;deployForCI&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;sfc:deployForCI&lt;/span> &lt;span style="color:#1f2328">username=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;${sf.username}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">password=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;${sf.password}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">serverurl=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;${sf.serverurl}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">deployRoot=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/var/lib/jenkins/workspace/${sf.workspace}/src&amp;#34;&lt;/span> &lt;span style="color:#1f2328">sobjectPlural=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#1f2328">checkOnly=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#1f2328">testResultFile=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/var/lib/jenkins/workspace/${sf.workspace}/test-result.xml&amp;#34;&lt;/span> &lt;span style="color:#1f2328">coverageResultFile=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/var/lib/jenkins/workspace/${sf.workspace}/coverage.xml&amp;#34;&lt;/span>&lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/target&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;/project&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Jenkinsを使ってSalesforceのCIにトライ</title><link>https://blog.freedom-man.com/jenkins-salesforce-ci.html</link><pubDate>Tue, 29 Apr 2014 14:57:23 +0000</pubDate><guid>https://blog.freedom-man.com/jenkins-salesforce-ci.html</guid><description>&lt;p>今更感がありますが、&lt;a title="jenkins" href="http://jenkins-ci.org/" target="_blank">Jenkins&lt;/a>でSalesforceの&lt;a title="継続的インテグレーション" href="http://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3" target="_blank">CI&lt;/a>にチャレンジ！&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回は手動デプロイ実行と、カバレッジ/テスト結果表示まで。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. JenkinsやWebサーバ、antのインストール&lt;/strong>&lt;/h3>
まずはここから。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ apt-get update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ apt-get install jenkins nginx ant
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. nginxの設定変更&lt;/strong>&lt;/h3>
/etc/nginx/sites-enabled/default　を以下のように編集して
&lt;p>Basic認証とJenkinsへのリバースプロキシを設定します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>server {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> listen 80 default_server;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> listen [::]:80 default_server ipv6only=on;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> root /usr/share/nginx/html;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index index.html index.htm;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> server_name *****;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> location / {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> auth_basic_user_file /etc/nginx/.htpasswd;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> auth_basic &amp;#34;jenkins server&amp;#34;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> proxy_pass http://localhost:8080;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> proxy_set_header Authorization &amp;#34;&amp;#34;;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>※ここでは非SSLの設定ですが、Basic認証使っているので絶対にSSLにした方が良いです。&lt;/p>
&lt;p>→参考URL：&lt;a title="JenkinsサーバのSSL対応とBasic認証" href="http://dev.classmethod.jp/tool/jenkins/jenkins_ssl_and_basic_auth/" target="_blank">JenkinsサーバのSSL対応とBasic認証&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>htpasswdの設定も忘れずに&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ apt-get install apache2-utils
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ htpasswd -c /etc/nginx/.htpasswd jenkinsuser
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>DockerのPrivateなリポジトリをs3に作る</title><link>https://blog.freedom-man.com/docker-private-s3.html</link><pubDate>Sat, 26 Apr 2014 18:50:41 +0000</pubDate><guid>https://blog.freedom-man.com/docker-private-s3.html</guid><description>&lt;p>Dockerは&lt;a title="Docker Index" href="https://index.docker.io/">&lt;a href="https://index.docker.io/">https://index.docker.io/&lt;/a>&lt;/a>にPublicなリポジトリを持てるんだけど&lt;/p>
&lt;p>&lt;a title="dotcloud docker-registry" href="https://github.com/dotcloud/docker-registry">docker-registry&lt;/a>っていうのをdockerイメージを使えば&lt;/p>
&lt;p>Privateなリポジトリを超簡単に持てる＆S3に永続保持できるらしいので試してみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Publicなところに、AWSのClientIDとかSecretKeyとかうっかり保存しそうな私みたいな人には超オススメ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>やりかたは超簡単でregistry立ててpushするだけ！&lt;/p>
&lt;h3>&lt;strong>1. docker-registryをpullしてコンテナー化&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ docker pull registry
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ docker run -i -t registry /bin/bash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>registryもdockerで提供されているっていう。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. registryのconfigファイル設定&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> /docker-registry/config
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ mv config.yml config.yml.original
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ cp config_s3.yml config.yml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ vim config.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>config.ymlはこんな感じで。(S3の例)&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>prod:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> storage: s3
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> boto_bucket: test-docker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s3_access_key: AKI*************
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s3_secret_key: ****************************
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s3_bucket: test-docker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s3_encrypt: true
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> s3_secure: true
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> secret_key: xxxxx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> storage_path: /images
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>サンプルは何故かs3_encryptとs3_secureが2つずつあったので&lt;/p>
&lt;p>1つずつ削除しました。（ちゃんと動いているので多分OKだと思います。）&lt;/p>
&lt;p>storage_pathは実際にS3に格納される時のサブディレクトリを指定します。&lt;/p></description></item><item><title>force.com Sitesにリバースプロキシを挟んで独自ドメインSSL対応させてみる。</title><link>https://blog.freedom-man.com/forcecom-sites-ssl.html</link><pubDate>Mon, 21 Apr 2014 00:13:17 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom-sites-ssl.html</guid><description>&lt;p>force.com Sitesでは非SSLにおいて独自ドメインを設定できますが、SSLにおいては独自ドメインを適用できません。&lt;/p>
&lt;p>force.com Sitesはポータル系のログイン画面やフォーム画面等で利用されることが多く&lt;/p>
&lt;p>企業によっては「ドメインにforce.comとか入ってるのはダメ！」とか言われちゃったりします。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これ、リバースプロキシで出来るんじゃね？ということでちょっとやってみることに。&lt;/p>
&lt;p> &lt;/p>
&lt;p>方法は簡単で、適当なWebサーバを用意してリバースプロキシの設定をするだけ。&lt;/p>
&lt;p>以下はnginxの設定例&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>server {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> listen 443;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> server_name *******.com; #独自ドメイン
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl on;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_certificate server.crt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_certificate_key server.key;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_session_timeout 5m;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_protocols SSLv3 TLSv1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_prefer_server_ciphers on;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> location / {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> proxy_pass https://****-developer-edition.na7.force.com/; #SitesのベースURL
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>あとは設定したドメインにアクセスするだけ！&lt;/p>
&lt;p>今回試したVFページ＋Apexはこんな感じ&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:page&lt;/span> &lt;span style="color:#1f2328">controller&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SitesTestPage&amp;#34;&lt;/span> &lt;span style="color:#1f2328">showHeader&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">send&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">Visualforce&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">remoting&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Manager&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">invokeAction&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;{!$RemoteAction.SitesTestPage.sendRA}&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">escape&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:outputText&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!display}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;display&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span> &lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;送信！&amp;#34;&lt;/span> &lt;span style="color:#1f2328">action&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!send}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&amp;lt;&lt;/span>&lt;span style="color:#0550ae">br&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;送信！(ajax)&amp;#34;&lt;/span> &lt;span style="color:#1f2328">action&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!send}&amp;#34;&lt;/span> &lt;span style="color:#1f2328">reRender&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;display&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&amp;lt;&lt;/span>&lt;span style="color:#0550ae">br&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> username:&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:inputText&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!username}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&amp;lt;&lt;/span>&lt;span style="color:#0550ae">br&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> password:&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:inputSecret&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!password}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&amp;lt;&lt;/span>&lt;span style="color:#0550ae">br&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;login&amp;#34;&lt;/span> &lt;span style="color:#1f2328">action&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!login}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:page&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>GoInstant触ってみる【ACL編】</title><link>https://blog.freedom-man.com/goinstant-acl.html</link><pubDate>Sun, 20 Apr 2014 23:00:54 +0000</pubDate><guid>https://blog.freedom-man.com/goinstant-acl.html</guid><description>&lt;p>これまで、GoInstantのデータの取り扱いについて説明してきましたが、実際のアプリケーションでは&lt;/p>
&lt;p>”このルームにはこのユーザしか入れない”とか&lt;/p>
&lt;p>”この時間になったら、このルームへの入出を許そう”とか&lt;/p>
&lt;p>”このデータを取得できるのはadminユーザだけ”とか&lt;/p>
&lt;p>そういったアクセスコントロール要件が出てきます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>もちろんこういったアクセスコントロールにもGoInstantは対応しています。&lt;/p>
&lt;p>ということで、今回はACLについて。&lt;/p>
&lt;p> &lt;/p>
&lt;p>基本的にGoInstantではAccess Controlという&lt;a title="Creating &amp; Managing ACLs" href="https://developers.goinstant.com/beta/security_and_auth/guides/creating_and_managing_acl.html" target="_blank">JSONの設定&lt;/a>とユーザの&lt;a title="Users &amp; Authentication" href="https://developers.goinstant.com/beta/security_and_auth/guides/users_and_authentication.html" target="_blank">JWT&lt;/a>（ユーザ名とかグループ名）によって&lt;/p>
&lt;p>制御することができます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>例えば、RoomにJoinできるユーザを絞り込みたいときは&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;$room&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;#join&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;localhost:tzm%40freedom-man.com&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]&lt;/span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>　&lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こんな感じにやると、localhostで発行されたtzm@freedom-man.comっていうユーザがJoinできる設定になります。&lt;/p>
&lt;p>（@を%40にしないとエラーになったので、ちゃんとURLエンコードしないとダメみたい…。）&lt;/p>
&lt;p> &lt;/p>
&lt;p>グループだとこんな感じ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;$room&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;#join&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#34;groups&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;freedom-man&amp;#34;&lt;/span>&lt;span style="color:#1f2328">]},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>freedom-manっていうグループに属するユーザはJoinできるっていう設定になります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>一つ一つ特定のユーザ名やグループ名を設定するのは正直しんどいので、&lt;/p>
&lt;p>ルームの名前が付いたグループとかユーザ名を一括で許可する設定ができます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;$room&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;#join&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;groups&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;$room-grp&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こうすると、ルームの名前 + &amp;ldquo;-grp&amp;quot;の名前（lobbyだったら&amp;quot;lobby-grp&amp;rdquo;）のグループに対して&lt;/p>
&lt;p>一括でJoinの権限を付与することができます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>あるキーの読み取りを制限したい場合は以下のように書きます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;$room&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;test&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;#get&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;localhost:tzm%40freedom-man.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これで、localhostから発行されたtzm@freedom-man.comユーザのみtestキーの値を取得することが出来ます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>onメソッドのイベントも制御することができます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;$room&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;test&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;#onSet&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;users&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;localhost:tzm%40freedom-man.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こうすると、on(&amp;ldquo;set&amp;rdquo;, &amp;hellip; と記述してもlocalhost:tzm@freedom-man.comユーザ以外では&lt;/p></description></item><item><title>GoInstant触ってみる【CollectionとDataLifeCycle】</title><link>https://blog.freedom-man.com/goinstant-collection-datalifecycle.html</link><pubDate>Fri, 18 Apr 2014 00:56:09 +0000</pubDate><guid>https://blog.freedom-man.com/goinstant-collection-datalifecycle.html</guid><description>&lt;p>今回はGoInstantのCollectionとDataLifeCycleについて！&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>Collection&lt;/strong>&lt;/h3>
GoInstantはJSONのキーバリューを動的に増やしていくような機能(add)を持ってます。
&lt;p>サンプル↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">goinstant&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">connect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">room&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rooms&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;added data!!&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/addcollection.jpg">&lt;img class="alignnone size-medium wp-image-895" alt="addcollection" src="https://blog.freedom-man.com/img/2014/04/addcollection-300x148.jpg" width="300" height="148" />
&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>見ての通り、key値が自動的に生成されて、そのkeyに対して指定した値がセットされます。&lt;/p>
&lt;p>addを繰り返すと、こんな感じに増えていきます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/addcollection2.jpg">&lt;img class="alignnone size-medium wp-image-896" alt="addcollection2" src="https://blog.freedom-man.com/img/2014/04/addcollection2-300x78.jpg" width="300" height="78" />
&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>&amp;lsquo;/test/xxxx&amp;rsquo;っていう重複しないキーに対して値をセットすれば同様の挙動を得られますが、&lt;/p>
&lt;p>自動的に重複しないキーを生成したい場合はaddを利用することになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>※配列やオブジェクトの型を持つ値に対して&lt;/p>
&lt;p>読み込み(get)→読み込んだデータに値を追加→書き込み(set)&lt;/p>
&lt;p>というフローでもいけそうですが、トランザクションを考えると排他制御をかけないといけないし&lt;/p>
&lt;p>排他制御をしたところで、リアルタイムなコミュニケーションはできなくなるので、この方法はダメ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>Data Life Cycle&lt;/strong>&lt;/h3>
GoInstantではデータの有効期限を設定することが出来ます。
&lt;p>以下のコードはセットしたデータが3秒後に削除されるサンプルです。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">goinstant&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">connect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">room&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rooms&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;remove&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#1f2328">expire&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0550ae">3000&lt;/span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/expiredata.jpg">&lt;img class="alignnone size-medium wp-image-897" alt="expiredata" src="https://blog.freedom-man.com/img/2014/04/expiredata-300x101.jpg" width="300" height="101" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみにここで設定するexpireは、GoInstant上で保存されたタイミングから起算するため、&lt;/p>
&lt;p>JavaScriptで設定してGoInstantサーバにデータが保存されるレイテンシを考えると&lt;/p>
&lt;p>多少の誤差があります。（といっても秒レベル）&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、階層構造上、親子関係でない値であっても、キー同士を関連付けて&lt;/p>
&lt;p>「ある特定のキーが削除されたら、関連するキーも削除する」といったことが可能です。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">goinstant&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">connect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">room&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">rooms&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test/aaa&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">parent&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test/cd&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">cascade&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">parent&lt;/span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">//&amp;#39;test/aaa&amp;#39;の値も削除される。
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test/cd&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">remove&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>GoInstant触ってみた【Retrieving&amp;Setting Keys編】</title><link>https://blog.freedom-man.com/goinstant-key.html</link><pubDate>Sat, 12 Apr 2014 01:25:43 +0000</pubDate><guid>https://blog.freedom-man.com/goinstant-key.html</guid><description>&lt;p>今回はGoInstantで一番大事（だと思ってる）なデータ部分の操作を解説してみます。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>任意のキーの値を設定&lt;/strong>&lt;/h3>
前回同様connectでroomにJoinしてroomのメソッドで
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;aaa&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>と書くと、/testのキーに対する値を設定できます。&lt;/p>
&lt;p>返り値のresultはこんな感じ↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/set.jpg">&lt;img class="alignnone size-medium wp-image-879" alt="setkey" src="https://blog.freedom-man.com/img/2014/04/set-300x180.jpg" width="300" height="180" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>オブジェクト、数値型、配列の値も入力できます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>&lt;span style="color:#0a3069">&amp;#34;aaa&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;bbb&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">cd&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">2&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0550ae">3&lt;/span>&lt;span style="color:#1f2328">]}).&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>任意のキーの値を取得&lt;/strong>&lt;/h3>
こんな感じで取得できます。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/test&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>Roomのデータの持ち方は階層構造になっていてJSONみたいな構造になっています。&lt;/p>
&lt;p>1Room1JSONって感じで、&amp;quot;/test&amp;quot;のキー値が{&amp;ldquo;aaa&amp;rdquo;: &amp;ldquo;bbb&amp;rdquo;}のようなオブジェクト構造であれば&lt;/p>
&lt;p>&amp;ldquo;/test/aaa&amp;quot;というキー値で&amp;quot;bbb&amp;quot;という値を取ってこれます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、以下のように&amp;rdquo;/&amp;ldquo;というRootのキー値を指定するとRoom内の全てのデータを取得出来ます。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/allroomdata.jpg">&lt;img class="alignnone size-full wp-image-880" alt="allroomdata" src="https://blog.freedom-man.com/img/2014/04/allroomdata.jpg" width="173" height="100" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>キー値の設定を検知&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/test&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;set&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">context&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>valueは更新値、contextは誰が何を更新したか的な情報になります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/onset.jpg">&lt;img class="alignnone size-medium wp-image-881" alt="onset" src="https://blog.freedom-man.com/img/2014/04/onset-300x162.jpg" width="300" height="162" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>キーの削除&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">key&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;/test&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">key&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">remove&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>removeの検知はkey.on(&amp;ldquo;remove&amp;rdquo;, &amp;hellip; でOK。&lt;/p>
&lt;p>キー値を削除するので、下位のキー値も全て削除されます。&lt;/p>
&lt;p>また、&amp;rdquo;/.users&amp;quot;は削除できないっぽいです。Joinしてるからそりゃ無理ですよね…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これらのキー値の取得、設定、削除、変更の検知を駆使してWebRTCを実現するのが&lt;/p>
&lt;p>GoInstantアプリケーションのメインの部分になると思います。&lt;/p></description></item><item><title>GoInstant触ってみた【User Presence&amp;Data編】</title><link>https://blog.freedom-man.com/goinstant-user.html</link><pubDate>Fri, 11 Apr 2014 01:30:59 +0000</pubDate><guid>https://blog.freedom-man.com/goinstant-user.html</guid><description>&lt;p>WebRTCサービスのGoInstant触ってみたので基本的なところを紹介してみまっす。&lt;/p>
&lt;p> &lt;/p>
&lt;p>GoInstantの紹介は以下のWebサイトが詳しいです。&lt;/p>
&lt;p>・&lt;a title="リアルタイムBaaS「GoInstant」の概要" href="http://stomita.hatenablog.com/entry/2014/04/07/174859">リアルタイムBaaS「GoInstant」の概要&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>超カンタンに言うと、GoInstantはチャットやWeb会議的なリアルタイムコミュニケーションアプリを&lt;/p>
&lt;p>簡単に作るためのサービス（Baas）です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>GoInstantでは&lt;a title="Rooms" href="https://developers.goinstant.com/v1/overview/rooms.html">Room&lt;/a>という概念があります。&lt;/p>
&lt;p>これは&lt;span style="line-height: 1.5em;">データ伝達範囲の単位で、GoInstantでは同一Room内でのみデータのやり取りが行われます。&lt;/span>&lt;/p>
&lt;p>GoInstantではRoomに対して各ユーザがJoin（ログイン的なもの）して、Room内のデータを操作したり&lt;/p>
&lt;p>同一Roomの他のユーザがデータを更新したら、即座に画面に反映したりといったことが出来ます。&lt;/p>
&lt;p>一人のユーザが複数のRoomにJoinすることもできます。&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;"> &lt;/span>&lt;/p>
&lt;p>Room内のデータは&lt;a title="Data Structure" href="https://developers.goinstant.com/v1/overview/data_structure.html">階層構造&lt;/a>で持っていて、JSONみたいな感じです。&lt;/p>
&lt;p>JSONのプロパティに当たる部分をGoInstantではkeyと呼びます。&lt;/p>
&lt;p>（むしろJSONでもkeyって呼ぶ気がするけど…）&lt;/p>
&lt;p> &lt;/p>
&lt;p>概念的なことはさておき、&lt;del>これ以上説明するとボロが出る&lt;/del>百聞は一見に如かずということで、&lt;/p>
&lt;p>実際にコードを書いていきます！&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>GoInstantに接続(RoomにJoin)&lt;/strong>&lt;/h3>
以下のようなコードを書けばOK。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&amp;lt;!DOCTYPE html&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">meta&lt;/span> &lt;span style="color:#1f2328">charset&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;https://cdn.goinstant.net/v1/platform.min.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">url&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://goinstant.net/xxxx/*****&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">goinstant&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">connect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">connection&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これを実行するとguestアカウント（匿名）としてデフォルトのRoomである[Lobby]にjoinします。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/lobby.jpg">&lt;img class="alignnone size-medium wp-image-863" alt="lobby" src="https://blog.freedom-man.com/img/2014/04/lobby-300x30.jpg" width="300" height="30" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>guestアカウントの表示名やJoinするRoomを指定するにはconnectメソッドの部分を&lt;/p>
&lt;p>以下のように書き換えるだけ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">userObj&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">user&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">displayName&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Test&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;TestRoom&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">goinstant&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">connect&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">userObj&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">err&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">connection&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/TestRoom.jpg">&lt;img class="alignnone size-medium wp-image-862" alt="TestRoom" src="https://blog.freedom-man.com/img/2014/04/TestRoom-300x34.jpg" width="300" height="34" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>基本的にはこのconnectを実行した後の非同期コールバック関数の引数に入る&lt;/p>
&lt;p>roomやconnectionを使って色々と操作をすることになります。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>Room内にJoinしているユーザ一覧を取得する&lt;/strong>&lt;/h3>
connect実行後のコールバック関数のroomオブジェクトを使って
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">room&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">users&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">then&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">users&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">result&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">userIds&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">Object&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keys&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">users&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">userIds&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forEach&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#1f2328">){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">users&lt;/span>&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#1f2328">].&lt;/span>&lt;span style="color:#1f2328">displayName&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>と書けばOK。&lt;/p></description></item><item><title>force.comのOAuth 2.0 JWT Bearer Token Flow試してみた。</title><link>https://blog.freedom-man.com/forcecom-oauth-jwt.html</link><pubDate>Sun, 06 Apr 2014 17:41:19 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom-oauth-jwt.html</guid><description>&lt;p>force.comのOAuthをJWT投げ入れるだけで出来るらしい（&lt;a title="OAuth 2.0 JWT べアラートークンフロー" href="http://help.salesforce.com/HTViewHelpDoc?id=remoteaccess_oauth_jwt_flow.htm&amp;language=ja">ヘルプ&lt;/a>）ので、試してみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>JWT投げ入れるだけでOAuth2.0でアクセス許可を得られると言っても&lt;/p>
&lt;p>対象ユーザが既に認可しているか、管理者が事前にユーザを承認していなければ利用できません。&lt;/p>
&lt;p>つまり、refresh_tokenの代替手段になります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>JWTではコンシューマの秘密(client_secret)の代わりに&lt;/p>
&lt;p>x509証明書をアプリに登録して、Webアプリ側で登録したx509に基づく秘密鍵を使って&lt;/p>
&lt;p>JWTのSignature生成を行うことで、なりすまし等の不正アクセスを防ぎます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、実際に進めてみます。&lt;/p>
&lt;h3>&lt;strong>1. x509証明書を作成&lt;/strong>&lt;/h3>
linuxとかでこんな感じに作成します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ openssl genrsa &lt;span style="color:#0550ae">2048&lt;/span> &amp;gt; server.key
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ openssl req -new -key server.key &amp;gt; server.csr
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ openssl x509 -days &lt;span style="color:#0550ae">3650&lt;/span> -req -signkey server.key &amp;lt; server.csr &amp;gt; server.crt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. 接続アプリケーションの作成&lt;/strong>&lt;/h3>
サンプル↓
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/04/ab79480a4052fe0b28f847d61d2e2938.png">&lt;img class="alignnone size-medium wp-image-852" alt="接続アプリケーション OpenIDConnect ~ Salesforce - Developer Edition" src="https://blog.freedom-man.com/img/2014/04/ab79480a4052fe0b28f847d61d2e2938-254x300.png" width="254" height="300" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>デジタル署名を使用にチェックを付けて、ファイルには1で作成した証明書(server.crt)をアップロード。&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">また、選択したOAuth範囲に&amp;quot;ユーザに代わっていつでも要求を実行&amp;quot;を必ず入れてください。&lt;/span>&lt;/p>
&lt;p>これを入れないと、認可しても以下のエラーが出てトークンが発行できなくなります。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#34;error_description&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#0a3069">&amp;#34;user hasn&amp;#39;t approved this consumer&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#0a3069">&amp;#34;error&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span>&lt;span style="color:#0a3069">&amp;#34;invalid_grant&amp;#34;&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">それ以外は、通常のOAuthアプリと同様に作成すればOKです。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. Webアプリ側でJWTを生成する&lt;/strong>&lt;/h3>
JWTヘッダは{"alg":"RS256"}
&lt;p>JWTクレームセットは&lt;/p>
&lt;p>&amp;ldquo;iss&amp;rdquo; → SFDCアプリケーションのClientID
&amp;ldquo;prn&amp;rdquo; → SFDCのユーザ名
&amp;ldquo;aud&amp;rdquo; → https://login.salesforce.com or &lt;a href="https://test.salesforce.com">https://test.salesforce.com&lt;/a>
&amp;ldquo;exp&amp;rdquo; → 発行したJWTの有効期限タイムスタンプ(5分以内)&lt;/p></description></item><item><title>PythonとかApexでJWT作ってGoInstantにぶっこんでみる。</title><link>https://blog.freedom-man.com/python-apex-jwt-goinstant.html</link><pubDate>Sat, 05 Apr 2014 01:30:00 +0000</pubDate><guid>https://blog.freedom-man.com/python-apex-jwt-goinstant.html</guid><description>&lt;p>Salesforceが&lt;a title="GoInstant - Build real-time mobile and web applications easily..htm" href="https://goinstant.com/">GoInstant&lt;/a>買収してどうのこうのって話らしいので、GoInstant試してます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>GoInstantでユーザ認証するには外部の認証プロバイダ（facebook, salesforce, github, google, twitter）&lt;/p>
&lt;p>を使って&lt;a title="OpenID Connect" href="http://openid.net/connect/">OpenID Connect&lt;/a>やら何やらで認証するか&lt;/p>
&lt;p>自前の認証プロバイダ（と言っても普通のログイン機能を有するアプリ）で&lt;/p>
&lt;p>&lt;a title="JSON Web Token (JWT)" href="http://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html">JWT&lt;/a>をGoInstantに投げ入れて認証します。&lt;/p>
&lt;p> &lt;/p>
&lt;p>前者の場合はそれぞれのアプリケーション設定して&lt;/p>
&lt;p>ClientIDとかSecretを設定してJS叩くだけで超簡単に実装できます（&lt;a title="https://developers.goinstant.com/v1/auth_api/getting_started.html" href="https://developers.goinstant.com/v1/auth_api/getting_started.html">リファレンス&lt;/a>）。&lt;/p>
&lt;p>後者のJWT生成も&lt;a title="Authentication Libraries" href="http://https://developers.goinstant.com/v1/security_and_auth/libraries/index.html">GoInstantのライブラリ&lt;/a>（Ruby、Java、PHP、node.js）があって&lt;/p>
&lt;p>ライブラリのない言語の場合もJWT生成のライブラリを使えば、こちらも楽勝。&lt;/p>
&lt;p> &lt;/p>
&lt;p>んで、PythonでチャレンジしようとJWT生成のライブラリをインストールしてみたけど&lt;/p>
&lt;p>うまくいかなかったのでJWTの勉強がてら、自前で生成してみた。&lt;/p>
&lt;p> &lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">base64&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">hmac&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">hashlib&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">base64url_decode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">input&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">input&lt;/span> &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span> &lt;span style="color:#0550ae">*&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0550ae">4&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">len&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">input&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">%&lt;/span> &lt;span style="color:#0550ae">4&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> base64&lt;span style="color:#0550ae">.&lt;/span>urlsafe_b64decode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">input&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">base64url_encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">input&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> base64&lt;span style="color:#0550ae">.&lt;/span>urlsafe_b64encode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">input&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>replace&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>key &lt;span style="color:#0550ae">=&lt;/span> base64url_decode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Input Your App Key&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>header &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;typ&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#39;JWT&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;alg&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#39;HS256&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>payload &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;iss&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#39;localhost&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;sub&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#39;test@freedom-man.com&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;dn&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#0a3069">&amp;#39;freedom-man@display&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;g&amp;#39;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#cf222e">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>header_payload &lt;span style="color:#0550ae">=&lt;/span> base64url_encode&lt;span style="color:#1f2328">(&lt;/span>json&lt;span style="color:#0550ae">.&lt;/span>dumps&lt;span style="color:#1f2328">(&lt;/span>header&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> base64url_encode&lt;span style="color:#1f2328">(&lt;/span>json&lt;span style="color:#0550ae">.&lt;/span>dumps&lt;span style="color:#1f2328">(&lt;/span>payload&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sig &lt;span style="color:#0550ae">=&lt;/span> base64url_encode&lt;span style="color:#1f2328">(&lt;/span>hmac&lt;span style="color:#0550ae">.&lt;/span>new&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">,&lt;/span> header_payload&lt;span style="color:#1f2328">,&lt;/span> seed&lt;span style="color:#1f2328">,&lt;/span> hashlib&lt;span style="color:#0550ae">.&lt;/span>sha256&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>digest&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">print&lt;/span> seed &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#34;.&amp;#34;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> sig
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>force.comポータルでOAuth2.0</title><link>https://blog.freedom-man.com/salesforce-portal-oauth.html</link><pubDate>Mon, 31 Mar 2014 00:41:23 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce-portal-oauth.html</guid><description>&lt;p>&lt;a title="force.com REST APIのOAuthエンドポイント" href="https://blog.freedom-man.com/forcecom_rest_oauth_endpoint/">以前の記事&lt;/a>でforce.comでREST APIを使用する際のドメイン名に関して取り上げたけど&lt;/p>
&lt;p>ポータルへのOAuth認証(Sites利用)は&lt;/p>
&lt;p>普通のSalesforceユーザへのOAuthの設定方法よりやや面倒な感じになる。&lt;/p>
&lt;p>ということで、今回はポータル+Sites+OAuthについて書いてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">【ポータルOAuthの事前準備】&lt;/span>&lt;/p>
&lt;p>ポータルユーザに対してREST APIを利用したい場合は、対象ポータルに紐付けたSitesを設定する必要がある&lt;/p>
&lt;p>※ポータルユーザに対してREST APIのOAuthリクエストをする際のドメインは、Sitesのドメインになる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>【ポータルOAuthの仕様・注意点】&lt;/p>
&lt;ol>
&lt;li>SitesドメインのOAuthエンドポイントに対してAuthorizationCodeをリクエストするときに&lt;/li>
&lt;/ol>
&lt;p>ポータルユーザのセッションIDが切れていた場合は401のエラーページに遷移するので&lt;/p>
&lt;p>当ページでログイン処理を行う必要がある。&lt;/p>
&lt;ol start="2">
&lt;li>401のエラーページではSite.Loginメソッドを使ってセッションを発行し&lt;/li>
&lt;/ol>
&lt;p>return値(PageReference)をクライアントに返す必要がある。&lt;/p>
&lt;ol start="3">
&lt;li>2のreturn値によってfrontdoor.jspにリダイレクトされることで&lt;/li>
&lt;/ol>
&lt;p>セッションIDがCookieにセットされ、OAuthのリダイレクトURLに遷移する。&lt;/p>
&lt;p>※2-3の詳細は&lt;a title="Site.Loginの挙動とSalesforceの画面遷移" href="https://blog.freedom-man.com/sitelogin-salesforce/">この記事&lt;/a>を参照。&lt;/p>
&lt;p> &lt;/p>
&lt;p>401のエラーページっていうのはSitesの設定の以下の部分。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/SitesErrorPage.jpg">&lt;img class="alignnone size-medium wp-image-829" alt="SitesErrorPage" src="https://blog.freedom-man.com/img/2014/03/SitesErrorPage-300x57.jpg" width="300" height="57" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>普通のSalesforceユーザに対するOAuth認証と異なるのは1-2の工程。&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">Sitesを使ってポータルユーザへのOAuthを行う場合には&lt;/span>&lt;/p>
&lt;p>401のエラーページのVF画面でSite.Loginメソッドを使って認証させる必要があります。&lt;/p>
&lt;p>逆に、普通のSalesforceユーザではOAuthログイン画面の自由なカスタマイズが出来ないのに対して&lt;/p>
&lt;p>ポータルユーザへのログインはフロントにSitesを利用しているため自由なカスタマイズが出来るということです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、注意しておかないといけない点としては&lt;/p>
&lt;p>認証ページはVF画面（UnAuthorized）を使用できるので自由にカスタマイズできるが&lt;/p>
&lt;p>認可の画面はカスタマイズできず、以下のような固定画面になること。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/OAuthLoginPage.jpg">&lt;img class="alignnone size-medium wp-image-830" alt="OAuthLoginPage" src="https://blog.freedom-man.com/img/2014/03/OAuthLoginPage-300x192.jpg" width="300" height="192" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ポータル案件ではデザイン性が要求されるため&lt;/p>
&lt;p>カスタマイズできない画面があるというのは、十分留意しておく必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>コミュニティはここらへんどうなんだろう…？&lt;/p></description></item><item><title>Site.Loginの挙動とSalesforceの画面遷移</title><link>https://blog.freedom-man.com/sitelogin-salesforce.html</link><pubDate>Sat, 29 Mar 2014 00:08:07 +0000</pubDate><guid>https://blog.freedom-man.com/sitelogin-salesforce.html</guid><description>&lt;p>force.comでは、Sitesがポータルログインのフロントとしてよく使われます。&lt;/p>
&lt;p>Salesforceが提供するカスタマーポータルの標準画面はアレだからね…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、Sitesを入り口にするということはVF、Apexでログイン処理をするわけで&lt;/p>
&lt;p>ログインのメソッドとしてSite.Login(username, password, startUrl)というのがあって、&lt;/p>
&lt;p>ここにバインドしたユーザ名やパスワードを入れたらSitesに紐付けたポータルにログインできます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>が、ここで注意しておきたいのが、Site.Loginメソッドが以下の手順でログイン処理を実装していること。&lt;/p>
&lt;p> &lt;/p>
&lt;ol>
&lt;li>
&lt;p>エンドユーザがユーザ名とパスワードを入力してログインボタンを押下する。（htmlのformタグによるPOST）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Apex側でSite.Loginを呼び出し、セッションを発行する。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>※発行するだけで、エンドユーザのブラウザのCookieに保存するわけではないことに注意！&lt;/p>
&lt;ol start="3">
&lt;li>
&lt;p>Site.Loginのreturn値であるPageReferenceをメソッドの戻り値としてreturnする。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>エンドユーザはSite.Loginのreturn値のURL(https://[site-domain]/secur/frontdoor.jsp)にリダイレクトする。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>frontdoor.jspにsidパラメータ付きで渡されると、sid値をセッションIDとしてレスポンスのSet-Cookieによって&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>ブラウザにCookieが設定されて、認証完了となる。&lt;/p>
&lt;ol start="6">
&lt;li>認証後の画面(Site.LoginのstartUrl値)にリダイレクトする。&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>実際のレスポンス（HTTPヘッダ）はこんな感じ(firebug)&lt;/p>
&lt;p>Site.Loginのレスポンス↓
&lt;a href="https://blog.freedom-man.com/img/2014/03/84886404c108b63d7fa1b2d0a4db198c.jpg">&lt;img class="alignnone size-medium wp-image-817" alt="Site.loginのレスポンス" src="https://blog.freedom-man.com/img/2014/03/84886404c108b63d7fa1b2d0a4db198c-300x147.jpg" width="300" height="147" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>frontdoor.jspのレスポンス↓（ドメイン名やSessionIDや組織IDを隠そうとしたら、Cookieのほとんどが黒塗りｗ）&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/f65b1903569e881349dc39718726f328.jpg">&lt;img class="alignnone size-medium wp-image-816" alt="frontdoor.jspのレスポンス" src="https://blog.freedom-man.com/img/2014/03/f65b1903569e881349dc39718726f328-300x124.jpg" width="300" height="124" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>重要なのは、2の時点ではセッションを発行しているだけで、ブラウザにSet-Cookieを発行しているわけではなく、&lt;/p>
&lt;p>frontdoor.jspに発行したセッションIDをパラメータで渡すことで&lt;/p>
&lt;p>初めてブラウザにSet-Cookieが発行されるということ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>つまり、Site.Loginのreturn値を返さずに別のPageReference値を返すと&lt;/p>
&lt;p>セッションが発行されるだけで、認証が完了しないということになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ただし、&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>PageReference&lt;span style="color:#fff"> &lt;/span>loginPr&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Site&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">login&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>username&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>password&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>startUrl&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>String&lt;span style="color:#fff"> &lt;/span>sessionId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>loginPr&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getParameters&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>sid&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>のように、frontdoor.jspへのリダイレクトURLからセッションIDを取得して保持しておき&lt;/p>
&lt;p>ログインするときにはfrontdoor.jsp?sid=[セッションID]のURLにリダイレクトさせてあげれば&lt;/p>
&lt;p>Site.Loginを発行した直後ではない任意のタイミングでログインを実行させることも可能です。&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;"> &lt;/span>&lt;/p>
&lt;p>また、上記でリダイレクトと書きましたが、これは301とかのステータスコードによるリダイレクトではなくて&lt;/p>
&lt;p>JavaScript(location.href)によるオートリダイレクトになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>つまり3でPOSTに対するレスポンスはlocation.href=[frontdoor.jspのurl]が書かれたhtmlで、&lt;/p>
&lt;p>5のfrontdoor.jspに対するGETリクエストのレスポンスはlocation.href=[startUrl]が書かれたhtmlということ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">基本的にApexのPageReferenceでポストバックじゃない場合は、全部このリダイレクト方法っす。&lt;/span>&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;"> &lt;/span>&lt;/p>
&lt;p>ちなみに、Site.LoginでカスタマーポータルにログインしたときのドメインはSitesのドメインですが&lt;/p>
&lt;p>デフォルトの/secur/login_portal.jspでログインしたり、&lt;a title="http://deferloader.blog.uhuru.co.jp/?p=357" href="http://deferloader.blog.uhuru.co.jp/?p=357">login_portal.jspのformをハックする方法&lt;/a>でログインすると&lt;/p>
&lt;p>Salesforce組織のドメイン(csとかapとかnaとか)になります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>後者の方法でもPOSTすると、frontdoor.jspに飛ばされてCookieをセットするフローになります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>この後、/_nc_external/identity/legacylogin/server/PortalDoorっていうURLに飛ばされて&lt;/p>
&lt;p>さらにリダイレクトしてstartUrlに遷移します。（legacyloginって思いっきり書いてあるｗ）&lt;/p></description></item><item><title>dockerコンテナで動くmysqlを永続化してみる【Zabbix編】</title><link>https://blog.freedom-man.com/docker-mysql-zabbix-separete.html</link><pubDate>Sun, 16 Mar 2014 22:57:39 +0000</pubDate><guid>https://blog.freedom-man.com/docker-mysql-zabbix-separete.html</guid><description>&lt;p>今回はdockerコンテナで動くmysqlデータをホストOS上にセーブすることで、&lt;/p>
&lt;p>commitしなくてもデータを維持する！ということをしてみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今まではコンテナ落とす度にちゃんとcommitしないと、次に起動するときにデータが無くなり&lt;/p>
&lt;p>&lt;a title="http://www.nttdata.com/jp/ja/insights/trend_keyword/2013122601.html" href="http://www.nttdata.com/jp/ja/insights/trend_keyword/2013122601.html">Immutable Infrastructure&lt;/a>とは程遠い感じになっていたので&lt;/p>
&lt;p>サーバーは機能だけを提供して、データは別にするという疎結合な感じにするっていうのがモチベーション。&lt;/p>
&lt;p> &lt;/p>
&lt;p>本日の参考サイトはこちら↓&lt;/p>
&lt;p>&lt;a title="http://www.zabbix.jp/documents/installation/install-rpm" href="http://www.zabbix.jp/documents/installation/install-rpm">&lt;a href="http://www.zabbix.jp/documents/installation/install-rpm">http://www.zabbix.jp/documents/installation/install-rpm&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://cpw.hatenadiary.jp/entry/2013/08/20/220306" href="http://cpw.hatenadiary.jp/entry/2013/08/20/220306">&lt;a href="http://cpw.hatenadiary.jp/entry/2013/08/20/220306">http://cpw.hatenadiary.jp/entry/2013/08/20/220306&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>考え方としては、ホストOSにmysqlデータを格納してそれをコンテナがマウントして使うって感じ。&lt;/p>
&lt;p>&lt;a title="DigitalOcean + docker + Zabbixで監視サーバ立ててみる" href="https://blog.freedom-man.com/digitalocean-docker-zabbix/">docker+zabbixの回&lt;/a>で既にmysql-serverがインストールされているので、そのデータ移行もやってみます。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. ホストOSに任意のディレクトリを作成。&lt;/strong>&lt;/h3>
コンテナにマウントさせる共有ディレクトリを作成します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir /home/tzm/docker/share
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ mkdir /home/tzm/docker/mysql
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>前者はダンプファイル共有用、後者はmysqlデータ格納用になります。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>&lt;span style="line-height: 1.5em;">2. docker run でコンテナ作成。&lt;/span>&lt;/strong>&lt;/h3>
1で作成した共有ディレクトリの内、ダンプファイル共有用のディレクトリをマウントしてコンテナを作成します。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ docker run -v /home/tzm/docker/share:/share -i -t tzm/zabbix /bin/bash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>これでホストOSの/home/tzm/docker/shareディレクトリがコンテナの/shareでアクセス出来るようになります。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>&lt;span style="line-height: 1.5em;">3. mysqlのダンプを取ってマウントしたディレクトリ内に格納してコンテナを落とす。&lt;/span>&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> /share
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ mysqldump -u root -p zabbix &amp;gt; dump.sql
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">exit&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>4. mysqlデータ共有ディレクトリをマウントして再度コンテナ起動。&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ docker run -v /home/tzm/docker/mysql:/var/lib/mysql &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-v /home/tzm/docker/share:/share -p 443:443 -p 10051:10051 -i -t tzm/zabbix /bin/bash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>zabbixをnginxで動かす！</title><link>https://blog.freedom-man.com/zabbix-nginx.html</link><pubDate>Sun, 16 Mar 2014 16:26:49 +0000</pubDate><guid>https://blog.freedom-man.com/zabbix-nginx.html</guid><description>&lt;p>DigitalOceanの512MBプランでやっている都合上メモリは極力抑えたい。&lt;/p>
&lt;p>apacheだとメモリ食いまくるので&lt;del>貧乏人&lt;/del>節約家的にはシングルスレッドなWebサーバで&lt;/p>
&lt;p>メモリは安くやりたいところです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで&lt;a title="DigitalOcean + docker + Zabbixで監視サーバ立ててみる" href="https://blog.freedom-man.com/digitalocean-docker-zabbix/">前回&lt;/a>インストールしたzabbixをnginxで動かします。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">で、方法は色々とありそうですが、&lt;/span>&lt;a style="line-height: 1.5em;" title="http://blog.kenjiskywalker.org/blog/2013/01/03/zabbix/" href="http://blog.kenjiskywalker.org/blog/2013/01/03/zabbix/">こちら&lt;/a>&lt;span style="line-height: 1.5em;">の方法が簡単そうだったのでトライしてみました。&lt;/span>&lt;/p>
&lt;p>原理は簡単で、zabbixのパスでアクセスしてきたら&lt;/p>
&lt;p>/usr/share/zabbix(phpアプリの場所)にアクセスするようにリンクを貼ってあげて&lt;/p>
&lt;p>phpに対するアクセスはphp-fpmに渡せばOK。&lt;/p>
&lt;p>ついでにSSLも対応しちゃいます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>まずはnginxとphp-fpmのインストールから&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ apt-get install nginx php5-fpm
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>ドキュメントルート直下にリンクを貼る&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ ln -s /usr/share/zabbix /usr/share/nginx/www/zabbix
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>SSLの証明書＆キーを作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ &lt;span style="color:#6639ba">cd&lt;/span> /etc/nginx
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ openssl req -new -days &lt;span style="color:#0550ae">365&lt;/span> -x509 -nodes -keyout cert.key -out cert.crt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>ログ用のディレクトリを作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ mkdir /var/log/nginx/zabbix
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>/etc/nginx/conf.d/zabbix.confを作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>server {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> listen 80;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> listen 443 default_server ssl;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> root /usr/share/nginx/www;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl on;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_certificate /etc/nginx/cert.crt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_certificate_key /etc/nginx/cert.key;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_session_timeout 5m;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_protocols SSLv2 SSLv3 TLSv1;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_ciphers HIGH:!aNULL:!MD5;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ssl_prefer_server_ciphers on;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> server_name ************;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index index.html;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> access_log /var/log/nginx/zabbix/access_log main;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> error_log /var/log/nginx/zabbix/error_log error;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> location /zabbix {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> index index.php;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> location ~ \.php$ {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fastcgi_pass 127.0.0.1:9000;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fastcgi_index index.php;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> include fastcgi_params;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>DigitalOcean + docker + Zabbixで監視サーバ立ててみる</title><link>https://blog.freedom-man.com/digitalocean-docker-zabbix.html</link><pubDate>Sat, 15 Mar 2014 23:44:01 +0000</pubDate><guid>https://blog.freedom-man.com/digitalocean-docker-zabbix.html</guid><description>&lt;p>激安VPSの&lt;a title="https://www.digitalocean.com/" href="https://www.digitalocean.com/">DigitalOcean&lt;/a>で、&lt;a title="https://www.docker.io/" href="https://www.docker.io/">docker&lt;/a>のコンテナで&lt;a title="http://www.zabbix.com/jp/" href="http://www.zabbix.com/jp/">Zabbix&lt;/a>を使って&lt;/p>
&lt;p>&lt;span style="color: black;">&lt;del>ストーキング&lt;/del>監視サーバを立てるのが今回の目的。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;p>何でZabbixかっていうと、先日の&lt;a title="https://www.ospn.jp/osc2014-spring/" href="https://www.ospn.jp/osc2014-spring/">OSC 2014&lt;/a>でトピックに上がっていて&lt;/p>
&lt;p>個人的に興味持ったので、その検証用って感じっす。&lt;/p>
&lt;p> &lt;/p>
&lt;p>何でDigitalOcean＆dockerかっていうと&lt;del>お金がないから&lt;/del>今熱いからです！&lt;/p>
&lt;p> &lt;/p>
&lt;p>で工程としては&lt;/p>
&lt;ol>
&lt;li>
&lt;p>DigitalOceanでサーバ立てる&lt;/p>
&lt;/li>
&lt;li>
&lt;p>dockerをインストール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>dockerでコンテナを立てる&lt;/p>
&lt;/li>
&lt;li>
&lt;p>コンテナOSにZabbixとかインストール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Zabbixとapacheを起動&lt;/p>
&lt;/li>
&lt;li>
&lt;p>監視対象サーバにZabbixエージェントをインストールして起動&lt;/p>
&lt;/li>
&lt;li>
&lt;p>WebGUIで設定&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>って感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. DigitalOceanでサーバを立てる&lt;/strong>&lt;/h3>
DigitalOceanはAWSみたいにサーバを自由に作ったり壊したりできる
&lt;p>格安クラウドサービスで、月額500円でメモリ512MB相当のVPSを作れます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はテキトーに512MBのUbuntuで作成。&lt;/p>
&lt;p> &lt;/p>
&lt;p>EC2とかと違って、配布されるユーザはrootなので&lt;/p>
&lt;p>作った後は作業用ユーザ作成して、sshのログインとかパスワード認証禁止して&lt;/p>
&lt;p>公開鍵設定して、みたいなことは全部やんないとダメなので注意。&lt;/p>
&lt;p>ここらへんは自前でChefとかで自動化した方が良いかもねー。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. dockerのインストール&lt;/strong>&lt;/h3>
今回はUbuntu使ったので
&lt;p>&lt;a title="http://docs.docker.io/en/latest/installation/ubuntulinux/" href="http://docs.docker.io/en/latest/installation/ubuntulinux/">&lt;a href="http://docs.docker.io/en/latest/installation/ubuntulinux/">http://docs.docker.io/en/latest/installation/ubuntulinux/&lt;/a>&lt;/a>&lt;/p>
&lt;p>に従ってインストールする。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. dockerでコンテナを立てる&lt;/strong>&lt;/h3>
dockerでコンテナを作成
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ sudo docker run -p 80:80 -p 443:443 -p 10051:10051 -i -t ubuntu /bin/bash
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>dockerの使い方はここらへんを参考にしました↓&lt;/p>
&lt;p>&lt;a title="http://apatheia.info/blog/2013/06/17/docker/" href="http://apatheia.info/blog/2013/06/17/docker/">&lt;a href="http://apatheia.info/blog/2013/06/17/docker/">http://apatheia.info/blog/2013/06/17/docker/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://qiita.com/h_demon/items/096dafed2b8fec362323" href="http://qiita.com/h_demon/items/096dafed2b8fec362323">&lt;a href="http://qiita.com/h_demon/items/096dafed2b8fec362323">http://qiita.com/h_demon/items/096dafed2b8fec362323&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>最初のイメージをダウンロードする時間はちょっとかかるけど&lt;/p>
&lt;p>一回ダウンロードした後のコンテナの起動は超早い、っていうか一瞬です。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>4. コンテナOSにZabbixとかインストール&lt;/strong>&lt;/h3>
コンテナが作成されたらbash起動するので
&lt;p>Zabbixの&lt;a title="https://www.zabbix.com/documentation/jp/2.0/manual/installation/install_from_packages" href="https://www.zabbix.com/documentation/jp/2.0/manual/installation/install_from_packages">インストール方法&lt;/a>に従って、色々とインストール。&lt;/p>
&lt;p>※上記リンクの順番と違って、Zabbixよりも先にmysql-serverをインストールするのがミソ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ apt-get install wget 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ wget http://repo.zabbix.com/zabbix/2.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_2.0-1precise_all.deb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ dpkg -i zabbix-release_2.0-1precise_all.deb
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ apt-get update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>$ apt-get install mysql-server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>JanrainとSalesforce連携してみる</title><link>https://blog.freedom-man.com/janrain_salesforce.html</link><pubDate>Thu, 06 Mar 2014 00:12:03 +0000</pubDate><guid>https://blog.freedom-man.com/janrain_salesforce.html</guid><description>&lt;p>&lt;a title="OpenID勉強してたら、Janrainというサービスを発見したので紹介してみる。" href="https://blog.freedom-man.com/janrain/">前回&lt;/a>説明したJanrain。&lt;/p>
&lt;p>これ、SalesforceとSSOできちゃうみたいです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで今回はSalesforceとソーシャルサインオン連携してみる回です。&lt;/p>
&lt;p> &lt;/p>
&lt;p>認証プロバイダ作るあたりは&lt;a title="salesforceでfacebook, google, salesforceを認証プロバイダにしてSSOしてみる。" href="https://blog.freedom-man.com/salesforce_facebook_google_salesforce_sso/">google, facebook, salesforceでSSO&lt;/a>したときと同じなので&lt;/p>
&lt;p>こちらも合わせてご参考ください！&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. Janrainアプリのホワイトリストにsalesforceのドメインを追加&lt;/strong>&lt;/h3>
helpにはsalesforce.comを追加って書いてありますが
&lt;p>これじゃダメで、login.salesforce.com(あるいは*.salesforce.com)とSitesのドメインを指定してあげます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainWhiteListExample.jpg">&lt;img class="alignnone size-medium wp-image-770" alt="JanrainWhiteListExample" src="https://blog.freedom-man.com/img/2014/03/JanrainWhiteListExample-300x129.jpg" width="300" height="129" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ホワイトリストの設定が間違っているとこんな感じのエラーが出ます。&lt;/p>
&lt;p>login.salesforce.comが設定されていない場合↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainWhiteListError1.jpg">&lt;img class="alignnone size-medium wp-image-772" alt="JanrainWhiteListError1" src="https://blog.freedom-man.com/img/2014/03/JanrainWhiteListError1-300x28.jpg" width="300" height="28" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>Sitesのドメインが設定されていない場合↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainWhiteListError2.jpg">&lt;img class="alignnone size-medium wp-image-771" alt="JanrainWhiteListError2" src="https://blog.freedom-man.com/img/2014/03/JanrainWhiteListError2-300x133.jpg" width="300" height="133" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;p>何気にここが一番のハマりどころでした…。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. 認証プロバイダの登録&lt;/strong>&lt;/h3>
セキュリティのコントロール＞認証プロバイダから新規に認証プロバイダを作成する。
&lt;p>プロバイダタイプをJanrainにして、コンシューマの秘密にJanrainのappKeyを設定。&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、こんな感じになる↓&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainIdentityProvider.jpg">&lt;img class="alignnone size-medium wp-image-773" alt="JanrainIdentityProvider" src="https://blog.freedom-man.com/img/2014/03/JanrainIdentityProvider-300x166.jpg" width="300" height="166" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>他の認証プロバイダと違ってflowtype=xxxというパラメータが付与されています。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. Sitesにログインページ(VF)を作成&lt;/strong>&lt;/h3>
こんな感じ↓
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:page&lt;/span> &lt;span style="color:#1f2328">showHeader&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;false&amp;#34;&lt;/span> 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">standardStyleSheets&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;false&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">docType&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;html-5.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">html&lt;/span> &lt;span style="color:#1f2328">lang&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;ja&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">meta&lt;/span> &lt;span style="color:#1f2328">charset&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;utf-8&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">typeof&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">janrain&lt;/span> &lt;span style="color:#0550ae">!==&lt;/span> &lt;span style="color:#0a3069">&amp;#39;object&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">janrain&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">typeof&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">janrain&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">settings&lt;/span> &lt;span style="color:#0550ae">!==&lt;/span> &lt;span style="color:#0a3069">&amp;#39;object&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">janrain&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">settings&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">janrain&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">settings&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">tokenUrl&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https://login.salesforce.com/services/authcallback/00Dxxxxxxxxxxxx/Janrain?flowtype={!$CurrentPage.parameters.type}&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#1f2328">isReady&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">janrain&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ready&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span> &lt;span style="color:#1f2328">};&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addEventListener&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addEventListener&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;DOMContentLoaded&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">isReady&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">false&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">attachEvent&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;onload&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">isReady&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">e&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createElement&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;script&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">type&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;text/javascript&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">id&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;janrainAuthWidget&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">location&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">protocol&lt;/span> &lt;span style="color:#0550ae">===&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https:&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">src&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;https://rpxnow.com/js/lib/tzm-freedom/engage.js&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">else&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">src&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;http://widget-cdn.rpxnow.com/js/lib/tzm-freedom/engage.js&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">s&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getElementsByTagName&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;script&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)[&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">];&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">s&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">parentNode&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">insertBefore&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">s&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">})();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">a&lt;/span> &lt;span style="color:#1f2328">class&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;janrainEngage&amp;#34;&lt;/span> &lt;span style="color:#1f2328">href&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;#&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>Sign-In&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">a&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:page&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>OpenID勉強してたら、Janrainというサービスを発見したので紹介してみる。</title><link>https://blog.freedom-man.com/janrain.html</link><pubDate>Wed, 05 Mar 2014 00:50:40 +0000</pubDate><guid>https://blog.freedom-man.com/janrain.html</guid><description>&lt;p>&lt;a title="http://openid.net/" href="http://openid.net/">OpenID Connect&lt;/a>ローンチおめでとう！&lt;/p>
&lt;p>ということで、OpenID ConnectはOAuth 2.0の技術を使ってるぐらいしか知らず、&lt;/p>
&lt;p>OpenID 2.0もわりとさっぱりだったので最近勉強してたんですけど、よし使ってみるか！って思って&lt;/p>
&lt;p>&lt;a title="http://wiki.openid.net/w/page/12995176/Libraries" href="http://wiki.openid.net/w/page/12995176/Libraries">ライブラリ&lt;/a>見てたら、&lt;a title="http://janrain.com/" href="http://janrain.com/">Janrain&lt;/a>というSaasを発見したので紹介してみるっていう流れ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>なお、Janrainに関する日本語の情報がとても乏しく、さらにJanrain経験3時間くらいのスライムなので&lt;/p>
&lt;p>色々と間違っているかもしれませんが、いつも通りご容赦を。&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、Janrainは認証系のSaasで&lt;/p>
&lt;p>・OpenIDとかOAuthとかそういう系のソーシャルサインオンを提供&lt;/p>
&lt;p>・色んなWebアプリ（認証プロバイダ）に対応&lt;/p>
&lt;p>・Janrain自体にもユーザ情報を確認できるらしい（未確認）&lt;/p>
&lt;p>・シングルサインオンもできます&lt;/p>
&lt;p>・ユーザ登録数とかログイン数とかの分析もできます&lt;/p>
&lt;p>・Social Sharing（Twitterで共有的な）も簡単にできます&lt;/p>
&lt;p>といったサービスです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>メインどころは一番最初に書いたソーシャルサインオンのところで、&lt;/p>
&lt;p>普通はサービスに応じて認証プロトコルを変えないといけないから&lt;/p>
&lt;p>OAuth 1.0, 2.0やらOpenID 1.1, 2.0, Connectやら色々と切り替えないといけなくて&lt;/p>
&lt;p>利用言語のライブラリもその分対応してないといけないけど&lt;/p>
&lt;p>JanrainだとAPI呼ぶだけであとはJanrainがサーバサイドでサービスごとの差異を吸収しますよー&lt;/p>
&lt;p>っていうのが良いみたい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>百聞は一見に如かずということで、実際にやってみました。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. Janrain登録&lt;/strong>&lt;/h3>
まずは登録。→&lt;a title="https://dashboard.janrain.com/signin" href="https://dashboard.janrain.com/signin">https://dashboard.janrain.com/signin&lt;/a>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainSignIn.jpg">&lt;img class="alignnone size-medium wp-image-751" alt="JanrainSignIn" src="https://blog.freedom-man.com/img/2014/03/JanrainSignIn-300x144.jpg" width="300" height="144" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>もちろん、ソーシャルサインオンもできまっせ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. ダッシュボードからアプリ（Engage）を作成&lt;/strong>&lt;/h3>
ログインすると&lt;a title="https://dashboard.janrain.com/" href="https://dashboard.janrain.com/">ダッシュボード&lt;/a>画面に遷移するので
&lt;p>[New Property]から新しいアプリ（Engage）を作成します。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainDashboard1.jpg">&lt;img class="alignnone size-medium wp-image-753" alt="JanrainDashboard" src="https://blog.freedom-man.com/img/2014/03/JanrainDashboard1-300x87.jpg" width="300" height="87" />&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainNewProperty.jpg">&lt;img class="alignnone size-medium wp-image-754" alt="JanrainNewProperty" src="https://blog.freedom-man.com/img/2014/03/JanrainNewProperty-300x153.jpg" width="300" height="153" />&lt;/a>&lt;/p>
&lt;p>&lt;a style="line-height: 1.5em;" href="https://blog.freedom-man.com/img/2014/03/JanrainNewApp.jpg">&lt;img class="alignnone size-medium wp-image-759" alt="JanrainNewApp" src="https://blog.freedom-man.com/img/2014/03/JanrainNewApp-300x170.jpg" width="300" height="170" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. 作成したアプリの吹き出しアイコン(?)をクリックして管理画面へ遷移&lt;/strong>&lt;/h3>
&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainDashboardAfterCreate.jpg">&lt;img class="alignnone size-medium wp-image-755" alt="JanrainDashboardAfterCreate" src="https://blog.freedom-man.com/img/2014/03/JanrainDashboardAfterCreate-300x91.jpg" width="300" height="91" />
&lt;/a>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>4. Sign-InsをクリックしてWidget作成画面に遷移&lt;/strong>&lt;/h3>
色々と表示されてますが、とりあえずSign-Insでソーシャルログイン用のWidgetを作成します。
&lt;p>ダッシュボード画面でユーザ登録数とかログイン回数をグラフで閲覧することもできます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/03/JanrainApp.jpg">&lt;img class="alignnone size-medium wp-image-757" alt="JanrainApp" src="https://blog.freedom-man.com/img/2014/03/JanrainApp-300x205.jpg" width="300" height="205" />&lt;/a>&lt;/p></description></item><item><title>AnonymousなREST APIをCORSに対応させてみる。</title><link>https://blog.freedom-man.com/forcecom_sites_rest_cors.html</link><pubDate>Mon, 03 Mar 2014 00:03:47 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_sites_rest_cors.html</guid><description>&lt;p>以前、SitesでApex RESTクラスを公開することで認証なしで&lt;/p>
&lt;p>&lt;a title="SitesでanonymousなREST APIをコールする。" href="https://blog.freedom-man.com/forcecom_sites_anonymous_rest/">Anonymous（サイトゲストユーザ）なREST APIをコールできます&lt;/a>的な話をしましたが、&lt;/p>
&lt;p>CORS対応できるかどうかを検証してみました！&lt;/p>
&lt;p>CORSに関しては以下のURLが詳しい感じっす。&lt;/p>
&lt;p>&lt;a title="https://developer.mozilla.org/ja/docs/HTTP_access_control" href="https://developer.mozilla.org/ja/docs/HTTP_access_control">&lt;a href="https://developer.mozilla.org/ja/docs/HTTP_access_control">https://developer.mozilla.org/ja/docs/HTTP_access_control&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://dev.classmethod.jp/etc/about-cors/" href="http://dev.classmethod.jp/etc/about-cors/">&lt;a href="http://dev.classmethod.jp/etc/about-cors/">http://dev.classmethod.jp/etc/about-cors/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、今回検証したサンプル↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">@RestResource&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>urlMapping&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>MyRestContextExample&lt;span style="color:#0550ae">/*&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>global&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">MyRestContextExample&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">	
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">@HttpGet&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>Account&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">doGet&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>RestRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>RestContext&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">request&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>RestResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>RestContext&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Access&lt;span style="color:#0550ae">-&lt;/span>Control&lt;span style="color:#0550ae">-&lt;/span>Allow&lt;span style="color:#0550ae">-&lt;/span>Origin&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;*&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>accountId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">requestURI&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">substring&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">requestURI&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">lastIndexOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>1&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Account&lt;span style="color:#fff"> &lt;/span>result&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">[&lt;/span>SELECT&lt;span style="color:#fff"> &lt;/span>Id&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Name&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Phone&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Website&lt;span style="color:#fff"> &lt;/span>FROM&lt;span style="color:#fff"> &lt;/span>Account&lt;span style="color:#fff"> &lt;/span>WHERE&lt;span style="color:#fff"> &lt;/span>Id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>accountId&lt;span style="color:#0550ae">]&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>result&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">@HttpPost&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>Boolean&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">doPost&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>RestRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>RestContext&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">request&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>RestResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>RestContext&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Access&lt;span style="color:#0550ae">-&lt;/span>Control&lt;span style="color:#0550ae">-&lt;/span>Allow&lt;span style="color:#0550ae">-&lt;/span>Origin&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;*&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">true&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>ApexからAutoScaling触ってみる。</title><link>https://blog.freedom-man.com/autoscaling_using_apex.html</link><pubDate>Sun, 02 Mar 2014 10:37:15 +0000</pubDate><guid>https://blog.freedom-man.com/autoscaling_using_apex.html</guid><description>&lt;p>今回は&lt;a title="http://aws.amazon.com/jp/autoscaling/" href="http://aws.amazon.com/jp/autoscaling/">Auto Scaling&lt;/a>をApexから&lt;a title="http://docs.aws.amazon.com/AutoScaling/latest/APIReference/Welcome.html" href="http://docs.aws.amazon.com/AutoScaling/latest/APIReference/Welcome.html">REST API&lt;/a>で触ってみます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Auto Scalingは指定したインスタンスが落ちたら自動的に指定のインスタンス数になるまで&lt;/p>
&lt;p>同じインスタンスを立ててくれたり、指定した時刻にインスタンスを動的に増減させることのできる&lt;/p>
&lt;p>自動でスケーリングをしてくれるサービスです。（って名前そのまんまの説明…）&lt;/p>
&lt;p> &lt;/p>
&lt;p>これを使うと、&lt;/p>
&lt;p>「毎週日曜日は負荷が高いから自動的に処理をするインスタンス数を増やそう！」とか&lt;/p>
&lt;p>「万が一インスタンスが落ちてもすぐにインスタンスを立ち上げるようにしよう！」とか&lt;/p>
&lt;p>「不健全なインスタンスを落として健全なインスタンスだけ生かしたい！」とか&lt;/p>
&lt;p>こういったスケールアウト、スケールインが自由自在にできちゃいます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>前回はEC2をREST APIを使って手動で立ち上げていて、&lt;/p>
&lt;p>”EC2のREST APIを使ってスケジュール化するためにはApexバッチが必要”と書きましたが、&lt;/p>
&lt;p>このAuto Scalingを使えばスケールアウトを自動化できるので&lt;/p>
&lt;p>インスタンス数を0→1にスケールアウトするようなスケジューリングをAuto ScalingをCUIとかで&lt;/p>
&lt;p>一回設定してあげれば自動インスタンス起動の処理ができちゃいます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Auto Scalingのスケジューリングに関する参考URL↓&lt;/p>
&lt;p>&lt;a title="http://blog.suz-lab.com/2012/04/ec2.html" href="http://blog.suz-lab.com/2012/04/ec2.html">&lt;a href="http://dev.classmethod.jp/cloud/auto-scaling-schedule/">http://dev.classmethod.jp/cloud/auto-scaling-schedule/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://blog.suz-lab.com/2012/04/ec2.html" href="http://blog.suz-lab.com/2012/04/ec2.html">&lt;span style="line-height: 1.5em;">&lt;span style="line-height: 1.5em;">&lt;a href="http://blog.suz-lab.com/2012/04/ec2.html">http://blog.suz-lab.com/2012/04/ec2.html&lt;/a>&lt;/span>&lt;/span>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">また、Auto Scalingを利用しない単純なEC2インスタンス起動は、立ち上げた後は負荷が高かろうが&lt;/span>&lt;/p>
&lt;p>インスタンスが落ちようが、別のAPIでチェックしない限りは検知することができないのと&lt;/p>
&lt;p>検知しても自動的にスケールさせたり、落ちた時に自動的にインスタンスを立ち上げるという&lt;/p>
&lt;p>仕組みを自前で実装しなければなりません。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そこで、Auto Scalingの出番ということです！&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、今回のサンプル！↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">AutoScalingCommon&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AccessKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSAccessKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SecretKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSSecretKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeySecret__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">final&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>REGION&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>us&lt;span style="color:#0550ae">-&lt;/span>east&lt;span style="color:#0550ae">-&lt;/span>1&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">final&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>autoscaling&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AutoScalingGroupの更新(インスタンス数の最大、最小を変更)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">updateAutoScalingGroup&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>autoScalingGroupName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Integer&lt;span style="color:#fff"> &lt;/span>minSize&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Integer&lt;span style="color:#fff"> &lt;/span>maxSize&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>content&lt;span style="color:#0550ae">-&lt;/span>length&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>REGION&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>aws4_request&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UpdateAutoScalingGroup&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2011&lt;span style="color:#0550ae">-&lt;/span>01&lt;span style="color:#0550ae">-&lt;/span>01&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AutoScalingGroupName&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>autoScalingGroupName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>MinSize&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>minSize&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>MaxSize&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>maxSize&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>body&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createStringToSign&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#0550ae">-&lt;/span>HMAC&lt;span style="color:#0550ae">-&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createHashedCanonicalRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{},&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>autoscaling&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>content&lt;span style="color:#0550ae">-&lt;/span>length&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>body&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">},&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>body&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>stringToSign&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">callAutoScalingCallCommon&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>autoscaling&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>REGION&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>body&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AutoScalingへのAPIコールの共通メソッド
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">callAutoScalingCallCommon&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>body&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Length&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>body&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Authorization&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#0550ae">-&lt;/span>HMAC&lt;span style="color:#0550ae">-&lt;/span>SHA256&lt;span style="color:#fff"> &lt;/span>Credential&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignedHeaders&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getLowerCaseSortedList&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signedHeaders&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//&amp;#39; + hostname + &amp;#39;/&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>body&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * HashedCanonicalRequestを作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createHashedCanonicalRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>url&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>payload&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>url&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createCanonicalHeaders&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>headers&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getLowerCaseSortedList&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signedHeaders&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertToHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateDigest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>payload&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertToHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateDigest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * StringToSignを作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createStringToSign&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>requestDateTime&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>hashedCanonicalRequest&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>requestDateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>requestDateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>hashedCanonicalRequest&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>requestDateTime&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>service&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kDate&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>requestDateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSSecretKeyId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kRegion&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>region&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kDate&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kService&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>service&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kRegion&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kSigning&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>aws4_request&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kService&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertToHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kSigning&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Auto ScalingはSignature &lt;a title="http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html" href="http://docs.aws.amazon.com/general/latest/gr/signature-version-2.html">Version2&lt;/a>と&lt;a title="http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html" href="http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html">Version4&lt;/a>の両方が使えるんですが、&lt;/p></description></item><item><title>ApexからEC2を触ってみる。</title><link>https://blog.freedom-man.com/ec2_using_apex.html</link><pubDate>Sat, 01 Mar 2014 00:35:27 +0000</pubDate><guid>https://blog.freedom-man.com/ec2_using_apex.html</guid><description>&lt;p>恒例の触ってみるシリーズ、今回はAWSの大黒柱（だと勝手に思っている）&lt;a title="http://aws.amazon.com/jp/ec2/" href="http://aws.amazon.com/jp/ec2/">EC2&lt;/a>です！&lt;/p>
&lt;p> &lt;/p>
&lt;p>SalesforceでEC2を触ることのモチベーションの一つとしては&lt;/p>
&lt;p>「Apexでは不可能な処理をEC2を一時的に立てて処理を行わせる」ということ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>例えば、Salesforceの全データをバックアップする！といったバッチ処理の場合は&lt;/p>
&lt;p>force.com内部で行わせるよりは別サーバからデータローダCLI等のAPI経由でやってもらった方が&lt;/p>
&lt;p>ガバナ制限から開放される上に、プログラミング言語がサポートする範囲の&lt;/p>
&lt;p>自由な形式でデータを出力することができます。&lt;/p>
&lt;p>しかし、常時稼働のサーバを立ててしまうとコストが大きいため&lt;/p>
&lt;p>こういったデータバックアップのような処理はバッチ実行時のみのスポット稼働が求められます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そこでEC2の出番ということです！&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで今回のサンプル↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * EC2コモンクラス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">EC2Common&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AccessKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSAccessKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SecretKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSSecretKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeySecret__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">final&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>REGION&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>us&lt;span style="color:#0550ae">-&lt;/span>east&lt;span style="color:#0550ae">-&lt;/span>1&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * インスタンスのStart
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">startInstances&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>instanceId&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>StartInstances&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWSAccessKeyId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureMethod&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureVersion&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>InstanceId&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">1&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>instanceId&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2013&lt;span style="color:#0550ae">-&lt;/span>10&lt;span style="color:#0550ae">-&lt;/span>15&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Timestamp&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYY&lt;span style="color:#0550ae">-&lt;/span>MM&lt;span style="color:#0550ae">-&lt;/span>dd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ssZ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ec2&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>REGION&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//ec2.&amp;#39; + REGION + &amp;#39;.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * インスタンスのStop
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">stopInstances&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>instanceId&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>StopInstances&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWSAccessKeyId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureMethod&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureVersion&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>InstanceId&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">1&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>instanceId&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2013&lt;span style="color:#0550ae">-&lt;/span>10&lt;span style="color:#0550ae">-&lt;/span>15&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Timestamp&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYY&lt;span style="color:#0550ae">-&lt;/span>MM&lt;span style="color:#0550ae">-&lt;/span>dd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ssZ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ec2&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>REGION&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//ec2.&amp;#39; + REGION + &amp;#39;.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">base64Encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSSecretKeyId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Wordpressのパーマリンク変更</title><link>https://blog.freedom-man.com/wordpress_permalink.html</link><pubDate>Thu, 27 Feb 2014 00:08:33 +0000</pubDate><guid>https://blog.freedom-man.com/wordpress_permalink.html</guid><description>&lt;p>以前は/%category%/%post_id%/　という形式であったが、&lt;/p>
&lt;p>他のWebサイトでも問題視しているように&lt;/p>
&lt;p>・post_idは投稿時以外（下書き等）でもカウントアップされてしまい歯抜けになる。&lt;/p>
&lt;p>・post_idはサーバー移行をすると移行前後で値が変わってしまうらしい。&lt;/p>
&lt;p>・category変更があった場合にリンク切れを起こす&lt;/p>
&lt;p> &lt;/p>
&lt;p>という大きな問題が有り、まだ投稿数60ちょっとしかない状況だったので&lt;/p>
&lt;p>この際、/%post_name%/というユニークな投稿名を自分で決定する方式に変更した。&lt;/p>
&lt;p> &lt;/p>
&lt;p>それに伴い、以前の/%category%/%post_id%/のパスで来た人を&lt;/p>
&lt;p>/%post_name%/にリダイレクト(301)してあげる必要が出てきた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>色々と調べてきたら.htaccessを自分で書き上げる方法が良さそうだったので共有してみる。&lt;/p>
&lt;p>参考URL↓&lt;/p>
&lt;p>&lt;a href="http://nekonomemo.net/wordpress-permalink-redirect/">http://nekonomemo.net/wordpress-permalink-redirect/&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://webshufu.com/calc-and-get_posts-makes-redirecting-ease/">http://webshufu.com/calc-and-get_posts-makes-redirecting-ease/&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>上記Webサイトに書かれているように、パーマリンク変更前と変更後をリスト出力して&lt;/p>
&lt;p>Excelで&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Redirect permanent /hoge_cateory/xxxx http://freedom-man.com/post_name
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>の形式で出力して.htaccessに記載するだけのシンプルな方法だが、&lt;/p>
&lt;p>私の環境では何故か生成した.htaccessをドキュメントルート直下に置いても動作しなかった。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Redirectが効かないとか有り得ないので、&lt;/p>
&lt;p>httpd.conf及びインクルードしているconfファイルの設定で上書きしているのでは？と思ったら、&lt;/p>
&lt;p>案の定、httpd.confがインクルードしているconf/wordpress.confで&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Alias /blog /var/www/hogehoge/
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>とエイリアスが貼ってあり、/blogはドキュメントルートじゃないところにアクセスしていたので、&lt;/p>
&lt;p>リダイレクトディレクティブを/var/www/hogehoge直下の.htaccessに入れてあげたらちゃんと動作してくれた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、めでたしめでたし。&lt;/p>
&lt;p> &lt;/p></description></item><item><title>SalesforceとSWFの連携【机上の空論編】</title><link>https://blog.freedom-man.com/swf_salesforce.html</link><pubDate>Wed, 26 Feb 2014 23:58:08 +0000</pubDate><guid>https://blog.freedom-man.com/swf_salesforce.html</guid><description>&lt;p>さて、これまでApexからSWFと連携させてきましたが、&lt;/p>
&lt;p>SalesforceとSWFの連携のユースケースについて自由気ままに考えてみます！&lt;/p>
&lt;p>※今回はSWFについてあーだこーだ言う回です。特にまとまっていません。&lt;/p>
&lt;p>SWFでシステムを実装したことないので机上の空論です。&lt;/p>
&lt;p>ということで、ところどころ、おかしいところがあるかもしれませんが、ご容赦くださいm(_ _)m&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. Salesforce内部から外部Webサービスの利用&lt;/strong>&lt;/h3>
ApexからのHTTPコールアウトはガバナ制限があり、
&lt;p>1トランザクション当たりの長時間のコールアウトの対応が難しい。&lt;/p>
&lt;p>※2014/02時点では1トランザクション当たりの合計時間が120秒以内の制限値。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そこで、長時間のコールアウトになる場合、つまり時間がかかるようなタスク処理をさせるには&lt;/p>
&lt;p>HTTPリクエストに対する応答は即座に返し、タスク処理を非同期で実行するような仕組みが必要になる。&lt;/p>
&lt;p>この非同期実行処理はSWFが適しており、&lt;/p>
&lt;p>ApexからのHTTPリクエストはSWFに対してStartWorkflowExecutionを実行し、&lt;/p>
&lt;p>処理を実行するDecider、Workerは処理を実行するサーバ側に立ててあげれば容易に実現できる。&lt;/p>
&lt;p>非同期処理自体はSWF等のクラウドキューサービスがなくてもWorker上に実装できるが、&lt;/p>
&lt;p>SWFを利用する方がスケールアウトしやすく再利用性が向上する。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">ただし、タスク処理自体が同期実行でなければならない場合は、基本的にはSWFは適さない。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. 外部WebサービスからSalesforceを利用する場合&lt;/strong>&lt;/h3>
外部WebサービスからSalesforceのデータを利用する場合は
&lt;p>a. Salesforceのデータを画面表示するような即時利用パターン&lt;/p>
&lt;p>b. Salesforceのデータを別サーバDBに連携するパターン&lt;/p>
&lt;p>c. 別サーバのデータをSalesforceに連携するパターン&lt;/p>
&lt;p>の3パターンが考えられる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">a のような即時利用パターンではSWFのような非同期処理は向いていないので適用不可能。&lt;/span>&lt;/p>
&lt;p>この場合は素直にforce.com canvasとか使ってAPI使っでやるのが吉かと。&lt;/p>
&lt;p> &lt;/p>
&lt;p>b では連携したいSalesforceレコードを、Salesforce側からSWFに投げてもらい&lt;/p>
&lt;p>別サーバがWorkerとしてそのデータを受け取り、タスク処理（連携処理）を実行する方法が考えられる。&lt;/p>
&lt;p>Salesforceではアウトバウンドメッセージという外部連携用の標準機能が存在するが、&lt;/p>
&lt;p>疎結合のメリットを活かすのであれば、エンドポイントを共通化出来るSWFを利用した方法が良い気がする。&lt;/p>
&lt;p> &lt;/p>
&lt;p>c では別サーバ側が作成・更新したいレコード情報をSWFに投げて、&lt;/p>
&lt;p>そのデータをforce.comのApexスケジューラで拾わせてApexクラス側で作成・更新処理を行う。&lt;/p>
&lt;p>単なるデータ同期だけでなく、Webフォームで入力されたデータをSWFを介して&lt;/p>
&lt;p>Workerに処理させることができるので、連携先プラットフォームに変更があっても&lt;/p>
&lt;p>送信元プログラムの変更がないことが利点。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Salesforceへの連携をする上でSWFを利用する共通のメリットとしては、APIコール数を消費しないということ。&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">デメリットとしてはSalesforceをWorkerやDeciderとして動作させるためにはApexスケジューラを利用する&lt;/span>&lt;span style="line-height: 1.5em;">必要があり、&lt;/span>&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">一日あたりのスケジュール実行数等の制限値・ガバナを考慮する必要があるということ。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、cのパターンでWebフォームからの連携を考える場合、エラー時は同期実行、つまり即時でエラーを&lt;/p>
&lt;p>エンドユーザに知らせる必要があるので非同期になるSWFでは適していない。&lt;/p>
&lt;p>エラーハンドリングをWeb側で独自で行ってしまうと、&lt;/p>
&lt;p>入力規則等のSalesforceのカスタマイザブルなビジネスロジックの構築というメリットを損ねてしまう上に&lt;/p>
&lt;p>バリデーション系はモデルに実装すべきというMVCモデルの理想からも離れてしまう。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">また、経験的にAPIコール数も上限を越えるケースがあまり無く、&lt;/span>&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">上限もオプション（追加料金）である程度解決できたりするから&lt;/span>&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">2のパターンにおけるメリットは全体的に微妙かな~とも思ったり。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;p>結局のところ、疎結合・非同期処理と密結合・同期処理という2つの相反する特性を把握した上で&lt;/p>
&lt;p>SWFを利用するか従来型のAPI連携をするかを判断をすべきかと。&lt;/p>
&lt;p>密結合なシステムでも比較的小さなシステムであればそこまで大きな問題にはならない気がする。&lt;/p>
&lt;p>一番大切なのはちゃんと動くシステム。その次に保守性。って感じ？&lt;/p>
&lt;p> &lt;/p>
&lt;p>スケールアウトと再利用性は比較的大きいシステムでこそ大きな力を発揮できるものなのかな～思う。&lt;/p>
&lt;p> &lt;/p>
&lt;p>あと、SWFの基本概念を学んだ印象としては、&lt;/p>
&lt;p>「疎結合・非同期なシステムを作るにはとてもよいサービス」である一方で&lt;/p></description></item><item><title>AWSのSWFについて書いてみる【補足編】</title><link>https://blog.freedom-man.com/swf_using_apex_4.html</link><pubDate>Sat, 22 Feb 2014 22:59:12 +0000</pubDate><guid>https://blog.freedom-man.com/swf_using_apex_4.html</guid><description>&lt;p>&lt;a title="ApexからSWFを触ってみる【ワークフローの終了まで】" href="https://blog.freedom-man.com/swf_using_apex_3/">前回&lt;/a>まではApex(force.com)でSWFを触ってみましたが、今回はSWFに関する補足説明をしていきます！&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;"> &lt;/span>&lt;/p>
&lt;h2>&lt;strong>&lt;span style="line-height: 1.5em;">【イベント登録に関する補足】&lt;/span>&lt;/strong>&lt;/h2>
それぞれのActorがSWFに通知を行うことでワークフローが進むというのが
&lt;p>SWFのおおまかな構造になっていますが、通知を行う毎にワークフロー上には&lt;/p>
&lt;p>イベントが登録されていきます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>イベント登録の流れについては正常系フローに沿って書くと以下のようになります。&lt;/p>
&lt;h3>&lt;strong>1. ワークフローのスタート&lt;/strong>&lt;/h3>
StartWorkflowExecutionを実行すると、
&lt;p>WorkflowExecutionStarted、DecisionTaskScheduledの2つのイベントが登録されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/StartWorkflowExecution.jpg">&lt;img class="alignnone size-medium wp-image-704" alt="StartWorkflowExecution" src="https://blog.freedom-man.com/img/2014/02/StartWorkflowExecution-300x120.jpg" width="300" height="120" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. Decision Taskの取得&lt;/strong>&lt;/h3>
PollForDecisionTaskを実行すると、スケジュールされたDecisionTaskがDeciderによって取得され
&lt;p>DecisionTaskStartedのイベントが登録されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/PollForDecisionTask.jpg">&lt;img class="alignnone size-medium wp-image-703" alt="PollForDecisionTask" src="https://blog.freedom-man.com/img/2014/02/PollForDecisionTask-300x120.jpg" width="300" height="120" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. Decision&amp;ActivityTaskの登録&lt;/strong>&lt;/h3>
RespondDecisionTaskCompleted(ScheduleActivityTaskDecision)を実行すると、
&lt;p>DecisionTaskCompleted、ActivityTaskScheduledのイベントが登録されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/ScheduleActivityTaskDecision.jpg">&lt;img class="alignnone size-medium wp-image-705" alt="ScheduleActivityTaskDecision" src="https://blog.freedom-man.com/img/2014/02/ScheduleActivityTaskDecision-300x120.jpg" width="300" height="120" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>4. Activity Taskの取得&lt;/strong>&lt;/h3>
PollActivityTaskを実行すると、Deciderによって登録されたActivityTaskが
&lt;p>Workerによって取得され、ActivityTaskStartedイベントが登録されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/PollActivityTask.jpg">&lt;img class="alignnone size-medium wp-image-700" alt="PollActivityTask" src="https://blog.freedom-man.com/img/2014/02/PollActivityTask-300x119.jpg" width="300" height="119" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>5. ActivityTaskの実行＆完了通知(DecisionTaskの登録)&lt;/strong>&lt;/h3>
RespondActicityTaskCompletedを実行すると、
&lt;p>ActivityTaskCompleted、DecisionTaskScheduledイベントが登録されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/RespondActicityTaskCompleted.jpg">&lt;img class="alignnone size-medium wp-image-701" alt="RespondActicityTaskCompleted" src="https://blog.freedom-man.com/img/2014/02/RespondActicityTaskCompleted-300x120.jpg" width="300" height="120" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>7. ワークフローの終了通知&lt;/strong>&lt;/h3>
CompleteWorkflowExecutionを実行すると、
&lt;p>DecisionTaskCompleted、WorkflowExecutionCompletedイベントが登録されます。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/CompleteWorkflowExecution.jpg">&lt;img class="alignnone size-medium wp-image-702" alt="CompleteWorkflowExecution" src="https://blog.freedom-man.com/img/2014/02/CompleteWorkflowExecution-300x120.jpg" width="300" height="120" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h2>&lt;strong> 【各種タイムアウトに関する補足】&lt;/strong>&lt;/h2>
&lt;span style="line-height: 1.5em;">タイムアウトは以下の種類があり、WorkflowTypeやActivityType側で&lt;/span>
&lt;p>&lt;span style="line-height: 1.5em;">それぞれ、デフォルト値を設定することができます。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;p>a. ワークフロー本体の開始から終了までの時間(Execution Start to Close timeout)&lt;/p></description></item><item><title>ApexからSWFを触ってみる【ワークフローの終了まで】</title><link>https://blog.freedom-man.com/swf_using_apex_3.html</link><pubDate>Sat, 22 Feb 2014 13:37:29 +0000</pubDate><guid>https://blog.freedom-man.com/swf_using_apex_3.html</guid><description>&lt;p>&lt;a title="ApexからSWFを触ってみる【ActivityTaskのスケジュールまで】" href="https://blog.freedom-man.com/swf_using_apex_2/">前回&lt;/a>はActivityTaskの登録までやったので、今回はワークフローの終了までやります！&lt;/p>
&lt;p>※REST APIの基本的な部分は端折っているので、詳細な部分を知りたい方は&lt;a title="ApexからSWFを触ってみる【REST API説明編】" href="https://blog.freedom-man.com/swf_using_apex/">過去記事&lt;/a>をご参考ください！&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>4. Activity Taskの取得(PollForActivityTask)&lt;/strong>&lt;/h3>
実行ActorはWorkerになります。
&lt;p>Activity TaskListに投げられたActivity Taskを取得します。&lt;/p>
&lt;p> &lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">PollForActivityTask&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>domain&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>identity&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>taskList&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>JSON&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">serialize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>domain&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>domain&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>identity&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>identity&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>taskList&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>taskList&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">});&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>callSWFAPI&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>PollForActivityTask&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>■主要パラメータの説明&lt;/p>
&lt;p>identity&lt;/p>
&lt;p>→どのWorkerが取得しようとしているかを明示する。ワークフロー履歴でTaskを取得したWorkerを特定するためのパラメータ。&lt;/p>
&lt;p>taskList&lt;/p>
&lt;p>→取得先のActivity TaskListを指定。3(ActivityTaskのスケジュール)と同じTask Listを設定すれば、&lt;/p>
&lt;p>3で投げたワークフローのDecision Taskを取得可能。&lt;/p>
&lt;p> &lt;/p>
&lt;p>レスポンスは以下のとおり&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;activityId&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;20140222001&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;activityType&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Step1&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;version&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;1.0&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;input&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Test Message&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;startedEventId&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0550ae">6&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;taskToken&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;AAAAKgAAAAEAAAAAAAAAAvVSh6dDFC0ONKeUJ5V4YZk0vaDKdDleJM44ZuQLyH3himdckWB6mlfE1/h50XB+3s7dRrfohwBLbK5j3e98AbLaUUYvDP6DVv9VTu3AWZK/Yj4groIH8+0dZ92BDv343v//czgLxB4UBv2U4OiDvZLynDv9QXguiSIH6dK6QYF+Dbb6JGHs9taGOkIsreAFYrc4ytRCYhMNJnHb6TQpquPWKMNDHaltFbshHGamQACmF67eBGeonfkD1sk7ERZko00SUbeCY75fI5CFkKTCjS9Q7hRHukWapFVG9+dEKKJ1&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;workflowExecution&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;runId&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;12ZEh2TCxHYJmPaQoN8noi6wgOhyZ0XIhFxxeOdgdpiWI=&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;workflowId&amp;#34;&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;20140222001&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>ApexからSWFを触ってみる【ActivityTaskのスケジュールまで】</title><link>https://blog.freedom-man.com/swf_using_apex_2.html</link><pubDate>Thu, 20 Feb 2014 23:34:07 +0000</pubDate><guid>https://blog.freedom-man.com/swf_using_apex_2.html</guid><description>&lt;p>&lt;a title="ApexからSWFを触ってみる【REST API説明編】" href="https://blog.freedom-man.com/swf_using_apex/" target="_blank">前回&lt;/a>はREST APIのSignature生成とAPIコールの基本的なところを説明したので、今回は実際にSWFをApexから触ってみます！&lt;/p></description></item><item><title>ApexからSWFを触ってみる【REST API説明編】</title><link>https://blog.freedom-man.com/swf_using_apex.html</link><pubDate>Tue, 18 Feb 2014 01:44:06 +0000</pubDate><guid>https://blog.freedom-man.com/swf_using_apex.html</guid><description>&lt;p>前回、SWFの概要を説明しましたが、きっと私の説明力不足により&lt;/p>
&lt;p>よくわからなかったと思うので、今回からは実際にApexからSWFを触ってみて挙動を確認します。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ApexでSWFを動かすには例のごとくSDKは存在しないので、&lt;/p>
&lt;p>直接&lt;a title="http://docs.aws.amazon.com/amazonswf/latest/developerguide/UsingJSON-swf.html" href="http://docs.aws.amazon.com/amazonswf/latest/developerguide/UsingJSON-swf.html">REST API&lt;/a>をコールする必要があります。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、今日はREST APIをApexからコールするところのベース（Signature生成）を説明します！&lt;/p>
&lt;p> &lt;/p>
&lt;p>さて、AWS REST API恒例のSignature生成ですが、&lt;/p>
&lt;p>SimpleDBのSignature Version2やDynamoDBのSignature Version4と異なり、&lt;/p>
&lt;p>Signature Version3という署名認証方式で行われます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Signature Version3は以下の形式で生成します。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>Canonicalヘッダ&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;ヘッダ1:値1\n&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;ヘッダ2:値2&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">...;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;HTTPメソッド名\n&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;リソースのパス\n&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;クエリパラメータ\n&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;Canonicalヘッダ\n&amp;#34;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#34;HTTPリクエストのBody&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>hmac&lt;span style="color:#1f2328">(&lt;/span>digest&lt;span style="color:#1f2328">(&lt;/span>string_to_sign&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>Apexのサンプルは以下のとおり&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">//Signatureの生成&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>header_map&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>postBody&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>createCanonicalHeaders&lt;span style="color:#1f2328">(&lt;/span>header_map&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>string_to_sign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>postBody&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>System&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>string_to_sign&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>b_sig&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateDigest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>string_to_sign&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>AWSAccessKeySecret&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">base64Encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>b_sig&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">//Canonicalヘッダの生成&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createCanonicalHeaders&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>headers&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">isEmpty&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>lowerCaseHeaders&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>lowerCaseHeaders&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>getSortedList&lt;span style="color:#1f2328">(&lt;/span>lowerCaseHeaders&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;:&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>lowerCaseHeaders&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">trim&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;\n&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>AWSのSWFについて書いてみる【概要と用語編】</title><link>https://blog.freedom-man.com/aws_swf.html</link><pubDate>Sun, 16 Feb 2014 22:55:21 +0000</pubDate><guid>https://blog.freedom-man.com/aws_swf.html</guid><description>&lt;p>最近、疎結合なシステム構築のためのサービスであるAWSの&lt;a title="http://aws.amazon.com/jp/sqs/" href="http://aws.amazon.com/jp/sqs/">SQS&lt;/a>、&lt;a title="http://aws.amazon.com/jp/swf/" href="http://aws.amazon.com/jp/swf/">SWF&lt;/a>に興味を持ったので触ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>SQSは何でも色々できるけど、プログラムで制御しないと正常に動作しない部分が多くて、&lt;/p>
&lt;p>SWFは疎結合なシステムをSQSより簡単に(?)構築できるらしい。（参考URLは&lt;a title="http://aws.amazon.com/jp/swf/faqs/" href="http://aws.amazon.com/jp/swf/faqs/">こちら&lt;/a>）&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;">ということで、今回はSWFのお話。&lt;/span>&lt;/p>
&lt;p> &lt;/p>
&lt;p>といっても、私自身SWFを利用してのシステム構築は残念ながらまだない上に&lt;/p>
&lt;p>SWFのお勉強3日目くらいのドシロートで、これから書く記事は机上の空論だったり、&lt;/p>
&lt;p>そもそも誤った解釈があるかもしれませんが、そこらへんはご容赦を。&lt;/p>
&lt;p>というかご指摘いただくと泣いて喜びます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>最後にSWFの用語をずらずらーっと並べて書いたのでそちらもご覧くださいませ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、SWFの話ですが、以下のリンク先のように既に色々と解説されているので、&lt;/p>
&lt;p>まずはそちらをご覧頂いたほうが理解が早いかもｗ&lt;/p>
&lt;p>&lt;a title="http://dev.classmethod.jp/cloud/aws/introduction-to-amazon-simple-workflow-service/" href="http://dev.classmethod.jp/cloud/aws/introduction-to-amazon-simple-workflow-service/">&lt;a href="http://dev.classmethod.jp/cloud/aws/introduction-to-amazon-simple-workflow-service/">http://dev.classmethod.jp/cloud/aws/introduction-to-amazon-simple-workflow-service/&lt;/a>&lt;/a>
&lt;a title="http://www.slideshare.net/AmazonWebServicesJapan/20130424-aws-meisterregenerateswfpublic" href="http://www.slideshare.net/AmazonWebServicesJapan/20130424-aws-meisterregenerateswfpublic">&lt;a href="http://www.slideshare.net/AmazonWebServicesJapan/20130424-aws-meisterregenerateswfpublic">http://www.slideshare.net/AmazonWebServicesJapan/20130424-aws-meisterregenerateswfpublic&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>簡単に言うとSWFはワークフローの各タスクを疎結合にするための仕組みを提供するサービス。&lt;/p>
&lt;p> &lt;/p>
&lt;p>SWFではTaskList（キュー）に各々のタスクをスケジュールし、&lt;/p>
&lt;p>タスク処理をするアプリ(Activity Worker)やビジネスロジックを制御するアプリ(Decider)が&lt;/p>
&lt;p>それぞれのTaskListにポーリングを行い、各々のタスクを取得後、処理結果を登録し、&lt;/p>
&lt;p>次のタスクをスケジューリングするという流れでワークフローの処理を進めていく仕組みになっている。&lt;/p>
&lt;p> &lt;/p>
&lt;p>具体的には&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Starterがワークフローをスタート＆Decision Task(Decider用のタスク)のスケジュール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>DeciderがTaskListにポーリングしてタスクを取得&lt;/p>
&lt;/li>
&lt;li>
&lt;p>2のDeciderが過去のタスクの実行履歴を参照して、Activity Task(Activity Worker用のタスク)をスケジュール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Activity WorkerがTaskListにポーリングしてタスクを取得&lt;/p>
&lt;/li>
&lt;li>
&lt;p>4のActivity Workerがタスク情報を参照して、タスクを実行し、Decision Taskをスケジュール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>2～5を繰り返して、ワークフローを進める&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Deciderがワークフロー終了条件を満たしたと判断した場合、ワークフローを終了する&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>というようなフローになる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>SWFが提供しているTaskListを介することで、各々のWorker（アプリ）が&lt;/p>
&lt;p>SWFと密結合になるものの、Worker同士は疎結合になる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>疎結合になると再利用性や、スケーラビリティが向上する上に&lt;/p>
&lt;p>SWFがTaskListというキューのみを提供しているという特性上、&lt;/p>
&lt;p>HTTP接続が出来れば、SWFを利用するデバイスの種類や場所（クラウドかオンプレか）を問わないので&lt;/p>
&lt;p>より柔軟な構成にしやすい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、別ワークフローへのコンポーネント再利用やスケールアウトは&lt;/p>
&lt;p>EC2のAMIを使ってサーバーの複製が簡単にできるため、SWFはEC2と相性が良かったりする。&lt;/p>
&lt;p> &lt;/p>
&lt;p>設計例として、あるシステムから他の外部システムにPDF生成処理を要求するワークフローを考えてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>PDF生成処理システムが公開しているAPIを介してリクエストを送る設計だと、&lt;/p>
&lt;p>PDF生成処理システムをスケールアウトする場合には&lt;/p>
&lt;p>生成要求（HTTPコールアウト）に対してロードバランサーやリバースプロキシで&lt;/p>
&lt;p>処理を振り分ける設計にする必要がある。&lt;/p>
&lt;p> &lt;/p>
&lt;p>さらに、PDF生成処理システムのAPIエンドポイントが変わったり、&lt;/p>
&lt;p>&amp;ldquo;要求前に要求内容を上長が確認する&amp;quot;等のビジネスロジックの変更があると&lt;/p>
&lt;p>要求元のプログラムを変更しなければならない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これはビジネスロジックや結合先システムに依存してしまう&lt;/p>
&lt;p>密結合なシステムになっていることに起因している。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これをSWFを介して連携するように実装をすると&lt;/p>
&lt;p>・スケールアップ&lt;/p>
&lt;p>→コールアウト先はSWFになり変更の必要がない。&lt;/p>
&lt;p>また、PDF生成の要求内容（タスク）は要求先システムによるポーリングで取得されるため&lt;/p>
&lt;p>ポーリング＆タスク処理を行うサーバーを単純に複製しても正常に動く（スケールアウトが容易）。&lt;/p>
&lt;p> &lt;/p>
&lt;p>・APIエンドポイントの変更&lt;/p>
&lt;p>→要求先のシステムに依存しないため、変更の必要がない。（SWFがエンドポイント）&lt;/p>
&lt;p> &lt;/p>
&lt;p>・ビジネスロジックの変更&lt;/p>
&lt;p>→要求後に行う処理はDeciderが決定する為、Deciderのプログラムを新しいビジネスロジックに変更すれば良く、&lt;/p>
&lt;p>要求元、要求先プログラムの変更の必要がない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>といったように、疎結合の恩恵が得られる。&lt;/p>
&lt;p>またこういった疎結合なシステム構築により並列・結合処理を実装することも容易になる。&lt;/p>
&lt;p>その場合も、ビジネスロジックを制御するDecider側プログラムの修正のみになるため&lt;/p>
&lt;p>既存のタスク処理を変更する必要がない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみにSWFコンソールで実行できるサンプルプログラムは&lt;/p>
&lt;p>1つのEC2インスタンスがStarter, Decider, Activity Workerを兼任していて、&lt;/p></description></item><item><title>JavaScript Remoting利用時のエラー</title><link>https://blog.freedom-man.com/forcecom_javascript_remoting_error.html</link><pubDate>Sat, 15 Feb 2014 20:17:51 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_javascript_remoting_error.html</guid><description>&lt;p>force.com開発でAjax使いたいときに重宝する&lt;a title="http://www.salesforce.com/us/developer/docs/pages/Content/pages_js_remoting.htm" href="http://www.salesforce.com/us/developer/docs/pages/Content/pages_js_remoting.htm">JavaScript Remoting&lt;/a>だが、&lt;/p>
&lt;p>コンソール上で以下のエラーが出て動かなくなってしまった。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/JSRemotingError.jpg">&lt;img class="alignnone size-medium wp-image-647" alt="JSRemotingError" src="https://blog.freedom-man.com/img/2014/02/JSRemotingError-300x42.jpg" width="300" height="42" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>エラーメッセージは&lt;/p>
&lt;p>&amp;ldquo;Visualforce Remoting Exception: Method &amp;lsquo;ScheduleActivityTaskDecision&amp;rsquo; not found on controller SWFTestController. Check spelling, method exists, and/or method is RemoteAction annotated. &amp;quot;&lt;/p>
&lt;p>って書いてあるが、@RemoteActionちゃんとつけてるし、クラスもメソッドもちゃんと存在しているし&lt;/p>
&lt;p>VF呼び出し側には{!$RemoteAction.[controller].[method]}の形式で&lt;/p>
&lt;p>グローバル変数使った書き方してて、コンパイルもちゃんと通る。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ハマりの住人になりかけたが、Google様が以下のWebサイトを紹介してくれました。&lt;/p>
&lt;p>&lt;a title="https://developer.salesforce.com/forums/ForumsMain?id=906F000000097OUIAY" href="https://developer.salesforce.com/forums/ForumsMain?id=906F000000097OUIAY">&lt;a href="https://developer.salesforce.com/forums/ForumsMain?id=906F000000097OUIAY">https://developer.salesforce.com/forums/ForumsMain?id=906F000000097OUIAY&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a title="http://enreeco.blogspot.jp/2013/01/apex-javascript-what-is-remoteaction.html" href="http://enreeco.blogspot.jp/2013/01/apex-javascript-what-is-remoteaction.html">&lt;a href="http://enreeco.blogspot.jp/2013/01/apex-javascript-what-is-remoteaction.html">http://enreeco.blogspot.jp/2013/01/apex-javascript-what-is-remoteaction.html&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>つまりは、定義されていない変数使うとこのエラーが出るっぽい。&lt;/p>
&lt;p>boolean型のパラメータにnullを入れてもダメって書いてあったけど、私のところでは再現せず…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみに私はｊQueryで$(&amp;quot;#hogehoge&amp;rdquo;).val()で値を取得しようとしたのは良いものの&lt;/p>
&lt;p>存在しないIDを指定してたからでしたorz&lt;/p></description></item><item><title>force.com REST APIのOAuthエンドポイント</title><link>https://blog.freedom-man.com/forcecom_rest_oauth_endpoint.html</link><pubDate>Thu, 13 Feb 2014 01:45:00 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_rest_oauth_endpoint.html</guid><description>&lt;p>foce.comのREST APIではOAuth2.0を利用することができるが、&lt;/p>
&lt;p>Salesforce環境やユーザによってOAuthのエンドポイントが異なっていたのでメモる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>基本的には認可のエンドポイントは&lt;/p>
&lt;p>https://[domain]/services/oauth2/authorize&lt;/p>
&lt;p>トークン発行のエンドポイントは&lt;/p>
&lt;p>https://[domain]/services/oauth2/token&lt;/p>
&lt;p>となっており、[domain]の部分がSalesforce環境やログインユーザによって変わってくる感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. 環境によるエンドポイントの違い&lt;/strong>&lt;/h3>
■Developer環境・本番環境
&lt;p>→login.salesforce.com&lt;/p>
&lt;p> &lt;/p>
&lt;p>■Sandbox環境&lt;/p>
&lt;p>→test.salesforce.com&lt;/p>
&lt;p> &lt;/p>
&lt;p>■私のドメイン設定時&lt;/p>
&lt;p>→私のドメインの値。&lt;/p>
&lt;p>上記の環境によるドメイン値も利用できるが、&lt;/p>
&lt;p>「https://login.salesforce.comからのログインを防止」にチェックがついていると&lt;/p>
&lt;p>ログインされていない状態の場合は、認証画面でログインできないので&lt;/p>
&lt;p>素直に私のドメインをエンドポイントにした方が良い。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/mydomain.jpg">&lt;img class="alignnone size-medium wp-image-640" alt="mydomain" src="https://blog.freedom-man.com/img/2014/02/mydomain-300x100.jpg" width="300" height="100" />&lt;/a>&lt;/p>
&lt;p>&lt;span style="line-height: 1.5em;"> &lt;/span>&lt;/p>
&lt;h3>&lt;strong>2. ポータル・コミュニティユーザの場合&lt;/strong>&lt;/h3>
■ポータル
&lt;p>→ポータルに紐付けたSitesを設定し、そのSitesのドメイン名をエンドポイントにする。&lt;/p>
&lt;p>基本的にポータルのログイン画面は&lt;/p>
&lt;p>https://[domain]/secur/login_portal.jsp?orgId=[orgId]&amp;amp;portalId=[portalId]&lt;/p>
&lt;p>の形式になっており、通常のSalesforceのログイン画面ではログインできないため、&lt;/p>
&lt;p>Sitesのドメインを介してログインする方式。&lt;/p>
&lt;p> &lt;/p>
&lt;p>詳細は&lt;a title="http://blogs.developerforce.com/developer-relations/2013/02/oauth-for-portal-users.html" href="http://blogs.developerforce.com/developer-relations/2013/02/oauth-for-portal-users.html">こちら&lt;/a>から。&lt;/p>
&lt;p>ちなみにSOAP APIではorganizationIdやportalIdを設定可能。&lt;/p>
&lt;p> &lt;/p>
&lt;p>■コミュニティ&lt;/p>
&lt;p>→コミュニティで設定したドメイン名。&lt;/p>
&lt;p>こちらはポータルと違ってドメイン名を設定が必須なので、Sitesを使う必要はない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ポータルのSites設定方式は面倒なので、出来れば新機能のコミュニティに寄せたい感じ。&lt;/p>
&lt;p>そもそも新規の環境ではコミュニティ使えないはずだし。&lt;/p></description></item><item><title>apex:Messageの挙動について調べてみる</title><link>https://blog.freedom-man.com/forcecom_apexmessage.html</link><pubDate>Wed, 12 Feb 2014 01:59:39 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_apexmessage.html</guid><description>&lt;p>force.comでフォーム的な画面を作ることはよくあると思いますが&lt;/p>
&lt;p>その際に&lt;a href="apex:inputField">apex:inputField&lt;/a>とかでVFを組んでると、必須項目の制約とかメールアドレスの形式チェックとか&lt;/p>
&lt;p>Salesforceのシステムバリデーションが効いてくれる上に&lt;/p>
&lt;p>型に合わせてhtmlを生成してくれるから日付型とか使うときに便利だったりします。&lt;/p>
&lt;p> &lt;/p>
&lt;p>が、&lt;a href="apex:inputField">apex:inputField&lt;/a>でシステムが出すバリデーションは&amp;quot;エラー: 値を入力してください&amp;quot;&lt;/p>
&lt;p>というように決められた文言でしか出すことができずエラーを出す位置も決まってしまうため&lt;/p>
&lt;p>Salesforceのオペレータ側ではなく対顧客に対するフォームを作成するときには&lt;/p>
&lt;p>デザイン・UI的にちょっと難が…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そこで&lt;a href="apex:message">apex:message&lt;/a>というのを使ってみようと思ったけど、&lt;/p>
&lt;p>色々と苦戦した挙句、挙動が？だったので、ちょっと書いてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>パターン1. &lt;apex:inputField>のみ&lt;/strong>&lt;/h3>
検証用VFページ↓
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:inputField&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!acc.Name}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;空送信&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>以下のように固定のエラーメッセージが出る。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/919854bb99f89066ab079adc81a87a43.jpg">&lt;img class="alignnone size-full wp-image-627" alt="inputfieldのみ" src="https://blog.freedom-man.com/img/2014/02/919854bb99f89066ab079adc81a87a43.jpg" width="214" height="85" />&lt;/a>&lt;/p>
&lt;p>このメッセージを自由に変更して、自由な位置に出力したい！というのが今回の趣旨。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>パターン2. &lt;apex:inputField> + &lt;apex:message/>&lt;/strong>&lt;/h3>
では実際にmessageタグを使ってみる。
&lt;p>検証用VF↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:inputField&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Field&amp;#34;&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!acc.Name}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:message&lt;/span> &lt;span style="color:#1f2328">for&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Field&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;空送信&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こうすると、inputFieldタグが出すエラーメッセージと&lt;/p>
&lt;p>messageタグが出すエラーメッセージで2重に出力されちゃう。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/inputfield_message.jpg">&lt;img class="alignnone size-full wp-image-626" alt="inputfield_message" src="https://blog.freedom-man.com/img/2014/02/inputfield_message.jpg" width="243" height="89" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>パターン3. &lt;apex:inputField> + &lt;apex:message/> + commandButtonのimmediate&lt;/strong>&lt;/h3>
SalesforceのSystemバリデーションを走らせないで送信したらどうなるかを検証。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span> &lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:inputField&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Field&amp;#34;&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!acc.Name}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:message&lt;/span> &lt;span style="color:#1f2328">for&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Field&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">immediate&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;空送信&amp;#34;&lt;/span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;span style="line-height: 1.5em;">結果、commandButtonのactionで何もしていないせいか何も出力されず…。&lt;/span>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/02/1dedb41ac917d118b278e78d139c00b2.jpg">&lt;img class="alignnone size-full wp-image-630" alt="空送信フォーム" src="https://blog.freedom-man.com/img/2014/02/1dedb41ac917d118b278e78d139c00b2.jpg" width="189" height="63" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>パターン4. &lt;apex:inputField> + &lt;apex:message > + immediate + action指定&lt;/strong>&lt;/h3>
実際にアクションでインサートしてエラーをキャッチしてページにエラーメッセージを出してみる。
&lt;p>検証用VF↓&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span> &lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:pageMessages&lt;/span> &lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:inputField&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Field&amp;#34;&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!acc.Name}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:message&lt;/span> &lt;span style="color:#1f2328">for&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Field&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">apex:commandButton&lt;/span> &lt;span style="color:#1f2328">immediate&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;true&amp;#34;&lt;/span> &lt;span style="color:#1f2328">value&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;インサート&amp;#34;&lt;/span> &lt;span style="color:#1f2328">action&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{!testMessage}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">apex:form&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>検証用Apexクラス↓&lt;/p></description></item><item><title>AWS CLIを使ったS3の超簡単バックアップ</title><link>https://blog.freedom-man.com/s3_backup_using_awscli.html</link><pubDate>Tue, 11 Feb 2014 11:18:32 +0000</pubDate><guid>https://blog.freedom-man.com/s3_backup_using_awscli.html</guid><description>&lt;p>業務でS3を使うことが多くなったが、&lt;/p>
&lt;p>S3自体の耐久性は99.999999999%(イレブンナイン)なので問題無いとしても&lt;/p>
&lt;p>プログラムやAWSコンソール画面で”うっかり削除しちゃった”系のミスがあったときに&lt;/p>
&lt;p>バケットごとバックアップする機能があったら便利だなーと思って&lt;/p>
&lt;p>&lt;a title="http://aws.amazon.com/jp/cli/" href="http://aws.amazon.com/jp/cli/">AWS CLI&lt;/a>のS3のサブコマンド見てたらあったので紹介！&lt;/p>
&lt;p>詳細は&lt;a title="http://docs.aws.amazon.com/cli/latest/reference/s3/sync.html" href="http://docs.aws.amazon.com/cli/latest/reference/s3/sync.html">こちら&lt;/a>から。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. S3のバケット内のオブジェクトをローカルPCにバックアップ&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#aws s3 sync [s3 path] [local path]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>aws s3 sync s3://mybucket /home/user/s3backup
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>用途としてはバックアップというよりは、&lt;/p>
&lt;p>&amp;ldquo;S3からデータを一括で引っ張ってきて加工して再アップロード&amp;rdquo;&lt;/p>
&lt;p>みたいなことをするときに便利。&lt;/p>
&lt;p>オブジェクトキーのセパレータがスラッシュ(/)の場合は自動的にディレクトリを作って階層構造にしてくれる。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. S3のバケット内のデータを別のバケットにバックアップ&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#aws s3 sync [s3 path&amp;lt;from&amp;gt;] [s3 path&amp;lt;to&amp;gt;]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>aws s3 sync s3://mybucket s3://backup
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>バックアップに使える以外には、テスト環境と本番環境のデータを同期する時など&lt;/p>
&lt;p>複製して使いたい場合に有効。&lt;/p>
&lt;p>異なるリージョン間でも同期できたので、S3を使っててレイテンシを考慮する場合は使えるかも！？&lt;/p>
&lt;p>S3使っててレイテンシ考慮するケースってほとんど&lt;a title="http://aws.amazon.com/jp/cloudfront/" href="http://aws.amazon.com/jp/cloudfront/">CloudFront &lt;/a>使っちゃうと思うけど…。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. ローカルのデータをS3にバックアップ&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#aws s3 sync [local path] [s3 path]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>aws s3 sync /home/user/data s3://mybucket
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>バックアップのクラウドのデータストレージとしてS3を利用する場合に有効。&lt;/p>
&lt;p>&amp;ndash;deleteオプションを付けるとローカルに存在しないファイルは自動的にS3バケット上で削除してくれる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>うまく使えば簡易的なDropbox的なこともできるかも！？&lt;/p>
&lt;p> &lt;/p>
&lt;p>こんな感じでAWS CLIは簡単にインストールできて、簡単に使えて&lt;/p>
&lt;p>bashに組み込めるから少々テクニカルなこともできちゃうのでオススメです！&lt;/p></description></item><item><title>herokuのpostgreSQLへのデータ移行</title><link>https://blog.freedom-man.com/heroku_datamigration_postgresql.html</link><pubDate>Tue, 28 Jan 2014 23:59:22 +0000</pubDate><guid>https://blog.freedom-man.com/heroku_datamigration_postgresql.html</guid><description>&lt;p>herokuからpostgreSQLのデータ移行の方法をまとめてみる。&lt;/p>
&lt;p>方法としては以下の２つがあるみたい。&lt;/p>
&lt;ol>
	&lt;li>pg:pushでローカルのレコードまるごとインポート&lt;/li>
	&lt;li>標準入力からpsqlコマンドでインポート&lt;/li>
&lt;/ol>
&lt;h3>&lt;strong>1. pg:pushを使う&lt;/strong>&lt;/h3>
この方法はローカルのpostgreSQLデータベースのデータをそのままherokuに反映するような方法。
&lt;p>具体的には&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>heroku pg:reset DATABASE_URL
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">PGUSER&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>postgres　heroku pg:push &lt;span style="color:#0550ae">[&lt;/span>MyLocalDBName&lt;span style="color:#0550ae">]&lt;/span> DATABASE_URL
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>とheroku側のDBをリセットして、ローカルのDBをインポートする感じ。&lt;/p>
&lt;p>この方法の詳細は&lt;a title="https://devcenter.heroku.com/articles/heroku-postgresql" href="https://devcenter.heroku.com/articles/heroku-postgresql">こちら&lt;/a>から。&lt;/p>
&lt;h3>&lt;strong>2. ローカルDBのdumpからリストアする。&lt;/strong>&lt;/h3>
ローカルDBのdumpを作成し、s3等のWebリソースに置き、heroku側postgreSQLからこのdumpを使ってリストアする方式。
&lt;p>s3とかのオープンなスペースに置くとなると一時的とはいえセキュリティ的にどうなの？って印象。&lt;/p>
&lt;p>詳細は&lt;a title="https://devcenter.heroku.com/articles/heroku-postgres-import-export#import" href="https://devcenter.heroku.com/articles/heroku-postgres-import-export#import">こちら&lt;/a>。&lt;/p>
&lt;h3>&lt;strong>3. psqlからインポート&lt;/strong>&lt;/h3>
psqlコマンドでherokuのpostgreSQLにログインして、インポート対象のCSVファイルに対してcopyコマンドを打つと、herokuのpostgresユーザがsuperuserでない為に「ローカルからファイルを読み込めない」的なエラーになってしまう。
&lt;p>ただし、標準入力からだといけるので&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat &lt;span style="color:#0550ae">[&lt;/span>target csv file path&lt;span style="color:#0550ae">]&lt;/span> &lt;span style="color:#1f2328">|&lt;/span> psql -U &lt;span style="color:#0550ae">[&lt;/span>heroku user name&lt;span style="color:#0550ae">]&lt;/span> &lt;span style="color:#0a3069">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">&lt;/span>-W -h &lt;span style="color:#0550ae">[&lt;/span>heroku host name&lt;span style="color:#0550ae">]&lt;/span> &lt;span style="color:#0550ae">[&lt;/span>heroku db name&lt;span style="color:#0550ae">]&lt;/span> -c &lt;span style="color:#0a3069">&amp;#34;copy hoge(fuga1, fuga2, fuga3) from stdin with csv&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>とやればインポート可能。&lt;/p>
&lt;p>herokuのホスト名やユーザ名等はherokuのpostgreSQL設定画面から取得する。&lt;/p>
&lt;p>参考URLは&lt;a title="http://siguniang.wordpress.com/2013/02/07/heroku-postgresql-python-psycopg2/" href="http://siguniang.wordpress.com/2013/02/07/heroku-postgresql-python-psycopg2/">こちら&lt;/a>。&lt;/p>
&lt;p>ところで、一括更新する場合（例えばマスタの更新とか）ってどうするんだろ？&lt;/p></description></item><item><title>Salesforce開発を効率化するUserScriptを作ってみた。</title><link>https://blog.freedom-man.com/userscript_salesforce_development.html</link><pubDate>Sun, 26 Jan 2014 21:24:34 +0000</pubDate><guid>https://blog.freedom-man.com/userscript_salesforce_development.html</guid><description>&lt;p>いや、言うほど効率化しないですがｗ&lt;/p></description></item><item><title>ApexからSharepointのREST APIを触ってみる。</title><link>https://blog.freedom-man.com/sharepoint_using_apex.html</link><pubDate>Sat, 25 Jan 2014 00:34:06 +0000</pubDate><guid>https://blog.freedom-man.com/sharepoint_using_apex.html</guid><description>&lt;p>毎度恒例Apexから触ってみるシリーズ。
&lt;a title="SharepointのREST APIのリファレンスが不親切だったので簡潔に(?)書いてみる。" href="https://blog.freedom-man.com/sharepoint_restapi/" target="_blank">前回&lt;/a>はSharepointのREST APIの解説をしたので、今回は実際にApexからコールしてみます。&lt;/p></description></item><item><title>SharepointのREST APIのリファレンスが不親切だったので簡潔に(?)書いてみる。</title><link>https://blog.freedom-man.com/sharepoint_restapi.html</link><pubDate>Tue, 21 Jan 2014 00:23:24 +0000</pubDate><guid>https://blog.freedom-man.com/sharepoint_restapi.html</guid><description>&lt;p>MicrosoftのサービスのSharepointにREST APIで接続しようとリファレンス見たら、全然わからなかったので、簡潔に書いてみます。&lt;/p></description></item><item><title>WindowsからSambaに繋ごうと思ったらクソハマった話</title><link>https://blog.freedom-man.com/samba_from_windows.html</link><pubDate>Sat, 11 Jan 2014 23:42:03 +0000</pubDate><guid>https://blog.freedom-man.com/samba_from_windows.html</guid><description>&lt;p>WindowsからSambaサーバ(VM)に繋ごうとしたときにクソハマったのでそのお話。&lt;/p></description></item><item><title>ApexからSTS触ってみる。</title><link>https://blog.freedom-man.com/sts_using_apex.html</link><pubDate>Wed, 08 Jan 2014 00:50:59 +0000</pubDate><guid>https://blog.freedom-man.com/sts_using_apex.html</guid><description>&lt;p>例のごとくApexから&lt;a title="http://docs.aws.amazon.com/STS/latest/UsingSTS/Welcome.html" href="http://docs.aws.amazon.com/STS/latest/UsingSTS/Welcome.html">STS&lt;/a>を触ってみました。&lt;/p></description></item><item><title>SalesforceからAWSにAssumeRoleWithSAMLをコールするときの注意点</title><link>https://blog.freedom-man.com/salesforce_aws_assumerolewithsaml.html</link><pubDate>Sun, 05 Jan 2014 21:40:27 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce_aws_assumerolewithsaml.html</guid><description>&lt;p>&lt;a title="http://wiki.developerforce.com/page/Configuring-SAML-SSO-to-AWS" href="http://wiki.developerforce.com/page/Configuring-SAML-SSO-to-AWS">この記事&lt;/a>を参考にSalesforceからAWSにSAMLAssertionを投げて、AWSのコンソール画面にシングルサインオンするっていうのは出来たが、対象のRoleの一時的なAccessKeyIdやSecretAccessKeyを取得するためのAssumeRoleWithSAML のREST APIが通そうとしたところ、こんな感じのエラーが出てしまった。&lt;/p></description></item><item><title>SNSのHTTP通知のハンドラーをforce.com Sitesで作ってみる。</title><link>https://blog.freedom-man.com/sns_httphandler_using_forcecom_sites.html</link><pubDate>Sat, 04 Jan 2014 12:21:07 +0000</pubDate><guid>https://blog.freedom-man.com/sns_httphandler_using_forcecom_sites.html</guid><description>&lt;p>SNSのHTTP通知ハンドラーをforce.com Sitesで作って、HTTP通知の中でTwilio API呼び出してSMS送信するような処理を作ってみました。&lt;/p>
&lt;p>SNSからSMS送信できるのは米国の電話番号だけっぽいので日本の電話番号に対応できるように、Twilio API経由でSMS送信するっていうのが目的。&lt;/p></description></item><item><title>SitesでanonymousなREST APIをコールする。</title><link>https://blog.freedom-man.com/forcecom_sites_anonymous_rest.html</link><pubDate>Fri, 03 Jan 2014 12:02:51 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_sites_anonymous_rest.html</guid><description>&lt;p>SNS(AWS)のHTTPハンドラーとしてforce.com Sitesを使おうと思って、Visualforce + Apexで試行錯誤したものの、PageReferenceのgetParametersはhttpのrequestBodyを取ってくるわけじゃなく、key=value形式のパラメータしか取ってこれません。つまりVFを使った方法だとJSONをrequestBodyに持ってくるようなSNSのNotificationには対応していません。&lt;/p></description></item><item><title>Salesforceのパッケージインストール時の謎のエラーについて</title><link>https://blog.freedom-man.com/salesforce_package_install_error.html</link><pubDate>Fri, 03 Jan 2014 00:41:38 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce_package_install_error.html</guid><description>&lt;p>&lt;a title="https://tajitsu-test-developer-edition.my.salesforce.com/packaging/installPackage.apexp?p0=04t30000000Ojst" href="https://tajitsu-test-developer-edition.my.salesforce.com/packaging/installPackage.apexp?p0=04t30000000Ojst">AWSのToolkit&lt;/a>とか&lt;a title="https://login.salesforce.com/packaging/installPackage.apexp?p0=04ti0000000XkE0" href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04ti0000000XkE0">Twilioのライブラリ&lt;/a>をインストールしようとしたときに、&lt;/p>
&lt;p>あるDeveloper環境ではエラーが起きてインストールできず、他の環境ではインストール出来るという&lt;/p>
&lt;p>謎の現象が起きてしまった。&lt;/p>
&lt;p> &lt;/p>
&lt;p>パッケージインストールでは詳細なエラーメッセージが出ないっぽいので&lt;/p>
&lt;p>インストールできた他の環境からインストールしたい対象の環境に対して&lt;/p>
&lt;p>パッケージのコンポーネントを丸ごとデプロイしてみて、エラーが出るか確認。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そしたら、以下のエラーメッセージが出てデプロイ失敗しました。&lt;/p>
&lt;p>[Test.isRunningTest method does not exist]&lt;/p>
&lt;p> &lt;/p>
&lt;p>「いやいや、Test.isRunningTestはメソッドとして存在するでしょ。」&lt;/p>
&lt;p>「他の環境でインストールできているってことはapex versionも問題ないだろうし。」&lt;/p>
&lt;p>とか小賢しいこと思って色々調べたらdeveloer forumにこんな記事が…。&lt;/p>
&lt;p>&lt;a href="https://developer.salesforce.com/forums?id=906F00000008zvnIAA">&lt;a href="https://developer.salesforce.com/forums?id=906F00000008zvnIAA">https://developer.salesforce.com/forums?id=906F00000008zvnIAA&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、testっていうクラスがあったせいでした。そりゃそうだよな…。&lt;/p>
&lt;p>apexは大文字小文字区別しないからtestであろうとTestであろうと見事に引っかかります。&lt;/p>
&lt;p>testクラスからTestApexクラスに変更したら無事インストール出来ました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Developer環境でTest.isRunningTestを使ってなかったし、&lt;/p>
&lt;p>そもそも検証用環境だからテストクラス回したりなんて滅多にしないから気付かなかった…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみにTest.isRunningTest()じゃなくてSystem.Test.isRunningTest()っていう風に&lt;/p>
&lt;p>Systemっていう名前空間的なものをつけてあげれば既存のTestっていうクラスを消さずにもイケるっぽい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Testっていうクラスに&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>Boolean&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">isRunningTest&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>System&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Test&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">isRunningTest&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>っていうメソッド持たせるのもOK。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はパッケージであんまりコードを修正したくなかったし、&lt;/p>
&lt;p>Testっていうクラスをリネームしても問題なかったので良かったけど&lt;/p>
&lt;p>どうしてもリネームできない理由があるのであれば上記2つの手段を使うのもOKだと思います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>どんな組織にも入れることが出来るようなパッケージを作る場合は&lt;/p>
&lt;p>パッケージのクラスのSystemっていう名前空間がつくものには全てSystem名前空間を付与した方が良さそう。&lt;/p></description></item><item><title>ApexからTwilio APIを叩く！</title><link>https://blog.freedom-man.com/twilio_using_apex.html</link><pubDate>Thu, 02 Jan 2014 18:19:28 +0000</pubDate><guid>https://blog.freedom-man.com/twilio_using_apex.html</guid><description>&lt;p>巷で有名な&lt;a title="Twilio" href="http://twilio.kddi-web.com/">Twilio&lt;/a>をapexから触ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Twilioとは、Web技術で電話やSMS送信が出来るサービス。&lt;/p>
&lt;p>&lt;a title="Twilio REST API" href="https://jp.twilio.com/docs/api/rest">REST API&lt;/a>がサポートされていて&lt;/p>
&lt;p>例のごとくREST APIをラッピングしている各々のプログラム言語のライブラリ(&lt;a title="https://jp.twilio.com/docs/libraries" href="https://jp.twilio.com/docs/libraries">Helperライブラリ&lt;/a>)も公開されてます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>サポートされているプログラミング言語では珍しくapex(force.com)も利用できるので、今回カンタンに触ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>使い方のドキュメントとgithubのURLはこちら↓&lt;/p>
&lt;p>&lt;a href="https://twilio-salesforce.readthedocs.org/en/latest/">&lt;a href="https://twilio-salesforce.readthedocs.org/en/latest/">https://twilio-salesforce.readthedocs.org/en/latest/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://github.com/twilio/twilio-salesforce">&lt;a href="https://github.com/twilio/twilio-salesforce">https://github.com/twilio/twilio-salesforce&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>まずはTwilioのアカウントを取得して電話番号を購入する。&lt;/p>
&lt;p>※現在、日本の電話番号だとSMSを送信できないので、SMS送信する場合は、アメリカあたりの海外の電話番号をTwilioで取得する必要があります。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/01/BuyPhoneNumber.jpg">&lt;img class="alignnone size-medium wp-image-539" alt="BuyPhoneNumber" src="https://blog.freedom-man.com/img/2014/01/BuyPhoneNumber-300x154.jpg" width="300" height="154" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>その後、パッケージリンクからSalesforce環境にオブジェクトやらクラスをインストール↓&lt;/p>
&lt;p>&lt;a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04ti0000000XkE0">&lt;a href="https://login.salesforce.com/packaging/installPackage.apexp?p0=04ti0000000XkE0">https://login.salesforce.com/packaging/installPackage.apexp?p0=04ti0000000XkE0&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>そのあと、Twilio Configというカスタム設定（リスト）で適当にレコードを作成して、&lt;/p>
&lt;p>AccountSidとAuthTokenに&lt;a title="https://jp.twilio.com/user/account" href="https://jp.twilio.com/user/account">Twilioダッシュボード&lt;/a>で表示されている値をセットする。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/01/Twilio-Dashboard.jpg">&lt;img class="alignnone size-medium wp-image-537" alt="Twilio Dashboard" src="https://blog.freedom-man.com/img/2014/01/Twilio-Dashboard-300x71.jpg" width="300" height="71" />&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2014/01/TwilioConfigForSalesforce.jpg">&lt;img class="alignnone size-medium wp-image-538" alt="TwilioConfigForSalesforce" src="https://blog.freedom-man.com/img/2014/01/TwilioConfigForSalesforce-300x70.jpg" width="300" height="70" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>あとは、コードを書くだけ！&lt;/p>
&lt;p> &lt;/p>
&lt;p>電話かけるとき&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>TwilioRestClient&lt;span style="color:#fff"> &lt;/span>client&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>TwilioAPI&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getDefaultClient&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>TwilioCall&lt;span style="color:#fff"> &lt;/span>call&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>client&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getAccount&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">getCalls&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>To&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Input&lt;span style="color:#fff"> &lt;/span>Your&lt;span style="color:#fff"> &lt;/span>To&lt;span style="color:#fff"> &lt;/span>Phone&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">Number&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>E&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">164&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>From&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Input&lt;span style="color:#fff"> &lt;/span>Your&lt;span style="color:#fff"> &lt;/span>From&lt;span style="color:#fff"> &lt;/span>Phone&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">Number&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>E&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">164&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Url&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Input&lt;span style="color:#fff"> &lt;/span>Your&lt;span style="color:#fff"> &lt;/span>TwiML&lt;span style="color:#fff"> &lt;/span>url&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>Call&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">});&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>salesforceでfacebook, google, salesforceを認証プロバイダにしてSSOしてみる。</title><link>https://blog.freedom-man.com/salesforce_facebook_google_salesforce_sso.html</link><pubDate>Tue, 31 Dec 2013 22:28:48 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce_facebook_google_salesforce_sso.html</guid><description>&lt;p>facebook, google, salesforceを認証プロバイダにしてシングルサインオンが簡単にできるみたいなので試してみた。&lt;/p>
&lt;p>（facebookとかにログインすると自動的にsalesforceにログインする的な感じ）&lt;/p>
&lt;p> &lt;/p>
&lt;p>salesforceを認証プロバイダにする場合は別salesforce環境を用意する必要があります。&lt;/p>
&lt;p>salesforceを認証プロバイダってなんだそりゃ？って思いましたが&lt;/p>
&lt;p>多分、お客さんがSalesforce環境をすでに使っていて&lt;/p>
&lt;p>カスタマーコミュニティとかでそのお客さんを管理する場合に利用するものなんだと思います。&lt;/p>
&lt;p> &lt;/p>
&lt;p>以下、参考URL↓&lt;/p>
&lt;p>&lt;a href="http://www.slideshare.net/DeveloperForceJapan/webinar-13324430">&lt;a href="http://www.slideshare.net/DeveloperForceJapan/webinar-13324430">http://www.slideshare.net/DeveloperForceJapan/webinar-13324430&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://tyoshikawa1106.hatenablog.com/entry/2013/06/02/212452">&lt;a href="http://tyoshikawa1106.hatenablog.com/entry/2013/06/02/212452">http://tyoshikawa1106.hatenablog.com/entry/2013/06/02/212452&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://help.salesforce.com/HTViewHelpDoc?id=sso_provider_facebook.htm&amp;language=ja">&lt;a href="https://help.salesforce.com/HTViewHelpDoc?id=sso_provider_facebook.htm&amp;amp;language=ja">https://help.salesforce.com/HTViewHelpDoc?id=sso_provider_facebook.htm&amp;amp;language=ja&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://developers.google.com/accounts/docs/OpenID?hl=ja">&lt;a href="https://developers.google.com/accounts/docs/OpenID?hl=ja">https://developers.google.com/accounts/docs/OpenID?hl=ja&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>facebook&lt;/strong>&lt;/h3>
&lt;span style="line-height: 1.5em;">1. facebookアプリを登録&lt;/span>
&lt;ol start="2">
&lt;li>
&lt;p>セキュリティのコントロール＞認証プロバイダ　で新規認証プロバイダを作成&lt;/p>
&lt;/li>
&lt;li>
&lt;p> 2でコールバックURLが自動生成されるので、1のアプリにコールバックURLを設定&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>([Facebookでログインが可能なウェブサイト]の[サイトURL]に設定する。)&lt;/p>
&lt;p> &lt;/p>
&lt;p>以下、設定例&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2013/12/facebook.jpg">&lt;img class="alignnone size-medium wp-image-516" style="line-height: 1.5em;" alt="facebook" src="https://blog.freedom-man.com/img/2013/12/facebook-300x178.jpg" width="300" height="178" />&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2013/12/facebook-app.jpg">&lt;img class="alignnone size-medium wp-image-512" alt="facebook-app" src="https://blog.freedom-man.com/img/2013/12/facebook-app-300x169.jpg" width="300" height="169" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>google&lt;/strong>&lt;/h3>
1. &lt;a title="Google Developers Console" href="https://cloud.google.com/console?redirected=true#/project">Google Developers Console&lt;/a>にアクセスしてProjectを作成し、Google+APIを有効化
&lt;ol start="2">
&lt;li>
&lt;p>セキュリティのコントロール＞認証プロバイダ　で新規認証プロバイダを作成&lt;/p>
&lt;/li>
&lt;li>
&lt;p>2でコールバックURLが自動生成されるので、1のアプリにコールバックURLを設定&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>(APIs &amp;amp; auth &amp;gt; CredentialsのOAuthセクションでRedirect URIsを設定)&lt;/p>
&lt;p> &lt;/p>
&lt;p>以下、設定例&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2013/12/google.jpg">&lt;img class="alignnone size-medium wp-image-515" style="line-height: 1.5em;" alt="google" src="https://blog.freedom-man.com/img/2013/12/google-300x217.jpg" width="300" height="217" />&lt;/a>&lt;/p>
&lt;p>途切れているユーザ情報エンドポイントURLはhttps://www.googleapis.com/plus/v1/people/me/openIdConnect　です。&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2013/12/google-project.jpg">&lt;img class="alignnone size-medium wp-image-513" style="line-height: 1.5em;" alt="google-project" src="https://blog.freedom-man.com/img/2013/12/google-project-300x122.jpg" width="300" height="122" />&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>Salesforce&lt;/strong>&lt;/h3>
1. 別組織のSalesforceの作成＞アプリケーションにアクセスして、接続アプリケーション(OAuth)を作成
&lt;ol start="2">
&lt;li>
&lt;p>セキュリティのコントロール＞認証プロバイダ　で新規認証プロバイダを作成&lt;/p>
&lt;/li>
&lt;li>
&lt;p>2でコールバックURLが自動生成されるので、1のアプリにコールバックURLを設定&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>以下、設定例&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2013/12/salesforce.jpg">&lt;img class="alignnone size-medium wp-image-514" alt="salesforce" src="https://blog.freedom-man.com/img/2013/12/salesforce-300x176.jpg" width="300" height="176" />&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://blog.freedom-man.com/img/2013/12/salesforce-app.jpg">&lt;img alt="salesforce-app" src="https://blog.freedom-man.com/img/2013/12/salesforce-app-300x108.jpg" width="300" height="108" />&lt;/a>&lt;/p></description></item><item><title>2014</title><link>https://blog.freedom-man.com/2014.html</link><pubDate>Wed, 01 Jan 2014 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2014.html</guid><description/></item><item><title>OpenAMでSSO【IdP Initiated SSO】</title><link>https://blog.freedom-man.com/openam_sso_idp_initiated.html</link><pubDate>Sun, 29 Dec 2013 22:09:38 +0000</pubDate><guid>https://blog.freedom-man.com/openam_sso_idp_initiated.html</guid><description>&lt;p>&lt;a title="SalesforceとOpenAMでSSOやってみる。" href="https://blog.freedom-man.com/openam_salesforce_sso/" target="_blank">前回&lt;/a>はSP initiated SSOで&lt;/p>
&lt;ol>
 	&lt;li>SPにアクセス&lt;/li>
 	&lt;li>リダイレクトとかPOSTとかでIdPにアクセス[SAMLリクエスト]&lt;/li>
 	&lt;li>IdPに対して認証処理&lt;/li>
 	&lt;li>認証OKならSPにSAMLレスポンスを返してSP側の認証も完了&lt;/li>
&lt;/ol>
というフローでしたが、今回はIdP initiated SSOをやってみます。</description></item><item><title>apexからSimpleDB触ってみる。</title><link>https://blog.freedom-man.com/simpledb_using_apex.html</link><pubDate>Sun, 29 Dec 2013 02:23:08 +0000</pubDate><guid>https://blog.freedom-man.com/simpledb_using_apex.html</guid><description>&lt;p>例のごとくapexから&lt;a title="http://aws.amazon.com/jp/simpledb/" href="http://aws.amazon.com/jp/simpledb/">SimpleDB&lt;/a>触ってみる。&lt;/p>
&lt;p> &lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SimpleDBのコモンクラス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">SimpleDBCommon&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AccessKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSAccessKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SecretKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSSecretKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeySecret__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * ドメイン作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createDomain&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>domainName&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>CreateDomain&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWSAccessKeyId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureMethod&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureVersion&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>DomainName&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>domainName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2009&lt;span style="color:#0550ae">-&lt;/span>04&lt;span style="color:#0550ae">-&lt;/span>15&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Timestamp&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYY&lt;span style="color:#0550ae">-&lt;/span>MM&lt;span style="color:#0550ae">-&lt;/span>dd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ssZ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>sdb&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//sdb.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * ドメイン削除
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">deleteDomain&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>domainName&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>DeleteDomain&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWSAccessKeyId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureMethod&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureVersion&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>DomainName&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>domainName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2009&lt;span style="color:#0550ae">-&lt;/span>04&lt;span style="color:#0550ae">-&lt;/span>15&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Timestamp&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYY&lt;span style="color:#0550ae">-&lt;/span>MM&lt;span style="color:#0550ae">-&lt;/span>dd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ssZ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>sdb&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//sdb.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * アイテム作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">putAttributes&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>domainName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>itemName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>attributes&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>PutAttributes&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWSAccessKeyId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureMethod&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureVersion&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>DomainName&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>domainName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2009&lt;span style="color:#0550ae">-&lt;/span>04&lt;span style="color:#0550ae">-&lt;/span>15&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Timestamp&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYY&lt;span style="color:#0550ae">-&lt;/span>MM&lt;span style="color:#0550ae">-&lt;/span>dd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ssZ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>ItemName&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>itemName&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Integer&lt;span style="color:#fff"> &lt;/span>i&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>1&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>attributes&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Attribute&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>i&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Name&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Attribute&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>i&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Value&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>attributes&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>i&lt;span style="color:#0550ae">++&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>sdb&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//sdb.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * クエリ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">query&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>queryString&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Select&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWSAccessKeyId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureMethod&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignatureVersion&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SelectExpression&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>queryString&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Version&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>2009&lt;span style="color:#0550ae">-&lt;/span>04&lt;span style="color:#0550ae">-&lt;/span>15&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Timestamp&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYY&lt;span style="color:#0550ae">-&lt;/span>MM&lt;span style="color:#0550ae">-&lt;/span>dd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ssZ&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>sdb&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//sdb.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>System&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">base64Encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSSecretKeyId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Utilityクラス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>without&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Utility&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">getSortedList&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Set&lt;span style="color:#fff"> &lt;/span>keys&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#fff"> &lt;/span>sortedList&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>sortedList&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">addAll&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>keys&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>sortedList&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sort&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedList&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * key=value&amp;amp;...でつないだ文字列を返却
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param mapParam 対象文字列=&amp;gt;文字列マップ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @return key=value&amp;amp;...でつないだ文字列
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>mapParam&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>mapParam&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>mapParam&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">isEmpty&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>getSortedList&lt;span style="color:#1f2328">(&lt;/span>mapParam&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>percentEncodeRfc3986&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>percentEncodeRfc3986&lt;span style="color:#1f2328">(&lt;/span>mapParam&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">substring&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>0&lt;span style="color:#1f2328">,&lt;/span>param&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#fff"> &lt;/span>1&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">percentEncodeRfc3986&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>s&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>s&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;+&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">%&lt;/span>20&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;*&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">%&lt;/span>2A&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">%&lt;/span>7E&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;~&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>herokuでdjango動かしてみる。</title><link>https://blog.freedom-man.com/heroku_django.html</link><pubDate>Sat, 28 Dec 2013 17:30:23 +0000</pubDate><guid>https://blog.freedom-man.com/heroku_django.html</guid><description>&lt;p>この冬はLPICの受験勉強！&lt;/p>
&lt;p>→スマホとかPCから勉強できる自分用の単語帳的なアプリが欲しい！&lt;/p>
&lt;p>→Androidアプリ開発者レベル1だからとりあえずWebアプリで早急に作ろう！&lt;/p>
&lt;p>→手軽にホスティングできて、手軽に作れるフレームワークで！&lt;/p>
&lt;p>→heroku + python + django！&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、linux環境からherokuでdjango動かすまでの備忘録。っていうかherokuガイドの日本語訳ｗ&lt;/p>
&lt;p>詳しいやり方はherokuのstartガイド参照↓&lt;/p>
&lt;p>&lt;a href="https://devcenter.heroku.com/articles/getting-started-with-django">&lt;a href="https://devcenter.heroku.com/articles/getting-started-with-django">https://devcenter.heroku.com/articles/getting-started-with-django&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみにdjangoデプロイするときにherokuのwsgirefのpipインストールの時に&lt;/p>
&lt;p>python3系だと何故かコケちゃうので、バージョンは2.7でデプロイしてます。&lt;/p>
&lt;p> &lt;/p>
&lt;ol>
&lt;li>pipとかのインストール&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh &lt;span style="color:#1f2328">|&lt;/span> sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>apt-get install python-setuptools python-pip python-dev python-psycopg2 libpq-dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>virtualenv venv --python&lt;span style="color:#0550ae">=&lt;/span>/usr/bin/python --distribute
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">source&lt;/span> venv/bin/activate
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pip install django-toolbelt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>※もしかしたらpython-setuptoolsインストールしなくてもイケるかも。&lt;/p>
&lt;p>※sudo pip installとかやるとルートユーザ権限で実行される関係で、venvの環境外にインストールされちゃうっぽい。&lt;/p>
&lt;p> &lt;/p>
&lt;ol start="2">
&lt;li>djangoアプリ作成&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>django-admin.py startproject hellodjango
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>3.Procfile（設定ファイル）作成&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">cd&lt;/span> hellodjango
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vim Procfile
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>で、以下を入力↓&lt;/p>
&lt;p>web: gunicorn hellodjango.wsgi&lt;/p>
&lt;p> &lt;/p>
&lt;ol start="4">
&lt;li>django起動確認&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>foreman start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>でブラウザでhttp://localhost:5000を開き、&amp;ldquo;It Worked!&amp;ldquo;が出ていることを確認。&lt;/p>
&lt;p> &lt;/p>
&lt;ol start="5">
&lt;li>インストールされているパッケージ一覧をrequirements.txtに記述&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>pip freeze &amp;gt; requirements.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;ol start="6">
&lt;li>あとはお馴染みのherokuのデプロイコマンド&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git init
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git add .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git commit -m &lt;span style="color:#0a3069">&amp;#34;Message&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>heroku create
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>git push heroku master
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>apexからDynamoDB触ってみる。</title><link>https://blog.freedom-man.com/dynamodb_using_apex.html</link><pubDate>Wed, 25 Dec 2013 01:40:12 +0000</pubDate><guid>https://blog.freedom-man.com/dynamodb_using_apex.html</guid><description>&lt;p>巷で有名な&lt;a title="http://aws.amazon.com/jp/dynamodb/" href="http://aws.amazon.com/jp/dynamodb/">DynamoDB&lt;/a>さんにApexから触ってみました。&lt;/p></description></item><item><title>apexからAmazon Elastic Transcoderを触ってみる。</title><link>https://blog.freedom-man.com/amazon_elastic_transcoder_using_apex.html</link><pubDate>Mon, 23 Dec 2013 22:40:08 +0000</pubDate><guid>https://blog.freedom-man.com/amazon_elastic_transcoder_using_apex.html</guid><description>&lt;p>&lt;a title="http://aws.amazon.com/jp/elastictranscoder/" href="http://aws.amazon.com/jp/elastictranscoder/">Amazon Elastic Transcoder&lt;/a>とはAmazon Web Serviceの一つ(ベータ版)で&lt;/p>
&lt;p>メディア変換をできるクラウドサービス。&lt;/p>
&lt;p> &lt;/p>
&lt;p>あんまりメディアファイルを扱ったこと無いから利用イメージが湧かないが、&lt;/p>
&lt;p>iOS用のストリーミング技術のHLSへの変換が簡単そうなので触ってみることにした。&lt;/p>
&lt;p> &lt;/p>
&lt;p>基本的な使い方は安定のクラスメソッドさんのブログで↓&lt;/p>
&lt;p>&lt;a href="http://dev.classmethod.jp/cloud/amazon-elastic-transcoder-start/">&lt;a href="http://dev.classmethod.jp/cloud/amazon-elastic-transcoder-start/">http://dev.classmethod.jp/cloud/amazon-elastic-transcoder-start/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://dev.classmethod.jp/references/amazon-elastic-transcoder-hls/">&lt;a href="http://dev.classmethod.jp/references/amazon-elastic-transcoder-hls/">http://dev.classmethod.jp/references/amazon-elastic-transcoder-hls/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>一般的なWeb言語のSDKは存在するものの、apex用のSDKはもちろん無いので&lt;/p>
&lt;p>pipeline(入出力バケットの設定)とjob(実際の変換操作)の作成部分を作ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AETコモンクラス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">AETCommon&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	&lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">final&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>elastictranscoder&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Access Key Id
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSAccessKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyID__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Access Key Secret
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSAccessKeySecret&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EnvSetting__c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getOrgDefaults&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeySecret__c&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * パイプラインを作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createPipeLine&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>pipelineName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>inputBucket&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>outputBucket&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>thumnailBucket&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>role&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>aws4_request&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">//Body&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>jsonMap&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Name&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>pipelineName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>InputBucket&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>inputBucket&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>OutputBucket&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>outputBucket&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Role&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>role&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Notifications&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Progressing&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Completed&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Warning&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Error&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Json&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">serialize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jsonMap&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>2012&lt;span style="color:#0550ae">-&lt;/span>09&lt;span style="color:#0550ae">-&lt;/span>25&lt;span style="color:#0550ae">/&lt;/span>pipelines&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createStringToSign&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#0550ae">-&lt;/span>HMAC&lt;span style="color:#0550ae">-&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createHashedCanonicalRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>elastictranscoder&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">},&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>stringToSign&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">callCommonAETCall&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>elastictranscoder&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * jobを作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createJob&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>pipelineId&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>inputKey&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>outputKey&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>outputKeyPrefix&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">					 &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>aws4_request&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">//Body&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>jsonMap&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>PipelineId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>pipelineId&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Input&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Key&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>inputKey&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#1f2328">},&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Outputs&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 	&lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Object&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 		&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Key&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>outputKey&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 		&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>PresetId&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>1351620000001&lt;span style="color:#0550ae">-&lt;/span>200050&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 		&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SegmentDuration&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;5&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 	&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#1f2328">},&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>OutputKeyPrefix&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>outputKeyPrefix&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#1f2328">};&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Json&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">serialize&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jsonMap&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createStringToSign&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#0550ae">-&lt;/span>HMAC&lt;span style="color:#0550ae">-&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createHashedCanonicalRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>2012&lt;span style="color:#0550ae">-&lt;/span>09&lt;span style="color:#0550ae">-&lt;/span>25&lt;span style="color:#0550ae">/&lt;/span>jobs&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>elastictranscoder&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">},&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>hmacSHA256&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>SERVICE&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>stringToSign&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">callCommonAETCall&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>elastictranscoder&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">amazonaws&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">com&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>signature&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>2012&lt;span style="color:#0550ae">-&lt;/span>09&lt;span style="color:#0550ae">-&lt;/span>25&lt;span style="color:#0550ae">/&lt;/span>jobs&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>jsonBody&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * AETへのAPIコールの共通メソッド
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">callCommonAETCall&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>resource&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>jsonBody&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Host&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>hostname&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>amz&lt;span style="color:#0550ae">-&lt;/span>date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>application&lt;span style="color:#0550ae">/&lt;/span>json&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> &lt;/span>charset&lt;span style="color:#0550ae">=&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Length&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jsonBody&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Authorization&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#0550ae">-&lt;/span>HMAC&lt;span style="color:#0550ae">-&lt;/span>SHA256&lt;span style="color:#fff"> &lt;/span>Credential&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>SignedHeaders&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getLowerCaseSortedList&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signedHeaders&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//&amp;#39; + hostname + resource);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>jsonBody&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * HashedCanonicalRequestを作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createHashedCanonicalRequest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>url&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>params&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>signedHeaders&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>payload&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff"> 	
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>method&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>url&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>params&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createCanonicalHeaders&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>headers&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Utility&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getLowerCaseSortedList&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signedHeaders&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>signature&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertToHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateDigest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>payload&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertToHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateDigest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>signature&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	 &lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * StringToSignを作成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createStringToSign&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>requestDateTime&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>hashedCanonicalRequest&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	 &lt;/span>requestDateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;T&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	 &lt;/span>requestDateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HHmmss&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;Z&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>credentialScope&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>Constants&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">LF&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>hashedCanonicalRequest&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff"> 	
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>requestDateTime&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>region&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>service&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>stringToSign&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>system&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">debug&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>stringToSign&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">toString&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kDate&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">			&lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">			&lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>requestDateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">formatGmt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>YYYYMMdd&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS4&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeySecret&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kRegion&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>region&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kDate&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kService&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>service&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kRegion&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#fff"> &lt;/span>kSigning&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>aws4_request&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kService&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">convertToHex&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">		&lt;/span>algorithm&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">		&lt;/span>stringToSign&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>kSigning&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Utilityクラス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>without&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Utility&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * key=value&amp;amp;...でつないだ文字列を返却
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param mapParam 対象文字列=&amp;gt;文字列マップ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @return key=value&amp;amp;...でつないだ文字列
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">getSortedParam&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>mapParam&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>mapParam&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>mapParam&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">isEmpty&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>getSortedList&lt;span style="color:#1f2328">(&lt;/span>mapParam&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>percentEncodeRfc3986&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;=&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>percentEncodeRfc3986&lt;span style="color:#1f2328">(&lt;/span>mapParam&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">))&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;amp;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">substring&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>0&lt;span style="color:#1f2328">,&lt;/span>param&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">-&lt;/span>&lt;span style="color:#fff"> &lt;/span>1&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">percentEncodeRfc3986&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>s&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>s&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;+&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">%&lt;/span>20&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;*&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">%&lt;/span>2A&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">replace&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">%&lt;/span>7E&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;~&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createCanonicalHeaders&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#cf222e">if&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>headers&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">==&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">null&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">||&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">().&lt;/span>&lt;span style="color:#1f2328">isEmpty&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>lowerCaseHeaders&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Map&lt;span style="color:#0550ae">&amp;lt;&lt;/span>String&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">())&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 		&lt;/span>lowerCaseHeaders&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">(),&lt;/span>&lt;span style="color:#fff"> &lt;/span>headers&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>getSortedList&lt;span style="color:#1f2328">(&lt;/span>lowerCaseHeaders&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keySet&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedKey&lt;span style="color:#1f2328">){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;:&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>lowerCaseHeaders&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">trim&lt;/span>&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;\n&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>param&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">getLowerCaseSortedList&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>List&lt;span style="color:#fff"> &lt;/span>keys&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>List&lt;span style="color:#fff"> &lt;/span>sortedKeys&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>List&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">for&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>key&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#fff"> &lt;/span>keys&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>sortedKeys&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">add&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>key&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">toLowerCase&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>sortedKeys&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sort&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>sortedKeys&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>SalesforceとOpenAMでSSOやってみる。</title><link>https://blog.freedom-man.com/openam_salesforce_sso.html</link><pubDate>Fri, 20 Dec 2013 23:42:08 +0000</pubDate><guid>https://blog.freedom-man.com/openam_salesforce_sso.html</guid><description>&lt;p>最近SSOが熱いのでやってみた。&lt;/p>
&lt;p>&lt;a title="http://www.salesforce.com/jp/platform/identity/" href="http://www.salesforce.com/jp/platform/identity/">Salesforce Identity&lt;/a>とか出てるけど関係ない！OSS最高！！&lt;/p></description></item><item><title>ApexからSNSを使ってAndroidにPush Notification！</title><link>https://blog.freedom-man.com/sns_for_android_using_apex.html</link><pubDate>Thu, 19 Dec 2013 23:03:13 +0000</pubDate><guid>https://blog.freedom-man.com/sns_for_android_using_apex.html</guid><description>&lt;p>&lt;a title="/aws/442/ " href="https://blog.freedom-man.com/sns_for_android_using_gcm/" target="_blank">前回&lt;/a>はAWSコンソールからPush Notificationしましたが、API経由じゃないと何の旨味もないので、Apexを使ってPush Notificationしてみます。&lt;/p></description></item><item><title>Android端末にSNS(AWS) + GCMでPush Notification</title><link>https://blog.freedom-man.com/sns_for_android_using_gcm.html</link><pubDate>Wed, 18 Dec 2013 23:02:27 +0000</pubDate><guid>https://blog.freedom-man.com/sns_for_android_using_gcm.html</guid><description>&lt;p>最近モバイルが熱いので、モバイル系？のPush NotificationサービスのSNSを触ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回はRegistrationIDを発行して、AWSコンソールからPublishする感じまで。&lt;span style="line-height: 1.5em;"> &lt;/span>&lt;/p>
&lt;p>参考URL：&lt;/p>
&lt;p>&lt;a href="http://docs.aws.amazon.com/sns/latest/dg/mobile-push-gcm.html">&lt;a href="http://docs.aws.amazon.com/sns/latest/dg/mobile-push-gcm.html">http://docs.aws.amazon.com/sns/latest/dg/mobile-push-gcm.html&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://dev.classmethod.jp/smartphone/android/amazon-sns-mobile-push/">&lt;a href="http://dev.classmethod.jp/smartphone/android/amazon-sns-mobile-push/">http://dev.classmethod.jp/smartphone/android/amazon-sns-mobile-push/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>全体の流れとしては&lt;/p>
&lt;p>1. GCMの設定&lt;/p>
&lt;ol start="2">
&lt;li>
&lt;p>AWSサンプルアプリ（&lt;a title="https://s3.amazonaws.com/codesamples/sns/latest/snsmobilepush.zip" href="https://s3.amazonaws.com/codesamples/sns/latest/snsmobilepush.zip">snsmobilepush.zip&lt;/a>）をダウンロードしてAndroidアプリを作成&lt;/p>
&lt;/li>
&lt;li>
&lt;p>サンプルのAndroidアプリを起動するとRegistrationIDが発行されるので、&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>その値をAWSコンソールでSNSに設定。&lt;/p>
&lt;ol start="4">
&lt;li>SNSのコンソールでメッセージをPublish！&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>1, 2までは簡単なんだけど、3でRegistrationIDが発行されなくて、激ハマリ状態に陥りました。&lt;/p>
&lt;p>具体的にはAWSサンプルアプリは起動するものの、「Welcome」の文字列しか出ない状態。&lt;/p>
&lt;p> &lt;/p>
&lt;p>LogCatタグを見てみると&lt;/p>
&lt;p>SERVICE_NOT_AVAILABLE とか&lt;/p>
&lt;p>unable to start service intent act=com.google.android.c2dm.intent.registration　～&lt;/p>
&lt;p>とかっていうログが吐かれている。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これはAVDがGoogleAPIsに対応していない為に起こる問題で、&lt;/p>
&lt;p>Android SDK Managerで対象プラットフォームのGoogle APIsをインストールして、&lt;/p>
&lt;p>AVDのTargetに[Google APIs～]を選択してあげればOKでした。&lt;/p>
&lt;p> &lt;/p>
&lt;p>つまりはGoogle APIsがAndroid端末にインストールされていないのに&lt;/p>
&lt;p>GCMのAPIは叩けないよっていうことみたい。そりゃそうか。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみに下の方にあるExtrasのGoogle Play servicesもインストールが必要で、&lt;/p>
&lt;p>下記の参考URLにあるように、google-play-services.jar、android-support-v4.jar、android.jarを入れてあげないとダメっす。&lt;/p>
&lt;p> &lt;/p>
&lt;p>RegistrationID発行はGCMの世界だけど&lt;/p>
&lt;p>RegistrationIDをSNSに登録したり、PublishしたりはAPIで可能らしいので&lt;/p>
&lt;p>次回はapex(force.com)でSNSを弄ってみます。&lt;/p></description></item><item><title>force.com REST APIでコンテンツ作るのが面倒くさかったので共有</title><link>https://blog.freedom-man.com/forcecom_restapi_create_contents.html</link><pubDate>Sun, 15 Dec 2013 01:02:29 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_restapi_create_contents.html</guid><description>&lt;p>force.com SOAP APIでコンテンツ(ContentVersion)上げるのは普通にレコード作るだけで良くて&lt;/p>
&lt;p>実データもBase64エンコードしたバイナリをVersionData項目に入れるだけですごく簡単。&lt;/p>
&lt;p> &lt;/p>
&lt;p>force.com REST APIでも通常のCRUDと同じようにできるかと思ったが、&lt;/p>
&lt;p>バイナリデータをアップロードするには結構面倒くさいみたいなので共有しまっす。&lt;/p>
&lt;p> &lt;/p>
&lt;p>リファレンスを読むとmultipart/form-data形式で送らないとダメっぽい。&lt;/p>
&lt;p>以下はphp(curl使用)のサンプル&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-php" data-lang="php">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_CLIENT_KEY&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input Your Client Key&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_CLIENT_SECRET&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input Your Client Secret&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_USERNAME&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input Your SFDC User Name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_PASSWORD&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input Your SFDC Password&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_TOKEN_URL&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;https://login.salesforce.com/services/oauth2/token&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_REST_VERSION&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;27.0&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">define&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;SFDC_CONTENTS_LIBRARY_ID&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$sf&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">SforceRest&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">SFDC_CLIENT_KEY&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">SFDC_CLIENT_SECRET&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">SFDC_USERNAME&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">SFDC_PASSWORD&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;--boundary_string&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Content-Disposition: form-data; name=&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">Nandemo OK&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">;&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#1f2328">json_encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;Title&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input Your ContentVersion Title&amp;#34;&lt;/span> &lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;PathOnClient&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Input Your Upload FileName&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;Description&amp;#39;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Input Your ContentVersion Description&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// &amp;#39;FirstPublishLocationId&amp;#39; =&amp;gt; SFDC_CONTENTS_LIBRARY_ID 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span> &lt;span style="color:#0550ae">.&lt;/span>&lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;--boundary_string&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;Content-Disposition: form-data; name=&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">VersionData&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">;filename=&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">test.pdf&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#1f2328">file_get_contents&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;test.pdf&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">PHP_EOL&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$json&lt;/span> &lt;span style="color:#0550ae">.=&lt;/span> &lt;span style="color:#0a3069">&amp;#34;--boundary_string--&amp;#34;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">$sf&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">insertContentVersion&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$json&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">SforceRest&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">private&lt;/span> &lt;span style="color:#953800">$loginInfo&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * コンストラクタ(ログイン)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param type $client_key
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param type $client_secret
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param type $user
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param type $password
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">__construct&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$client_key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$client_secret&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$password&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$ch&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">curl_init&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">SFDC_TOKEN_URL&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_POST&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_HEADER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_RETURNTRANSFER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_SSL_VERIFYPEER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$post_data&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;grant_type&amp;#34;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#0a3069">&amp;#34;password&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_id&amp;#34;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$client_key&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;client_secret&amp;#34;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$client_secret&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;username&amp;#34;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$user&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;password&amp;#34;&lt;/span> &lt;span style="color:#0550ae">=&amp;gt;&lt;/span> &lt;span style="color:#953800">$password&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_POSTFIELDS&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$post_data&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">curl_exec&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">loginInfo&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">json_decode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$res&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * コンテンツにデータを格納
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> * @param $json コンテンツのデータ
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> */&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">public&lt;/span> &lt;span style="color:#cf222e">function&lt;/span> &lt;span style="color:#6639ba">insertContentVersion&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$json&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$ch&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">curl_init&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#0a3069">{&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">loginInfo&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">instance_url&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">/services/data/v&amp;#34;&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#1f2328">SFDC_REST_VERSION&lt;/span> &lt;span style="color:#0550ae">.&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/sobjects/ContentVersion&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_POST&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_HTTPHEADER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">array&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;Authorization: Bearer &lt;/span>&lt;span style="color:#0a3069">{&lt;/span>&lt;span style="color:#953800">$this&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">loginInfo&lt;/span>&lt;span style="color:#0550ae">-&amp;gt;&lt;/span>&lt;span style="color:#1f2328">access_token&lt;/span>&lt;span style="color:#0a3069">}&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;Content-Type: multipart/form-data;boundary=&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">boundary_string&lt;/span>&lt;span style="color:#0a3069">\&amp;#34;&lt;/span>&lt;span style="color:#0a3069">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_BINARYTRANSFER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_RETURNTRANSFER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_SSL_VERIFYPEER&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">curl_setopt&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">CURLOPT_POSTFIELDS&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#953800">$json&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#953800">$res&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">curl_exec&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$ch&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#1f2328">json_decode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#953800">$res&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>windowsでVPN接続とネットワーク接続を併用したときのハマり</title><link>https://blog.freedom-man.com/windows_vpn_network.html</link><pubDate>Sat, 14 Dec 2013 00:31:58 +0000</pubDate><guid>https://blog.freedom-man.com/windows_vpn_network.html</guid><description>&lt;p>Windows のEC2インスタンスとprivate subnet内のEC2インスタンスをVPN接続したいとき、&lt;/p>
&lt;pre tabindex="0">&lt;code>Windows &amp;lt;=&amp;gt; ルータ &amp;lt;=&amp;gt; EC2(private subnet)
&lt;/code>&lt;/pre>&lt;p>というような構成になるが、WindowsとルータをVPN接続しつつネットワーク接続も利用する場合は、
ネットワークの設定で &lt;code>[リモートネットワークでデフォルトゲートウェイを使う]&lt;/code> を外す必要がある。&lt;/p>
&lt;ul>
&lt;li>参考URL：&lt;a title="http://www.kisc.meiji.ac.jp/~ksd/nsd/support/dialup/vpn_s_xp.html" href="http://www.kisc.meiji.ac.jp/~ksd/nsd/support/dialup/vpn_s_xp.html">&lt;a href="http://www.kisc.meiji.ac.jp/~ksd/nsd/support/dialup/vpn_s_xp.html">http://www.kisc.meiji.ac.jp/~ksd/nsd/support/dialup/vpn_s_xp.html&lt;/a>&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>チェックをつけた場合は、全てのトラフィックがVPNで接続しているネットワークのゲートウェイ経由でインターネットに接続しようとする（デフォルトゲートウェイがVPNのルータになる）。&lt;/p>
&lt;p>しかし、チェックをつけない場合は、ネットワーク接続とVPN接続を併用できるものの、デフォルトゲートウェイが既存のものなので、
windows側のローカルIPが192.168.x.x とかでEC2側が10.0.x.x とかの場合は
10.0.x.xに対するトラフィックがネットワーク接続のデフォルトゲートウェイを通ってしまうため、
接続できなくなってしまう。&lt;/p>
&lt;p>したがってwindowsのインスタンス上で、EC2のprivate subnetに対するルーティングを以下のように設定する必要がある。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>route ADD &amp;lt;private subnetの宛先IP&amp;gt; MASK &amp;lt;private subnetのサブネットマスク&amp;gt; &amp;lt;ルータのIP&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ちなみに、私の試した環境ではWindowsのEC2インスタンスとVPN接続する場合は、
ネットワーク接続と併用しないと既存のRDP接続が失われてしまい、結果としてVPN接続できなかった…。&lt;/p>
&lt;p>多分、デフォルトゲートウェイがVPNルータになるからかな？&lt;/p></description></item><item><title>IEでVisualforceページのjQueryのAjax処理が動かない</title><link>https://blog.freedom-man.com/visualforce_jquery_ajax_on_ie.html</link><pubDate>Fri, 13 Dec 2013 00:55:14 +0000</pubDate><guid>https://blog.freedom-man.com/visualforce_jquery_ajax_on_ie.html</guid><description>&lt;p>Visualforceページ内でActionFunction等のajax系のapexタグ・属性&lt;/p>
&lt;p>(&lt;a href="apex:actionFunction">apex:actionFunction&lt;/a>, &amp;lt;apex:commandButton reRender=&amp;quot;&amp;quot;&amp;gt;等)を利用しつつ、&lt;/p>
&lt;p>jQueryの$.ajaxを利用している場合に、IEで$.ajaxがうまく動かなくなってしまう。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これは、Apexのajax系処理をVFに実装して画面を表示すると&lt;/p>
&lt;p>/faces/a4j/g/3_3_3.Finalorg.ajax4jsf.javascript.AjaxScript?rel=**********　のURLで&lt;/p>
&lt;p>Sarissa.js(&lt;a title="http://dev.abiss.gr/sarissa/" href="http://dev.abiss.gr/sarissa/">&lt;a href="http://dev.abiss.gr/sarissa/">http://dev.abiss.gr/sarissa/&lt;/a>&lt;/a>)というAjaxのライブラリが読み込まれてしまうためで、&lt;/p>
&lt;p>IEでSarissa.jsが読み込まれると&lt;/p>
&lt;p>ブラウザ組み込みのXMLHttpRequestオブジェクトがSarissa.jsによって上書きされてしまい&lt;/p>
&lt;p>結果としてjQueryの$.ajaxが動かなくなってしまうことが原因。&lt;/p>
&lt;p> &lt;/p>
&lt;p>対応策としては、&lt;/p>
&lt;p>・Apexのajax系処理を使う場合はjQueryのAjax通信を行わない。&lt;/p>
&lt;p>（どちらか片方に寄せる）&lt;/p>
&lt;p>・下記のようにしてjQueryオブジェクトのxhrプロパティを書き換える。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">jQuery&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ajaxSetup&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">xhr&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ActiveXObject&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ActiveXObject&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Microsoft.XMLHTTP&amp;#34;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span> &lt;span style="color:#cf222e">catch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">e&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#6639ba">window&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">XMLHttpRequest&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>の2パターン。&lt;/p>
&lt;p>force.com内で完結するのであれば、JavaScript Remotingとかajax系タグだけでも問題ないが、&lt;/p>
&lt;p>外部Webサービスとajaxを利用して連携する場合には注意が必要。&lt;/p></description></item><item><title>SalesforceのセッションIDを無理やり取得する方法</title><link>https://blog.freedom-man.com/salesforce_get_sessionid.html</link><pubDate>Thu, 12 Dec 2013 02:33:19 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce_get_sessionid.html</guid><description>&lt;p>Salesforceで現在ログインしているユーザのセッションIDは、&lt;/p>
&lt;p>cookie上ではkey値[sid]のvalueとして格納されるため、以下のようにして取得することが出来る。&lt;/p>
&lt;p> &lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">cookie&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">substring&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">cookie&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">indexOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;=&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">cookie&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">indexOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;sid=&amp;#34;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">cookie&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">indexOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;;&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">cookie&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">indexOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;sid=&amp;#34;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>そもそもログインユーザであれば、お知らせ等のサイドコンポーネントの中に&lt;/p>
&lt;p>JavaScriptを出力するVFを埋め込んだりして、標準画面上でもある程度動的なことは可能だが、&lt;/p>
&lt;p>UserScriptをブラウザに取り込んで、salesforceドメインで常々動作させる機能を書いたりするときには&lt;/p>
&lt;p>セッションIDをcookieから取得する上記の方法が有効。&lt;/p>
&lt;p> &lt;/p>
&lt;p>もちろん、Salesforceの仕様が変わって、key値がsidから変更されてしまったら&lt;/p>
&lt;p>上記のスクリプトが動かなくなってしまうので、お客さんの環境ではこの取得方法は利用しないほうが良い。&lt;/p>
&lt;p>飽くまで、開発者用のツール等を作成するときに利用できますよー、ということで。&lt;/p></description></item><item><title>EC2のubuntuにユーザ名ec2-userでログインできなくてハマった</title><link>https://blog.freedom-man.com/ec2_ubuntu_ec2-user.html</link><pubDate>Tue, 10 Dec 2013 01:10:17 +0000</pubDate><guid>https://blog.freedom-man.com/ec2_ubuntu_ec2-user.html</guid><description>&lt;p>EC2でubuntu立ち上げてec2-userでログインしようとしたら、&lt;/p>
&lt;p>Permission denied(public key)が出やがる…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>以下の記事のように、各AMI毎にデフォルトのユーザ名が異なるみたいで、&lt;/p>
&lt;p>ubuntuはユーザ名[ubuntu]でログインしないとダメみたい。&lt;/p>
&lt;p>&lt;a href="http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/GettingStartedGuide/ec2-connect-to-instance-linux.html">&lt;a href="http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/GettingStartedGuide/ec2-connect-to-instance-linux.html">http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/GettingStartedGuide/ec2-connect-to-instance-linux.html&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>当たり前のようにec2-userでログインしてきた私はAmazonLinuxのAMIしか使ったこと無いことがモロバレっすね…。&lt;/p>
&lt;p> &lt;/p></description></item><item><title>AWSのSESをApex使って触ってみた。</title><link>https://blog.freedom-man.com/ses_using_apex.html</link><pubDate>Wed, 04 Dec 2013 01:08:49 +0000</pubDate><guid>https://blog.freedom-man.com/ses_using_apex.html</guid><description>&lt;p>AWSの&lt;a title="http://aws.amazon.com/jp/ses/" href="http://aws.amazon.com/jp/ses/">SES&lt;/a>というメール配信サービスが気になったので、force.comのApexから動かしてみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>・コンソールから送る方式&lt;/p>
&lt;p>・SMTP方式&lt;/p>
&lt;p>・HTTPS方式&lt;/p>
&lt;p>の3つがあって、自動配信とかそういうのやる場合はプログラムでSMTP or HTTPS方式でやるみたい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ApexからSMTPは不可能なので、HTTPS方式で、メール送る処理だけ書いてみた。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * SES呼び出しコモンクラス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">SESCommon&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	&lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">	 * AccessKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">	 */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSAccessKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AKI&lt;span style="color:#0550ae">**********&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	&lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">	 * SecretKey
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">	 */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">	&lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>AWSSecretKeyId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">**************************&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * メール送信
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param fromAddress fromアドレス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param toAddress toアドレス
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param subject メール件名
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * @param messageBody メール本文
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">public&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">sendMail&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>fromAddress&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>toAddress&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>subject&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>messageBody&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>String&lt;span style="color:#fff"> &lt;/span>postBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Action&lt;span style="color:#0550ae">=&lt;/span>SendEmail&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">		&lt;/span>postBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">&amp;amp;&lt;/span>Source&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>fromAddress&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">		&lt;/span>postBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">&amp;amp;&lt;/span>Destination&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ToAddresses&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">member&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">1&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>toAddress&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">		&lt;/span>postBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">&amp;amp;&lt;/span>Message&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Subject&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Data&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>subject&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">		&lt;/span>postBody&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">&amp;amp;&lt;/span>Message&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Body&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Text&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Data&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">urlEncode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>messageBody&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>UTF&lt;span style="color:#0550ae">-&lt;/span>8&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>dateHeader&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getDateTime&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DateTime&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">now&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>HttpRequest&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Date&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>dateHeader&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Type&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>application&lt;span style="color:#0550ae">/&lt;/span>x&lt;span style="color:#0550ae">-&lt;/span>www&lt;span style="color:#0550ae">-&lt;/span>form&lt;span style="color:#0550ae">-&lt;/span>urlencoded&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Content&lt;span style="color:#0550ae">-&lt;/span>Length&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>postBody&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">length&lt;/span>&lt;span style="color:#1f2328">()));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setHeader&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>X&lt;span style="color:#0550ae">-&lt;/span>Amzn&lt;span style="color:#0550ae">-&lt;/span>Authorization&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>AWS3&lt;span style="color:#0550ae">-&lt;/span>HTTPS&lt;span style="color:#fff"> &lt;/span>AWSAccessKeyId&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSAccessKeyId&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Signature&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>createSignature&lt;span style="color:#1f2328">(&lt;/span>dateHeader&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Algorithm&lt;span style="color:#0550ae">=&lt;/span>HmacSHA1&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setEndpoint&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>https&lt;span style="color:#1f2328">:&lt;/span>&lt;span style="color:#57606a">//email.us-east-1.amazonaws.com&amp;#39;);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setMethod&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>POST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">setBody&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>postBody&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Http&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>HTTPResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>http&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">send&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">getBody&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * フォーマットされた日付文字列を取得
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">getDateTime&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>DateTime&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>dt&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">format&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>EEE&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>dd&lt;span style="color:#fff"> &lt;/span>MMM&lt;span style="color:#fff"> &lt;/span>yyyy&lt;span style="color:#fff"> &lt;/span>HH&lt;span style="color:#1f2328">:&lt;/span>mm&lt;span style="color:#1f2328">:&lt;/span>ss&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">+&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">+&lt;/span>0900&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#57606a">/**
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> * Signature生成
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"> */&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">private&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">createSignature&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>target&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 	&lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>EncodingUtil&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">base64Encode&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Crypto&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">generateMac&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> 		&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>HMacSHA1&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>target&lt;span style="color:#1f2328">),&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Blob&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">valueOf&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">this&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">AWSSecretKeyId&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">));&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>force.com開発におけるApexとJavaScriptの使い分け</title><link>https://blog.freedom-man.com/forcecom_apex_javascript.html</link><pubDate>Mon, 02 Dec 2013 23:35:28 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_apex_javascript.html</guid><description>&lt;p>最近ではMobileの波が来ていることもあり、jQueryだけでなくBackbone.jsやAngular.js等の&lt;/p>
&lt;p>JSフレームワークを利用した開発サンプルもSalesforceから提供されるようになった。&lt;/p>
&lt;p>既存のApexタグと同じくらいJavaScriptも使いこなせないとね、って感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そこで、出てくるのがApexとJavaScriptとの使い分け。&lt;/p>
&lt;p>ここらへんってApexだけじゃなくて、全てのサーバサイドプログラミング言語に共通していることで、&lt;/p>
&lt;p>私が偉そうに言えることでも無いけど、とりあえず書いてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>まず、混在するパターンとしては以下のとおり&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. Visualforceページ開発におけるバリデーションチェックでの混在。&lt;/strong>&lt;/h3>
→JavaScriptによるチェックは、デプロイ不要なため手軽に利用でき、
&lt;p>チェックにサーバへのアクセスが不要なため、ユーザビリティ的にも良いが、&lt;/p>
&lt;p>JavaScript自体、書き換え可能なため不正な値がサーバにPOSTされる可能性がある。&lt;/p>
&lt;p> &lt;/p>
&lt;p>一方、Apexによるチェックは、デプロイやテストクラスの修正が必要になるが、&lt;/p>
&lt;p>サーバにPOSTされた値を検証するため、不正な値が来ても問題ない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>こうしたトレードオフにより、両者を併用することがセキュリティ的にはベストな実装。&lt;/p>
&lt;p>デプロイ不要という手軽さ故、暫定対応的にJavaScriptのみのバリデーションを実装することが多いが、&lt;/p>
&lt;p>飽くまでも暫定対応。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Apexによるチェックと書いたけど、入力規則をうまく使えば、サーバサイド（Apex）でのバリデーションチェックすらも要らない。&lt;/p>
&lt;p>そもそもMVC的にはコントローラではなくモデルにバリデーションチェックを入れるべきだから、&lt;/p>
&lt;p>入力規則やトリガに任せるのが一番良いんだろうけど…。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. カスタムボタンのOnClickJSでの実装。&lt;/strong>&lt;/h3>
→これはOnClickJSでSOAP API(Ajax Tool Kit)を利用するパターンで、
&lt;p>カスタムSOAP APIを作って、それを呼び出すパターンが良い実装。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Apexクラスであればテストクラスが利用できるし、色々と再利用も可能。&lt;/p>
&lt;p>OnClickJSで標準のSOAP APIをごりごり使うのも良いけど、&lt;/p>
&lt;p>APIコール数の消費を抑えたり、単体テスト自動化を実装するためにも&lt;/p>
&lt;p>カスタムSOAP APIでのApexクラスの利用を考えたほうが良い。&lt;/p>
&lt;p> &lt;/p>
&lt;p>っていうか、個人的にはカスタムボタン使うくらいだったら、&lt;/p>
&lt;p>インラインVFでAPIコール無しに自由にJavaScriptとApexクラスで実装しようよって感じなんだけど。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. ApexをREST APIとして利用して、&lt;/strong>&lt;/h3>
&lt;h3>&lt;strong>HTML5,JavaScriptでゴリゴリとアプリを書くっていうパターン。&lt;/strong>&lt;/h3>
→最近のWebアプリはこんな感じだと思うので詳細は割愛。
&lt;p>force.comではRemoteAction(Salesforceが出しているライブラリとしては&lt;a title="https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit/" href="https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit/">remoteTK&lt;/a>)を利用する。&lt;/p>
&lt;p> &lt;/p>
&lt;p>どのパターンにおいても意識しないといけないことが「単体テストの自動化」ということ。&lt;/p>
&lt;p>Apexクラスにはテストクラスと呼ばれるテスト自動化の仕組みがあり、比較的利用がしやすい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>一方JavaScriptの方は一般的なWebでの方法は確立されているものの、&lt;/p>
&lt;p>導入の難易度が比較的高く、force.comでのテスト自動化が難しいように感じる。（OnClickJSとかでは特に）&lt;/p>
&lt;p> &lt;/p>
&lt;p>アジャイル開発なforce.com開発において（というかアジャイルじゃなくても）テスト自動化は超重要事項。&lt;/p>
&lt;p>salesforce側はMobileの波を受けて、JavaScript開発を薦めている感じだから&lt;/p>
&lt;p>きっとJavaScriptのテスト自動化もsalesforce側で、つまりPaas的に提供される日がいつか来るんじゃないかと。&lt;/p></description></item><item><title>Salesforceにおけるカスタム設定の利用法</title><link>https://blog.freedom-man.com/salesforce_custom_setting.html</link><pubDate>Sun, 01 Dec 2013 19:18:04 +0000</pubDate><guid>https://blog.freedom-man.com/salesforce_custom_setting.html</guid><description>&lt;p>Salesforceのカスタム設定がかなり使えるので書いてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>まず、Salesforceのカスタム設定には、リスト形式と階層形式の2種類が存在する。&lt;/p>
&lt;p> &lt;/p>
&lt;p>リスト形式は他オブジェクトと関連付けることが出来ないこと以外は、&lt;/p>
&lt;p>通常のオブジェクトと同じような機能をもっており、&lt;/p>
&lt;p>カスタム設定の機能であるSOQLのコストをかけずに設定レコードを取得したり&lt;/p>
&lt;p>データをキャッシュすることができるもので、ApexやAPI経由でのみ利用することが可能。&lt;/p>
&lt;p> &lt;/p>
&lt;p>一方、階層形式は組織・ユーザ・プロファイル毎に定義することが出来る設定値で&lt;/p>
&lt;p>通常のオブジェクトと同じような振る舞いをするリスト形式と異なり、&lt;/p>
&lt;p>あるユーザが取得できるカスタム設定は1レコードのみになる。&lt;/p>
&lt;p>ユーザが決定されると、取得できるレコードが1つに決まるため、&lt;/p>
&lt;p>こちらはApex、API経由以外に数式（カスタム項目、入力規則、ワークフロールール）や&lt;/p>
&lt;p>Visualforceページ単体（Apexページで値を明示的に値を取得する必要がない）でも利用が可能。&lt;/p>
&lt;p> &lt;/p>
&lt;p>「使える」方はこの階層形式の方なので、こちらの具体的な利用方法について書いてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. バッチ実行サイズや変更の可能性のある固定値をSalesforce上に持たせたい場合&lt;/strong>&lt;/h3>
→変更の可能性のある固定値を「組織のデフォルト値」に持たせれば、
&lt;p>変更があった時も開発の必要がない。（設定値を変更するだけでOK）&lt;/p>
&lt;p>他にも消費税等を数式で「*0.05」とハードコーディングする必要がなくなり、&lt;/p>
&lt;p>数式に利用している変更しうる固定値を定義・利用することが可能。&lt;/p>
&lt;p>VFページ内では「$Setup.～」の形式で書けばそのまま利用できるのも利点で、&lt;/p>
&lt;p>JavaScriptで利用したい固定値をApexクラスのプロパティ値無しに定義できる。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. プロファイル・ユーザによってVisualforceページや数式の見せ方を変更したい場合&lt;/strong>&lt;/h3>
→例えばある特定ユーザ・プロファイルの条件を満たすユーザの
&lt;p>VFページの表示・非表示を切り替える等という要件があり、&lt;/p>
&lt;p>さらにその条件がフレキシブルに変更可能にしないといけない場合に利用できる。&lt;/p>
&lt;p>また、カスタム設定を使用した数式項目をレポートやリストビューに組み込むことで&lt;/p>
&lt;p>ユーザやプロファイルを横断したグループ毎に、レポートの見せ方を変えることが出来る。&lt;/p>
&lt;p> &lt;/p>
&lt;p>このように、開発でもカスタマイズでも様々な恩恵がある。&lt;/p>
&lt;p>特に開発者にとってはVFページ等で変更の都度、コントローラ・テストクラスの修正とデプロイ作業をするという手間を&lt;/p>
&lt;p>カスタム設定の利用で削減できる可能性があるのは大きな魅力と言える。&lt;/p>
&lt;p>また、Salesforceの旨味を殺さないための、&lt;/p>
&lt;p>「カスタマイザブル」な実装設計にするためにもカスタム設定を利用することは重要かと。&lt;/p>
&lt;p>カスタマイズでも数式項目やWF、カスタムボタンのURLパラメータ等の固定値を&lt;/p>
&lt;p>一箇所に集束させることによる保守面でのメリットは大きい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、salesforceを導入されている皆さん、カスタム設定（階層）を使いましょう！&lt;/p></description></item><item><title>force.com開発におけるトリガのリスクとワークフロールールの共存について</title><link>https://blog.freedom-man.com/forcecom_triggerrisk_workflow.html</link><pubDate>Sun, 01 Dec 2013 09:52:15 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_triggerrisk_workflow.html</guid><description>&lt;p>Salesforceデベロッパーにおける永遠の課題（？）である&lt;/p>
&lt;p>トリガとワークフロールール（以後、WFと略す）の共存について書いてみる。&lt;/p>
&lt;p>まずは両者のメリット・デメリットを記述する。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>WF&lt;/strong>&lt;/h3>
[メリット]
&lt;p>・ノン開発のカスタマイズにより、簡単かつスピーディーにビジネスロジックを構築可能。&lt;/p>
&lt;p>[デメリット]&lt;/p>
&lt;p>・対応できないビジネスロジックが存在する。&lt;/p>
&lt;p>・項目自動更新では数式のコンパイルサイズに制限がある。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>トリガー&lt;/strong>&lt;/h3>
[メリット]
&lt;p>・WFよりビジネスロジックの自由度が高く、カスタマイズのみではできない複雑なビジネスロジックでも対応可能&lt;/p>
&lt;p>[デメリット]&lt;/p>
&lt;p>・ビジネスロジックの再構成に開発・テストコード構成・デプロイが必要になるため、フレキシブルな対応がしづらい。&lt;/p>
&lt;p>・あらゆるDML操作によって起動する可能性があるため、綿密な設計が必要になる。&lt;/p>
&lt;p>（WFでも同様だが、ビジネスロジックが複雑になりがちで、他レコードのDML操作も可能なトリガでは特に注意が必要。）&lt;/p>
&lt;p>・トリガ独自のガバナ制限（SOQLで10万件以上の母数のレコードを検索するときにインデックス項目が必要等）&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、両者を併用することで以下のデメリットが存在する。&lt;/p>
&lt;p>・以下URLに記載されるトリガーとWFの実行順序を考慮した設計が必要になる。&lt;/p>
&lt;p>例えば、トリガーの処理結果を受けてWFの項目自動更新処理が行われた場合、&lt;/p>
&lt;p>それによって再度トリガー処理が走るという事象を考慮した設計が必要になる。&lt;/p>
&lt;p>&lt;a href="http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_triggers_order_of_execution.htm?SearchType=Stem">http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_triggers_order_of_execution.htm?SearchType=Stem&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>上記事項をまとめると、&lt;/p>
&lt;p>「WFは手軽に構成できるビジネスロジックであるが、複雑なビジネスロジックに対応できず、&lt;/p>
&lt;p>トリガーは手軽ではないが複雑なビジネスロジックに対応可能で&lt;/p>
&lt;p>両者を組み合わせると、あらゆるDML操作によって起動するトリガ処理と、&lt;/p>
&lt;p>WFとトリガーの実行順序を考慮した難解な設計作業が必要になる。」&lt;/p>
&lt;p>ということ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>よってSalesforceにおける設計においては以下のような設計方針が存在する。&lt;/p>
&lt;p>これは、ビジネスロジックの棄却はしない前提で、&lt;/p>
&lt;p>現実的なSalesforce導入において「混在したWFとトリガのロジックを全て見渡すことは極めて困難」&lt;/p>
&lt;p>という立ち位置での設計方針である。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>1. 各オブジェクトに対するビジネスロジックの構成はWFかトリガーのどちらかに寄せる。&lt;/strong>&lt;/h3>
→WFとトリガーの実行順序を考慮した複雑な設計が不要になり、ロジックが見えやすくなる。
&lt;p> &lt;/p>
&lt;h3>&lt;strong>2. トリガーによる他レコード更新は可能な限り行わない。&lt;/strong>&lt;/h3>
→他レコードの更新により、他レコードのWF・トリガーが走るというトリガーリレーを防ぐことができ、
&lt;p>ロジックが見えやすくなる。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>3. トリガの作成というソリューションを避ける&lt;/strong>&lt;/h3>
&lt;h3>&lt;strong>（インラインVFやカスタムボタンによる手動起動）&lt;/strong>&lt;/h3>
→ロジックの見通しがしづらいトリガ自体をなくすことができるが、運用が回りづらくなる危険性もある。
&lt;p> &lt;/p>
&lt;p>それぞれについて解説する。&lt;/p>
&lt;p>1の場合は、ビジネスロジックが簡単な場合はWFに寄せれるし、&lt;/p>
&lt;p>複雑なロジックが存在し、簡単なロジックが不変な場合（ビジネスロジックの変更がない）は&lt;/p>
&lt;p>トリガーに寄せれるということになる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>2の方針は、トリガーの最悪なシナリオは複雑なビジネスロジックによる自レコードの更新よりも&lt;/p>
&lt;p>例え簡単なビジネスロジックでも他レコードの更新の方がリスクが高い為である。&lt;/p>
&lt;p>トリガーリレーが走るとロジック上問題がなくとも、&lt;/p>
&lt;p>SOQL、DML、ステップ数等のガバナ制限に抵触する可能性が増えてしまう。&lt;/p>
&lt;p> &lt;/p>
&lt;p>3の構成案としては&lt;/p>
&lt;p>例えば、参照関係における子オブジェクトの集計や積上集計項目数の枯渇で、&lt;/p>
&lt;p>Apex開発での集計をする場合にはトリガではなく、&lt;/p>
&lt;p>・標準画面のインラインVFページにボタンを置いて集計処理をさせる。&lt;/p>
&lt;p>・OnClickJS等のカスタムボタンで集計処理をさせる。&lt;/p>
&lt;p>・短い時間間隔によるバッチ集計処理をさせる。&lt;/p>
&lt;p>といった実装をするということ。&lt;/p>
&lt;p>「オペレーションを簡素にする」「即時反映」という絶対要件がある場合は&lt;/p>
&lt;p>このパターンは使えない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>いずれも個人的な意見・対応案ではあるけれど、&lt;/p>
&lt;p>気軽にビジネスロジックやERの変更が可能なSalesforceにおいて「保守性」を担保する実装方針を&lt;/p>
&lt;p>デベロッパーは意識すべきで、トリガとWFの共存という課題は特に考慮しておかないとダメなんじゃないかなーと。&lt;/p></description></item><item><title>LinuxクライアントからLinuxサーバ(nfs)やWindowsサーバ(samba)へマウントしてみた。</title><link>https://blog.freedom-man.com/linux_nfs_samba.html</link><pubDate>Sat, 30 Nov 2013 09:39:07 +0000</pubDate><guid>https://blog.freedom-man.com/linux_nfs_samba.html</guid><description>&lt;p>AWSのVPC関連の仕事でLinuxへのマウントをやってみたので手順について書いてみる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>まずは共有サーバ（マウントされる側）は&lt;/p>
&lt;p>root権限でnfsとrpcbindをインストールして各種設定後、サービスをスタートする。&lt;/p>
&lt;h3>1. サービスのインストール&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>yum -y install nfs-utils
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>yum -y install rpcbind
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3>2. マウント設定&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>mkdir /nfs_dir
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chown nfsnobody:nfsnobody /nfs_dir
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>vim /etc/exports　で以下のように編集
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> /nfs_dir 10.0.0.0/255.255.255.0&lt;span style="color:#0550ae">(&lt;/span>rw,root_squash&lt;span style="color:#0550ae">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3>3. サービスのスタート&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>/etc/init.d/rpcbind start
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>/etc/init.d/nfs start
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>クライアント（マウントする側）は
各種サービスインストール後、マウントするだけ。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>yum -y install nfs-utils
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>yum -y install rpcbind
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkdir /mnt/nfs_dir
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mount -t nfs 10.0.0.0:/nfs_dir /mnt/nfs_dir
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>※マウントは/etc/fstabにマウント情報を記載してマウントした方が良いかも。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Linuxサーバのマウント関連は以下のURLが詳しいです。&lt;/p>
&lt;p>&lt;a href="http://www.oss-d.net/nfs/1.2">&lt;a href="http://www.oss-d.net/nfs/1.2">http://www.oss-d.net/nfs/1.2&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://unixlife.jp/linux/centos-6/nfs-server.html">&lt;a href="http://unixlife.jp/linux/centos-6/nfs-server.html">http://unixlife.jp/linux/centos-6/nfs-server.html&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;p>ついでに、あんまりニーズは無いかもしれないけど、&lt;/p>
&lt;p>LinuxクライアントからWindowsサーバへのマウントも試してみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>まずはサーバ側(Windows)で共有フォルダの設定をしてから、&lt;/p>
&lt;p>クライアント側で以下を実行する。&lt;/p>
&lt;h3>1. Sambaとcifs-utilsのインストール&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>yum install samba-client
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>yum install cifs-utils
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3>2. マウント&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>mount -t cifs //&amp;lt;Windows server IP address&amp;gt;/share /mnt/share -o &lt;span style="color:#953800">username&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&amp;lt;username&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>検証にはEC2のAmazonLinuxっていうよくわかんないディストリビューション（？）使ってたから&lt;/p></description></item><item><title>force.comにおけるCSRF対策について</title><link>https://blog.freedom-man.com/forcecom_csrf.html</link><pubDate>Wed, 27 Nov 2013 00:57:39 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_csrf.html</guid><description>&lt;p>force.com開発におけるCSRF対策について。&lt;/p></description></item><item><title>force.com Web APIにおけるトランザクション処理</title><link>https://blog.freedom-man.com/forcecom_webapi_transaction.html</link><pubDate>Sun, 24 Nov 2013 22:04:57 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_webapi_transaction.html</guid><description>&lt;p>force.com Web APIにはREST APIとSOAP APIが存在する。&lt;/p>
&lt;p>どちらもステートレスなAPI故に標準のAPIでは複雑なトランザクション処理を行うことが出来ない。&lt;/p>
&lt;p>例えば、&lt;/p>
&lt;ol>
&lt;li>
&lt;p>見積オブジェクト（親オブジェクト）を作成。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>1が成功した場合、1で作成した見積オブジェクトに紐づく見積明細オブジェクト（子オブジェクト）を作成。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>失敗した場合は、エラー処理を行う。&lt;/p>
&lt;ol start="3">
&lt;li>2で見積明細オブジェクトを作成するのに失敗した場合は、見積オブジェクト作成前までロールバックを行う。&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>といったトランザクション処理を行う場合は標準のAPIだけでは対応できない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>代わりにforce.comではカスタムのREST API, SOAP APIを作成することが出来る。&lt;/p>
&lt;p>このカスタムのAPIは特定Apexクラスのメソッドを呼び出すことが出来る仕組みになっており、&lt;/p>
&lt;p>Apexクラス内であれば、Savepoint設置やDatabase.rollbackを行うことができるため、&lt;/p>
&lt;p>上記のような要件を満たすことが出来る。&lt;/p>
&lt;p> &lt;/p>
&lt;p>作成方法は簡単で&lt;/p>
&lt;p>REST APIは&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">@RestResource&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>urlMapping&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#0550ae">/&lt;/span>TestRest&lt;span style="color:#0550ae">/*&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>global&lt;span style="color:#fff"> &lt;/span>with&lt;span style="color:#fff"> &lt;/span>sharing&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">CustomRESTController&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">@HttpPost&lt;/span>&lt;span style="color:#fff"> 
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>global&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>String&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">customPost&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>RestRequest&lt;span style="color:#fff"> &lt;/span>req&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>RestContext&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">request&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>RestResponse&lt;span style="color:#fff"> &lt;/span>res&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>RestContext&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">response&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>test&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こんな感じで書いて、&lt;/p>
&lt;p>&lt;a href="https://instance.salesforce.com/services/apexrest/TestRest/">https://instance.salesforce.com/services/apexrest/TestRest/&lt;/a>&amp;hellip;をエンドポイントとして呼び出せばOK。&lt;/p>
&lt;p> &lt;/p>
&lt;p>SOAPの方は&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>global&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">MyWebService&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>webService&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#fff"> &lt;/span>Id&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#6639ba">makeContact&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>String&lt;span style="color:#fff"> &lt;/span>lastName&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>Account&lt;span style="color:#fff"> &lt;/span>a&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>Contact&lt;span style="color:#fff"> &lt;/span>c&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">new&lt;/span>&lt;span style="color:#fff"> &lt;/span>Contact&lt;span style="color:#1f2328">(&lt;/span>lastName&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Weissman&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>AccountId&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>a&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Id&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>insert&lt;span style="color:#fff"> &lt;/span>c&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#cf222e">return&lt;/span>&lt;span style="color:#fff"> &lt;/span>c&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>こんな感じで書いたクラスのWSDLをエクスポートして、&lt;/p></description></item><item><title>開発環境 = Virtualbox + linuxbean + Dropboxの導入</title><link>https://blog.freedom-man.com/virtualbox_linuxbean_dropbox.html</link><pubDate>Sat, 23 Nov 2013 10:13:19 +0000</pubDate><guid>https://blog.freedom-man.com/virtualbox_linuxbean_dropbox.html</guid><description>&lt;p>windowsにおける開発を行っていて&lt;/p>
&lt;p>・プログラムの情報がwindows環境よりもmac,linux環境の方が多い（気がする）&lt;/p>
&lt;p>・パッケージ管理システムが羨ましい（&lt;a title="http://chocolatey.org/" href="http://chocolatey.org/">chocolatey&lt;/a>があるけど…）&lt;/p>
&lt;p>・FHSじゃないからどこに設定ファイルがあるのか探すのがキツイ。&lt;/p>
&lt;p>・コマンドプロンプトのシェル能力に不満。&lt;/p>
&lt;p> &lt;/p>
&lt;p>とlinuxバンザイ！な展開で、とはいえメインOSをlinuxにしたりデュアルにするのも面倒だったので&lt;/p>
&lt;p>&lt;a title="https://www.virtualbox.org/" href="https://www.virtualbox.org/">Virtualbox&lt;/a>で軽量linuxの&lt;a title="http://sourceforge.jp/projects/linuxbean/" href="http://sourceforge.jp/projects/linuxbean/">linuxbean&lt;/a>を導入することにした。&lt;/p>
&lt;p> &lt;/p>
&lt;p>手順としては、&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Virutualboxのインストール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>linuxbeanのisoファイルをダウンロード&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Virtualboxを起動し、新しいVMをlinuxの設定で作成&lt;/p>
&lt;/li>
&lt;li>
&lt;p>VMを起動(2でダウンロードしたisoを起動ディスクとして指定）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>isoをliveCDとしてOSが起動するので、デスクトップ上にあるアイコンをクリックしてインストール&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>という流れ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>インストール後は&lt;/p>
&lt;ol>
&lt;li>
&lt;p>メニューのデバイス＞Insert Guest Additions CD Imageをクリック&lt;/p>
&lt;/li>
&lt;li>
&lt;p>/mediaにVBOXADDITIONS～というディレクトリがあるので、そこに移動&lt;/p>
&lt;/li>
&lt;li>
&lt;p>VBoxLinuxAdditions.runを起動&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>とすることで、共有フォルダ使えたり、ホストOS-&amp;gt;ゲストOSのカーソル移動をシームレスに出来たりします。&lt;/p>
&lt;p> &lt;/p>
&lt;p>共有フォルダの設定は&lt;/p>
&lt;ol>
&lt;li>メニューのデバイス＞共有フォルダ設定で設定を行う&lt;/li>
&lt;/ol>
&lt;p>2. sudo usermod -a -G vboxsf &lt;username>　でvboxsfグループにログインユーザを追加&lt;/p>
&lt;p>することで可能。&lt;/p>
&lt;p> &lt;/p>
&lt;p>この共有フォルダをdropboxに向けてあげることで、&lt;/p>
&lt;p>dropboxにソースコードを置いてlinux環境で修正・実行することが可能になります。&lt;/p>
&lt;p>もちろんlinux版のdropboxをインストールしても良いですが、&lt;/p>
&lt;p>単純にネットワーク通信量2倍になるし、あんまり効率的じゃない気がします。&lt;/p>
&lt;p> &lt;/p>
&lt;p>また、ゲストOS側でWebサーバやアプリを立ち上げて、それをホストOSで見る場合には&lt;/p>
&lt;ol>
&lt;li>
&lt;p>ゲストOS側でFirewallの設定（ホストOSからのパケットを許可してあげれば良い）&lt;/p>
&lt;/li>
&lt;li>
&lt;p>ネットワーク設定でポートフォワーディングを行う。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;a href="http://www.nekotricolor.com/blog/2013/04/25/956/">&lt;a href="http://www.nekotricolor.com/blog/2013/04/25/956/">http://www.nekotricolor.com/blog/2013/04/25/956/&lt;/a>&lt;/a>&lt;/p>
&lt;p>と設定を行うことで、ホストOSでlocalhost:8888のURLを叩くと&lt;/p>
&lt;p>ゲストOSのWebサーバ(localhost:80)にアクセスできたり、&lt;/p>
&lt;p>sshでログイン出来たりします。&lt;/p>
&lt;p> &lt;/p>
&lt;p> &lt;/p>
&lt;p>これで&lt;/p>
&lt;p>puttyに頼らずsshできるし&lt;/p>
&lt;p>winscpに頼らずscpできるし&lt;/p>
&lt;p>gitのインストールもワンコマンドだし&lt;/p>
&lt;p>grepもfindもlessもvimも使えてbashバンザイ！だし&lt;/p>
&lt;p>linuxサーバを本番環境とする場合は開発環境としても利用できる&lt;/p>
&lt;p> &lt;/p>
&lt;p>というサイコーな環境が出来ました。&lt;/p>
&lt;p>dropboxとか共有フォルダを利用せずにgit使うのも有りだと思います。（っていうか普通はそっち使うか）&lt;/p></description></item><item><title>Visualforceにおけるajaxあれこれ</title><link>https://blog.freedom-man.com/visualforce_ajax.html</link><pubDate>Sat, 23 Nov 2013 00:59:58 +0000</pubDate><guid>https://blog.freedom-man.com/visualforce_ajax.html</guid><description>&lt;p>force.comのVisualforceページにおいてajaxを行う方法について書いてみる。&lt;/p>
&lt;h2 id="1-apexcommandbutton等のrerender">1. &amp;lt;apex:commandButton&amp;gt;等のrerender&lt;/h2>
&lt;p>&lt;code>&amp;lt;apex:commandButton&amp;gt;&lt;/code>等のコントローラのメソッドを呼び出す処理を行うタグに対して&lt;/p>
&lt;p>rerender属性(メソッド呼び出しの結果、再描画するエリア指定)を設定することで、メソッド呼び出し部分をsubmitではなくajaxで処理するというもの。&lt;/p>
&lt;p>apexタグで記載された表示を再描画する場合には有効。&lt;br>
例えば、&lt;code>&amp;lt;apex:pageBlockTable&amp;gt;&lt;/code> で一覧表示したデータをメソッド呼び出し後に再描画するとか。&lt;/p>
&lt;p>コールバック処理はoncomplete属性に書き込むことになる。&lt;/p>
&lt;h2 id="2-apexactionfunction">2. &amp;lt;apex:actionFunction&amp;gt;&lt;/h2>
&lt;p>コントローラのあるメソッドの呼び出しをJavaScript関数の呼び出しで実現できるようにするためのタグ。&lt;/p>
&lt;p>1と同様にrerender,oncomplete属性を持たすことが可能。&lt;/p>
&lt;p>1の場合はapexタグで指定されたボタンやリンクのクリックと自動的に関連付けられてajax処理が行われるが、
&lt;code>&amp;lt;apex:actionFunction&amp;gt;&lt;/code> の場合は、グローバルスコープにJavaScript関数が定義されることにより、
任意のJavaScript処理内にコントローラのメソッド呼び出し(ajax)処理を埋め込むことが出来るのが利点。&lt;/p>
&lt;p>1,2ともにメリット、デメリットは以下の通り&lt;/p>
&lt;h3 id="メリット">メリット&lt;/h3>
&lt;ul>
&lt;li>インスタンスメソッドの呼び出しなので、コントローラの状態(ViewState)を変更することが出来る&lt;/li>
&lt;li>再描画処理を自動的にSalesforceが行ってくれる（JSオンリーの場合はajaxによるデータ取得→取得したら自前DOM操作という流れ）&lt;/li>
&lt;/ul>
&lt;h3 id="デメリット">デメリット&lt;/h3>
&lt;ul>
&lt;li>任意の引数を渡し辛い（&lt;code>&amp;lt;apex:inputHidden&amp;gt;&lt;/code>などを利用すれば行けるが、コントローラにインスタンス変数が増える）&lt;/li>
&lt;li>任意の返り値を返す処理が書きづらい（非表示にしたタグで返り値実装できるが、コントローラにインスタンス変数が増える）&lt;/li>
&lt;li>oncomplete属性によるコールバックで、通常のajax的な書き方とは異なり、jQuery deffered等の技術が使いづらそう（出来ないことは無さそうだけど…）&lt;/li>
&lt;/ul>
&lt;h2 id="3-remoteaction">3. @RemoteAction&lt;/h2>
&lt;p>メソッドに@RemoteActionアノテーションを付与して、静的メソッドとすることで&lt;/p>
&lt;p>VisualforceページのJavaScriptによる呼び出し(ajax)ができる仕組み。&lt;/p>
&lt;p>こちらはVFページのコントローラのインスタンスと紐付いていないため、&lt;/p>
&lt;ul>
&lt;li>再描画処理などが出来ない→再描画する場合は自前DOM操作
* コントローラの状態(ViewState)の変更ができない→更新する必要がある場合は、別途仕組みを作らないとダメ。&lt;/li>
&lt;/ul>
&lt;p>というデメリットが有る一方、&lt;/p>
&lt;p>* メソッドに渡せるパラメータをJavaScript側で自由にコントロールできる
* コールバックを含む一連の処理が普通に書ける。（oncomplete属性による擬似的な?コールバックではないのでdefferedが使える！）
* メソッドの返り値が自由にコントロールできる。&lt;/p>
&lt;p>というメリットが有るため、&lt;/p>
&lt;p>apexタグなんかに頼らずに自前JavaScriptで実装するぜ！&lt;/p>
&lt;p>っていうタイプには向いている方法。&lt;/p>
&lt;h2 id="4-自前ajaxjqueryのajax等">4. 自前ajax(jQueryの$.ajax等)&lt;/h2>
&lt;p>Visualforceページに自前RESTページを作成し、自前RESTページにhttpリクエストをajaxで投げて実装する方法。&lt;/p>
&lt;p>例えば、REST.pageというVFページを作成し、コントローラ(REST.cls)のコンストラクタあるいは初期処理(apex:pageのaction属性)で
URLパラメータに応じたデータ操作を行うように実装して、呼び出し元のVFページ内で&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">ajax&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>  &lt;span style="color:#1f2328">url&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;/apex/REST&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>  &lt;span style="color:#1f2328">data&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">action&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;select&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">name&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;test&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ってな感じで呼び出せばOK。&lt;/p>
&lt;p>メリット・デメリットは3と同様。&lt;/p>
&lt;p>3との違いは完全に自由なAPIを設計できる一方で、CSRFを自前で対策しないといけないところ。&lt;/p>
&lt;p>（1, 2, 3はSalesforceが自動的にCSRFトークンを生成・送信してくれます）&lt;/p>
&lt;h2 id="まとめ">まとめ&lt;/h2>
&lt;ul>
&lt;li>処理実行→実行結果を元に再描画等の処理であれば1,2&lt;/li>
&lt;li>JavaScript処理の為のデータ取得・SFDCをDBとしたJavaScriptゴリゴリのアプリを作る場合は3,4&lt;/li>
&lt;/ul>
&lt;p>って感じでしょうかね。&lt;/p>
&lt;p>VFのViewState突破するとかで3,4を利用するのも有りかもしれないけど、それなりのコストは掛かるかと思います。&lt;/p></description></item><item><title>windowsのパッケージ管理システムChocolatey触ってみた。</title><link>https://blog.freedom-man.com/windows_chocolatey.html</link><pubDate>Wed, 13 Nov 2013 02:11:17 +0000</pubDate><guid>https://blog.freedom-man.com/windows_chocolatey.html</guid><description>&lt;p>Linuxにはyumとかapt-getとかのパッケージ管理システムがあり、&lt;/p>
&lt;p>インストール時に依存関係とか解決してくれるし、&lt;/p>
&lt;p>インストールもコマンド叩くだけで自動的にやってくれるから&lt;/p>
&lt;p>windowsにもこういうの欲しいなーと思っていたところで&lt;/p>
&lt;p>&lt;a title="http://chocolatey.org/" href="http://chocolatey.org/">chololatey&lt;/a>というパッケージ管理システムがあることを知りました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>公式サイトに有るように、インストールは非常に簡単で&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-powershell" data-lang="powershell">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#953800">@powershell&lt;/span> -NoProfile -ExecutionPolicy unrestricted -Command &lt;span style="color:#0a3069">&amp;#34;iex ((new-object net.webclient).DownloadString(&amp;#39;https://chocolatey.org/install.ps1&amp;#39;))&amp;#34;&lt;/span> &lt;span style="color:#1f2328">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#6639ba">SET &lt;/span>PATH&lt;span style="color:#1f2328">=&lt;/span>&lt;span style="color:#cf222e">%&lt;/span>PATH&lt;span style="color:#1f2328">%;&lt;/span>&lt;span style="color:#cf222e">%&lt;/span>systemdrive&lt;span style="color:#1f2328">%\&lt;/span>chocolatey&lt;span style="color:#1f2328">\&lt;/span>bin
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>をコマンドプロンプトで叩くだけ！&lt;/p>
&lt;p> &lt;/p>
&lt;p>あとは&lt;a title="http://chocolatey.org/packages" href="http://chocolatey.org/packages">ここ&lt;/a>にあるパッケージをcinstコマンドでインストールしていくだけ！&lt;/p>
&lt;p>よく使うプログラムは大抵登録されているので、非常に便利。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみに、&lt;a title="https://github.com/chocolatey/chocolatey-cookbook" href="https://github.com/chocolatey/chocolatey-cookbook">chefも対応している&lt;/a>のでクリーンな環境で&lt;/p>
&lt;p>自動的に必要なプログラムをインストールすることも可能みたい。&lt;/p>
&lt;p>ただ、windowsの場合はlinuxと違ってディストリビューションによるコマンドの差異がないし、&lt;/p>
&lt;p>作業用の環境として利用するだけで、サーバと違って細かい設定もあまりないので、&lt;/p>
&lt;p>単なるbatファイルとかでも十分だと思う。&lt;/p>
&lt;p> &lt;/p>
&lt;p>更にパッケージは開発者登録をしたユーザがアップロードすることが出来ます。(&lt;a href="https://github.com/chocolatey/chocolatey/wiki/CreatePackages">&lt;a href="https://github.com/chocolatey/chocolatey/wiki/CreatePackages">https://github.com/chocolatey/chocolatey/wiki/CreatePackages&lt;/a>&lt;/a>)&lt;/p>
&lt;p> &lt;/p>
&lt;p>chocolateyは最近のものじゃないみたいで、&lt;/p>
&lt;p>あんまり盛り上がっていないのが不思議でしょうがない。&lt;/p>
&lt;p>最近、会社のPC壊れたりしてPCの環境を設定するのに時間がかかってたから、&lt;/p>
&lt;p>こういうのあると嬉しい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>ただし、必ずしも最新のものを取ってきているわけじゃないので、&lt;/p>
&lt;p>最新のもので検証したい場合は、別途インストーラでインストールした方が良いけど&lt;/p>
&lt;p>最新じゃなくてよいプログラムは一括でchocolateyで登録した方が良いと思う。&lt;/p></description></item><item><title>djangoのbuilt-in viewの利用</title><link>https://blog.freedom-man.com/django_built-in-view.html</link><pubDate>Sun, 03 Nov 2013 23:47:14 +0000</pubDate><guid>https://blog.freedom-man.com/django_built-in-view.html</guid><description>&lt;p>djangoのユーザ管理ではビルトインのviewが利用できる。&lt;/p>
&lt;p>&lt;a href="https://docs.djangoproject.com/en/1.5/topics/auth/default/#module-django.contrib.auth.views">&lt;a href="https://docs.djangoproject.com/en/1.5/topics/auth/default/#module-django.contrib.auth.views">https://docs.djangoproject.com/en/1.5/topics/auth/default/#module-django.contrib.auth.views&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>上記URLに書いてあるようにloginの場合はurls.pyに&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^accounts/login/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;django.contrib.auth.views.login&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;template_name&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;myapp/login.html&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>みたいな感じで、viewにビルトインのビューと任意のテンプレートを設定してあげて、&lt;/p>
&lt;p>テンプレートにはこれまたデフォルトで設定されているformを色々と弄ってあげればOK。&lt;/p>
&lt;p>（※上記参照）&lt;/p>
&lt;p> &lt;/p>
&lt;p>と、ここまでは使い方がソースコードとともに説明されてあるから良いけど、&lt;/p>
&lt;p>logout以降はサンプルソースとか使い方が詳細に書いていない！&lt;/p>
&lt;p>本当にどこにも書いてない上に、ググっても出てこないので、&lt;/p>
&lt;p>django使いはソースコードを読んで理解しているのか！？&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、ソースコード直接読んで何となく理解しました。&lt;/p>
&lt;p>基本的にはフィールドの設定とバリデーションを組んでいるだけで、&lt;/p>
&lt;p>templateは利用するフィールドを理解していれば、&lt;/p>
&lt;p>あとはPOSTするだけでOKな感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>具体的には&lt;/p>
&lt;ol>
&lt;li>{% form %}とか{% for field in form.base_fields %}{{  field }}{% endfor %}とかで&lt;/li>
&lt;/ol>
&lt;p>出力するフィールド名をメモ&lt;/p>
&lt;ol start="2">
&lt;li>対象フィールド名をformタグ内に書き込む(ex.  {{ form.old_password}})&lt;/li>
&lt;/ol>
&lt;p>な流れで不自由なく使えると思う。&lt;/p>
&lt;p> &lt;/p>
&lt;p>っていうかそんな大したソースじゃないので&lt;a title="https://github.com/django/django" href="https://github.com/django/django">github&lt;/a>で解析するのが一番かも。&lt;/p>
&lt;p> &lt;/p>
&lt;p>で、password_changeはこんな感じで動いた。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> extends &lt;span style="color:#0a3069">&amp;#34;user/base.html&amp;#34;&lt;/span> &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> block title &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>パスワード変更&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> endblock &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> block contents &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;&lt;/span>form method&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;post&amp;#34;&lt;/span> action&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{&lt;/span>&lt;span style="color:#0a3069">% u&lt;/span>&lt;span style="color:#0a3069">rl &amp;#39;user:password_change&amp;#39; %}&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> csrf_token &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>table&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>tr&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>旧パスワード&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{{&lt;/span> form&lt;span style="color:#0550ae">.&lt;/span>old_password &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> &lt;span style="color:#cf222e">for&lt;/span> error &lt;span style="color:#0550ae">in&lt;/span> form&lt;span style="color:#0550ae">.&lt;/span>old_password&lt;span style="color:#0550ae">.&lt;/span>errors &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>span style&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;color:red;font-weight:bold;&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{{&lt;/span> error &lt;span style="color:#1f2328">}}&lt;/span>&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>span&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> endfor &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>tr&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>tr&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>新パスワード&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{{&lt;/span> form&lt;span style="color:#0550ae">.&lt;/span>new_password1 &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> &lt;span style="color:#cf222e">for&lt;/span> error &lt;span style="color:#0550ae">in&lt;/span> form&lt;span style="color:#0550ae">.&lt;/span>new_password1&lt;span style="color:#0550ae">.&lt;/span>errors &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>span style&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;color:red;font-weight:bold;&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{{&lt;/span> error &lt;span style="color:#1f2328">}}&lt;/span>&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>span&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> endfor &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>tr&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>tr&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>新パスワード&lt;span style="color:#1f2328">(&lt;/span>確認&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{{&lt;/span> form&lt;span style="color:#0550ae">.&lt;/span>new_password2 &lt;span style="color:#1f2328">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> &lt;span style="color:#cf222e">for&lt;/span> error &lt;span style="color:#0550ae">in&lt;/span> form&lt;span style="color:#0550ae">.&lt;/span>new_password2&lt;span style="color:#0550ae">.&lt;/span>errors &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>span style&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;color:red;font-weight:bold;&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">{{&lt;/span> error &lt;span style="color:#1f2328">}}&lt;/span>&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>span&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> endfor &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>td&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>tr&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;/&lt;/span>table&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0550ae">&amp;lt;&lt;/span>&lt;span style="color:#6639ba">input&lt;/span> &lt;span style="color:#6639ba">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;submit&amp;#34;&lt;/span> value&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;パスワード変更&amp;#34;&lt;/span> &lt;span style="color:#0550ae">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;/&lt;/span>form&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0550ae">%&lt;/span> endblock contents &lt;span style="color:#0550ae">%&lt;/span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Djangoでpjax！</title><link>https://blog.freedom-man.com/django_pjax.html</link><pubDate>Sun, 03 Nov 2013 21:57:59 +0000</pubDate><guid>https://blog.freedom-man.com/django_pjax.html</guid><description>&lt;p>今話題(?)の&lt;a title="https://github.com/defunkt/jquery-pjax" href="https://github.com/defunkt/jquery-pjax">pjax&lt;/a>をdjangoで使ってみることにした。&lt;/p>
&lt;p> &lt;/p>
&lt;p>百聞は一見に如かずということで、まずはソースから&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&amp;lt;!DOCTYPE html&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">html&lt;/span> &lt;span style="color:#1f2328">lang&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;ja&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">title&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>{% block title %}DjangoProject{% endblock %}&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">title&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">meta&lt;/span> &lt;span style="color:#1f2328">name&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;generator&amp;#34;&lt;/span> &lt;span style="color:#1f2328">content&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;PyScripter&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">meta&lt;/span> &lt;span style="color:#1f2328">charset&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;utf8&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {% load staticfiles %}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;{% static &amp;#39;jquery.pjax.js&amp;#39; %}&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">pjax&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;a&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">container&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;#pjax-container&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fragment&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;#pjax-container&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;submit&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;form&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">pjax&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">submit&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">event&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">container&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;#pjax-container&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fragment&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;#pjax-container&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">head&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">div&lt;/span> &lt;span style="color:#1f2328">id&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;pjax-container&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {% block contents %}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {% endblock %}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">div&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">body&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">html&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>load staticfilesと{% static &amp;lsquo;jquery.pjax.js&amp;rsquo; %}で静的ファイルを読み込んでます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>静的ファイルの設定はsetting.pyの&lt;/p>
&lt;p>STATICFILES_DIRSに対象ディレクトリを&lt;/p>
&lt;p>&amp;ldquo;C:/Users/admin/python/django/taskapp/static&amp;rdquo;&lt;/p>
&lt;p>みたいな感じで設定してあげればOK。&lt;/p>
&lt;p> &lt;/p>
&lt;p>これでstatic で読み込んだ時に自動的に対象パスを検索してくれます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そんで肝心のpjaxはベースとなるテンプレートファイルにJSで&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">$&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">document&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">pjax&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;a&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">container&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;#pjax-container&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">fragment&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;#pjax-container&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>みたいに書いてあげればOK。&lt;/p></description></item><item><title>Djangoのユーザモデル</title><link>https://blog.freedom-man.com/django_user_model.html</link><pubDate>Sat, 02 Nov 2013 23:21:43 +0000</pubDate><guid>https://blog.freedom-man.com/django_user_model.html</guid><description>&lt;p>DjangoにはデフォルトでUserモデルなるものが存在します。&lt;/p>
&lt;p>admin画面作ってログインしたときにAuthのところのUsersっていうモデルがそれ。&lt;/p>
&lt;p>もちろん最初に作成するadminユーザもUserモデル。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Userモデルは以下のURLで説明があります。例のごとく英語…。&lt;/p>
&lt;p>&lt;a href="https://docs.djangoproject.com/en/dev/topics/auth/">&lt;a href="https://docs.djangoproject.com/en/dev/topics/auth/">https://docs.djangoproject.com/en/dev/topics/auth/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://docs.djangoproject.com/en/dev/topics/auth/default/">&lt;a href="https://docs.djangoproject.com/en/dev/topics/auth/default/">https://docs.djangoproject.com/en/dev/topics/auth/default/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>まずはsettings.pyのINSTALLED_APPSに&lt;/p>
&lt;p>django.contrib.auth
django.contrib.contenttypes&lt;/p>
&lt;p>が記述されていることを確認。&lt;/p>
&lt;p>記述されていないorコメントアウトされていたら、&lt;/p>
&lt;p>設定後にpython manage.py syncdb&lt;/p>
&lt;p> &lt;/p>
&lt;p>その後は、自由にユーザモデルを作成したり、ログインしたり。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>1. ユーザの作成(views.py)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.contrib.auth.models&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> User
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Create&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>View&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">post&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> request&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user &lt;span style="color:#0550ae">=&lt;/span> User&lt;span style="color:#0550ae">.&lt;/span>objects&lt;span style="color:#0550ae">.&lt;/span>create_user&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;email&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;password&amp;#34;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user&lt;span style="color:#0550ae">.&lt;/span>is_staff &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">False&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user&lt;span style="color:#0550ae">.&lt;/span>save&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> redirect&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;user:detail&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> user_id&lt;span style="color:#0550ae">=&lt;/span>user&lt;span style="color:#0550ae">.&lt;/span>id&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>is_staffはアドミンサイトにログインできるかどうかを判別（true=ログイン可能）&lt;/p>
&lt;p> &lt;/p>
&lt;h3>2.ユーザログイン(views.py)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Login&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>View&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">post&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> request&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user &lt;span style="color:#0550ae">=&lt;/span> authenticate&lt;span style="color:#1f2328">(&lt;/span>username&lt;span style="color:#0550ae">=&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span> password&lt;span style="color:#0550ae">=&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#34;password&amp;#34;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> user &lt;span style="color:#0550ae">is&lt;/span> &lt;span style="color:#0550ae">not&lt;/span> &lt;span style="color:#cf222e">None&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">if&lt;/span> user&lt;span style="color:#0550ae">.&lt;/span>is_active&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Success&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> login&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> user&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Error&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;Credentials Incorrect&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> redirect&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;user:detail&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> user_id&lt;span style="color:#0550ae">=&lt;/span>user&lt;span style="color:#0550ae">.&lt;/span>id&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>ログイン後は、 request.user.is_authenticated()がtrueかfalseかで認証状況を判別して&lt;/p>
&lt;p>request.userコンテキストの情報をうまく使ってアプリを作っていく感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>あとは作成したモデルにユーザ情報をひもづける場合は例のごとく&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.db&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> models
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.contrib.auth.models&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> User
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Task&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>models&lt;span style="color:#0550ae">.&lt;/span>Model&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">__str__&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>title
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> title &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>CharField&lt;span style="color:#1f2328">(&lt;/span>max_length&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">255&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> description &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>TextField&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> done &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>BooleanField&lt;span style="color:#1f2328">(&lt;/span>default &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">False&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> user &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>ForeignKey&lt;span style="color:#1f2328">(&lt;/span>User&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>のように、ForegnKey設定してあげればOK&lt;/p></description></item><item><title>AWSのJavaScriptSDKのDeveloperプレビュー試してみた。(S3編)</title><link>https://blog.freedom-man.com/s3_javascriptsdk_developer_preview.html</link><pubDate>Sat, 02 Nov 2013 22:19:41 +0000</pubDate><guid>https://blog.freedom-man.com/s3_javascriptsdk_developer_preview.html</guid><description>&lt;p>先日AWSがJavascriptSDKのDeveloperプレビューをローンチしました。&lt;/p>
&lt;p>&lt;a href="http://aws.typepad.com/aws_japan/2013/11/developer-preview-aws-sdk-for-javascript.html">&lt;a href="http://aws.typepad.com/aws_japan/2013/11/developer-preview-aws-sdk-for-javascript.html">http://aws.typepad.com/aws_japan/2013/11/developer-preview-aws-sdk-for-javascript.html&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ということで、S3との連携をやってみました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>基本的な流れは&lt;/p>
&lt;ol>
&lt;li>Web Federationの設定&lt;/li>
&lt;/ol>
&lt;p>2.AWS側の設定(CORS,IAM Role等)&lt;/p>
&lt;ol start="3">
&lt;li>javascriptコーディング&lt;/li>
&lt;/ol>
&lt;p>って感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>1. AWS Web Identity Federation&lt;/h3>
AWS Web Identity Federation ってのは別のWebサービスを利用したID連携のことです。
&lt;p>OpenID的なもの？&lt;/p>
&lt;p>詳しくはこちら↓&lt;/p>
&lt;p>&lt;a href="http://aws.amazon.com/jp/iam/">&lt;a href="http://aws.amazon.com/jp/iam/">http://aws.amazon.com/jp/iam/&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://docs.aws.amazon.com/STS/latest/UsingSTS/CreatingWIF.html">&lt;a href="http://docs.aws.amazon.com/STS/latest/UsingSTS/CreatingWIF.html">http://docs.aws.amazon.com/STS/latest/UsingSTS/CreatingWIF.html&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>JavaScriptでKeyとSecretをハードコーディングして指定してしまうやり方も出来るんだけど、&lt;/p>
&lt;p>そうするとクレデンシャルが丸見えなので&lt;/p>
&lt;p>Roleでアクセスコントロールをかなり厳しくしとかないとNG。&lt;/p>
&lt;p>その点Web Identity FederationはOAuthみたいにクレデンシャルを一切外部に公開しないため&lt;/p>
&lt;p>セキュアということで、今回はWeb Identity Federationを採用。&lt;/p>
&lt;p> &lt;/p>
&lt;p>facebookあんまり好きじゃないので天下のAmazonさん(&lt;a title="http://login.amazon.com/website" href="http://login.amazon.com/website">Login with Amazon&lt;/a>)を利用。&lt;/p>
&lt;p>認証アプリの作成方法は&lt;/p>
&lt;ol>
&lt;li>
&lt;p>AmazonのDeveloperアカウントをとる&lt;/p>
&lt;/li>
&lt;li>
&lt;p>アプリ登録&lt;/p>
&lt;/li>
&lt;li>
&lt;p>アプリのAppIDとClientIDをメモ&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>でOK。&lt;/p>
&lt;p> &lt;/p>
&lt;h3> 2.AWS側の設定(CORS,IAM Role等)&lt;/h3>
S3を利用する場合はCORSをバケットに対して設定する。
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-xml" data-lang="xml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;UTF-8&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;CORSConfiguration&lt;/span> &lt;span style="color:#1f2328">xmlns=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;http://s3.amazonaws.com/doc/2006-03-01/&amp;#34;&lt;/span>&lt;span style="color:#0550ae">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;CORSRule&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedOrigin&amp;gt;&lt;/span>https://localhost&lt;span style="color:#0550ae">&amp;lt;/AllowedOrigin&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedMethod&amp;gt;&lt;/span>HEAD&lt;span style="color:#0550ae">&amp;lt;/AllowedMethod&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedMethod&amp;gt;&lt;/span>GET&lt;span style="color:#0550ae">&amp;lt;/AllowedMethod&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedMethod&amp;gt;&lt;/span>PUT&lt;span style="color:#0550ae">&amp;lt;/AllowedMethod&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedMethod&amp;gt;&lt;/span>POST&lt;span style="color:#0550ae">&amp;lt;/AllowedMethod&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedMethod&amp;gt;&lt;/span>DELETE&lt;span style="color:#0550ae">&amp;lt;/AllowedMethod&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;AllowedHeader&amp;gt;&lt;/span>*&lt;span style="color:#0550ae">&amp;lt;/AllowedHeader&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;/CORSRule&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0550ae">&amp;lt;/CORSConfiguration&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Web Identity FederationのためのIAM(Role)を作成する。&lt;/p>
&lt;p>IAM&amp;gt;Role&amp;gt;Create New Roleで&lt;/p>
&lt;p>Role for Web Identity Provider Accessを選択してあとはウィザード形式で作成。&lt;/p></description></item><item><title>djangoでsqlite3からpostgreSQLに移行してみた。</title><link>https://blog.freedom-man.com/django_from_sqlite3_to_postgresql.html</link><pubDate>Sat, 26 Oct 2013 17:39:25 +0000</pubDate><guid>https://blog.freedom-man.com/django_from_sqlite3_to_postgresql.html</guid><description>&lt;p>sqlite3は非常に手軽に扱えてGoodなんだけど、&lt;/p>
&lt;p>外部キー制約をadd constraint で追加できなかったり&lt;/p>
&lt;p>コマンド上でカラムを一気に複数作れなかったり、&lt;/p>
&lt;p>drop columnも&lt;a title="http://d.hatena.ne.jp/rayfill/20071107/1194373607" href="http://d.hatena.ne.jp/rayfill/20071107/1194373607">こんな感じ&lt;/a>で結構面倒。&lt;/p>
&lt;p> &lt;/p>
&lt;p>軽さ故に痒いところに手が届かない感じでハマりまくった。&lt;/p>
&lt;p> &lt;/p>
&lt;p>基本機能としてrailsのマイグレーションみたいなのをサポートしていないdjangoは&lt;/p>
&lt;p>Southとかのツールを利用しないとなるとテーブルを直接触らないといけないので&lt;/p>
&lt;p>sqlite3ではちょっと学習効率も開発効率も悪いなーと思ったので&lt;/p>
&lt;p>postgreSQLに乗り換えてみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>pythonのpostgreSQLドライバとしてはpsycopg2が有名なんだけど&lt;/p>
&lt;p>windows だとpip install psycopg2 ってやると&lt;/p>
&lt;p>vcvarsall.batが無いとか言われて、&lt;/p>
&lt;p>この為だけにVC++2010をインストールしたけど&lt;/p>
&lt;p>それでもうまく動かず…。&lt;/p>
&lt;p> &lt;/p>
&lt;p>psycopg2のWebサイトに行ったら&lt;a title="http://www.stickpeople.com/projects/python/win-psycopg/" href="http://www.stickpeople.com/projects/python/win-psycopg/">windows用のインストーラ&lt;/a>があるとかいう&lt;/p>
&lt;p>何という灯台下暗し！&lt;/p>
&lt;p> &lt;/p>
&lt;p>しかるべきバージョンのインストーラをダウンロードし、exeクリックで余裕でインストール！&lt;/p>
&lt;p>あとはdjangoのsettings.pyを&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>DATABASES &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;default&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;ENGINE&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;django.db.backends.postgresql_psycopg2&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Add &amp;#39;postgresql_psycopg2&amp;#39;, &amp;#39;mysql&amp;#39;, &amp;#39;sqlite3&amp;#39; or &amp;#39;oracle&amp;#39;.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;NAME&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;django_mytaskapp&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Or path to database file if using sqlite3.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># The following settings are not used with sqlite3:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;USER&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;postgres&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;PASSWORD&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;xxxxx&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;HOST&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;localhost&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Empty for localhost through domain sockets or &amp;#39;127.0.0.1&amp;#39; for localhost through TCP.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;PORT&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;5432&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Set to empty string for default.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ってやって &amp;ldquo;python manage.py syncdb&amp;quot;でOK。&lt;/p></description></item><item><title>S3のマネージメントコンソールでポリシー設定をミスってアクセスできなくなった時の対処法</title><link>https://blog.freedom-man.com/s3_console_bucket_policy.html</link><pubDate>Wed, 23 Oct 2013 23:01:09 +0000</pubDate><guid>https://blog.freedom-man.com/s3_console_bucket_policy.html</guid><description>&lt;p>S3のバケットポリシーをawsコンソール画面で編集しているときにIPアドレスの設定をミスり&lt;/p>
&lt;p>コンソール画面上でバケットのポリシーを閲覧・編集ができなくなってしまった。&lt;/p>
&lt;p> &lt;/p>
&lt;p>S3のサポートに問い合わせたところ、コンソールプログラムの仕様上、編集できなくなっているが、&lt;/p>
&lt;p>API経由だとバケット編集できますよ、という話だった。&lt;/p>
&lt;p> &lt;/p>
&lt;p>つまりRESTやSOAP使うか、ラッピングした各言語のSDKか&lt;/p>
&lt;p>コマンドラインツールのawscliとかを利用すればバケット編集可能ということ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>サードパーティ製ツールのCloudBerry Explorer for Amazon S3　とかを&lt;/p>
&lt;p>使えばGUIでいけるのでラクラク変更できます。&lt;/p>
&lt;p>&lt;a href="http://www.cloudberrylab.com/free-amazon-s3-explorer-cloudfront-IAM.aspx">&lt;a href="http://www.cloudberrylab.com/free-amazon-s3-explorer-cloudfront-IAM.aspx">http://www.cloudberrylab.com/free-amazon-s3-explorer-cloudfront-IAM.aspx&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみにCUI好きの私はawscliでバケットポリシーを編集しました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>awscliはpythonアプリなのでpythonがインストールされていない環境だと&lt;/p>
&lt;ol>
&lt;li>pythonをインストール&lt;/li>
&lt;/ol>
&lt;p>2. ez_setup.py (&lt;a title="http://peak.telecommunity.com/dist/ez_setup.py" href="http://peak.telecommunity.com/dist/ez_setup.py">&lt;a href="http://peak.telecommunity.com/dist/ez_setup.py">http://peak.telecommunity.com/dist/ez_setup.py&lt;/a>&lt;/a>)をダウンロードして、&lt;/p>
&lt;p>python ez_setup.pyでインストール&lt;/p>
&lt;ol start="3">
&lt;li>
&lt;p>easy_install pip&lt;/p>
&lt;/li>
&lt;li>
&lt;p>pip install awscli&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>ってな流れでインストール可能。&lt;/p>
&lt;p> &lt;/p>
&lt;p>あとの使い方はリファレンス参照(&lt;a href="http://docs.aws.amazon.com/cli/latest/reference/">&lt;a href="http://docs.aws.amazon.com/cli/latest/reference/">http://docs.aws.amazon.com/cli/latest/reference/&lt;/a>&lt;/a>)&lt;/p>
&lt;p> &lt;/p>
&lt;p>ってか当たり前だけど、バケットのポリシーを編集するときは&lt;/p>
&lt;p>テスト用バケットでちゃんと確認してからやった方が良いっすね。&lt;/p>
&lt;p>マジ焦ったｗ&lt;/p></description></item><item><title>Python初心者がDjangoチュートリアルを触ってみる(Part 4)</title><link>https://blog.freedom-man.com/django_tutorial4.html</link><pubDate>Sun, 20 Oct 2013 17:37:06 +0000</pubDate><guid>https://blog.freedom-man.com/django_tutorial4.html</guid><description>&lt;p>今回はフォーム画面の作成。&lt;/p>
&lt;p>チュートリアルだとvoteだけだったので、Pollの新規作成画面も作成してみた。&lt;/p>
&lt;p>チュートリアルとの差分はurls.py, newpoll.html, index.htmlあたり。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>polls/urls.py&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.conf.urls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> patterns&lt;span style="color:#1f2328">,&lt;/span> url
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">polls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> views
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>urlpatterns &lt;span style="color:#0550ae">=&lt;/span> patterns&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>IndexView&lt;span style="color:#0550ae">.&lt;/span>as_view&lt;span style="color:#1f2328">(),&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;index&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/5/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;pk&amp;gt;\d+)/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>DetailView&lt;span style="color:#0550ae">.&lt;/span>as_view&lt;span style="color:#1f2328">(),&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;detail&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/5/results/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;pk&amp;gt;\d+)/results/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>ResultsView&lt;span style="color:#0550ae">.&lt;/span>as_view&lt;span style="color:#1f2328">(),&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;results&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/5/vote/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;poll_id&amp;gt;\d+)/vote/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>vote&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;vote&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/new/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^new/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>newpollview&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;newpoll&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/newpost/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^newpost/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>newpollpost&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;newpollpost&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/deletepoll&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;poll_id&amp;gt;\d+)/delete/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>deletepoll&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;deletepoll&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>polls/views.py&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.http&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> HttpResponse&lt;span style="color:#1f2328">,&lt;/span> HttpResponseRedirect
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.template&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> RequestContext&lt;span style="color:#1f2328">,&lt;/span> loader
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.shortcuts&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> render&lt;span style="color:#1f2328">,&lt;/span> get_object_or_404
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.core.urlresolvers&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> reverse
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.views&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> generic
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">polls.models&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> Poll&lt;span style="color:#1f2328">,&lt;/span> Choice
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#genericモジュールを使用しないバージョン&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">index&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#pub_dateが最新のPollオブジェクトを取得&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> latest_poll_list &lt;span style="color:#0550ae">=&lt;/span> Poll&lt;span style="color:#0550ae">.&lt;/span>objects&lt;span style="color:#0550ae">.&lt;/span>order_by&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;-pub_date&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)[:&lt;/span>&lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#ショートカットを使わない場合&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> template = loader.get_template(&amp;#39;polls/index.html&amp;#39;)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> context = RequestContext(request, {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#39;latest_poll_list&amp;#39; : latest_poll_list,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> })
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> return HttpResponse(template.render(context))
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#テンプレートにバインディングして表示&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> context &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;latest_poll_list&amp;#39;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> latest_poll_list&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/index.html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> context&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#genericモジュールを使用しないバージョン &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">detail&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> poll_id&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#主キーからオブジェクトを取得。見つからない場合は404を返す&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> poll &lt;span style="color:#0550ae">=&lt;/span> get_object_or_404&lt;span style="color:#1f2328">(&lt;/span>Poll&lt;span style="color:#1f2328">,&lt;/span> pk&lt;span style="color:#0550ae">=&lt;/span>poll_id&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/detail.html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#39;poll&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>poll&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#genericモジュールを使用しないバージョン &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">results&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> poll_id&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> poll &lt;span style="color:#0550ae">=&lt;/span> get_object_or_404&lt;span style="color:#1f2328">(&lt;/span>Poll&lt;span style="color:#1f2328">,&lt;/span> pk&lt;span style="color:#0550ae">=&lt;/span>poll_id&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/results.html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#39;poll&amp;#39;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> poll&lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">vote&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> poll_id&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> p &lt;span style="color:#0550ae">=&lt;/span> get_object_or_404&lt;span style="color:#1f2328">(&lt;/span>Poll&lt;span style="color:#1f2328">,&lt;/span> pk&lt;span style="color:#0550ae">=&lt;/span>poll_id&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">try&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> selected_choice &lt;span style="color:#0550ae">=&lt;/span> p&lt;span style="color:#0550ae">.&lt;/span>choice_set&lt;span style="color:#0550ae">.&lt;/span>get&lt;span style="color:#1f2328">(&lt;/span>pk&lt;span style="color:#0550ae">=&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;choice&amp;#39;&lt;/span>&lt;span style="color:#1f2328">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">except&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>KeyError&lt;span style="color:#1f2328">,&lt;/span> Choice&lt;span style="color:#0550ae">.&lt;/span>DoesNotExist&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> render&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/detail.html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;poll&amp;#39;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> p&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;error_message&amp;#39;&lt;/span> &lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#34;You didn&amp;#39;t select choice.&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">else&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> selected_choice&lt;span style="color:#0550ae">.&lt;/span>votes &lt;span style="color:#0550ae">+=&lt;/span> &lt;span style="color:#0550ae">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> selected_choice&lt;span style="color:#0550ae">.&lt;/span>save&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> HttpResponseRedirect&lt;span style="color:#1f2328">(&lt;/span>reverse&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;polls:results&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> args&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>p&lt;span style="color:#0550ae">.&lt;/span>id&lt;span style="color:#1f2328">,)))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">IndexView&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>generic&lt;span style="color:#0550ae">.&lt;/span>ListView&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> template_name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/index.html&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> context_object_name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;latest_poll_list&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">get_queryset&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> Poll&lt;span style="color:#0550ae">.&lt;/span>objects&lt;span style="color:#0550ae">.&lt;/span>order_by&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;-pub_date&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)[:&lt;/span>&lt;span style="color:#0550ae">5&lt;/span>&lt;span style="color:#1f2328">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">DetailView&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>generic&lt;span style="color:#0550ae">.&lt;/span>DetailView&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> template_name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/detail.html&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model &lt;span style="color:#0550ae">=&lt;/span> Poll
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">ResultsView&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>generic&lt;span style="color:#0550ae">.&lt;/span>DetailView&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> template_name &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/results.html&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> model &lt;span style="color:#0550ae">=&lt;/span> Poll
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#新規Pollフォーム画面&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">newpollview&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> render&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;polls/newpoll.html&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#新規Poll作成処理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">newpollpost&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p &lt;span style="color:#0550ae">=&lt;/span> Poll&lt;span style="color:#1f2328">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>question &lt;span style="color:#0550ae">=&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>POST&lt;span style="color:#1f2328">[&lt;/span>&lt;span style="color:#0a3069">&amp;#39;question&amp;#39;&lt;/span>&lt;span style="color:#1f2328">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>pub_date &lt;span style="color:#0550ae">=&lt;/span> datetime&lt;span style="color:#0550ae">.&lt;/span>now&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p&lt;span style="color:#0550ae">.&lt;/span>save&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> HttpResponseRedirect&lt;span style="color:#1f2328">(&lt;/span>reverse&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;polls:index&amp;#39;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">#Poll削除処理&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">deletepoll&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#1f2328">,&lt;/span> poll_id&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#6639ba">print&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>method&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">if&lt;/span> request&lt;span style="color:#0550ae">.&lt;/span>method &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#0a3069">&amp;#39;POST&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p &lt;span style="color:#0550ae">=&lt;/span> get_object_or_404&lt;span style="color:#1f2328">(&lt;/span>Poll&lt;span style="color:#1f2328">,&lt;/span> pk&lt;span style="color:#0550ae">=&lt;/span>poll_id&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>p&lt;span style="color:#0550ae">.&lt;/span>delete&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">return&lt;/span> HttpResponseRedirect&lt;span style="color:#1f2328">(&lt;/span>reverse&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;polls:index&amp;#39;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Python初心者がDjangoチュートリアルを触ってみる(Part 3)</title><link>https://blog.freedom-man.com/django_tutorial3.html</link><pubDate>Sun, 20 Oct 2013 09:41:09 +0000</pubDate><guid>https://blog.freedom-man.com/django_tutorial3.html</guid><description>&lt;p>今回は完成形を見た方が早いので以下にまとめました。&lt;/p>
&lt;p>流れとしては&lt;/p>
&lt;ol>
&lt;li>
&lt;p>polls/views.pyにレスポンスを返すメソッドを指定&lt;/p>
&lt;/li>
&lt;li>
&lt;p>mysite/urls.py, polls/urls.pyでURLをマッピング&lt;/p>
&lt;/li>
&lt;li>
&lt;p>必要に応じてpolls/templates/以下のテンプレートを利用してレンダリング&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>って感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>mysite/urls.py&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.conf.urls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> patterns&lt;span style="color:#1f2328">,&lt;/span> include&lt;span style="color:#1f2328">,&lt;/span> url
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">polls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> views
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># Uncomment the next two lines to enable the admin:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.contrib&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> admin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>admin&lt;span style="color:#0550ae">.&lt;/span>autodiscover&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>urlpatterns &lt;span style="color:#0550ae">=&lt;/span> patterns&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>index&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;index&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#polls/* のURLの時はpolls/urls.pyを読み込み&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^polls/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> include&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;polls.urls&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> namespace&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;polls&amp;#34;&lt;/span>&lt;span style="color:#1f2328">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a">#管理画面URL設定&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^admin/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> include&lt;span style="color:#1f2328">(&lt;/span>admin&lt;span style="color:#0550ae">.&lt;/span>site&lt;span style="color:#0550ae">.&lt;/span>urls&lt;span style="color:#1f2328">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>polls/urls.py&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.conf.urls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> patterns&lt;span style="color:#1f2328">,&lt;/span> url
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">polls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> views
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>urlpatterns &lt;span style="color:#0550ae">=&lt;/span> patterns&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>index&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;index&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/5/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;poll_id&amp;gt;\d+)/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>detail&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;detail&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/5/results/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;poll_id&amp;gt;\d+)/results/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>results&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;results&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># ex: /polls/5/vote/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^(?P&amp;lt;poll_id&amp;gt;\d+)/vote/$&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> views&lt;span style="color:#0550ae">.&lt;/span>vote&lt;span style="color:#1f2328">,&lt;/span> name&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#39;vote&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>WordPressのSticky Noteプラグインでうまく動かないときの修正点</title><link>https://blog.freedom-man.com/wordpress_stickynote_plugin.html</link><pubDate>Sat, 19 Oct 2013 18:58:46 +0000</pubDate><guid>https://blog.freedom-man.com/wordpress_stickynote_plugin.html</guid><description>&lt;p>ブログネタをwordpress内で管理したいなーと思って、管理画面内のメモプログインとしてSticky Note Plugin()をインストールしたものの&lt;br>
Options画面からメモを保存しようとすると &lt;code>options.php was not found&lt;/code> とか言われてうまく動かない。&lt;/p>
&lt;p>よく見るとパスが&lt;br>
&lt;code>{BASE URL}/blog/wp-content/...&lt;/code> じゃなくて&lt;br>
&lt;code>{BASE URL}/wp-content/...&lt;/code> とWordpressのホームディレクトリの設定がおかしくなっている。&lt;/p>
&lt;p>そこでプラグインを以下のように編集してみたら、ちゃんと動いた。&lt;/p>
&lt;h3>\[sticky-note/sticky-note-admin.php]&lt;/h3>
&lt;ul>
&lt;li>変更前：&lt;code>&amp;lt;form method=&amp;quot;post&amp;quot; action=&amp;quot;/wp-content/plugins/sticky-note/options.php&amp;quot;&amp;gt;&lt;/code>&lt;/li>
&lt;li>変更後：&lt;code>&amp;lt;form method=&amp;quot;post&amp;quot; action=&amp;quot;/blog/wp-content/plugins/sticky-note/options.php&amp;quot;&amp;gt;&lt;/code>&lt;/li>
&lt;/ul>
&lt;h3>\[sticky-note/options.php]&lt;/h3>
&lt;ul>
&lt;li>変更前：&lt;code>header(&amp;quot;location:/wp-admin/options-general.php?page=sticky-note&amp;quot;);&lt;/code>&lt;/li>
&lt;li>変更後：&lt;code>header(&amp;quot;location:/blog/wp-admin/options-general.php?page=sticky-note&amp;quot;);&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>っていうかそもそも、/blog/とかサブディレクトリ形式でサイトを運用しているのもおかしいのでそろそろ、&lt;code>blog.freedom-man.com&lt;/code> のサブドメイン形式で運用していこうかな。
そうするとプラグインもう一回書きなおし…。&lt;/p>
&lt;p>普通にevernote＆ブラウザプラグイン使え！っていうツッコミは無しでお願いします。&lt;/p></description></item><item><title>Python初心者がDjangoチュートリアルを触ってみる(Part 2)</title><link>https://blog.freedom-man.com/django_tutorial2.html</link><pubDate>Sat, 19 Oct 2013 16:39:17 +0000</pubDate><guid>https://blog.freedom-man.com/django_tutorial2.html</guid><description>&lt;p>今回はAdminサイトの構築。&lt;/p>
&lt;p>Djangoはこれが売りらしい。&lt;/p>
&lt;p>DBさえ与えてしまえばCRUDできるアプリが自動でできるっていうのはSalesforceに近い感じがする。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>settting.pyを変更&lt;/strong>&lt;/h3>
&lt;ul>
	&lt;li>INSTALLED_APPSの'django.contrib.admin'のコメントアウトを解除&lt;/li>
	&lt;li>python manage.py syncdb実行(実行しなくても大丈夫？かも）&lt;/li>
&lt;/ul>
&amp;nbsp;
&lt;h3>&lt;strong>urls.pyを変更（コメントアウトを削除）&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.conf.urls&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> patterns&lt;span style="color:#1f2328">,&lt;/span> include&lt;span style="color:#1f2328">,&lt;/span> url
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># Uncomment the next two lines to enable the admin:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.contrib&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> admin
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>admin&lt;span style="color:#0550ae">.&lt;/span>autodiscover&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>urlpatterns &lt;span style="color:#0550ae">=&lt;/span> patterns&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># Examples:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># url(r&amp;#39;^$&amp;#39;, &amp;#39;mysite.views.home&amp;#39;, name=&amp;#39;home&amp;#39;),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># url(r&amp;#39;^mysite/&amp;#39;, include(&amp;#39;mysite.foo.urls&amp;#39;)),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># Uncomment the admin/doc line below to enable admin documentation:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># url(r&amp;#39;^admin/doc/&amp;#39;, include(&amp;#39;django.contrib.admindocs.urls&amp;#39;)),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># Uncomment the next line to enable the admin:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> url&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">r&lt;/span>&lt;span style="color:#0a3069">&amp;#39;^admin/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> include&lt;span style="color:#1f2328">(&lt;/span>admin&lt;span style="color:#0550ae">.&lt;/span>site&lt;span style="color:#0550ae">.&lt;/span>urls&lt;span style="color:#1f2328">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>python manage.py runserver で起動してlocalhost:8000/admin　で管理画面にアクセス。&lt;/p></description></item><item><title>Python初心者がDjangoチュートリアルを触ってみる(Part 1)</title><link>https://blog.freedom-man.com/django_tutorial1.html</link><pubDate>Sat, 19 Oct 2013 01:29:40 +0000</pubDate><guid>https://blog.freedom-man.com/django_tutorial1.html</guid><description>&lt;p>Pythonの有名フレームワークDjangoのチュートリアルを触って超簡単にまとめてみる。
チートシート的な感じで。&lt;/p>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>プロジェクトの作成&lt;/strong>&lt;/h3>
&lt;strong>&lt;/strong>django-admin.py startproject &lt;project_name>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>Django起動&lt;/strong>&lt;/h3>
python manage.py runserver
&lt;p> &lt;/p>
&lt;h3>&lt;strong>アプリケーションの作成&lt;/strong>&lt;/h3>
python manage.py startapp &lt;app_name>
&lt;p> &lt;/p>
&lt;h3>&lt;strong>アプリケーションフォルダ内のmodels.pyを変更(O/Rマッパーみたいな？)&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.db&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> models
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">from&lt;/span> &lt;span style="color:#24292e">django.utils&lt;/span> &lt;span style="color:#cf222e">import&lt;/span> timezone
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">import&lt;/span> &lt;span style="color:#24292e">datetime&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a"># Create your models here.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Poll&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>models&lt;span style="color:#0550ae">.&lt;/span>Model&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> question &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>CharField&lt;span style="color:#1f2328">(&lt;/span>max_length&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">200&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> pub_date &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>DateTimeField&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;date published&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">__str__&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>question
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">was_published_recently&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>pub_date &lt;span style="color:#0550ae">&amp;gt;=&lt;/span> timezone&lt;span style="color:#0550ae">.&lt;/span>now&lt;span style="color:#1f2328">()&lt;/span> &lt;span style="color:#0550ae">-&lt;/span> datetime&lt;span style="color:#0550ae">.&lt;/span>timedelta&lt;span style="color:#1f2328">(&lt;/span>days&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">1&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">class&lt;/span> &lt;span style="color:#1f2328">Choice&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>models&lt;span style="color:#0550ae">.&lt;/span>Model&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> poll &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>ForeignKey&lt;span style="color:#1f2328">(&lt;/span>Poll&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> choice_text &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>CharField&lt;span style="color:#1f2328">(&lt;/span>max_length&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">200&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> votes &lt;span style="color:#0550ae">=&lt;/span> models&lt;span style="color:#0550ae">.&lt;/span>IntegerField&lt;span style="color:#1f2328">(&lt;/span>default&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0550ae">0&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">def&lt;/span> &lt;span style="color:#6639ba">__str__&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">return&lt;/span> &lt;span style="color:#6a737d">self&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>choice_text
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;h3>&lt;strong>DB設定の為にsetting.pyを変更&lt;/strong>&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>DATABASES &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;default&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;ENGINE&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;django.db.backends.sqlite3&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Add &amp;#39;postgresql_psycopg2&amp;#39;, &amp;#39;mysql&amp;#39;, &amp;#39;sqlite3&amp;#39; or &amp;#39;oracle&amp;#39;.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;NAME&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;sqlite3.db&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Or path to database file if using sqlite3.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#57606a"># The following settings are not used with sqlite3:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;USER&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;PASSWORD&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;HOST&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Empty for localhost through domain sockets or &amp;#39;127.0.0.1&amp;#39; for localhost through TCP.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#0a3069">&amp;#39;PORT&amp;#39;&lt;/span>&lt;span style="color:#1f2328">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#57606a"># Set to empty string for default.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>socket.ioとTwitter StreamingAPIでツイート垂れ流しタイム</title><link>https://blog.freedom-man.com/socketio_twitter_streamingapi.html</link><pubDate>Fri, 18 Oct 2013 00:20:47 +0000</pubDate><guid>https://blog.freedom-man.com/socketio_twitter_streamingapi.html</guid><description>&lt;p>node.js初心者がsocket.io&amp;amp;Twitter Streaming APIを使ってツイートを垂れ流すという、&lt;/p>
&lt;p>socket.ioの学習にありがちなサンプルを試してみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>全体の流れは&lt;/p>
&lt;ol>
&lt;li>
&lt;p>node.jsインストール&lt;/p>
&lt;/li>
&lt;li>
&lt;p>npm install express　とか　npm install ntwitter　とか必要なモジュールをインストール&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>3. express -e exapp → cd exapp → npm install でexpressアプリのひな形作成&lt;/p>
&lt;ol start="4">
&lt;li>exapp/views/index.ejs, exapp/app.js　を下記のように書き換え&lt;/li>
&lt;/ol>
&lt;p> &lt;/p>
&lt;p>app.js&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">express&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;express&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">routes&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;./routes&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">user&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;./routes/user&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">http&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;http&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">path&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;path&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">app&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">twitter&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;ntwitter&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// all environments
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;port&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0550ae">8888&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;views&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">__dirname&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#39;/views&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">set&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;view engine&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;ejs&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">favicon&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">logger&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;dev&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">bodyParser&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">methodOverride&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">router&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#cf222e">static&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">path&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">join&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">__dirname&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#0a3069">&amp;#39;public&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">// development only
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#57606a">&lt;/span>&lt;span style="color:#cf222e">if&lt;/span> &lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;development&amp;#39;&lt;/span> &lt;span style="color:#0550ae">==&lt;/span> &lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;env&amp;#39;&lt;/span>&lt;span style="color:#1f2328">))&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">use&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">express&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">errorHandler&lt;/span>&lt;span style="color:#1f2328">());&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">server&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">http&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">createServer&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">listen&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;port&amp;#39;&lt;/span>&lt;span style="color:#1f2328">),&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(){&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;Express server listening on port &amp;#39;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;port&amp;#39;&lt;/span>&lt;span style="color:#1f2328">));&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">io&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#1f2328">require&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;socket.io&amp;#34;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">listen&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">server&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">req&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">var&lt;/span> &lt;span style="color:#1f2328">tw&lt;/span> &lt;span style="color:#0550ae">=&lt;/span> &lt;span style="color:#cf222e">new&lt;/span> &lt;span style="color:#1f2328">twitter&lt;/span>&lt;span style="color:#1f2328">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">consumer_key&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Input your consumer key&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">consumer_secret&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Input your consumer secret&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">access_token_key&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Input your access token&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">access_token_secret&lt;/span>&lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#0a3069">&amp;#39;Input your access token secret&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">io&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">sockets&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;connection&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">socket&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">tw&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">stream&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;statuses/filter&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>&lt;span style="color:#0a3069">&amp;#39;track&amp;#39;&lt;/span> &lt;span style="color:#0550ae">:&lt;/span> &lt;span style="color:#1f2328">req&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">query&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">keyword&lt;/span> &lt;span style="color:#1f2328">},&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">stream&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;data&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">data&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">socket&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">emit&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;stream&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">data&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;end&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">stream&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">on&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#34;destroy&amp;#34;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#cf222e">function&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">)&lt;/span> &lt;span style="color:#1f2328">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">console&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">log&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#1f2328">res&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">render&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;index&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">{});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">});&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">app&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">get&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;/users&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span> &lt;span style="color:#1f2328">user&lt;/span>&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">list&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p></description></item><item><title>Python初心者がPython（標準ライブラリ）でTwitterクライアントを作ってみた（黒歴史削除編）</title><link>https://blog.freedom-man.com/python_twitterclient.html</link><pubDate>Mon, 14 Oct 2013 23:06:11 +0000</pubDate><guid>https://blog.freedom-man.com/python_twitterclient.html</guid><description>&lt;p>第二弾ということで今度は黒歴史を削除する機能を実装しました。&lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/TwitterClientByPython">&lt;a href="https://github.com/tzmfreedom/TwitterClientByPython">https://github.com/tzmfreedom/TwitterClientByPython&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>token.jsonをトークン設定ファイルとして&lt;/p>
&lt;p>削除ファイルを標準入力から読み込ませて、id値を元に削除する感じ。&lt;/p>
&lt;p>twitter_client.py -d &amp;lt; delete.json って感じなコマンドで削除できます。&lt;/p>
&lt;p> &lt;/p>
&lt;p>多分リツイートは削除できないはずなので、もうちょっと手を入れないとダメっすね。&lt;/p>
&lt;p>あと、ツイートをCSV出力→CSVのID値から削除っていう流れの方が美しいような気がするので&lt;/p>
&lt;p>そこらへんの修正もお勉強がてら直していきまっす。&lt;/p>
&lt;p>ツイート機能も欲しいところ。&lt;/p>
&lt;p>実装しちゃえばcronかタスクスケジューラでボット作れるし。&lt;/p>
&lt;p>といっても今更ボットの需要は無いかｗｗ&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回の機能実装でちょっとハマったのがTwitterのアプリケーション設定のところ。&lt;/p>
&lt;p>当たり前だけど削除とか更新する場合はTwitterのアプリケーション設定(OAuth設定)で&lt;/p>
&lt;p>Access levelがRead and Writeじゃないと、どんなに正確に署名が作れてても、Unauthorizedとか言ってエラります。&lt;/p>
&lt;p>さらに当たり前な事で、Read→Read and Writeに変更した後に、&lt;/p>
&lt;p>もう一回OAuthの認証フローやってあげないと、Write権限は反映されません。&lt;/p>
&lt;p> &lt;/p>
&lt;p>さぁこれで黒歴史を削除したところだし、Twitter再開してみますかねー。&lt;/p></description></item><item><title>PHPでforce.com Canvasを触ってみる</title><link>https://blog.freedom-man.com/forceom_canvas_using_php.html</link><pubDate>Sun, 13 Oct 2013 23:41:09 +0000</pubDate><guid>https://blog.freedom-man.com/forceom_canvas_using_php.html</guid><description>&lt;p>SaleforceでSummer13(?)で正式リリースされたWebアプリケーション統合機能のCanvasを触ってみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>仕組みとか出来る事とかはこちらのリンクが詳しいです。&lt;/p>
&lt;p>&lt;a href="http://techblog.appirio.co.jp/2012/10/forcecom-canvas-12.html">&lt;a href="http://techblog.appirio.co.jp/2012/10/forcecom-canvas-12.html">http://techblog.appirio.co.jp/2012/10/forcecom-canvas-12.html&lt;/a>&lt;/a>&lt;/p>
&lt;p>&lt;a href="http://www.terrasky.co.jp/blog/?p=1584">&lt;a href="http://www.terrasky.co.jp/blog/?p=1584">http://www.terrasky.co.jp/blog/?p=1584&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>Webで調べるとほとんどがRubyとかJavaとかのサンプルだったので、あえてphpでサンプルを作成。&lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/SalesforceCanvasSample/">&lt;a href="https://github.com/tzmfreedom/SalesforceCanvasSample/">https://github.com/tzmfreedom/SalesforceCanvasSample/&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ChatterAPIでフィード投稿するだけのかなり簡素なサンプルだけど、&lt;/p>
&lt;p>force.com Canvas自体は署名したトークンとかのデータをiframeにPOSTして&lt;/p>
&lt;p>アプリ内でPOSTされた署名データを復号化して正しいデータかどうかを検証して&lt;/p>
&lt;p>OKだったらあとはそのトークン使ってREST API使ってねっていう機能なので&lt;/p>
&lt;p>phpコードの大事なところは最初の20行くらい。&lt;/p>
&lt;p> &lt;/p>
&lt;p>JavascriptからREST APIを使う仕組みはpostmessageで&lt;/p>
&lt;p>親フレームのSFDCをプロキシとしてしているだけで、技術的には何も新しくない機能だと思ってる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>多分、出来るプログラマさん達はCanvasが出る前からこういうこと考えていたと思うし。&lt;/p>
&lt;p>っていうか、むしろSOAP APIでも良いような気がする。&lt;/p>
&lt;p>force.com Canvasが出来た技術的背景としてはHTML5の存在が大きいのかな。&lt;/p>
&lt;p>VisualforcePageに２つ埋め込んで相互通信するとかもあんまりメリットを感じない。&lt;/p>
&lt;p> &lt;/p>
&lt;p>一番のメリットはやっぱりChatterのパブリッシャーアクションとかで利用できるところかな。&lt;/p>
&lt;p> &lt;/p>
&lt;p>とは言うものの、どういったアプリが出てくるのかは検討がつかない。&lt;/p>
&lt;p>force.com Canvasで業務アプリ界のキラーアプリが出てくるのかなー。&lt;/p>
&lt;p> &lt;/p></description></item><item><title>Python初心者がPython（標準ライブラリ）でTwitterクライアントを作ってみた</title><link>https://blog.freedom-man.com/python_twitterclient-2.html</link><pubDate>Sat, 12 Oct 2013 21:54:46 +0000</pubDate><guid>https://blog.freedom-man.com/python_twitterclient-2.html</guid><description>&lt;p>PythonでTwitterクライアントを作ってソースコードを公開している人がほとんど見当たらないので&lt;/p>
&lt;p>自前で作ってみることにした。&lt;/p>
&lt;p> &lt;/p>
&lt;p>今回の実装したい機能は&lt;/p>
&lt;p>・過去のツイートのバックアップ&lt;/p>
&lt;p>・過去のツイートの削除&lt;/p>
&lt;p> &lt;/p>
&lt;p>つまりは黒歴史の削除用途（黒歴史はローカルに保存）&lt;/p>
&lt;p> &lt;/p>
&lt;p>バックアップ機能まで作成したものをgithubにあげてみた。&lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/TwitterClientByPython">&lt;a href="https://github.com/tzmfreedom/TwitterClientByPython">https://github.com/tzmfreedom/TwitterClientByPython&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみに、Pythonレベル1なので温かい目で見るように！！ｗ&lt;/p>
&lt;p> &lt;/p>
&lt;p>使い方としては&lt;/p>
&lt;ol>
&lt;li>
&lt;p>config.jsonに自分のTwitterアプリのconsumer_keyとconsumer_secretを入力&lt;/p>
&lt;/li>
&lt;li>
&lt;p>twitter_client.py -a をプロンプトで叩く&lt;/p>
&lt;/li>
&lt;li>
&lt;p>OAuth認証開始で、ブラウザに表示されたPINコードを入力してEnter。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>token.jsonというファイルが生成される&lt;/p>
&lt;/li>
&lt;li>
&lt;p>twitter_client.py -o &amp;lt; token.json　をプロンプトで叩く&lt;/p>
&lt;/li>
&lt;li>
&lt;p>out_00000.json, out_00001.json って感じで自分のツイートのバックアップが自動的に生成&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>って感じ。&lt;/p>
&lt;p> &lt;/p>
&lt;p>自分用に作ったので全然汎用的に作ってない上に自分のTwitterアプリ登録が必要っていうｗ&lt;/p>
&lt;p>クライアントアプリだし、俺のアプリ情報晒したくねぇし！&lt;/p>
&lt;p>しかも、よくよく考えたらpythonインストールしている人しか使えねぇわ。&lt;/p>
&lt;p>あとでpy2exeとかで実行ファイルとかにしときます。&lt;/p>
&lt;p>linuxやmacは標準でpython入ってる（と思う）から問題なし！&lt;/p>
&lt;p> &lt;/p>
&lt;p>あと、久々にOAuth1.0を自前で作ってみたけど、相変わらずsignature生成が鬼門だったわ。&lt;/p>
&lt;p>OAuth2.0がすげー楽なことがわかりました。&lt;/p>
&lt;p> &lt;/p>
&lt;p>とりあえず色々と作ってみてPythonレベル上げてきます。&lt;/p>
&lt;p>今回良く使ったコードパターンを下記にメモってみる。&lt;/p>
&lt;p> &lt;/p>
&lt;p>[GET送信]&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>req &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>Request&lt;span style="color:#1f2328">(&lt;/span>url&lt;span style="color:#0550ae">=&lt;/span>url &lt;span style="color:#0550ae">+&lt;/span> &lt;span style="color:#0a3069">&amp;#39;?&amp;#39;&lt;/span> &lt;span style="color:#0550ae">+&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>parse&lt;span style="color:#0550ae">.&lt;/span>urlencode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">dict&lt;/span>&lt;span style="color:#1f2328">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>res &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>urlopen&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>retString &lt;span style="color:#0550ae">=&lt;/span> res&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;UTF-8&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>[POST送信]&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>req &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>Request&lt;span style="color:#1f2328">(&lt;/span>url&lt;span style="color:#0550ae">=&lt;/span>url&lt;span style="color:#1f2328">,&lt;/span> data &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>parse&lt;span style="color:#0550ae">.&lt;/span>urlencode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#6639ba">dict&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>encode&lt;span style="color:#1f2328">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>res &lt;span style="color:#0550ae">=&lt;/span> urllib&lt;span style="color:#0550ae">.&lt;/span>request&lt;span style="color:#0550ae">.&lt;/span>urlopen&lt;span style="color:#1f2328">(&lt;/span>req&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>retString &lt;span style="color:#0550ae">=&lt;/span> res&lt;span style="color:#0550ae">.&lt;/span>read&lt;span style="color:#1f2328">()&lt;/span>&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#0a3069">&amp;#39;UTF-8&amp;#39;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>[URLクエリパース]&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>urllib&lt;span style="color:#0550ae">.&lt;/span>parse&lt;span style="color:#0550ae">.&lt;/span>parse_qs&lt;span style="color:#1f2328">(&lt;/span>returnTokenParameter&lt;span style="color:#1f2328">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p> &lt;/p>
&lt;p>[JSONパース]&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>json_decoder &lt;span style="color:#0550ae">=&lt;/span> json&lt;span style="color:#0550ae">.&lt;/span>JSONDecoder&lt;span style="color:#1f2328">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#cf222e">for&lt;/span> one_json &lt;span style="color:#0550ae">in&lt;/span> json_decoder&lt;span style="color:#0550ae">.&lt;/span>decode&lt;span style="color:#1f2328">(&lt;/span>retJson&lt;span style="color:#1f2328">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#cf222e">pass&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Pythonの開発環境をPyDevにした</title><link>https://blog.freedom-man.com/python_pydev.html</link><pubDate>Mon, 07 Oct 2013 00:26:28 +0000</pubDate><guid>https://blog.freedom-man.com/python_pydev.html</guid><description>&lt;p>Pythonの開発環境が今までnotepad++だったりNinja IDEだったりで&lt;/p>
&lt;p>どちらもまともにデバッグ出来ないっぽいのでEclipse+PyDevプラグインに乗り換えてみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>PyDev自体のインストールは&lt;/p>
&lt;p>いつものようにHelp &amp;gt; Install New Software で&lt;/p>
&lt;p>&lt;a href="http://pydev.org/updates">http://pydev.org/updates&lt;/a>からpydevをインストールすればOK。&lt;/p>
&lt;p> &lt;/p>
&lt;p>インストール後はJavaとかのデバッグと一緒。&lt;/p>
&lt;p>やっぱり使い慣れたEclipseのプラグイン系は良いっすねー。&lt;/p>
&lt;p> &lt;/p>
&lt;p>php開発のときもphpEclipseとかでお世話になりました。&lt;/p></description></item><item><title>SalesforceとS3の連携(REST)</title><link>https://blog.freedom-man.com/s3_using_apex.html</link><pubDate>Sat, 13 Jul 2013 23:30:58 +0000</pubDate><guid>https://blog.freedom-man.com/s3_using_apex.html</guid><description>&lt;p>Salesforceにはドキュメントやコンテンツなどのファイル管理システムがあるものの、&lt;/p>
&lt;p>1ファイルあたりの容量制限と、ファイル容量の制限等の理由でSalesforce単体では要求を満たせないことが多い。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そこでAWSのサービスの一つであるS3とSalesforceを連携させることで、&lt;/p>
&lt;p>ファイル容量制限を突破しつつ、低コストで高い堅牢性・可用性のファイルストレージを確保することが可能になるため&lt;/p>
&lt;p>S3との連携は重要なトピックかなーということで、&lt;/p>
&lt;p>githubにAWSとの連携サンプルプログラム(Apex, Visualforce)を置いてみた。&lt;/p>
&lt;p> &lt;/p>
&lt;p>&lt;a href="https://github.com/tzmfreedom/SalesforceS3Sample">&lt;a href="https://github.com/tzmfreedom/SalesforceS3Sample">https://github.com/tzmfreedom/SalesforceS3Sample&lt;/a>&lt;/a>&lt;/p>
&lt;p> &lt;/p>
&lt;p>ちなみにgithub初投稿なのでREADMEとか色々とテキトーですｗ&lt;/p>
&lt;p> &lt;/p>
&lt;p>Utility.clsは置いてないけど、Utility.getParamはMap&amp;lt;String, String&amp;gt;からkey=value&amp;amp;&amp;hellip;のパラメータ文字列を生成するだけのクラスメソッドです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>そもそも、force.comのツールキットとしてこれ→&lt;a href="http://aws.amazon.com/jp/solutions/global-solution-providers/salesforce/">&lt;a href="http://aws.amazon.com/jp/solutions/global-solution-providers/salesforce/">http://aws.amazon.com/jp/solutions/global-solution-providers/salesforce/&lt;/a>&lt;/a>があるんだけど、US-standard以外のリージョンではそのままでは使えなかったり、&lt;/p>
&lt;p> &lt;/p>
&lt;p>SOAPベースでよくわからないので（私の修行不足）、わかりやすーいREST APIで書き下ろした感じです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>Commonの方は汎用的に作ったつもりだけど、他の人からみたらビミョーだと思うので&lt;/p>
&lt;p>signatureの生成だけでも、参考にしてもらえれば幸いです。&lt;/p>
&lt;p> &lt;/p>
&lt;p>次回はGoogle API(とりあえずDrive限定)のforce.comサンプルの予定。&lt;/p></description></item><item><title>色々と取得</title><link>https://blog.freedom-man.com/get_qualification.html</link><pubDate>Tue, 15 Jan 2013 01:26:33 +0000</pubDate><guid>https://blog.freedom-man.com/get_qualification.html</guid><description>&lt;p>だいぶご無沙汰な更新。&lt;/p>
&lt;p>年末年始にかけてLPIC Level1の試験勉強をしてたり、この一週間はOSS-DB Silverの試験勉強をしてたりでなかなか更新できない＆更新のネタがない状況でしたorz&lt;/p>
&lt;p>その甲斐あってか(?)、無事上記２つの資格を取得できました！&lt;/p>
&lt;p>LPIC Level1は実質10日間くらいでOSS-DBは1週間くらい。
どちらも8～9割で合格できたので(合格点65％くらい)、結構満足です♪&lt;/p>
&lt;p>1週間前後で取得できる資格って持っていても意味あるのか？っていう感じですが、資格取得はステータスの獲得もそうですが、”試験勉強をした本人が知識の整理ができる＆当分野における知識の偏りを減らすことができる”というのが大きなメリットだと思います。&lt;/p>
&lt;p>資格があれば仕事が出来るわけじゃないけど、知識があまりない状態での経験っていうのもどうかと思ってます。&lt;/p>
&lt;p>経験から知識を吸い上げるのは非常に大切なことだけど、それが先人がやっているのであれば知識を別の媒体から取り入れる（先人の真似をする）ことでさらに進歩できるのだと思います。&lt;/p>
&lt;p>もちろん、知識だけあって経験がないのは俗に言う頭でっかちな状態で、「知識」は経験を伴った「知恵」には数段劣ってしまいますので、ダメダメです。&lt;/p>
&lt;p>知識はレベルアップの前提条件みたいなもんですね。&lt;/p>
&lt;p>そんな訳で、今年は続けてLPIC Level2,簿記2級,応用情報技術者あたりを取得しようかと思っております。&lt;/p></description></item><item><title>2013</title><link>https://blog.freedom-man.com/2013.html</link><pubDate>Tue, 01 Jan 2013 00:00:00 +0900</pubDate><guid>https://blog.freedom-man.com/2013.html</guid><description/></item><item><title>インスタンスの動的生成</title><link>https://blog.freedom-man.com/forcecom_create_dynamic_instance.html</link><pubDate>Thu, 20 Dec 2012 01:32:02 +0000</pubDate><guid>https://blog.freedom-man.com/forcecom_create_dynamic_instance.html</guid><description>&lt;p>Apex(force.com)では以下のようにTypeクラスを使用して動的にインスタンスを生成できる。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>SObject&lt;span style="color:#fff"> &lt;/span>obj&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>SObject&lt;span style="color:#1f2328">)&lt;/span>Type&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forName&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>Account&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">newInstance&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>obj&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">put&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>name&lt;span style="color:#0a3069">&amp;#39;,&amp;#39;&lt;/span>TEST&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>insert&lt;span style="color:#fff"> &lt;/span>obj&lt;span style="color:#1f2328">;&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>これを利用してバッチを動的に起動することも可能&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>Database&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Batchable&lt;/span>&lt;span style="color:#0550ae">&amp;lt;&lt;/span>sObject&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#fff"> &lt;/span>batch&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Database&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">Batchable&lt;/span>&lt;span style="color:#0550ae">&amp;lt;&lt;/span>sObject&lt;span style="color:#0550ae">&amp;gt;&lt;/span>&lt;span style="color:#1f2328">)&lt;/span>Type&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forName&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>TestBatch&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">newInstance&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>Database&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">executeBatch&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>batch&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>スケジュールもこんな感じで書ける&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-java" data-lang="java">&lt;span style="display:flex;">&lt;span>Schedulable&lt;span style="color:#fff"> &lt;/span>sch&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#1f2328">(&lt;/span>Schedulable&lt;span style="color:#1f2328">)&lt;/span>Type&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">forName&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>TestBatchSch&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">).&lt;/span>&lt;span style="color:#1f2328">newInstance&lt;/span>&lt;span style="color:#1f2328">();&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#fff">&lt;/span>system&lt;span style="color:#1f2328">.&lt;/span>&lt;span style="color:#1f2328">schedule&lt;/span>&lt;span style="color:#1f2328">(&lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>TestSchedule&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>48&lt;span style="color:#fff"> &lt;/span>29&lt;span style="color:#fff"> &lt;/span>1&lt;span style="color:#fff"> &lt;/span>20&lt;span style="color:#fff"> &lt;/span>12&lt;span style="color:#fff"> &lt;/span>&lt;span style="color:#0550ae">?&lt;/span>&lt;span style="color:#fff"> &lt;/span>2012&lt;span style="color:#f6f8fa;background-color:#82071e">&amp;#39;&lt;/span>&lt;span style="color:#1f2328">,&lt;/span>sch&lt;span style="color:#1f2328">);&lt;/span>&lt;span style="color:#fff">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>問題はnewInstanceメソッドは引数がないので、コンストラクタに引数がないバッチ、スケジュールしか汎用化できないっぽいこと。&lt;/p>
&lt;p>せめてObjectのリストを渡していければなーと思うのだが、、、。&lt;/p></description></item><item><title>よく使うCDN</title><link>https://blog.freedom-man.com/cdn.html</link><pubDate>Thu, 13 Dec 2012 01:56:36 +0000</pubDate><guid>https://blog.freedom-man.com/cdn.html</guid><description>&lt;p>googleは有名なJavaScriptライブラリをCDNとして公開している。
これによってわざわざライブラリをダウンロードせずとも、下記のように記述するだけでライブラリを利用可能。
ファイルがかさばらないので結構便利。&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">link&lt;/span> &lt;span style="color:#1f2328">href&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;//ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/blitzer/
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">jquery-ui.css&amp;#34;&lt;/span> &lt;span style="color:#1f2328">rel&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;stylesheet&amp;#34;&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/css&amp;#34;&lt;/span>&lt;span style="color:#1f2328">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;//ajax.googleapis.com/ajax/libs/
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">jquery/1.6.0/jquery.min.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;//ajax.googleapis.com/ajax/libs/
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">jqueryui/1.8.12/jquery-ui.min.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>ちなみに、&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#1f2328">&amp;lt;&lt;/span>&lt;span style="color:#0550ae">script&lt;/span> &lt;span style="color:#1f2328">type&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;text/javascript&amp;#34;&lt;/span> &lt;span style="color:#1f2328">src&lt;/span>&lt;span style="color:#0550ae">=&lt;/span>&lt;span style="color:#0a3069">&amp;#34;//ajax.googleapis.com/ajax/libs/
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#0a3069">jquery/1/jquery.min.js&amp;#34;&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&amp;lt;/&lt;/span>&lt;span style="color:#0550ae">script&lt;/span>&lt;span style="color:#1f2328">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>と、バージョンを一桁までしか書かないと、そのメジャーバージョン・マイナーバージョンでの最新のバージョンを取ってくるみたいです。&lt;/p>
&lt;p>あと、CDNとしては &lt;a href="http://cdnjs.com/">&lt;a href="http://cdnjs.com/">http://cdnjs.com/&lt;/a>&lt;/a> も有名。
マイナーなJavaScriptライブラリも結構置いてくれているので、開発用によく利用してます。&lt;/p></description></item></channel></rss>