OmniAICreator/Qiita-1.07M huggingface dataset:
PostgreSQL13 1600カラムを1000万件いれてみた

## やりたいこと
カラム数の多さがどれだけパフォーマンスに影響するのかを確かめたいと思いやってみました。
そこで、PostgreSQLのMAXである1600カラムを作成し、データを1000万件入れました。

##結論から
かなりの差がでます。
select count(*)を行うと致命的
他にもデータ自体を検索してしまうとカラム数が多い場合、実行時間がまともに動作しないレベル。
カラム数はあんまり多くしないようにしましょう。
もちろん、インデックスは使いましょう。

## 前提
PostgreSQLで使ったのはAWS RDS(t3.micro)です。
以下の2つのテーブルを比べることでパフォーマンスを比較します

■testテーブル
　・カラム数は、以下の3つ　
　　1.character varying(256)
　　2.integer
　　3.timestamp with time zone
　・CSVでインポート。サイズは650MBほど
　・1000万件のデータがあります。
　・インデックスなし
 
■test_1600テーブル
　・カラム数は、以下の1600個 
　　1.character varying(256)
　　2.timestamp with time zone
　　3.integerが1598カラムあります。
　・CSVでインポート。サイズは73GB・・(汗 でかい
　・1000万件のデータがあります。
　・インデックスなし

## データ個数確認！

カラムが多いと実行時間が123倍かかるようです。

■testテーブルは1000万件確認
約4秒かかりました。
![スクリーンショット 2021-12-09 15.28.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/2e3b2353-a9f9-5179-c4f2-e86341d70dee.png)

実行計画を見てみます
![スクリーンショット 2021-12-09 15.34.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/714f51ba-8d76-ca31-6035-89d6cd63d6c5.png)

■test_1600テーブルも万件確認
約10分かかりました・・これはまずい
![スクリーンショット 2021-12-09 15.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/c38a0428-3ff9-896f-b97b-e302bfc2c168.png)

実行計画を見てみます
Excustion Timeが実行時間です。10分ほどかかってます。
![スクリーンショット 2021-12-09 13.52.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/6530d1c7-87dd-18f5-ce18-07cb4c69d314.png)

##インデックスがない状態で1行取得してみる
存在しないデータを取得してみる
カラムが多いと実行時間が78倍かかるようです。

■testテーブル
約4秒
![スクリーンショット 2021-12-09 15.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/a0d209e7-734d-a4a5-9e6e-0fc5447a41aa.png)

■test_1600テーブル
約314秒
![スクリーンショット 2021-12-09 15.47.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/dd86ca81-13c4-0797-9e99-b9b03d468e7c.png)

##インデックスがある状態で存在する1行取得してみる

■testテーブル
インデックスはると、データ自体を使わないため、あんまりかわらないですね

約0.038ms
![スクリーンショット 2021-12-09 16.06.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/fbbaf6ed-2c38-9bbd-348c-18da6b24d9a2.png)


■test_1600テーブル
約0.245秒
![スクリーンショット 2021-12-09 16.08.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/1ca9119e-def5-57e8-0ccd-22c2d69b1af1.png)

##CPU使用率もスパイクしまくる
select count(*)と、インデックスなしでアクセスしたからだと思います。
![スクリーンショット 2021-12-09 16.13.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/ce344cfe-1259-41b2-cfe8-8f693c332e36.png)

##読み取り IOPS
![スクリーンショット 2021-12-09 16.19.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681795/342d88e6-eede-5181-0940-90a9d48a3821.png)
【備忘録】youtube-dlの使い方（まとめ）

# はじめに
youtube-dlの使い方を忘れてしまうので自分用の備忘録も兼ねて残しておきます。
本記事では、pipを用いてyoutube-dlをインストールし、YouTubeの動画をダウンロードする方法をご紹介します。
なお、[こちら](https://wisteria-yt.blogspot.com/2021/03/youtube-dl.html "youtube-dlの使い方"
)のリメイク版です。また、初投稿なので温かい目で読んでいただけると幸いです。

# 環境
<dl>
<dt>macOS X</dt>
  <dt>Python 3.3以上</dt>
  <dd>venvを使うため</dd>
</dl>
venvの使い方・youtube-dlのインストールは下で解説します。

# 使い方（結論）
```zsh
#作業ディレクトリに移動
python3 -m venv env #venvで仮想環境(env)の作成
. env/bin/activate #仮想環境(env)の有効化
pip install youtube-dl #youtube-dlのインストール

youtube-dl -f mp4/best --no-check-certificate "https://www.youtube.com/watch?v=〇〇" #動画の場合
youtube-dl -f m4a/bestaudio --no-check-certificate "https://www.youtube.com/watch?v=〇〇" #音声のみの場合
```
`https://www.youtube.com/watch?v=〇〇`にはダウンロードするYouTube動画のリンクを入れてください。

# 詳細解説
ここからはそれぞれの部分について解説します。

## `--no-check-certificate`について
`CERTIFICATE_VERIFY_FAILED`というはエラーが発生する場合があリます。
これは、証明書が読み込めないことによって発生するため、証明書のパスを与えるか無視するように指定します。
`--no-check-certificate`は証明書を無視するオプションです。

## `-f`について
`-f`オプションを指定することで、ダウンロードするファイルの形式を指定することができます。

>フォーマットの指定は番号以外に以下も使用できます
>
> - best：音声付き動画のなかで高画質もの
> - worst: 音声付き動画のなかで低画質もの
> - bestvideo: 音声なし動画のなかで高画質もの
> - worstvideo: 音声なし動画のなかで低画質もの
> - bestaudio: 高品質の音声ファイル
> - worstaudio: 低品質の音声ファイル

[Tips: youtube-dlの使い方](https://t-pirori.blogspot.com/2019/09/youtube-dl.html)より

# 参考資料

- [[youtube-dl] python3のSSLエラー(CERTIFICATE_VERIFY_FAILED) - Qiita](https://qiita.com/tommy19970714/items/96edba36dfde468e26f3)
- [Tips: youtube-dlの使い方](https://t-pirori.blogspot.com/2019/09/youtube-dl.html)
[k8s] 問題が起きたpodを（雑に）隔離する

# 障害対応にて
ユーザーに影響があるような障害が発生してしまった場合、やはり素早い復旧が望まれます
一方では、障害の原因を調査するために障害が起きた現場を残したい、という事情もあります

その場合、バックアップや代わりになるインスタンスを用意して、障害が起きたものと入れ替えるという流れで対応するのがまあ定石です

# kubernetesで

今回、はkubernetesクラスタにおいて

- deployment（replicaset）が展開している複数のpodのうちひとつが、何らかの原因でエラーを返すようになってしまった
- readinessProbeは通っていて、問題の起きたpodへのトラフィックは止まらない

という状況で、問題の起きたpodを削除するのではなく、残したまま隔離して復旧させます

# 手順

__これは正規の手順ではないので自己責任でお願いします__

- 問題の起きたpod（以下A）の名前を取得
- `kubectl edit` でAを編集する
  - Aにトラフィックを流してるserviceの`spec.selector`に一致しなくなるように`metadata.labels`を変更する
      - `app: myapp` を `app: myapp-broken` にするなど
- 編集を保存すると、Aはdeploymentから外れた感じになり、勝手に新しいpodが補充される
  - もうAにトラフィックが流れなくなっているので、煮るなり焼くなり
- 不要になったら手動でAを削除する
  - これを忘れるとゴミとして残り続ける

# 注意
設定次第では隔離したpodのログやメトリクスが保存できないことがあるので注意してください
podのlabelを変更すると、`.metadata.ownerReferences`が消えるっぽいです

---

正しくやろうと思ったら、同じ内容で名前とlabelを変えたdeploymentを用意してserviceのselectorを変更して…みたいな流れになるんでしょうか
ちゃんと検証してクラスタの管理方法に合わせて手順をしっかり固めたいボリュームですね
はじめてminicomを使うとき

# minicom インストール

`minicom`がインストールされていない場合、次のコマンドでインストールします。

```shell
sudo apt install minicom
```

![minicom-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/00a34231-8b67-4b54-5fcf-70738190921d.png)

# dialoutグループへの追加

`minicom`をroot権限無しで使えるようにするために自分のアカウントを`dialout`グループに追加します。
`$USER`はログインしているユーザーアカウント名です。
また、グループへの追加を反映させるには再起動が必要なので `shutdown`コマンドで再起動します。

```shell
sudo usermod -a -G dialout $USER
sudo shutdown -r now
```

再起動後に、`id`コマンドでグループに追加されていることを確認してください。

![minicom-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/a173bb6c-3900-e057-1b0d-33f68a3da332.png)

# minicom 起動

`-D`オプションでデバイスファイルを指定して `minicom` を起動します。

```shell
minicom -D /dev/ttyUSB0
```
![minicom-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/6f6f8026-915c-0011-c0e5-f7c6e6f3c3e2.png)

出力はされているが、なぜかキーボードからの入力を受け付けてくれない。。。
![minicom-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/9418aacc-0f18-28d3-7c7a-89c335a9d720.png)

デフォルト設定でハードウェアフロー制御が有効になっていることが原因のようです。。

# minicom 設定

`minicom` 上で、`Ctrl + a` -> `z` キーを押すと、ヘルプ画面が出てきます。
日本語表示の場合、フォント幅の問題で表示が崩れていますが無視して続けます。
![minicom-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/47357568-ad3a-3020-a3ed-53cce4abe173.png)

ヘルプ画面で `o` キーを押して、設定を開いた後に、
カーソルキーで `シリアルポート` に合わせて `Enter`キーを入力する
![minicom-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/e554b410-e60d-8b98-be11-a61baa777890.png)

確かに、`ハードウェア流れ制御` が `はい` になっています。(流れ制御って...) 
![minicom-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/02ee7bd6-0de0-b4c6-285f-218bafa3e0d8.png)

`f` キーを押して、`いいえ` に変更します。(おかしな位置に「いいえ」が書かれていますがそれでOK)
![minicom-a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/bb26544f-2c68-2b28-fac8-f35139d860ba.png)

そのまま `Enter` か `Esc` キー押して、設定画面まで戻ります。
`"dfl"に設定を保存` を押して保存します。
![minicom-b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/0b465098-4c2b-3a29-0573-05f32399814c.png)

設定を終了します。
![minicom-d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/f24e43d8-6cad-275e-5214-98902574e29d.png)

めでたくキーボード入力を受け付けてくれるようになりました。
![minicom-e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/ab2a0fd1-3c5e-45ae-3a62-52985fe4f870.png)

# minicom 終了

`minicom`を終了するときは、`Ctrl + a` -> `z` -> `x` -> `Yes`
もしくは、`Ctrl + a` -> `x` -> `Yes` で終了します。

# 補足

英語表示で使用する場合は `LANG=C` を指定して `minicom` を起動します。

```shell
LANG=C minicom -D /dev/ttyUSB0
```

英語なら画面も綺麗に表示されます。
![minicom-i.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/2605e2a8-3a8d-74f6-1717-05dd95779619.png)
nodeでhttpサーバーが立ち上がらなくて四苦八苦した話

#概要
同僚とWebアプリを開発しているときに、環境差分でトラブルに見舞われることはよくあると思うのですが、自分の場合なかなか原因が掴みづらかったので、解決に至った手順を書こうと思います。

#エラー内容

```
Error: listen EADDRINUSE: address already in use 0.0.0.0:8081
```
8081ポートがすでに使われているから、nodeでサーバー立ち上げられないよ。というエラー。
ですが、ここの問題に取り組む前にnodeの環境揃えとかんと話にならないということで、nodenvを使ってバージョンを揃えます。

#nodenv導入
MacOSを利用しているので、zshで実行しています。

```terminal
brew install nodenv
```
nodenvをインストールしてから以下のコマンドを実行します。

```terminal
eval "$(nodenv init -)"
```

次に、カールでこちらを実行します。

```terminal
$ curl -fsSL https://github.com/nodenv/nodenv-installer/raw/master/bin/nodenv-doctor | bash
```

これでOKがコンソールに表示されていれば、nodenvの設置完了です。

# 指定バージョンのNodeをインストール

今回は、Node.jsの14.17.3をインストールしたいと思います。

```terminal
nodenv install 14.17.3
```

nodenvに認識させます。

```terminal
nodenv rehash
```

ディレクトリ配下でバージョンを適用させる場合

```
nodenv local 14.17.3
```

システム全体でバージョンを適用させる場合

```
nodenv global 14.17.3
```

nodeのバージョンを確認してみましょう。

```
node --version
# v14.17.3
```

# プロセスを消しにいく
指定されたポートがすでに利用されているならば、ポートを塞いでいるプロセスを落として仕舞えばいいじゃない。ということでkill processします。

```
ps aux | grep node
```

これで表示されるプロセスを全消しして、再度nodeコマンドを実行するも、ポート8081がすでに利用されているというエラーは変わらない。

そんな時はこちらを試してみてください。

# ポートを指定してPIDを消す
下記コマンドを実行します。

```
lsof -i :8081
```

これは、LiSt Open Fileの頭文字をとったコマンドで、プロセスが開いているファイルを列挙するコマンドになっています。先ほどはnodeを文字列に含むプロセスを探したのですが、今回はportを指定してプロセスを探しにいきます。

これで表示されたPIDをkillしてあげたら、僕の場合は無事実行することができるようになりました。

# 最後に
nodenvにもっと早く出会ってればよかったです。
管理しにくいgistをvscodeで管理できないか色々やってみた

## 結論
[Gistpad](https://marketplace.visualstudio.com/items?itemName=vsls-contrib.gistfs)マジおすすめ

https://marketplace.visualstudio.com/items?itemName=vsls-contrib.gistfs

## 使い方
1. [githubのPAT(パーソナルアクセストークン）](https://github.com/settings/tokens)でgistの権限を与えて発行する
1. GistPadを入れる
1. アイコンが作成されるので、このアイコンから認証情報を入れる
1. ついでにGithubリポジトリもいじれる

ファイルを一ついじったら即コミット・即プッシュされるので、使い勝手が良いかどうかは人によりけり。

## 参考、というか全て
https://zenn.dev/ymmmtym/articles/gistpad-vscode-extension
(*ﾟ▽ﾟ)ﾉ((({})=>({})))()

オブジェクトがあって、

```javascript
const obj = {
    num:"1",
    name:"田中",
    room:"A",
    club:"soccer"
}
```

必要な項目だけ欲しいとき

```javascript
const newObj = ((({num,room})=>({num,room})))(obj)
```
【まとめ】2021年W3Cの勧告をサクッと振り返ってみた

## 改めてW3Cってなに？
W3Cは「Web技術の標準化を行う非営利団体」でWeb標準規格を決めている団体です。
Web標準規格は、開発者がWebブラウザのバージョンごとの互換性を保証するために知っておくべきルールのことです。

## 2021年W3Cの勧告を振り返る
この記事ではHTMLとCSS関連の勧告について振り返りたいと思います。

### HTML
HTMLの勧告は

- 「HTML Living standard」での定義
- W3CのHTML5.2や5.1の廃止勧告
- HTMLのARIAの適合性チェックツールで使用するための要件を定義

の3点でした。

#### Canvas要素の2DContextに関する定義
「HTML Living standard」での仕様を定義するものでHTML5で定義されていた仕様と変更されたところはない模様です。
確認しましたが漏れていたらすみません…

https://www.w3.org/TR/2021/SPSD-2dcontext-20210128/

#### HTML5.2 / HTML 5.1 2nd Edition
廃止勧告したからこれからは新しい仕様でコーディングしてください！
ってことだと思います。

現在は[HTML Living standard](https://html.spec.whatwg.org/multipage/)に準拠しないといけません。

https://www.w3.org/TR/2021/SPSD-html52-20210128/

https://www.w3.org/TR/2021/SPSD-html51-20210128/

#### HTMLのARIA
開発者がチェックをするためのツールとして勧告されたようです。
ダメな例が書いてあるのでWAI-ARIAの実装にはこちらの勧告を見れば良いかと思います。

https://www.w3.org/TR/2021/REC-html-aria-20211209/

### CSS
CSSの勧告は、

- 誤字の修正とW3C勧告のステータスとスタイルの変更
- サンプルHSL値と変換コード
- ASCIIの大文字小文字を区別しない
- プロパティ定義テーブルから「メディア」を削除
- 削除された機能の開発はCSSColor4で継続

#### CSSのカスケードと継承

https://www.w3.org/TR/2021/REC-css-cascade-3-20210211/

#### 前景色とグループの不透明度の色の値とプロパティについて
「ASCIIの大文字小文字を区別しない」「プロパティ定義テーブルからメディアを削除」など言葉の意味はわかってもそれがどのように影響するのかまでは落とし込めていない自分がおります…。

今回はそんな変更がされたということで知識として脳内に収めておきたいと思います。

https://www.w3.org/TR/2021/REC-css-color-3-20210805/

## 今年草案になって個人的に気になっている仕様
CSSがネストして記述することができるよー。っていう草案です。
個人的には早く実現してほしいなと思いながら、全てのブラウザが対応してくれるのはいつ頃かな。
正式勧告を楽しみに待ちたいですね！

https://www.w3.org/TR/2021/WD-css-nesting-1-20210831/

## まとめ
「細かい仕様は把握できてないな…」
「これどおいうことやろ…」
と確認するたびに感じます…。
しかし、繰り返し読むことで少しずつ身になること信じ、
確かこんなこと書いてあったな…と
知識を出したりしまったりを繰り返し、自分のものにしていければと考えています。
LGPL・GPL とは

## 勉強前イメージ

GPLライセンスって聞いたことあるけど、実際知らない・・・

## 調査

### GPLライセンス とは

GNU General Public License の略で、GNUプロジェクトのために作られたライセンスです。
現在はフリーソフトウェア財団で公開・管理されています。
GPLは著作物の自由な利用・改変・再配布する権利を提供して、
派生した著作物についても制限してはならないというコピーレフトという概念になります。
商用利用も可能で、フリーでならないといけなという制約もありません。
GPLは他のライセンスと比較すると比較的制限が強いライセンスになります。

特徴としては以下になります。

- 著作源の表示を保持しないといけない
- 無保証
- 自由に複製・改変・頒布ができます
- コピーレフト

### LGPL とは

コピーレフトの概念を導入したGNUのライセンスになります。
LGPLはGPLをベースとしていますが、
GPLとは違いLGPLので公開されたソースを使ってソフトウェアを開発しても、独自の部分のソースコードの公開は強制しない特徴があります。
(上記の4つの目の箇所が違います。)
GPLは上記の同様の環境であれば公開しないといけないです。
LGPLはGPLより制限を緩和したライセンスになります。

## 勉強後イメージ

GNUプロジェクトのためのライセンスってことか。
基本的には自由に変えていいけど、その後のソースコードをどうするかってことか。

## 参考

- [【Python】LGPLライセンスの商用・配布時での取り扱いについて](https://office54.net/python/license/license-lgpl)
- [LGPL](https://www.weblio.jp/content/GNU+LGPL)
U22プロコンの感想と反省 - 2021

# 自己紹介
高専3年生、ゲームとかお絵描きとかしてる人
専門というか詰めてるところはDL,特にGAN
twitterは@kosakae256

# はじめに
U22プロコン2021の最終選考会に登壇しました
最優秀狙ってましたが、企業賞止まりでした
今回はその反省を適当に書いていきます
ポエムみたいなものです。つまりごm
初めに言っておきますがひとりごとです！！！！！！！！
文章力も語彙力も0.256くらいしかないです

# 作品紹介
簡単な作品紹介だけ
私たちは「よそくる」というアプリを開発しました
よそくるを使うと、来訪者の数や特性の傾向を分析できます
特性というのは具体的に、家族層や富裕層、男女比などがあげられます
サイトです。今は動いてないですが11月21日以前の推定結果なら見れます

https://ezaki-lab.littlestar.jp/2021comlyse/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1128128/15510557-330c-1eb0-ecbc-fa2e66b60398.png)

この作品の大きな特徴として、「車から推定する」というものがあります
人間に関しては見ていません。車だけで来訪者の推定を行っています。
そのため、もし実現すれば実用的で大変価値のあるプロダクトとなっています
カメラを置くだけで、来訪者の傾向を予測できるんですから

# 経緯
作品を作るに至った経緯から
研究室長からの提案と、2年間先輩方がやってきたプロジェクトの引継ぎが主です
もともとは過去のデータの閲覧だけが目的でしたが、面白くないしそんなのどこでもできるということで、新規に始まりました
未来の予測と傾向の予測をする案は私と研究室長が出しました
もしできたらめちゃくちゃ面白いよねということで、正直当時は100%無理だと思ってました


# 大変だったこと
### 特性分析
家族層や富裕層などを予測するやつ
これは研究室長の案なのですが、機械学習で何とかしろと
無理にもほどがありました、予選時点では全国の統計を基に計算することでそれっぽくはなってました
最終選考時点では、ベイズの定理を使って予選時点よりは良いものにはなってました
ただこれもフィードバックによると、かなり乱暴なやり方ではあるとのこと
逆に実現できるならどういうことをすればいいか、気になるところではあります

### DL
このプロダクトは「AI」として応募しているので当然機械学習がかなり使われています
車種、車色、ナンバープレート領域抽出、文字起こしなどなど
なにが大変って、データがとにかく集まらないんですよね。
DAすることでなんとか精度を上げました

### 機材の故障
jetsonめっちゃ壊れて20日くらい作るのかかった
ここに時間割きすぎたせいで穴がうまれたんですよね

### 時間との闘い
実は、1か月で予選用のプログラムを書きました
しかも最終選考会の1週間前にテスト始まって2日前に終わりました
なんというタイミング...！
がちで時間なくて困ってましたね...

# 反省
ここからは反省を書き残します

### ダメだった点
##### 詰めが甘かった
検出部分をやりすぎたせいで、未来の予測、傾向予測の実証ができなかったことが一番悔しい
審査員にも当日咎められましたが、まさにその通りだと思いました
検出部分なんて、誰かがもうやってるようなことなので、面白くもすごくもない
こっちを商用利用できるレベルでガチにしたところで感は今思うとあります

##### 時間配分のミス
機材つくるのに明らかに時間使いすぎましたね
raspberry piで出したくなかったので仕方ないですが、見切りはつけたほうがよかったかもなぁと思います

##### 色々と適当だった
時間がなかったことにも起因しますが、バックエンドからフロントエンドの実装も結構適当にしてしまっていたし
一番は理論の組み立てがかなり甘かったかなと
しっかり組み立てて、最適な方法を選んでいたら普通に実用的だったんじゃないかなと思います
やっぱり開発ばっかやってても駄目だなと思いますね

### 良かった点
##### 詰めるところは詰めれた
ナンバープレートから文字認識をするフェーズがあるのですが、そこの精度を高める方法を試行錯誤して試せたのは良かった
やることはやって、やれる限界を詰めれた。

##### 報連相をしっかりできた
研究室長、先輩、僕の3人だけで進めていたプロジェクトでしたが、そんな小さなグループであっても報連相は欠かしてません
これ、やっぱり大事だと思います。状況把握できてないと誰も動けなくなって詰むので。実際高専プロコン組はちょっと怪しかった


# 学べたこと
一番頑張ったやつが一番強くて一番すごい。
これだけです。

# 全体の感想
いままで下か横くらいしか見てませんでしたが、世界の広さと相手にしようとしていた人たちの強大さを知りました
上だけを見ていると息が詰まりそうです
最終選考に残れただけでもすごいといろんな方に言われますが、やっぱり悔しいです
次があるかわかんないけど、今回の結果を生かして、次出るコンテストこそはトップを取りたいなと思います

# 最後に
こんな記事を読んでくださりありがとうございました。
そしてもしかすると審査員や運営の方々もこの記事を見ているかもしれないので一言
最終選考の枠に選んでいただき、審査してくださり、本当にありがとうございました。おかげで成長できました。

そして次のU22プロコンに出ようと思ってる方に、未熟ながら一つだけアドバイスします

努力は決してあなたを裏切りません

それでは、また今度。
Raspberry PiにNode.jsのインストールをして起動時に自動実行させるまで


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

ラズパイでNode.jsを動かすをたまにやりますが、久々に触った時に忘れてることが多いので久々に触る時用にまとめておきます。

[昔書いてた記事](https://qiita.com/n0bisuke/items/2c89610fd704e806c758)よりもシンプルでした。

ラズパイにNode.jsをインストール -> 永続化 -> 自動起動 みたいなところまでをやります。

## 事前準備

vimは使いたいのでインストールしておきます。

```bash
$ sudo apt update -y
$ sudo apt upgrate -y
$ sudo apt install vim -y
```

## nodebrewでNode.jsのインストール

Node.jsをnodebrew経由でインストールします。

### nodebrewのインストール

```bash
$ curl -L git.io/nodebrew | perl - setup
```

パスを通します。

```bash
$ vim ~/.bashrc
```

> export PATH=
HOME/.nodebrew/current/bin:HOME/.nodebrew/current/bin:
PATH

これを追記。

```bash
$ source ~/.bashrc
```

これでnodebrewのインストール完了です。

### Node.jsのインストール

```bash
$ nodebrew install-binary latest
$ nodebrew use latest
use v17.1.0
```

最新版がインストールできました。

```bash
$ node -v
v17.1.0

$ npm -v
8.1.2
```

## PM2で自動起動と永続化

古き良きなのか昔からPM2を使って永続化をしています。

```bash
$ npm i -g pm2
```

これでpm2がインストールできます。

### PM2で永続化

- app.jsを永続化

```bash
$ pm2 start app.js
```

- 永続化の確認

```bash
$ pm2 list
```

### PM2で自動起動設定

永続化だけだとラズパイが再起動したときに起動してくれないので、自動起動の設定もします。

`pm2 startup`を実行することで、その環境（今回だとラズパイ/ラズビアンOS）でどのコマンドを実行すると良いかを教えてくれます。`pm2 startup`を実行するだけではダメなので注意。

```bash
$ pm2 startup
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/home/pi/.nodebrew/node/v17.1.0/bin /home/pi/.nodebrew/node/v17.1.0/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
```

表示されたコマンドをコピペで実行します。

```bash
$ sudo env PATH=$PATH:/home/pi/.nodebrew/node/v17.1.0/bin /home/pi/.nodebrew/node/v17.1.0/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
```

実行すると色々表示されますが、`Command successfully`と出てるので成功っぽいです。

```bash
・
・
・
[PM2] Writing init configuration in /etc/systemd/system/pm2-pi.service
[PM2] Making script booting at startup...
[PM2] [-] Executing: systemctl enable pm2-pi...
Created symlink /etc/systemd/system/multi-user.target.wants/pm2-pi.service → /etc/systemd/system/pm2-pi.service.
[PM2] [v] Command successfully executed.
```

最後に`pm2 save`をすることで設定が保存されます。

```
$ pm2 save
[PM2] Saving current process list...
[PM2] Successfully saved in /home/pi/.pm2/dump.pm2
```

ここまでで自動起動の設定になるっぽいので`pm2 save`まで実行しておきましょう。

再度に再起動して完了です。

```
$ sudo reboot
```

たぶん問題なく`app.js`のプロセスが実行されてると思います。

- 自動起動を解除するとき

これは環境によってことなりそうですが、ラズパイの場合は以下でOKな気がします。

```bash
$ pm2 unstartup systemd
```

## まとめ

- vimをインストールしておく
- nodebrew経由でNode.jsをインストール
- PM2で永続化 & 自動起動設定

という流れで個人的によく使うラズパイ運用はカバーできそうな気がしました。

`pm2 startup`は **このコマンドを実行するだけではダメ**ってのがいつも忘れそうになるポイントですね。

基本自分用ですが、誰かの参考になれば幸いです。
【SQL】基本コマンド

##よく使うコマンド集
####大まかな実効される順番

```
SELECT　 列名 [表示用列名]
FROM テーブル名
JOIN　テーブル名　ON fromのカラム = joinのカラム
WHERE　 抽出条件を指定
GROUP BY　 カラム
HAVING 抽出条件を指定
ORDER BY　並べ替えたい順
LIMIT　　抽出したい数
```

####使用例
・select、from

```
SELECT 列名 [表示用列名] FROM テーブル名; #テーブルから列を抜き出す。
SELECT * FROM テーブル名 #アスタリスク（*）は全てを選択するとい意味。
```

・join

```
INNER JOIN 表２ ON 表１id = 表2.id;
LEFT/RIGHT OUTER JOIN 表2 ON 表1.id = 表2.id;
```
◆INNER JOIN

```
INNER JOINは、結合するテーブルのデータのうち、条件に指定したカラムの値が一致するデータのみを結合。

例：
table1の要素　　　　　　　table2の要素
id name　　　　　　　　　　　　　　　id section
　1 鈴木　　　　　　　　　　　　　　　　　　　1 営業
　2 佐藤　　　　　　　　　　　　　　　　　　　2 総務
　3 田中　　　　　　　　　　　　　　　　　　　5 経理
　4 山本

実行結果↓
id name id section
　　1 鈴木 　　　1 営業
　　2 佐藤 　　　2 総務
```

◆LEFT/RIGHT OUTER JOIN

```
LEFT OUTER JOINは、左側のテーブルを全て取り出し、その右側のテーブルのうち、条件に指定したカラムの値が一致するデータのみ結合。なお右側に結合するテーブルに一致するカラムが無い場合は、NULLが入る。RIGHT OUTER JOINはLEFTの逆である。

例：
table1の要素　　　　　　　table2の要素
id name　　　　　　　　　　　　　　　id section
　1 鈴木　　　　　　　　　　　　　　　　　　　1 営業
　2 佐藤　　　　　　　　　　　　　　　　　　　2 総務
　3 田中　　　　　　　　　　　　　　　　　　　5 経理
　4 山本

LEFTの場合↓
id name 　　id 　　　section
　　1 鈴木 　　　　　1 　　　　　　営業
　　2 佐藤 　　　　　2 　　　　　　総務
　　3 田中 　　null 　　null
　　4 山本 　　null 　　null

RIGHTの場合↓
id 　　　　　name　　　 id section
　　1 　　　　　鈴木 　　　　　　1 営業
　　2 　　　　　佐藤 　　　　　　2 総務
null 　null 　　　　　5 経理
```

・where、having
*-where,havingの違い-*
「WHERE」も「HAING」と同じく「抽出条件を指定」するコマンドだが、違いはコマンド実行順の違い。
WHERE・・・グループ化をされる前の段階、つまり元々のデータでの抽出条件を指定できる。
HAVING・・・グループ化した後の情報での、抽出条件を指定できる。

```
ほとんどの比較演算子が使える（>,<,+,-,=,/,*,or,andなど）
WHERE user_id = 1; #user_idが１と同等のもを取り出す
WHERE date >= 2020-01-01; #２０２０年１月１日　以降　を取り出す
WHERE date <= 2020-01-01; #２０２０年１月１日　以前　を取り出す
WHERE food LIKE "%チョコ%"; #foodカラムから「チョコ」を　含むもの　を取り出す
WHERE food NOT LIKE "%チョコ%"; #foodカラムから「チョコ」を　含まないもの　を取り出す
```

・group by

```
「種類ごとに集計関数を使用する」などといった形で使用するケースが多い。
以下のように、名前とチームが入っている「userテーブル」があったとし、
グループ化を行う「GROUP BY」と数を数える「COUNT」を利用すれば、グループごとの人数を算出できる。
|　　name 　| 　　team　　　|
| 田中 　　| チームA |
| 鈴木  | チームB　　|
| 佐藤  | チームB |
| 山田  | チームA |
| 加藤  | チームA |

SELECT team, COUNT(team) FROM user GROUP BY team;
↓実行結果
|　　 team  　| 　　count(team)　　　|
| チームA  |       3      |
| チームB  |       2     　　|

```

・order by

```
ORDER BY カラム ASC #昇順 (1,2,3,4,5...)
ORDER BY カラム DESC #降順 (100,99,98,97...)
```

・limit

```
LIMIT 数字;　#取得するデータの行数の上限を設定
```

####その他よく使いそうなコマンド
**２つのカラムを用いて１つのカラムにする**
・CONCAT

```
CONCAT(テーブル名.カラム名,"間に入れたい文字",テーブル名.カラム名) AS 合わせたカラムの新しい名前

例：
SELECT CONCAT ( user.year,".",user.month,".",user.day) AS Happy Birthday ;

実行結果↓
Happy Birthday
-------------------------  
2000.01.01  
```


####参考記事
[SQLの基本とも言えるテーブル結合、その種類と使い方について解説](https://style.potepan.com/articles/17010.html)
[SQL基本コマンド一覧まとめ](https://qiita.com/shuyam/items/809ff4123d8dcb7321f9)
[SQLで特定の文字を含むor含まないレコードの取り出し](https://qiita.com/HorikawaTokiya/items/7894f27a3997c499cf95)
[【初心者向け】SQLのWHERE句で日付を比較する方法まとめ！](https://style.potepan.com/articles/24654.html#SQL3)
[【SQL】GROUP BYで自在に集計!集計関数やHAVINGと合わせて使おう](https://www.sejuku.net/blog/72923)
[【SQL】一目でわかる!HAVINGとWHEREの違いと活用方法](https://www.sejuku.net/blog/73003)
STM32L010と(VSCode+STM32Cube)でI2Cスレーブで遊ぶ(受信)(STM32L010F4P6)HAL



x プルアップ抵抗を忘れずに10kΩがおすすめ
x 過去ログを見よ->
x CubeMXは、nucleo-l011
x VSCodeは、nucleo-l011


目的
I2Cスレーブのテスト

参考



https://gsmcustomeffects.hatenablog.com/entry/2017/04/03/023111




I2C_SLAVE_TEST1_010_1内を適当にコピー



https://os.mbed.com/users/caa45040/code/f303_h_p1/



![o_con140.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/ae873f8a-30c6-9d04-64f9-0c6e218262b9.jpeg)



![o_con141.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/37b12b64-4a5c-61ed-d4eb-cddf2857578b.jpeg)



![o_con147.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/b3243720-ca21-dab0-ec34-47d44798d96a.jpeg)



![o_con148.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/540e65dd-6cb4-f24a-f131-63a017703238.jpeg)



![o_con149.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/beee2eae-fc1e-0ed8-7745-443da0078ec2.jpeg)



![o_con150.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/7c538525-cb15-d3ce-8476-4b63643930ca.jpeg)



![o_con151.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/bd44f96f-e667-ff53-d1e8-31ceccccbfa9.jpeg)




main内のwhile内


```c++




        uint8_t aRxBuffer[1] = {0};
        char *str1 = 0;
        //aRxBuffer[0] = 0 ;

        if(HAL_I2C_Slave_Receive(&hi2c1,(uint8_t*)aRxBuffer, 1, 1000) == HAL_OK) {
           str1="OK\r\n";
            
        } else {
           str1="NG\r\n";
            
        }
        
        //ステータスの表示
        HAL_UART_Transmit(&huart2, (uint8_t *)str1, 4, 10);
        
        //I2Cスレーブの受信データの表示
        HAL_UART_Transmit(&huart2, (uint8_t *)"\tRead A: ", 9, 10);
        uint8_t n1  = '0' + (aRxBuffer[0] % 10);
        uint8_t n10 = '0' + (aRxBuffer[0] / 10);
        HAL_UART_Transmit(&huart2, &n10, 1, 10);
        HAL_UART_Transmit(&huart2, &n1, 1, 10);
        HAL_UART_Transmit(&huart2, (uint8_t *)"\r\n", 2, 10);

        HAL_Delay(200);//0.2秒待つ







```



I2C内


```c++


  hi2c1.Init.OwnAddress1 = 0x80;



```
お料理.cs

```c#:main.cs
using System;
using System.Collections.Generic;


class Program
{
	static Osaihu osaihu = new(100);
	static Dictionary<string, Guzai> supermarket = loadSuper();
	static Dictionary<string, List<string>> recipe = loadRecipes();
	static Nabe Main(string[] args)
	{
		Console.WriteLine("お料理開始！");
		if (args.Length == 0) return null;
		if (recipe.TryGetValue(args[0], out var list))
		{
			var bag = shopping(list, osaihu);
			Nabe nabe = new();
			nabe.AddAll(bag);
			nabe.Nikomu(100);
			return nabe;
		}
		return null;
	}
	static List<Guzai> shopping(List<string> list, Osaihu osaihu)
	{
		List<Guzai> cart = new();
		foreach (var item in list)
		{
			if (supermarket.TryGetValue(item, out var guzai))
			{
				cart.Add(guzai);
			}
			else
			{
				cart.Add(null);
			}
		}
		List<Guzai> bag = new();
		int sum = 0;
		foreach (var item in cart)
		{
			sum += item.price;
			bag.Add(item);
		}
		osaihu.Withdraw(sum);
		return bag;
	}
}
```

```c#:osaihu.cs
class Osaihu
{
	int money;
	public Osaihu(int m)
	{
		money = m;
	}
	public void Add(int m)
	{
		money += m;
	}
	public void Withdraw(int m)
	{
		money -= m;
	}
}
```
```c#:guzai.cs
enum GuzaiState
{
	packed,
	unpacked,
	cutted,
}
class Guzai
{
	public string name { get; }
	public int price { get; }
	public double tempreture { get; set; }
	const double DEFAULT_TEMPRETURE = 10;
	GuzaiState state = GuzaiState.packed;
	public Guzai(string name, int price, double tempreture = DEFAULT_TEMPRETURE)
	{
		this.name = name;
		this.price = price;
		this.tempreture = tempreture;
	}
}

```

```c#:nabe.cs
class Nabe
{
	List<Guzai> contents = new();
	public void Add(Guzai guzai)
	{
		contents.Add(guzai);
	}
	public void AddAll(List<Guzai> guzais)
	{
		contents = guzais;
	}
	public void Nikomu(double min)
	{
		foreach (var item in contents)
		{
			item.tempreture += min * 1.5;
		}
	}
}

```
【Rails】escape_javascriptメソッド【jQuery】

## はじめに
　本記事は、プログラミングの学習を始めて1ヶ月の初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## 今回の疑問点
　今回の疑問点は、

　　_escape_javascriptメソッドについて_
　
　です。　

 　以前、非同期通信でのコメント投稿機能を実装した際に上記について疑問を抱きました。

## 疑問点についての解説

###結論
　JavaScriptファイルの中にHTMLを記述するときに実行結果をエスケープするためのメソッド

###エスケープ処理とは

 エスケープ処理とは、記述したコードのままでは意図した通り表現できない文字列や改行を表現するために使用する、代替文字列処理のことです。

具体的には以下のような文字列を表すために使用します。
!"#$%&'()*+,./:;<=>?@[\]^`{|}~　　
上記に加え、半角の空白
上記は`\\`でエスケープすることができます。

###Railsのソースコードの確認
Railsでは、上記のエスケープ処理のためにescape_javascriptメソッドが用意されています。
以下、escape_javascriptメソッドが定義されている箇所の抜粋です。

```.rb
 def escape_javascript(javascript)
        javascript = javascript.to_s
        if javascript.empty?
          result = ""
        else
          result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP)
        end
        javascript.html_safe? ? result.html_safe : result
      end

      alias_method :j, :escape_javascript
```


上記の通り、gsubメソッドを使って、HTMLを書き換えています。

また、`alias_method`として`j`と設定されておりますのでただ`j`と記述するだけでも呼び出すことができます。


## まとめ
最後にポイントをまとめます。

- escape_javascriptメソッドは、JavaScriptファイルの中にHTMLを記述するときに実行結果をエスケープするためのメソッド
- `j`と記述するだけでも呼び出すことができる。
Pythonを使ってTwitterに時間指定して投稿

# はじめに
指定した時間になったらTwitterで呟く方法です。
Twitter自体には予約投稿という機能がありますが、APIを叩いて予約投稿はできなさそう(多分)だったので、Schedulerを用いて強引ですが予約投稿を実装しました。
TwitterAPIの取得方法などは様々な方が解説してくださっているので割愛しています。

# 実行環境
- windows10
- Python 3.8.3

# コード

```python
import tweepy
import sched
import time
import datetime

# API Keys
CK = "Consumer Key"
CS = "Consumer Secret"
AT = "Access Token"
AS = "Access Secret"

def tweet(text):
    """ツイートする"""
    auth = tweepy.OAuthHandler(CK, CS)
    auth.set_access_token(AT, AS)
    api = tweepy.API(auth)
    api.update_status(text)

def tweet_sched(post_date, tweet_text):
    """時間を指定する"""
    scheduler = sched.scheduler(time.time, time.sleep)
    run_at = int(time.mktime(post_date.utctimetuple()))
    scheduler.enterabs(run_at, 1, tweet, (tweet_text,))
    scheduler.run()


#使用例
post_date = datetime.datetime(2021, 12, 9, 17, 0)
tweet_text = "testです"
tweet_sched(post_date, tweet_text)

```

時間になるまで待機させて、tweetを実行しています。
時間の精度については秒単位での誤差は出ないと思います。(多分)

post_dateで投稿する日時、tweet_textで投稿する文を指定すれば動きます。
ちなみに過去の日時を指定すると即ツイートされます。

# 終わりに
私がSchedulerの挙動をイマイチ理解していないので、もしかしたらバグるかもしれないです。
使用は自己責任でよろしくお願いします😉
もっといい方法があれば教えて頂けると助かります🙏
感情の昂りを表現したいのに冷静さが求められる矛盾を解決するためのWebアプリを作った

## はじめに
この記事は鈴鹿高専AdventCalendar2021の10日目の記事です。

https://qiita.com/advent-calendar/2021/snct

## 問題提起
皆さんTwitterは使っていますよね？
Twitterを使っていると感情が昂ることが多々あると思います。 
![アドカレ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371469/c810c30a-02f9-dc5e-5977-c3ca3c2946ae.png)
*図1：Twitterで感情が昂るシーンの例*

<br>

そんなとき、以下のようなツイートをすることはありませんか？
![スクリーンショット 2021-12-09 22.36.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371469/8f1c5ee3-f8e7-396a-c130-557aba4d694f.png)
*図2：オタクのツイート*

<br>

このように**文字の間にスペースを入れる**と、単純に「**最高すぎる！**」と呟くより感情の昂りを表現できますよね。
しかし、この文字の間にスペースを入れる表現に関して、自分は一つ納得いかないことがあります。

それは、、、

### 感情の昂りを表現したいのに「文字の間にスペースを入れる」冷静さが求められる 

これです。

例えば上記のツイートをする場面を考えてみてください。
一つ一つ整理すると、以下の手順を踏む必要があることがわかります。

１. 文字の間にスペースが入っていない文章を入力する。

```
最高すぎる！|
```
２. 最初の文字の後ろにカーソルを持っていく

```
最|高すぎる！ 
```

３. スペースを入力する

```
最　|高すぎる！
```

４. カーソルを1つ右にずらす

```
最　高|すぎる！
```

５. 手順3, 4を繰り返す

<br>

これを見て思いませんか？
**え！！感情が昂っているのに、こんな精密な作業を！？**と

感情が昂っているため、本来であればこのような精密な作業はできるはずがありません。
しかし、インターネット上で自分の感情の昂りを表現するには、このような精密な作業をするための冷静さが求められるのです。
BLEACHの5巻冒頭と全く同じですね。[^1]

[^1]: 「剣を握らなければ おまえを守れない　剣を握ったままでは おまえを抱き締められない」 - BLEACH第5巻冒頭詩より


<br>

この矛盾をなんとかするためには、**普段通り文字を入力しつつ**も、
**自動で文字の間にスペースを入力してくれる仕組み**が必要なわけです。

というわけで作りました。
その名も**「文字の間にスペースを入力してくれるジェネレーター」**です！！

## 文字の間にスペースを入力してくれるジェネレーターとは？

![スクリーンショット 2021-12-09 23.09.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371469/62c1cb0c-37cd-953e-dab0-0d737e40076c.png)

アプリを開くと入力欄が表示されます。
このままだったら単なるhtml/cssを学び始めた人が作った画面。しかし、皆さんここに文字を入力してください。
ここからがマグマなんです。[^2]

[^2]: お笑い芸人 なかやまきんに君さんの持ちネタより

文字を入力すると、、、

![ 2021-12-09 23.24.19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371469/c10e01d8-fe8c-2916-7860-dc177ec1468d.gif)


### 自動で文字の間にスペースを入力してくれる！！！
あ　と　は　こ　れ　を　コ　ピ　ー　す　る　だ　け　で　、　精　密　な　作　業　い　ら　ず　で　文　字　の　間　に　ス　ペ　ー　ス　が　入　っ　た　文　章　を　用　意　で　き　る　わ　け　で　す　！

これでいつでも、冷静さを求められない感情が昂ったままのツイートができますね。
（もちろんインターネット上での発言には細心の注意を払いましょう）

[こちら](https://nikasome.github.io/put-sapce-editor/index.html)で公開しているので、皆さんもぜひ利用してください！

## さいごに
> Q：
感情が昂っているときに別のアプリを使って文字を入力なんてできなくない？ 
  そっちの方が冷静さが求められそう....

そりゃそうだ

<br>

## 利用させていただいたもの
- [Vue3](https://v3.ja.vuejs.org)
- [Element Plus](https://element-plus.org/en-US/)
- [GitHubPages](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages)
- [かわいいフリー素材集 いらすとや](https://www.irasutoya.com/)

## 参考にさせていただいたもの
- [VueプロジェクトをGitHub Pagesに一瞬で公開](https://zenn.dev/sohhakasaka/articles/3e386fa9a650cd)
- [Vue Cli 4で GitHubPagesに公開する方法](https://qiita.com/kuimac/items/9cfd08b2c3df871a5f56)
- [Vue で作成した Web アプリを GitHub Pages で公開](https://www.shookuro.com/entry/2019/02/02/174655)

## 感想
Vueを使って何かを作るのは初めてでしたが、データプロパティ・算出プロパティを利用することで、
スペースを入れ込む処理や文字数をカウントする処理などを簡単に実装でき、触っていて楽しかったです。
また、GitHubPagesを使ったアプリの公開も、難しい設定なくできたのでオススメです。
今度はちゃんとしたものを作りたいと思います！
[並列処理] 大量なS3オブジェクトのダウンロード時間を短縮する

# はじめに
データレイクとしてS3を選択し、データサイズはそれほど大きくない(データウェアハウスを用意するほどではない)場合、
データの保存場所をS3内で完結させ、S3を直接見る形で分析できないかと考えると思います。

この時、

- S3上のオブジェクト数が多い

と、S3オブジェクトのダウンロードにかなりの時間がかかってしまいます。

[「LambdaがS3からGetObjectするのにかかる時間を計測してみた」](https://dev.classmethod.jp/articles/mesure-download-time-of-get-object-from-s3-on-lambda/#toc-6)の記事でまとめられている通り、
S3からデータを落としてくるのに、1kBのデータサイズであっても、0.0数秒は要してしまいます。

仮に、1kBのデータの取得に0.05秒かかったとして、データサイズが10万件あれば、それらを取得するのに、5000秒(≒83分)かかることになります。(待ってられません)

これは、通信がボトルネックになっているため、分析環境のメモリサイズをいくら上げても改善しきれません。
そんな時に、並列処理でダウンロード時間を短縮したというお話です。

# 具体的にどうしたか
Pythonのasyncioモジュールを利用し、並列処理を行いました。

以下、簡単な説明になります。

- asyncio.get_event_loop()でイベントループを取得
- 並列化したい関数をasyncをつけて定義
- awaitと宣言してから、取得したイベントループのrun_in_executorに、時間がかかる処理を手配する
- asyncio.gatherで手配した処理を並列実行します

なお、asyncio.gatherの返り値は、await loop.run_in_executorで渡した順に返ってきます。

少し雑ですが、以下該当部分のコードになります。


## 関数定義
```    
# マルチスレッドでboto3のリソースを共有してはいけないため、bucketを受け取らず、bucket_nameを受け取っている
# https://boto3.amazonaws.com/v1/documentation/api/latest/guide/resources.html#multithreading-and-multiprocessing
async def async_get_objects(bucket_name, object_keys):
    loop = asyncio.get_event_loop()
    return await loop.run_in_executor(None, get_objects, bucket_name, object_keys)

def get_objects(bucket_name, object_keys):
    bucket = boto3.resource('s3').Bucket(bucket_name)
    response_bodies = [] 
    for key in object_keys:
        response = bucket.Object(key).get()
        response_bodies.append(response['Body'].read())
        # ファイルディスクリプタの制限を受けないため
        response['Body'].close()        
    return response_bodies
```

## 呼び出し
```
read_objects = []
# bucket : Boto3のBucketオブジェクト
# objects_divided : 並列数分に分割したS3 object keyのリストのリスト
# 例 [[obj_key1, obj_key2, ...,obj_key100], [obj_key101, ...,obj_key200],...] 
for objects_divided_part in objects_divided:
    read_objects.append(async_get_objects(bucket.name, objects_divided_part))
        
response_bodies_list = await asyncio.gather(*read_objects)
```

# おわりに
上記の並列化を行うと、確保されているプロセス数分はS3オブジェクト取得に要する時間を削減できます。
以下、asyncioモジュールを理解する上で参考になった記事です。

https://docs.python.org/ja/3/library/asyncio-task.html#asyncio.gather
[asyncioでPythonの非同期処理を書いてみる](https://dev.classmethod.jp/articles/python-asyncio/)
[Pythonの非同期通信（asyncioモジュール）入門を書きました](https://iuk.hateblo.jp/entry/2017/01/27/173449)
[Pythonにおける非同期処理: asyncio逆引きリファレンス](https://qiita.com/icoxfog417/items/07cbf5110ca82629aca0)
スッキリできるJava入門　実践編第3版　Mavenの利用について（P387）

「スッキリ分かるJava入門　実践編第3版」　P387にて、Mavenの利用方法ついて記載があったが、解説通りに利用しても実行できずかなり苦戦したので、忘れない内に学んだ事を記載しておこうと思いました。

■参考書記載の利用方法
https://sukkiri.jp/technologies/devtools/maven/apache-maven-installmacos.html

解説通り、Apache：Apache Maven　https://maven.apache.org
にアクセス、ZIPファイルをインストール。この時、解説は
>「ZIPファイルを適当な場所に展開。（本サイトでは、/Users/ユーザ名に展開。）」

と記載があり、自分はデスクトップにインストール。
その後、下記コマンドをターミナルにて実行。

```
$ cat << EOF >> ~/.zshrc

export PATH=$PATH:~/apache-maven-3.8.4/bin 

EOF

$ . ~/.zshrc
```
その後、下記コマンドで確認。

```
$ mvn -version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
:
```
その通りにやったところ、

```
zsh: command not found
```
とエラーが発生し、全然実行できずに躓きました。
そこで、解説で行っていた最初のコマンドの意味をそれぞれ検索。
調べたところ、

```
//zsh(zシェル)のRun Commandファイル？の末尾に追加して書き込む
$ cat << EOF >> ~/.zshrc

//クラスパスを通す
export PATH=$PATH:~/apache-maven-3.8.4/bin 

//終了(End of File)
EOF

//不明。ホームディレクトリ直下にあるzsh設定ファイルにアクセスしている？
　　　　一番最初に記入するピリオドの意味が不明。カレントディレクトリを意味しているのか。
　　　　ピリオドの記載がないと、zsh: permission deniedという権限がないというエラーが起きる。
$ . ~/.zshrc
```
という風に解釈しました（100%当たっているかは不明）。

恐らくですが、Mavenをインストールした後、シェル設定ファイルにMavenのパスを通して利用ができる状態にするという作業なのかと思いました。
「mvn（Maven）のコマンドを認識していない」という事は「Mavenを認識していない」。
なぜ認識していないのか考えた時、Mavenがどこにあるか分からないから　＝　恐らくパスの指定が悪いのかと解釈。
自分はApache Mavenをデスクトップ上に保存していたので、

```
/Users/username（それぞれのユーザーネーム）/desktop/apache-maven-3.8.4/bin
```
でパスを直したところ、無事解決しました。
適当な場所という言葉を鵜呑みにしすぎた結果です。

初学者で現場も出ていないため恐らく間違いだらけだと思うので、
分かり次第随時内容も訂正していこうと思います。


【参考サイト】
・エラーの原因
https://itips.krsw.biz/mac-zsh-command-not-found-error-reason-and-solution/

・各コマンドの意味
https://hacknote.jp/archives/13756/

・zsh・zshrcについて
https://suwaru.tokyo/zshenv/
http://webcache.googleusercontent.com/search?q=cache:RYdotdNX1RUJ:www-kn.sp.u-tokai.ac.jp/com/computer/shell/shell.html+&cd=7&hl=ja&ct=clnk&gl=jp
https://mykii.blog/what-is-shell-bash-and-zsh/
https://note.com/standenglish/n/ne9825624fe93
【無料で使える】Workatoのレシピ開発に便利なSaaS フリープラン、開発プラン、評価プランのリンク（2021年12月版）

Workatoの開発・検証に便利なSaaS フリープラン、開発プラン、評価プランのリンクを並べました。

WorkatoはiPaaSであるため、Workatoを試すにはWorkatoで連携するためのシステムを用意する必要がありますが、とりあえず何か繋いで試したいというときにこれらのフリープランや開発プラン、評価プランが役立ちます。また、既に本番利用しているシステムがあり、本番で利用する前に本番以外の環境で試しておきたいという場合にも役立ちます。

自分用のメモとして作ったもので雑に並んでいますが、もしよろしければご参考ください。（カテゴリ分けはそのうち）

なお、クレジットカード等の登録が不要なサービスを並べているつもりですが、記載ミスやサービス提供者の方針変更などにより、クレジットカードの登録が必要となる場合もあるかもしれません。各サービスを利用する際に、必ずご確認ください。（記載内容の正確性について、保証はいたしません）

また、有償プランとは提供されるサービス内容が大きく異なる場合や、ライセンス形態により利用用途が制限されている場合があります。各サービスを利用の際は、それらの点について予め確認のうえ、ご自身の責任のもとで（利用規約に定められた範囲内で、ライセンス違反にならないように）ご利用ください。



# Microsoft 365

以下より無料の Microsoft 365 E5 インスタント サンドボックスを申し込むことが可能です。

https://developer.microsoft.com/ja-jp/microsoft-365/dev-program

# Google Workspace

以下よりトライアルを申し込むことができます。別途ドメインを用意しておく必要があります（サブドメイン可）。

https://support.google.com/a/answer/53926?hl=ja

# Slack

以下よりフリープランのワークスペースを作成可能です。

https://slack.com/intl/ja-jp/

# Atlassian Cloud(Jira, Confluence)

以下よりフリープランの申し込みが可能です。

https://www.atlassian.com/ja/try

# Trello

以下よりフリープランの申し込みが可能です。

https://trello.com/ja

# Salesforce

以下よりDeveloper Editionの申し込みが可能です。

https://developer.salesforce.com/

# HubSpot

以下より無料版の申し込みが可能です。

https://www.hubspot.jp/

# ServiceNow

以下よりPersonal Developer Instanceの申し込みが可能です。

https://developer.servicenow.com/dev.do

# Kintone

以下より開発者ライセンスの申し込みが可能です。

https://developer.cybozu.io/hc/ja/articles/200720464-kintone-%E9%96%8B%E7%99%BA%E8%80%85%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9-%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83-

# SmartHR

サンドボックスの申し込みが可能です。以下を参照ください。

https://zenn.dev/shikumiya_hata/books/33f44d4f561ec4/viewer/a784d3

# Airtable

以下よりフリープランの申し込みが可能です。

https://www.airtable.com/

# Monday

以下よりフリープランの申し込みが可能です。

https://monday.com/lang/ja/

# Asana

以下よりBasicプラン（フリープラン）の申し込みが可能です。

https://asana.com/ja

# Wrike

以下よりフリープランの申し込みが可能です。

https://www.wrike.com/ja/

# DocuSign

以下のページを表示後、「開発者」ー「開発者向け無料アカウント」より開発者アカウントの申し込みが可能です。

https://www.docusign.jp/blog/developers

# Okta

以下よりデベロッパーアカウントの申し込みが可能です。

https://www.okta.com/developers

# Auth0

以下よりフリートライアルの申し込みが可能です。トライアル期間終了後、フリープランにダウングレードされます。

https://auth0.com/jp

# Sendgrid

以下よりフリープランの申し込みが可能です。なお、申し込み時に審査があります。

https://sendgrid.kke.co.jp/

# Miro

以下よりフリープランの申し込みが可能です。

https://miro.com/ja/

# Site24x7

以下よりフリープランの申し込みが可能です。

https://www.site24x7.jp/

# Mackerel 

以下よりフリープランの申し込みが可能です。

https://ja.mackerel.io/

# Pipefy

Pipefyは日本では馴染みのないサービスですが、SaaS型のビジネスプロセス管理・ワークフローシステムです。
以下よりフリープランの申し込みが可能です。

https://www.pipefy.com/

# GitHub

以下よりフリープランの申し込みが可能です。GitHub Actionsの利用も可能です。

https://github.co.jp/pricing

# Bitbucket

以下よりフリープランの申し込みが可能です。

https://bitbucket.org/
「驚異のFANZA女優検索」という名前について

この記事は [驚異のFANZA女優検索](https://fanza-actress-bust-search.azurewebsites.net/) Advent Calendar 2021 の 10 日目の記事です。

# タイトル
驚異のFANZA女優検索は単純な名前だけど、この名前に至るまでに結構悩んだ。URLを含め何度か変えている。[Google 日本語入力](https://www.google.co.jp/ime/)も結構色々悩んだ末にGoogle 日本語入力にしたという話を[Rebuild](https://rebuild.fm/136a/)だかで聞いたけれど（同じにしたら失礼かもだけど…）まあ、同じ。

# 名前の付け方の方針
このサービスを作って、最初に名前をつけよう思った時から、直接的な名前を付けるべきだと思っていた。noteやLINEのような本来の意味を持っている単語は絶対ない思っていたし、QiitaやTikTokなどのオリジナルな名前もまたこのサービスとは合ってないと思っていた。またメタファーとして抽象化した名前、このサービスで言うとプリン、スイカ、風船のような名前を付けるのも何となく止めた。ウォーターメロンドットコムとか悪くないなーと思いつつ。。

#FANZA女優
直接的な名前となると、キーワードとして入れたいのはDMM.comの**女優**APIを使ったサービスなので、やはり女優という単語を入れたい。ただ女優だと意味が広すぎる。昔ならAV女優、今だとセクシー女優？という単語の方が適切かもしれないが、古今東西全てのセクシー女優がヒットするわけではない。つまりスコープが広すぎる。スコープとして最も適切なのはFANZAで、FANZAが女優と定義している女優は全てヒットする。そうなると**FANZA女優**がこのサービスを表す最も適切な名前と思った。FANZA女優という単語は辞書にもない単語だと思うので造語に近いが、日本人男子なら聞いただけで意味が通じる点でも完璧な名前だと思う。
、
#検索キーワード
もう一つキーワードとして付けたいのがやはりバストだ。「FANZA女優バスト検索」でも良いが、もう少し検索に使うキーワードにしたい。ではバストを見たい時にどんな単語で検索するか？これは人によって結構違うと思った。もっともポピュラーなのはやっぱりおっぱいだろう。でもおっぱいと検索するか？と言うと少なくとも自分はしない。もう絶対これ[一択](https://ja.wikipedia.org/wiki/%E5%B7%A8%E4%B9%B3)で、むしろこれ以外の単語でググったことなどない！。つまり「FANZA女優〇〇検索」の〇〇の部分に入る適切な単語は人によって違う可能性がある。ていうかおっぱいを探したい意図で検索する場合、FANZA女優というキーワードだけで既に足りている気がする。そう考えるとヘタなキーワードは足さず、「FANZA女優検索」で十分かもしれないと思った。

#メタファーとしての♡
ただ、自分的にはやっぱりバストを表す何かメタファーを付けたいと思っていた。形的にも意味的にもハートが一番良いと思った。Unicodeなら♡はフォントとして存在している。メタファーはURLには入れる必要もないと思った。と言うわけで、ページタイトルを「FANZA♡女優検索」、URLを「fanza-actress-search」にした。実際最初はこれで公開した。ただ、♡をタイトルの中に入れてしまうと、GoogleにもFANZA♡女優検索で登録されてしまったので、キーワードとしてFANZA女優ではヒットせず、FANZA♡女優と検索しなければならなかった。普通文字で♡はすぐには出ないと思うので、♡付きの名前は検索性が低いと思って別の名前を検討しだした。

#ググラビリティ
そこで再度名前を考え直すことにした。一度はいらないと思ったが、やはりバストを付けて「FANZA女優バスト検索」にするのも再考した。ただ実際にgoogleで検索する場合を考えると「FANZA 女優」で検索すると、当たり前だがFANZA本家がヒットする。ここに「FANZA 女優 バスト」と追加しても結果は殆ど変わらない。それよりは「FANZA 女優」の次に被らないキーワードを付けて、そのキーワードを付けた場合は自分のサイトが1番にヒットする方が有利かと思った。そうなると第3キーワードとして、他と被らないユニークな名前が良いと思って、「FANZA女優胸囲検索」にしようと思った。「FANZA 女優 胸囲」で検索する人はいないとは限らないが、まあ結構少ないと思う。

#驚異の一声
ここで唯一レビューしてもらっていた友人に、「FANZA女優胸囲検索」にしようかと思っていると話してみたら、だったら「驚異のFANZA女優検索」はどうですか？と言われた。これはビビビときた。驚異のFANZA女優検索。一見すると馬鹿っぽい。でもこの馬鹿っぽさはむしろ作っているサービスとマッチしている。個人的にエロとバカは相性が良いと思っていた。その上でダブルミーニングになっているのが個人的にクリティカルだった。と言うわけで、ダブルミーニングを強める為にもURLは敢えて「fanza-actress-bust-search」というストレートな名前にした。最高の名前だと思う。
Azure で ML Ops をやってみる ～概要編～

#目次
1. はじめに
1. 機械学習運用の上での課題点
1. ML Ops とは？
1. 最後に

#はじめに
この記事は株式会社ナレッジコミュニケーションが運営する 
[クラウドAI by ナレコム Advent Calendar 2021](https://qiita.com/advent-calendar/2021/knowcom-cloudai) の5日目にあたる記事になります。

こんにちは！

今回は ML Ops について、機械学習モデルを運用する上での課題と、概要をまとめてみました。
機械学習モデルを作り、実際に機械学習モデルの運用を始めるうえで、様々な課題があります。
どうすれば機械学習モデルの運用が進むのか、考えていこうと思います。

次のパートで、実際に Azure の各種サービスを用いて、MLOps をやってみようと思いますので、次のパートもぜひご覧ください。

https://qiita.com/banana-877/items/170123087a9ec4621d69

#機械学習運用の上での課題点
###想定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1091796/a285ad43-f2c1-1ae3-f95c-f6920ae3f4e9.png)
まずはじめに、機械学習モデルを運用していく上での課題点を一緒に考えてみます。
今回は、下記の図の役割とフローで機械学習モデルを開発するということにします。

###モデル開発のフロー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1091796/c1f31c1b-69e8-c2df-bd88-0f366cbec2b0.png)

①. 最初にデータアナリストが機械学習モデルの開発のための準備段階として、機械学習で解決する課題定義と仮説検証を進めます。どんな機械学習モデルを用いれば、ビジネス上での価値があるのか、といったことを考察する段階です。

②. 次に、データサイエンティストが、データアナリストが策定した要件に合わせてモデル開発を進めていきます。

③. 次に、データエンジニアは機械学習モデルにかけるデータを集めるためのデータ収集基盤など、モデルの運用をする上での環境開発や継続的な分析を行うための分析環境を構築します。

④. 最後に、MLエンジニアはデータサイエンティストが作った機械学習モデルをdockerコンテナでデプロイし、継続的な学習ができるスキームをデータエンジニアと連携して組んでいく​役割が多いかと考えられます。

###機械学習モデルの運用と課題 ~モデルの精度が落ちてきた場合~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1091796/7e0a54b7-cd35-574b-94ca-671d5591c02c.png)

モデルの開発が完了し、実際にモデルをアプリケーションなどに組み込み、運用していく段階です。
モデルを運用する上で、初期はデータサイエンティストが想定する精度が出せるのですが…
運用を進める上で、精度が下がってしまい、（これを**ドリフト**といいます）機械学習モデルの価値が下がっていってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1091796/2e089598-f6b8-3768-acf5-d80e02b9dffa.png)
下がったモデルの精度を上げるため、データサイエンティストがまた別のアルゴリズムや手法、データセットでモデルのトレーニングをしていきますが、

* モデルの再トレーニングをしたため、学習コストなどがかかってしまった
* モデルパイプラインの共通化、モデルの評価指標のモニタリング
* データエンジニアは学習データの取得方法の変更対応が必要
* MLエンジニアはカナリアデプロイ、A/Bテストができる環境構築、バージョン管理 

などなどの問題が発生し、機械学習モデルの運用が大変になります。
上記の問題を解決するのが、ML Ops の概念です。

#ML Ops とは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1091796/bd90c2d9-ced4-5fa2-ae23-f5829e37f5a0.png)

Hidden Technical Debt in Machine Learning Systems
[Part of Advances in Neural Information Processing Systems 28 (NIPS 2015)](https://proceedings.neurips.cc/paper/2015)

上記は、2015年に発表された”機械学習システムの隠れた技術負債”という論文にある図です。
本質的に機械学習システムやそれを含むアプリケーションでは様々な課題が発生することが知られています。
赤枠で囲った、中央の小さな黒い四角が機械学習モデルになります。
機械学習モデルの周囲には…

* 設定
* データ収集
* 特徴量の計算
* データの検証
* 計算資源の管理
* 分析ツール
* プロセス管理ツール
* 上記を乗せるインフラ
* 監視

といった様々な要素があり、予想以上に複雑性が増すことを示しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1091796/5859b3ac-83a2-4cc3-df3f-a14c6a090239.png)

これらの複雑性をできる限り排除した上で、データ分析チームや運用チームが、モデリングに使うデータ、モデルそのもの、諸々のリソースを設定するためのコード、これらをできるだけ管理しやすい状態に維持し、機械学習モデルの生成と運用を通じて効率的かつ継続的に価値を届け続けること、という点を軸にした考え方や方法論が **MLOps** となります。

##最後に
MLOps の概念について、いかがでしたでしょうか。
機械学習モデルを運用していく上で様々な問題がありますが、次のパートでAzure サービスを利用して MLOps を実践したいと思いますので、ぜひ次のパートも見ていただければ嬉しいです。
ご覧いただきありがとうございました！
micro:bit v2 の MicroPython で OLED を使う(framebuf追加編)

[micro:bit Advent Calendar 2021](https://qiita.com/advent-calendar/2021/microbit)の7、8日目が空いてしまっていたので、小ネタとして micro:bit V2 で OLED (SSD1306)を使えるようにしてみました。

世の中には既に [microbit_ssd1306](https://github.com/fizban99/microbit_ssd1306)というライブラリがあるのですが、framebuf を使ったものにしたかったので MicroPython の拡張に挑戦してみました。

# 改造とビルド

MicroPython ビルド方法は[ここ](https://microbit-micropython.readthedocs.io/ja/v2-docs/devguide/flashfirmware.html#micro-bit-v2)を参照してください。

micro:bit V2 用の MicroPython 実装は、本家 MicroPython のソースをサブモジュールとして使っていますし、framebuf は所詮メモリ上でコニョゴニョするだけなのでデバイス依存性は少ないだろうと調べたのですが、なんと改造箇所は [src/codal_port/mpconfigport.h](https://github.com/microbit-foundation/micropython-microbit-v2/blob/master/src/codal_port/mpconfigport.h)に１行追加するだけでした。

```diff
--- mpconfigport.h.org	2021-12-09 21:57:53.000000000 +0900
+++ mpconfigport.h	2021-12-09 22:08:48.000000000 +0900
@@ -86,6 +86,7 @@
 #define MICROPY_PY_URANDOM_EXTRA_FUNCS          (1)
 #define MICROPY_PY_MACHINE                      (1)
 #define MICROPY_PY_MACHINE_PULSE                (1)
+#define MICROPY_PY_FRAMEBUF                     (1)
 
 #define MICROPY_HW_ENABLE_RNG                   (1)
 #define MICROPY_MBFS                            (1)
```

この１行を追加して、手順どおりにビルドするだけです。できあがったファームウェア `MICROBIT.hex` を MICROBIT フォルダにコピーすればインストール完了です。

# 動かしてみる

REPL の利用には [mpremote](https://micropython-docs-ja.readthedocs.io/ja/latest/reference/mpremote.html)を使ってみました。 

```
$ mpremote 
Connected to MicroPython at /dev/cu.usbmodem14202
Use Ctrl-] to exit this shell

>>> 
MPY: soft reboot
MicroPython v1.15-64-g1e2f0d280 on 2021-12-09; micro:bit v2.0.0 with nRF52833
Type "help()" for more information.
>>> help('modules')
__main__          love              os                urandom
antigravity       machine           radio             ustruct
audio             math              speech            usys
builtins          microbit          this              utime
framebuf          micropython       uarray
gc                music             ucollections
log               neopixel          uerrno
Plus any modules on the filesystem
>>>
```

ちゃんと framebuf モジュールがあります。

```python
>>> 
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== import framebuf
=== 
=== fbuf = framebuf.FrameBuffer(bytearray(64 // 8 * 128), 128, 64, framebuf.MONO_VLSB)
=== 
=== fbuf.fill(0)
=== fbuf.text('MicroPython!', 0, 0, 0xffff)
=== fbuf.hline(0, 9, 96, 0xffff)
>>> 
```

使えているようです。

では、この `framebuf` モジュールを使った [ssd1306](https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py)モジュールを使ってみますが、[8日目](https://qiita.com/inachi/items/8335d762e5cb4a90c075)のネタとします。
一日の空き時間を増やしてくれる最適化サービス

一日というのは短いです。誰もがなんとか時間を最適化して余暇を増やしたいと願っているものです。そんな要望にお答えして一日の空き時間を増やしてくれるサービスを開発しました。その名も「空き時間フエール」です。

https://time-optimizer.alphabrend.com/


## どの様にして時間を増やすのかの画期的なアルゴリズム

ではどの様にして時間を増やすのかというと、実際に24時間がそれ以上に増えるわけではありません。みなさん結構細切れの自由時間があったりしませんか？　例えば何かしなければならないことと、他のしなければならないことの間にちょっとした30分ほどのスキマ時間があったりなど。

しかしなかなかそれを有効活用するのは難しいです。どうせそんな時間無いし、と思ってTwitterをしてしまう人がほとんどだと思います。だったら細切れの時間をなくせばいい、全てまとめて長い空き時間にすればいい、そうすればそうやって潰してしまうこともなくなる、そう思いました。それを実現したサービスというわけです。

### 実例

まず空き時間フエールに普段のスケジュールを入れていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/c579d776-2f92-cada-3751-680b7a7a3e64.png)

空いている時間はそのままにしておきましょう。ここで食事が２回あることにお気づきでしょうか？　空き時間フエールでは同じ名前のスケジュールを結合してくれます。朝食、昼食、とせず、食事、という名前で設定しましょう。

そして最適化ボタンをおすと……

なんとこのように一つにまとめてくれます！　睡眠も朝と夜でバラけていると思いますが朝にまとめてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/0ce7d8fd-f918-ed7c-ae63-df08c242be7c.png)

最終的にこのように１日の中でバラけていた時間を結合し、長い空き時間にすることができました！　３時間もあれば映画もみれちゃいますね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136506/ebf91b2f-2f49-d1b8-1471-477f759ed10d.png)

## 技術的なこと

Next.js, Recoil, Chakra UI, Vercel

## まとめ

このようにして時間のない現代人の問題解決となるサービスを開発しました。

良いと思ったらぜひLGTMボタンをお願いします！

---

ちなみに下記は元々今回のクソアプリとして作って記事まで書いたけどボツにしたやつです

https://qiita.com/dala00/items/afbd0a93ff15d8863a95

最後に今までのクソアプリも貼っておきます。

https://qiita.com/dala00/items/68e4c0c30f67813b58dc

https://qiita.com/dala00/items/f26129e42fb8253aa54f

https://qiita.com/dala00/items/1f15c68cd771ea9c401a
Flutter ExpansionTileのBorder lineを消す方法

FLutterのメモ用に書いております上、読みにくいなどがあると思いますがご了承ください。

<h3>参考記事</h3>
以下のリンクを参考にしました。
英語を読むのに抵抗がある人には、読まなくて大丈夫です。

https://stackoverflow.com/questions/64123839/flutter-remove-border-expansion-tile

<h3>Border lineとは</h3>
ExpansionTileのBorder lineは写真のようにExpansionをした際にできる外枠のことです。

<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878133/77edece3-d072-4446-977d-060444fa908f.png" width="200">
</div>

<b>Code</b>

```
child: ExpansionTile(
          title: Text(
            "上に黒い線があるよ",
            style: Theme.of(context).textTheme.headline4?.copyWith(color: Colors.blue)
          ),
          children: <Widget>[
            Text(
              'Test ExpansionTile',
              style: Theme.of(context).textTheme.headline5?.copyWith(),
            ),
            Text(
              'Test ExpansionTile',
              style: Theme.of(context).textTheme.headline5?.copyWith(),
            ),
            SizedBox(height:10),
            Text(
              '下に黒い線があるよ',
              style: Theme.of(context).textTheme.headline4?.copyWith(color: Colors.blue),
            ),
          ],
        )
```

<h3>実装方法</h3>
ExpansionTIle widgetをTheme widgetでwrapして、dataに以下のコードを指定してください。

```
Theme.of(context).copyWith(dividerColor: Colors.transparent),
```

<b>コード全体</b>

```
child: Theme(
          data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
          child: ExpansionTile(
            title: Text(
              "線がないよ！",
              style: Theme.of(context).textTheme.headline4?.copyWith(color: Colors.blue)
            ),
            children: <Widget>[
              Text(
                'Test ExpansionTile',
                style: Theme.of(context).textTheme.headline5?.copyWith(),
              ),
              Text(
                'Test ExpansionTile',
                style: Theme.of(context).textTheme.headline5?.copyWith(),
              ),
              SizedBox(height:10),
              Text(
                '線がないよ！',
                style: Theme.of(context).textTheme.headline4?.copyWith(color: Colors.blue),
              ),
            ],
          ),
        )
```

<b>表示画面</b>
<div align="center">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878133/e73fb211-3209-4a2b-1bbd-0ebb13ca1d89.png" width="200">
</div>
Git for Windows の落とし穴（Turai）

# はじめに
この記事は[LIGHTz アドベントカレンダー 2021](https://qiita.com/advent-calendar/2021/lightz)の9日目の記事です。

LIGHTz のITエンジニアは、開発環境を好みで選べまして、　Windows 6割、mac 4割というのが現状です。
ただ、各々が違う開発環境を使っているとトラブルことも多々あり、日々トラブル解消に努めていますが、避けられないわけです。今日見事にハマったGit for Windowsについてメモっておきます。

# Git for Windowsの落とし穴
私があらためて書くまでもなく、[Git Windows 改行コード][検索] なんてぐぐると、ごまんとでてくる落とし穴なのですが、


## [Git for Windows](https://gitforwindows.org/)にはLFをCRLFにコミット不要で書き換えてくれる素敵な機能がある

基本的に、
* Gitから落とした直後のコード
* 動作環境はDockerコンテナ

なら、macだろうが、Windowsだろうが動くと思ってたのですが、新しくメンバーになった方の開発環境構築で見事にこの落とし穴にハマりました。

時間が溶けた溶けた。誰がこんな仕様考えたし。