OmniAICreator/Qiita-1.07M huggingface dataset:
Web技術の備忘録

##目的
Web技術について学習し、理解するために学んだ内容をまとめる


##サーバー
ネットワーク上で情報やサービスを提供する役割を持つコンピューター。

##クライアント
サーバーから提供された情報やサービスを利用する役割を持つコンピューター。
もしくはWebアプリケーションを使用している人を指す。
クライアントはインターネットを介して通信することでサービスを利用する。

##インターネット
世界中のコンピュータや情報機器がお互いに接続された環境のこと。

##プロトコル
ネットワークに接続された機器同士が通信をする際の、共通のルールや手順。

##TCP/IP
インターネット通信において最も利用されている通信プロトコルの総称。
インターネットへアクセス可能なコンピューターは全てTCP/IPに対応している。
全てのコンピューターが同じプロトコルを利用しているため、世界中のコンピューターは繋がることができる。
HTTPもTCP/IPの一部である。

##IPアドレス
IPアドレスとは、コンピュータやサーバーに設定されたインターネット上の住所（識別番号）のことを指す。
インターネット上においてIPアドレスは世界中でたった1つである。この住所を指定することで、
特定のコンピュータやサーバーと通信することができる。

##ポート番号
サーバーとアプリケーション間で通信する際に割り振られる番号。
サービスを利用する際、IPアドレスでコンピューターは指定できるが、IPアドレスだけではコンピューターのどのサービスを利用するかまでは指定できない。
利用する側は、IPアドレスに加えてポート番号を指定することで意図したアプリケーションにリクエストを送ることができる。
Webサーバーをマンションに例えると、IPアドレスは住所の番地まで、ポート番号は部屋番号と言える。

##ドメイン
ドメインとは数値とドットからなるIPアドレスを、人間が扱いやすく覚えやすいように文字列に変換したもの。

##DNS
DNSとは「Domain Name System」の略であり、ドメインをIPアドレスに変換する仕組みのことを指す。
DNSの役割は電話帳と似ている。
電話をかける際は電話番号が必要になるが、氏名と電話番号が紐付いて管理された電話帳があれば、電話をかけたい相手の氏名から番号を見つけることができる。
DNSも同様であり、IPアドレスのまま管理するのは大変であるが、「google.com」のように意味のある文字列に変換することで管理がしやすくなる。
そしてDNSのサービスを提供するサーバーを「DNSサーバー」と呼ぶ。
DNSサーバーは、ブラウザから入力されたドメインに対して、紐付けられたIPアドレスを返す。
MVVMとCoordinatorで画面遷移

#概要
M(Model)-V(View)-VM(ViewModel)って画面遷移はViewの仕事なのかなと思って調べたところCoordinatorパターンというものがあることをしったので、MVVMにどうにかして組み込んで見ようとしたらできた（なんとか）ので記事にします。


#説明
ますどういった仕組みで遷移させるか説明します。
`ViewModel`を`ViewController`のプライベートなプロパティにします。
そして`ViewModelBuilder`という`ViewModel`を初期化するための変数を作ります。
そして`Coordinator`から画面遷移する時に

```swift:Coordinator.swift
let vc = ViewController()
vc.viewModelBuilder = {
    let viewModel = ViewModel(input: $0)
    return viewModel
}
```

という感じでコードを書きます。
ここで`ViewModel`にボタンタップを検知するようにしておけば遷移はできますよね。

```swift:Coordinator.swift
viewModel.input.buttonTap.subscribe(onNext: {
    // 遷移処理
}).disposed(by: disposeBag)
```

こんな感じです。
ここで重要なのが今回は``単純な画面遷移機能``というところです。
もしこれがログイン画面の`Coordinator`だとしたらログイン処理はここですべきではないですよね。
ログイン処理はViewModelでして、画面遷移は`coordinator`に任せたいです。
それはどうやって実現するのかというと、

```swift:ViewModel
var tapEventSubject = PublishSubject<()>()

input.buttonTapped.drive(onNext: {
    // クロージャを引数にもつログイン処理 {
        tapEventSubject.onNext(())
    }
}).disposed(by: disposeBag)

```

このようにログイン処理完了した後にクロージャで`onNext`を流し、coordinatorで

```swift:Coordinator.swift
let vc = ViewController()
vc.viewModelBuilder = {
    let viewModel = ViewModel(input: $0)
    viewModel.tapEventSubject.subscribe(onNext: {
        // 遷移処理
    }).disposed(by: disposeBag)
    return viewModel
}
```
というように参照すれば役割は果たせてるのかなと思います。

#まとめ
今回はそれぞれの役割というものにだけ着目していたので
subjectはprivateにしとけよとか、もっとこうすればsubject使わなくてもいけるといった意見があるとございます。

改善案、質問などございましたら是非コメントしていただけると嬉しいです。
Coordinatorの利用が今回初めてだったので、もっと勉強して理解を深めて行きたいです。
mdファイルの中に書き込んだJSが自動成型されなかったとき

大量のmdファイルを修正していたのですが1ファイルだけvscodeのprettierが効きませんでした。

そのためvscodeの設定なども見直したのですが解決しませんでした。

最終手段として各ファイルで修正してからコピペしようとし、mdファイルからjsファイルにコピペしたときに気づきました。

**```{}```**の数がズレてエラーが起きている！？

これに気づいてmdファイルを修正すると無事にprettierが効くようになりました！
超初心者が学ぶランダムフォレスト・分類回帰樹木 (CART法)⓪

## 背景
初めまして、初投稿です。2021年1月より運と勢いだけで、全くの初心者としてとあるメーカーの社内データアナリストとして働き始めました新参者です。
会社で与えられた、最初に理解すべきアルゴリズムがランダムフォレストということで、参考書籍をベースに備忘録も含めて少しずつ記事として形に残したいと思い投稿しました。
参考書籍として、主に[**樹木構造接近法 (Rで学ぶデータサイエンス 9)**](https://www.amazon.co.jp/%E6%A8%B9%E6%9C%A8%E6%A7%8B%E9%80%A0%E6%8E%A5%E8%BF%91%E6%B3%95-R%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%83%BC%E3%82%BF%E3%82%B5%E3%82%A4%E3%82%A8%E3%83%B3%E3%82%B9-9-%E4%B8%8B%E5%B7%9D-%E6%95%8F%E9%9B%84/dp/4320110560)を使用予定です。
##目的
一番は**アルゴリズムの理解**です。なので意味不明な数式や用語の理解についても積極的に考察していきます。
言語はRを用いていますが、目的はあくまでもアルゴリズムの理解なので他言語やソフトウェアを使っている方にも少しでも参考になるような記事を書ければと思います。
モデルにぶち込み結果を得るだけでなく、変数の意味やモデリングの際の注意点等にもこの勉強を通して新たな発見や洞察を得ることが本質なので冗長な点が多々あると思いますがご了承ください。

週2くらいで投稿したいなという心持です。
##本題
ランダムフォレストについてなんとなく知っていることですが・・・
・回帰も分類もできる！アンサンブル学習（意味よく知りません）の典型！
・回帰は平均、分類は多数決で解が求まる！
・数値やカテゴリーで区分して枝を作っていく！
・なんか不純度やらジニ係数なるものがあるらしい
・たくさんの決定木を作ってブースティングやらブートストラップサンプリングやらといった手法で弱学習器を重ねて強いものにするっぽい

こんなふわっとした物をしっかりと体系的に固めていきましょう
###なんで樹木構造を使うのか？
樹木構造接近法とは、ランダムフォレストを含む、CART法やMARS法、PRIM法と呼ばれる分析手法の総称です。
これらの分析手法を使う主な理由としては以下の5つ
**①デンドログラム（樹木）として表せるので結果解釈が視覚的に簡単**
**②目的変数と説明変数の非線形構造。交互作用を有意義に捉えられる**
**③説明変数次元（列数）＞データ数にも適用できる**
**④説明変数の慎重な変換（コード化）が必要ない**
とのことですが、分析側にとっても受け手側にとっても取り扱いやすいって感じでしょうか。
###CART法
CART法の特徴について
・説明変数の尺度が名義尺度～間隔尺度まで扱える
・応答変数が連続の場合は回帰樹木、分類変数の場合は分類樹木と呼ばれる
・樹木図は上→下へふしが分岐する（条件がTrueの場合は左へが基本）
・終結ふしの値は応答の予測値であり、回帰の場合はふしに属する個体の**平均値**が、分類の場合には**多数決**方式が用いられる
特に説明変数の尺度なんかが自由なのは、ローデータそのままぶっこめそうなのがメリットに見えますね！
というわけで、Rに既存のcarsデータで実際に可視化すると

| speed | dist |
|:-:|:-:|
|4  |2   |
| 4  | 10  |
|  7 |  4 |
|   8|  22 |
|   9|  16 |
（以下略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031677/29300e94-b9e9-3222-0ace-23de44223f7f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031677/280f2d81-6679-e1cd-2c9d-c95af6f3f39d.png)
走行距離（dist）がスピードで分枝されて、平均走行距離が出力されてますね！
さて、分類について、irisデータでやってみると

|Sepal.Length| Sepal.Width |Petal.Length |Petal.Width |Species|
|:-:|:-:|:-:|:-:|:-:|
|5.1|         3.5|          1.4    |     0.2|  setosa
|4.9 |        3.0 |         1.4   |      0.2 | setosa
|4.7  |       3.2  |        1.3  |       0.2  |setosa
|4.6   |      3.1   |       1.5 |        0.2  |setosa
|5.0    |     3.6    |      1.4|         0.2  |setosa
（以下略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031677/4edd3b46-f6d0-0f35-f776-b6c0e90c583b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1031677/9d4bc763-f7aa-e5ff-ef23-820d45de7fa0.png)
Petal lengthとPetal Widthが説明変数、Speciesが分類応答変数となっていますが、プロットを見るとなかなかよく分けられていますね。
ここまではデータをモデルに突っ込んだだけです。なんでこのような結果が出るのか、果たしてこの結果の妥当性はどうなのか？という点がこのシリーズを始めた目的。
ジニ係数や枝の刈込、サンプリング等が重要になってくるのか・・・

今回はあまりに基礎の基礎の退屈記事になってしまいましたが・・・
次回からは本格的にそこを探っていきたいと思います！

###参考
[Rチートシート](https://rstudio.com/wp-content/uploads/2019/01/Cheatsheets_2019.pdf)
[Introduction to Data Science](https://rafalab.github.io/dsbook/)
[樹木構造接近法と最近の発展](https://www.jstage.jst.go.jp/article/jscswabun/18/2/18_KJ00004574188/_article/-char/ja/)
AWS Gateway Load Balancer が東京リージョンに対応したらしいので試してみた

#概要#
[AWS Gateway Load Balancerが東京リージョンに対応しました](https://aws.amazon.com/jp/blogs/news/aws-gateway-load-balancer-tokyo/)
WS Gateway Load Balancer を使うことで、FWやIDS,IPSのサードパーティの仮想ネットワークアプライアンスの可用性および、拡張性を向上させることができるようです。
今までもクラウド上に、仮想ネットワークアプライアンスを導入することは可能でしたが、可用性、拡張性といったところは課題になっていました。
例えば、ピーク時に負荷を処理するために、リソースを過剰にプロビジョニングしたり、トラヒックに基づいて手動でスケールアップ、スケールダウンしたり、もしくは、その他の補助ツールを使う必要がありました。
いずれにしても運用のオーバヘッドとコストの増加に繋がっておりましたが、AWS Gateway Load Balancerを使うことで、この課題を解決することができます。

*↓のページでもの概要にも書かれている通り、GWLB と GWLBE を利用することによりシンプルにスケール・可用性・サービス提供のしやすさを向上することが可能にになったらしい。
そしてこの間の通信はGeneveプロトコルを利用してレイヤー3でカプセル化され、透過的に転送することができるようだ。*
[[新サービス]セキュリティ製品等の新しい展開方法が可能なAWS Gateway Load Balancerが発表されたので調査してみた](https://dev.classmethod.jp/articles/introducing-aws-gateway-load-balancer/)

少々イメージがつきにくいので、り、GWLB と GWLBE を作成するところまで確認して見た。


#やって見た系#

##GLB##

「作成」
![スクリーンショット 2021-03-06 15.49.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/7f9b16a2-ad0d-5451-49e9-de5cb2633292.png)

基本的な設定は通常のELBと同じで、プロトコル：ポートが、**GENEVE:8081** になっているところぐらいだ。
![スクリーンショット 2021-03-06 15.57.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/1144eaf7-b22c-5b67-e856-2e3acb30d0bf.png)

##エンドポイントサービス##

GLBが作成されたら、「統合サービス」から、「エンドポイントサービスの作成」を開き、VPCエンドポイントサービスの画面へ遷移する。
![スクリーンショット 2021-03-06 16.17.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/245b153a-6872-21f8-f65d-4716d30e6fa3.png)

対象となるGLBを選択してエンドポイントサービスを作成する。
![スクリーンショット 2021-03-06 16.21.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/ffcbbfbf-20b1-6cfd-7f65-72d29c3e726c.png)

エンドポイントサービスが作成されたら、エンドポイントを作成するために「サービス名」をコピーしておく。
![スクリーンショット 2021-03-06 16.26.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/4491cc3d-2dc7-5a18-a159-fafb3df63d7d.png)

##エンドポイント##

「サービスを名前で検索」から先ほど控えたエンドポイントサービスのサービス名を入れて検証する。
![スクリーンショット 2021-03-06 16.34.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/04acd917-2beb-90f7-b186-2ff8be47e794.png)

最後にエンドポイントサービス側で、エンドポイントのリクエストを承認する。
![スクリーンショット 2021-03-06 16.37.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280929/3dff6a4e-fd44-f008-498c-836dd6d5b990.png)

とりあえずはここまで。詳しい動作については追々やっていこう。


#リンク#
[Elastic Load Balancing](https://qiita.com/leomaro7/items/0b96ad1b25bee1957f8c)
Qiitaの記事にvimeoの動画を埋め込んで再生させる方法(CodePen経由)

Vimeoの動画をCodePen経由でQiitaの記事に埋め込んで再生させる方法のメモです。YouTube動画を使うこちらの記事を参考にさせていただきました。
[【説明しよう】これがQiitaの投稿に動画(Youtube)を埋め込んで再生させる方法だ。](https://qiita.com/takada_impl/items/0287ddad3966a42903fb)

**Vimeo版作成手順**
1. CodePenに動画再生用のPenを作成
2. 再生したい動画を[Vimeo Player API](https://github.com/vimeo/player.js)を使ってPenに埋め込む
3. PenのEditorを開き、フッターの**Embed**ボタンをクリック
4. **Embed This Pen**画面が開くので、Previewセクション見てレイアウトを調整。**drag to resize**バナーを下にドラッグしてコンテナの高さを調整
5. **Copy &amp; Paste Code**セクションの**HTML(recommended)**タブを開くと埋め込み用HTMLコードが表示されるのでコピー
6. Qiitaの記事編集画面にペースト

結果のサンプルはこれです。
<p class="codepen" data-height="541" data-theme-id="light" data-default-tab="result" data-user="kaz_hashimoto" data-slug-hash="gOLdwmW" style="height: 541px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="gOLdwmW">
  <span>See the Pen <a href="https://codepen.io/kaz_hashimoto/pen/gOLdwmW">
  gOLdwmW</a> by Kazuhiro Hashimoto (<a href="https://codepen.io/kaz_hashimoto">@kaz_hashimoto</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

プレーヤーのオプション設定については、**JS**タブ内のJavaScriptを参照してください。
一応、レスポンシブ対応です。画面幅に合わせて動画の幅と高さが調整されます。
上記サンプルではインラインでの自動再生を可能にするため、音声はミュート設定にしました。

１つ欠点が。スマホで見たとき動画の寸法は調整されますが、Penの高さは固定のままなので、動画の下に余白ができてしまいます。コンテナの高さは上記作成手順4で調整した値(px)に固定されるためです。
rails マイグレーションファイルの削除について

## マイグレーションファイルの削除
何回も削除しているが削除のたびに見直しているのでQiitaに残しておきます。
## 現状のマイグレーションファイルの状態を確認

```
rails db:migrate:status
```

上記コマンドでマイグレーションファイルの状態を確認
![Alt text](https://gyazo.com/f263f36e07e9ee029f0c90018785748f.png)

up状態の場合は削除や編集はできないのでdown状態にします。
今回はロールバックを使用。

```
rails db:rollback
```
再度statusで確認してみると

![Alt text](https://gyazo.com/1c62ff647f8b4da5a36e818c0a5a43bc.png)

## マイグレーションの削除
あとは手動でdownになっているマイグレーションファイルを削除するだけです。削除したら以下のコマンドを入力して完了になります。

```
rails db:migrate
```

upになっているマイグレーションファイルを削除するとめんどくさくなるそうです。
[Python]辞書を1行ずつファイルに書き込む

keyとvalueの組を1行ずつファイル出力するプログラム
パッケージのimportなどは不要


```python:
dic = dict(key1="val1", key2="val2", key3="val3")

#ファイル出力
with open("output.csv", mode='w') as f:
    f.writelines("\n".join(str(k)+","+str(v) for k,v in dic.items()))
# key1,val1
# key2,val2
# key3,val3
```

**注意点**
joinの中に二重リストや二重タプルを入れることはできません．
また異なる型をjoinで結合しようとするとエラーを吐くため，結合前に各変数をstr型に変換してあげないといけません．
C++のためのASCIIコード表


|ASCIIコード表|
|-|-|-|

|10進|	16進|	文字|
|-|-|-|
|0	|0x00	|NUL（null文字)
|1	|0x01	|SOH（ヘッダ開始）
|2	|0x02	|STX（テキスト開始）
|3	|0x03	|ETX（テキスト終了）
|4	|0x04	|EOT（転送終了）
|5	|0x05	|ENQ（照会）
|6	|0x06	|ACK（受信ＯＫ）
|7	|0x07	|BEL（警告）
|8	|0x08	|BS（後退）
|9	|0x09	|HT（水平タブ）
|10	|0x0a	|LF（改行）
|11	|0x0b	|VT（垂直タブ）
|12	|0x0c	|FF（改頁）
|13	|0x0d	|CR（復帰）
|14	|0x0e	|SO（シフトアウト）
|15	|0x0f	|SI（シフトイン）
|16	|0x10	|DLE（データリンクエスケープ）
|17	|0x11	|DC1（装置制御１）
|18	|0x12	|DC2（装置制御２）
|19	|0x13	|DC3（装置制御３）
|20	|0x14	|DC4（装置制御４）
|21	|0x15	|NAK（受信失敗）
|22	|0x16	|SYN（同期）
|23	|0x17	|ETB（転送ブロック終了）
|24	|0x18	|CAN（とりけし）
|25	|0x19	|EM（メディア終了）
|26	|0x1a	|SUB（置換）
|27	|0x1b	|ESC（エスケープ）
|28	|0x1c	|FS（フォーム区切り）
|29	|0x1d	|GS（グループ区切り）
|30	|0x1e	|RS（レコード区切り）
|31	|0x1f	|US（ユニット区切り）
|32	|0x20	|（スペース）
|33	|0x21	|!
|34	|0x22	|"
|35	|0x23	|#
|36	|0x24	|$
|37	|0x25	|%
|38	|0x26	|&
|39	|0x27	|'
|40	|0x28	|(
|41	|0x29	|)
|42	|0x2a	|*
|43	|0x2b	|#ERROR!
|44	|0x2c	|,
|45	|0x2d	|-
|46	|0x2e	|.
|47	|0x2f	|/
|48	|0x30	|0
|49	|0x31	|1
|50	|0x32	|2
|51	|0x33	|3
|52	|0x34	|4
|53	|0x35	|5
|54	|0x36	|6
|55	|0x37	|7
|56	|0x38	|8
|57	|0x39	|9
|58	|0x3a	|:
|59	|0x3b	|;
|60	|0x3c	|<
|61	|0x3d	|#ERROR!
|62	|0x3e	|>
|63	|0x3f	|?
|64	|0x40	|@
|65	|0x41	|A
|66	|0x42	|B
|67	|0x43	|C
|68	|0x44	|D
|69	|0x45	|E
|70	|0x46	|F
|71	|0x47	|G
|72	|0x48	|H
|73	|0x49	|I
|74	|0x4a	|J
|75	|0x4b	|K
|76	|0x4c	|L
|77	|0x4d	|M
|78	|0x4e	|N
|79	|0x4f	|O
|80	|0x50	|P
|81	|0x51	|Q
|82	|0x52	|R
|83	|0x53	|S
|84	|0x54	|T
|85	|0x55	|U
|86	|0x56	|V
|87	|0x57	|W
|88	|0x58	|X
|89	|0x59	|Y
|90	|0x5a	|Z
|91	|0x5b	|[
|92	|0x5c	|\
|93	|0x5d	|]
|94	|0x5e	|^
|95	|0x5f	|_
|96	|0x60	|`
|97	|0x61	|a
|98	|0x62	|b
|99	|0x63	|c
|100	|0x64	|d
|101	|0x65	|e
|102	|0x66	|f
|103	|0x67	|g
|104	|0x68	|h
|105	|0x69	|i
|106	|0x6a	|j
|107	|0x6b	|k
|108	|0x6c	|l
|109	|0x6d	|m
|110	|0x6e	|n
|111	|0x6f	|o
|112	|0x70	|p
|113	|0x71	|q
|114	|0x72	|r
|115	|0x73	|s
|116	|0x74	|t
|117	|0x75	|u
|118	|0x76	|v
|119	|0x77	|w
|120	|0x78	|x
|121	|0x79	|y
|122	|0x7a	|z
|123	|0x7b	|{
|124	|0x7c	|
|125	|0x7d	|}
|126	|0x7e	|~
|127	|0x7f	|DEL（削除）


###### ⚠️0x7cは、 |
docker-composeを用いたローカルJenkins環境構築方法 メモ

* マスター/スレーブ構成のJenkinsをローカル環境にdocker-composeで構築する手順をメモする。

## Jenkins 構成

* マスターノードとスレーブノードの2コンテナで構成する。

  * マスターノード ： Jenkinsがインストールされたコンテナ

  * スレーブノード：マスターに操作されるコンテナ

    ※ビルド/実行環境などを分けたいときに利用する。



## 前提条件

* docker/docker-composeはインストール済みであること。
* 以下の構成のフォルダで作業する。

```
jenkins ____ jenkins_home		 # マウント場所。docker-compose up実行時に生成される。
		 L__ docker-compose.yml
		 L__ Dockerfile_SLAVE　	# スレーブ用Dockerfile		 
```



## 作成手順

### 1. マスターコンテナ作成

* docker-compose.ymlを用意する。※後でスレーブ用設定を追加する。

  ```yaml
  version: "3"
  services:
    jenkins_master:
      container_name: jenkins_master
      image: jenkins/jenkins:latest
      ports:
        - 18080:8080
      volumes:
        - ./jenkins_home:/var/jenkins_home
  ```

* マスターコンテナを起動する。

  * docker-compose.ymlを配置しているフォルダ内で以下のコマンドを実行する。

  ```
  docker-compose up -d
  ```

* マスターコンテナに入る。

  ```shell
  docker exec -it <コンテナID> /bin/bash
  ```

* 管理者パスワードを取得する。

  ```shell
  cat /var/jenkins_home/secrets/initialAdminPassword
  ```

* SSH認証キーを作成する。

  ```shell
  ssh-keygen -t rsa -C ""
  ```

  * `jenkins_home/.ssh/` に`id_rsa`(秘密鍵)、`id_rsa.pub`(公開鍵)が生成される。

* マスターコンテナを停止する。

  ```shell
  exit
  docker-compose stop
  ```

### 2. スレーブコンテナ作成

* スレーブコンテナ用Dockerfileを作成し、`docker-compose.yml`と同一フォルダに配置する。

  ```dockerfile
  FROM jenkinsci/ssh-slave
  RUN ln -s /usr/local/openjdk-8/bin/java /usr/local/bin/java
  ```

  ※Java のパスを通す。

* `docker-compose.yml`を修正する。

  * スレーブコンテナ用サービス設定を追加する。※以下は最終的な`docker-compose.yml`

  ```yaml
  version: "3"
  services:
    jenkins_master:
      container_name: jenkins_master
      image: jenkins/jenkins:latest
      ports:
        - 18080:8080
      volumes:
        - ./jenkins_home:/var/lib/jenkins_home
      links:
        - jenkins_slave01
  
    jenkins_slave01:
      container_name: jenkins_slave01
      build:
        context: .
        dockerfile: Dockerfile_SLAVE
      environment:
        - JENKINS_SLAVE_SSH_PUBKEY= #前述のid_rsa.pubの値を指定する。
  
  ```

### 3. 起動

* コンテナ起動

  ```shell
  docker-compose up -d
  ```

* 起動確認

  ```shell
  docker-compose ps
       Name                    Command               State                 Ports
  ---------------------------------------------------------------------------------------------
  jenkins_master    /sbin/tini -- /usr/local/b ...   Up      50000/tcp, 0.0.0.0:18080->8080/tcp
  jenkins_slave01   setup-sshd                       Up      22/tcp
  ```

  * URL:<http://localhost:18080/>にアクセスする。

  * 新規ノード追加などの設定を行う。

    ※「[SSH] No Known Hosts file was found at /var/lib/jenkins/.ssh/known_hosts. Please ensure one is created at this path and that Jenkins can read it. Key exchange was not finished, connection is closed.」のようなエラーが出て、上手くスレーブと接続できなかったが、ノード->スレーブ->起動方法の「Host Key Verification Strategy」を「Manually trusted key Verification Strategy」に変更することで接続できた。

## 参考情報

* [いちから始める Docker - 複数のコンテナを使う](https://yoo-s.com/topic/detail/807)
* [docker-composeを使って開発環境でJenkinsを動かせるようにした時のトラシュー](https://qiita.com/yagaodekawasu/items/c2c4b29febd21a489f17)
* [AWS環境で、Jenkins-slaveを追加する](https://qiita.com/mtomoaki_96kg/items/71d9acbbd68fc093ac89)
VS Code 1.54 の新機能 - 特殊キー2連打のショートカットキー登録が可能に

https://code.visualstudio.com/updates/v1_54#_modifier-only-keybindings

`Shift`, `Alt`, `win`, `cmd`などの特殊キーの２回連打をショートカットキーとして登録できるようになった。

ただし通常のショートカットキー設定画面からはまだ設定ができず、`keybindings.json`ファイルで定義する必要がある。

例えば`Shift`キー２連打の場合は以下のように`Key`値を指定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181011/e5b17294-ff2b-fa3f-3d2e-0f67167911a4.png)

なお、３連打以降は対応しておらず、３つ以上書いても２連打として扱われる。

新たにショートカットキーを定義しようとするとすぐ既存のものとバッティングしてしまうし、特殊キー２連打は押しやすいのでなかなか良い改善。あとは通常のショートカットキー設定画面から設定できるようになれば◎。
Google Dataportalで積み上げグラフを作る方法

# はじめに
この記事では，ダッシュボード作成・データ視覚化サービスの[Google Dataportal](https://datastudio.google.com/)で，積み上げグラフを作成する方法について説明します．

以下の2つの場合で作り方が異なってきます．

- 縦持ちデータの場合
- 横持ちデータの場合

# 方法1：横持ちデータの場合
以下の様な，横持ちデータを積み上げグラフにしたいとします．

| Date | Col1 | Col2 | Col3 | Col4 |
|:-:|:-:|:-:|:-:|:-:|
|1/1|  2000 |  1000 | 3000  | 4000  |
|1/2|  1500 | 3000  | 2500  | 3300  |
|1/3| 4000  |  2000 |  1200 | 1300  |
|1/4| 4600  |  1400 | 1000  |  1000 |

## 1. データポータルに取り込み
普通にデータリソースから取り込みます．

すると表の形で取り込まれます．
![スクリーンショット 2021-03-06 16.28.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/5398063a-a1f2-9adb-d929-9b7c4f42e936.png)

## 2. グラフを棒グラフに変更
右のバーから，グラフを棒グラフに変更します．
![スクリーンショット 2021-03-06 16.30.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/0c62d272-fdfb-9268-41ee-e18382478106.png)

## 3. ディメンションと指標を設定
ディメンションとは「グラフを表示する単位」，指標とは「グラフに現したい値」のことです．今回は，１日ごとの値を見たいので，ディメンションをDate，指標をCol1，Col2，Col3，Col4とします．また，時間通りの順番に並べたいので，並び替えをDateの昇順とします．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/e0a3c0d0-1a54-eef6-9ea9-f4e5ffe56d82.png)

これによって，日付順で毎日の値が棒グラフでみられるようになります．
![スクリーンショット 2021-03-06 16.35.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/54310499-8ecd-23e6-1cac-004f754835d0.png)

## 4. 積み上げグラフにする
スタイルから積み上げグラフのチェックを入れます．
![スクリーンショット 2021-03-06 16.36.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/eaa39892-2da2-38af-b253-9c53a41f4c6f.png)

そのままきれいな積み上げグラフになります．
![スクリーンショット 2021-03-06 16.37.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/6b6483d8-a6be-d3fd-cb27-2df62a2c0e82.png)

# 方法2. 縦持ちデータの場合
以下の様な，縦持ちデータを積み上げグラフにしたいとします．

|  Date | Type  |  Value |
|:-:|:-:|:-:|
|1/1	|Col1	|2000|
|1/1|	Col2|	1000|
|1/1|	Col3|	3000|
|1/1|	Col4|	4000|
|1/2|	Col1|	1500|
|1/2|	Col2|	3000|
|1/2|	Col3|	2500|
|1/2|	Col4|	3300|
|1/3|	Col1|	4000|
|1/3|	Col2|	2000|
|1/3|	Col3|	1200|
|1/3|	Col4|	1300|
|1/4|	Col1|	4600|
|1/4|	Col2|	1400|
|1/4|	Col3|	1000|
|1/4|	Col4|	1000|

## 1. データ・リソースを取り込み
データリソースから追加します．

## 2. グラフを追加
とりあえず積み上げグラフを選択．
![スクリーンショット 2021-03-06 16.43.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/1ab990f1-cbab-faf5-bad0-10f390848bc8.png)

## 3. ディメンションと内訳，指標を設定
今回は内訳があります．
ディメンションをDate，内訳をType，指標をValueにします．並び順はDateで昇順にします．
![スクリーンショット 2021-03-06 16.46.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/7c12bddc-ce72-def1-9d1f-cc7c37e41aa5.png)

するとグラフができます
![スクリーンショット 2021-03-06 16.46.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178565/a9c42242-4352-44a3-61bd-9f3bb15c9963.png)


# まとめ
横持ちグラフの場合は並列に，縦持ちグラフの場合は内訳に列を設定することで積み上げグラフの表示が可能となります．自分は潰しがきく点で，縦持ちグラフがおすすめです．
【Workato】便利なformulaの使い方やデータ操作一覧【随時更新】

#Workatoにおけるデータ操作
Workatoではformulaモードを使うことでExcelの関数のような感覚でデータの前処理や変換が可能である。
もし、さらに複雑なデータ変換や処理をしたい場合、「Ruby」コネクターや「JavaScript」コネクターが用意されているので、レシピの中にコードを埋め込むことも可能だ。（滅多に使うことはない。が、オプションとして存在するがために痒い所に手が届く。）
この記事では便利なformulaやその活用方法、Rubyのサンプルコードなどをまとめている。（随時更新）

##リストから特定の要素だけ抜き出したい
```ruby
[ARRAY].where("condition": "value")
```
例えば[Senses](https://product-senses.mazrica.com/)や[SmartHR](https://smarthr.jp/)のAPIはカスタムフィールドはリストに入って返ってくる。その中から特定のカスタムフィールドだけ参照したことがあるだろう。
そういうときはこういったformulaを使う。

```ruby
[案件詳細項目].where(name: "プロジェクト終了予定日")[0]['value']
```

![スクリーンショット 2021-03-06 16.00.30（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/947273/92193283-0632-7ae9-4bf9-891fe3c25646.png)

ちなみに、階層構造のオブジェクトで`.where()`を使いたい場合

```ruby
.where("parentkey.childkey": "condition")
```





##入れ子になったリストから特定の要素だけを取り出す
```ruby
[ARRAY].pluck(column_name)
```
Workdayから取れてくるデータのように、複雑に入れ子になっているデータの処理には`.pluck()`が便利。

```ruby
[
  {
    "name": "Jake"
  },
  {
    "name": "Kate"
  }
].pluck("name")

#["Jake", "Kate"]
```

```ruby
[
  {
    "Custom_ID_Data": {
      "ID": "0000001",
      "ID_Type_Reference": "00EAUEDI23983"
    }
  },
  {
    "Custom_ID_Data": {
      "ID": "0000002",
      "ID_Type_Reference": "00VIEIO495310"
    }
  }
].pluck(["Custom_ID_Data", "ID"], ["Custom_ID_Data", "ID_Type_Reference"])

#[["0000001","00EAUEDI23983"],["0000002","00VIEIO495310"]]
```





##String型のデータをリスト型のデータに変換
例えば`,`区切りの文字列をバラしてリストにしたい、といったときに使えるrubyアクション。

```ruby:string_to_list.rb
string = input['string_to_transform'] #string
output_list = [] #array

string.split(",").each do |item| #push each item in string to array
  output_list << {alphabets: item}
end

{output_list: output_list} #return array
```

[サンプルのコミュニティレシピ](https://app.workato.com/recipes/1253065?st=a68551)





##ランダムな文字列（パスワード等）を生成
```ruby:generate_random_password.rb
password = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + ['~','!','@','#','$','%','^','&','*','(',')','-','+']).sort_by{rand}.first(8).join

{password: password}
```

[サンプルのコミュニティレシピ](https://app.workato.com/recipes/1255249?st=5e4138)





##Shift_JISにエンコーディングするときに、対応できない文字を「?」に置き換える
```ruby
[DATA_PILL].encode("Shift_JIS", { :invalid => :replace, :undef => :replace, :replace => "?" })
```





##現在時刻を任意のフォーマットで取得
```ruby
now.in_time_zone("Asia/Tokyo").strftime("%Y/%m/%d %H:%M")
```





##全角文字、半角文字の抽出
```ruby
"ゼンカクﾊﾝｶｸ".scan(/[^ -~｡-ﾟ]/).join
```

```ruby
"ゼンカクﾊﾝｶｸ".scan(/[ -~｡-ﾟ]/).join
```





##数値に3桁区切りでカンマを挿入
```ruby
10000.to_s(:delimited) #10,000
```





##nullの可能性があるデータピルに対してformulaを使用する
```ruby
10000.to_s(:delimited) #10,000
```





##formula内でLookup Tableを参照
```ruby
lookup('JIS X 0401都道府県コード', 都府県名: "群馬県")["コード"]

#10
```
下図のように`Lookup entry`アクションを使用してエントリをLookupするのと同じ動作。（この際取得できるエントリの「コード」列を参照）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/947273/92397662-8ef1-d1f5-6288-dcdb42fd855e.png)
SwiftUI 枠内どこでも反応、Long Pressも反応するボタンを作成する

# やりたい事

![](https://kumonosu.cloudsquare.jp/wordpress/wp-content/uploads/2021/03/alltapbutton04.png)

①枠内どこでも反応
②Tap：Tap用のアクション
③Long Press：Long Press用のアクション

# 1stアクション

## コード

```swift
VStack(spacing: 16.0) {
    Button(action: {
        print("Button Action!!")
    }, label: {
        Text("Button")
            .frame(width: 200, height: 100, alignment: .center)
            .overlay(RoundedRectangle(cornerRadius: 16.0).stroke())
    })
    .onLongPressGesture {
        print("Button Action Long!!")
    }
    Text("Text Button")
        .frame(width: 200, height: 100, alignment: .center)
        .overlay(RoundedRectangle(cornerRadius: 16.0).stroke())
        .onTapGesture {
            print("Text Action!!")
        }
        .onLongPressGesture {
            print("Text Action Long!!")
        }
        .foregroundColor(.blue)
}
.padding(32.0)
.background(Color(.systemGray6))
```

## 結果

![](https://kumonosu.cloudsquare.jp/wordpress/wp-content/uploads/2021/03/alltapbutton05.png)

やりたい事全てを叶える事は出来ない。
ButtonはLong Pressを反応させられない。
Textは枠内どこでも反応させられない。


# 現時点の解決策

## コード

```swift
VStack(spacing: 16.0) {
    Text("Text2 Button")
        .frame(width: 200, height: 100, alignment: .center)
        .overlay(RoundedRectangle(cornerRadius: 16.0).stroke())
        .overlay(RoundedRectangle(cornerRadius: 16.0).foregroundColor(Color.red.opacity(0.0000001)))
        .onTapGesture {
            print("Text2 Action!!")
        }
        .onLongPressGesture {
            print("Text2 Action Long!!")
        }
        .foregroundColor(.blue)
}
.padding(32.0)
.background(Color(.systemGray6))
```

## 見た目

![](https://kumonosu.cloudsquare.jp/wordpress/wp-content/uploads/2021/03/alltapbutton03.png)

# 試行は続く
・タップとロングプレスをさせるUIデザインがどうなのか？
・他に方法があるのではないか。
Node.jsのnpmモジュールを使ってHTML, CSS, JavaScriptを軽量化・難読化する手順

#はじめに

Windows環境で、Node.jsのnpmモジュールを使って以下を行う手順をまとめます。

- HTML, CSSの軽量化(minify)
- JavaScriptの難読化(uglify)

#使用モジュール

- [html-minifier](https://www.npmjs.com/package/html-minifier) → HTMLファイルの軽量化モジュール
- [clean-css-cli](https://www.npmjs.com/package/clean-css-cli) → CSSファイルの軽量化モジュール
- [uglify-es](https://www.npmjs.com/package/uglify-es) → JavaScriptファイルの難読化モジュール

#準備：モジュールのインストール

1. Node.jsを取得しインストールする。→ https://nodejs.org/ja/

2. Node.js command promptを起動する。

3. 以下のコマンドを実行する。（2行目のプロキシ設定は必要な場合のみ実行）

```
$ npm -g config set registry http://registry.npmjs.org/
$ npm -g config set proxy http://xxx.xxx.xxx:8080
$ npm install -g html-minifier
$ npm install -g clean-css-cli
$ npm install -g uglify-es
```
#使用方法

Node.js command promptから、以下のコマンドを実行する。

##HTMLの軽量化

```
$ html-minifier --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype original.html -o original.min.html
```

##CSSの軽量化

```
$ cleancss -o original.min.css original.css
```

##JavaScriptの難読化

```
$ uglifyjs original.js -c --compress --mangle --output original.min.js
```

#参考記事

- [【備忘録】HTMLMinifierの全オプションについて調査した](https://qiita.com/ryo_hisano/items/9d41cd447a69943f8eb1)
- [UglifyJSでコードの削減](https://qiita.com/sasaplus1/items/66f69e51b510c3a19638)
ファイルにコンポーネントが散らばった

覚書です。

ディレクトリで整理するほどでもないけど、細かく仕分けたら一つのファイルに大量のコンポーネントが散乱してしまったときの対処法です。画面に表示されるコードが少なくなります。
IDEやテキストエディタなどに付属している`コード領域の展開/折り畳み`の機能がないとあまり効果を発揮できません。

```tsx
import React from 'react'
import styled from '@emotion/styled'

const Hoge = {
  Wrapper: <div>...</div>,
  P: styled.p`
    ...;
  `,
}

const HogePage: React.VFC = () => (
  <Hoge.Wrapper>
    <Hoge.P>hoge</Hoge.P>\
  </Hoge.Wrapper>
)
```

これでHogeオブジェクトでコードの折り畳み機能を使うと一行にまとまってくれるので画面がスッキリします。
ランディングページ等で活躍します。
Salesforce承認プロセスの注意点～承認ステップが２つ以上ある場合の落とし穴～

Salesforceの承認プロセスで分かりにくいことがあったのでここに残します。

<b>初認プロセス基本情報

まずは取引先の承認プロセスで下記のような「承認プロセスA」を作成します。
![承認プロセス０３０６１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/654aa84f-ef38-6f3d-170d-a763ea33cd02.png)

詳細は見てわかると思いますが
・最初の承認ステップは取引先名が「株式会社A」か否か判断。「株式会社A」でない場合無条件で承認
というルールです。
では、「株式会社A」ではない名称（株式会社X）で承認申請を出しましょう！

結果は「株式会社X」の場合、「株式会社A」ではないので即承認されました。
![承認プロセス成功1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/664a1b9f-baa7-45ff-c42a-7981d98c60f8.png)

さて、ここからが問題です。今度は下記のような「承認プロセスB」を作成します。
![承認プロセス０３０６２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/0e624aaa-fdfc-f11e-2868-85f653b840e4.png)

先ほどの「承認プロセスA」とよく似ています。
詳細としては
1最初の承認ステップは取引先名が「株式会社A」か否か判断。「株式会社A」でない場合次の承認ステップへ進む
2次の承認ステップは取引先名が「株式会社B」か否か判断。「株式会社B」でない場合承認済みとなる
3.最後の承認ステップは従業員数が「111」か否か判断。

2番目の承認ステップ詳細はこちらです。
![承認プロセス２詳細.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/ee12bf3f-bbb5-5709-bf92-2ec61e8f6602.png)
ちゃんと「それ以外の場合」「レコードを承認」となっています。

さあ、では早速検証しましょう。
今回は先ほどと同じように取引先名は「株式会社X」で承認申請を行います。
私の当初の予想としては
1最初の承認ステップは取引先名が「株式会社A」か否か判断。「株式会社A」でないので次の承認ステップへ進む
2次の承認ステップは取引先名が「株式会社B」か否か判断。「株式会社B」でないので承認済みとなる
です。
しかし実際は、承認と同時に却下となりました。

なぜだ。

エビデンスはなかったのですが、どうやら承認プロセスは下記の裏ルール（？）があるようです。

<b>
・最初の承認ステップが、「それ以外の場合、次のステップ」に設定されている場合
・誰からの承認がないまま２番目以降の承認ステップで「それ以外の場合」「レコードを承認」で設定されている場合
・自動的に却下となる

です。

皆様承認プロセス作成の際はこの裏ルール（？）にご注意ください！
1年間でpython収益化してみた

今日からpythonの勉強を始める
目標としてはこの1年で自分で案件を獲得し収益を生み出すこと

多くのサイトを閲覧しこの1年の大まかな計画を立てる
その中でこのサイトの手順が最も有効だと考えた

[【初心者必見】プログラミング未経験から3年間のpython学習ロードマップ](https://www.virtual-surfer.com/entry/learn-python-for-beginner)

基本的にこの手順に乗っ取って頑張ってみようと思う
【Swift】Realmでproblem 'Index  is out of bounds (must be less than 1)とエラーが出たときの対処法

RealmでTableViewにデータを表示しようとした時、タイトルのエラーが起きたので対応方法を記します。
このエラーはRealmのデータ更新時、Realmに保存されているモデルの件数と表示されているTableViewの件数(TableViewの認識している件数が以前のままで)の整合性がとれなくエラーになるようです。

    var participants: Results<Participant>?

    // cellにデータを表示
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: CELL_ID) as! AttendanceTableViewCell
        cell.delegate = self
        cell.index = indexPath
        cell.textLabel?.text = participants?[save:indexPath.row].name
     }

     // Resultsを拡張
    extension Results {
    subscript (save index: Int) -> Element? {
        if index < self.count {
            return self[index]
        } else {
            return nil
        }
    }
}
[Xcode]エラー "this class is not key value coding-compliant for the key"の対処

Xcode初学者でよく起こるエラーとのことで、自分もはまってしまったので備忘録です。

##エラーが起きる原因
・ @IBOutletや@IBActionをコードから消したが、StoryBoardから削除していない
・ クラスを同じ名前で作り直したが、以前設定したStoryBoardのTriggered Seguesを削除していない

##対処
StoryBoard側も削除して再ビルド


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1018670/38019f43-b82d-caa5-f7e9-354fea412f52.png)
ベイズの定理の基礎

# はじめに
大学の課題で，ベイズの定理の基礎を学んだのでメモしました．

# ベイズの定理

**定義式**

```math
P(Y|X) = \frac{P(Y)P(X|Y)}{P(X)}\\

\Bigr( P(X|Y)：事後確率、P(Y|X)：尤度、P(X)：事前確率 \Bigr)
```

* $P(Y)$: 事象Xが起きる前の事象Yが起きる確率（事前確率）
* $P(Y|X)$: 事象Xが起こった条件の下で事象Yが起きる確率（事後確率）

事象Xを「原因」、事象Yを「結果」と見れば、「原因Xが起きた時に結果Yが起こる確率$P(Y|X)$」を用いて、「結果Yが起きた時に原因Xであった確率$P(X|Y)$」を求めるというのがベイズの定理である。

すなわち、$P(Y|X)$という原因→結果という順方向の確率から、$P(X|Y)$という結果→原因という逆方向の確率を求めていることに等しい。

実際、ベイズの定理は、因果関係が分からないものにも適用することができる。

# ベイズの定理の導出
まず、条件付き確率の定義より、$P(Y|X)$は

```math
P(Y|X) = \frac{P(X\cap Y)}{P(X)}
```
上式の両辺にP(X)をかけて

```math
P(X\cap Y) = P(Y|X)P(X)
```
また、$P(X|Y)$も条件確率の定義より

```math
P(X|Y) = \frac{P(X\cap Y)}{P(Y)}
```

よって、

```math
P(X|Y) = \frac{P(Y|X)P(X)}{P(Y)}
```
となり、ベイズの定理は導出される。


# まとめ
ベイズの定理の基礎について学びました．ベイズの定理は，迷惑メールを自動的に発見・分類してくれるフィルタリング機能などに応用されているようですね．
NEM Symbol bootstrap のバージョンアップ

1.0.3 → 1.0.4 へのバージョンアップ時のメモです。

https-portal の停止/開始も含んでいます。

最新バージョンの確認

GitHUb nemtech / symbol-bootstrap
https://github.com/nemtech/symbol-bootstrap/releases



```
https-portalの停止
$ cd ~/https-portal/
$ docker-compose down

symbol-bootstrapの停止
$ cd ~/symbol-bootstrap/
$ symbol-bootstrap stop

rootユーザーにスイッチ
$ sudo su -

symbol-bootstrapのアンインストール
# symbol-bootstrap -v
# npm uninstall symbol-bootstrap

npmの最新化
# npm -v
# npm install -g npm@latest
# npm -v

symbol-bootstrapのインストール
# npm install -g symbol-bootstrap@1.0.4
# symbol-bootstrap -v
# exit

自身の設定ファイル内容を念のため確認
$ view my-preset.yml
----
今回の起動
  テストネットのみ新たなチェーンになるので今回はリセットします（これまでの大量のデータを破棄）
  $ symbol-bootstrap config -p testnet -a dual -c my-preset.yml --reset
  リセットしたのでスタート
  $ symbol-bootstrap start -d
---
通常の起動
  $ symbol-bootstrap config -p testnet -a dual -c my-preset.yml --upgrade    # テストネットの場合
  $ symbol-bootstrap compose --upgrade
  $ symbol-bootstrap run -d
----
$ symbol-bootstrap healthCheck

https-portalの起動
$ docker ps
$ cd ~/https-portal/
$ view docker-compose.yml
$ docker-compose up -d
$ docker ps
```

フォロー推奨
https://tanuson.slack.com/
STM32F103C8でHID Bootloader 2.2 (USBブートローダー)


1.ブートローダのダウンロード
https://github.com/Serasidis/STM32_HID_Bootloader/releases

STM32 HID Bootloader 2.2.2
stm32_binaries.zipをダウンロード

2.展開とファイル
stm32_binaries→F103→low_and_medium_density→hid_generic_pc13.bin
hid_generic_pc13.binをダウンロードディレクトリーにコピー

3.何らかの方法で書き込み 例ST-LINKを使う
接続、hid_generic_pc13.binファイルの読み込み、書き込み、切断

4.USBの接続、デバイスとプリンターでSTM32F HID Bootloaderが見える

5.Arduino→ツール→Upload method:→HID Bootloader 2.2

6.コンパイル実行

7.おわり

X BOOT1=0(実行) BOOT1=1(USBブートローダー)
AI素人のポンコツエンジニアがG検定対策に合格した件について（G検定対策）【前編】

#はじめに
　昨年（2020年）、日本ディープラーニング協会（以下JDLA）が運営するG検定に合格致しました。（下記の写真が合格した年度）

![general20203_regular.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/a55ccfa7-817f-f1e1-2f4b-90059b1280f9.jpeg)

当初は、AIに関しては「何となく」のイメージしか持っておらず、実際に「AIとは何なのか？」という漠然としたイメージしか持っていませんでした。そのため、AIに関しての現実的な認識を正確に把握していきたいと思い今回受験し、その結果無事に合格致しました。この記事では、私が実際にどのようにしてG検定を合格したのか、【前編】、【中編】、【後編】の3編に分けて解説していきたいと思います。構成は下記のようにしております。

<ul>
<li>【前編】：AI（機械学習・ディープラーニング）がそもそも何なのか理解したい初級者向け</li>
<li>【中編】：G検定の全容を把握したい中級者向け</li>
<li>【後編】：G検定を本格的に合格したい上級者向け</li>
</ul>

#そもそもG検定とは何なのか
　G検定とは、JDLAが主催する<b>ビジネスレベル（事業レベル）に相当する幅広いAIに関しての知識を証明する認定試験</b>となります。「AIって話題になっているけど具体的にはどのようなもの？」、「機械学習とかディープラーニングって何なのか？」、「私たちの生活・社会にとってAIは何の関係性・背景があるのか？」といったAIに関する歴史・技術・背景・法律・社会などを幅広いAI周りの知識の理解を目標としており、現在多数の主要IT企業も注目している認定試験でもあります。ちなみに、G検定の「G」はジェネラリスト（generalist）の頭文字から取ってきております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/f12e92d1-cbb9-9cae-1590-c2448e04e6c4.png)


#本題
　今回は、【前編】という訳で導入に関する対策方法を話していきたいと思います。ここでは、AI（機械学習・ディープラーニング）がそもそも何なのか関する『感覚的』な理解を中心とした対策方法を話していきます。

　AIに関する理解を深めるには様々なアプローチ方法が存在します。（機械学習の本を読む、python・SQLなどの実践書を活用する、SF小説を読んでイメージを掴むなど）しかし、G検定においては余りにも荒唐無稽な小説などを読むと考え方が抽象的になってしまいますし、かと言ってゴリゴリの技術書を読むと具体的になりすぎて概念や構想に関する捉え方の理解にたじろいでしまう可能性が出て来ます。そのため、ここに対する対策は<b>「抽象的な概念を強襲しつつ、かつ具体的事例に対し適度の距離感を保っているもの」</b>を主体とした書籍を中心に読んでいくといいです。

　おすすめの書籍としては、こちらの書籍が代表格としておすすめです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/615f2153-2ac1-6289-85eb-a3f2632bab76.png)

　こちらの「人工知能は人間を超えるか――ディープラーニングの先にあるもの」は、東京大学教授松尾豊先生が執筆した書籍です。（ちなみに、表紙の女性は劇場アニメ「イヴの時間」に登場する女性AIのサミィちゃんです😃）こちらの書籍はAIに関する入門書籍として最適で、難しい専門用語などを極力排除（もしくは丁寧に解説）しているため中学生・高校生からでも読める書籍となっております。
　まず、序章の部分で現代のAI技術と社会の関係性を考察しAIに対する認識を具体的事象として落とし込みます。その後、AIに関する概念的な（抽象的な）定義化を行い、歴史背景を絡めつつ実際の機械学習（ディープラーニング）がどのようなものであるかについて丁寧で分かりやすい解説をしていきます。そして、最後に今後の私達の未来とAIの関わりについてを1つの問いかけとして説いているため、技術書（ビジネス書）以外の価値がある書籍でもあると個人的には強く意識しております。
　
　ちなみに、著者である松尾豊先生はJDLAの理事も務めているので、こちらの書籍はG検定に対する指針・目的も理解する一助にもなるものでもあると個人的に強く認識しております。

また、個人的としてはこちらの書籍も補足知識を理解する上でおすすめです。こちらの「2045年問題」というのもAIをテーマに取り扱っている書籍で、より深いAIに関する『感覚的』な理解を促すものとなっております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681742/c0107742-be05-e855-ed83-3a0a0dc91d30.png)


#終わりに
　今回、AIに関する『感覚的』な理解に関しての対策方法を語っていきました。次回の【中編】ではこの理解を元に、G検定に関する概要を主体とした対策方法を話していきたいと思います。また、余談ですが今回のG検定の経験を元に「G検定対策辞典」というサイトを開設いたしました。

https://www.gsite.tech

こちらはG検定に頻出の用語を掲載している辞書サイトです。良かったらぜひご活用してみて下さい。それではまた。
FTPサーバーのファイルをチェックするツールを作ってみた

FTPサーバー上に設計書などを置いていると、設計書が更新されたことに気づかないことがしばしばありました。
なんとかチェックできないかな～、と思い、せっかくなので自分でツールを作ってみました。

使い方はGitHubのreadmeに書いてあるので、そちらを参照してもらって・・・

https://github.com/landwarrior/FTPCheck

ダウンロードはこちらから。
https://github.com/landwarrior/FTPCheck/releases

# 所感など

久々にC#を書いたのですが、そもそもWPFでのアプリ開発が初めてだったので調べながらやりました。
最初はPythonでサクッとコンソールアプリを作り、それをC#のコンソールアプリで書き直し、その後WPFに乗せる、という手順を踏みました。
コンソールアプリでもいいかな、と思っていたのですが、せっかくならGUIにしたいな、ということで、WPFに。
はじめはUWPにしようかとも思ったのですが、ストアアプリとして配信しないといけなさそうだったので断念。
そこまでする必要ないかな、ということでWPFにしました。

まー自己満のために作成し、せっかくなので会社のチームメンバーにも利用してもらってます。

設計がイケてないとか考慮不足があるとかあると思うのですが、そこまできっちりしてなくてもいいかな、ということでそのままになっています。
Linuxには対応してないと思うので、修正コミットをしてくれる方、お待ちしております 笑
【Salesforce】プラットフォームイベントの登録

[前回](https://qiita.com/311052/items/3ab92383fa27e1ac8caa)はプラットフォームイベントの公開方法について述べましたので、今回は受けとり側の処理について、使い方を整理したいと思います。

# プラットフォームイベント登録
プラットフォームイベントが登録された際、以下の方法からイベントを起動させることが可能です。

* [プロセス](#プロセス)
* [フロー](#フロー)
* [トリガ](#トリガ)

今回はこちらのテストイベントを使用します。
![スクリーンショット 2021-02-11 17.41.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/e4413589-c75c-0b22-186c-7ed5cd10f793.png)

テストイベントに定義されている項目は以下の通りです。
| 項目名 | データ型 | 内容 |
| :-- | :-- | :-- |
| エラーあり | チェックボックス | trueの場合エラーあり |
| フローID | テキスト | フローからイベントを公開した場合、発行元のフローIDを格納する |
| メッセージ  | ロングテキストエリア | エラーメッセージを格納する |
| レコードID | テキスト | 処理対象となるレコードID |

## プロセス
プロセスビルダーからプロセス作成時、プロセスを開始するタイミングで「プラットフォームイベントを受信したとき」を選択。
![スクリーンショット 2021-02-11 17.30.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/4745018b-8d2b-a60c-0468-fb811a6a3b57.png)

トリガを追加から定義したプラットフォームイベントを指定します。
それと同時に処理対象となるオブジェクトを指定します。

レコードの抽出には、テストイベントに記載されているレコードIDを使用して、対象のレコード（ここでは商談としています）を取り出します。
受信したプラットフォームイベントと処理対象となるオブジェクトはセットで扱う必要があるため、**プラットフォームイベントに対象のレコードを特定できる項目**を入れておきましょう。
![スクリーンショット 2021-02-11 17.31.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/b195528d-d7e3-bdad-a78a-316a054aeaaf.png)

## フロー
フローでプラットフォームイベントを受信するには、フロー作成の際に「プラットフォームイベントトリガフロー」を選択します。
![スクリーンショット 2021-02-11 18.11.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/d5237a43-3bf2-a3e5-a886-8b13c850a84b.png)

開始ノードでのプラットフォームイベントにテストイベントを指定します。
![スクリーンショット 2021-02-11 18.13.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/95e514fd-0c76-fc14-9a77-2f58d63c5ae7.png)

開始の段階で、条件を指定することはできないので、テストイベントを受信したときにエラーの有無に関わらず無条件にフローが起動します。

開始ノードで受信したプラットフォームイベントが「$Record」変数に入っているため、あとは従来のフロー通り、割り当てや判定に使います。
![スクリーンショット 2021-02-11 18.18.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/633073b6-861d-30d2-fc83-e42b4d3344d0.png)

## トリガ
プラットフォームイベント受信のタイミングでトリガを起動させることもできます。
トリガはオブジェクト名を指定する箇所（onの後）にプラットフォームイベントのAPI名（__eで終わるもの）を指定してあげればOKです。

```Java
trigger TestEventTrigger on TestEvent__e (after insert) {
    // ここに処理を記入
}
```
[UnrealEngine初級]アウトプットログを見やすくする

#概要
アウトプットログに出力される情報が多すぎて使いづらい。そんな時に欲しい情報だけ表示する方法です。
#本文
![スクリーンショット (1913).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/0856fe85-b85c-bfa7-db7c-cb9407a0c14e.png)

ブループリントでPrint stringを使うと、アウトプットログに「LogBlueprintUserMessages: \[～\](ログメッセージ)」の様に表示されます。なのでフィルタ欄にUserMessagesと入力しておけば欲しい情報だけを確認できるようになります。
元に戻したい時はフィルタ欄のUserMessagesを消すだけでOKです。
![スクリーンショット (1911).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/b2db4e14-b2b5-e23f-9cfe-0758f72e9d2d.png)
#おまけ
アウトプットログは枠内で右クリック > ログをクリアで履歴を消せます。
![スクリーンショット (1912).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/617265/1882fc6c-59a7-6ac1-3c27-c70f60b3db8f.png)
【Salesforce】プラットフォームイベントの公開

[前回]()はプラットフォームイベントの基礎情報と定義の仕方について紹介しました。
今回はプラットフォームイベントの登録の仕方についての記載となります。

# プラットフォームイベントの公開
プラットフォームイベントそれぞれ以下の手順から登録が可能です。
ほぼほぼオブジェクトレコードと同じやり方になります。

## プロセス
アクションでレコードを作成から公開が可能です。
従来のオブジェクトレコードの作成と同じやり方でOKです。
![スクリーンショット 2021-01-30 18.29.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/a1ccdd55-af64-2d6c-7e7b-cf49801a6257.png)


## フロー
こちらも従来のオブジェクトと同様の手順で、「レコードの作成」ノードから登録が可能です。
![スクリーンショット 2021-01-24 17.02.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/44a037a3-aa61-2ede-1d3c-ffd9efba9ae6.png)

## Apex
Apexからプラットフォームイベントを登録する場合はちょっと異なります。
Insertではなく、EventBus.publishメソッドを使用してプラットフォームイベントを公開します。

```
TestEvent__e pe = new TestEvent__e(
    RecordId__c = recordId,
    HasError__c = true,
    Message__c = 'エラーが発生しました'
);
Database.SaveResult sr = EventBus.publish(pe);
```

## REST API
プラットフォームイベントはREST API経由からでも登録できます。
外部システムからSalesforce側にイベントを通知するときはこのREST APIが主に使われるのではないかと思います。

こちらもオブジェクトレコードを登録する手順と同じです。
従来のオブジェクト名を入れるところで、プラットフォームイベントのAPI名(__eで終わるもの)を入れておけばOKです。

```
/services/data/v49.0/sobjects/TestEvent__e
```

POSTのリクエストボディにも項目と設定値をセットしてあげればOK。

```
{
   "RecordId__c" : "xxxxxxxxxxxxxxxxxx",
   "HasError__c" : false,
   "Message__c" : "Error",
   ・・・
}
```

次回はプラットフォームを受信する側の動作について定義していきたいと思います。
【Salesforce】プラットフォームイベントの定義

#プラットフォームイベントとは
Salesforceにおけるプラットフォームイベントは、イベントを起こしてイベント駆動型プログラミングモデルを使用してプロセスを自動化することができます。
もっと具体的にいうと、イベント公開のタイミングでトリガやプロセスなどを起動させる仕組みのことですね。
イベントを起こして何かを実行させるという点ではトリガに近い動作ができますが、大量件数を裁くことができ効率的に実行することができるのが特徴です。
#カスタムオブジェクトとの相違点
使い慣れているカスタムオブジェクトとプラットフォームイベントについて異なる点を簡単にまとめました。

* API名が「__e」で終わる
* 公開動作が指定できる
* レコードに保存期間がある（72時間）
* SOQLで取得ができない
* レコードやビューの表示ができない
* イベントの管理（一時停止、再開）ができる

以上の特徴から、以下のケースの場合にプラットフォームイベントを活用すべきところでしょうか。

* データ量を圧迫させたくない
* エラー時を含めたイベント処理を実施したい場合
* 外部システムとの連携

#プラットフォームの定義
[設定]→[プラットフォームイベント]から登録します。
![スクリーンショット 2021-01-30 17.57.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/c1ae578f-0087-1c37-1c33-8bc077b57d97.png)

カスタムオブジェクトを作成する感覚で、ラベル名、オブジェクト名を設定します。
公開動作の設定は以下の2つのいずれかを選択します。
        
* コミット後に公開:
**トランザクションが正常終了した時**にイベントメッセージが公開されます。
従来のオブジェクトレコードと同じような動作かな。

* すぐに公開:
**トランザクションの成功有無**に関わらずイベントメッセージを公開します。

プラットフォームイベント作成後は従来のカスタムオブジェクトと同様にカスタム項目を作成していきます。
作成可能なカスタム項目のデータ型はカスタムオブジェクトとは異なり、以下のものに制限されています。
いわゆるプリミティブ型と言われているものですね。

* テキスト
* ロングテキストエリア
* 数値
* 日付
* 日付/時間

![スクリーンショット 2021-01-24 16.41.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699607/28ece2a2-0419-4d3c-0e8a-bd608be2192c.png)
ここで定義する項目は**イベントを公開した時にどんな情報が欲しいか**を定義するためのもので、イベント受信側はその情報をもとに適切なイベント処理を行うことになります。

プラットフォームイベントの定義ができたところで、次回はプラットフォームイベントを公開する方法について記載していきたいと思います。
【Java】Apache Tikaでファイルの内容からMIMEタイプを推測する

# 動作環境
Java openjdk 11.0.7
Spring boot 2.4.2
Gradle 6.5

# 実装方法

### 依存関係
デフォルトではTikaを読み込めないので、依存関係に入れます。最新バージョンは[こちら](https://tika.apache.org/)から確認してください。

```build.gradle
dependencies{
  implementation 'org.apache.tika:tika-parsers:1.25'
}
```

### MIMEタイプを読み取るコード
今回はMultipartFileのインスタンスから中身をバイト配列として取り出し、そのバイト配列からMIMEタイプを判断しようと思います。以下のコードでは自作のgetMimeTypeメソッドとして定義していますが、メソッドとして定義する必要は（当然ですが）ありません。

```Java

private String getMimeType(MultipartFile multipartFile) throws IOException {
  Tika tika = new Tika();
  // getBytes()はMultipartFileのインスタンスの中身をバイト配列として取り出すというメソッド
  // getBytes()はIOExceptionを起こす可能性があるため、getMimeTypeメソッドにthrows IOExceptionを付けている
  // 以下3行は「return tika.detect(multipartFile.getBytes());」と1行で書くこともできる
  byte[] multipartFileContent = multipartFile.getBytes();
  // detect(byte[] prefix)メソッドで引数の中身からMIMEタイプを判断する
  String mimeType = tika.detect(multipartFileContent);
  return mimeType;
}
```
detectメソッドはバイト配列、Fileのインスタンス、文字列など[いろいろなもの](https://tika.apache.org/0.10/api/org/apache/tika/Tika.html#detect(byte[]))を入れて判断することができます。その場に応じて一番入れやすいものを入れましょう。
プレイングマネージャが記事投稿を半年やってみた振り返り

## 記事投稿のススメ

毎週土曜日にQiitaに記事投稿をすることにしてそろそろ半年になりますので、一回振り返りをしてみようと思います。

正直PVはボロカスですが、書いててよかったなと思うことも多いです。
記事書きたいけど面倒くさい、ネタがないという方のご参考になれば幸いです。


## 黎明期

記事を書いて view数や LGTMを集めてフォロワーいっぱいのtwitter有名人ぐらいになれたらいいなと不純な動機で書き始めました。

1記事では難しいだろうけど、 **「定期的に更新していればそのうちなんとかなるだろ戦略」** で、クオリティはさておき続けることに重点を起きました。どんな本を読んでも続けるのは大事と書いてあり、大概の人は続かないので続けさえすれば勝てると思い込むことにしました。

1記事書くのにも相当な時間がかかるので、出来上がった記事には愛着も期待もありました。投稿後は view 数が増えてないかとページのリロードをしまくって自分で view数 を稼いでしまう様な状態となりました。
その後、不正にview数を稼ぐのはよくないと思い、プロフィール→Googleアナリティクス設定を行い、動きもしないリアルタイムレポートとにらめっこする日々が続きました。

渾身の記事を書いて view数が伸びず挫折するのはあるあるかと思いますが、フリーのアプリを作りまくって95%ぐらいが鳴かず飛ばずという経験をしていたので、そこまで打ちひしがれる事もなくとりあえず継続することができました。

## 過渡期

大した計画もなく始めたのでネタのストックはあっという間に枯渇し、土曜日が近づく毎に恐怖を感じていました。

- やばいネタがない
- 毎日更新にしなくて本当によかった

やはり続けるコツは、無理のないスケジュールにすることと、全く無計画にしないことだなと思いつつも、ネタ不足は続きます。

この頃にある気づきがありました。

**「クオリティはさておきと言ったものの、新しいネタを仕入れないと書くことがない」**

わざわざ太字にするまでもない当たり前のことを言ってますが、これは割と重要な気づきでした。
「勉強しなきゃなー」と思いつつ明確な目的がないから勉強をしないというケースは多々あると思います。

**勉強をする明確な目的ができた** 重要な瞬間でした。

view 数を稼ぎたくて、view 数の高い記事をウォッチするようになったのは大きな収穫です。定常的に情報を仕入れるようなったのです。
とは言え自分にできることにも限界があるので、興味がありつつ短い時間で理解できそうな技術を探して勉強して、土曜日にまとめて記事にする、というスタイルに移行しました。

- できなかったことができた
- 知らなかったことを知れた

この頃には view数に対する興味は薄れて、割とシンプルな喜びをモチベーションに投稿をするようになりました。
また、一人でも二人でも自分の記事を書いて役に立ったと思ってくれた人がいれば充分幸せかなと思うようになりました。

## 成長期

そして数ヶ月が過ぎた頃、次に上げる副次的な効果が得られるようになったと感じます。

- 字を書くのが速くなった
- 理解をまとめるのが速くなった
- 伝えたいことを整理するのが速くなった

日本人なんだから日本語は普通に扱えているつもりでしたが、全然そんな事はありませんでした。
整理してシンプルに伝える能力を身につける、その能力を維持する、には反復練習が欠かせないと痛感しました。
格闘ゲームやfpsゲームと同じです。努力して強くなっても、やり続けていないとすぐ弱くなります。

記事を書く時に「めんどくせー」と感じるのは、 **「記事を書くのに充分な能力を持っていなくて試行錯誤で解決すべき点が自分で制御できない程度に存在している」** からではないかと思います。
なので、継続し反復練習を行う事で基本的な能力が上がれば、制御出来る点も増えて記事を書くことに対する抵抗感は下がっていくはずと思うようになりました。
実際は気のせいかもしれませんが、 **成長しているっぽい実感** が湧いてくると続けるための大きなモチベーションになります。

文章を書くのが速くなれば、記事を執筆する時間を確保するのがそれだけ容易になります。
毎週新しい技術を研究できるのは理想的だけど、充分な時間が取れない時はポエムを書く。
そんな感じでスケジューリングもできるようになってきました。はい。今週は忙しいです。

## おわりに

「物事を整理してまとめて伝える、または、プログラム等別の成果物としてアウトプットする。」
記事投稿はほとんどの業務で役に立つ基礎的な能力を身につけることができる活動だと思います。

ぜひやってみてくださいとオススメすることで、自分も続けないとなというモチベーションにしてまとめといたします。

最後まで読んでくださってありがとうございました。よろしければLGTM頂けますと大変励みになります。
【Laravel】一覧表示画面でDBのデータ有無で表示を切り替える方法（「◯◯はありません」と表示しよう）

## 概要

よくあるコンテンツ共有サービスの一覧画面で

|DBにデータが|動作・表示|
|:--:|:--:|
|ある|DBのデータを一覧表示|
|ない|「データはありません」というメッセージを表示する|

こんなよくある機能を実装する方法をちょっと詳しくまとめます。

## 環境

```
$ composer -V
Composer version 1.10.20 2021-01-27 15:41:06

$ php artisan --version
Laravel Framework 6.20.16
```

## 一覧表示画面でDBのデータ有無で表示を切り替える方法

手順はざっくりこんな感じ

- ルーティング設定
- Controller
- Viewで切り替えを実装（←ここがメイン）

※DBからのデータ取得はシンプルなものにするのでModelではなくControllerで処理することにします。

### ルーティング設定

```php:routes/web.php
Route::get('/', 'ArticleController@index')->name('index');
```

`resource`メソッドで定義しても問題ないです。

### Controller

記事テーブル（articles）に対応する`Article`モデルを使用してORMを使ってDBからデータを取得するケースを想定。

```php:app/Http/Controllers/ArticleController.php
    /**
     * 記事一覧画面表示
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $articles = Article::all();
        return view('articles.index', compact('articles'));
    }
```

以下の項目などは本記事では省略してシンプルに全件取得のみにしています。

- `->with()`でN+1問題対策
- `->orderBy()`メソッドでソート
- `->paginate()`でページネーション

### Viewで切り替えを実装（←ここがメイン）

今回ControllerでDBからデータを取得する処理は以下のコードで実装しています。

```php
$articles = Article::all();
```

この`$articles`を`ddd()`でデバッグしてみます。

![スクリーンショット 2021-03-06 10.57.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/512695/97e2f9ba-3b03-4794-4100-636dea29ea15.png)

データの型は`"Illuminate\Database\Eloquent\Collection"`クラスのオブジェクトです。
（`all()`を使うと`Collection`になります）

`ddd()`についてはこちらの記事で解説しています。
[【Laravel6.x〜】デバッグするならdd()？いやいや、ddd()を使おう！！](https://qiita.com/shimotaroo/items/b453b09a7d8ec3583b31)

`Collection`でデータの有無を判定する方法は主に以下の3つです。

|コード例|データがある|データがない|
|:--:|:--:|:--:|
|$article->isEmpty()|false|true|
|$articles->count()|true（1以上）|false（0）|
|$empty(articles->all())|false|true|

例として、`->isEmpty()`を使って以下のように書けます。

```php:resources/views/articles/index.blade.php
@if (!$articles->isEmpty())
    {{-- 記事データがDBにある場合の表示内容 --}}
@else
    {{-- 記事データがDBにない場合の表示内容 --}}
@endif
```

このように書くことによって

・データがある場合：データを一覧表示
・データがない場合：「データはありません」というメッセージを表示

することができます。

##注意点

`Collection`の場合、文字列の時みたいに以下の書き方をするとうまく条件分岐できないのでご注意ください。

```php:resources/views/articles/index.blade.php
{{-- これだとうまく条件分岐できない --}}
@if (!$articles)
    {{-- 記事データがDBにある場合の表示内容 --}}
@else
    {{-- 記事データがDBにない場合の表示内容 --}}
@endif
```

## まとめ

- Collectionというクラスがあるのを理解しておくべし
- 公式ドキュメントの日本語訳（ReaDouble）にメソッドがたんまり書いてあるので見ておくべし（最後に参考に載せてます）


## 参考

- [Laravel 6.x コレクション-利用可能なメソッド](https://readouble.com/laravel/6.x/ja/collections.html#available-methods)
- [ララジャパン-
正しいのは、isEmptyでした](https://www.larajapan.com/2019/03/02/isempty%E3%81%A7%E3%81%97%E3%81%9F/)
フロントサイトからCMSの編集画面に飛ぶブックマークレットを作ったら反響良かった話

# はじめに
こんにちは。母親が誕生日なので、[花キューピット](https://www.i879.com)で珍しく花送ってみた筆者です。
あれすごいですね、当日配送可能という**ほとばしる情熱**:+1: 皆さんもぜひ！

さて、自社インバウンドメディアの運営を行っているのですが、編集者の方々が、CMSで記事を執筆してくださっているのですが、そのなかで**低コストのしょうもないブックマークレット**を作ったのですが、結構喜ばれたので、他にもこれで幸せになる人いるかもと、本記事を執筆しております。

参考になれば幸いです。

# 背景
編集者の方々は、CMSとメディアサイトの往来を行う頻度が多いです。
その往来には、2パターン存在してます。

1. **CMSの記事編集ページ → メディアサイトの記事ページ**
2. **メディアサイトの記事ページ → CMSの記事編集ページ**

1については、記事のプレビューページの導線や公開済みの記事ページの導線がCMS上に表示されているため、スムーズに遷移可能です。

ただ、2については、記事タイトルや記事IDをコピーして、CMSを開いて記事検索して記事編集が画面にたどり着くという、地味にめんどくさい作業が発生してました。
(よくあるdebug用のheaderバー等も表示されていればいいんですがね... :thinking:)

また、弊社の場合、多言語のため、探すのも少し一苦労なのです...:sob:

# よしブックマークレットでも作るか
そんなわけで、上記背景の2を1と同じワンクリックで遷移できるブックマークレットを作成しました。

実際のコードは公開できませんが、イメージこんな感じです。
記事ページ: `http://example.com/1`でブックマークをクリックすると、CMSの記事編集ページ: `http://cms.example.com/edit/1` に別タブで表示させます。

```js
javascript: (() => {
  const url_article = 'http://example.com/1'
  const url_cms_base = 'http://cms.example.com/edit/'
  const article_id = url_article.pathname.split`/`[1]
  window.open(`${url_cms_base}${article_id}`, "blank")
})();
```

# おわりに
そもそもURL構成とかわかっていたので、自身が背景2のケースをわざわざ記事検索してたどり着くようなフローを取っていなかったですが、それでもこういったものがあるとポチるだけで飛べるのでとてもいいなと思いました。

書くコード量も少ないのに、結構喜びの声をいただきました:smile:

それでは！