OmniAICreator/Qiita-1.07M huggingface dataset:
【環境構築】docker-compose upで「WARNING: Found orphan containers (...) for this project. ...」が表示されたので「-p」でプロジェクト名をつけてみた。

どうも、たかふみです。
dockerを使って環境構築をしようと`docker-compose up`したところ、下記メッセージが出てきました。


```
MacBook-Pro:env moriyama$ docker-compose up --build
WARNING: Found orphan containers (app_go, env_web_1, env_db_1, env_mysql_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Building bot_wordwolf
Step 1/11 : FROM alpine
```
今回はこの「Found orphan containers」について調べてみました。

## 「orphans」とは何か調べてみる。
↓のstackoverflowに全部書いてありました。
>docker compose orphan containers warning
>https://stackoverflow.com/questions/50947938/docker-compose-orphan-containers-warning

どうやら、docker-compose.ymlでコンテナを生成する際につけられるコンテナ名はディレクトリ名を使ってつけられるようです。僕の場合、`env\docker-compose.yml`のディレクトリ構造で環境構築することが多いため、「env_web/ env_db/env_mysql」というコンテナが量産されてしまい、他のプロジェクトで生成したコンテナ名と競合して今回のWARNINGが表示されていたようです。

参考にしたstackoverflowで解決策として記載されていたのが、プロジェクト名をつけるというもの。
オプション 「-p」を使うことでつけられるとのことです。

```
docker-compose [-f <arg>...] [options] [--] [COMMAND] [ARGS...]
```

これでupしてみましょう。

```
MacBook-Pro:env moriyama$ docker-compose -p wordwolf up -d
Creating network "wordwolf_default" with the default driver
Building bot_wordwolf
Step 1/11 : FROM alpine
```

WARNINGが出ずに作成が始まっている！

そのほかにも「COMPOSE_PROJECT_NAME」という環境変数で指定をする方法や、docker-comose.ymlファイルと同ディレクトリに.envファイルを配置して「COMPOSE_PROJECT_NAME=myproject」を指定する方法もあるようです。

## まとめ：-pでプロジェクト名をつける方法もある
今回は参考にしたサイトで書かれていた方法を試しましたが、WARNINGメッセージに表示されている`--remove-orphans`をつけて実行すれば今回のWARNINGは表示されずコンテナが起動できるので、特に理由がなければメッセージの通り、`--remove-orphans`をつけての実行で良さそうです。

■docker docsより
>--remove-orphans
→Remove containers for services not defined in the Compose file.
引用：https://docs.docker.com/compose/reference/up/

僕は開発環境を作るときは、{プロジェクト名をつけたディレクトリ}\env\docker-compose.ymlの構成が多いので、プロジェクト名をつけたいときは`-p`で`docker-compose up`すると良さそうです。

それでは！

※12/27追記
「-p」をつけてupしたら、`docker-compose ps`でdocker-compose.yml内に記載したコンテナが表示されない。`docker ps`だと表示されなくなりました。`-p`つけると同一ネットワークのコンテナとして認識されないのでしょうか？ こちらについては調査中です。

###参考：
>・docker compose orphan containers warning
>https://stackoverflow.com/questions/50947938/docker-compose-orphan-containers-warning

>・docker-compose up
https://docs.docker.com/compose/reference/up/
[Rails] 初心者がコーディングする際の事前知識(コントローラー作成、アクション作成、アクション以外のクラス作成、ルーティング設定)

## 背景
Rails環境構築ができた後のコーディングの進め方をまとめました。

また、Ruby自体初心者の方は下記の記事に目を通しておくといいと思います。
・[Ruby基礎文法](https://qiita.com/Fendo181/items/eb2cb17f32d99aa01f59)

## コントローラー作成
コントローラーは基本的にモデル単位(DBのテーブル単位)で作成します。コントローラー名は複数形にします。
下記コマンドでコントローラーとコントローラーに対応するViewファイルをまとめて作成できます。
ちなみに、Railsの命名規則でファイル名がスネークケース、クラス名はキャメルケースとなっています。

```
rails generate controller コントローラー名
```
上記コマンド実行時のコントローラー名はスネークケース、キャメルケースのどちらでも作成されるファイル名はスネークケースになります。
また、上記のコマンドを使わず手動でコントローラーを作成することもできます。その際はコントローラーに対応するViewファイルも作成しましょう。

## アクション作成
アクションとはController内のメソッドのことです。
アクション内で行う処理がない場合も空のメソッドを作成します。
下記のようにすると、コマンドでコントローラー作成と同時にアクションを作成できます。

```
rails generate controller コントローラー名 アクション名1 アクション名2
```

新しく作ったアクションにさせたい処理が既存アクションですでに実装されている場合、`render`を使用することで既存アクションを使いまわすことができます。下記は例です。

```ruby
def create
  #他アクションに対応するViewを返す
  render action: :new
  #他コントローラーのアクションを返す
  render template: "hoge/new"
  #jsonを返す
  render json: @hoge
  #テキストを返す
  render text: "hoge"
  #xmlを返す
  render xml: @hoge
end
```

アクションではActiveRecordを介してデータベースを操作し、Viewに値を渡します。
下記は7つのアクションについての記事です。
[[Ruby on rails]7つのアクション以外のアクションの設定](https://qiita.com/imayasu/items/19f43a5726ed2170f611)

## アクション以外のクラス作成
プロジェクト内の任意の場所にディレクトリを作成し、そこにクラスを作りましょう。(app/commonclass/Hoge.rbやlib/Hoge.rbなど)
作ったらコントローラーから下記のように読み込ませます。

```ruby
class HogeController < ApplicationController
  #クラス読み込み
  require './app/commonclass/hoge'
  def index
  end
end
```
上記のようにrequireを使う以外にも、`config/application.rb`に下記を追記すれば読み込ませることができます。

```ruby
config.autoload_paths += %W(#{config.root}/読み込ませたいディレクトリ #{config.root}/読み込ませたいディレクトリ)
```

## ルーティング設定
下記の記事を参考にしました。
[Rails ルーティング 基礎 まとめ](https://qiita.com/akk11_k/items/a6a21beb2b736ebbc147)

## 蛇足
下記は命名規則についての記事です。
・[Railsにおける命名規則](https://qiita.com/gakkie/items/3afcd505c786364aa5fa)

特に下記の記事を参考にさせていただきました。
・[他言語経験者による初めてのrails](https://qiita.com/jpshadowapps/items/fa1197cc8ad135e26f71)
・[【Rails】クラスファイルを用意してcontrollerから呼び出したい](https://sashimistudio.site/controller-call-class/)

最後に、参考にさせていただいた記事の投稿者の皆様、ありがとうございます。
私の記事に不備などありましたらご指摘いただけると幸いです。
Udemy もう怖くないGit!チーム開発で必要なGitを完全マスター　(ブランチ・マージ編)

>引用先
>[Udemy もう怖くないGit!チーム開発で必要なGitを完全マスター](https://www.udemy.com/course/unscared_git/)
>このコースではGitの裏側でどのような挙動でGitが動いているのかを図で詳しく解説しているので深く知りたい方は受講してみることをおすすめします。

#ブランチとは
並行して複数機能を開発するためにある。
共同開発において必ず必要となる。

#ブランチの仕組み
コミットをしていくと前回のコミットを親コミットとしてコミット1,2,3と時系列順にならんでいき、コミット名としてコミットID(コミットハッシュ値)を割与えられる。
ブランチとは最新のコミットIDを指すポイントにすぎない。
**要するにブランチの中にデータが入っているわけではなく、いつコミットしたものかのデータ情報にすぎないということ。**

####(余談)HEADについて
Gitを使っているとちょくちょくでてくるHEADについて記述。
今、自分が作業しているポインタのことをHEADという。

#新しいブランチを作成
```
git branch <ブランチ名>
```
ブランチを作成するだけで、ブランチの切り替えは行わない。

#ブランチの一覧を表示
```
git branch

#　全てのブランチを表示
git branch -a
```
何のブランチが確認する時に使う。
※印がついているのが今いるブランチ。

#ブランチを切り替える
```
git checkout <既存ブランチ名>

# ブランチを新規作成して切り替える
git checkout -b <新ブランチ名>
```
-bはbranchの略。

#変更をマージ(統合)する
```
git merge <ブランチ名>
git remote <リモート名/ブランチ名>
```
マージすると他の人の変更履歴を統合する。

##マージには３種類ある

###①Fast Foward : 早送りになるマージ
ブランチが枝分かれせずマージした時は、ブランチのポインタを前に進めるだけ。

###②Auto Merge : 基本的なマージ
枝分かれして開発していた場合、マージコミットという新しいコミットを作る。
マージコミットは親コミットを2つ持っている特徴がある(マスターブランチとブランチ)。

###③コンフリクト
同じファイルを複数人で異なる変更した時に起こる。
例えば、index.htmlの３行目を二人のエンジニアが変更しマージした時に起こる。

#コンフリクトの解決方法
コンフリクト発生画面

```
<h1>Gitチュートリアル</h1>
<p>ようこそ</p>
<<<<<<<HEAD
<p>git addについて学ぼう</p>     ←今自分がいるブランチの変更内容
=======
<p>git commitを知ろう</p>       ←別のブランチの変更内容
>>>>>>>feature
```
↓　修正

```
<h1>Gitチュートリアル</h1>
<p>ようこそ</p>
<p>git addについて学ぼう</p>
<p>git commitを知ろう</p>
```
修正方法
①ファイルの内容を書き換える
②「<<」 「==」 「>>」 の記述を削除する

##コンフリクトが起きないようにするには？
①　複数人で同じファイルを変更しない
②　pullやmergeする前に変更中の状態をなくしておく(commit,stashをしておく)
③　pullする時は、pullするブランチに移動してからpullする

#ブランチ名を変更
```
git branch -m <ブランチ名>
```
今作業しているブランチ名を変更できる
#ブランチを削除
```
# masterにマージされていない変更が残っている場合削除しない
git branch -d <ブランチ名>

# masterにマージされていなくても強制削除する
git branch -D <ブランチ名>
```

#ブランチを利用した開発の流れ
masterブランチをリリース用ブランチ。
開発はトピックブランチを作成して進めるのが基本。

**最新のマスターからトピックごとにブランチをして、開発が終わったらマスターの方にマージしていく。**
物流用語

リードタイム：商品・サービスを発注してから納品されるまでの時間や日数

3PL:企業のロジスティクスの一部もしくは全部を外部委託する。

QCD:クオリティー、コスト、deliver納期

ロット:商品を管理する単位。問題が発生し、リコールなどがあってもロット単位の回収をすれば良い。
https://www.kantsu.com/terms/2853/

#WMSを作るには

####効率化のためには
①作業者が何をしているか。
②作業者が行っている作業を分析して、改善策を作るが大事。

####SCMとWMS

SCM:SCP,ERP,SCEの3つから成り立つ。
WMSはSCEの一つ。

SCP:需要予測システム、生産管理システムなどの計画系
ERP:統合型管理システム、財務、経理など基幹システムを指す。
SCE:実行系のシステム。

WMSはERPからの情報を元に稼働するシステムである。
ERPの中にWMSを内包するシステムもあるが、現場作業性が少ない、基幹システムと切り離せない場合は、ERPの中でそのまま管理すれば良い。
物量が多い、マテハン機器との連動が必要など管理を分ける場合にWMSを使用するべき。

####WMSとTMS
TMS:輸配送の効率化、納品厳守、安全管理を目的としたシステム

####取引先とのデータ連携
仕入れ先とのデータ連携:ASN情報があれば管理効率化可能。なければ入荷予定データ、発注データを予定データとする。
→どのような入荷データが来るのか聞くこと。

社内仕入れ先のマスタ情報：商品の詳細変更などがあれば、タイムリーに連携する必要あり。

得意先連携：返品データについて。返品された商品により、在庫の数が狂うことも多い。
→返品があるのか。返品データはどのように来るのか聞く必要あり。

####商品マスタ
基幹システムとWMSは商品マスタを基本として連携されている。商品マスタの情報は重要。

管理にはJANコードが基本だが、インストアコード(社内コード)での管理がされていることもある。
①一つのJANコードに複数の商品がある場合(メーカーによってある)
②取引先によりコードが分かれている。
→商品単位でどのようなコードで管理されているのか聞く。

####共通マスタとWMS
共通マスタのデータ連携は基本的に
基幹システム→WMS
が基本。

社員マスタ、作業者マスタ、仕入れ先マスタ、得意先マスタ、出荷先マスタ、セットマスタ、荷主マスタ、倉庫マスタ

####WMS独自マスタ
配送コースマスタ、出荷バッチ管理マスタ、梱包マスタ、ロケマスタ、ゾーンエリア管理マスタ、バース管理マスタ

####WMS独自のパラメーター
#####入荷
日付逆転チェック、入荷時のバーコード印刷、配布指示(商品にJANコードがない場合にバーコードを貼る指示をするなど)

#####入庫
ローケーション指定、温度帯管理、滞留在庫管理(一定の期間が過ぎたものを滞留在庫とする。)
#####出荷
出荷日付期限

####入荷予定
固定ロケーションかフリーロケーションか
(フリーロケーションの場合は入荷時に人が割り当てる処理もしくは機会が割り当てる処理が必要。
固定ロケは商品のロケが割り当てられていなと問題)

入荷作業計画
バース(トラックが来るところ)、人員

####入荷検品
入荷予定リストは最小限(枚数が多いと作業がしずらい)

バーコードのない商品はその場でバーコードを印刷すると管理が楽

####入荷実績、入荷検品シール
入荷検品の結果を入荷実績とし、入荷実績を参考に入荷検品シールを作成し物に貼り付けておく。
(入荷検品シールは、検品済みをわかりやすくする、どのロケに置くかわかるようにするなどの意味がある。)

####ステータス管理、振替機能
良品、不良品、保留品などで分ける(ステータスは振替できるように振替機能をつける)
(ステータスはどうしたいか聞く)

####棚移動、ロケ移動
棚移動、ロケ移動があるか聞く(冬の売れもの商品など時期によってよく出荷する商品を特定のロケに移動したりする)
ロケ移動時に、ピッキングできないのでピッキング停止する処理などする。

####棚卸
期末棚卸
在庫データ作成→棚卸リスト(ロケあり)→実数カウント→在庫差異リスト→理論在庫差異→実数登録

循環棚卸

####在庫調整
作業ミスでの調整
返品の対応
営業の持ち出しによるイレギュラー対応

####在庫照会の主な機能
倉庫別在庫照会、荷主別在庫照会、ロケ別在庫照会、日付別在庫照会、商品別在庫照会、ロット別在庫照会

####補充
リザーブエリアが存在する(一旦貯めておく場所)場合、補充が発生する
緊急補充:なくなったら補充
定期補充:定期的

####出荷引当
①基幹システムで引当の調整をしてから、出荷予定が来る場合(基本的には欠品ない。あれば基幹システムからやり直し)
②WMSで引当
基幹システムから出荷指示データを受信
→欠品がないか確認
→本引当

####出荷指示データ、出庫指示データの作成
出荷指示データ分割:自動倉庫、ソーター、DPS、ハンディーなどマテハン機器で行う出荷分と出荷リストで行う出荷分で分ける。
→ゾーン、データ別で分ける

####ピッキング方式
シングルオーダーピッキング、トータルピッキング、マルチオーダーピッキング

####流通加工
セット品があるかどうか

####出荷停止
出荷停止指示書の出力
移動指示と移動先の登録(保留エリアへ置く)

####返品入荷
返品検品
返品予定データがある場合は、それを元に、ない場合は実際の商品のバーコードを読み込み返品実績を作成。

返品シール
返品シールを貼る

在庫ステータスの移動
返品された商品を良品か不良品に分けるか、保留品に一旦置いておくかのどちらか。

####締め処理
１日の終わりや、週の終わりなどに、入荷実績や出荷実績を基幹システムと同期する必要がある。
[Unity]WebGL: Server configuration for Nginx

Unityの公式には、WebGLのサーバ設定例はIISとApacheしか書いていません。
[WebGL: Server configuration code samples](https://docs.unity3d.com/2020.2/Documentation/Manual/webgl-server-configuration-code-samples.html)

nginx向けに書いて動作確認したものを掲載しておきます。

## 環境など

- Unity 2020.2.0f
- 使用したDockerイメージ: `nginx:alpine`
- Herokuにホスティングする都合上、ポート番号が環境変数になっています。
- gzip圧縮にのみ対応。Brotli圧縮の場合でも同じように書けばよいはず。

## nginx.conf

```nginx
server {
  listen $PORT;

  location / {
    root   /webgl; # お好みで
    index  index.html;

    gzip off;

    location ~* \.gz$ {
      add_header Content-Encoding gzip;

      location ~* \.data\.gz$ {
          types { }
          default_type application/octet-stream;
      }
      location ~* \.wasm\.gz$ {
          types { }
          default_type application/wasm;
      }
      location ~* \.js\.gz$ {
          types { }
          default_type application/javascript;
      }
      location ~* \.symbols\.json\.gz$ {
          types { }
          default_type application/octet-stream;
      }
    }
  }
}
```

### content-typeの設定について

若干ハック感ありますが、一応nginxの公式の記法に倣っています。
[Module ngx_http_core_module#types](http://nginx.org/en/docs/http/ngx_http_core_module.html#types)

追加モジュールが必要ですが、以下の方法で設定した方が可読性は高くなると思います。
[nginxでレスポンスヘッダを書き換える - Qiita](https://qiita.com/reiki4040/items/218438c6e32ba585fd99)

## 余談: Herokuデプロイ用のDockerfile

```dockerfile
FROM nginx:alpine

# copy binary files
WORKDIR /webgl
COPY ./bin .

# configure and run in foreground
WORKDIR /etc/nginx/conf.d
RUN rm default.conf
COPY ./environments/webgl.conf.template .
CMD /bin/ash -c "envsubst '\$PORT' < webgl.conf.template > default.conf" && /usr/sbin/nginx -g "daemon off;"
```

## 全体を通して

もっとこうしたほうがいいぞ、等あればご指摘ください。
Django検索

#Djangoでの検索

```find.py
変数 = モデル名.objects.filter(フィルター内容)
```

## フィルター内容

###文字検索
```samle.py
変数 = モデル名.objects.filter(フィルター内容)
# 完全一致
変数 = モデル名.objects.filter(項目名=値)
# 値で始まる
変数 = モデル名.objects.filter(項目名__startswith=値)
# 値で終わるものを検索
変数 = モデル名.objects.filter(項目名__endswith=値)
# あいまい検索
変数 = モデル名.objects.filter(項目名__contains=値)
# 大小区別しない検索
変数 = モデル名.objects.filter(項目名__iexact=値)
# 大小区別しないあいまい検索
変数 = モデル名.objects.filter(項目名__icontains=値)
変数 = モデル名.objects.filter(項目名__istartswith=値)
変数 = モデル名.objects.filter(項目名__iendswith=値)
```

###数値比較
```sample.py
変数 = モデル名.objects.filter(フィルター内容)
# 値と等しい
変数 = モデル名.objects.filter(項目名=int(値))
# より大きい
変数 = モデル名.objects.filter(項目名__gt=int(値))
# 以上
変数 = モデル名.objects.filter(項目名__gte=int(値))
#より小さい
変数 = モデル名.objects.filter(項目名__lt=int(値))
# 以下
変数 = モデル名.objects.filter(項目名__lte=int(値))
```

###AND検索
```sample.py
変数 = モデル名.objects.filter(1つ目の条件,2つ目の条件,...)

変数 = モデル名.objects \
  .filter(1つ目の条件) \
  .filter(2つ目の条件) \
```

###OR検索
```sample.py
変数 = モデル名.objects.filter(Q(1つ目の条件)|Q(2つ目の条件),...)
```

###リスト検索
```sample.py
変数 = モデル名.objects.filter(項目名__in=リスト)
```

###SQLでの検索
```sample.py
変数 = モデル名.objects.raw(sql文)

# sql文
sql = 'SELECT * FROM テーブル名'
##テーブル名
アプリケーション名_モデル名
```
【Swift】配列から要素をランダムに取り出す

配列 Arrayのプロパティ`randomElement()`でランダムに要素を取り出してくれます。

```swift
let omikujiResults = ["大吉","中吉","吉","小吉","凶","大凶"]
let thisYearLuck = omikujiResults.randomElement()
print(thisYearLuck!)

//出力結果：大吉
```

実際に自分が試したら、<b><font color="red">大凶</font></b>が出ました。👹
今年はいい年になりますように。
Fargate1.4.0以降でのVPC エンドポイント（PrivateLink）を設定する際の注意とterraformでの例

Fargate（ECS） + VPC + Natゲートウェイ + ECR の組み合わせにおいて、VPCエンドポイントを作成してPrivateLink経由にする事で、コスト削減が可能となります。

概要については偉大な先人達の記事をご参照ください。

[Amazon ECR インターフェイス VPC エンドポイント \(AWS PrivateLink\) \- Amazon ECR](https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/vpc-endpoints.html)
[\[AWS\] FargateをNatゲートウェイと組み合わせて完全に死亡した話 \| 個人利用で始めるAWS学習記](https://noname.work/?p=2386)
[PrivateLinkとALBを利用してECS Fargateをロードバランシングする \| Enjoy IT Life](https://nishinatoshiharu.com/alb-fargate-privatelink/)
[AWS ECRのPrivate Linkを作る](https://kennys.tech/aws-create-ecr-privatelink/)
[エンドポイントを使用してプライベートサブネットでECSを使用する \| Developers\.IO](https://dev.classmethod.jp/articles/privatesubnet_ecs/)


# Fargate1.4.0以降の場合の注意

AWSのDocumentには但し書きがたくさんありますが、Fargate1.4.0以降と未満では必要な設定が異なります。
解説/やってみた記事では、1.3.0以前（1.4.0未満）の内容になっている場合があるので注意が必要です。

具体的には、

> Fargate 起動タイプとプラットフォームバージョン 1.4.0 以降を使用する Amazon ECS タスクでこの機能を使用するには、com.amazonaws.region.ecr.dkr と com.amazonaws.region.ecr.api Amazon ECR VPC エンドポイントの両方、および Amazon S3 ゲートウェイエンドポイントが必要です。

が該当します。1.3.0未満との差分は、`com.amazonaws.region.ecr.api` が追加で必要になった事です。


まとめると、

必要

- com.amazonaws.region.ecr.api
- com.amazonaws.region.ecr.dkr
- com.amazonaws.region.s3

log出力するなら必要

- com.amazonaws.region.logs

となります。


# terraformで書く例

VPC、subnetは各自置き換えてください。


```terraform

resource "aws_vpc_endpoint" "ecr_api" {
  service_name      = "com.amazonaws.ap-northeast-1.ecr.api"
  vpc_endpoint_type = "Interface"
  vpc_id            = aws_vpc.main.id
  subnet_ids        = [aws_subnet.private_1a.id, aws_subnet.private_1c.id]

  security_group_ids = [
    aws_security_group.https.id,
  ]

  private_dns_enabled = true

  tags = {
    "Name" = "ecr-api"
  }
}

resource "aws_vpc_endpoint" "ecr_dkr" {
  service_name      = "com.amazonaws.ap-northeast-1.ecr.dkr"
  vpc_endpoint_type = "Interface"
  vpc_id            = aws_vpc.main.id
  subnet_ids        = [aws_subnet.private_1a.id, aws_subnet.private_1c.id]

  security_group_ids = [
    aws_security_group.https.id,
  ]

  private_dns_enabled = true

  tags = {
    "Name" = "ecr-dkr"
  }
}



resource "aws_vpc_endpoint" "logs" {
  service_name      = "com.amazonaws.ap-northeast-1.logs"
  vpc_endpoint_type = "Interface"

  vpc_id = aws_vpc.main.id

  subnet_ids = [aws_subnet.private_1a.id, aws_subnet.private_1c.id]

  security_group_ids = [
    aws_security_group.https.id,
  ]
  private_dns_enabled = true

  tags = {
    "Name" = "logs"
  }
}

resource "aws_vpc_endpoint" "s3" {
  service_name      = "com.amazonaws.ap-northeast-1.s3"
  vpc_endpoint_type = "Gateway"
  vpc_id            = aws_vpc.main.id
  route_table_ids = [
    aws_default_route_table.private.id
  ]

  tags = {
    "Name" = "-s3"
  }
}

resource "aws_security_group" "https" {
  name        = "https"
  description = "https"
  vpc_id      = aws_vpc.main.id

  egress {
    cidr_blocks = ["0.0.0.0/0"]
    from_port   = 0
    protocol    = "-1"
    to_port     = 0
  }

  ingress {
    cidr_blocks = ["0.0.0.0/0"]
    from_port   = 443
    protocol    = "tcp"
    to_port     = 443
  }

  timeouts {}

  tags = {
    Name = "https"
  }
}
```
【Python】Pyxel(ピクセル)ちょっとやってみた

環境メモ
⭐️Mac Book Pro(macOS Catalina)
⭐️Anaconda 4.9.2
⭐️Python 3.8.5
⭐️Jupyter Note book 6.1.6


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">✨Python（Pyxelピクセル）✨<br>ドット絵🍄（ピクセルアート）🍄タイプのレトロな2Dゲームが作れるPythonライブラリ❤️Pyxel（ピクセル）🧡やってみた😊<br>楽しいなぁ🎀v(≧∇≦)v💕💕<br><br>【Python】Pyxel(ピクセル)ちょっとやってみた<a href="https://t.co/0kHuxXIQ7N">https://t.co/0kHuxXIQ7N</a><a href="https://twitter.com/hashtag/python?src=hash&amp;ref_src=twsrc%5Etfw">#python</a> <a href="https://twitter.com/hashtag/Pyxel?src=hash&amp;ref_src=twsrc%5Etfw">#Pyxel</a> <a href="https://t.co/SZ9A7u7vBt">pic.twitter.com/SZ9A7u7vBt</a></p>&mdash; non (@nonnonkapibara) <a href="https://twitter.com/nonnonkapibara/status/1345614508128043015?ref_src=twsrc%5Etfw">January 3, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## Python（Pyxelピクセル）とは
ドット絵（ピクセルアート）タイプのレトロな2Dゲームが作れるPythonライブラリ。

下記Gitに、Pyxelのインストール手順やサンプルプログラムの説明が記載されています。

<b><font color="MediumVioletRed">PyxelのサンプルプログラムのGit</font></b>
https://github.com/kitao/pyxel/blob/master/README.ja.md
![スクリーンショット 2021-01-03 14.22.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/25efed45-65cd-01d4-a878-e04b8294644e.png)


## Mac環境でインストールしてみた
事前にPython3の環境作成済みの状態です。
Python用ライブラリ 「glfw」 をインストールする

```
brew install python3 glfw
```

次に「glfw」のインストール

```
pip3 install pyxel
```

これで環境は完成！！

## サンプルプログラム
Pyxelのサンプルプログラムをインストールする

```
install_pyxel_examples
```

サンプルプログラムのファイルへ移動する

```
cd pyxel_examples
```

サンプルプログラムの「Hello Pyxel」を起動してみる

```
python3 01_hello_pyxel.py
```

![hellopyxel.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/df41e0af-e838-ce6e-0806-24e96bd8b30f.gif)

起動成功！！

「Q」キーを押すと終了する。

他にも、サンプルプログラムがあります
![スクリーンショット 2021-01-03 14.46.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/c1c05d0f-18d0-d1b0-3e7b-cf00a207149a.png)


## 自分でも作ってみた
![nonple.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93155/ad282aea-0730-6419-7f05-9472cd9957de.gif)

```python:nonkapibara.py
import math
import pyxel

radius=1 # 半径
back_color=11 #背景色
screen_size=256 # 画面サイズ
start=2 # 描画スタート位置
range_step=6 # 描画ステップ
speed_step=0.5 # スピードステップ
pyxel.init(screen_size,screen_size)
speed=0

def center_circle():
   square=math.sqrt((x_range-128)**2+(y_range-128)**2)
   sin=math.sin(square*0.2+speed)*3
   colror=(20-square*10)%12
   pyxel.circ(x_range+sin,y_range,radius,colror)

while True:
  pyxel.cls(back_color)
  for x_range in range(start,screen_size,range_step):
 	 for y_range in range(start,screen_size,range_step):
 	 	 center_circle()
  speed+=speed_step
  pyxel.flip() # 画面を更新
```


「esc」キーを押すと終了する。
Redmine

Redmineは個人的な学習のスケジューリングに使用している。
使い勝手は何とも言えないが、無料ということと、インストールが一番楽そうだったので
BITNAMI REDMINE を選択した。

1.　ダウンロード & インストール
　　　BITNAMI REDMINE
　　　https://bitnami.com/stack/redmine/installer
　　
2.　追加プラグイン
　　　easy_gantts
　　　https://www.easyredmine.jp/en/redmine-gantt-plugin
　　　ガントチャートの帯を直接ドラッグして操作できるプラグイン。
落下物で歯車（？）を回してみた (CANNON.js + THREE.js)

ポエムタグは出来心です。

<p class="codepen" data-height="427" data-theme-id="light" data-default-tab="result" data-user="kob58im" data-slug-hash="ExgQbXG" style="height: 427px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="freefall by using cannon.js">
  <span>See the Pen <a href="https://codepen.io/kob58im/pen/ExgQbXG">
  freefall by using cannon.js</a> by kob58im (<a href="https://codepen.io/kob58im">@kob58im</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 歯車（？）の形状作成部分

`Quaternion`を使って、角度を変えながら`body`に`addShape`していっています。

```js

// 補足：
//  Wings = 5;
//  body = new CANNON.Body({mass: 2, material:matWing});

function makeWing(body) {
  for(let i=0;i<Wings;i++){
    let quo = new CANNON.Quaternion();
    let rad = 2*Math.PI*i/Wings;
    quo.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), rad);
    body.addShape(
      new CANNON.Box(new CANNON.Vec3(WidthOfWing, 0.2, Radius-0.3)),
      new CANNON.Vec3(0, Radius*(1-Math.sin(rad)), Radius*Math.cos(rad)),
      quo
    );
  }
}
```

# 回転軸との接触

`ContactMaterial`で摩擦と反発係数を`0`にしておくのがポイント。
`mass: 0`にするのが必須かはわからないが、`0`以外にすると重力の作用を受けるので、空中には浮かせられない。

```js

phyBasement = new CANNON.Body({mass: 0, material:matBasement});
(・・・中略・・・)
let matBW = new CANNON.ContactMaterial(matBasement, matWing, { friction: 0.5, restitution: 0.0});
world.addContactMaterial(matBW);
```

以下は余談

途中まで`phyBasement.angularVelocity.set(0, 0, 4);` とかにしてたせいで、しょっぱなから歯車が吹っ飛ぶありさまで、暫く原因不明でハマってました。
`mass: 0`なので物体は動かないが、跳ね飛ばす力は作用してしまうっぽい。

# 参考サイト
 - [CANNON.jsでContactMaterialを使う - Qiita](https://qiita.com/edo_m18/items/9b5c86ca2a781b066fab)
 - [物理エンジン cannon.js の使い方（コードの書き方）で悩んでます。どなたか、お助けくださいませ。（->解決しました） - Qiita](https://qiita.com/yamazaki3104/items/01215c9c4db4d9eac123)
 - [Three.jsとCannon.jsを使ってだるま落としをつくってみた | 株式会社ジュニ](https://junni.co.jp/release/56/)
 - [複合形状の物体を物理演算の世界に持ち込む (CANNON.js + THREE.js) - Qiita](https://qiita.com/kob58im/items/2c845c0296caa74aee9b)
reactの勉強1 -reducerを使って入力欄をつくる-

###はじめに
reactの勉強をするので、記録を残す。
今回は以下の「12.イベントの状態遷移を管理する」を見ながら勉強している。
https://www.udemy.com/share/101tSGB0cYcFZVQnw=/

###覚えておくことリスト
State…状態
Store…Stateの保管場所
Action…状態の更新を指示する
Dispatch…ActionをStoreに送る
Reducer…Actionの指示に応じてStateをどうこうする

###やりたいこと
幽霊屋敷の生存者リストを作成する。
幽霊屋敷の生存者を追加したり、削除したりいろいろ。

###やったこと

```src/reducers/index.js
const events = (state = [], action) =>{
  switch (action.type) {
    case 'ADD_PEOPLE':
      const people = { name: action.name, body: action.body }
      const length = state.length
      const id = length == 0 ? 1 : state[length - 1].id + 1
      return [...state, { id, ...people }]
    case 'LEAVE_PEOPLE':
      return state
    case 'LEAVE_ALL_PEOPLE':
      return []
    default:
      return state
  }
}
```

`events`というコンポーネントを作成する。
このコンポーネントでは幽霊屋敷の訪問者の状態を 

* 追加する（`case 'ADD_PEOPLE'`）
* 消える（`case 'LEAVE_PEOPLE'`）
* すべて消える（`case 'LEAVE_ALL_PEOPLE'`）
* 現状（`default`）

という四種類のタイプで定義する。

```src/components/App.js
const App = () => {
  const [state, dispatch] = useReducer(reducer, [])
  const [name, setName] = useState('')
  const [body, setBody] = useState('')

  const addPeople = e =>{
    e.preventDefault()
    dispatch({
      type: 'ADD_PEOPLE',
      name,
      body
    })
    setName('')
    setBody('')
  }

  return (
    <div className="container-fluid">
      <h4>幽霊屋敷の生存者作成</h4>
      <form>
        <div className="form-group">
          <label htmlFor="formPeopleName">訪問者名</label>
          <input className="form-control"
                 id="formPeopleName"
                 value={name} 
                 onChange={e =>
                 setName(e.target.value)} />
        </div>

        <div className="form-group">
          <label htmlFor="formPeopleBody">訪問者のプロフィール</label>
          <input className="form-control"
                 id="formPeopleBody"
                 value={body}
                 onChange={e =>
                 setBody(e.target.value)} />
        </div>

        <button className="btn btn-primary" onClick={addPeople}>上記の人物が屋敷に訪れる</button>
        <button className="btn btn-danger">すべての人間が姿を消す</button>
      </form>

      <h4>生存者一覧</h4>
      <table className="table table-hover">
        <thead>
          <tr>
            <th>ID</th>
            <th>生存者名</th>
            <th>プロフィール</th>
          </tr>
        </thead>
      </table>
    </div>
  )
}
```

`addPeople`というコンポーネントを定義し、ここで`src/reducers/index.js`で定義した訪問者の追加（`ADD_PEOPLE`）を利用して入力欄（人物名/人物のプロフィール）に追加したい訪問者の情報を入力する部分まで定義する。

※ ここまでの段階では追加ボタンをクリックしても生存者一覧に表示することはできないが、実際に入力した内容が渡っているかどうか確認したい場合は`addPeople`内で`console.log`を使って確認できる。

```
const addPeople = e =>{
    e.preventDefault()
    dispatch({
      type: 'ADD_PEOPLE',
      name,
      body
    })
    setName('')
    setBody('')

    console.log({ name, body })
  }
```

![スクリーンショット 2021-01-03 14.59.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555473/24e53eb3-be85-c780-836a-44ddedcfa045.png)

![スクリーンショット 2021-01-03 15.00.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555473/4e7f3d76-620d-3f1b-fbb2-d366c238a2dc.png)


正直reactのことはよくわかっていない。このStateやらDispatchやらもなんとなくの感覚でつかってみたがやっぱりよくわかっていない。この先どうなってしまうのか
p5.js入門記 -その１雪を降らせる-

# はじめに
p5.jsの入門を終わらせた後、実際に作品を作っていこうという記事です。
探り探りですが書いていこうと思います。

# 入門時に参考にしたもの一覧
+ [ドットインストール](https://dotinstall.com/) p5.js入門
+ [paizaラーニング](https://paiza.jp/works) JavaScript入門編
+ [p5.js公式サイト](https://p5js.org/)
+ [p5.js で様々なパターンを描画してみた](https://qiita.com/Haruka-Ogawa/items/8ecb8692bf7455e7f124)

# 雪を降らせる
冬なので雪を降らせてみたいと思いました。

【参考】

+ 公式サイトのサンプル: [Snowflakes](https://p5js.org/examples/simulate-snowflakes.html)
+ 公式サイトのサンプル: [Load and Display Image](https://p5js.org/examples/image-load-and-display-image.html)

【使用素材】
by いらすとや

+ [雪が降る住宅街のイラスト（背景素材）](https://www.irasutoya.com/2018/08/blog-post_202.html "雪が降る住宅街のイラスト（背景素材）")
+ [雪の中で遊びまわる子供達のイラスト](https://www.irasutoya.com/2014/01/blog-post_4063.html "雪の中で遊びまわる子供達のイラスト")

# 成果物
![snow2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/289055/c5d65925-5392-629f-5b7a-34f90969370d.gif)


# コード
雪部分はほぼサンプルコード通りですが、粒の大きさなど適宜調整しました。

```js:sample.js
let snowflakes = []; // array to hold snowflake objects
var bg;
var img;

function setup() {
  createCanvas(720, 400);
  fill(240);
  noStroke();
  bg = loadImage("bg_snow_jutaku.jpg");
  img = loadImage("kids_hashirimawaru_snow.png");
}

function draw() {
  image(bg,0,0);
  image(img, width/3, 80, img.width/2, img.height/2);

  let t = frameCount / 60; // update time

  // create a random number of snowflakes each frame
  for (var i = 0; i < random(10); i++) {
    snowflakes.push(new snowflake()); // append snowflake object
  }

  // loop through snowflakes with a for..of loop
  for (let flake of snowflakes) {
    flake.update(t); // update snowflake position
    flake.display(); // draw snowflake
  }
}

// snowflake class
function snowflake() {
  // initialize coordinates
  this.posX = 0;
  this.posY = random(-50, 0);
  this.initialangle = random(0, 2 * PI);
  this.size = random(6, 12);

  // radius of snowflake spiral
  // chosen so the snowflakes are uniformly spread out in area
  this.radius = sqrt(random(pow(width / 2, 2)));

  this.update = function(time) {
    // x position follows a circle
    let w = 0.6; // angular speed
    let angle = w * time + this.initialangle;
    this.posX = width / 2 + this.radius * sin(angle);

    // different size snowflakes fall at slightly different y speeds
    this.posY += pow(this.size, 0.5);

    // delete snowflake if past end of screen
    if (this.posY > height) {
      let index = snowflakes.indexOf(this);
      snowflakes.splice(index, 1);
    }
  };

  this.display = function() {
    ellipse(this.posX, this.posY, this.size);
  };
}
```

# おわりに
また次回、よろしくお願いします！
 
+ [-その２Flaskにp5.jsの画像を載せる-](https://qiita.com/akihanari/items/5676b5bf8eb9bad1bb1d)
【Jenkins：Mac】Deploygateにアップロード

# 概要
androidやiosのビルドしたアプリのパッケージをdeploygateにアップロードしたい

アップロードとかめんどくさい印象あるけどdeploygateは結構簡単にいけます
というかdeploygate側のリファレンスが色々と分かりやすく書かれています
https://docs.deploygate.com/reference#deploygate-api

ちなみにdeploygate側のアカウント作成とかは端折るので作っておいてください
deploygateのアカウント設定のページの一番下あたりにある「API Key」を後程使用します

Jenkinsバージョン：2.270
deploygate-plugin：1.2
※Jenkinsとプラグインのバージョンが異なると動作しない可能性があります

# 1. プラグイン追加

まず最初に
Jenkinsの管理 > プラグインの管理 > 「利用可能」タブ
から「deploygate-plugin」を探してインストールしてください
再起動は不要だと思うので「install without restart」でインストール

# 2. スクリプト作成

いつも通りPipelineで作成します
適当にジョブ作ってPipelineScriptに下記を記述

```:コード
node
{
    stage ("upload")
    {
        sh '''
        curl \
        -F "token=[トークン]" \
        -F "file=@${WORKSPACE}/sample/sample.apk" \
        -F "message=${UPLOAD_TEXT}" \
        https://deploygate.com/api/users/[ユーザー名]/apps
        '''
    }
}
```

deploygateのリファレンスにも載ってますがざっくり説明すると

**token**
deploygateのアカウント設定のページの一番下あたりにある「API Key」を[トークン]にコピペしてください

**file**
アップロードするファイルです
多分アプリをビルドしてこの処理を呼ぶことになると思うんですが
その時に作成したファイルのパスを書いてください
※例ではファイル名はandroidの例でapkにしてるけどiosの場合はipaです

**message**
deploygateにアップロード時の説明です
これは固定テキストというは微妙なので
例のようにJenkinsのビルドパラメータで設定して呼び出す形の方がいいと思います

最後にアップロードするパスです
[ユーザー名]に自身のアカウントのユーザー名を記載してください

# 3. ビルド

ビルドすると
deploygateでこんな感じで更新情報が追加されるはずです
![deploygate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/1898fc67-7153-2b9b-1ccd-02992ead564f.png)
Ansible初期セットアップ

## 前提
- クライアント： AnsibleはMacにインストール済(ansible 2.10.2)
- サーバー： VagrantのUbuntu2004の基本的な構築をansibleを使って行うことを想定してます

## 初期セットアップ
1 logの出力先を準備

```
$ mkdir logs
```

2 ansible.cfgファイルの作成

- **remote_user**: ansibleを実行するユーザの指定
- **remote_port**: defaultは22番ポートだが、今回はvagrant起動時に指定された2222番ポートを使用するため設定
- **private_key_file**: ansibleユーザのkeyを指定
- **gathering**: ターゲットノードのデータ取得方法の指定
- **host_key_checking**: SSH接続時に公開鍵のフィンガープリントをチェックを行うか否か
- **log_path**: ansible実行時のログの出力先を指定



```diff
diff --git a/ansible.cfg b/ansible.cfg
index 0440d48..3b83cfc 100644
--- a/ansible.cfg
+++ b/ansible.cfg
@@ -1 +1,8 @@
 [defaults]
+
+remote_user = ansible
+remote_port = 2222
+private_key_file = /Users/tshu1/.ssh/id_ed25519_ansible
+gathering = smart
+host_key_checking = False
+log_path = /Users/tshu1/ghq/github.com/tshu1/ubuntu-2004/logs/ansible.log
```

3 inventoryファイルの作成

```
$ mkdir inventory

$ vim inventory/vagrant

[ubuntu]
localhost 
```

4 ansible-galaxyコマンドでｒoleを作成

```
$ ansible-galaxy role init base

$ tree
.
├── README.md
├── Vagrantfile
├── ansible.cfg
├── base
│   ├── README.md
│   ├── defaults
│   │   └── main.yml
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   │   └── main.yml
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   ├── tests
│   │   ├── inventory
│   │   └── test.yml
│   └── vars
│       └── main.yml
├── inventory
│   └── vagrant
└── logs
    └── ansible.log
```


5 接続確認

```
$ ansible -i inventory ubuntu -m ping
localhost | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
```
ルーティング実践（Laravel）

# はじめに

今回はルーティング記述しついで対応するコントローラとメソッドをコマンドで作成するところまで、軽く基本をおさらいします。


## ルーティングとは

ルーティングとは〜にアクセスされたら〜コントローラーの〜アクションメソッドを実行する、という処理の流れを表すものです。

routes/web.phpにRouteファサードを使って記述します。たとえば
`Route::get('/user', 'UserController@index');`
getメソッドを使うとこんな感じです。処理の流れとしては、/userにアクセスされた時、UserControllerコントローラのindexアクションメソッドが実行されます。

Route::get
Route::post
Route::put
Route::patch
Route::delete

などが同様に使えます。

書式は以下の通り
Route::get('path', クロージャ); // クロージャの中にpathに対応する処理を書く
Route::get('path', 'コントローラ名@アクション名');


## ルーティングを記述

実はLaravelでは、よく使われる機能のルーティング（CRUDルーティング）をひとまとめにしたメソッドがデフォルトで用意されています!

`Route::resource` を`laravel/routes/web.php`に追加すると下記７つの処理を定義するルートが全て登録できます！


- 一覧表示（index）
- 個別表示（show）
- 登録画面表示（create）
- 登録処理（store）
- 更新画面表示（edit）
- 更新処理（update）
- 削除処理（destroy）

ためしてみましょう。

```laravel/routes/web.php
<?php

Auth::routes();
Route::resource('/articles', 'ArticleController'); //この行を追加
```

下記コマンドでルーティングが追加できたか確認・・

```
$ php artisan route:list
```

追加できてる！！

```
+--------+-----------+-------------------------+------------------+------------------------------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                                                 | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------------------------------+------------+
|        | POST      | articles                | articles.store   | App\Http\Controllers\ArticleController@store    登録処理                       | web        |
|        | GET|HEAD  | articles                | articles.index   | App\Http\Controllers\ArticleController@index    一覧表示                       | web        |
|        | GET|HEAD  | articles/create         | articles.create  | App\Http\Controllers\ArticleController@create   登録画面表示                       | web        |
|        | DELETE    | articles/{article}      | articles.destroy | App\Http\Controllers\ArticleController@destroy  削除処理                       | web        |
|        | PUT|PATCH | articles/{article}      | articles.update  | App\Http\Controllers\ArticleController@update   更新処理                       | web        |
|        | GET|HEAD  | articles/{article}      | articles.show    | App\Http\Controllers\ArticleController@show     個別表示                       | web        |
|        | GET|HEAD  | articles/{article}/edit | articles.edit    | App\Http\Controllers\ArticleController@edit　　　更新画面表示
```



{article}の部分には更新対象とするArticleモデルのid
例えば、idが3である記事の更新画面を表示するURLは、開発環境では`localhost/articles/3/edit`となります。



## コントローラーとメソッドも作る

`php artisan make:controller ArticleController --resource`で対応するコントローラとメソッドを自動生成！

## まとめ

今回はルーティング記述しついで対応するコントローラとメソッドをコマンドで作成するところまで。最近はLaravelを触りたくてしょうがないです。また投稿します。
JestでdataProviderを使う

# やりたいこと
Jestでテストをする際に、テスト内容は同じで与えられるデータだけが異なる場合に、重複した処理を書かずに済ませたい。

PHPUnitでテストを書いている時に使ったことのある、data providerという仕組みがJestにもないか調べてみた。

# 実装
以下のように、`describe.each()`を使えばdata providerと同じようなことができる。

```javascript
interface Datum {
  hoge: string,
}

const data: Datum[] = [
  {
    hoge: 'hoge'
  },
  .
  .
  .
]

describe.each(data)('hogeのユニットテスト', (datum: Datum) => {
  const { hoge } = datum

  it(`${hoge}の場合。`, () => {
    // テストの実装
  })
})

```

# 参考記事
[Using data provider pattern for javascript unit tests](https://medium.com/@sergioviniciuss/using-data-provider-pattern-for-javascript-unit-tests-1965ff8478ba)
ゼロから学ぶスパイキングニューラルネットワークをリリースしました

# ゼロから学ぶスパイキングニューラルネットワーク
というサイトを作りました！

👉 [ゼロから学ぶスパイキングニューラルネットワーク](https://snn.hirlab.net)

SNNの啓蒙活動的な感じですが，半分は自己満です．笑
誰かしらの役に立ったら幸いです．

軽量なサイトを目指して作成したので，ストレスなく読めると思います．

# 対象者
* これからSNNを研究分野にしようとしている人
* 神経回路をモデル化してシミュレーションしようとしている人
* 新世代のAIモデルについてそれなりに詳しく知りたい人
* 暇つぶしの読み物を求めている理系の人

# コンセプト
* この研究分野に興味を持ってもらうこと
* SNNの知名度をあげる
* SNN研究の導入となるような内容を提供する
* 実装方法の一例も紹介する

# コード
サイトでは所々に実装例をPythonで挙げていますが，それらのコードはGithubにて掲載していますので，必要な方は活用してください！

[HiroshiARAKI/snn_from_scratch](https://github.com/HiroshiARAKI/snn_from_scratch)

宣伝記事ですみません...
Android11にしたらテザリングが使えなかった話(楽天モバイル)

#特になんでもない書き出し

愛用のGalaxyNote20Ultra(SIMフリー版)に、
年明け早々にAndroid11のリリースがあった

WindowsUpdateでもそうなのだが、とりあえず最新がリリースされたら速攻で最新にしちゃう派なのだが、
まあいつも大体痛い目にあう。
例に漏れず今回も不具合というか「おや？」ってなったので紹介

#Google先生は全知全能
表題の通りアップデートしたらテザリングが使えなくなったのだ。
楽天モバイルの契約を行っており、使い放題よろしくテザリングでいろんな端末をじゃんじゃか繋いでいるのだが、
どの端末も「ネットワーク接続なし」と表示されるのだ。
テザリングはONになっていて、端末側もアクセスポイントへ接続できているのだが「ネットワーク接続なし」とのこと…

なんでや……

調べると一瞬で出た。
さすがGoogle

#原因は楽天モバイルのAPNタイプ
どうやら「APNタイプ」とやらの設定が悪かったようだ
楽天のSIMを初めて指したときは特になんの設定もしていなかったのだが、Android11にしたことによって何やら変わってしまったようだ。

下記の記事を参考に接続中のAPNの「APNタイプ」を「default,dun」に変えて再起動したら問題なくテザリングが行えた
https://shizuoka-bunka.jp/android10-tethering/

#よくあるあとがき
みんなもテザリングで接続した端末のネットワークが「インターネット接続なし」のときはテザリングしている端末のAPNタイプを確認してみてほしい。
MacでZIPファイルを展開できない時の対処方法

MacでZIPファイルを展開しようとすると、
「エラー79 ファイルタイプかフォーマットに誤りがあります」
といった文章が出てきてファイルを展開できない、ということがありました。

その解決策をメモしておきたいと思います。

# 解決方法
①：まず、Macでターミナルを開く。
②：展開できないZIPファイルを置いているディレクトリまで、cdコマンドで移動
③：「unzip 展開できないファイル.zip」というコマンドを実行

```none:ターミナル
% unzip 展開できないファイル.zip
// 結果
Archive:  展開できないファイル.zip
  inflating: ○○
  inflating: ××
  ...
```

これでZIPファイルが展開されます。
念の為、Finderからもファイルが解凍されているか確認してください。

# 参考
こちらのサイトを参考にさせていただきました。
https://itojisan.xyz/trouble/13743/

ありがとうございました。
BeautifulSoup use cases

#  Use case 1 : read anchored links of interest from a url
I have a url of an html page that contains links to various courses. I am interested in extracting href links of courses only.

## Problem solution outline

1. The url is https://www.jdla.org/certificate/engineer/#certificate_No04
2. First I will read the url and save raw html text in a variable
3. Then I will instantiate BeautifulSoup, using its instance I first get the list of ```div``` blocks with a class ```wp-block-group``` 
4. Finally I will parse each ```div``` block and extract ```href links```

## Problem solution code

```python
import requests
from bs4 import BeautifulSoup

url = "https://www.jdla.org/certificate/engineer/#certificate_No04"

res = requests.get(url)
html = res.text

soup = BeautifulSoup(html, 'lxml')

divs = soup.find_all('div', attrs={'class':'wp-block-group'})
preliminary_links = [div.find_all('a') for div in divs]

# preliminary_links is in the form of list of lists. Moreover some lists are empty. We will flatten it and get rid of empty lists simultaneously

import itertools

flat_links = list(itertools.chain.from_iterable(preliminary_links))

# Finally I have got list of links I am interested in. Now I will extract their href attributes and text

links = [(link.get_text(),link.get_attribute_list('href')) for link in flat_links]

# extract actual href from list of lists
clean_links = [(title,href_list_of_list[0]) for (title,href_list_of_list) in links]
links_df = pd.DataFrame(columns=['title','link'], data=clean_links)
```

# Use case 2 : parse non-basic http auth password protected url 
## Problem
Some URLs are password protected and can not be accessed by basic http auth. Meaning you can not access them with below code

```python
import requests
from requests.auth import HTTPBasicAuth
res=requests.get(url,auth=HTTPBasicAuth('<username>','<password>'))
html=res.text
soup=BeautifulSoup(html,"lxml")
```
In such cases, you can leverage session as below
The keys in data should match ```input.name``` value of the form of the specific url you are trying to access.

```python
s=requests.Session()
data={"u":"<username>","p":"<password>"}
res=s.post(url,data=data)
html=res.text
soup=BeautifulSoup(html,"lxml")
```
CPI サーバーで concrete5 CLI を使えるようにする方法



## SSH でログイン

CPI サーバーに SSH でログインできるよう設定する

## PHP コマンドを使えるように設定ファイルを作成

.cshrc ファイルに PHP コマンドで PHP7.2 が起動するようにする

```
$ cd
# 旧サーバープランの場合
$ echo alias php php-7.2  >> .cshrc
# シェアードプラン Business Standard の場合
## PHP 7.4
echo alias php /usr/local/bin/php-7.4 >> .cshrc
## PHP 8.0
echo alias php /usr/local/bin/php-8.0 >> .cshrc
## PHP 8.1
echo alias php /usr/local/bin/php-8.1 >> .cshrc
# 変更を反映させる
source .cshrc
```

## SSH ログアウト&再ログイン

一旦、SSH をログアウト

```
$ exit
```

再度ログイン

## 動作確認

PHP バージョンコマンドでうまく行ったかを確認

```
$ php -v

PHP 7.2.20 (cli) (built: Jul  8 2019 17:55:27) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
```

## concrete5 CLI コマンドの実行方法

あとは、CLI コマンドを実行する前に php を必ずつけて実行します。

```
$ cd [concrete5 サイトのあるパス]
$ php concrete/bin/concrete5 [コマンド]

# 参考: 環境情報を出力する
$ php concrete/bin/concrete5 c5:info

```

## 設定を変更する場合

`.cshrc` テキストファイルに php コマンドだったら上記のコマンドを叩くという設定を加えているので、PHPバージョンの変更などをする際は、`.cshrc` テキストファイルを開いて中身を編集します。


## 参考情報

参考
https://mi-rai.co.jp/blog/876
https://support.cpi.ad.jp/manual/bs/tools/sshkeys
AWS　コンピューティング

#AWS　コンピューティング
##EC2
　サイズ変更可能な仮想マシン（EC2インスタンス）をクラウド提供するサービス
###Amazonマシンイメージ（AMI）
　EC2を起動する際に必要なテンプレートがインストールされている
　逆に、自分で設定したEC2レシピも保存しておくことが出来る
 
###インスタンスタイプ
　EC2起動時に設定するもの、提供したいサービスの容量により変更可能
 
###セキュリティグループ
　ホワイトリスト形式（この通信はOK,NGと記述したリストで判断する形式）で制御される
　そのためELB,RDS,ElasticCacheなんかも記述すれば設定できる（なんやそれ！！後述します）
##ELB（Elastic　Load　Balancing）　厳密にはELBのALB
※GW　←　ELB（ALB）　←　アプリ{パブリックサブネット（NATGW）←プライベートサブネット}
　アクセス数に対して不可のバランスを複数のEC2に分散させる
　もし1台のEC2だけでサイトを運営していた場合、サーバー障害が起きたら復旧まで何も出来ません。
　ただし複数のEC2でサイトを運営していたら、1つに障害が起きても切り替えればOKということになります。
　1つのEC2だけでなく、アクセスに応じてサイトアクセスのバランスをとってくるれる機能です
###ELBは3種類
　・ALB（アプリケーション・ロードバランサー）：HTTP/HTTPSに対応した不可分散
　・NLB（ネットワーク・ロードバランサー）　　：TCP/UDPに対応した不可分散
　・CLB（クラシック・ロードバランサー）　　　：元ELBと呼ばれてましたが、ALBが出来たので名称変更

###EC2　AutoScailing機能
　EC2のCPU使用率を監視し閾値を超えたら、自動的にELBの下にインスタンスを自動追加できる機能
##ECS（Amazon　Elastic　Container　Service）
例）1社がサービスを3つ持っている、そのサービスにつきEC2が複数あるような状態となっている
　　1個1個EC2を見て管理できますか？出来ませんよねと言う理由から生まれたECS
　　従来1つのサーバーに複数の機能を持たせていたが（メッセージ機能、コメント機能的な
   Rilsでいうモデルを1つのファイルにまとめている状態）、があまりにも膨大になったことで、
   クラウド技術で機能を分割（コンテナ化）して、ダメだったら捨てて、次にいきましょう（アジャイル化）
   ということで使用されている。
   そう言う観点から見ると、私のPFは旧来のサーバーを、AWSのEC2に置き換えてアプリが置いている状態
   （このアプリの中に継ぎ足しをしている）と言える。
　　より実戦として考えたら、EC2インスタンスを機能ごとに増やさなければいけない。
  
###ECS
　ECSクラスターをベースに、その上にECSインスタンス、その上にDockerコンテナを実行・停止が出来るサービスとなっている
　ECSインスタンスは、{EC2を含む + Dockerコンテナ（アプリの概要）=タスク}を生み出せる
　もう1個1個設定しなくてもECS様がやってくれる 
  ただし上記の動作を一発で解消してくれるためには、タスク定義をしなければいけない（初見殺し、ここで皆散っていきます）
  
###ECR(Elastic Container Registory（レシピ）)
　AWS版のDockerhub(Dockerレジストリ＝コンテナの保管場所)
　ローカルで作ったDockerイメージをpushすると保存、pullして保存した内容を引き出してくれる（DockerコマンドでOK）
 
###Fargate（どちらもECSを使う、EC2タイプ？Fargateタイプ？の違いだけ）
　ECSを使用してEC2を使う＝ECS(1つのECSインスタンスの中にEC2があり、設定が必要) 
　ECSを使用してEC2を使わない＝Fargate（EC2部分の設定が不要で、コンテナあればOK）
　※インフラ部分はAWSで補います！ということ
###EKS（同じくコンテナオーケストレーションサービスのkubernetes用）
　ECS同様にFargateタイプも選択することが出来る
【Word VBA】PDF形式で保存するマクロ

# WordファイルをワンクリックでPDF保存する
WordファイルをワンクリックでPDF保存するマクロを作りました。
PDFファイルは開いたWordファイルと同じ場所に保存されます。

## ソース
```vb
Option Explicit

Sub SavePDF()
    Dim FilePath As String
    FilePath = ActiveDocument.Path + "\"
    
    Dim Buf As Variant
    Dim FileName As String
    Buf = Split(ActiveDocument.Name, ".")
    FileName = Buf(0) + ".pdf"

    ActiveDocument.ExportAsFixedFormat _
        OutputFileName:=FilePath + FileName, _
        ExportFormat:=wdExportFormatPDF, _
        OpenAfterExport:=False, _
        OptimizeFor:=wdExportOptimizeForPrint, _
        Range:=wdExportAllDocument, _
        From:=1, _
        IncludeDocProps:=True, _
        BitmapMissingFonts:=True
End Sub
```

## 設定方法
1\. Microsoft Wordを起動し、何かしらの文章を開く（空白の文章でもOK)

2\. Alt + F11キーを押し、Visual Basic Editorを開く

3\. Normalの標準モジュール(赤枠部）で右クリック → 挿入 → 標準モジュール
![image0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223372/f6ae36f8-54aa-5bea-fa3e-1f9e4371753e.png)

4\. 追加したモジュールにソースをコピペ
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223372/ac59c562-6e32-9954-8b3d-0b5a3d05a254.png)

5\. ファイル → オプションからWordのオプションを開く
クイックアクセスツールバーのカスタマイズ画面を開き、
① コマンドの選択をマクロにする
② 今回作成したマクロを選択する
③ 追加を押す
④ 追加されたものを選択し、変更ボタンを押す。アイコンと名前を変更する
⑤ アイコンと名前が変更されたものになったことを確認する
⑥ Word上部にPDF保存ボタンが追加される
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223372/5fd1e910-c61c-d9db-80cf-35acb337b481.png)
「え！？いつのまに新刊出てたの！？」を解消するアプリを作りました【ポートフォリオ解説】

# はじめに
実務未経験者がどうやって・どんなポートフォリオを制作したのか
ポートフォリオの解説→意識したこと・苦労したことの順で解説します。

よければ読んでみてください

# コンセプト
### 「え！？いつのまに新刊出てたの！？」を解消する

**好きなマンガや小説など・好きな作家を登録しておくと新刊の発売3日前にメールでお知らせします**
ちなみにアプリ名はブクシルです。「ブック」+「(新刊の発売を)知る」ですね。
我ながら気に入ってます。寒くないです。だれですか寒いって言ったの。

# 使用イメージ
### 書籍の検索ができます(楽天API使用)
![search](https://user-images.githubusercontent.com/67740063/103458229-60633d80-4d49-11eb-841b-fb739ee2a575.gif)

### お気に入り登録ができます(作品のシリーズと作者名)
![favorite](https://user-images.githubusercontent.com/67740063/103458272-c223a780-4d49-11eb-9bd4-33858b43726a.gif)

### 発売3日前にメールでお知らせします
![output_0000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680176/ec13a4d2-8415-5c5e-e343-fe5cbc15aad9.png)

# 開発背景
**せっかくポートフォリオをつくるんだったら、だれかの役に立つものが作りたい**と思い、以下の流れで作り始めました

1. 周囲の知人・友人に「どんなサービスがあったら便利か」「日常生活で不便に感じていることはないか」とヒアリング
2. 「気づいたら新刊が発売されていることがあるから事前に知りたい」との意見を聞く
3. 自分自身、読書が趣味で同じ悩みを持っていたこともあり、それを解決できるアプリを作りたいとの想いで製作開始

# 使用技術
**フロントエンド**
HTML/CSS(Sass)
Bootstrap 4.5.2
jQuery 3.5.1

**バックエンド**
Ruby 2.6.6
Ruby on Rails 6.0.3.3

**API**
楽天書籍ブックスAPI、楽天ジャンル検索API

**RDBMS**
PostgreSQL 13.1

**インフラ**
AWS(VPC・EC2・RDS・IAM・Route53・ACM)
独自ドメイン
HTTPS化

# DB設計
一番苦労したのがDB設計です。
開発前に軽くER図を作ってからスタートしましたが、当初の構想ではうまくリレーションできず、何回も作り直すことになりました。
最終的に下図の通りになりました。
![booksiru_ER_diagram](https://user-images.githubusercontent.com/67740063/103469627-a7cde600-4daa-11eb-9292-b1c3909cd658.png)

# 開発で意識したこと
### 1. エラー解決方法
実務に入ったときに先輩社員や上司の時間を無駄に奪うことにならないように
**まずは自分の力で解決する**ことを強く意識しました。
具体的には、前後することもありますがおおよそ次の順番です。

1. エラーメッセージやログをよく読む
2. 処理のどの段階でエラーが出ているか推測する
3. bindnig.pryでデバッグする
4. エラー内容を検索する。(なるべく一次情報から読み解くことを意識。)
5. どうしても解決できなければメンターの方に質問する

### 2. 質問の仕方
Slackを使ってだいたい以下の構成で質問していました。
**なるべく少ないやり取りで済み、相手の人の時間を無駄に奪わない内容にすることを意識しました。**

1. やりたいこと・困っていることを端的に表現
2. 自分なりに試したこと (書いたコード・コマンド)
3. 試した結果 (エラーメッセージ)
4. <font color="LightSlateGray">わからないなりに怪しいと思っている部分を述べる  
・・・違っている場合にメンターの方から意見を頂ける  
→理解が深まり、以降の質問を減らせる</font>
5. GitHubのソースコードを記載・・・思わぬところにエラーの原因があることも多いため

**実務において1人でずっと悩み続けることはかえって損失になってしまうと思うので
上記の方法である程度(15~30分？)独力でやって解決できなかった場合には、端的かつ過不足ない内容で質問することで時間的な損失を最小限にすることを心がけていきたいと思います。**

### 3. 模擬チーム開発
実務を想定して模擬チーム開発を意識しました。
・ Git, GitHubを用いたソース管理
・ 必要要件をIssuesに列挙し、タスク消化
・ featureやfixのブランチを切ってプルリクベースで開発

ただ、Issuesはプルリクと結びつけられると後で知ったので、使い方が甘かったなと反省しています。

# 開発で特に苦労したところ
**DB設計**
上でも述べましたが一番苦労しました。
リレーションについてわかったつもりでも、いざ自分のアプリに落とし込むとなるとうまくいかず、何度も紙に書いては関係性を整理しました。

**楽天書籍ブックスAPIの適用**
公式ドキュメントだけではどう扱うのかのイメージがつかず、調べた限りでは使用例も少なかったです。
少ない情報の中からどう自分のアプリに落とし込むのか、使用例からどこが一般化できるのか、実際にコードを書きながら試行錯誤を繰り返しました。

# 感想
**エラー解決がめちゃくちゃ楽しい。**
**エラーを乗り越えたときに両手を突き上げるほど興奮した**ことが何回かあります。
ゲームで強いボスを倒したときみたいな感じですね。
負けては次の手を考え実行する、を繰り返して最終的に勝つみたいな。

プログラミング学習をはじめたころはエラーが怖かったと思うのですが、成長したのかなあと。
あとは仮設と検証を繰り返す作業が現職の研究業務と似ているなあと思ったりしていました。

# 課題/今後実装したいこと
やりたいことはまだ残っているので、ひとつずつ良くしていきたいと思います。

・レスポンシブWebデザイン(スマホ対応)
・お気に入り登録/解除時にフラッシュ表示➡実装済み
・お気に入り登録/解除時の非同期処理
・LINEログイン
・LINEのMessaging APIを使用してLINEで通知

# さいごに
長い文章をここまで読んでくださってありがとうございました
良かったと思った方は<font color="#55c500">LGTM</font>して頂けると嬉しいです！
どなたかの参考になれば幸いです！
ElectronアプリでKeycloakと連携(2. Electronアプリの作成編)

# 背景

前回、keycloakの設定まで実施した。今回は認証機能を導入するElectronアプリを実装してみる。
https://qiita.com/yusuke-ka/items/69d4146f344a95aa4662

Auth0のブログで公開されているやり方が安全そうな気がするので、ここを参考にしてやってみようと思う。
https://auth0.com/blog/securing-electron-applications-with-openid-connect-and-oauth-2/

といっても、今回は単純なElectronアプリを作るだけで、認証回りは次回。

# 準備

まずは、プロジェクトの作成から。

```terminal
> mkdir electron
> cd electron
> yarn init
```

initはすべてデフォルトのまま。

続いて依存のインストールを実施する。

```terminal
> yarn add electron --dev
```

Electronのインストールだけ。少し時間がかかった。

# Electronアプリの作成

最初に、アプリのホームページを作ってみる。

renderersというフォルダを作り、その下に以下のようなファイル(home.html)を作成する。

```renderers/home.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Electron App</title>
  </head>

  <body>
    <p>Home</p>
    <button id="logout" class="btn">Logout</button>
  </body>

</html>
```

直接ブラウザでhome.htmlを読み込んだ際の見た目はこんな感じ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/25c51cf8-44f3-6d8b-2d61-937e5055a90a.png)

テスト用なので、Homeという文字とログアウトボタンだけを配置したシンプルなホームページ。
もちろん、ログアウトボタンを押しても何も起こらない。

続いて、このページをElectronで表示するようにしてみる。

今度はmainというフォルダを作成し、その下にapp-process.jsというファイルを置く。

```main/app-process.js
const { BrowserWindow } = require("electron");

function createAppWindow() {
  let win = new BrowserWindow({
    width: 1000,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      enableRemoteModule: true,
    },
  });

  win.loadFile("./renderers/home.html");

  win.on("closed", () => {
    win = null;
  });
}

module.exports = createAppWindow;
```

**nodeIntegration: true**は、Node.jsの組み込みを実施するための設定。
**enableRemoteModule: true**は、レンダラープロセスがメインプロセスと通信するための設定。 

createAppWindowというfunctionをexportして公開している。

続いて、ルートフォルダの下に、最初に呼び出されるファイル(main.js)を作成する。

```main.js
const {app} = require('electron');

const createAppWindow = require('./main/app-process');

async function showWindow() {
  try {
    return createAppWindow();
  } catch (err) {
    // TODO 認証
  }
}

app.on('ready', showWindow);

app.on('window-all-closed', () => {
  app.quit();
});
```

今はまだ、先ほどのapp-process.jsが公開しているcreateAppWindowを呼び出すだけの実装。

とりあえず、この状態で動かしてみる。

package.jsonに以下を追記。

```package.json
  "scripts": {
    "start": "electron ./main.js"
  }
```

electronコマンドでmain.jsを呼び出しているだけ。

実行。

```terminal
> yarn start
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/3e0e16ac-3f39-ebf9-f24c-8d77b3b4f830.png)

Electronアプリとして、ホームページが表示された。

# 次回予告
ElectronアプリでKeycloakと連携したログイン機能を実装するために、今回は、確認用のシンプルなElectronアプリの実装をおこなった。

次は、いよいよElectronアプリに認証機能を導入する。
https://qiita.com/yusuke-ka/items/17a5b8fbd544c4c211a3
ElectronアプリでKeycloakと連携(1. keycloakの設定編)

# 背景

以前、Nuxt.jsでKeycloakと連携したログイン機能を実装してみた。
https://qiita.com/yusuke-ka/items/1beef8d9e0bbeb052e5a

今度はelectronアプリでKeycloakと連携したログイン機能を実装してみようと思う。

その準備として、今回は、まずkeycloakの設定をやってみる。

keycloakのインストール等は以下で実施したので、これを使う。

https://qiita.com/yusuke-ka/items/1beef8d9e0bbeb052e5a#keycloak%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97

# keycloakの設定

keycloakの管理UIにアクセスして、keycloakの設定を実施していく。

## レルム追加

最初にレルムを追加する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/f8a7823b-9adb-3c88-d054-4673f2ba9ba7.png)

「Name」を入力して、「Create」ボタンを押すだけ。

## クライアントの追加

続いて、作成したレルムの「Clients」でclientを新規作成。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/bd68a4a6-c127-5687-d43e-acb0a678b6ab.png)

右のほうにある「create」ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/2d6b1373-a1e5-3738-7012-95ce7d4bbd2a.png)

Clientの追加画面が表示されるので、「Client ID」だけ入力して「Save」ボタンを押すと、詳細設定画面に遷移する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/5fe6bde6-5633-98aa-c956-7d3cc5c6a4f5.png)

「Client Protocol」の設定は「openid-connect」のままにする。

electronアプリの場合、クライアント認証は難しそうなので、「Access Type」もとりあえず「public」のままにしておく。
(「confidencial」にすると、Client Secretや秘密鍵をクライアント側で保持する必要がでてくる。electronアプリのように、エンドユーザーのPCにインストールするようなアプリだと、これらを安全に保持するのはとても難しいと思われる。)

「Standard Flow Enabled」が有効になっていることを確認。

electronアプリから利用することを想定しているので、「Valid Redirect URIs」には、とりあえず、「 http://localhost/callback 」を設定しておく。

publicなクライアントの場合、コードの横取りに対処する必要があるとのことなので、PKCE(Proof Key for Code Exchange by OAuth Public Clients)の設定を使うようにしてみる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643184/ae3e58a7-517f-5589-60bf-aeb48f679490.png)

下の方にある「Advanced Settings」を展開すると、「Proof Key for Code Exchange Code Challenge Method」という項目が出てくる。「Plain」と「S256」が選択できるので、今回は「S256」を選択してみた。

「save」ボタンで保存する。

## ユーザーの追加

確認用のユーザーも作っておく。やり方は下記を参照(「Keycloakの設定」という項目の最後のほう)。
https://qiita.com/yusuke-ka/items/1beef8d9e0bbeb052e5a#keycloak%E3%81%AE%E8%A8%AD%E5%AE%9A


# 次回予告

electronアプリでKeycloakと連携したログイン機能を実装するために、今回は、Keycloak側の設定を実施した。

次は、electronアプリを作成する。
https://qiita.com/yusuke-ka/items/a4767c511f03b6083afc