OmniAICreator/Qiita-1.07M huggingface dataset:
【rails】 Rails routesでいつも確認していないですか？

<h1>rails routesでUR確認していないんですか？</h1>

こんにちは。
エンジニアの卵、風見優人です。

毎日毎日、プログラミングに追われて
一日も早くプロエンジニアになりたいと願っています。

役立つ情報をアウトプットしていきますので
よければ参考にしていってくださいね！

<h1>ルーティングの確認方法</h1>

railsなどでURLやパスを確認するときって
どうやって確認をしていますか...?

おそらく、ターミナルで rails routesと毎回
手入力しているのではないでしょうか？！

<h2>そんなことしなくてもOK</h2>

rails routesをするとターミナルを切らないといけないですし
めんどくさくないですか？

裏技があるんです。
ターミナルを起動した状態で

rails/info/routes

とurlを打ち込んでください！！！
すると、URLの一覧がみれてしまうんです。

もっと早く知っていればよかったと後悔ｗｗｗ
効率化にもつながるのでぜひ参考にしてみてくださいね！

それでは、アディオス！！！！
LDAP コマンドのメモ

無茶振りされたので調査中です。

構築手順については以下の記事が大変参考になります。

https://qiita.com/y-araki-qiita/items/0c954c3ae25d4ed9dbb8

# 確認系

root で実行します。

```bash:設定関連
# 1. 全設定
# とりあえずこれで全部の設定が確認できるはず
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b "cn=config"

# 2. DB設定だけ確認する
# mdb ではない場合があるらしく、その場合は 1. で全量出力して確認すると良い
# ディレクトリ管理者 RootDN、Suffix、アクセス権限などの設定が確認できる
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b "olcDatabase={2}mdb,cn=config"

# 3. スキーマ定義の確認
# エントリを追加する際に気になることがあるので、確認できるようにしておくと良い
# cn=config を見るときに大量に流れていくやつ
# ldif-wrap=no しておくと grep できるので良い
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b "cn=schema,cn=config" -o ldif-wrap=no
```

```bash:ディレクトリエントリ関連
# ディレクトリのエントリ全体を出力
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b "dc=example,dc=com"

# uid=test のエントリを検索
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b "dc=example,dc=com" "uid=test"
```

# 更新系

```bash
# 追加
ldapadd -Y EXTERNAL -H ldapi:// -f hoge.ldif

# 削除
# 子エントリがある場合は先に子エントリを削除する必要がある
ldapdelete -Y EXTERNAL -H ldapi:// "uid=test,ou=Users,dc=example,dc=com"

# 更新
# 基本的に ldapdelete と ldapadd を使うと良い。
# ldapmodify は構築時などdeleteするわけには行かない場合に使用するもの。

# 例えば、以下のような流れだとオペレーションが安定する（気がする）
# 更新対象エントリの出力
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b "dc=example,dc=com" "uid=test" > entry.ldif
# エントリの修正（必要に応じてバックアップを作っておく）
vi entry.ldif
# 削除
ldapdelete -Y EXTERNAL -H ldapi:// "uid=test,ou=Users,dc=example,dc=com"
# 追加
ldapadd -Y EXTERNAL -H ldapi:// -f hoge.ldif
```

# 外部からアクセスする場合

外部からアクセスする場合は `-H` に接続先情報と、`-D` でアクセスユーザー、`-W` はパスワードを対話入力するオプションです。

```bash
ldapsearch -LLL -Y EXTERNAL -H ldap://123.123.123.123:389 -W -D "cn=Manager,dc=example,dc=com" -b "dc=example,dc=com"
```
【Rails】コントローラーからjavascriptへパラメータを渡す

# はじめに  
・本記事ではコントローラからjavascriptにパラメータを渡す方法を説明します。

## controller→view→javascriptとviewを介してパラメーターを渡すことができます。

まず、コントローラからビューへは、インスタンス変数を使いパラメータを渡します。

```ruby:/app/controller/books_controller.rb
def index
  #パラメータを、インスタンス変数でビューに渡す
  @book = 'コントローラからjavascriptへパラメータを渡す方法'
end
```

view(ビュー)ではinputタグでtypeをhidden属性にし、valueとして受け取ります。

```html:/app/views/books/index.html.erb
<h1>indexページ</h1>

<input type="hidden" id="book" value="<%= @book %>">
```

javascriptで、htmlの要素をdocument.getElementByIdで取得します。

```javascript:/app/assets/javascripts/application.js
window.onload = function () {
  const book = document.getElementById('book').value
  alert(book);
}
```

ブラウザで確認すると、コントローラから渡した@bookのパラメータが、javascriptのalertログで出力されていることが分かります。
Golang の構造体の初期値をnil にしたいときはポインタ型でフィールド変数で定義する

# Golangの初期値
Golangはプリミティブ型にそれぞれ初期値を持っている。
string型 なら`""`
int型　なら`0`

など、ゼロ値という名前でそれぞれのプリミティブ型を定義した時になんの値が入っているかが既に決まっている。

しかし、フィールド変数の型をユーザ定義型にしている構造体を扱う場合、単純に構造体のインスタンスを生成してしまうと、ユーザ定義型を遡ってプリミティブ型のゼロ値を代入された構造体が生成され、特定のフィールドだけnil にすることができません。

こうしてしまうと、他のAPIからjson を読み込みたい時などに全てのフィールドに空文字が入ってしまったり、0 が入ってしまったりしてしまうため、あまり良いとは言えません。

# 解決策
フィールド定義を行う時にユーザ定義型のポインタ型にしましょう。
ポインタ型のゼロ値はnil なので、代入されていないフィールドが自動的にnil になって返却されます。


# 参考元
https://pon3-blog.com/?p=137
消費者とブランドとの関係を考慮した階層ベイズモデルによるクロスメディア効果推定（日高・佐藤 2016）を読んで

## この論文を読んだ理由
総合系の広告代理店勤務でマーケティング関係の仕事をしている立場として、

・階層ベイズモデルおもしろそう。
・クロスメディア効果...なんだか気になる！

と思い、実務への応用も期待して選びました。

## 前提
### ①広告効果、クロスメディア効果について
広告の効果といっても様々あり、状況に応じて定義される。
売り上げやインストール数の変化など、短期的な指標をKPIとして広告効果を測定する事もあれば、
認知度や企業イメージなど、長期的な指標をKPIとして広告効果を測定する事もある。
前者はログデータから取得可能なものが多いが、後者はアンケート調査などによって測定される事が多い。

一般には、
デジタル広告は、短期的な指標に対する効果がでやすく、
TVCMや屋外広告は、長期的な指標に対する効果がでやすい、といった傾向がある。

また、クロスメディア効果とは、特定商品・企業の広告に複数の異なるメディアを通して接触した場合に、それぞれの主効果（単一のメディアから得られる効果）とは別の、メディア間のシナジー効果の事をいう。
（回帰分析でいうと、交互作用項が有意になる。）

ここでいう「異なるメディア」というのは、
「TVCMとデジタル広告」、のように、物理的に異なる接触経路を指す事もあるし、
「Twitter広告とFacebook広告」など、デジタル内での別のメディアを指しても良い。

### ②異質性について
消費者の異質性はマーケティング系の論文ではさかんに議論に上がるが、
簡単にいえば、**消費者ごとの違い**の事。

例えば、「男性と女性では広告の効果の出方に差があるはずなので、男女で別々に効果を推定しよう。」という発想である。
完全に別々で推定を行っている訳ではないが、イメージを掴むには上記で問題ない。

異質性の考慮には消費者のデモグラフィック属性が使われる事が多く、
今回紹介する論文では、「広告呈示前のブランドへの態度」という変数も使われていた。

## 概要
消費者異質性（広告呈示前のブランドへの態度を含む）を考慮して、複数広告素材の相乗効果（クロスメディア効果）を測定・推定するモデルを提案した。
これにより、広告の主効果は、企業に対して良いイメージを持っている消費者に対して大きく出やすいが示された。
一方で、広告のクロスメディア効果は、企業に対して良いイメージを持っている消費者に対して、正に出る場合と負に出る場合の両方が混在する結果となった。


## 先行研究との比較
先行研究には、
・消費者の異質性を考慮してクロスメディア効果を測定した研究がない。
・広告呈示前のブランドへの態度を考慮した研究がない。
・購入意図や購買行動指標に着目した研究が少ない。
といった課題があった。

上記の課題に対して、
消費者の異質性に広告呈示前のブランド態度を考慮して、クロスメディア効果の推定を行った。
目的変数には、認知や興味の他に、購買行動指標も含めた。

## モデルについて
目的変数をブランド態度指標とする固体内モデルと、
目的変数が観測モデルの係数、説明変数が消費者属性である個体間モデルの
2モデルで構成される、階層ベイズ順序ロジットモデル。

消費者属性によって係数が変化するランダム係数モデルに、ベイズ推定を適用させたモデルと解釈する事ができる。

（数式は元論文をご確認下さい。すみません...）

## 結果
・すべての目的変数（広告効果測定指標）において、交互作用項を含むモデルが採択された。

・ブランドに対して好意的な程、広告の主効果が大きくなる。

・ブランドに対して好意的でも、クロスメディア効果は、正の場合も負の場合もある。

・複数の素材が効果を持つ消費者は少ない。消費者によって効果の大きい広告は異なり、広告効果には多様性がある。

## ビジネスへの適用
広告効果を測定する際に他の広告素材の影響も考慮する必要があるという点は、納得のいく示唆である。
現在、単一のメディアにのみ広告を出稿している企業は少なく、より精緻な効果検証が求められる。

企業が広告を出稿する目的は、認知の拡大、ブランディング（長期的な好意形成）、短期的な売り上げ増加など、複数ある。
パネルデータに対して本研究で提案されたモデルを用いる事で、企業が広告を出稿する目的に合わせて広告効果を推定し、より大きな効果が期待されるターゲットに対して広告を出稿する事が可能である。
場合によっては、出稿目的から考えさせるような提案にも繋がる。



## 所感
クロスメディア効果というと、テレビCM・デジタル広告・屋外広告・店頭POPなど、広告接触経路の交互作用を考慮した研究を想像していた。

今回の研究は、上記のメディアの広告素材をすべて**PC上で接触させて**効果を測定している研究であるため、広告素材（**クリエーティブ**）のクロス効果を測定した研究として位置づけられるのではないか。
（PCを通して実験的に屋外広告の広告素材に接触させたとして、「屋外広告に接触した」と定義するには無理があると考えるため。）

私の中でのクロスメディア効果は、テレビ・スマホ・屋外広告といった広告接触経路の交互作用であり、こちらも気になる所である。
ただ、こういった検証を厳密に行うには、テレビ接触ログ・デジタル広告接触ログ・位置情報データなど、大規模なログデータが必要になるので、データベンダーとの調整が大変になるだろう。
この点、Chang et al.(2004)や井上(2007)はどのような観点で検証を行っているのか、次に読んでみたい。





## 参考文献
[・日高徹司, & 佐藤忠彦. (2016). 消費者とブランドとの関係を考慮した階層ベイズモデルによるクロスメディア効果推定. 日本オペレーションズ・リサーチ学会和文論文誌, 59, 106-133.](https://www.jstage.jst.go.jp/article/torsj/59/0/59_106/_pdf/-char/ja)

・井上哲浩. (2007). クロスメディア対応のマーケティングコミュニケーション. 広告月報, (566), 40-45.

[・Chang, Y., & Thorson, E. (2004). Television and web advertising synergies. Journal of advertising, 33(2), 75-84.](https://www.researchgate.net/profile/Esther-Thorson/publication/261623164_Television_and_Web_advertising_synergies/links/57714f5308ae6219474a4821/Television-and-Web-advertising-synergies.pdf)
GASで効率良くサーチする方法

GASでスプレッドシート内の大量データの中に対象となるデータが存在するかを検索する。
今回は、10,000行のデータの中から「golden-time」というデータを探す方法を2つ紹介。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955768/2a78ebbe-9b3e-2e75-9702-863778e5e3eb.png)


# ①大量データの中から総当たりで検索
スプレッドシートの1行目から最終行目までをfor文で1つずつ確認する方法。
細かな解説は省きますが、for文を回すことでターゲットとなる文字列を探しています。
※例外処理やelse文は面倒くさいので書いていませんが、本来は処理として入れるべき

```gas:searchValue.gs
//---------- 特定の文字列を検索する関数 ----------
function searchValue() {
  // 現在のシートを取得
  const Sheet = SpreadsheetApp.getActiveSheet();
  // シートの最終行を定義
  const LastRow = Sheet.getLastRow() + 1;
  // ターゲット文字列を定義
  const Target = "golden-time";

  // ☆☆☆☆☆☆☆☆☆ 1つずつクローリング ☆☆☆☆☆☆☆☆☆
  let value = "";
  for (let i = 1; i < LastRow; i++) {
    value = Sheet.getRange(`A${i}`).getValue();
    if (value == Target) {
      Logger.log(`${Target}は${i}行目にあります`);
      break;
    }
  }
  // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
}
```

# ②大量データの中から一気に検索
最初の部分は①と同じ定義です。簡単な解説は以下をご参照下さい。

1. 大量データを一括取得
この時、getValues()で取得したデータは2次元配列になっているので、flat()で1次元化します。

2. indexOf()メソッドにより、ターゲットとなる文字列（今回の場合はgolden-time）が1.で取得した1次元配列の中に入っているかを確認します。
・文字が入っている場合は、配列の何番目に入っているかを返す
・文字が入っていない場合は、-1を返す
※true or falseで返したい場合はincludes()メソッドを使ってください

```gas:searchValue2.gs
//---------- 特定の文字列を検索する関数 ----------
function searchValue() {
  // 現在のシートを取得
  const Sheet = SpreadsheetApp.getActiveSheet();
  // シートの最終行を定義
  const LastRow = Sheet.getLastRow() + 1;
  // ターゲット文字列を定義
  const Target = "golden-time";

  // ################### 一気に検索 ###################
  const ValueArr = Sheet.getRange(`A1:A${LastRow}`).getValues().flat();
  const Index = ValueArr.indexOf(Target);
  if (Index != -1) {
    Logger.log(`${Target}は${Index + 1}行目にあります`);
  }
  // #################################################
}
```

# 実行速度比較
①と②の実行速度ですが、結論から申し上げますと②の方が断然早いです。
試しにそれぞれの検索方法で10回処理を行い平均値を出してみたところ、次のような結果になりました。
①：11983.3[ms] → 約11秒
②：187.3[ms] → 約0.2秒

もちろん実行環境により差異はありますが、②の方が10倍以上速く処理が終わります。

# まとめ
GASは実行速度が遅い上に、実行時間に制限があるので注意が必要です。
数万行のデータを自動化処理する場合は、途中で処理が切れてしまわないようにコーディングをする必要があるので、本記事が参考になれば幸いです。
[CSS]文字を斜めにする

# はじめに
本記事では、以下`Let's Log in!`のように文字を斜めに表現する方法を記述します。

![ログイン画面　CSS 斜め.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1768158/918dfa06-8abe-5351-dbaf-bb9167d5c7ff.jpeg)

# 記述方法
## コード

```css
.login-subtitle {
  color: rgb(0, 0, 0);
  font-family: 'Permanent Marker', cursive;
  font-size: 12vh;
  text-align: start;
  transform: rotate(-7deg); ←ここ！！！
  padding-left: 15vw;
  position: absolute;
}
```

`transform: rotate(-7deg);`で文字を回転することができます。
`-7deg`でマイナスになっております。
`プラスでは時計回り`、`マイナスでは反時計回り`のイメージです。

以下、`7deg`にしてみました。

![ログイン画面　CSS 斜め　プラス.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1768158/e553abf7-155b-45a4-6f59-0b98135d4d41.jpeg)

`90deg`にしてみました。

![ログイン画面　CSS 斜め 90度.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1768158/1799545d-40c5-8e00-e8de-54cffec3e855.jpeg)

`90度`になりました。Let's Log in!がお辞儀してますねw

つまり、`~deg`の数字は角度を意味しています。

`180deg`にすれば、

![ログイン画面　CSS 斜め 180度.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1768158/61872bd4-99c6-3ae1-4ae0-3a28819e113e.jpeg)

すってんころりん！180度ですね。
ということは、180の倍数では、このような形になります。

360degだと添付しなくてもわかりますね、傾き０ですね。

以上です。


# 終わりに
短い記事ですが、いかがでしょうか。
斜めにしてみるとデザインを工夫しやすいと思います。

また、今回思ったこととして、
自分が想像し、実現したいことは、CSSやJavaScriptでできるなと思いました。

以下今回の参考サイトです。
[CSSでテキストを斜めに傾ける方法 (transformのrotateで回転させる)
](https://delaymania.com/201708/web/css-transform-text/)

明日も頑張ります！！
gRPCのInterceptorでみれるもの

## 個人メモ

クライアント側

```sh
❯ client.go add 1 2 3 10
16
```


Interceptorの実装

```golang
func Interceptor1(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	fmt.Println("FullMethod", info.FullMethod)
	fmt.Println("Server", info.Server)
	fmt.Println("--before--")
	m, err := handler(ctx, req)
	fmt.Println("--after--")
	fmt.Println("gRPC Response", m)
	return m, err
}
```

Interceptorの出力結果

```sh
FullMethod /proto.Calc/Add
Server &{{}}
--before--
add  %v %n [1 2 3 10] 16 <- server側の実装の結果
--after--
gRPC Response params:16
```

## まとめ

Interceptorでは **gRPCでのリクエスト・レスポンス・実行されたRPC名** が取れる
【Error対応】Unpermitted parameters: :format, :registration について

# はじめに

React、Rails APIでSPAを開発しているのですが、標記エラーに遭遇しました。
忘備録として、また同じエラーに遭遇した人に向けて、記事として残そうと思います。

# エラー

ログイン機能を実装するためにdevise_token_authを使っているのですが、実装後、テストのためReact <=> Rails API間の通信時にエラーが発生しました。

調べる前に、エラー分をよく読んでみます。

翻訳通り、許可されていないパラメータをやりとりしているから？なのでしょうか、でもログイン処理は完了していました。

```
web_1  | Unpermitted parameters: :format, :registration
web_1  | Unpermitted parameters: :format, :registration
web_1  | Unpermitted parameters: :format, :registration
```

# 対応

調べた結果、通信を受けるAPI側でストロングパラメータの定義がまずかったことが判明。
requireメソッドを使用して、params内の特定のキー(registration)に紐付く値だけを抽出するよう記述する必要がありました。
※ストロングパラメータに関しては、参考記事がわかりやすかったため、そちらに役割を譲りたいと思います。気になる方はご確認ください。

```
class Api::V1::Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController
  private
    def user_params
      params.require(:registration).permit( :name, :email, :password, 
                      :password_confirmation )
    end
```


これでエラーは解消することができました。


# 参考

devise_token_authで「Unpermitted parameters: :format, :registration」が出た時の対処法
https://qiita.com/sssssatou/items/aedd9ec093afd89a3190

【Ruby on Rails】ストロングパラメータって何なの？
https://qiita.com/ozackiee/items/f100fd51f4839b3fdca8
ビジネスアナリティクスの基本とアンチパターン

# これはなに
ビジネスアナリティクスは割と一般化が難しい分野だ（と思っている）が、仕事をやっている中でなんとなく要諦みたいなものを言語化してみる試み。
気が向いたら（というかなにかに気づいたら）書き溜めてみようと思っているが、本当に続くかは不明。

# 特定の事象が発生する確率（頻度）を分解して理解する
SaaSにおけるChurn rateや特定機能の利用率など、分析においてターゲットとなる数字（KPIと呼んでもよい）は何らか**無次元化された確率であることが多い。**
この確率が発生するメカニズムや背景を数字をもって理解し、どのようにすれば上げられるか（下げられるか）を考えることが、分析によってビジネスの意思決定を行うということに対応する。

このような確率を**直接的に**理解するときには、何らかの直感的な構成要素（属性）で分解していくのが王道パターンと言える。
これを理解したい事象$A$が発生する確率$P(A)$と、構成要素$x$が占める比率$P(x)$を用いると以下のように表される。

```math
P(A)=\sum _x P(A|x)P(x)
```
ただし、$\sum_x P(x)=1$を満たす。

**この右辺に存在する$P(A|x)$と$P(x)$の関係性がビジネス仮説に対応** し、どのような施策を打つべきか、何を目指して戦略を立てるべきかのヒントとなる。

以上を機能Aの利用率を業種別に分解して理解する場合を例にして具体的に書き下すと、以下の通り。

```math
\begin{eqnarray}
機能A利用率&=&\left(小売の機能A利用率\times 小売の比率\right)+\left(建設の機能利用率\times 建設の比率\right)+\cdots\\
&=&\sum _{業種X} \left( 業種Xの機能A利用率\times 業種Xの比率\right)
\end{eqnarray}
```

この分解をもとに、例えば**全体に占める比率が大きいが、機能A利用率が低い業種に着目すれば、その業種の利用率を上げることができないかを考えるのが施策に落とし込む、ということ**である。

この分解に於いては、**どのような構成要素（属性）$x$を選択するかが肝であり、分析官のセンスと経験が問われるところといえる。**
この構成要素選択の基準は経験上このようなものが大事。

- MECEな分解になっている（必須条件）　$\because \sum_x P(x)=1$
    - 必ずいずれかの業種に所属し、被りがないとする
- 事象Aの発生確率の高低を説明する仮説が立つ
    - 特定の業種は他に比べて機能A利用率が高いのではないか
- 分解結果$P(x)$に極端に小さな部分がない
    - 極端に少ない業種がいたらその他とかにまとめればいい
- 分解結果$P(A|x)$が$x$ごとに大小の差が大きい
    - これは分析して確かめる

必ずしも一つの要素で分解する必要は無く、和がネストされることも大いにあるが、あまり複雑にしすぎると理解が困難になることに注意。

## アンチパターン
特定の事象が発生する確率の分解でなく、**特定の事象が発生している中で、どのような構成要素が多いのか、と分解してしまう。**
これは上との対比では、**$P(A)$を理解するために本来算出すべき$P(A|x)$ではなく、$P(x|A)$を算出している例に該当し、ここへ$P(A)$の分解からたどり着くのは困難。**
$A$の事象を理解したいのに$A$の事後確率を算出しており、論理的な考察にはたどり着かない。

機能Aの例では、**機能Aを利用した事業者全体に占める業種の割合を算出すること**に対応。
機能Aを利用している事業者のうち、大半が業種Yだったとしても、対象事業者の大半が業種Yだったとしたら何の示唆も生まないよね、という感じ。
最小構成の Pulumi project (TypeScript) を作成する


## これはなに

Pulumi の新規 Project 作成に関して公式ドキュメントでは、AWS, Google Cloud, Azure, Kubernetes を管理する前提となっており、 `pulumi new aws-typescript`, `pulumi new azure-typescript`と記述されている。
複数クラウドを管理したい場合や、クラウドを管理する目的以外に Pulumi を利用する場合、余計な設定など含まれてしまうため以下のように作成しているのでメモです。

## Pulumi CLI のインストール

以下 URL を参考に Pulumi CLI をインストールしてください。

https://www.pulumi.com/docs/get-started/install/

## 使用する Node をインストール

今回は、 `v16.3.0` を [nodenv](https://github.com/nodenv/nodenv)[^1] 経由で設定する。

```bash
nodenv install 16.3.0
```

## Pulumi project 用のディレクトリを作成

今回は、 `pulumi` ディレクトリ内にセットアップしていく。

```bash
mkdir pulumi && cd pulumi
```

## 使用する Node のバージョンを固定

`nodenv local` を実行し `.node-version` を作成します

```bash
nodenv local 16.3.0
```

### 今後セットアップに yarn を利用する場合

以下コマンドを実行し `yarn` を install してください

```bash
npm i -g yarn
```

https://yarnpkg.com/getting-started/install

## Pulumi project を作成

`pulumi new` で TypeScript Project を作成すると、デフォルトで `npm` を利用します。
`yarn` を利用したい場合は `PULUMI_EXPERIMENTAL` に `true` を設定します [^2]

それぞれコマンド実行後 package install が実行されるので気長に待ちます。

### npm を利用する場合

```bash
pulumi new typescript
```

### yarn を利用する場合

:::note warn
GitHub 等で公開されている Project template から Project を作成する場合は Project 側の設定に従ってください。
:::

```bash
PULUMI_EXPERIMENTAL=true pulumi new typescript
```

https://github.com/pulumi/pulumi/pull/3556

### コマンド実行後

Project のセットアップが終わると以下のようなディレクトリ構成になります。

```
drwxr-xr-x   11 mziyut  staff     352 Sep  5 22:24 .
drwxr-xr-x   14 mziyut  staff     448 Sep  5 22:21 ..
-rw-r--r--    1 mziyut  staff      21 Sep  5 22:22 .gitignore
-rw-r--r--    1 mziyut  staff       7 Sep  5 22:22 .node-version
-rw-r--r--    1 mziyut  staff      86 Sep  5 22:22 Pulumi.yaml
-rw-r--r--    1 mziyut  staff      42 Sep  5 22:22 index.ts
drwxr-xr-x  315 mziyut  staff   10080 Sep  5 22:33 node_modules
-rw-r--r--    1 mziyut  staff     253 Sep  5 22:33 package.json
-rw-r--r--    1 mziyut  staff     438 Sep  5 22:22 tsconfig.json
-rw-r--r--    1 mziyut  staff  135600 Sep  5 22:33 yarn.lock
```

ここまで実行すれば、最小構成の Pulumi project の作成は完了です。

[^1]: [GitHub - nodenv/nodenv: Manage multiple NodeJS versions.](https://github.com/nodenv/nodenv)

[^2]: [Add ability to opt-in to using yarn instead of npm by justinvp · Pull Request #3556 · pulumi/pulumi](https://github.com/pulumi/pulumi/pull/3556)
STM32L010と液晶、ACM1602K-NLW-BBWで3分タイマー


x 原因は、わからないが液晶がちらつく場合は、ウェートを調整してね!!


STM32L010でMbedを使い16文字2行液晶に3分を
表示するプログラム

74hc164シフトレジスターを使用した。
液晶とのピン数を節約した。信号線10本から
信号線3本に減らした。

1 CLK クロック端子(緑色)
2 RSDATA RS端子とデータの共有端子(黄色)
3 E 読み込み書き込み同期信号(青色)

秋月電子
キャラクター液晶 [ACM1602K-NLW-BBW] 通販コード　P-10185
半固定ボリューム１０ｋΩ [TSR-065-103-R] 通販コード　P-06063

アイテンドウ
8ビットシフトレジスタ [HD74LS164P]　www.aitendo.com/product/12485


![h_con39.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e9c9673d-a7dd-e5a9-0286-1042b79fbeb9.jpeg)



![h_con52.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2b6c820c-64f1-8761-7fa7-6bcb04939b5c.jpeg)



```c++


#include "mbed.h"

//*          *****  *****       ***  * *
//*         *       *    *     *   * * *
//*         *       *    *     *   * * *
//*         *       *    *     *   * * *
//*         *       *    *     *   * * *
//********   *****  *****       ***  * *

#define swclk1  PA_5    //A4
#define swdio1  PA_7    //A6
#define en1     PA_4    //A3

DigitalOut swdclk(swclk1);
DigitalOut swdio(swdio1);
DigitalOut en(en1);

int kk;
#define oun_min() for(kk=0;kk<60;kk++){wait_ms(1000);}

//             12345678   12345678   12345678   12345678
char b8[8] = {0b10000000,0b01000000,0b00100000,0b00010000,
              0b00001000,0b00000100,0b00000010,0b00000001 };

void seg1(int v,int rs)
{
    for(int jj=0;jj<8;jj++){
        if( (v & b8[jj]) == 0 ){
                swdio=0; //ビットが0
        } else {
                swdio=1; //ビットが1 
        }//endif
        swdclk=1;swdclk=0; //clk
    }//for

    swdio=rs;
    en=1;    wait_ms(1);
    en=0;
}

//文字列の表示 nana_seg
int ns_printf(char *str1) {

    //文字の中身がゼロか
    while(*str1){

        //一文字出力
        seg1( *str1 ++ , 1  );


    } //while

    //戻り値
    return(0);
}//ns_printf

int lcd_int[]={
  0x30,0x30,0x30,0x38,0x08,0x01,0x06,0x08+0x04
};//lcd_init

int main() {

    //GPIOの初期化
    en=0;

    //液晶の初期化
    for(int ii=0;ii<8;ii++){ 
        seg1( lcd_int[ii] , 0);wait_ms(2);
    }//for

    seg1( 0x80+0x00 , 0  ); //1ライン目にカーソルを移動
    ns_printf( "START" ); wait_ms(500);

    //画面クリア
    seg1(   0x01  , 0  ); 
    wait_ms(5);

    ns_printf( "0," );
    oun_min()
    ns_printf( "1," );
    oun_min()
    ns_printf( "2," );
    oun_min()
    ns_printf( "3" );

    while(1){} //無限ループ

}


```
Lambda

import boto3
import os
import datetime


"""
This portion will obtain the Environment variables from AWS Lambda.
"""

GROUP_NAME = os.environ['GROUP_NAME']
DESTINATION_BUCKET = os.environ['DESTINATION_BUCKET']
PREFIX = os.environ['PREFIX']
NDAYS = os.environ['NDAYS']
nDays = int(NDAYS)


"""
This portion will receive the nDays value (the date/day of the log you want
want to export) and calculate the start and end date of logs you want to
export to S3. Today = 0; yesterday = 1; so on and so forth...
Ex: If today is April 13th and NDAYS = 0, April 13th logs will be exported.
Ex: If today is April 13th and NDAYS = 1, April 12th logs will be exported.
Ex: If today is April 13th and NDAYS = 2, April 11th logs will be exported.
"""

currentTime = datetime.datetime.now()
StartDate = currentTime - datetime.timedelta(days=nDays)
EndDate = currentTime - datetime.timedelta(days=nDays - 1)


"""
Convert the from & to Dates to milliseconds
"""

fromDate = int(StartDate.timestamp() * 1000)
toDate = int(EndDate.timestamp() * 1000)


"""
The following will create the subfolders' structure based on year, month, day
Ex: BucketNAME/LogGroupName/Year/Month/Day
"""


BUCKET_PREFIX = os.path.join(PREFIX, StartDate.strftime('%Y{0}%m{0}%d').format(os.path.sep))


"""
Based on the AWS boto3 documentation
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.create_export_task
"""


def lambda_handler(event, context):
    client = boto3.client('logs')
    client.create_export_task(
         logGroupName=GROUP_NAME,
         fromTime=fromDate,
         to=toDate,
         destination=DESTINATION_BUCKET,
         destinationPrefix=BUCKET_PREFIX
        )
Reactコンポーネントに渡される文字列内のURLをリンクにする方法



## 現状
umiJSのcommentにリンクを挿入する
`renderItem={}`内の`comment`タグがチャットメッセージコンポーネントに該当する。
その中の`content`プロパティにメッセージが渡されている。

## 問題点
`item`を受け取って`text`を表示している。
問題はここが全て`string`型で渡されているので、URLを添付してもリンクが繋がらない。



```JavaScript
// 修正前
<List
       /* 省略 */
  renderItem={item => {
     return (
         <li>
           <Comment
             author={item.username}
             content={item.text} // <== ここ
            />
        </li>
      )
    }}
 />
```

## 実装方針

入力された文字列からURLを検索し変換してから`content`に渡す。
正規表現を用いてURLライクな文字列を抽出し、aタグに置換する。

```JavaScript:ブログより借用
const ｌink = (str) => {
    const regexp_url = /https?:\/\/[a-zA-Z0-9.\-_@:/~?%&;=+#',()*!]+/g;
    const regexp_makeLink = (url) => {
	    return '<a href="' + url + '">' + url + '</a>';
    }

    return str.replace(regexp_url, regexp_makeLink);
}
```
`str`を受け取って`replace(検索文字, 置換後)`メソッドで置換する。
`regexp_url`を正規表現で定義して、https://~~~という文字列を検索する。
末尾の`/g`はテキストないの全てのurlを検索するもので、urlがヒットするたびに`regexp_makeLink`メソッドが実行される。

`replace`メソッドは第一引数が席表現の場合、第二引数の関数の引数は`(文字列, n番目の()で括られた文字列)`を受け取る。

`regexp_makeLink`は受け取った`regexp_url`をaタグで囲う関数。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace



https://ginpei.hatenablog.com/entry/20070811/1186846446

そして`autoLink`関数で処理した`item.text`を`Comment`の`content`プロパティに渡す。

```JavaScript:components/TextChat/index.tsx
// 修正前
<List
       /* 省略 */ 
  renderItem={item => {
     return (
         <li>
           <Comment
             author={item.username}
             content={ｌink(item.text)} // <== ここ
            />
        </li>
      )
    }}
 />
```

## この時点で予期しない挙動に気づく...

`<a href="' + url + '">' + url + '</a>`がそのまま文字列として表示されてしまう。
現状は全て文字列として渡されてしまっているものを`JSX.Element`として渡さないといけない。

セキュリティ上あまり良くないような気がするが、InnerHTMLで埋め込む方針をとる。
Reactの場合、`dangerouslySetInnerHTML`という書き方になる。

```JavaScript:dangerouslySetInnerHTMLでaタグを認識させる。

  const link = (str: string): JSX.Element => {
    const regexp_url = /https?:\/\/[a-zA-Z0-9.\-_@:/~?%&;=+#',()*!]+/g;
    const regexp_makeLink = (url: string): string => {
      return `<a href=${url} target="_blank" rel="noopener noreferrer">${url}</a>`;
    }
    const replacedString = str.replace(regexp_url, regexp_makeLink);

    return (
      <p dangerouslySetInnerHTML={{__html: replacedString}}></p>
    )
  };

```


__htmlプロパティに先ほど変換したURLを含む全ての文字列を渡すことで、pタグのなかにaタグを含む文字列を入れる。
ちなみに新規タブで開きたかったので`target="_blank"`を追記。

加えて、「開かれた新規タブ側で、リンク元タブの URL を操作できてしまう」という虚弱性対策として` rel="noopener noreferrer`を加える。



https://ja.reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml

https://toragramming.com/web/html/html-link-target-blank/
Heroku ステージング環境から本番環境にプロモートできない

# 内容
アプリをherokuのステージング環境にデプロイしており、動作確認が完了したので本番環境にプロモートしようとしたところ

```
Fetching app info...
Fetching apps from app-name-pipeline...
Starting promotion to production...
Waiting for promotion to complete...
Fetching release info...
Running release command...
rails aborted!
PG::ConnectionBad: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

Tasks: TOP => db:migrate
(See full trace by running task with --trace)
 ›   Warning: 
 ›   Promotion to some apps failed
app-name: failed
                   release command failed
```
のようなエラーが出て、プロモートが拒否されました。

# 解決法
該当アプリを今まで一度も本番環境にpushしたことがないとこのようなエラーが出ることがあるようです。
その場合

```
heroku addons:create heroku-postgresql -a 本番環境のアプリ名
```
をターミナルで実行し、本番環境に直接データベースを作成し

```
heroku pipelines:promote
```

を実行すると、ステージング環境から本番環境にプロモートすることができました。
Vuetifyを導入後にESLint（Airbnb）でMissing file extension ＋その他エラーになる場合の対応方法

新しくVue.jsプロジェクトを作成してVuetifyを導入した後、まずお試しにと`yarn serve`したらLinterのエラーが出ました。
Vuetifyのデフォルトで生成されるHome.vueがESLintのAirbnbルール違反の箇所があるのと、あと私はPrettierでファイル保存時にフォーマットをかけていたのでそれとESLintとの干渉を回避する必要もありました。

# 結論

* コンポーネントをimportする際に拡張子まで明記する
* Prettierの設定を変えてESLintと干渉しないようにする（シングルクォート, 末尾カンマ）


# 出たエラー
```
   6:24  error  Missing file extension "vue" for "../components/HelloWorld"  import/extensions
   6:24  error  Strings must use singlequote                                 quotes
   9:9   error  Strings must use singlequote                                 quotes
  12:15  error  Missing trailing comma                                       comma-dangle
  13:4   error  Missing trailing comma                                       comma-dangle
```

# 対象のコード
```vue:Home.vue
<template>
  <hello-world />
</template>

<script>
import HelloWorld from "../components/HelloWorld";

export default {
  name: "Home",

  components: {
    HelloWorld
  }
};
</script>
```

# 対応内容
### コンポーネントをimportする際に拡張子まで明記する
import HelloWorld from '../components/HelloWorld.**vue**';

Airbnb以外のESLintルールを使うことでもいいようですし、できる人なら拡張子解決のルールだけ上書きしてもいいと思います。

### Prettierの設定を変えてESLintと干渉しないようにする

Linterに怒られないように、Prettierの方でダブルクォートへ変換してもらい、かつ末尾カンマの付与を強制します。
プロジェクトルートに`.prettierrc`を作成し、以下の内容を記述します。

```json:.prettierrc
{
  "singleQuote": true,
  "trailingComma": "all"
}
```

# 参考
[Running completion hooks...error: Missing file extension "vue" for "./components/HelloWorld" #157](https://github.com/vuetifyjs/vue-cli-plugins/issues/157)
ゲームで遊べるコンテナを作る(ソリティア) 

# はじめに

[PodmanでGUIアプリを起動させる](https://qiita.com/karosuwindam/items/7aa0e55168d91cfcfbfe)でGUIが起動するアプリを作った
応用としてソリティアが遊べるコンテナアプリを作ってみる

# ソースコード

作成するDockerfileは以下の通り

```Dockerfile
FROM debian:8.6

RUN apt-get update
RUN apt-get install aisleriot -y

CMD ["/usr/games/sol"]
```

aisleriotはソリティアカードゲームのコレクションのライブラリーである
参照リンク：https://wiki.gnome.org/Apps/Aisleriot
また、インストール後、/usr/games/にsolというバイナリが登録されるため、
コンテナが立ち上げた時に実行するようにする

# ビルド

以下のコマンドでビルドを実行する

```bash
podman build -t sol .
```

作成したイメージサイズは以下の通り、かなりでかくなる
小さくしたい場合は、いらないパッケージを削除しないといけないけど
本記事は省略する

```bash
$ podman images
REPOSITORY                TAG     IMAGE ID      CREATED         SIZE
localhost/sol             latest  114c11d10db7  30 minutes ago  679 MB
docker.io/library/debian  8.6     19134a8202e7  4 years ago     129 MB
```

# 実行
以下のコマンドを実行するとことで、ゲームが立ち上がる

```bash
podman run --rm -e DISPLAY=:0 -v /tmp/.X11-unix:/tmp/.X11-unix localhost/sol
```

以下のように、立ち上がった画面で、マウスを使用してゲームを遊ぶことができる

![Screenshotfrom2021-09-05 22-38-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425374/9f10d74f-8610-6a21-ff0a-18559b48c16d.png)


# まとめ

GNOME系のゲームを立ち上げてゲームを遊ぶことができた
ABC212 C - Min Difference を解いてみた

https://atcoder.jp/contests/abc212/tasks/abc212_c

![ABC212_C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/94e0c79d-e8f4-81f9-8bdc-9f2dbe9e6d44.png)

2重 for で全探索してもよいが、計算量が 4*10^10 となり、TLE となる。
糸口を探すため、とりあえずサンプルを確認してみる。

![abc212_SAMPLE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/66a653f1-ae33-fa33-9029-4a9be7c6f255.png)

個人的に注目したのは**入力例3**。
最小値を探すってことは、**数列 A , 数列 B の中から値が近い要素の組み合わせを出せば良い**んだよね？

ココから更に飛躍が入ります。
じゃあ、**数列 A と数列 B を合体して sort したら A[n]=>B[m] or B[m]=>A[n] となる並びが必ずあり、
その中から差分が最小となる組み合わせを探せば良い**んだよね？

っと言うことで、これで行けました。

```MinDifference_1.py
N,M = map(int,input().split())
A = list(map(int,input().split()))
B = list(map(int,input().split()))

A = list(set(A))#A の重複要素を排除
B = list(set(B))#B の重複要素を排除

#A,B を合体すると、ごちゃまぜで分からなくなるので、
#辞書で管理することにしました。
dicA = {}
dicB = {}

for i in range(len(A)):
    dicA[A[i]] = 1#冒頭で set() してるので重複要素なし、要素は必ず 1 つ
for i in range(len(B)):
    dicB[B[i]] = 1#冒頭で set() してるので重複要素なし、要素は必ず 1 つ

X = A + B # AとB を合体
X.sort()  # sort する

ans = float("inf") # 無限大より小さいものを for で探す

#辞書はリストに無い key の所在を尋ねると Error を返します。
#if X[i] in dicA としても良かったかもだが、dicA/dicB の要素数が計算量として上乗せされる。
#そのため 2*10^5 x 2*10^5 となる可能性があるので記述は避けた。
#代わりに try / except を使って計算量を抑えた.
for i in range(len(X)-1):#=> X を端から確認し、X[i],X[i+1] の差分をcheck。
    try:
        if dicA[X[i]] == 1 and dicB[X[i+1]] == 1:#辞書で X[i],X[i+1] がそれぞれ A,B であることを確認
            if abs(X[i]-X[i+1]) < ans:
                ans = abs(X[i]-X[i+1])
    except:#上記で Error で返したら、以下の処理に入る
        try:
            if dicB[X[i]]==1 and dicA[X[i+1]]==1:#辞書で X[i],X[i+1] がそれぞれ A,B であることを確認
                if abs(X[i] - X[i + 1]) < ans:
                    ans = abs(X[i] - X[i + 1])
        except:
            pass#上記でもダメなら pass。次の検証に向かう
print(ans)
```

####きっと、もっと分かり易くて良い解法があるはず。
とりあえず、ほかの人の解法も読みながらイメージを積み上げてみようと思う。
感動したら、追記するかも。

理解があやふやかもしれないが、
上記の場合の計算量は O(N) だと思うが相違ないだろうか？
有識者のアドバイスがあれば助かります m(_ _)m

#あれから
まだまだ少ないが色々解いて見識が広がったと信じ、再チャレンジ。
以下でも通った。

```MinDifference_2.py
N,M = map(int,input().split())
A = list(map(int,input().split()))
B = list(map(int,input().split()))

dicA = {}
dicB = {}

for n in range(N):
    if A[n] not in dicA:
        dicA[A[n]] = 0
    dicA[A[n]] += 1

for m in range(M):
    if B[m] not in dicB:
        dicB[B[m]] = 0
    dicB[B[m]] += 1

X = A + B
X.sort()
score = float("inf")
for i in range(N+M-1):#max O(4*10**5)
    if X[i] in dicA and X[i+1] in dicB or X[i] in dicB and X[i+1] in dicA:
        score = min(score,abs(X[i]-X[i+1]))
print(score)
```

##改善点
・A/B の重複削除の記述を排除
  仮に重複があったともして前述にあるように O(4*10^5) なので計算量は問題にならないし、答えが変わることはない。
・try/except の記述を削除
  辞書の in演算は O(1) なのでガンガン使うことで記述が計算量を気にせず、シンプルに書ける。

https://takeg.hatenadiary.jp/entry/2019/06/02/172831
PICマイコン開発入門　前知識編

## はじめに

私は業務でゲーム開発を主に行っていますが、ここ最近アミューズメント機器のゲーム開発に携わるようになり、よりハードウェアに近い部分のプログラミングに興味を持つようになりました。
現在組込プログラミング分野では、ホビー用途として人気のArduinoのほか、MbedやNucleoといったワンボードマイコンが多く利用されていますが、シンプルな部分から学ぼうと、PICを利用して学習をすすめることにしました。
今回は基本的な前知識を備忘録的に書きました。
こんな知識もあったほうがいいなどあればコメントでお知らせください。

## マイコンとは

電気的な回路や機械的な部分を制御する半導体チップです。
現在では様々な電子機器に搭載され、頭脳としての役割を担っています。

## PICとは

Peripheral Interface Controllerの略称で、Microchip Technology Inc.が製造しているマイクロコントローラ製品群の総称です。
Peripheral Interface Controllerを直訳すると『周辺機器の接続部分を制御するもの』となります。

## ハーバード・アーキテクチャ

PICはハーバード・アーキテクチャと呼ばれるコンピュータアーキテクチャを持ちます。
これは、命令用とデータ用でそれぞれ物理的に独立した記憶装置や信号通路を持ち、現在コンピュータの主流であるフォンノイマン型アーキテクチャと異なります。

### ハーバード・アーキテクチャの利点

命令用とデータ用で記憶装置や信号通路が独立しているため、それぞれのデータの読み出しが競合せず高速化が可能になります。

## ワンチップマイコン

PICはワンチップマイコンと呼ばれますが、これはICチップ一つの中に、CPU、プログラムメモリ、データメモリ、入出力制御、タイマ、etcといった多数の機能を搭載したものです。

### CPU

中央演算処理装置とよばれ、まさしく頭脳となる部分です。
各種命令の読み出し、実行可能な形式への変換、実行を行います。

### プログラムメモリ

プログラムそのものを格納するメモリです。

### データメモリ

各種演算に使用するデータを格納するメモリです。

### タイマ

一定間隔でシグナルをシステムへ送る機構です。
基礎から学ぶReact/React Hooks学習メモ 2 React基礎

# React基礎

## JSX

- 最上位に1つの要素を配置する
    - `<Fragment></Fragment>` または `<></>` を最上位にすれば余計なタグが入らない。
- `class` → `className`、 `for` → `htmlFor` に置き換える。
- 直接style属性は使えない
    - `<h1 style={{fontSize: 16, color: 'red'}}>` のように書く。
        - 外側の`{}`はReactの記法、内側の`{}`はJavaScriptのオブジェクト定義。
- defaultValue属性、defaultChecked属性
    - stateで更新されない非制御コンポーネントで、value属性でフォームの初期値を設定してしまうと、後から値の変更ができなくなる。

```js
const App = () => {
  return (
    <>
      <input type="text" defaultValue="Hello, React!" />
      <input type="radio" name="radio01" value="radio01" defaultChecked={true} />
      <input type="radio" name="radio02" value="radio02" />
    </>
  )
}
```

## props

- 受け取る側

```js
const Hello = () => {
  return <p>Hello, {props.name}!</p>
}

// または{name}として受け取る
const Hello = ({name}) => {
  return <p>Hello, {name}!</p>
}
```

- 渡す側

```js
const App = () => {
  return (
    <>
      <Hello name="text" name="React" />
    </>
  )
}

ReactDOM.render(<App />, document.getElementById("root"));
```

## state

- 関数コンポーネントでは、stateを管理するには、フックの`useState()`を利用する。

```js
// 状態変数、状態を変更するための関数、初期値
const [liked, setLiked] = useState(false);
```

## レンダリング

- 次のタイミングでレンダリングが行われる
    - コンポーネントの初回レンダリング時
    - コンポーネントのstateがん変化したとき
    - 親コンポーネントがレンダリングされたとき
    - カスタムフックからコンポーネントが受け取っている変数が変化したとき
 

## React Hooks

- useState
    - 関数コンポーネント内で、state管理ができる
- useEffect
    - 副作用（DOMの書き換え、変数代入、API通信など）を追加、制御、副作用関数の実行タイミングをUI構築後まで遅らせる
- useMemo
    - 関数の結果を保持する。結果が同じ場合、そこから結果を再取得する。
- useCallback
    - 関数自体をメモ化する。React.memoと組み合わせて利用する。
- useRef
    - 要素の参照を行う。コンポーネント内で値を保持する。
- useContext
    - Context機能をシンプルに使えるようになる。propsで渡さなくても、Contextに収容されているデータへシンプルにアクセスできる。
- カスタムフック
    - 「use」で始まる独自のフック。UIと切り離したロジックの抽出が可能。処理を切り分けることもできる。

参考
- [基礎から学ぶReact/React Hooks](https://www.amazon.co.jp/dp/B09CP8T4TX)
抽出条件が抽象的なリストビューの作成

事の発端
---
「商談の完了予定日が今日から7日以内までの商談を抽出するリストビューが欲しい」ってカンジの要望がたまにある。
しかし、リストビューでは日付の指定にToday()関数は使えずYMD形式で指定する必要があるので、抽出の度に日付を設定する手間が発生する。
**「今日」**と言う抽象的な日付をどう扱うか…

解決作
---

**リストビューで持てないならオブジェクトに持たせれば良いじゃない**


「完了予定日が今日から7日以内の商談」の判定結果を商談オブジェクトの項目として持たせ、リストビューではその結果を抽出する。

今回は可読性を優先して「今日から7日先の日付」持たせたカスタム項目「FutureDate__c」を予め用意している。
そして「完了予定日が今日から7日以内であればTrue」となる数式「Formulas__c」を作成する。

```数式
IF (
 AND( TODAY() <=  CloseDate , CloseDate <= FutureDate__c )
, true, false)
```

**結果**
この記事を書いているのが2021年9月5日なので結果はこの様に右端「Formulas」項目で対象のレコードのみTrueとなる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/2785325b-ec7e-ccd3-227e-cbffd66fb330.png)

あとは、リストビューの抽出条件で「Formulas__c」がTrueのレコードを絞り込むだけ。
これで「今日」から7日以内と言う抽象的な抽出が可能となる。

応用編
---

**自分と同じチームの商談のみを表示したい**

今回は、ユーザ情報に選択リストで「営業チーム（SalesTeam__c）」なるものを追加し、各ユーザにチームを割り当てる。

先程と同様に商談に数式項目を追加しリストビューの抽出条件で指定するだけ

```数式2
TEXT($User.SalesTeam__c) =  TEXT(Owner.SalesTeam__c )
```

結果の画像は省略

**利点**
チームの数だけリストビューを作らずに済み、メンテもユーザ情報の項目のみとなり、将来的なチームの増減時の修正コストが抑えられることである。
http・httpsとの違いって？？初心者は必見

# はじめに
URLの「http」に「https」、ちょっとした違いのように思われるかもしれませんが、かなり重要な違いなんです。
中にはなんとなく「http」より「https」の方がセキュリティ的に安全と理解している人もいらっしゃるかと思うでしょう。私も含めてなんとなくで理解していたので今回、「http」と「https」の違いについて調べてみました。

![ダウンロード.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572216/80d07748-e9d8-661d-05a9-fe436ceca480.jpeg)


# HTTPとは
HTTPとは「Hyper Text Transfer Protocol」の事で、ホームページのデータは文字だけでなく画像や動画などがあります。これらのデータをサーバとクライアントの間で通信するときの通信規約（プロトコル）がHTTPです。
インターネットが普及して、パソコンやスマートフォンが当たり前に使われる現代、Webサイト閲覧などで利用されるHTTPは一番馴染みのあるプロトコルといっても過言ではない。

__HTTP通信によってスマホやパソコンからWebページを閲覧するときには
「データが暗号化されていない」状態になっています。__

そのため、もし第三者にこの通信データが傍受された場合には、通信内容が簡単に漏洩してしまいます。

#　HTTPSとは

HTTPに対してHTTPSには文字列の最後に「S」が付いています。この最後の「S」は「Secure（セキュア）」の「S」です。「Secure」という単語を辞書で調べてみると、

>安全な、危険のない、安全で、安定した、心配のない、保証された、確実な

Web用語ではセキュリティがしっかりしているといった意味で使用される。

そこでHTTP通信でやり取りするデータを盗み見られても分からないように暗号化した通信の方法がHTTPSです。

HTTPSもHTTPと同じプロトコルの一つですが、HTTPSではSSL（Secure Socket Layer）というプロトコルが使用されています。厳密に言うと現在はSSLではなくTLS（Transport Layer Security）というプロトコルが使用。

# 安全性を確保する仕組み

HTTPSで利用されるSSL/TLSでは、以下の３つの仕組みによりWebサイトの安全性を確保している。

* 盗聴防止（暗号化通信）
使用する暗号化方式を最後に確認し、暗号化通信を実行します。
クライアント側で有している共通鍵を使ってデータを暗号化した上でWebサーバ側に送信し、Webサーバ側は暗号化されたデータを受け取り、Webサーバ側が持つ共通鍵を使って暗号化された内容を平文にします。

* 改ざん防止
　ネットバンキングにおいて振込先情報が書き換えられしまうとデータの改ざんとして、「メッセージダイジェスト」が利用される。メッセージダイジェストとは、あるデータから一意の短いデータ（ハッシュ値）を取り出す計算のこと。データの送受信にハッシュ値を比較して改ざんを検知できる。

* なりすまし防止
SSLサーバ証明書（公開鍵含む）をクライアント側に送付し、クライアント（ブラウザ）が有するルート証明書でSSLサーバ証明書を確認します。また、この際にクライアント側は共通鍵を生成します。
正しいWebサーバであることを確認できなかった場合、ブラウザ上で警告が出ます。

# サーバ証明書の種類

企業認証...「ドメイン名の使用権」「組織の法的実在性」を認証する
EV認証...「ドメイン名の使用権」「組織の法的・物理的実在性」
         「組織の運営」「承認者・署名者の確認」を認証する

# まとめ　HTTPとHTTPSの違い

HTTPとHTTPSの主な違いは通信内容が暗号化されていないか、されているかの違いです。

HTTPSに対応したホームページを開くとブラウザのURLの左の方に「保護された通信」と表示されます。
また「保護された通信」ではなく、組織名が表示される場合もあります。

![スクリーンショット 2021-09-05 21.53.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1572216/12673006-5c07-ee6b-7774-e2023d3b96ca.png)

# HTTPはなぜ安全じゃないのか

HTTPは通信内容が暗号化されておらず、中間者攻撃によって通信内容の盗聴や改ざんが行われる可能性があります。 そのため通常のHTTPは安全ではないとされています。

# HTTPSで暗号化してるけど、安全じゃない場合もある？
HTTPよりもHTTPSのほうが安全ではありますが、HTTPS通信だからといって100％安全だと言い切れるわけではありません。HTTPS通信であっても、通信相手が偽者だった場合は全く安全ではない。

# HTTPS のデメリット

* Webサーバ側はSSL証明書を定期的に更新する必要がある
* SSLサーバ証明書の発行には金銭・時間ともにコストが掛かる（無料で発行できるものもある）
* 非対応のWebページは見れなくなる
* 平文に比べてサーバに負荷が掛かる

# 参考サイト
https://cybersecurity-jp.com/column/25772
docker compose で localhost 以外のIPアドレスをする（MAC）

会社では、laravel + postgres のプロジェクトがあり、今まで Homestad を使用していたが、M1 使用者が増えてきたので、Docker 化をする必要があった。

Docker はデフォルトで localhost が割り当てられる。
初めは、 `nginx-proxy` (リバースプロキシ)でポート番号をプロジェクトごとで分けて、対応しようと思った。

https://github.com/nginx-proxy/nginx-proxy

## 問題
プロジェクトごとでポートが被らないようにポート番号を考えるのがめんどくさい。
だからプロジェクト毎にIPアドレス割り当てようと考えた。

```yaml:docker-compose.yaml
version: '3'

services:
    app:
        build: ./docker/app
        ports:
            - '${DOCKER_HOST:-127.0.0.1}:${APP_PORT:-80}:80'
        environment:
            VIRTUAL_HOST: 'domein.jp'
        volumes:
            - '.:/var/www/html'
        depends_on:
            - db
            - mailhog
        tty: true #永続起動する設定

    db:
        image: 'postgres:9.6'
        ports:
            - '${DOCKER_HOST:-127.0.0.1}:${DB_PORT:-5432}:5432'
        environment:
            PGPASSWORD: '${DB_PASSWORD:-secret}'
            POSTGRES_DB: '${DB_DATABASE}'
            POSTGRES_USER: '${DB_USERNAME}'
            POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
        volumes:
            - 'db:/var/lib/postgresql/data'
            - .:/laravel

    mailhog:
        image: 'mailhog/mailhog:latest'
        ports:
            - '${DOCKER_HOST}:8025:8025'

volumes:
    db:
```

```env:.env
DOCKER_HOST=127.0.0.3

APP_PORT=80

DB_PORT=secret
DB_DATABASE=laravel
DB_USERNAME=postgres
DB_PASSWORD=secret
```

上記のように設定して、`docker-composer up -d` を実行したところ以下エラーが出た。

```sh
Error response from daemon: Ports are not available: listen tcp 127.0.0.3:8025: bind: can't assign requested address
```

## 解決方法
MAC OS ではデフォルトでは `127.*.*.*` は使用できないらしい。

そのため、以下コマンドで使用できるようにする必要があった。

```sh
sudo ifconfig lo0 alias 127.0.0.3 up
```

.zshrc や config.fish などで起動時に有効にするようにすれば、毎回やる必要はなくなる。

```sh:.zshrc
for ((i=2;i<256;i++))
do
    sudo ifconfig lo0 alias 127.0.0.$i up
done
```

```sh:config.fish
for i in (seq 255); sudo ifconfig lo0 alias 127.0.0.$i up; end
```

## 関連
https://wand-ta.hatenablog.com/entry/2020/05/23/011001

https://superuser.com/questions/458875/how-do-you-get-loopback-addresses-other-than-127-0-0-1-to-work-on-os-x
Windowsの自動起動にアプリを追加する

Windows10, 11で検証済み

Store経由でインストールしても、外部のインストーラーでインストールしても、
1. "Win+R" で　shell:appsfolder　と入力して開くフォルダにほとんどのソフトがあります。ここで目的のアプリのショートカットを作ります(デスクトップに生成されます)。
2. 次に"Win+R"で shell:startup と入力し開くフォルダに先ほどのショートカットを追加し、再起動すれば完了です。

例えば、Windows11ではLINEの設定に自動起動が無いらしいですが、この方法で解決できます。
起動時に実行させたいスクリプトなどもstartupに追加すれば自動実行されると思います。
ストア経由でインストールしたアプリはデスクトップにショートカットを作成しづらいですが1.　の手順で作れるのは覚えて置くと便利ですね。
Cloud Firestore(+Cloud Functions)で関連度つき全文検索をするやり方

# 概要
Firestoreには全文検索機能はないため、通常であればElasticsearchなどの外部サービスを利用する必要が出てくるわけですが、それを使わずにFirestore(とCloud Functions)で全文検索できるようにするやり方を紹介します。
内容的には、[Firestore(+Cloud Functions)で関連度つき全文検索をできるようにした話](https://qiita.com/tommyktech/items/473ccbc4fd8edfed4df2) で紹介した[ソースコード](https://github.com/tommyktech/Japanese-Fulltext-Search-in-Firestore)の使い方の解説になります。

# 前提
- 課金できるGCPアカウントを持っていること（Firestoreで必要）
- gcloudコマンドを実行できる環境があること（推奨）
    - なければ [ここ](https://cloud.google.com/sdk/docs/install?hl=JA) を参考にインストールする
    - なくても手動でデプロイすればいけるので、必須ではない

# 大まかな流れ
- Consoleからプロジェクトを作成
- Cloud Firestoreをセットアップする
- Cloud Funcionsの関数をデプロイする

すでにセットアップ済みの部分は適宜飛ばしてください。

# Consoleからプロジェクトを作成
[GCPのWebコンソール](https://console.cloud.google.com/) の上部にある、__∴プロジェクト名▼__ のところからプロジェクトを作成するか、__[プロジェクト作成ページ](https://console.cloud.google.com/projectcreate)__に直接アクセスしてプロジェクトを作成する。
![ image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/aacbe7a6-f8b8-2774-8cb5-4e81e28f696a.png)



# Cloud Firestoreをセットアップする

### 1. Firestoreをネイティブモードで開始
**[Firestoreのプロダクトページ](https://console.cloud.google.com/firestore/redirect/firestore)**に移動し、__ネイティブモードを選択__をクリックし、続いて表示されるページでリージョンを選択して__データベースを作成__する。
このとき、選択するリージョンは後々作成するCloud Functionsと同じものにする必要がある（検索速度維持のため）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/c175f173-2067-7de8-37c7-b3f6fd1bd926.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/33a84f5c-6323-cf75-8d9a-f2c86b422bde.png)


### 2. Firebaseを有効にする
データベース作成が完了したらFirestoreのデータベースのページが表示されているはずなので、そこの左側にある__セキュリティルール__をクリックし、ページ遷移先にある__FIREBASEを有効にする__ボタンをクリックする。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/74b36e6d-803a-7beb-0efb-8993fbb24188.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/15dbe63f-ccf7-fe47-baaf-0f9d82e59323.png)

# Cloud Functionsの関数をデプロイする
### 1. Cloud Build APIを有効にする
Cloud Functionsの関数をデプロイするために必要なので、以下のURLにアクセスしてCloud Build APIを有効にする。
https://console.cloud.google.com/apis/library/cloudbuild.googleapis.com
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1955693/abadda06-b055-d092-5fd7-4f0ff6bf5026.png)



### 2. Cloud Functionsの関数をデプロイする
以上で設定が終わったので、次は関数をデプロイして実際にテキストを格納・検索できるかどうかを確認します。
以下、gcloudでのデプロイ方法を解説しますが、当然コンソールからデプロイすることも可能です。その場合はリージョンをFirestoreと同じものにすること、メモリを2GB以上にすることを忘れないでください。

1. `gcloud config set project [プロジェクトID]` でプロジェクトを切り替えて
1. デプロイするファイル（`main.py`と`requirements.txt`）が存在するディレクトリに移動して
1. `main.py`中のFirebaseプロジェクト名を、今回作成したプロジェクトのIDに置き換えて
1. 以下のコマンドでデプロイする  
     `gcloud functions deploy [function名] --entry-point main --runtime python38 --trigger-http --allow-unauthenticated --region [Firestoreのリージョン] --memory 2048MB`



### 3. HTTPのトリガーURLにアクセスしてデプロイできたか確認する
以下が正常に行えるかを確認する：

1. テキストをFirestoreに入れる  
    https://[トリガーURL]?method=index&text=テストです
2. 検索する  
    https://[トリガーURL]?method=search&q=テスト
3. 削除する  
    https://[トリガーURL]?method=delete&q=[テキストのdoc_id]



以上です。
TensorFlowをソースからビルドする

# はじめに
TensorFlowを使用したところ、以下のエラーが発生しました。

```
$ python3 -c "from keras import backend as K"
Using TensorFlow backend.
Illegal instruction
```

CPUがAVX命令に対応していない場合に、上記のエラーが発生するようです。
TensorFlowを実行環境でビルドしなおせばいいという情報があり、1.15.0のソースからビルドすることにしました。

# 実行環境
OS：Windows10のWSL2(Debian)
プロセッサ：Intel(R) Core(TM) i3 CPU       M 380  @ 2.53GHz   2.53 GHz
実装RAM：8.00 GB (7.68 GB 使用可能)
Pythonのバージョン：3.7.11

# 参考サイト
以下の公式ページを参考にしました。

https://www.tensorflow.org/install/source?hl=ja


# ビルド手順
※以下は上記の公式ページの「Bazel をインストールする」以降の作業内容となります。この作業よりも前にkeras_preprocessing等のインストールが必要となりますので、詳しくは上記リンクを参照ください。

```
$ sudo apt update
$ sudo apt install -y curl build-essential
$ curl -L -o bazel https://github.com/bazelbuild/bazelisk/releases/download/v1.10.1/bazelisk-linux-amd64
$ chmod +x bazel
$ export PATH="${PATH}:${PWD}"
$ git clone https://github.com/tensorflow/tensorflow.git
$ cd tensorflow
$ git checkout v1.15.0
```

以下のファイルにBazelのバージョン「0.26.1」を指定する。

```
$ vi .bazelversion
```

以下のコマンドで構成セッションが開始される。今回は全てデフォルトのままとしたが、必要に応じて変更する。

```
$ python configure.py
```

ビルドを開始する。
※TensorFlow 1.xを指定するオプション`--config=v1`を指定するとエラーが出たため、無指定とした。`git checkout v1.15.0`をせずに最新のソースコードでこのオプションを指定する方法も可能かもしれない（未検証）。

```
$ bazel build //tensorflow/tools/pip_package:build_pip_package
```

私の環境ではビルドに15時間程度かかった。

```
Target //tensorflow/tools/pip_package:build_pip_package up-to-date:
  bazel-bin/tensorflow/tools/pip_package/build_pip_package
INFO: Elapsed time: 52524.336s, Critical Path: 1560.65s
INFO: 19514 processes: 19514 local.
INFO: Build completed successfully, 20531 total actions
```

pipパッケージをビルドする。

```
$ ./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
```

pipパッケージをインストールする。

```
$ python3 -m pip install /tmp/tensorflow_pkg/tensorflow-1.15.0-cp37-cp37m-linux_x86_64.whl
```
【Error】mbind: Operation not permitted @ MYSQL(Docker) への対応方法

# はじめに

Dockerで開発していた際、標記エラーが発生。対策方法を探し、解決できたので記録として残しておく。

## Error文

```
mbind: Operation not permitted
mbind: Operation not permitted
mbind: Operation not permitted
```

# 概要

## Docker 開発環境

Docker : v3.8
Ruby : v 3.0
Rails(API) : v 6.1.4
React : 0.1.0
MYSQL: 8.0


## 状況

* ReactでSPAアプリ開発時、サーバーサイド側ではRails APIでdevise_token_authを使い、サインアップ機能を実装。その動作確認をする時に以下エラーが出た、という状況です。通信にはReact側でaxiosモジュールを使用。
* エラーは出ますが、問題なくDBにはデータを保存できていました。しかしながら、謎のエラー文が(しかも3行も)出続けるし、放置しておくのは気持ちが悪かった。


# 解決方法

```
services:
  db:
    image: mysql:8.0
    volumes:
      - db-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    command: --default-authentication-plugin=mysql_native_password
    ports:
      - "3306:3306"
    // ここから追加
    cap_add:
      - SYS_NICE
    // ここまで追加
```

参考にしたGithub上での回答や参考にした記事にもありますが、特定のNUMA操作ができなくなってしまうようです。
追加してエラーを回避しておくに越したことはなさそうです。ご参考まで。

# 参考

mysql 8.0.11 docker: mbind: Operation not permitted #422
https://github.com/docker-library/mysql/issues/422

DockerのMySQLで「mbind: Operation not permitted」が出る件
https://selfnote.work/20210315/programming/mysql-docker-error-mbind/
Docker イメージを GitHub に登録する【Packages】

「GitHub Packages」を利用すると、Docker イメージを GitHub で管理することができます。GitHub Packages では Docker イメージのほかに、npm パッケージを公開することもできます。

https://github.co.jp/features/packages

GitHub が提供しているレジストリには、``https://ghcr.io``と``https://docker.pkg.github.com``の 2 つがありますので、この 2 つに Docker イメージを登録してみます。

## 準備

コンテナレジストリ認証・登録のために、``write:packages``の権限があるパーソナルアクセストークンを発行しておきます。

また、レジストリに登録するイメージも作成しておきます。

```Dockerfile:Dockerfile
FROM alpine:3.10
ENTRYPOINT ["echo", "hello world"]
```

1\. Dockerfile からイメージを作成

```terminal
$ docker build -t helloworld:latest .
```

2\. イメージのテスト

```terminal
$ docker run --name hello-world helloworld:latest
// hello world
```

## パッケージ名前空間``https://ghcr.io``に登録

### 1. コンテナレジストリでの認証

```terminal
$ export CR_PAT=YOUR_TOKEN
$ echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
```

### 2. tag を付ける

```terminal
$ docker tag helloworld:latest ghcr.io/kiyo27/helloworld:latest
```

### 3. コンテナレジストリにプッシュ

```terminal
$ docker push ghcr.io/kiyo27/helloworld:latest
```

プッシュが成功すると**[Packages]**タブから登録された Docker イメージを確認することができます。
![cr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780549/702f1d9f-3dff-2d7b-77d3-8f00a4b2150a.png)

参考: [コンテナレジストリの使用](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-container-registry)

## ``https://docker.pkg.github.com``に登録する

GitHub の Docker レジストリ(``docker.pkg.github.com``)は、コンテナレジストリ(``https://ghcr.io``)に置き換えられたみたいです。コンテナレジストリの方がきめ細かい権限管理ができるそうです。
https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-docker-registry
今後もしかしたら、GitHub の Docker レジストリは非推奨になるかもしれません。

### 1. Docker レジストリでの認証

```terminal
$ echo $CR_PAT | docker login https://docker.pkg.github.com -u kiyo27 --password-stdin
```

### 2. tag を付ける
_OWNER_をリポジトリを所有しているユーザ名に、_REPOSITORY_にはイメージを公開するリポジトリ名に変換します。
``$ docker tag IMAGE_ID docker.pkg.github.com/OWNER/REPOSITORY/IMAGE_NAME:VERSION``

```terminal
$ docker tag helloworld:latest docker.pkg.github.com/kiyo27/hello-world-workflow/helloworld:latest
```

### 3. イメージをプッシュ

```terminal
$ docker push docker.pkg.github.com/kiyo27/hello-world-workflow/helloworld:latest
```

登録したイメージは、リポジトリに関連付けられています。
![pkg-cr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/780549/a612244c-471c-ff75-dfc2-6978d33e7615.png)

参考: [Docker レジストリの使用](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-docker-registry)

## 参考


- [Packages: Container registry now supports GITHUB_TOKEN](https://github.blog/changelog/2021-03-24-packages-container-registry-now-supports-github_token/)
- [Migrating to the Container registry from the Docker registry](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/migrating-to-the-container-registry-from-the-docker-registry)
- [npmレジストリの利用](https://docs.github.com/ja/packages/working-with-a-github-packages-registry/working-with-the-npm-registry)
Djangoで418 I'm a teapotを実装する

## 418 I'm a teapot
418 I'm a teapotとは1998年のエイプリルフールに発表されたジョークステータスコードです。これをDjangoで実装する方法を見つけたので書いていきます。

## 前提
※ファイル、フォルダ群の階層構造は省略
とりあえずこの記事では前提としてurls.pyは以下のものとします

```python:urls.py
#import文などは省略
urlpatterns = [
	path("teapot", views.teapot, name="teapot"),
	]
```

## 単純に418を返す場合
```python:views.py
from django.http import HttpResponse

def teapot(request):
    return HttpResponse(status=418)
```
この状態でpython manage.py runserverを行い、<a href="http://127.0.0.1:8000/teapot">http://127.0.0.1:8000/teapot</a>にアクセスすると

```
[05/Sep/2021 21:15:43] "GET /teapot HTTP/1.1" 418 0
```
とコンソールに表示され、418番が出ていることが分かります。

## 418専用のHTMLを出したい場合
まずtemplatesフォルダ直下に418.html(別にこの名前じゃなくてもOK)を作成しておき、

```html:418.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <h1>I'm a teapot!!</h1>
        <img src = "{% static 'picture/teatime_teapot.png' %}">
    </body>
</html>
```
と書き、そしてviews.pyに

```python:views.py
from django.shortcuts import render

def teapot(request):
    return render(request, "418.html", status=418)
```
と書いておきます。
この状態でpython manage.py runserverをし、<a href="http://127.0.0.1:8000/teapot">http://127.0.0.1:8000/teapot</a>にアクセスすると、
![418_qiita.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1073363/d0d01b06-5b43-afba-6f87-880206cb74e6.png)
と表示されるはずです。