OmniAICreator/Qiita-1.07M huggingface dataset:
railsチュートリアル第十三章 画像の検証

###画像の検証
アップロードされた画像に対する制限がないため、もしユーザーが巨大なファイルを上げたり、無効なファイルを上げると問題が発生してしまいます。この欠点を直すために、画像サイズやフォーマットに対するバリデーションを実装しましょう。

####Active Storageバリデーション用のgemを追加する
Gemfile

```
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',                      '6.0.3'
gem 'active_storage_validations', '0.8.2'
gem 'bcrypt',                     '3.1.13'
.
.
.
```
```
bundle install
```

####画像バリデーションを追加
app/models/micropost.rb

```rb
class Micropost < ApplicationRecord
# ApplicationRecordを継承したモデルが作られます
  belongs_to :user
  # userモデルとの間に「1対1」のつながりが設定
  # 割り当てる
  has_one_attached :image
  # 指定のモデルと、アップロードされたファイルを関連付ける
  # この場合はimageを指定してMicropostモデルと関連付けます
  default_scope -> { order(created_at: :desc) }
  # データベースから要素を取得したときの、
  #   デフォルトの順序を指定するメソッドです。
  # order(created_at:desc) でこのカラムの順序に指定する
  # デフォルトで最も古い投稿が最初に投稿が表示されている。
  # :desc 新しい投稿から古い投稿の順になります
  # -> ラムダ式という。
  validates :user_id, presence: true
  # presence これは存在するか
  # presenceメソッドはオブジェクトが存在すればそのオブジェクトを返し、
  #   オブジェクトが存在しなければnilを返すメソッドとなります
  validates :content, presence: true, length: { maximum: 140 }
  # 最大１４０文字まで
  validates :image,   content_type: { in: %w[image/jpeg image/gif image/png],
                                      # content_typeを検査することで画像をバリデーション
                                      # %w 配列を作る
                                      message: "must be a valid image format" },
                      size:         { less_than: 5.megabytes,
                                      # 画像の最大サイズを5 MBに制限
                                      message: "should be less than 5MB" }
end
```

###jQueryでファイルサイズをチェックする
app/views/shared/_micropost_form.html.erb

```html
.
.
.
  </span>
<% end %>

<script type="text/javascript">
// micropost_imageを含んだ要素を見つけ出し、この要素を監視しています。
  $("#micropost_image").bind("change", function() {
    var size_in_megabytes = this.files[0].size/1024/1024;
    if (size_in_megabytes > 5) {
    //  // サイズが大きすぎたら
      alert("Maximum file size is 5MB. Please choose a smaller file.");
    // メッセージを表示する 
      $("#micropost_image").val("");
    }
  });
</script>
```

####有効な画像フォーマットだけを許可する
app/views/shared/_micropost_form.html.erb

```html
 </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
  <span class="image">
   <%= f.file_field :image, accept: "image/jpeg,image/gif,image/png" %>
  　<!--app/models/micropost.rbのhas_one_attached :imageに対応する-->
  　<!--"image/jpeg,image/gif,image/png ファイルの種類-->
  　<!--複数の種類と思われる-->
  </span>
<% end %>

<script type="text/javascript">
.
.
.
```

###演習
1.
5MB以上の画像ファイルを送信しようとした場合、どうなりますか?

選択できない。
2.
無効な拡張子のファイルを送信しようとした場合、どうなりますか?

選択できない。
【AWS】RDSのまとめ

# はじめに

こんにちは。
この記事は[GFAMアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/gfamz)の５日目の記事です。
RDSについてまとめてみました。

# RDSの概要

RDSはマネージド型のリレーショナルデータベースサービスです。利用者はOSやデータベースソフトウェアを導入する必要がなく、テーブル設計やカラム設計に注力できます。アプリ開発者でもインフラの構築や管理を考える必要なくデータベースサービスを扱えます。フェールオーバー構成を手軽に作れたり、スケールアップなどが簡単に行える点も特徴です。

# RDSがサポートするエンジン

RDSでサポートするエンジンは以下があります。

* Amazon Aurora
* PostgreSQL
* MySQL
* MariaDB
* Oracle Database
* MariaDB

## Amazon Aurora

サポートエンジンの中でもAmazon Auroraは、AWSが構築したRDBです。MySQLの5倍、PostgreSQLの3倍のスループットがあります。MySQL、PostgreSQLと互換性があります。Auroraと互換性のあるRDSとではアーキテクチャが異なります。ユースケースや要件に応じて使い分けますが、詳細はまた別の機会に。

以下は、RDSの特徴の一部を記載します。

# RDSのマスターースレーブ構成

フェールオーバーの構成を手軽に作れます。マスターからスレーブへのレプリケーションは自動で行なわれます。マスターに障害が発生した場合、自動でスレーブにフェイルオーバーされます。アプリからRDSへの接続はエンドポイントで行いますので、フェイルオーバーされたとしてもアプリ側の設定変更は不要です。

# リードレプリカ

リードレプリカは、読み取り専用として構築したデータベースのことです。読み取りをレプリカで行うことによって、マスターの負荷を抑えることができます。

# スナップショット

スナップショットは、データベース全体のバックアップを取得したものです。設定により自動で実行されます。

# パッチ当て

AWSが自動でセキュリティ等のパッチを適用します。設定により自動で実行されます。

# パラメータの設定

AWSでは、設定をconfファイルではなくGUI上で行います。

# おわりに

今回はRDSをまとめました。
次回はCloudWatchについて学習します。

# 参考

* [BlackBelt](https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/)
Prefect で簡単なワークフローを構築してみた

# はじめに

python のライブラリ Prefect を少し触ってみました。
ワークフローが思った以上に簡単に構築できて良さげだったので、試したことのメモをまとめました。

# Prefect について

ワークフローを構築する python ライブラリ。

# 参考資料

- Prefect の Github : https://github.com/PrefectHQ/prefect
- Prefect API Document : https://docs.prefect.io/api/latest/

# インストール

```
pip install prefect
```

# 簡単な用語説明

超簡単な用語説明

- Task
  - 作業単位、一つのまとまった処理
- Edge
  - 2つの Task を結合したもの
  - 前段 Task の処理結果を key を媒体に次の Task に渡せる
- Flow
  - Task の集合
  - ワークフロー

今回はこれらを組み合わせて簡単なワークフローを構築してみます。

# ワークフローを構築してみる

簡単にワークフローを構築してみます。

今回はお試しで以下のワークフローを Prefect で構築してみます。

- 数値1を生成 => 10を追加 => 2倍にする => 結果の数値を print


### 書いたコード

```py
from prefect import task, Task, Flow

# Task クラスを継承してタスク定義、run メソッドにタスクで実行したい処理を定義する
class GenerateTask(Task):
    def run(self):
        print(f"=========GenerateTask===============")
        return 1

class Add10Task(Task):
    def run(self, number):
        print(f"=========Add10Task {number}===============")
        return number + 10

class DoubleTask(Task):
    def run(self, number):
        print(f"=========DoubleTask {number}===============")
        return number * 2

# @task を使った版のタスク定義
@task
def print_task(result):
    print(f"=========PrintTask {result}===============")

# Flow を作成
sample_flow = Flow(name="sample_flow")

# Task のインスタンス化
generate_task = GenerateTask()
add_10_task = Add10Task()
double_task = DoubleTask()
print_task = print_task

# Task 同士を結合した Edge を登録
# 前段の処理結果を key で次のタスクに受け渡し
sample_flow.add_edge(generate_task, add_10_task, key='number')
sample_flow.add_edge(add_10_task, double_task, key='number')
sample_flow.add_edge(double_task, print_task, key='result')

# Flow の実行
sample_flow.run()
```

### 実行結果

```
[2021-12-14 22:49:16+0900] INFO - prefect.FlowRunner | Beginning Flow run for 'sample_flow'
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'GenerateTask': Starting task run...
=========GenerateTask===============
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'GenerateTask': Finished task run for task with final state: 'Success'
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'Add10Task': Starting task run...
=========Add10Task 1===============
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'Add10Task': Finished task run for task with final state: 'Success'
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'DoubleTask': Starting task run...
=========DoubleTask 11===============
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'DoubleTask': Finished task run for task with final state: 'Success'
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'print_task': Starting task run...
=========PrintTask 22===============
[2021-12-14 22:49:16+0900] INFO - prefect.TaskRunner | Task 'print_task': Finished task run for task with final state: 'Success'
[2021-12-14 22:49:16+0900] INFO - prefect.FlowRunner | Flow run SUCCESS: all reference tasks succeeded
```

各タスクが実行され、key による値の受け渡しもできていそうです。


# まとめ

お手軽にワークフローが構築できて良さそうでした。

今回は簡単なワークフローを構築するところまでしか試せていませんが、
「複数の依存 Task がある場合の Task / Flow / Edge の定義」や「ワークフローの途中で失敗した際のリトライ処理は可能か」あたりは気になっているので、
もう少し掘り下げてみようと思います。
BitriseのGooglePlayDeploy設定方法

結構迷う事の多い設定だと思いますので、纏めておこうと思います。

まず初めに、BitriseでGooglePlayに配信する為には以下情報が必要になります。

<dl>
  <dt>・サービスアカウントのJsonキー</dt>
  <dt>・対象アプリのパッケージ名</dt>
  <dt>・配信先（内部テスト？alpha？）</dt>
</dl>

サービスアカウントの発行は[こちら](https://labs.armut.com/android-ci-cd-pipeline-with-bitrise-deploy-app-to-google-play-store-6bd95f652f8c)の記事が参考になります。

:::note warn
サービスアカウントを発行する手順ですが、アップデート等で資料とは発行手順が異なっている可能性があります。
:::


上記が準備できましたら、設定の手順に移ります。

####1. Jsonキーのアップロード
Code Signingタブの一番下の欄（画像参照）に、GENERIC FILE STORAGEという項目があると思います。

![スクリーンショット 2021-12-14 22.36.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/7cbdf3c5-91db-af6b-29f6-4a1564e680fe.png)

こちらに、取得したjsonキーをアップロードするのですが、先に任意の名称を決める必要があります。
任意の名称を決めていただいた後、アップロードすればjsonファイルのアップロードは完了です。

####2. 署名設定
アップロードする為にはまず署名する必要があります。
設定手順に関しましては、[こちら](https://qiita.com/tomo1139/items/4d081928d93cf7472357#%E7%BD%B2%E5%90%8D%E8%A8%AD%E5%AE%9A)に沿って設定頂ければ良いかと思います。

署名が完了すると、以下パラメータが取得できるようになります。

**$BITRISE_SIGNED_AAB_PATH**

上記を後ほど使用します。

####3. GooglePlayステップの設定

Android Signよりも後のステップで＋ボタンを選択し、検索窓にGooglePlayと入力します。
検索されると、GooglePlayのステップが出てくると思いますので、選択して追加します。

ステップ追加後、必要項目を設定するのですが、基本的に設定すべき項目は4つです。

#####・Service Account JSON key file path 
これは手順１で設定した名称で設定すれば問題ありません。

入力欄を選択してfilterByKeyと書かれた検索欄があるので、そこに設定した名称を入力すると検索可能です。

#####・Package name 
これはビルド対象のパッケージ名を選択してください。
事前にENV Varsタブ内のパラメータに設定しておくと、Insert Variableから選択して設定するだけなので少し楽です。

#####・App file path
どのアプリケーションを配信するか、といった設定です。
こちらは署名時に取得した以下をそのまま設定すれば問題ありません。

**$BITRISE_SIGNED_AAB_PATH**

#####・Track

これはどのトラックにアップロードするかの設定です。
あらかじめ依頼者から確認しておいたトラック情報を設定します。

ちなみに記載がありますが、選択できるのは以下4つです。

internal, alpha, beta, production

基本internalかalphaに設定することになるかと思いますが、プロジェクトの方針によるので要確認です。

以上で設定は完了です。
ビルドを実行し、問題なければアップロードされるはずです。

実行した結果、４０３や４０４が出るようでしたら、PlayConsoleやプロジェクトの設定を見直したり、手動でアップロードしてエラーが出ない状態に調整してみてください。
SORACOM サービス更新情報の裏側をご紹介します

これは、株式会社ソラコムに在籍するエンジニアによってお届けしている [株式会社ソラコム Advent Calendar 2021](https://qiita.com/advent-calendar/2021/soracominc) の 15 日目の記事です。

久しぶりの投稿なので自己紹介します。株式会社ソラコムでソフトウェアエンジニア兼プロダクトマネージャーをやっている @pachirel と申します。ソラコムのサービスローンチ当初から、ユーザーコンソールや複数のサービスの開発を担当していました。2021年からプロダクトマネージャーにジョブチェンジしたのですが、ついついコードを書きたくなってしまいます。

今日は、そんな私がプロダクトマネージャーとして最初の仕事としてやった [SORACOM サービス更新情報](https://changelog.soracom.io) についてご紹介します。「SORACOM サービス更新情報」はその名の通り、SORACOM プラットフォームが提供するサービスの更新をお届けするためのメディアです。

## SORACOM 更新情報のこだわりポイント

このサイトを準備するにあたって、こだわったのは以下の3点です。順番にご紹介します。

- 機能追加以外にも、さまざまな更新情報を掲載
- 日本語だけでなく、英語でも提供
- レビュー・記事公開プロセスの整備

### 機能追加以外にも、さまざまな更新情報を掲載

ソラコムはサービスローンチ当初から「2週間に1度のペースで機能改善などをリリースすること」に目指しています。
サービスの更新内容は[SORACOM 公式ブログ](https://blog.soracom.com/ja-jp/)に公開してきました。

今でもなるべく公式ブログに更新内容を載せるようにしていますが、いくつかの改善ポイントがありました。

まず、ブログ記事として読み応えのある内容に仕上げるために、機能リリースから記事の公開までにタイムラグが発生してしまうことがあったことです。お客様にいち早く更新内容を届けたいと思う気持ちと、記事として満足していただけるものを出したいという気持ちのジレンマが発生します。また、すべての更新内容を掲載することが、読者の期待とマッチしないのではという懸念もありました。

これらを解決するために、サービス更新情報を「タイムリーに SORACOM サービスの更新内容をお届けするメディア」として独立させることで、読者の期待を調整しつつ、公式ブログとの違いを明確にしました。
まず、サービス更新情報を掲載し、それを活用したブログ記事を後追いで公開したり、更新内容のまとめを紹介するブログ記事を作成することで両立を図っています。

「SORACOM サービス更新情報」の記事カテゴリ分けも、今後、数をなるべく増やさずにすむように工夫しました。

### 日本語だけでなく、英語でも提供

ソラコムは日本を含む 140 を超える国と地域でご利用いただける通信プラットフォームを提供しています。
そのため、ユーザーコンソールやウェブサイトは日本語と英語でご利用いただけるようになっています。

ブログの内容を英語で公開しようとすると、どうしても文量の多さから翻訳に時間がかかったり、地域によっては利用できないデバイスやサービスを使っていないかといった観点でレビューをする必要があったりします。

サービス更新情報は簡素な表現で端的に情報を伝えることをガイドラインとしています。これを多言語対応することで、言語の壁を越えて、タイムリーな情報提供が可能になりました。

### レビュー・記事公開プロセスの整備

サービス更新情報の記事は開発に関わっているエンジニアが書く運用にしています。

バックエンドには [AnnounceKit](https://announcekit.app/) を採用しました。
多言語対応や、ウェブサイトに埋め込むためのガジェット機能、GraphQL による API が提供されていたのが理由です。

AnnounceKit 上のエディタで記事を編集することもできますが、レビューしづらいので別の方法を用意することにしました。
まず、Github に記事を管理するためのリポジトリを用意しました。Markdown で書いた記事を Pull Request 上でレビュー、翻訳まで行います。それらが終わったら AnnounceKit の API を使って記事を追加するスクリプトを実行してから Pull Request をマージするようにしました。

AnnounceKit の API は HTML のみ受け付けるため、スクリプトを使って Markdown を HTML に変換しています。
記事の ID や予約公開日時、ラベルの設定は Markdown の front-matter を使って組み込みました。

この工夫によって、記事のレビュー・公開をスムーズに運用することができています。

## まとめ

今回は、SORACOM サービスの更新情報をお届けする仕組みの裏側について紹介しました。
ソラコムのプロダクト開発体制などに興味を持っていただけた方がいらっしゃいましたら、[エンジニア向け会社説明会「オープンハウス」](https://careers.soracom.jp/event)の情報もチェックしてみてください。
AutifyのWeb APIクライアントを作成しました

この記事は[Autify Advent Calendar 2021](https://qiita.com/advent-calendar/2021/autify)15日目です。

AutifyのWeb API用のクライアントライブラリを作成したの少しまとめます。
https://github.com/trknhr/autify-go

# Autifyとは
自動E2Eテスト支援ツールです。私の所属している会社で採用されているため私も業務の時間で触ることが多いです。

# このライブラリはなにをするか
Autify Web APIを直接叩く部分をラップします。ユーザーにとってはGoでAPIを呼び出してそのデータを取得するのではなく関数を呼ぶだけで該当のAPIを操作できることになります。
https://autifyhq.github.io/autify-api/#/schedule/post_schedules__schedule_id_

# なぜ作ったか

Autifyのシナリオの中身まで検索したい時がありその時に即興でWeb APIのラッパー的なのを作っていたのでそれをライブラリとして切り出しました。

# 苦労した点
## レスポンスのデータの型がswaggerの記載と違う
大体合ってる気がしましたが、レスポンスのJSONのデータとswaggerに記載されている型と異なることがあり1つづつAPIのレスポンスを確認する必要がありました。
特に欲しかったシナリオの中身のステップを取得する箇所はswaggerファイルではごっそり抜けてたので1つ1つデータを確認する必要がありました。

# 迷った点
## int or int64?
Goのintは処理系によってint32 or int64になります。IDはかなり大きな値もあり得ると21億より多くなるかも判断して当初からIDを全てint64に統一しています。
しかしGoに強い人に聞いたところ大体いまのPCの処理系は64bitだからあんまり気にする必要ないんじゃないかという助言を受け、intにしておいた方がよかったと感じました。int64は使う方もint64であることを意識せざる場面があるからです。
例えば`func hoge(id int64) {}`という関数は

```go
hoge(1) // OK
id := 1
hoge(id) //NG
```

となりユーザがint64を意識する必要がありイマイチだなぁと感じました。

## APIのバージョニングをどうするか

大抵のREST APIでバージョンニングがされています。バージョンニングに対してどうやってライブラリと対応するべきかという点についても調べました。結論から言うと今回のライブラリは何も考えずに作成しています。

### バージョンニングされたディレクトリを作成するパターン

```
/v1/*.go
/v2/*.go
```

のようなディレクトリを作成して、ユーザー側で欲しいバージョンのWeb APIクライアントを

```go
github.com/hogehoge/v1
```

のようにインポートする必要があります。

### ライブラリは特定のバージョンのみを対応するパターン

これは何も考えず現在のライブラリは特定のバージョンのみをサポートすると言う考え方です。Web APIのバージョンが上がったらリポジトリを新たに作るか、新しいバージョンのWeb APIに適応するようにライブラリをアップグレードします。

## クエリパラメーター

クエリパラメーターをどうやて組み立てるかについて少し悩みました。当初は以下のように直感的に実装しました。

```go
var (
page *int
id *int
)
if page != nil {
//etc
}
```

この方法でも悪くないのですが、if文を何回も書くのが手間なところとベタガキなので使い回しの効きにくいことがネックでした。
mapにしてfor分で回すことも考えました。
クエリパラメータのためにmapを作成するのも少し嫌でしたしkeyとなる文字列はやはり使い回しのききにくいものとなっていました。

と色々調べて回った結果クエリパラメータをセットする関数を返す関数を作成する方法を採用しました。クエリパラメータの種類ごとに関数を作成する必要がありますが、これなら使い回しがしやすく且つ使う方も直感的に使えそうでした。
実装はこの辺を参照ください
https://github.com/trknhr/autify-go/blob/main/request_param.go


# まとめ

Web APIのクライアントは処理としてはかなり単純でGoのライブラリ作成の練習になりました。普段ライブラリの作成などを行わないのでとても勉強になりました。限られた工数の中で作成したライブラリなのでユニットテストなどまだまだやりたい部分は残りますが、徐々に良い形にして行けたらと思います。
「新人の方によく展開している有益な情報」の中で大学時代に得ておけばよかった情報

# はじめに

以下の記事「新人の方によく展開している有益な情報」の中から、大学時代に得ておけばよかった情報を選んでみました。

https://qiita.com/kazuo_reve/items/d1a3f0ee48e24bba38f1


# 選定結果

私が大学時代に得ておけばよかった情報は『写経』です。
具体的には以下の記事です。

[53]@momotaro98，「プログラミングの勉強方法として写経は非効率？」
https://qiita.com/momotaro98/items/9d1075df13a98669d1b7

[54]@yuya_takeyama，「写経でプログラミングが上達するか」
https://qiita.com/yuya_takeyama/items/b8a8c548a4a1c6a05531

[55]@cervomansan，「プログラミング初心者の勉強方法について」
https://qiita.com/cervomansan/items/9aa3cc003807d370226b

[56]@kaizen_nagoya，「転職(16) ６５歳からのプログラミング入門」
https://qiita.com/kaizen_nagoya/items/1561f910c275b22d7c9f

記事の中に示されていることの中で、特に、@yuya_takeyamaさんが述べている以下が重要だと感じています。
> 自分で実際に書いて、実行したことがある、という自信


# 反省
ちなみに、大学時代に、『写経』ではなく、『コピペ』をしていたことがありました。
『コピペ』は、よい経験にならなかったし、自信も得られませんでした。
Next2D Framework [config設定]

初期構築が終わると、`src/config`配下に下記の`stage.json`、`config.json`、`routing.json`が書き出されます。今日は`stage.json`、`config.json`の解説を書きたいと思います。

# stage.json
stage.jsonの設定値は[Next2D Player入門](https://qiita.com/ienaga/items/6089b96e62d18e3250c0)で記載した設定項目と同一のものとなります。

```json:stage.json
{
  "width": 240,
  "height": 240,
  "fps": 12,
  "options": {
    "base": ".",
    "fullScreen": true
  }
}
```

名前|型|デフォルト値|説明
---|---|---|---
width|number|240|表示領域(Stage)の幅を設定します。
height|number|240|表示領域(Stage)の高さを設定します。
fps|number|12|1秒間に何回描画するかを指定します。

## Optionの設定値

名前|型|デフォルト値|説明
---|---|---|---
base|string|"."|相対パスでJSONを取得する場合、ここで設定したURLがrootとして適用されます。絶対パスの場合はここで設定したURLは適用されません。
fullScreen|boolean|false|Stageクラスで設定した幅と高さを超えて画面全体に描画されます。
tagId|string|null|IDを指定すると、指定したIDのエレメント内で描画を行います。
bgColor|array|null|背景色の[R,G,B,A]の配列は0～255で指定できます。falseは無色透明です。

# config.json
```json:config.json
{
  "local": {
    "api": {
      "endPoint": "/"
    },
    "content": {
      "endPoint": "/"
    }
  },
  "dev": {
    "api": {
      "endPoint": "/"
    },
    "content": {
      "endPoint": "/"
    }
  },
  "stg": {
    "api": {
      "endPoint": "/"
    },
    "content": {
      "endPoint": "/"
    }
  },
  "prd": {
    "api": {
      "endPoint": "/"
    },
    "content": {
      "endPoint": "/"
    }
  },
  "all": {
    "spa": true,
    "loading": {
      "callback": "Loading"
    },
    "gotoView": {
      "callback": ["callback.Background"]
    }
  }
}
```

初期は`local`、`dev`、`stg`、`prd`、`all`と、区切られており、`local`、`dev`、`stg`、`prd`は任意の環境名なので、環境に合わせて変更、もしくは追加が可能です。
例えば、国内のメジャーなプラットフォームであれば`gree`や`mobage`などがありますが、複数のプラットフォームでゲームをリリースする事もあるかと思います。その時は、下記のような追加も可能です。

```json:config.json
{
  "local": {
    "api": {
      "endPoint": "/"
    },
    "content": {
      "endPoint": "/"
    }
  },
  ...省略
  "gree_dev": {
    "api": {
      "endPoint": "https://greeのサンドボックスのapiのエンドポイント"
    },
    "content": {
      "endPoint": "https://gree開発用のCDN環境"
    }
  },
  "mobage_dev": {
    "api": {
      "endPoint": "https://mobageのサンドボックスのapiのエンドポイント"
    },
    "content": {
      "endPoint": "https://mobage開発用のCDN環境"
    }
  },
  ... 省略
  "all": {
    "spa": true,
    "loading": {
      "callback": "Loading"
    },
    "gotoView": {
      "callback": ["callback.Background"]
    }
  }
```

このように複数のプラットフォームに対応した変数管理も可能です。

# all
`all`はその名の通り、どの環境でも書き出される共通変数となります。
`all`で機能に影響のある設定項目は以下の項目となります。

名前|型|デフォルト値|説明
---|---|---|---
spa|boolean|true|Single Page Applicationとして、URLでシーンを制御することができます。
loading.callback|string|Loading|画面遷移の準備が完了するまでの間、ローディング画面を表示するかどうかを設定します。コールバックとして設定されたクラスのstart関数とend関数を呼び出します。
gotoView.callback|string or array|["callback.Background"]|gotoView関数が終了した後にコールバックするクラスを指定できます。

# 書き出し
書き出しコマンドの`env`に環境の値を入れると対象の環境変数と`all`の値を結合して`Config.js`を生成します。

```linux
npm run build -- --env="prd"
```

最後の設定項目、`routing.json`の解説は少し長くなりそうなので、明日引き続き記載したいと思います。
Litecoinのアドレスをbitcoinjs-libで生成する

# はじめに

https://qiita.com/shu-kob/items/13dfce46bcec3d1c0727

前回、Litecoinの拡張秘密鍵と拡張公開鍵を生成しました。

今回は、鍵からLitecoinのアドレスを生成します。

# 参照するソースコード

こちらのファイルを使います。

https://github.com/shu-kob/walllet-dev-study/blob/master/getSingleSigAddresses.js

前回の記事通り、あらかじめ、拡張公開鍵を生成しておきます。

# ソースコードの変更

https://github.com/shu-kob/walllet-dev-study/blob/e0e4ffe93740db68bbee07453e2b2f5e9a4fb6d3/getSingleSigAddresses.js#L31

↓以下に変えます

```getSingleSigAddresses.js
let bitcoinNetwork = LITECOIN; // MAINNET, TESTNET, LITECOIN or DOGECOIN
```

# 実行

```
node getSingleSigAddresses.js
```

```
External Addresses
addressPath: m/44'/2'/0'/0/0
P2PKH:
LdhVys1Bw8Rx5EwquiUdx1DyWJF2xtXPmQ
P2SH-P2WPKH:
MS1kPMTjQV9DVLGvXWw9QhAJVaHAjHh81o
P2WPKH:
ltc1qe2nl3405p8hx30ckqaujeqm7a5v5fdly8jjvjf
addressPath: m/44'/2'/0'/0/1
P2PKH:
Lhndm82LjvYAxGVBMMTo5n7BbMjYZjNKMM
P2SH-P2WPKH:
M9qp7vB1zP8SjaftWgZzt227gQmaPz9RRa
P2WPKH:
ltc1q77qsedw9ylryfv9rm7jtwc5x3qp8x63w2qhnfe
addressPath: m/44'/2'/0'/0/2
P2PKH:
Lhe19NonsgS6oSJoDZY6Cxq9EWcHpjNZMW
P2SH-P2WPKH:
MGkxT1KkGBzDx2md8ykLWrWUHtyVepYHpd
P2WPKH:
ltc1q7h0j0ltfxeynfrc7wwv4rz450tpxsdw3y35sc0
addressPath: m/44'/2'/0'/0/3
P2PKH:
Lczgx7H5rnooKineWtMjgyAdhTm3k4HrBZ
P2SH-P2WPKH:
MAPa7Ljp9mtEcVDabazwpruarefPLcsK1W
P2WPKH:
ltc1qctcpx806ph292xzmjwkeuzpknv3v3meg0xjyrz
addressPath: m/44'/2'/0'/0/4
P2PKH:
LSeRMNSVrvEAfnCyLrEu4EaAJzMsce6kBx
P2SH-P2WPKH:
MJ4a5AbVRsA3uoHwDggqJGj7i4C8eMyU9b
P2WPKH:
ltc1q295hnmz50r0k3fe2tdjuzk43ntdfp0eyzg8ajm


Change Addresses
addressPath: m/44'/2'/0'/1/0
P2PKH:
Lf2etHShvR9zzcxMSgaLFjEQT8mhcksTvu
P2SH-P2WPKH:
MKi7cntWFajHogweM9aho2EKfswFdWwvV6
P2WPKH:
ltc1qmylk7q9nc27zpy9ly2hgxy5dk758e0a9uffjhy
addressPath: m/44'/2'/0'/1/1
P2PKH:
Ldszr9CsQgLjwn7bHEn9KHuhjQNLojfZcw
P2SH-P2WPKH:
MDGQYiiocNK4voYcjddN1Pf9SP5eRmvahb
P2WPKH:
ltc1qejjr5l4pr7y7dqyncdv4s22g6rywx00afudnra
addressPath: m/44'/2'/0'/1/2
P2PKH:
LRnWK6i1zaAUuZgG4TqfPfVF8S7EBarDqh
P2SH-P2WPKH:
MPZYPYeeeB6nEn7HzKkfqrMJPZjXCbrfbv
P2WPKH:
ltc1qgludrwl3wprpq8zjm0ner3vlhyrxdghjkur5al
addressPath: m/44'/2'/0'/1/3
P2PKH:
LfDM1TbJiDXqqCR5Bq3QjzULbLBJaYvAYY
P2SH-P2WPKH:
M8dqek6yx37tD78AXHACoQYHgeNtB7HMHN
P2WPKH:
ltc1qmdz3vw8x2seku8ldw0rym0f0wynqp3en5rz550
addressPath: m/44'/2'/0'/1/4
P2PKH:
LUX9sP4zVh7qUFF6wwSPY3ZpM4iuHyWV1G
P2SH-P2WPKH:
MLPhXACwYU4CBMGU17Ai49wYZHLXepJHC1
P2WPKH:
ltc1qvhu7g5mymmfgdssrs9le6u0252lna4dr96m2lj
```

シングルシグのP2PKH, P2SH-P2WPKH, P2WPKHが生成できました。

なお、拡張公開鍵が`Ltub`なのでLitecoin以外のアドレスを生成しようとするとエラーになります。

P2PKHは`L`

P2SH-P2WPKHは`M`、

P2WPKHは`ltc1q`で始まるのが特徴です。

このようにして、bitcoinアドレスとの混同を防いでいます。

Bitcoin派生のコインで遊んでみると面白いですよ！お試しあれ！
Github Pushまで

ターミナルを利用してPushまでの流れを紹介！
＃Github＃Push出来ない＃Git＃git＃github＃Push＃commit＃リポジトリ＃ローカル＃リモート＃無理

⇨Pushができずにお困りの方へ、これを見れば必ずできるようになるはずです！

※注意
エラーが出たらまずはそれを調べてみよう。解決方法はすぐに見つかります！
⇨自分は英語が苦手なので、エラーを理解しないまま進めがち、、
　今後の為にも、エラーが出たらすぐ覚えちゃいましょう！




□基本的な流れ

①githubのサイトで新しくリポジトリを作成する

②ローカル（自分のパソコン内で管理するために作成したリポジトリ）上でpushしたいファイルに移動する

③「git init」でgitを初期化する(初回のみ)
⇨次にローカル環境でローカルリポジトリを作成する。

④「git add」でcommitする前に変更内容を一時的に保存する
⇨ファイルをインデックスに追加する（コミットの対象にする）

⑤「git commit」 でディレクトリの変更をローカルリポジトリに登録
⇨インデックスに追加した変更をリポジトリに記録する

⑥「git remote add origin[url]」でローカルリポジトリとリモートリポジトリを繋ぐ（初回のみ）
⇨リモートリポジトリを関連付けする
　Githiub上でリポジトリの作成を行いPushする際のURLを取得する

⑦「git push origin master」でローカルリポジトリのデータをリモートリポジトリに反映する
仕様書の基本

## プログラミングの事を書けと言ったよね？
すまん、ここ数年コンソール見てないんだ……
他人の書いた仕様書ばかり見るようになってしまった。だからこそ言える事がある。
## 仕様書ってなんだろう
多くの人が「これから俺はこんなものを作るんだぜ、と他人に伝える書」ぐらいにしか思ってないんじゃないだろうか。
違う。違うんだ。
**仕様書は「武器」なのだ**ぜ。
## 「攻め」の姿勢で仕様書を書こう
**「仕様書」で書いたものは「仕様」になる。バグではなくなる。**
そう、そこ超重要なのだぜ。
自分の書いている仕様書が、後々に、自分を守る「武器」となる。
具体的には何か問題が起きた時に「これってバグじゃない？」って言われた時に**「違いますぅ、仕様ですぅ、仕様書に書いてありますぅ」**と口を尖らせながら見せつけるためのものだ。
で、逆に見せつけられた時に「こうとも読めるよね？」と返されるようじゃ武器にならないのです。そう、よく言われる「誰が読んでも同じ意味になるように書け」は、自分を守るためのものでもあります。
「ちっ、うっせーな、反省してまーす」と言いながら言われた事だけ修正するなんて、バカのやる事です(元ネタはググって下さい)。
ここで書いた事は、将来俺を守るためのものだ、と思いながら書くものなのです。

## 仕様書を「武器」にするためにその１、要件定義書
仕様書を武器にしたいなら「積み重ね」が大事です。
要件定義書、基本設計書、詳細設計書。(企業が違うと呼び方が変わるが、大体こういう感じの３段階の仕様書になるはず)。
お客さんに見せるのは、要件定義書が中心で、基本設計書は見るお客さんもいれば見ないお客さんもいる。そう考えたら、今まで面倒くさかっただけの要件定義書が、どれだけ重要かわかるはず。
そう、**要件定義書を見せて「これ仕様ですぅ」と言える程度**には、相手に「仕様を伝える書」じゃなければダメなのだ。
仕事のとっかかりで、お客さんに初めて出す書類で、何とか無難に乗り切ろう……そんな考えでは、キツいだけだ。武器にしよう。これからの自分を守るための武器にするのだ。
## 仕様書を「武器」にするためにその２、基本設計書
「基本設計書」は２つの意味を持つ。
１つ、詳細設計書は「詳細設計書を見せる前の最後の書である」ということだ。
詳細設計書を作る時、基本設計書に書いてある事をパラメータに落とし込む。パラメータがどの値の時にどう動くかなんて、だいたいはベンダが決めることだ。
逆にいうと**あなたが作る「仕様」を具体的にお客さんに伝える最後の場面**だ。ここで書いた書が仕様のフィックスとなる。ここで手を抜いてはいけないのだ。
そしてもう１つの意味。基本設計書は「詳細設計書の前」なのだ。詳細設計書を書く人が、要件定義書を見なくても、基本設計書全てを読まなくても、部分だけの基本設計書を読むだけで詳細設計書を作れないといけない。そうしないと、**何があっても100%、自分が詳細設計書を書くハメになる**。
人が少ないんですぅ、忙しすぎますぅ、人を増やして下さいぃ、と上に頼んで、人が来る事は稀だが、来る事もある。
どんな人材だろうが、未経験のプロジェクトであれば、来てからマッチアップまで時間がかかる。
**そうなった時を見越して基本設計書を作るべきなのだ。**基本設計書の部分だけを見て、詳細設計書に落とし込める。そういう意識で書いた書でなければ、基本設計書から詳細設計書に落とし込みをするのは難しい。

## 仕様書を「武器」にするためにその３、詳細設計書
詳細設計書、これこそ武器だ。お客さんに見せる事はほぼ無いが、ある時はある。日本で一番大きなIT企業の時代だと提出してたし、自分が中の人だった時はよく読んだ。
しかし、詳細設計書を武器にする理由は、そこじゃない。
**詳細設計書をVBAに読み込ませたら、環境を構築するCLIを自動的に吐くorそのように動作するシェルを自動生成する**ぐらい、詳細設計書は自動化を見越して作っておくべきだ。
本当にVBAを組む必要はない。前述した通り、プロジェクトの急な要因増加があったら、そういう事をやってくれる人材が来てくれるかも知れない。
問題は、**そういった人材が来た時に、ほい、と渡せる仕様書かどうか、**だ。
仕様書に読み方があって、VBAで単純に処理できないものであったら、実は悪い詳細設計書の書き方をしている、という事は大いに有り得る。

## 大事なのは「誰が読んでも同じ意味になる」ようにすること
この「誰」は多くの場合は**新規参画者**だ。**VBAの場合**もある。
大体**あなたと同じ会社の人**だし**あなたと利害関係が一致する人**のはずだ。
あなたがもしも病気で倒れてしまったら、もし急な用事で職場を離れなければならなくなったら……**仕様書だけを置いて消える**。それができるように準備しておかなければならないのだ。
誰が読んでも同じ意味になる仕様書であれば、置いていける。置いていって、後は他の人に託そう。

## 義務感でやってる人へ
自分は上記のように、仕様書は常に「武器」と思って書いていたので、仕様書作成は非常に楽しかったです。
苦しい思いをしている人は、上記を理解していない人がほとんどだと思います。
苦手とか面倒くさいとか、仕様書はそういったこととは縁が遠いものなのです。チェンジマインド！
InkdropのドキュメントをAlfredから検索できるようにする

# 概要

InkdropのドキュメントをAlfredで検索して開けるようにする方法について記載しています。
AlfredとInkdropを利用しているユーザの場合、かなり快適にドキュメント検索ができるようになります。

# 前提条件

macOS

# 手順

## Alfredのワークフローをインストールする

下記からAlfredのワークフローをダウンロードして、インストールする。
[Releases · inkdropapp/inkdrop\-alfred\-workflow](https://github.com/inkdropapp/inkdrop-alfred-workflow/releases)

※ワークフローのインストールはダウンロードしたファイルをダブルクリック


## InkdropでHTTPサーバを有効にする

下記の公式ドキュメントの通り、設定ファイルにHTTPサーバを有効にする設定を行う。
[Accessing the Local Database \| Inkdrop Documentation](https://docs.inkdrop.app/manual/accessing-the-local-database#accessing-via-http-advanced)

### 手順

* Inkdropが起動中であれば、いったん終了する。
* 設定ファイル（config.cson）に、HTTPサーバを有効にする記載を追記する。  

設定ファイルの場所（User data directory）：
[Basic Usage \| Inkdrop Documentation](https://docs.inkdrop.app/manual/basic-usage#user-data-directory)

設定例）

```
"*":
  core:
    server:
      enabled: true
      port: 19840
      bindAddress: "127.0.0.1"
      auth:
        username: "foo"
        password: "bar"
```

* Inkdropを起動する。



## AlfredのワークフローにHTTPサーバの設定を行う

Alfredのワークフロー設定画面から、最初にインストールしたワークフローの設定画面を開く。
※左上の一番左側のボタン [x] を押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10525/b77df017-089a-93a0-2899-ff644d1b204c.png)

ワークフローの環境変数の設定画面が開くので、そこにInkdropの設定ファイルに記載した値を設定し、Saveで保存する。

# 使い方

Alfredのコマンド入力ウィンドウにて、「ink 検索文字列」を入力すると該当するドキュメントが検索される。
ロガーのWinstonでformat.colorizeが効かない時の対処

## 結論

ネットで調べると出てくる`format.colorize()`を最初に書けというのと逆のことをします。（※該当箇所だけ抜粋）
これでカラーになりました。

```
format.combine(
    format.json(),
    format.prettyPrint(),
    format.colorize({ all: true })
)
```

## 参考）環境
winston 3.3.3
macOS、Next.js、Docker
AWS CDKで爆速LINEBotのBackendを構築するの巻

## TL; DR

CDKたのしい☺️

## 概要

LINE Botのサーバレスなバックエンドを構築するためのCDKサンプルです（Typescript）．
LINEのMessagingAPIのバックエンドとして，AWSのAPI GatewayとLambdaを構築します．
以下のリポジトリで公開しています．
https://github.com/umihei/LINEMessagingAPIBackendStarterTemplate

こんな感じのやまびこBOTが爆速でできます．
この先どうやってBOTを発展させていくかはあなた次第です．
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580420/d34cc483-d186-5815-2dc1-83f523af4db1.jpeg" width="400">


## Architecture

![Screen Shot 2021-12-14 at 22.17.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580420/59bb4d6c-50a2-81e7-ec53-5b0f2dfedfe5.png)

## 使い方

この辺りを参考に，LINEのChannelを作成して，チャネルシークレットとアクセストークンを入手したら，

https://qiita.com/nkjm/items/38808bbc97d6927837cd

次のコマンドで，SSMのパラメタストアにシークレットとトークンを格納します．

```
aws ssm put-parameter --type 'String' --name 'CHANNEL_ACCESSTOKEN' --value 'your channel's access token'
aws ssm put-parameter --type 'String' --name 'CHANNEL_SECRET' --value 'your channel's secret'
```

あとは，クローンしたリポジトリで`npm install`したのち，

```
cdk deploy
```

でバックエンドが立ち上がります．
（初めてCDKを使う場合は，`cdk bootstrap`が必要）
リソースを立ち上げる途中で，SSMからシークレットとトークンを取得してLambdaの環境変数にセットしています．
API GatewayのEndpointが`cdk deploy`したコンソールに表示されるので、そのURLをLINE DevelopersのページでWebhookに指定します。
オフラインで Docker 環境下の開発を行うときに困ったこと（Web アプリ版）

先日，しん↑かん↓しぇ～ん→で出張する機会がありましたが，暇だったので Web アプリ開発の続きをやろうと思いました．
車内で PC を開いて環境を立ち上げようとすると・・・

```text
failed to solve with frontend dockerfile.v0: failed to create LLB definition: failed to do request: Head "https://regist
ry-1.docker.io/v2/library/php/manifests/7.4.16-apache-buster": dial tcp: lookup registry-1.docker.io on 192.168.65.5:53:
 no such host
```

＿人人人人人人人人＿
＞ no such host ＜
￣^Y^Y^Y^Y^Y^Y^Y

ひえーそういえばインターネットなかったんだ😱

東海道新幹線に Wi-Fi がついているので接続して使おうとしますが，多数の方が同時に使われるものですので，開発用途で大容量ファイルをダウンロードするのは良くないです．

どうしたらいいでしょうか？

ここからは私が考えた，新幹線車内で起こる問題と対策をご紹介します．

## Docker イメージの取得に失敗する

Docker イメージの取得に失敗するのを避けるには，あらかじめ Docker イメージをプルしておきましょう．

PHP + Apache 環境のイメージをプルする例です．

```sh
docker pull php:7.4.16-apache-buster
```

## Docker イメージのビルドに失敗する

パッケージのインストールなど，インターネットに接続して処理を行うコマンドを含む場合，ビルドに失敗します．

これもインターネットがないことが原因ですので，あらかじめビルドしておきましょう．

```sh
docker build -t php-apache:latest .
```

起動もあらかじめビルドしたイメージから行います．

```sh
docker run --rm -it php-apache:latest
```

Docker Compose から起動する場合， `docker-compose.yaml` は

```yaml
services:
  php-apache:
    build:
      context: .
      dockerfile: dockerfile/php-apache.dockerfile
```

のように `build` を使って書いているところを

```yaml
services:
  php-apache:
    image: php-apache:latest
```

のように `image` でビルドしたイメージ名を指定しましょう．

## 外部ライブラリの読み込みに失敗する

これもインターn(ry

例えば Bootstrap を [こちら](https://getbootstrap.com/docs/5.1/getting-started/introduction/#modules) のように CDN から読み込んでいたのであれば，

```html
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
```

ダウンロードするか npm や Composer などでインストールして使いましょう．

[Bootstrap のダウンロードページ](https://getbootstrap.com/docs/4.0/getting-started/download/#npm)

## 外部 API の実行に失敗する

これは仕方ない問題だと思います．

API が呼び出せないことでその後の動作に支障が出るのであれば，API に相当する何か別の関数を作ってそれを読み込むといいかもしれません．

PHP + Apache などでローカルにサーバがある場合は，初めからローカルサーバ内の決まった URL にアクセスし，その中で API を呼び出すようにします．

```php
public function get_something()
{
    $isオフライン = $this->環境変数('オフラインで利用する');
    if ($isオフライン) {
        echo '130'; // 固定値やサーバ内部で完結するような関数を呼び出す
        exit;
    }

    // API を呼び出す処理...
}
```

でも Web 系アプリなら本番環境がインターネットにつながっているのは大前提なので，ソースコードにこんなコードを書くのはやはりおすすめしません・・・
どうやらしん↑かん↓しぇ～ん→ API 関連は永遠の課題になりそうです．もしいいアイデアをお持ちの方がいらっしゃれば教えていただきたく:pray:

---

最後になりましたが，みなさんがどっか (Docker) に行くときにこの記事を読まれて，快適な旅をされることを心よりお祈り申し上げます🚄🙏
2021年、アドベントカレンダーに参加しました

[アドベントカレンダー初参加する人を応援したい、アドベントカレンダーに参加したきっかけアドベントカレンダー Advent Calendar 2021](https://qiita.com/advent-calendar/2021/sanka-kikkake) 17日目の記事です。
今年初めてアドベントカレンダーに参加したので、その話を書きます。

##参加のきっかけ
###①今後のキャリアにプラスになるかもしれない
最近の風潮として、転職も普通になってきたと思います。
今すぐどうこうというわけではないのですが、何かあった時にQiitaへの投稿が役立つのではないかと。
まあ正直に話すと、「自分ここまでアウトプットしていますよ！(フッ)」と面接官などに言いたい。かなり邪な理由です。

###②アウトプットの実践
やっぱり資料を読んでいるだけでは覚えられないので、どこかで発表したいと思っていました。
誰かに見てもらうことを考えると、根本的な理解というのが必要になるので、自分の実力アップにつながると期待しました。

###③何かお祭りやってる。面白そう。
タイトルのまま。
内容はよくわからないけど面白そうなので、1回ぐらい参加してみようと。
<br>

ちなみに理由の割合としては下記の通りです。
うーん、邪な考えが圧倒的。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1259951/a578b02f-9754-bf69-0b7f-d643338c2132.png)

##これまで参加したテーマ
[「色　いろいろ」](https://qiita.com/advent-calendar/2021/colour)
 ⇒茄子紺とナスの色を比較
[完全に理解したTalk](https://qiita.com/advent-calendar/2021/easyeasy)
⇒VPN完全に理解した(とは言っていない)
[ググって解決しづらかったこと](https://qiita.com/advent-calendar/2021/gseach)
⇒ただの叫び
[しくじり先生](https://qiita.com/advent-calendar/2021/shikujiri)
⇒pipでAnacondaをおかしくした話
[Flask](https://qiita.com/advent-calendar/2021/flask)
⇒簡単なフォームを作成するまでの道のり

## 参加した感想
### 最初の考えは甘かったことを痛感
元々冒頭で述べた邪な理由がきっかけだったのですが・・・考えが甘かったと痛感しました。流石にちょっとした投稿で「君できそうだね！採用！」になることはないです(そりゃそうよ)
プロのエンジニア[^1]~~変態~~の投稿を見て心が折れました。こんなレベルは無理だ～

### アウトプットはスキルアップの手助けになる
これは本当に実感しました。自分比にはなりますが、参加する前に比べて学んだことは多かったです。
調べていく中で対象にしている分野だけでなく、その周辺の知識も必要になることがあり、思っていない知見が得られました。

特に実感したのはFlaskでのフォーム作成で、絶望しながらもhtmlやCSSを勉強してなんとか形に持って行けたのが印象に残っています。

### 強制力があるからやりやすい
強制力というと語弊があるかもしれませんが、この日にやるというプレッシャーがあるのはよかったです。
人間って、明日やろう⇒明後日やろう⇒・・・となってずるずる先延ばしにすること、ありがちだと思います。
やらざるを得ない環境にいるとどうにかするので、成果も上がりやすいのではないでしょうか。

ちなみに筆者がプログラミングを学び始めたのも、会社から強制されたという経緯があります(やる羽目になった時は噓でしょとか思っていた)。

### お祭りだった
これは参加する前と変わらないですね。初めての人も猛者達も楽しめるものでした。
最初、こんな簡単なレベルの記事投稿して大丈夫かな？とか思ったのですが、批判は出なかったので安心しました。それだけでなく、自分の記事に興味を持ってくれる方もいてちょっと嬉しかったです。

## まとめ

邪な考えは砕け散りましたが、参加してよかったです。
他の方の記事でも書いてあるように、まずは投稿してみることが大事だなと思いました。
来年は気力があれば、一人アドベントカレンダーに取り組むかもしれない。

[^1]: ここでは、「ソフトウエアもしくはサーバーの保守・開発に携わり、サービス提供によって収入を得ている」と定義しています(異論は認めます)
Power Automate: 例外処理コネクターが出てくると思ってたら・・Scopeを使うんですね

# 背景
以下の Tweet をみて Title をよく読まずに「Try/Catch/Finally」コネクターが出るのをずっと待ってたが全然来ない・・

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">An example on how you can use Try, Catch and Finally in Power Automate by using the Scope action.<a href="https://twitter.com/hashtag/Dynamics365?src=hash&amp;ref_src=twsrc%5Etfw">#Dynamics365</a> <a href="https://twitter.com/hashtag/Microsoft?src=hash&amp;ref_src=twsrc%5Etfw">#Microsoft</a> <a href="https://twitter.com/hashtag/PowerPlatform?src=hash&amp;ref_src=twsrc%5Etfw">#PowerPlatform</a> <a href="https://twitter.com/hashtag/PowerAutomate?src=hash&amp;ref_src=twsrc%5Etfw">#PowerAutomate</a> <a href="https://twitter.com/hashtag/Dataverse?src=hash&amp;ref_src=twsrc%5Etfw">#Dataverse</a> <a href="https://twitter.com/hashtag/Dynamics365CE?src=hash&amp;ref_src=twsrc%5Etfw">#Dynamics365CE</a><a href="https://t.co/2oTftpIt6f">https://t.co/2oTftpIt6f</a> <a href="https://t.co/2oTftpIt6f">https://t.co/2oTftpIt6f</a></p>&mdash; Fredrik Engseth (@EngsethFredrik) <a href="https://twitter.com/EngsethFredrik/status/1460880602744471554?ref_src=twsrc%5Etfw">November 17, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

あれ？と思って、久しぶりに思い出して検索したら・・

- Scope の Configure run after の設定を変えて使う

ってことだったんですね・・しかも、半年以上も昔のことだそうな・・
これだとエラー処理が Scope 単位になってやりやすいですね！今までの苦労が :crying_cat_face: 

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Power Automate の try-catch-finally はスコープを利用して行う。 <a href="https://t.co/kDyZOf3jS7">pic.twitter.com/kDyZOf3jS7</a></p>&mdash; Ota Hirofumi 📖 Microsoft Teams 踏み込み活用術 (@hrfmjp) <a href="https://twitter.com/hrfmjp/status/1366620705639395329?ref_src=twsrc%5Etfw">March 2, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# サンプル

上の Twitter のリンク先にもまとめ記事がありますが、[MS の Template](https://japan.flow.microsoft.com/en-us/galleries/public/templates/e8e028c6df7b4eb786abdf510e4f1da3/try-catch-and-finally-template/) もあります。

https://www.fredrikengseth.com/how-to-use-try-catch-and-finally-scopes-in-power-automate/

# 補足

人によって、例外の範疇が違うので、上の記事のように、Time out を Catch するのもありかな、と。
[MS の Template](https://japan.flow.microsoft.com/en-us/galleries/public/templates/e8e028c6df7b4eb786abdf510e4f1da3/try-catch-and-finally-template/) だと、failed のみを拾うようになってるので。
Alibaba Cloud Serverless Workflowについて

# Alibaba Cloud Serverless Workflowとは
分散タスクを調整するフルマネージドのサーバーレスクラウドサービスです。
Serverless Workflowでは、定義された順番に処理を実行していきます。
処理も分岐させたりなど出来るようです。
Azure Logic Appsの様なサービスかと思います。
↓Flow作成時(Create Flow with Code選択時)に表示される基本的です。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/193451b3-4684-e4f7-5f82-d72989d6686e.png)


# 価格
料金は、使用したリソースに対してのみ請求されます。
また、フローの実行ステップ遷移の数に基づいて課金されます。
毎月無料枠として、5,000ステップ分割り当てられます。
10,000ステップごとに、1.7人民元(日本円で30円程度)課金んされます。

# Hello Worldしてみましょう
Flowの設定は、Flow DefinitionとFlow Configに分かれています。

## Flow Definition
**1.Create flowをクリックする**
![0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/f7c161ca-ec0f-6ffc-6224-2c7e18460055.png)

**2.Hello Worldをクリックする**
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/ac770f4a-19b0-0e94-0063-c4eef3cb6d5d.png)

**3.DetailsのNameを設定する**
**4.Next Stepをクリック**

## Flow Config
**1.Create a RAM roleをクリック**
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/10b0226e-2cdc-81bd-2740-53e671467356.png)

**2.Create Roleをクリック**
こちらの画面に遷移するので、「Confirm Authorization Policy」をクリックします。
アクセスする権限の付与を行います。
![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/7f9d52b6-b066-e2ad-ce17-263ad3f3702c.png)

**3.権限を付与すると、Select an existing RAM roleが選択され、Flow Roleに情報が設定されます**
![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/c553a183-42b3-f2d4-50a2-98130bee3c66.png)

**4.Create Flowをクリックすると、こちらの画面が表示されます**
![6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/169695ee-72e7-3af5-67c6-4e3ddcee4ba0.png)

**5.Start ExecutionをクリックしてExecution NameとInputを設定**
Optionalなので設定・変更しなくても実行されます。
設定内容確認後、「Start Execution」をクリック
![7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/a8883763-7c3e-a559-3ecf-962f74d7006e.png)

**6.実行結果**
Detailsに実行結果の成功/失敗や実行時間が表示されています。

Visualizationエリア内の図形をクリックすると、その図形の中でinputやoutputがどうなっているか右側のStep Detailsで確認することができます。
![8-1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/3fe98d2c-34d0-3533-950a-296b03068890.png)

実行時の履歴も確認することができます。
IDの番号の左側の＋をクリックすると、アコーディオンが展開されてそのステップで取り扱われているデータなどを確認することができます。
![8-2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/97936468-8d17-2270-f82f-014b8c2712aa.png)

Input/Outputは実行時に設定した内容とその出力内容が表示されます。
今回はInputだけ設定して出力自体は特に設定していないので、このような結果になっています。
![8-3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/f1f40dee-2aeb-13ad-fcc0-c420f9e4a4f5.png)


# まとめ
視覚的にFlowを確認できたり、他のサービスと連携できるようなので、使い方は色々とあるのかなと思います。
今回は簡単なFlowだったのでエラーのパターンなど検証できませんでしたが、この様なサービスはエラー発生時などの対応をどうするかの検討も必要になります。
他にもスケジュール機能などもあるので、引き続き検証したいと思います。
TypeScriptでメタデータを扱う

[Node.jsアドベントカレンダー](https://qiita.com/advent-calendar/2021/nodejs)の記事です。

JavaScript本体の仕様策定でなかなかステージ3にあがらない[デコレータ](https://github.com/tc39/proposal-decorators)。
TypeScriptには``--experimentalDecorators``オプションが必要ですが、以前から実装されています。この場合にのみメタデータが扱えるようになっています。

メタデータのプリミティブな使い方を書いておきます。greetingメソッドにメタデータを付与します。それを実行時に取り出して表示しています。

```ts
import "reflect-metadata";
 
class A {
  @Reflect.metadata("metadata-key-dayo", "hello world")
  greeting() {
    const message = Reflect.getMetadata("metadata-key-dayo", this, "greeting");
    console.log(message);
  }
}

const a = new A();
a.method();
// hello world
```

どんな値でも入れられる便利な箱となっています。

``--emitDecoratorMetadata``オプションをつけると、TypeScriptは次のようなコードを生成します。

```ts
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
__decorate([
    Reflect.metadata("metadata-key-dayo", "hello world"),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], A.prototype, "method", null);
```

このreflect-metadataパッケージを使ったコードです。細かいところを省くと、上記のサンプルのようなメタデータが自動で追加されます。それには"design:type"と、"design:parameters"と"design:returntype"というキーでもろもろの情報が付与されることがわかります。フィールドデコレータがついた場合は"design:type"だけで、クラスには特に追加のメタデータは付与されません。

最初のサンプルはメソッドの中で情報を取得しましたが、そのインスタンスメソッドの中でも外でも、同じようにこれらの情報にアクセスできます。

```ts
console.log("🐙", Reflect.getMetadata("design:type", a, "method"));
console.log("🐙", Reflect.getMetadata("design:paramtypes", a, "method"));
console.log("🐙", Reflect.getMetadata("design:returntype", a, "method"));
```

これらのメタデータは、あくまでも「なにかしらのメタデータが付与されたフィールド、クラス」に対する追加情報ですので、なにもデコレータが付いていなかった要素は型情報も取得できない点に注意です。

面白そうですよね？JSONからのシリアライズで型チェックをしながらクラスのフィールドに値を入れていくとかできそうですよね？

今までどういうものか調べようと思っていてずっと先延ばしにしていたのですが、ちょうどNode.jsアドベントカレンダーが空いていたので軽く調べて書いてみました。

詳しくはこちらに書いてあります。

https://www.typescriptlang.org/docs/handbook/decorators.html#parameter-decorators
Tailwind3.0で何が変わった？


# はじめに
フロントエンド開発で大きな力を発揮するTailwindCSSは
ユーティリティ・ファーストで作られており、
クラス名を考えずに済み、自由自在にスタイルを組むことができます。
先日v3.0の公開がされたとのことで、使えそうな追加機能を
ピックアップしてまとめていきたいと思います。
（*全て網羅している訳ではありません。）
https://tailwindcss.com/blog/tailwindcss-v3#multi-column-layout

## 標準機能の追加
Just in time、通称JITはブランケットで囲うことで任意の値を設定できたり、
擬似要素が使えたりと何かと便利な機能です。
従来はtailwind.config.jsに`mode: 'jit'`
と追記して使用できましたが、3.0からは標準搭載となりました。

さらに拡張パレットも標準搭載
baseカラーが8→22種類に増加！
それぞれ10段階の濃淡(50〜900)から選択可能なので
合計220種類の色がデフォルトで用意されることとなります。

## Multi-column layout
列数を指定し、手軽に新聞記事のようなレイアウトへ
レスポンシブにも応用できます。

[活用例: Multi-columns layout](https://play.tailwindcss.com/rgxvOhjX7m)


## aspect-ratio
defaultでビデオサイズと正方形 を用意されており、
ブランケット内に任意の比を指定することも可能

[活用例: aspect-ratio](https://play.tailwindcss.com/pafjtBSBs2)

## flex-basis, fit-content

フレックスアイテムの寸法を設定可能。
数値指定に誤りがあっても親要素内に収まるよう調整される。
また、Sizingにfitが追加されました。

[活用例: flex-basis, fit-content](https://play.tailwindcss.com/9gbahKNdQp)


## Scroll snap API

スクロールスナップのプロパティが追加され、制御可能に！
snap-centerで、スワイプ時に要素を中央に持ってきています。

[活用例: Scroll snap API](https://play.tailwindcss.com/wGGRqVHdZg)
Electron＋Canvas＋WebGL＋Reactのお絵描きツールの進捗2021

この記事は [Web グラフィックス Advent Calendar 2021](https://qiita.com/advent-calendar/2021/webgraphics) の14日目の記事です。

# はじめに

何年か前からElectron＋Canvas＋WebGL＋Reactでベクター系お絵かきツールを作っていて、毎年アドベントカレンダーで進捗報告をしています。

[ソースコード (GitHub warotarock/manual_tracing_tool)](https://github.com/warotarock/manual_tracing_tool)
[ライブデモ (GitHub Pages)](https://warotarock.github.io/manual_tracing_tool/dist/)

今年はずっとUIとソースコードの整理をしていたのでパッと見去年とあまり変わらないですが、一年やったなりの成果をご報告します。初めて見る方は、ライブデモだけでも少し見ていただけたらと思います。

![自作お絵かきツール](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/28c2db4b-4e71-4f0c-bd7f-a588c68c6669.png)


# リボンっぽいUIを拡充していった

このツールを作り始めたころはGUIは極力作らないでキーボードショートカットで解決しようと思っていました。完全に自分のためのツールのつもりだったのでそれでよかったわけです。

じっさい、作り始めた当時はそれで正解だったように思います。DOM操作を書きたくなくてボタンとかもCanvasで描いてましたから、そうとう面倒くさかったです。CSSとかもあまり知らなかったですし。それに、キーボードショートカットでも絵を描くことは十分できました。

その後Reactとか色々と便利なものが出てきたので、やっぱりGUIを作るかーと思い始めたのが運の尽きでした。できることが増えたことで、あれもしようこれもしようと自分で仕事を増やしている。

しかし、頑張ったかいあって、なかなかツールっぽくなってきたように思います。

Reactを導入して最初に作った線画タブ。
![線画タブ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/4418bcd9-09e1-9ff2-9fff-e7f50c60df2d.png)

レイヤータブ。
![レイヤータブ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/50d00596-33b2-a4b4-cbdc-2b5032d27be9.png)

少し変わったところで、画像ファイルレイヤー用のタブ。現在のレイヤーの種類に応じてタブの構成が変わります。以前はタブが右に増えていく感じでしたが、一番左のタブが切り替わる形になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/81c20071-2524-6745-9f9a-98e23446db2f.png)

もっと変わっている３Ｄポーズレイヤー用のタブ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/e86acc87-9680-7591-1b21-783dfdd93892.png)

開発初期はレイヤーごとに違う色々な項目を操作するのに専用のダイアログやウィンドウを表示していたので、それよりはかなり画面スペースを有効に使えるようになったと思います。オフィス系のソフトと同じ過ちの歴史をたどってる感じがします。

あとはルーラーを足したり、エクスポート範囲外を暗くする機能なんかも実装しました。ルーラーはあると無いとではけっこう見た目の印象が違いますね。

# 自動塗りつぶし

UIの他はソースコードの整理ばかりしていて新機能がほぼ無いんですけど、ずっと作りたいと思っていた自動塗りつぶし機能に手を付けました。手を付けたのが５日前くらいの話で、がんばってみたんですが、残念ながらまだ未完成です。

なお、最近流行りのAIがよしなにしてくれる機能ではなくて、線に囲まれた領域を色で塗りつぶす機能です。なんか[数日前のアドベントカレンダー](https://qiita.com/warotarock/items/1d3ba8883d67577296ad)で似たようなことをやりましたが、それとは技術的にはまったく関係ないものです。「塗りつぶし処理に異常な執着をもつ男」とかではないですよ(笑)。 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/c3bd4ad9-d05e-02fb-b3b5-edfa4ddcfad8.png)

虫眼鏡みたいなのがあるのが分かると思いますが、一言でいうと、その場所から一番近い線の一番近い位置かスタートして右回りで線をたどっていき、もとの場所まで戻ってくるまでの経路を塗りつぶし領域とするというアルゴリズムです。

一言でいうと簡単ですけど、小さな隙間の対応とか、線が交差している場合とか、データ的に逆順の場合とかを考えるとめちゃくちゃ面倒くさいです。この数日間、あかん…わからん…死ぬ…無理…~~尊い…~~と何度つぶやいたかわからないです。しかしなんとか今日、簡単な図形なら塗りつぶしができるようになりました。１レイヤー１か所しか塗りつぶしできなかったりしますが。

今後は、きちんと実装するのと、あとは線のほうを修正したらそれに追従して更新されるようにするなどしていきたいです。

# 今後について

ソースコードの整理も落ち着いてきたので、今後は３Ｄデッサン人形やパレットの機能を拡充していきたいと思っています。

３Ｄの方は、もっと自由に配置できたり、ユーザーがデッサン人形をカスタマイズできるようにしたいです。パレットの方は、いわゆるモディファイアみたいなものを実現できたらいいと思っています。グラデーションを生成したりとか、影色を自動生成したりとかいった機能を考えています。

あとはアニメーション機能ですね。これは簡易なものでよくて、実はすでに半分くらい実装されていたりもします。

それらができたら、このツールはだいたい完成になります。以前はモバイル向けアプリにしたいと思っていたんですが、自分で使うだけでもまあいいかなと最近は思っています。

# おわりに

今年のお絵かきツールの進捗を報告させていただきました。
短いうえに全くプログラムが書いてなくて申し訳ないです。他にも記事を書いたしご容赦ください。

今年のアドベントカレンダーはちょっと寂しい感じですが、また来年もアドベントカレンダーでお会いできたらと思います。続いてるかなー(笑)。
それでは良いお年を。
あれ？timestampのインサートができない。。。15分ほど悩んだ。

test1テーブルのtimestampを変更したくて15分つまづきました。
カラムの型が何かっていうのちゃんと把握してSQL書こうねっていう話です。


###変更前(テーブル）

|id  |name  |timestamp  |
|---|---|---|
|1  |pe  |2021-12-1 09:00:00  |
|2  |bu  |2021-12-2 10:00:00  |
|3  |ze  |2021-12-3 11:00:00  |
|3  |pe  |2021-12-3 11:10:00  |


###変更後（こうしたい）

|id  |name  |timestamp  |
|---|---|---|
|1  |pe  |2021-11-24 09:00:00  |
|2  |bu  |2021-11-25 10:00:00  |
|3  |ze  |2021-12-3 11:00:00  |
|3  |pe  |2021-12-3 11:10:00  |

というわけでググってそれっぽいのがあったので下記のSQLを実行・・・した結果エラー

```:mysql
UPDATE test1 SET date=2021-11-24 09:00:00  WHERE name= 'pe'
```


```:mysql-error
#1064 - You have an error in your SQL syntax;
 check the manual that corresponds to your MySQL server version 
for the right syntax to use near '2021-11-24 09:00:00 WHERE name= 'pe'' at line 1
```

何かしら構文が間違っていることは分かるけどどこかがいまいち分からず
解説サイトをモソモソと。。。

この時ぺは2行あるのでpeじゃダメなんだろうか。。。。
エラー的には違うんだよなぁ、云々考えつつ、こういうこともできるかな？と思って色々と実行

```:まちがったmysql
#1
UPDATE test1 
SET ,date = 2021-11-24 09:00:00 
WHERE name= 'pe'
---err=> #1064 - You have an error in your SQL syntax;

#2
UPDATE test1 
SET ,date = 2021-11-24
WHERE name= 'pe'
---err=> #1064 - You have an error in your SQL syntax;

#3
UPDATE test1 
SET date = 2021-11-24 09:00:00 
WHERE name= 'pe'

---err=> #1064 - You have an error in your SQL syntax;
```

うーん、なんかあとちょっとなのに上手く行かない。
とりあえず文字囲いしてみると・・・

#答え
```:mysql
UPDATE `test1` 
SET date = '2021-11-24 09:00:00'
WHERE name= 'pe'
```

TIMESTAMP型は数字か文字列かをちゃんと把握せずにSQLを書いて、「あっ」となったのでした。
以上、カラムの型が何かっていうのちゃんと把握してSQL書こうね。という話でした。


#参考にした
https://www.doodle-office.work/entry/2017/07/12/161520
updata文を一旦再確認
http://sql.main.jp/sql13.html
【ゆく年2021】SDカード変換アダプタが余っていたのでM5全機種で使えるように半田付けした話

#1. はじめに

昨今ではmicroSDを購入すると　ほとんどSDカード変換アダプタが付いてくる

https://www.amazon.co.jp/%E3%83%90%E3%83%83%E3%83%95%E3%82%A1%E3%83%AD%E3%83%BC-BSCRMSDA-iBUFFALO-microSD%E3%82%AB%E3%83%BC%E3%83%89-SD%E3%82%AB%E3%83%BC%E3%83%89%E5%A4%89%E6%8F%9B%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF%E3%83%BC/dp/B00CRVXR14

microSDだけ取り出して
この変換アダプタもうこれどうにかならないの？
って事で花札が出来るくらいたまり ふと 疑問に思う
これ線繋いでるだけなんだよね？
であれば繋いでみる?

#2. 半田付け作業

確か SDカードって確か SPIの線を引っ張れば動くと思うんですが...

https://qiita.com/nanbuwks/items/0f5401ca3ba42ce4ff28

https://qiita.com/chrmlinux/items/5d65893760dad6f4bee0

![sdcard_back.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2063214/05defee5-2375-a12e-00f3-d70bfb0274f6.jpeg)

#3. ブレッドボードに配線

![sdcard_circit.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2063214/320bf8bb-b498-7899-b17a-87ce8c415a7b.jpeg)

```
SDカード変換     　　M5AtomLite側
アダプタ側

　　　CS   <---(灰)---> GND
　　　MOSI <---(茶)---> G19
　　　GND  <----------> NC 
　　　3.3V <---(赤)---> 3.3V
　　　CLK  <---(黄)---> G23
　　　GND  <---(黒)---> GND
　　　MISO <---(緑)---> G33

* SDカード変換アダプタ側のGNDは内部で繋がってます

```

#4. 確認スケッチ
いつものように [lang-ship](https://lang-ship.com/blog/work/m5lite-sd/) さんのお世話になります

https://lang-ship.com/blog/work/m5lite-sd/

```　M5.ino
#include "M5Lite.h"
SPIClass SPI_EXT;
void setup() {
  M5Lite.begin();
  
  if (M5.Ex.board == lgfx::board_M5Stack) {
    // AutoStart
  } else if (M5.Ex.board == lgfx::board_M5StackCore2) {
    // AutoStart
  } else if (M5.Ex.board == lgfx::board_M5StickC) {
    // SD   M5StickC
    // 3V3  3V3
    // GND  GND
    // CLK  GPIO0
    // MISO GPIO36
    // MOSI GPIO26
    // CS   GND
    SPI_EXT.begin(0, 36, 26, -1);
    SD.begin(-1, SPI_EXT);
  } else if (M5.Ex.board == lgfx::board_M5StickCPlus) {
    // SD   M5StickC
    // 3V3  3V3
    // GND  GND
    // CLK  GPIO0
    // MISO GPIO36
    // MOSI GPIO26
    // CS   GND
    SPI_EXT.begin(0, 36, 26, -1);
    SD.begin(-1, SPI_EXT);
  } else if (M5.Ex.board == lgfx::board_unknown) {
    // SD   ATOM(Lite, Matrix) Doesn't work with Echo!
    // 3V3  3V3
    // GND  GND
    // CLK  GPIO23
    // MISO GPIO33
    // MOSI GPIO19
    // CS   GND
    SPI_EXT.begin(23, 33, 19, -1);
    SD.begin(-1, SPI_EXT);
  }
}
void loop() {
  M5Lite.Lcd.setCursor(0, 0, 1);
  M5Lite.Lcd.println("M5LiteSD");
  M5Lite.Lcd.println(millis());
  
  // delay & M5Lile.update()
  M5Lite.Ex.delay(100);
}

```
#5. シリアルポートから確認

![sdcard_tfcard.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2063214/e3c2a9c8-e29e-53d8-f9b9-4b9e45737315.jpeg)


`SD` と打つと
![sdcard_info.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2063214/93f45a47-2981-5ba3-e9da-e76ebb9ba8d2.jpeg)

ををｗ

#6. 最後に
捨てる神あれば拾う神という事で
みなさまも机の中にある SDカード変換基板
半田付けして有効活用してみませんか？
ご清聴ありがとうございましたっ
勤怠管理の作成を目指す＋α：Day１

　会社から「座学だけで勉強が進む性格していないでしょ？ 勤怠管理作ってみてよ」と提案され、全くもってその通りだったので、JAVA SEの取得目標と合わせて進めていこうというログとなります。

　ひとまず、指針を決めにゃダラけ街道まっしぐらなので、今日は簡単な指針を決めるとこから。
　ついでに、その日の計画をその日に立ててもダレたりやらなかったりする甘ったれな性分なので、次の日の目標を立てて消化できたか否かを振り返ろうと思います。

今日やったこと
---------
・勤怠管理の前に、打刻を通すことだけを考える必要がある
・打刻を通す前に、ボタンを押したら同じページに時間を出力する
上記から、下記サイトを参考にやってみる
https://eng-entrance.com/java-get-time

明日やること
----------
・上記サイトを読み進めて実践してみる
・勉強としてUdemyの動画を進める