OmniAICreator/Qiita-1.07M huggingface dataset:
個人ブログのスパム対策に関して（Rails）

## 概要
先日、Railsで開発した個人ブログを公開しました。
- [Niken log](https://nikenlog.com/)
- [サービス概要](https://nikenlog.com/blogs/16)

その公開に伴いGoogleのサーチコンソールに登録したは良いものの、問い合わせフォームに、RichardcenceさんやGeorgewetさんなど知らない外国人から「登録したら〇〇ドルもらえる！」というスパムが大量に届いたため、その対策として行ったことを簡単にまとめます。

![スクリーンショット 2021-11-19 14.57.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425582/6b198bfc-f1cd-8099-7a1c-7647633ca775.png)

## 1. URLのバリデーション
早急にbot等でのスパムメールを送れないようにするため、まず初めに問い合わせフォームの本文にURLのバリデーションを設定しました。

```model.rb

## URLの正規表現を生成して定数へ
  VARID_URL_REGEX = /\A#{URI::DEFAULT_PARSER.make_regexp(%w(http https))}\z/

## 上記の正規表現が含まれていたらNG
  validates :message, presence: true,
                      format: { without: VARID_URL_REGEX }

```

[参考サイト1](https://blog.furu07yu.com/entry/ruby-check-regex-url)
[参考サイト2](https://runebook.dev/ja/docs/ruby/uri/rfc2396_parser)

このバリデーションだけで恐らく大半のスパムbotは送れなくなると思います。（自身のサイトで企業案件などを募集している方はURLが入力できなくなるのでご注意ください。）

## 2. googleのreCAPTCHA
加えて自分の場合は、botからの送信対策として、googleのreCAPTCHAを導入しました。

※reCAPTCHAとは、ユーザー登録等で、信号とかバスとか選択させられたり、自分がロボットか否か確認させられたりするやつです。参考：[WHAT IS RECAPTCHA?](https://www.google.com/recaptcha/about/)

実装は[pikawakaさん](https://pikawaka.com/rails/recaptcha)のサイトを参考に行いました。
今回の実装の注意点として、

- シークレットキーとサイトキーの発行

自分のサイトの場合、ユーザーからの問い合わせを円滑にするため、v2非表示（サイトの右下に利用規約が表示されるタイプです）を利用しました。その際、サイトキーとシークレットキーが発行されますが、非表示とチェックボックスを切り替える際にキーを発行し直す必要があります。

- 環境変数の設定

上記で発行した各キーを読み込むために、.envファイルもしくはcredentialへの記載が必要です。
自分はcredentialを用いて、config/initializers下に以下のコードを記載しました。
※設定の詳細は割愛しますが、開発/本番環境で用いるcredentials.ymlも編集しています。

```recaptcha.rb

Recaptcha.configure do |config|
  config.site_key = Rails.application.credentials.recaptcha[:site_key]
  config.secret_key = Rails.application.credentials.recaptcha[:secret_key]
end

```

- submitボタンをreCAPTCHAの非表示用のタグに変更

非表示のreCAPTCHAを用いる場合は、通常のform_withなどで用いるsubmitボタンのタグをinvisible_recaptcha_tagsに変更する必要があります。

参考：[recapthca gemのREADME](https://github.com/ambethia/recaptcha#invisible_recaptcha_tags)

```sample.html.erb

 <%= invisible_recaptcha_tags({ text: "送信", class: "btn btn-success w-25" }) %>

```

以上を行うと、フォームの送信時にbotかどうか、確認してくれるようになります。

![スクリーンショット 2021-11-29 23.55.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425582/249e9d0e-5baa-b515-8640-624fd663c17c.png)

## まとめ
上記を行ったことで、1日最大で300件近く届いていたスパムメールが**0**になりました！
（サイト自体の訪問者も少ないので、問い合わせ自体が0になりました…）

スパムで困っている方の少しでも力になれれば幸いです。
また、編集リクエストなどあれば、気軽にコメント/リクエストください。

ここまでお読みいただきありがとうございました。

## 完全な宣伝です
以下の個人ブログを運営しています。
- [Niken Log](https://nikenlog.com/)
- [サイト/運営者に関して](https://nikenlog.com/about)

サイトに関しての意見や共通の趣味がある方からの連絡、その他諸々大歓迎です。（スパムはご遠慮ください笑）
ぜひ気軽にサイトまでお越しください。
久しぶりのVBA（キーワード検索しヒットした行のセルの値をマージ）

# はじめに
久しぶりにVBAでプログラミングをしてみました。
まだ、レビュー＆テストは不十分です・・・

# 仕様
検索キーワードを列挙したファイルからマクロを実行。
指定した検索対象ファイルから検索キーワードに部分一致するセルを検索。
検索でヒットした行から指定した2つの列の値をマージし、検索キーワードを列挙したファイルに出力。

## イメージ
###検索キーワードを列挙したファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243842/ebff6056-2433-9f1e-69f8-634d286582f4.png)

###検索対象ファイル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243842/d8357297-a843-9716-3e9d-6e8b255ebd7f.png)

###実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243842/d651c6fa-59a7-87b9-b568-68a0905dd933.png)

#コード
```
Const TARGET_FILE_NAME As String = "ファイルパスを指定"
Const TARGET_SHEET_NAME As String = "シート名を指定"
Const START_ROW As Long = 3
Const KEY_COL As Long = 1
Const OUTPUT_COL As Long = 2
Const SAERCH_KEY_RANGE As String = "C:C"
Const MERGE_DATA_COL_1 As Long = 1
Const MERGE_DATA_COL_2 As Long = 2


Public Sub CelSerchAndMerge()

    Dim thisWS As Worksheet
    Set thisWS = ThisWorkbook.ActiveSheet
    
    Application.ScreenUpdating = False
    Dim beforeCalculation As XlCalculation
    beforeCalculation = Application.Calculation
    Application.Calculation = xlCalculationManual
    
    Dim targetWB As Workbook
    Set targetWB = Workbooks.Open(TARGET_FILE_NAME, ReadOnly:=True)
    Dim targeWS As Worksheet
    Set targeWS = targetWB.Sheets(TARGET_SHEET_NAME)
        
    Dim tgt As Range  ' 検索するセル範囲
    Dim rng As Range  ' 見つかったRange
    Dim adr As String  ' 最初に見つかったRangeのAddress
    Dim mergeString As String
    
    Dim row As Long
    row = START_ROW
    Do While (thisWS.Cells(row, KEY_COL) <> "")
        
        Set tgt = targeWS.Range(SAERCH_KEY_RANGE)
        Set rng = tgt.Find(What:=thisWS.Cells(row, KEY_COL), LookAt:=xlPart, LookIn:=xlValues)
            
        If rng Is Nothing Then
        Else
            adr = rng.Address
            mergeString = targeWS.Cells(rng.row, MERGE_DATA_COL_1) & vbCrLf & targeWS.Cells(rng.row, MERGE_DATA_COL_2)
            
            Do
                Set rng = tgt.FindNext(After:=rng)
                If rng.Address = adr Then
                    Exit Do
                Else
                    mergeString = mergeString & vbCrLf & targeWS.Cells(rng.row, MERGE_DATA_COL_1) & vbCrLf & targeWS.Cells(rng.row, MERGE_DATA_COL_2)
                End If
            Loop
            thisWS.Cells(row, OUTPUT_COL) = mergeString
        End If
        
        row = row + 1
    Loop
    
    targetWB.Close
    
    Application.ScreenUpdating = True
    Application.Calculation = beforeCalculation

End Sub
```

#参考記事
## Findメソッド
https://www.relief.jp/docs/excel-vba-range-findnext-specific-area.html

https://valmore.work/find-cell-by-find/

https://excel-ubara.com/excelvba4/EXCEL225.html

## 文字列操作
https://www.officepro.jp/excelvba/basic/index7.html

https://www.tipsfound.com/vba/04001
property_exists()でstatic|selfを使う

##はじめに
静的クラス（関数）で自身のクラスのプロパティが存在するか調べたい、という願いを叶える記事です。

##解決
普通に書くとこうなります。

```php:ダメな例
public static function existsFoo() {
    return property_exists(static, 'foo');
}
```

しかし、この状態だとこんなエラーが出ます。

>syntax error, unexpected token ",", expecting ":"

もう答えは書いてありますが、さっぱりわからない、という方もいると思います。

まずは、正解をご覧ください。

```php:正解例
public static function existsFoo() {
    return property_exists(static::class, 'foo');
}
```

`static`に`::class`を付け加えました。

>::classとは
> class キーワードでもクラス名の解決を行うことが出来ます。 クラスの名前が ClassName になっているクラスの完全修飾名を取得するには、 ClassName::class を使います。

要するに、クラスの名前解決をしてエラーを取り除きますよーという優れものです。

また、`property_exists()`についても少しみてみます。

```php
function property_exists($object_or_class, string $property): bool { }
@param object|string $object_or_class
The class name or an object of the class to test for

@param string $property — The name of the property

@return bool
```

第一引数の`$object_or_class`の型に注目です。`object|string`とありますね。今回のケースでは`string`型になっています。

##終わりに
この`static::class`は色々なところで使われます。もし躓くことがあれば、また思い出してみてください。
場面の変更

場面の変更を行うときにおしゃれな演出を入れるプロジェクトを見つけたので、リミックスして紹介します。
ミソは、画面全体を丸く切り抜かれたスプライトで覆い、その大きさを徐々に変えていくことにあります。

サンプルプロジェクト
https://scratch.mit.edu/projects/608561023

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/608561023_480x320.png)
インタラクティブシェルとログインシェル

https://qiita.com/ikkyu193/items/5c9a87b22fdf7697422e

※調査することになった理由
umaskでなんで、_bashrcが実行されないのかわからなかった。
原因判明：bashrcがログインシェルの場合、はじいている。。。
shopt -q login_shell
だからif文処理に入らないんだ。。多分。
※.bash_profileは実行されているように見えるのに。
※.bash_profileには、.bashrcがあれば実行するという記載があるのに。。。

ソースコードを追いかけているがさっぱりわかんない。

どうもインタラクティブシェルとログインシェルという概念があるみたい。

まずは手元の環境から整理します。

SSH接続の結果
ログインシェル　かつ　インタラクティブシェル

```
shopt login_shell
login_shell     on
```

```
echo $-
himBH
```


GUI接続の結果
ノンログインシェル　かつ　インタラクティブシェル

```
shopt login_shell
login_shell     off
```

```
echo $-
himBH
```

仮説だが、ログインシェルの場合、.bashrcはなぜか実行されない。。。
原因不明。

GUIのノンログインシェルの場合は実行されているのを確認。
ログインシェル→bashコマンドでノンログインモードに変更しても.bashrcが実行されることは確認しました。
コメントでStylelintを無効にする方法

## 再度有効化するまでエラーを無効化

``stylelint-disable``と書くと、Stylelintを無効にできる。``stylelint-enable``で再度有効にするまで、Stylelintのエラーは無視される。

また、``stylelint-disable``や``stylelint-enable``のあとにカンマ区切りでルールの名称を指定すると、そのルールだけを有効化/無効化できる。

```css
/* stylelint-disable */

.hoge {} /* この行のエラーは無視される */

.foo {} /* この行のエラーも無視される */

/* stylelint-enable */
```

```css
/* stylelint-disable rule-1, rule-2 */

.hoge {} /* この行のrule-1とrule-2に関するエラーは無視される */

.foo {} /* この行のrule-1とrule-2に関するエラーも無視される */

/* stylelint-enable rule-1, rule-2*/
```

## 特定の行のエラーを無効化

``stylelint-disable-line``と書くと、その行のみStylelintを無効にできる。

また、``stylelint-disable-line``のあとにカンマ区切りでルールの名称を指定すると、そのルールだけを無効にできる。

```css
/* ``.hoge``のエラーは無視されるが、
 * ``background: red !important;``の行のエラーや``.foo``のエラーは無視されない
 */

.hoge { /* stylelint-disable-line */
    background: red !important;
}

.foo {}
```

```css
/* .hogeのrule-1に関するエラーを無効化する */

.hoge {} /* stylelint-disable-line rule-1 */
```

## 次の行のエラーを無効化

``stylelint-disable-next-line``と書くと、そのコメントの次の行のみStylelintを無効にできる。

また、``stylelint-disable-next-line``のあとにカンマ区切りでルールの名称を指定すると、そのルールだけを無効にできる。

```css
/* ``background: red !important;``の行のエラーは無視される
 * 他の行のエラーは無視されない
 */

.hoge {
    /* stylelint-disable-next-line */
    background: red !important;
}
```

```css
/* ``background: red !important;``の行のrule-1に関するエラーは無視される
 * 他の行のエラーは無視されない
 */

.hoge {
    /* stylelint-disable-next-line rule-1 */
    background: red !important;
}
```

## ファイルごと無効化

ファイル丸ごとエラーを無効にしたい場合は、``.stylelintignore``ファイルを作成し、無効にしたいファイルのパスを指定する。

``.stylelintignore``ファイルの書式は``.gitignore``と同じ。

## 参考

- [Ignoring code | Stylelint](https://stylelint.io/user-guide/ignore-code/)
【Swift】PDFViewで前後のページに移動する

SwiftのPDFKitで前後のページに移動する方法。

## PDFKitの導入

設定画面のGeneralの`Frameworks,Libraries, and Embedded Content`のプラスボタンから`PDFKit.framework`を追加。

コードで実装する際は以下の通り。

```swift
let pdfView = PDFView()

pdfView.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height)
pdfView.autoScales = true
pdfView.displayMode = .singlePage
pdfView.displayDirection = .horizontal
pdfView.displaysPageBreaks = true
pdfView.usePageViewController(true)
```
各プロパティの詳細は以下をご覧ください。

https://developer.apple.com/documentation/pdfkit/pdfview

## 前後のページに移動

PDFViewで前後のページに移動する際は以下の処理。

```swift
//前のページに戻る
pdfView.goToPreviousPage(self)
//後のページに進む
pdfView.goToNextPage(self)
```

## 参考
https://qiita.com/taketomato/items/8102a80cd4ce516523de
https://dev.classmethod.jp/articles/ios-11-pdfkit/

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html
JIGを使ってリファクタリングする

この記事は　[ZOZO #3 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/zozo) 1日目の記事になります。


今年もそんな季節になりました。今年は14本エントリーしております。何卒よろしくです。

1日目にご紹介したいのは[JIG](https://github.com/dddjava/jig)というツールになります。

設計の支援ツールです。
一般的に設計といえば、実装前に行うもの。設計し、実装した後というのは、概して修正などしないことが多いと思います。

しかし、アプリケーションにとって本当に大事なのは実装後のリファクタリングだというのは、一定層にはもう周知の事実。

この点については、[テスト駆動開発](https://www.amazon.co.jp/dp/B077D2L69C)の付録C「テストは質をあげないー質を上げるのはプログラミング」を読んでいただくとよいと思います。

で、どのようなリファクタリングをするかという点について。

細かいバリューオブジェクトのロジックをリファクタリングしていくことや、アプリケーション層やインフラ層に紛れ込んだビジネスロジックをモデルに移行するといったリファクタリングも有効かと思います。

[JIG](https://github.com/dddjava/jig)を使ったリファクタリングで有効なのは、もう少し大きなところ、モデルも構造・構成、モデルの名前の整合性を取っていくという観点でリファクタリングしていくところになります。

[JIG](https://github.com/dddjava/jig)は既存のコードを解析し、様々なドキュメントを出力してくれます。
どのようなドキュメントがあるかは[こちら](https://github.com/dddjava/jig/wiki/JIG%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88)を見ていただくといいかと思います。（実際の画像貼ろうと思いましたが実プロダクトのドキュメント貼るのが難しく・・・

手っ取り早く参考にするなら
・[区分図](https://github.com/dddjava/jig/wiki/%E5%8C%BA%E5%88%86%E5%9B%B3)
・[アーキテクチャ図](https://github.com/dddjava/jig/wiki/%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E5%9B%B3)
なんかは実装中の設計の整理に即役に立つと思います。

また、Excelで出力される[ビジネスルール一覧](https://github.com/dddjava/jig/wiki/%E3%83%93%E3%82%B8%E3%83%8D%E3%82%B9%E3%83%AB%E3%83%BC%E3%83%AB%E4%B8%80%E8%A6%A7)はクラスの一覧が出力されるので名前の再検討にもってこいです。

上記リンク先では、こういう状態であればこうリファクタリングするといいといったアドバイスも記載されていますので、読んでみるといいと思いいます。

導入については、Gradleを使っていれば[Gradleプラグイン](https://github.com/dddjava/jig/tree/main/jig-gradle-plugin)を使うのが便利です。

自分のチームではmainにマージするときにGithubActionsでドキュメントを生成し、生成されたドキュメントをS3にアップロードすることでチームメンバーがいつでも最新のドキュメントを閲覧できるようにしています。

アドベントカレンダー初日はJIGの紹介でした。次の日も自分ですね。「バリデーションだけじゃ足りない時がある。契約による設計に対する考察」というタイトルでお届けいたします。
がじぇるねの中の人に聞いてみた、2021年総括

# はじめに

さぁ、はじめての、かじぇるねGRシリーズのAdvent Calendarが始まるよ！

ということで、1日目の今日は、「がじぇるね」そして「がじぇるねGRシリーズ」をより知ってもらうために、がじぇるねの中の人（O氏）に2021年総括と題して10の質問をぶつけてみました。

スタート！

## Q1. がじぇるねって何ですか？

2012年に発足した「がじぇっとるねさす」というルネサスのプロジェクトです。公式ページに概要が載ってます。

https://www.renesas.com/jp/ja/products/gadget-renesas/about-gr

## Q2. がじぇるねGRシリーズを使ってみて欲しい人はどんな人でしょう？

第一弾となるGR-SAKURAボードで設定したペルソナは女子大生でした。そのときのエピソードは以下のLIGさんのブログに掲載されています。

https://liginc.co.jp/279331

その後はボードごとに設定しています。GR-ADZUKIなどはお子様と親御様、GR-ROSEはROSでロボットやりたい人、とかです。

## Q3. がじぇるねGRシリーズを使った作品で特に印象に残っているものは何でしょう？

数えきれないないですが、敢えて挙げるなら以下です。

https://www.youtube.com/watch?v=TmnzdkGcOwQ


https://www.youtube.com/watch?v=hovr75iSL-M


がじぇリズムは今でこそ有名になってしまった、自作キーボードのお店「遊舎工房」の社長の作品です。超クールな作品ですよね。

がじぇるねじゃんけんはcarcon999さんの作品ですが、2012年当時の私は素人同然だったので画像認識、音声合成、リール制御すべてがすごいと思いました。奥様と作り上げた羊毛フェルトのぐーちょきぱーとか、デザインも素敵でした。

2012年から半年に1回、ルネサスナイトという作品自慢大会をやってきました。ご参考までに計15回の1位～3位の作品タイトルを示します。

![スネサスナイトの歴史](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51272/db79f3f4-e03f-32ea-a9ab-b5fd7cc6d16f.png)


## Q4. 2021年に発売されたがじぇるねGRシリーズはありますか？

ずばりないんです。

ちょっと本尊の中の色々な変更といいますか、流れといいますか、変更がございまして、がじぇるねの取り組みを内部に活かす方に注力しています。

もちろんまたピンクのボードをプロデューサーの皆様と一緒に作りたいと思ってます。


## Q5. ズバリ！今一番おすすめなのはどれ？

んーー、GR-ROSEですかね。

最近ALGYANさんと開催したIoTコンテストでも使いましたが、AWSやAzureと接続できる他に、ロボット向け基板ということで小さく作ったので色々と取り回しが楽だと思います。

https://algyan.connpass.com/event/224849/

初心者の方向けに本もありますし。

- [「GR‐ROSE」ではじめる電子工作](https://www.kohgakusha.co.jp/books/detail/978-4-7775-2084-8)

ROSのバージョンアップにちょっとついていけてなくて申し訳ないですが、以下のtctclabさんの作品とかに使われていると思うと胸熱ですよね。

https://twitter.com/tctclab/status/1404398169933303814

## Q6. コロナはがじぇるねにどういう影響をあたえましたか？

2019年末のルネナイ15で一旦自慢大会を休止したので、あまり影響がなかったのですよね。


## Q7. 半導体不足はがじぇるねにどういう影響があったでしょうか？

んーー、ないですね。新規がじぇるねボードの企画は前述の通り少しお休みしてましたし。


## Q8. ざっくり、がじぇるねにとって2021年はどんな年でしたか？

静かに実った年、そんな感じです。

過去のGRボードが今の商談につながっていたということなのですが、マイコンビジネスって、やっぱり採用されるまでに時間がかかるのですよね。

GRボードのリリースから3年～5年のときを経て今になってルネサスの売り上げになり、本来の目的が静かに達成されたことは、がじぇるねGRのプロデューサの皆様に感謝をお伝えしたい気持ちで一杯です。

## Q9. 2022年に発売予定のものはありますか？

まだ予定はないです。

でもここ最近ルネサスが買収することとなったDialog、Celenoの無線は皆様にお届けしたい要素です。大体において無線は規格化されていますよね？差別化する要素も少ないのですが、以下のページを見てください。50セントとか書いてあるんですよ。

https://www.dialog-semiconductor.com/press-releases/dialog-semiconductors-smartbond-tiny-module-demystifies-iot-development


がじぇるね化計画はまだありませんが、企画アイデアは溢れんばかりです。

## Q10. 最後に2022年のがじぇるねはどうなる？

ここだけの話、教育分野に一石を投じたいと思っています。静かに始まって色々な協力者を巻き込みながら大きくしていけたらと考えています。

それとロボットですね。ルネサスのArmマイコンもmicroROS対応が完了し、ROS2もいよいよ実ビジネスに利用されることが増えてくると思います。

2022年はがじぇるね再燃のきっかけを作る年かなと思います。


## 最後に一言どうぞ

コロナを乗り越え、ものづくりへの思いを馳せ、そしてよい年をお迎えください！
Vanilla JavaScript をずっと書いていたけど、Reactに入門してみた。

# はじめに
お疲れさまです。急に寒い日々が続いていますが、皆様はいかがお過ごしでしょうか？

半年間、業務量が倍になり、なかなか技術本を読む時間が取れなかったです。。

しかし、最近は落ち着いたので、本を読む時間が取れそうです。。！（あとゲームも）

# Reactを勉強することにしました。
素のJavaScript（かろうじて、ES2015の記法を習得）に書き慣れているのですが、
本腰を入れて有名なフレームワーク Reactを勉強してみることにしました。
今回は環境構築を中心に備忘録として投稿します。

* Windows11
* Visual Studio Code
* Node.js

# Reactの開発環境を整える。
1. vscodeを開き、新しいフォルダーを作成します。
1. cmdを起動し、以下のコマンドを入力します。(sampleは任意のフォルダ名になります。）

```
npx react-create-app sample
~~~

1. ローカル環境でReactを起動してみます。

```
cd sample #プロジェクトに移動
npm start #start コマンドを実行する
```
下のように、表示されると、環境構築成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501045/050efc1f-bfe3-ea6c-67eb-ceca49cae80f.png)

# Hello World!を表示してみる。
せっかくなんで、Hello world!をしてみましょう。

現在のフォルダ構成は以下の状態になっていると思いますが、
srcフォルダ内のindex.js以外のファイルを削除してください。

```
sample
├─node_modulues
├─public
└─src
```

index.jsを以下のように変更しましょう

```index.jsx
import React from 'react';
import ReactDOM from 'react-dom';

const App = () => {
  return(
    <>
      <h1>Hello World!</h1>
    </>
  );
};

ReactDOM.render(<App />, document.getElementById('root');
```
下のように表示されましたでしょうか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501045/bdc9248e-c44e-440a-3495-244894250ef3.png)

# 所感
今回は、Reactの環境構築とHello Worldの表示を行いました。
index.jsで少しだけ登場したJSX記法。。最初は、違和感ありましたが、
書いてみるとなかなか、面白いですね。
今回はh1タグ一つだけですが、これを関数コンポーネントを利用して画面の一つ一つを部品として
とらえて、描画していきます。

# 終わりに
1回目の投稿で、Pythonを使った自動翻訳を紹介しました。
（動かないコードを公開する大失態をしでかしてますが。。）
2回目でReactの環境構築を紹介して、何をしてるんだと思います。

。。実は、Pythonの自動翻訳ですが、結構注文が来てます。「このファイル翻訳してください」と。
需要があるなら展開しようと考えたのですが、どうせならGUIで操作できるようにしたいな～と
それなら、フロントエンドをReactで作ってみよう！と現在学習中です。

Webサーバーの環境はないので、デスクトップアプリとして展開するのですが、
Python寄りでEelを使用するか、JavaScript寄りでElectronを使用するか。ですね。

そこまで、急ぎの案件ではなく、業務改善の一環で行っていることですので、
手堅く作るならElectronでしょうか？

EelとElectronも環境構築できる程度は学習しましたので、これらも投稿できればいいかなと
思っています。

長文になりましたが、Reactに入門してみました。
ここまで読んで頂いた方、ありがとうございました。

次の投稿は。。来年かな？
スプライトでスコアを表示する

画面上にスコアを表示しようとしたときに、変数の内容をそのまま出すのは味気ないので、スプライトを使って独自のデザインで表示したいと思う時があります。そんな場合に使えるテクニックです。

1. 数字のスプライトを桁数ごとに作る（３桁なら三つ）
2. スプライトのコスチュームで０から９までの数字を用意する。名前は"Glow-0"のように文字列＋数値にする（数値だけにすると後の処理で問題が発生します）
3. スコアが変わったときにコスチュームを、`文字列＋（（スコア変数 / 10^（桁数-1））の切り下げ）を10で割ったあまり` で求められるものに置き換えます。(10^桁数-1)は１桁目なら１、２桁目なら10になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/eb82b385-3484-3787-0218-ccb4052de2c4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75307/6e01bb5c-4944-596f-3424-82a4c6a5e64b.png)

この式だと、スコア/nのnの値を変えるだけで、どの桁数でも対応できます。スコア用のスプライトをクローンで作るともっとスマートですが、スプライトの位置合わせをプログラムで制御しないといけないので、ちょっとだけデザインで苦労するかもしれません。

サンプルプロジェクト
https://scratch.mit.edu/projects/608515242

![スクリーンショット](https://cdn2.scratch.mit.edu/get_image/project/608515242_480x320.png)
【本紹介】初心者フロントエンドエンジニアがおすすめできる今年読んだ本を紹介（後編）

#はじめに
皆さんこんにちは。

先月に投稿した本紹介後編になります。
後編はよりフロントエンドエンジニアらしい本です。
（駆け出しエンジニアが何いってんだって話ですが。笑）

本業でLaravelも採用しているので、Laravelの本も紹介します。

前編をまだ確認していない方はよろしければどうぞ！

[【本紹介】初心者フロントエンドエンジニアがおすすめできる今年読んだ本を紹介（前編）](https://qiita.com/hiroyuki_0507/items/2d9240c653d49e3f1370)

前編でも紹介しましたが、下記項目で１冊ずつ紹介いたします。

#本の紹介の仕方

###本の名前
######1．書籍紹介（著者、初版発行年月日、金額、ページ数、出版社）
######２．難易度（初級・中級・上級で判断）
######３．簡単な感想

それではいきましょう！

#【６冊目】[JavaScript コードレシピ集](https://amzn.to/3I7bRH0)
######1．書籍紹介
著者：池田 泰延
出版社：技術評論社
初版発行年月日：2019年1月25日
金額：3,278円
ページ数：608p

######２．難易度（初級・中級・上級で判断）
初級

######３．簡単な感想
なんかこんなメソッドなかったっけ？ってよくある疑問を解決してくれる本です。
僕は辞典的な役割で使ってます。
暇なときに眺めてると、へえ〜こんなメソッドあるんか。ってなったりするので勉強になります。

#【７冊目】[改訂新版JavaScript本格入門 ～モダンスタイルによる基礎から現場での応用まで](https://amzn.to/3rhsmKi)
######1．書籍紹介
著者：山田 祥寛
出版社：技術評論社
初版発行年月日：2016/9/30
金額：3,278円
ページ数：456p

######２．難易度（初級・中級・上級で判断）
中級〜上級

######３．簡単な感想
入門というタイトルに騙されないでください！
本当に本格的にフロントエンドに首を突っ込む方にはおすすめです。
非常にわかりやすいが、開発業務じゃないと使わない仕様が多いので、Web制作が業務範囲だとあまり使わないかも。
ES６にしっかり対応しているので、初版は古いですがまだまだいけます。

#【８冊目】[【特典付き】HTML5&CSS3デザイン 現場の新標準ガイド【第2版】 (Compass Booksシリーズ)](https://amzn.to/3rklxYn)
######1．書籍紹介
著者：エビスコム
出版社：マイナビ
初版発行年月日：2020/10/23
金額：3,289円
ページ数：368p

######２．難易度（初級・中級・上級で判断）
初級

######３．簡単な感想
Web制作に関わる方やこれから学んでみたいという方にうってつけの本だと思います。
あくまでもガイドなので、参考書程度に思ってください。
わからない実装はこの本を読めばだいたい解決します。
僕はいつも、HTMLとCSSの仕様の確認に使ってます。

#【９冊目】[これからはじめるVue.js実践入門](https://amzn.to/32weoKf)
######1．書籍紹介
著者：山田 祥寛  (著)
出版社：SB Creative
初版発行年月日：2019/8/22
金額：6,628円
ページ数：468p

######２．難易度（初級・中級・上級で判断）
初級

######３．簡単な感想
なぜか金額が高騰していた名著。
山田さんが作る本にはハズレはないですね。
いわゆるカエル本といわれるシリーズです。
JSにある程度なれている方ならすんなり学べる本です。
説明がとてもわかり易く、ハンズオン形式で進んでいきます。

ルーティングやVuexでのStoreまで網羅しています。
ただ、Vue3は対応できていないのでVueの触り程度に学び、Vue3の学習へ移行するのを個人的にはおすすめします。

#【１０冊目】[動かして学ぶ! Laravel開発入門 (NEXT ONE)](https://amzn.to/3E48luh)
######1．書籍紹介
著者：山崎 大助  (著)
出版社：翔泳社
初版発行年月日：2021/3/15
金額：3300円
ページ数：328p

######２．難易度（初級・中級・上級で判断）
中級

######３．簡単な感想
Laravelの仕様や全体像を把握するには良書です。
ただ後半のハンズオン形式での開発は、開発環境がAWSのCloud９を利用するため初学者には厳しいかなと思いました。
また、想定外のエラーが出てくるので、最初の概要だけ把握したら、他教材で学ぶのをおすすめします。


#【１1冊目】[フロントエンド開発入門 プロフェッショナルな開発ツールと設計・実装](https://amzn.to/3I3Drod)
######1．書籍紹介
著者：安達 稜  (著), 武田 諭  (著)
出版社：秀和システム
初版発行年月日：2020/10/9
金額：3,080円
ページ数：280p

######２．難易度（初級・中級・上級で判断）
中級

######３．簡単な感想
最近読んだ本の中でピカイチに面白いし、わかりやすい。
フロントエンド周辺のツールを網羅的に学べるので、開発業務に携わっているものとしてとても勉強になる本だった。
僕にwebpackを学ぶきっかけをくれた本でもあります。

フロントエンドはHTML/css/JSだけではない。

その他周辺のJSを取り巻くライブラリ群たちをどう使いこなすかで今後の市場価値が変わります。
ぜひ、この本読んでください。

#終わりに。
今年読んだ参考書は計22冊でした。
その中から厳選？して10冊紹介いたしました。

参考書高いですよね。
買って後悔することが多かったので、こちらの記事執筆させていただきました。
少しでも参考になれば幸いです。

それでわ〜
launchWhen〇〇〇は止めてrepeatOnLifecycleを使おう！

# はじめに

皆さんはlaunchWhenCreated, launchWhenStarted, launchWhenResumedを使ってますか？coroutinesでライフサイクルを意識して書く場合、必須とでも言うべきメソッドです。

ですが、Flowでこれらを利用するのは避けたほうが良いです。なぜか？
launchWhen〇〇〇ではFlowが完全には停止せず、リソースが消費される可能性があるからです。

https://developer.android.com/topic/libraries/architecture/coroutines

> Lifecycle が STOPPED の場合、前者の API はコルーチンをキャンセルするのではなく停止するため、アップストリーム フローはバックグラウンドでアクティブのままにされ、新しいアイテムが出力される可能性やリソースが浪費される可能性があります。

## launchWhen〇〇〇は将来的に廃止予定

また、launchWhen〇〇〇は将来的に下記リンクにある通りで`This API will be removed in a future release.` とのこと。

https://developer.android.com/reference/kotlin/androidx/lifecycle/LifecycleCoroutineScope

## 今後はrepeatOnLifecycleを使おう

では何を使うべきか。`androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha01` からrepeatOnLifecycle APIが利用できるようになっており、これを使うように推奨されています。2.4.0は2021/10/27にStableになりました。

書き方は非常に簡単。

- launchWhen〇〇〇でこう書いていたのを...

```kotlin:launchWhenStarted
    override fun onCreate(savedInstanceState: Bundle?) {
        lifecycleScope.launchWhenStarted {
            latestNewsViewModel.uiState.collect { uiState ->
                ...
            }
        }
    }
```

↓ こう書くだけ！

```kotlin:repeatOnLifecycle
    override fun onCreate(savedInstanceState: Bundle?) {
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                latestNewsViewModel.uiState.collect { uiState ->
                    ...
                }
            }
        }
    }
```

上記の例だと、repeatOnLifecycleはLifecycle が STOPPEDの際にJobをキャンセルしてくれて、STARTEDになったら再度Jobをlaunchしてくれるのでリソースの消費を防げます。
実は、他に細かい動作の違いとかあるので書こうと思ったんですが、moriさんのブログがとてもきれいにまとまっていたためこちらにリンク置いときます。非常に勉強になります。
https://at-sushi.work/blog/35/


# 参考

https://at-sushi.work/blog/35/
Sassでの記述方法

# Sassとは
Sassとは、「Syntactically（文法的に） Awesome（イケてる・すごい） StyleSheet（スタイルシート）」の略で、CSSのメタ語です。（プリプロセッサと言われます）
※メタ語とはある言語についてなんらかの記述をするための言語で、特定のルールを加えて具体的な応用を可能にするものです。

要は<b>「CSSを拡張して、文字通りイケてる書き方ができるようにしたもの」</b>ということになります。

規模の大きいサイトを作成していくと、コードが複雑になり、スタイルの管理も難しくなるので、それを管理しやすくするためにSassが作られました。また、作業効率もあがると思います。

SassにはSASS記法とSCSS記法の２種類ありますが、主流はscssなのでこちらで説明していきます。

# 記述方法

<details>
<summary>今回使用する`index.html`</summary>
<div>

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <!-- 変数 -->
    <h1>あいうえお</h1>
    <h2>かきくけこ</h2>
    <h3>さしすせそ</h3>

    <!-- ネスティング -->
    <div id="nest">
      <p id="nestp1">たちつてと</p>
      <p id="nestp2">なにぬねの</p>
      <p id="nestp3">はひふへほ</p>
    <div>

    <!-- ミックスイン -->
    <div class="mixins1">まみむめも</div>
    <div class="mixins2">やゆよ</div>

    <!-- 継承 -->
    <p class="inheritance1">らりるれろ</p>
    <p class="inheritance2">わをん</p>
  </body>
</html>
```
</div>
</details>

### ファイルについて
CSSの場合ファイル名の拡張子は`.css`でしたが、scssの場合、`.scss`となります。

### 文法
基本的に`css`と書き方は同じで、機能（文法）が追加されたと考えて良いです。
よく使う以下４つの文法を説明します。

#### ①変数
変数とは、プログラミング言語における「値を入れておく箱」のこと
https://wa3.i-3-i.info/word1603.html

繰り返し使うような値を変数に格納しておけば、メンテナンス時に変更したい箇所が出て来た時に、少ない作業量で済みます。

```scss
$main-color: red;
h1 {
  color: $main-color;
}
h2 {
  color: $main-color;
}
h3 {
  color: $main-color;
}
```

#### ②ネスティング（nesting）

ネスティング（nesting）とは、入れ子にすること
https://wa3.i-3-i.info/word1284.html

```scss
#nest {
  #nestp1 {
    color: blue;
  }
  #nestp2 {
    color: green;
  }
  #nestp3 {
    color: orange;
  }
}
```

#### ③ミックスイン（mixins）
少し難易度高いですが、知っておくと便利です。

`@mixin`でコードの塊を作成し、別の場所でそれを呼び出すことができます。
以下は「hoge」という「mixin」を作成し、それを「.mixins1」、「.mixins2」で呼び出しています。

```scss
@mixin hoge($color: black, $fSize: 10px) {
  color: $color;
  font-size: $fSize;
}
.mixins1 {
  @include hoge(red, 20px);
}
.mixins2 {
  @include hoge();
}
```

#### ④継承（inheritance）

継承とは、元ネタから要素を受け継いで、元ネタの特徴を備えた新しいのを作ること
https://wa3.i-3-i.info/word1202.html
こちらも難易度高めですが、知っておくと便利です。

`%test-shared`でスタイルを指定し、「.inheritance1」や「.inheritance2」の`@extend %test-shared;`のコードにて`%test-shared`で指定したスタイルを継承しています。

```scss
%test-shared {
  border: 1px solid #ccc;
  padding: 10px;
  color: black;
}
.inheritance1 {
  @extend %test-shared;
}
.inheritance2 {
  @extend %test-shared;
  border-color: red;
}
```


### 使用方法

`scss`ファイルはそのままでは使用できず、`css`ファイルに戻す（コンパイルする）必要があります。
それを自動で実施してくれるツールがあるので紹介します。

Live Sass Compiler
https://marketplace.visualstudio.com/items?itemName=ritwickdey.live-sass

上記をVSCodeでインストールした後、画面下部に`Watch Sass`と表示されるのでそれをクリック。
すると自動で、`scss`ファイルをコンパイルして`css`ファイルに変換してくれます。
`scss`ファイルを編集しても、保存すると同時に`css`ファイルも自動で反映してくれるので便利です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1888749/2357e720-1a09-16ed-d75e-a3eec88d7cfd.png)

## 参考
https://digitalidentity.co.jp/blog/creative/css-sass.html
https://www.fenet.jp/dotnet/column/tool/5245/#SCSSとは何か
https://wa3.i-3-i.info
Python でテキストデータの会話文を1行に成型する

テキストデータを自然言語処理する際に、会話文を抽出したかったが、テキストデータにおいて、1行に'「」'の対が複数あったり、逆に'「」'の対が複数行にまたがって存在していたりしており、成型がめんどうであった。
「」の対が1要素に収まっているリストを返す関数をメモ代わりに記載する。


```python
# テキストファイルのパス
path = 'hogehoge.txt'

# 「」の対が1要素に収まっているリストを返す関数

def preprocessing(path):
    text = []
    with open(path, mode='r', encoding='utf-8') as f:
        for line in f.readlines():
            # text の list の要素に'「', '」'がそれぞれ1つ以下になるよう加工する
            line = line.replace('「','\n「')
            line = line.replace('」','」\n')
            if '\n' in line:
                line = line.split('\n')
                line = [l for l in line if l != '']
            else:
                line = [line]
            text.extend(line)

    # 「」の対が複数要素にまたがっているものを1つの要素に結合する
    document = []
    counter = 0
    stack = []
    for line in text:
        stack.append(line)
        if '「' in line:
            counter += 1
        if '」' in line:
            counter -= 1
        if counter == 0:
            stack = ''.join(stack)
            document.append(stack)
            stack = []
            
    return document
```

おそらくもう少し賢い書き方があるに違いないし、すべての場合に対応可能であるわけでは当然ないけれども、とりあえず目的は達成できたのでよしとする。
ゼロトラスト とは

## 勉強前イメージ

安全なlocal環境なんてない、全部が危ない みたいな考え方だった気もする

## 調査

### ゼロトラスト とは

トラスト(信頼)がゼロ ということで 信頼できないという言葉になり、2010年にForrester Research社が提唱したセキュリティの考え方のことを指します。
信頼しないという考え方から、外部や内部からのアクセスでもセキュリティ的に疑って制御を行います。

今までの考え方は境界型防御で、 `Trust but Verify(信ぜよ、されど確認せよ)` という考え方が主流で
企業であれば社内は安全だけど外部のネットワークは危険だというセキュリティ対策の方法でした。
ゼロトラストは `Verify and Never Trust(決して信頼せず必ず確認せよ)` という考え方で
企業の内部と外部は区別せずにすべて検証しようとします。

- 境界型防御

内部は信頼するが、外部からは信頼しない

![12021-11-29 # ゼロトラスト とは - diagrams.net - Google Chr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/f768d39e-8edb-6cbf-2994-b3dad278f083.png)

- ゼロトラスト

内部も外部も信頼しない

![22021-11-29 # ゼロトラスト とは - diagrams.net - Google Chr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/48ff8732-b0de-b6de-302c-74e501e259c0.png)

### 境界型防御との違い

↑で記載している通り、境界型防御は内部は信頼するということで
一度境界の内部に入ってしまえば、ウイルスなどに侵されていても自由に行動できてしまうので
サイバー攻撃に対して対策ができていなかった。
ゼロトラストでは社内からのアクセスでも安全か確認を行うため、境界型防御の弱点であるサイバー攻撃も防御できます。
また、ゼロトラストにはユーザに応じた最低限の権限しか与えないので、
悪意のあるユーザに侵略されてもリスクを最低限に抑えられる
また、クラウドサービスを利用することで社内の情報を外部に保管することが増えたので機密情報を守ることが難しくなってきた背景があります。

## 勉強後イメージ

大体イメージ合ってた！
内部に入ってしまった侵略者へのリスクも最低限に

## 参考

- [ゼロトラスト](https://www.nri.com/jp/knowledge/glossary/lst/sa/zero_trust)
【TransitVIF】TGW＋DxGWの構成案【未対応でも大丈夫】

# はじめに
本記事では、契約したDirectConnectのデリバリーパートナーがTransitGatewayの仮想プライベートインターフェイス（TransitVIF）に対応していなかったとき、TransitGatewayをどう導入したかをご紹介します。
初心者向けというよりはある程度AWSに知見がある方向けの内容になりますので、基本的な用語説明などは割愛させて頂きます。ご了承ください。

※DirectConnect→以下Dx
※TransitGateway→以下TGW
※仮想プライベートインターフェイス→以下VIF

# 環境説明
わたしがTGWの導入を行なったときの環境はざっくりこんな感じでした。
![移行前.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/10657841-8ce9-27c9-7604-2b9d1adcb25e.png)

- 1つのDxを複数のアカウントで共有
- Direct Connect Gateway（以下DxGW）は使用せず、各アカウント毎にPrivateVIFを作成
- VPC間で通信が必要なところはPeerで対応

このDxのデリバリーパートナーをA社からB社に変更することになり、それを機に全体の構成の見直しを図りました。

最初の移行案がこちらです。
![移行案.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/62ff192c-72c8-9bc9-bfb0-6a09c1f29629.png)


- 1つのDxをDxGWで共有
- DxGWをTransitVIFで承諾
- VPC間の通信はTGWにより可能にする

しかし、作業の1週間前になって、契約先のデリバリーパートナーがまだTransitVIFに対応していないということがわかり、設計からやり直しとなってしまいました。。

# どう回避したか
Dxの契約変更を機に全VPC間で通信が取れるようにしたいとの顧客の要望があったため、TGWの導入を諦める＝Peerをフルメッシュで張る必要がある＝作業量が膨大＝**死** :innocent:
という状況だったため、どうにかTGWが使用できる方法を考えました。

そして編み出した構成がこちらです。
![移行後.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494752/acd89dfe-5691-3a02-9bb2-618c7fe0feb8.png)


- 1つのDxをDxGWで共有
- DxGW所有アカウントでPrivateVIFを承諾
- その他のアカウントではVGWとDxGWを関連付け
- TGW用に用意したVPCにTGWを配置、各アカウントにリソース共有設定をしVPC間の通信を可能にする

つまり、TGWを配置する用のVPCと、DxGWをアタッチする用のVPCを分けました。

TGWをDxの下に配置して関連付ける、ということに固執しなければ意外と簡単な構成で実現できます:clap:

# 注意点
TGWやDxGWなどの利用にはいくつか制限があります。
個人的にその中でも特に注意が必要だと思うのは以下の3つです。

- DxGWに関連付けられるVGW数は最大で10個まで（上限緩和も不可）
- オンプレ・AWS全体でASNの重複はできない
- CIDRの重複も不可

参考：[AWS Direct Connect のクォータ](https://docs.aws.amazon.com/ja_jp/directconnect/latest/UserGuide/limits.html)、[トランジットゲートウェイのクォータ](https://docs.aws.amazon.com/ja_jp/vpc/latest/tgw/transit-gateway-quotas.html)

# さいごに
今回はTransitVIF未対応の場合の、TGW＋DxGWの構成案についてご紹介しました。
詳細に書くときりがないためかなり簡潔にまとめましたが、どなたかの参考になれば幸いです。
最後までお読み頂きありがとうございました！
応用数学

https://qiita.com/arigra/items/4d893b311a37fba7012e

https://qiita.com/arigra/items/47192a810f5cae2256ab

https://qiita.com/arigra/items/76da6942b0ecd3ab0fc7

https://qiita.com/arigra/items/416355b38529348482cf

https://qiita.com/arigra/items/4824aa85068d5fec5007
JSONのデータを種類ごとにリスト表示する(TypeScript+React)

# 作成物
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/792099/cc623be5-9abc-a89c-1f89-d42baff8d461.png)

https://botanic7arc.github.io/ts-react-json-list/

# ソース(index.tsx除く)

## JSON

```json:ingredients.json
{
    "title": "食材",
    "testData": [
        {
            "name": "豚バラ",
            "kinds": "肉"
        },
        {
            "name": "キャベツ",
            "kinds": "野菜"
        },
        {
            "name": "鶏むね",
            "kinds": "肉"
        },
        {
            "name": "牛カルビ",
            "kinds": "肉"
        },
        {
            "name": "ほうれん草",
            "kinds": "野菜"
        },
        {
            "name": "にんじん",
            "kinds": "野菜"
        }
    ]
}
```

## tsx

```tsx:App.tsx
import React from 'react';
import Data from './ingredients.json'
import {makeListDivFromJson} from './makeListDivFromJson'

export const App = () => {
  return (
    <div>
      <h1>{Data.title}</h1>
      <div>{makeListDivFromJson(Data)}</div>
    </div>
  );
}
```

```tsx:makeListDivFromJson.tsx
type JsonData = { testData: { name: string, kinds: string }[] };
interface HtmlList { lh: string; li: string[]; };

export const makeHtmlList = (plh: string, pli: string[]): HtmlList => {
    let list: HtmlList = { lh: plh, li: pli }
    return list;
}

export const makeListDivFromJson = (Data: JsonData): object[] => {
    let outDiv = [];
    let uniKinds = Array.from(new Set(Data.testData.map((x) => x.kinds)));
    let outDivData: HtmlList[] = [];

    for (let i = 0; i < uniKinds.length; i++) {//データ作成
        let matchItem = Data.testData.filter(x => (x.kinds === uniKinds[i])).map(x => x.name);
        outDivData.push(makeHtmlList(uniKinds[i], matchItem));
    }

    for (const element of outDivData) {//HTML作成
        let listData = [];
        outDiv.push(<h2>{element.lh}</h2>);
        listData.push(element.li.map(x => <li>{x}</li>));
        outDiv.push(<ul>{listData}</ul>);
    }

    return outDiv;
}
```

## 解説

importでJSONのデータを読み込み、処理を行う関数に渡す。
Array.fromとSetを使い、重複していない種類の配列を作る。
次にfilterで種類と一致している名前を取り出す。
最後にリストとしてdivに追加する。

## 詰まったところ

&lt;ul&gt;で囲まれていない&lt;li&gt;要素を連結して最終的に出力divに追加するところ。
解決方法として&lt;li&gt;要素を一時的に配列に保持しておき、追加し終えた際に&lt;ul&gt;で囲んで出力divに追加するようにした。

## 参考

- [JavaScriptで重複排除を自分で実装してはいけない（Setを使う） - Qiita](https://qiita.com/netebakari/items/7c1db0b0cea14a3d4419)
「Gitでやらかした!!」でも、大丈夫です

## はじめに
みなさん！プログラムファイルの管理はしっかりできていますか？ 

今回は初心者がついついGitでやらかしがちな3つのケースに焦点を当てて話していきたいと思います。
※ Gitの基本的概念や使い方に関しては別の記事を見てください。

## ケース1.　「間違えてaddしてしまった」
本来addする予定のないファイルを間違えて勢いでaddしてしまった！やばい！ってなったことありませんか？
そんな時は、、、

```
$ git reset ファイル名
```
上記のコマンドを叩くことでステージングエリアに追加された特定のファイルを取り消すことができます。

また全てのファイルを取り消したい時は、、、

```
$ git reset
```
上記のコマンドを叩くことでステージングエリアに追加された全てのファイルを取り消すことができます。

## ケース2.　「間違えてcommitしてしまった」
無事addし、commitした直後に実はいらないファイルも混ぜてしまってた！やばい！ってなったことありませんか？
そんな時は、、、

```
$ git reset --soft HEAD^
```
上記のコマンドを叩くことで直前のcommitを取り消すことができます。
しかし、この<strong>--soft</strong>ってなんじゃって思いませんか？
思った方は勘が鋭いですね！
実は他にも種類があります。
それらについてまとめたものを以下の表で示します。

| オプション | 意味 |
|:--------:|:----------:|
| --soft   | commitを取り消した後もインデックスと作業ツリーの状態はそのままである  |
| --mixed(デフォルト) | commitを取り消した後作業ツリーの状態はそのままであるが、インデックスの状態は実行前の状態に戻る  |
| --hard   | commitを取り消した後インデックスと作業ツリーの状態までも実行前の状態に戻る   |

簡単にいうと
<strong>--soft</strong>は作業ツリーの修正をしたい時
<strong>--hard</strong>は1つ前のcommitの状態に戻りたい時
に用います。
※ --hardは変更内容が全て無くなるので注意して用いてください。

## ケース3.　「間違えてpushしてしまった」
無事add, commitし、勢いよくpushしたが実はブランチを間違えてしまってた、中途半端なcommitだった！やばい！ってなったことありませんか？
そんな時は、、、

```
$ git reset --hard HEAD^        　 // 直前のcommitの取り消し
$ git push -f origin ブランチ名   　// 強制push
```
上記のコマンドを叩くことで誰にもバレずにpushを取り消すことができます。
しかし、チーム開発には向いていません。
なぜなら、仮に自分以外のメンバーがローカル環境にローカル環境にpullし別の開発を始めていたら不整合が生じて今後pullができなくなります。

ではどうするか、、、

```
$ git revert        　 　　　　　　// 直前のcommitを打ち消すcommit
$ git push origin ブランチ名
```
上記のコマンドを叩くことで間違えてpushしたcommitを残しつつ、取り消しを意味する新しくcommitを作成しpushを取り消すことができます。

## おわりに
add, commit, pushとGitの流れに沿ってやらかしそうなところをピックアップしてみました。
本記事でおっちょこちょいさんを少しでも助けれたらなと思います。
それでは！よいGitライフを〜！
Ubuntu20.04＠wsl2でDockerを使えるようにする(WindowsのDockerDesktopを使いたくない）

## WindowsでDockerが使いたいけど、Docker Desktopは使いたくない
Ubuntu20.04＠wsl2でDocker利用したい(Windows上のDockerDesktopを使いたくない）のでDocker EngineをUbuntu20.04@wsl2にインストールします。

お役に立てたら、LGTMよろしくお願いします。

## Ubuntu20.04＠wsl2でsystemd(systemctl)を自動起動する
[こちらの記事](https://qiita.com/egoo/items/20b2599b0ce6f0eee98a)を参考にsystemdをPID1で起動できるようにする
実は↑が一番重要。あとは、[公式を参考](https://docs.docker.com/engine/install/ubuntu/)に実施すれば比較的すんなりいきます。

## Repositoryをセットアップ
```bash
$ sudo apt-get update
$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# amd64のところはマニュアルだと$(dpkg --print-architecture)。うまくいかなかったので直接amd64としていするとなぜか行けた。
```

## Docker Engineをインストール

```bash
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
# ちなみにPID1でsystemdが立ちあがっていないとここでインストールできない
```

インストールは完了したので、helloしてみる

```bash
docker run hello-world
#実行結果
docker: Got permission denied while trying to connect to the Docker daemon socket…
```
実行権限がないと怒られる。

## 作業中のユーザーに権限を与える
[公式](https://docs.docker.com/engine/install/linux-postinstall/)を参考に、

```bash
$ sudo gpasswd -a $(whoami) docker
$ sudo chgrp docker /var/run/docker.sock
$ sudo service docker restart
```
一旦Ubuntuからログアウトしてwslを再起動（wsl --shutdown)して、もう一度Ubuntuにログイン。
その上で再度helloしてみる

```bash
$ docker run hello-world
# 実行結果。中段に下記が出ていればOK
Hello from Docker!
This message shows that your installation appears to be working correctly.
```

以降は自動でDockerも立ち上がるようになっており、
これでUbuntu20.04＠wsl2上でDockerが使えるようになります。
Electronの始め方〜HelloWorldまで〜

普段はElectronとは無縁の生活の者です。
2018年くらいの記事を読んで失敗したので書き留めます。

今回はElectronでhello worldできれば完成です！

##ディレクトリ作成
```
mkdir helloworld
```

##ファイルの追加

次にhelloworldディレクトリに3つファイルを追加します。

helloworld/
　├ main.js
　├ preload.js
　└ index.html


```javascript:main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')

function createWindow () {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})
```


```javascript:preload.js
window.addEventListener('DOMContentLoaded', () => {
  const replaceText = (selector, text) => {
    const element = document.getElementById(selector)
    if (element) element.innerText = text
  }

  for (const type of ['chrome', 'node', 'electron']) {
    replaceText(`${type}-version`, process.versions[type])
  }
})
```

```html:index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
    <h1>Hello World!</h1>
</body>
```

##npmのインストール
```
cd helloworld
npm init
```

package.jsonを編集します。

```json:package.json
{
  "name": "helloworld",
  "version": "1.0.0",
  "description": "",
  "main": "main.js", 
  "dependencies": {
    "electron": "^16.0.2"
  },
  "devDependencies": {},
  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

```
ここで注意する点は、
"main"の部分が"main.js"になっているか。
それと、
"script"の部分に"start"の部分を足すこと。

次に、やっとelectronのインストールに入ります。

```
npm install --save-dev electron
```
helloworldディレクトリでインストールします。当たり前だけど、間違えがち。変なディレクトリでインストールしがち。

これでOK
起動します。もちろんhelloworldディレクトリで。

```
npm start
```


![スクリーンショット 2021-11-29 22.38.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612364/8d296afe-097e-684b-561b-7e00b8ee3cb0.png)

めでたくhelloworld！
今年Houdini関係で登壇して公開した資料まとめ

# 今年Houdini関係で登壇して公開した資料まとめ
今年登壇した「ボーンデジタル様主催のセミナー」「Unity道場」「CGWORLDクリエイティブカンファレンス」で発表時に使用し、一般公開している資料や動画の紹介及びまとめになります。
皆様のHoudiniの勉強や業務にお役立て頂ければ幸いです。

## Houdiniで作るNPRエフェクト＆After Effectsでのコンポジット実践解説オンラインセミナー

![Sasaki-y_BDS_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/e441b448-18ef-3ac1-3751-52602b298ede.png)

[登壇資料はこちら](https://www.klab.com/jp/blog/creative/2021/houdininprafter-effects-1.html)

[CGWORLD様によるセミナー内容のまとめ記事はこちら](https://cgworld.jp/feature/202102-houdini-nrp.html)

当日の登壇動画は、ボーンデジタル様とAUP契約を結んでいるユーザー様は申請すればご覧になることができます。

## Unity道場 Houdini編 『UnityとHoudiniで作るRealtimeVFX実践解説』
![03-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/138c3da4-0dc5-3fa0-8252-830a6675ef77.png)

![04-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/7683f143-fd3a-ac46-fd4b-7b59dcf00f0e.png)



[登壇資料はこちら](https://www.klab.com/jp/blog/creative/2021/unity-houdini-unityhoudinirealtimevfx-1.html)
[Unity Learning Materials : 前編の動画及び資料](https://learning.unity3d.jp/7010/)
[Unity Learning Materials : 後編の動画及び資料](https://learning.unity3d.jp/7109/)

## CGWORLD 2021 クリエイティブカンファレンス
**【TechDEMO“OKURIGAMI” : VFX Breakdown】Houdini x Unity x AfterEffectsを用いたRealtimeVFXテクニックや苦労話紹介**

![Oku_CCWCC2021_image_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/8a6c289d-e2bd-308a-6e15-67a4a2840349.png)

![Oku_CCWCC2021_still_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/b2e7cbcf-992d-6583-533a-2a776e83464c.png)

![Oku_CCWCC2021_still_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/913ec6fa-f83e-d424-0e95-ef9266101b6c.png)

![Oku_CCWCC2021_still_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539096/8b95d9f5-de27-0bcd-cc49-e689b8cb32e1.png)


[登壇資料はこちら](https://www.klab.com/jp/blog/creative/2021/cgworld-2021.html)
[ArtStationにアップしてある各項目のArtDumpはこちら](https://www.artstation.com/klab-rrr)
[セッション紹介ページはこちら](https://cgworld.jp/special/cgwcc2021/schedule/klab/)
登壇のアーカイブ動画は2021年12月20日まで配信されている予定です。2021年のクリエイティブカンファレンスに登録した方は誰でも視聴可能です。


## おわりに
如何だったでしょうか？　業界活性化や次に続く人たちのためにも、出来るだけ資料はオープンな形で公開するようにしてきているので、これらの資料が少しでも皆様のHoudiniの勉強や業務のお役に立てたのなら幸いです。

最後までお目通し頂きありがとうございました。
作業用PCをMacBookにしてみたら - Office編

作業用PCを更新すべきタイミングになった。
M1チップ搭載のMBPの性能がとても注目され、自分もそれにしてみたいと思って、
ついに申請して、作業用PCをThinkpad（Windows 10）からMacBook（MacOS Monterey）にチェンジした。

プライベートではMBPを使用しているので、そんなに困ることがないだろうと予想したが、
やはりハマってしまったポイントが出た。
この文章でハマったポイントを記録していきたい。

## Excel

Mac版Excelをインストールし使ってみたら、Windowsと見た目が少し変わるが許容できるレベルなので、
ホッとしたところ、問題発生。
Yu Gothic UI　フォントを使用しているシートに出会った。
文字が完全に隠れて見えないぐらい、ずれ込んでいた。

調べたところ、UI系フォントはWindowsのUIのためにだけ、存在するフォントだということがわかった。
https://t-blo.com/entry/ui-font

しかしこのシートは広い範囲で共有するものであり、簡単にフォントを変更することができない。
結局のところ、Office365　onlineで開き、更新していくことで解決した。（解決していない気分ですが。。）

フォント起因なので、WordとPowerPointも同じ事象が発生するだろう。

## Outlook

ほとんど問題ないが、Mac版のOutlookのカレンダーで他人の予定表を追加することができなかった。
これも結構困ったが、とりあえずonlineで他人の予定表を追加できたのでそれで対処。（ローカルに反映する時間は思ったより重く、何分かかかった。）

## Project

Mac版のProjectは存在しない。
代替としてOmniPlanがあるが、値段と使用になかなか手出しできない。
Projectを見るときだけ、windowsを併用しているはずかし局面に。
はやく他に良い代替策を探さないと。。
DockerでYew(Rust+WebAssembly)環境を構築

# 公式提供のDockerイメージが使えない場合にどうぞ

Docker環境でRustの開発を行いたい場合、第一の選択肢として[公式がdockerhubに提供してくれているコンテナイメージ](https://hub.docker.com/_/rust)があります。

しかし、自分がRust+WebAssemblyのアプリ作成のために[Yew](https://yew.rs/)というフレームワーク用の環境を作成しようとした際、公式提供のイメージをベースにするとあれこれ問題が起こりどうにも解決できませんでした。そのためOSのみのイメージをベースに[公式が提供しているコマンド](https://www.rust-lang.org/ja/tools/install)を使ってRustを入れ環境構築しようとしたのですが、この対応にあたりまとまった情報がなかなか見つからなかったため、解説もないメモ書き程度のものですが公開だけしておきます。これでチュートリアルくらいは突破できると思います。

似たようなことでお困りのかたがいらしたら参考になれば幸いです。


# Dockerfile

```dockerfile
FROM debian:latest

RUN apt update -y && apt upgrade -y 

RUN apt-get install -y curl

RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

ENV PATH=/root/.cargo/bin:$PATH

RUN apt-get install -y libssl-dev pkg-config build-essential

RUN cargo install wasm-pack

RUN cargo install trunk wasm-bindgen-cli

RUN rustup target add wasm32-unknown-unknown
```

# 補足

Rustは全体的にインストールが重く、初回ビルドにはけっこう時間かかります。（なお上記の公式imageのpullもまあまあ時間がかかります）

30分〜1時間くらいは許容範囲ですので、時間がかかっても焦らず気長にお待ちください。
暇なので『RPAツール』を作る #6　GUI編　ライブラリとの別れと出会い

#はじめに
皆さん、大変お久しぶりです。enp（えん）です。最近、暇じゃなくなってきました。
この記事は『RPAツール』を作ろうとする人の進捗報告になります。
RPAやRPAツールの作り方が書いてあるものではございませんので、ご了承ください。（もしかしたら、ソースは少しだけ載せるかもしれません。気分次第です）
今回は私が抱えている問題とライブラリとの別れと出会いについてお話ししようと思います。（openpyxlは記事にするほどの内容になりませんでした......）
最後までお付き合いいただければ幸いです。

#ライブラリとの別れ
改めて皆さん、お久しぶりです。一年以上も更新をストップしてしまいました。
本当に久しぶりに記事を書いているので、__今までどうやって記事を書いていたのか分からない状態です。__
作文って難しいですよね。国語は一番苦手でした。
さて、私の国語力はどうでもよく、皆さんは__<font color=red>『なぜ更新が一年以上も止まってしまったのか？』</font>__が気になると思います。
大変申し訳なく思います。しかし、サボっていたわけではありません。
###大きな変更を余儀なくされました。
その大きな変更とは__ライブラリの変更__です。今まで使っていたライブラリを変えることにしました。
そのライブラリとは__『Kivy』と『selenium』__です。今まで学んでいたseleniumさんと涙の別れ。辛いものを感じます。
しかし、__seleniumを学んで見えてきたこと__ですので学習していた時間が全て無駄という訳ではありません。
それでは、なぜ二つのライブラリを変えることにしたのかお話していきます。

#Kivyとの別れ、そして出会い
まずは『Kivy』からお話していきます。
Kivyに関しては使い勝手が悪いなどの理由ではありません。
###__<font color=red>ゲームエンジンの方が開発しやすそうだと思ったからです。</color>__
まず、__RPAツールに必要なこと__を考えたとき、__RPAを保存しなければならない__と思いました。
###__<font color=red>保存と言えばMySQL！</font>__
と安直な結論を出そうと思いましたが、__データベースにRPAを保存？　と少々疑問__に思いました。
そこで、思いついたのが__<font color=red>ゲームのセーブ機能</font>__です。
セーブ機能を応用すれば編集中のRPAだろうが、完成したRPAだろうが保存可能だと考えたわけです。
以上のような流れでゲームエンジンで開発しようと思いました。
あと、__Kivyさんが日本語に弱いという理由も少しあったりします。__気になる方は自分で調べてください。
###__<font color=red>じゃあ、お前はゲームエンジン何使うん？</font>__
という話ですが、__使うのはUnrealEngine。__とても有名なゲームエンジンです。
Unityなどありましたが、__公式の学習教材が無料というのがUnrealEngineに決めた大きな理由__です。
というわけで、これからはUnrealEngineを用いてGUIを含めた開発を行っていこうと思います。
しかし、これは__挑戦的な意味が大きいため、できなければKivyに戻ってくるかもしれません。__

#seleniumとの別れ、そして出会い
次はseleniumさんについて話していこうと思います。
seleniumさんは今まで#3から#5まで主役を飾っていたライブラリです。
しかし、今回をもってお別れ。悲しい限りです。
その__理由としてはseleniumとセットで使うChromeDriverにあります。__
###<font color=red>彼を使うとメンテが大変なんじゃ！</font>
ChromeDriverなどのseleniumとセットで使うドライバーは__ブラウザが更新された瞬間に使えなくなります。__
__ドライバー自身も更新が必要__になり、__同じドライバーを使い続けるということが出来ません。__
さて、ここで少し考える時間です。
seleniumを使ってアプリを開発し、配布したとします。
しかし、そのアプリはブラウザが更新された瞬間に使い物にならなくなる。
###単純に使い勝手が悪くない？
そういう事です。
アプリを使い続けたいと思うのなら、__ブラウザが更新するたびにアプリも更新するという作業が必要__になります。__非常に面倒。__
出来るなら、__ブラウザ更新に左右されないアプリケーションが望ましい__です。
__<font color=red>そこで登場するのがMechanicalSoupさんです。</font>__
MechanicalSoupは__簡易的なブラウザを自ら生成、スクレイピングする優れもの__です。
これで、ブラウザ更新に怯える生活から解放されます。
しかし、MechanicalSoupを形作るものは主に以前紹介したBeautifulSoupとrequest。
__任意のボタンを押してくれるのか非常に心配です。__
MechanicalSoupについてもまだ試験的な段階にすぎません。

#最後に
はい。以上がKivyとseleniumと別れを告げた全貌です。
しかし、勝負はこれからです。
__今からMechanicalSoupとUnrealEngineを学ばなければなりません。__
私は__GUIがすこぶる苦手です。__そのため、今まで以上に学習で四苦八苦することが多くなるでしょう。
さて、次回からはGUIを使ったアプリケーション開発(仮)をやっていこうと思います。
題材としては番外編として紹介したモノをGUIにしていく感じです。
その中で問題個所も解決していく予定ですのでお楽しみに！
しかし、始まるのは私がUnrealEngineの使い方をある程度把握し、MechanicalSoupがボタンを押せると分かってからです。
そのため、更新がまた一年以上開くかもしれませんがご容赦ください。
最後までお付き合いいただき誠にありがとうございました。
新規Railsアプリケーションの雛形作成〜データベース作成まで

# 新規Railsアプリケーション雛形作成
railsをPCにインストールしている前提で説明していきます。
今回、Railsのバージョンは6.0.0を使用。
データベース管理システムはmysqlを使用します。

ターミナル

```
# アプリケーションを入れたいディレクトリに移動
% cd ~/〇〇〇〇(ディレクトリ名)

# Railsアプリケーションで用いる仕組みの一部を設定するコマンドを実行
% bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl@1.1)"

# Railsのバージョン6.0.0を用いて、新しいAppを作成(〇の箇所には好きなアプリ名を入れる
% rails _6.0.0_ new 〇〇〇〇_app -d mysql

# 「〇〇〇〇_app」ディレクトリに移動
% cd 〇〇〇〇_app

```

上記の操作を行って、
/Users/ユーザー名/指定したディレクトリ名/指定したアプリ名
と表示されれば作成完了です。

# データベース作成
ターミナル

```
# 先ほど作成した〇〇〇〇_appディレクトリにいることを確認
% pwd

# データベースの作成
% rails db:create

```

コマンドを実行すると、以下の2つのメッセージがターミナルに表示されます。

【例】ターミナル

```
Created database '〇〇〇〇_app_development'
Created database '〇〇〇〇_app_test'

```
つまり、2つのデータベースが作成されたということです。
これらは、自分のPCで開発を進めるために必要なデータベースとなります。


今回は

```
% rails _6.0.0_ new アプリケーション名 -d データベース管理システム名
```

とバージョンを6.0.0に指定しデータベース管理システムはmysqlとしましたが、
私が学習したものがバージョン6.0.0でmysqlを使用したものであったため
これらを指定させていただきました。
もし他のバージョンなどで学習されていたらバージョンが変わるとプログラムの書き方が変わることがあるためご注意ください。
バージョンを指定しなかった場合、PCにインストールされている最新のRailsのバージョンが使われます。
【docker】herokuへのデプロイ作業で、No images to pushと表示される

#No images to pushと表示されてしまう
###エラー内容
herokuにdocker環境で作成したアプリをpushしようとした際に上記のエラーを吐いてしまった。


```
$ heroku container:login
Login Succeeded
$ heroku create アプリ名
Creating ⬢ アプリ名... done
https://アプリ名.herokuapp.com/ | https://git.heroku.com/アプリ名.git
$ heroku container:push web 
 ▸    No images to push

```

###状況整理
ディレクトリ構成は下記のようになっており、SRCディレクトリにrailsアプリのファイル群が格納されており、SRCディレクトリと同じディレクトリにdocker-compose.ymlなどのDocker用ファイルを配置しておりました。
SRC
|-APP
|-bin
  ... 
docker-compose.yml
dockerfile
entrypoint.sh

###原因解明と解決方法について
dockerfileなどの内容と配置に問題はなかったのですが、ファイル名が原因でした。
誤）dockerfile
正）Dockerfile
Dockerfileの頭文字が大文字になっていなかったため発生したことがわかりました。修正後に`heorku container:push web`を実行したところ無事にpushできました。

何を言いたいかというと、Dockerfileのファイル名が誤りでもDockerfileとして認識していればちゃんとDockerが動くあたりすごいなと。
一台の物理マシンで複数リポジトリから利用されるself-hosted runnerになる

**これは、自分用メモ**

タイトルのようなことを調べてて、EnterpriseかOrganizationレベルのself-hosted runnerを追加すれば複数リポジトリから共同利用できる様子。もしくは、下の絵のようにself-hosted runnerのインストール先（および起動）を別ディレクトリにすればやりたいことはひとまずできる。[actions-runner-controller](https://github.com/actions-runner-controller/actions-runner-controller)を使う方法などいろいろあるけど、状況によってはこれが一番簡単。
![Untitled(2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118448/0d8bd539-0e1d-de43-757b-76ca063a7d8f.png)
こうすると、一台のマシン上で複数のRunner.Listenerを起動できるのと、Github側に設定するself-hosted runnerの名称はラベル名含め複数のリポジトリ間で仮に同一であっても、ジョブの投げ先であるRunner.Listenerは区別されている。そして、複数のRunner.Workerは同時実行可能。
AngularのCustom Validationの作成について

Angularのデフォルトにもある程度のバリデーションが備わっていますが、入力において、特定の条件でバリデーションエラーを発するようにするためにはカスタムバリデーターを作成する必要があります。
作成の流れを抽象的に記載します。

## 必要なファイル
* カスタムバリデーター
* スクリプト(コンポーネント)
* テンプレート(コンポーネント)

カスタムバリデーターの配置はどこでもいいです。(vscodeであればimportする時に自動的にディレクトリが決まるはずなので)
所属の会社の人に確認してください。


### コード例
**カスタムバリデーター**

```custom-validator.ts
import { AbstractControl, ValidationErrors } from '@angular/forms';

export const 定数名 = function (control: AbstractControl): ValidationErrors | null {
  処理内容...
  if(バリデーションエラーの場合) {
    return { バリデーションエラー名: true} ←このバリデーションエラー名はテンプレートで使われます。
  } else {
    return null  // ← 「 ValidationErrors | null 」　と型定義しているため
  }
}
// 以下複数作成するのも可　↓↓
```

**スクリプト**

```hoge.component.ts

import { 定数名 } from './ディレクトリの場所/custom-validator'; // ←自動的に作成されるはず
import { FormBuilder, FormGroup } from '@angular/form'; // ←Formの定義にFormBuilderを使います
// 省略
export default class HogeComponent {

  public inputForm!: FormGroup;

  constructor(
    public formBuilder: FormBuilder
  ){}

  this.inputForm = this.formBuilder.group({
    some: [
      '',
      [定数名] // ← カスタムバリデーターで「定数名」と定義しているので。[]は配列の[]
    ]
  })
}
```

:::note info
コード内の[定数名]の部分は普段はデフォルトでついているバリデーションで、空欄を許可しない[Validator.required]が入ることが多いです。
:::
**テンプレート**

```hoge.component.html
<input type="text" formControlName='some' placeholder="some">
<span *ngIf="inputForm.get('some')?.hasError('バリデーションエラー名')">入力が不正です</span>
```

とりあえず一旦これで書けると思います。