OmniAICreator/Qiita-1.07M huggingface dataset:
NuxtでESLintのルールを無効にする

Nuxt.jsではpropsでオブジェクトなどを受け取る際、空のオブジェクトを子コンポーネントで定義しておきます。その際、空のオブジェクトがあるとESLintに怒られるため、グローバルで無効にしておくことにしました。

例　子コンポーネント（propsに空のオブジェクト）

```vuejs:components/atoms/Child.vue
<script>
export default {
  props: {
    receivedObject: {
      type: Object,
      default: () => {},
    },
  },
}
</script>

```

プロジェクトディレクトリ直下の.eslintrc.jsファイル内

```javascript:.eslintrc
module.exports = {
  // add your custom rules here
  rules: {
    'no-empty-function': 'off',
    // 空のfunctioｎあっても大丈夫
  },
}

```

プロジェクトではこの辺も追加しました。

```javascript:.eslintrc
module.exports = {
  // add your custom rules here
  rules: {
    'no-console': 'off', // console.log();OK
    'no-unused-vars': 'off', // 使っていない変数あってもOK
    // ↓空白行に対してwarnのみ出るようにする。
    'no-multiple-empty-lines': ['warn', { max: 1 }],
    // 'lodash/prefer-lodash-method': [2, { ignoreObjects: ['_'] }],
    'no-empty-function': 'off',
    // 空のfunctioｎあっても大丈夫
  },
}

```

グローバルに適用する必要がない場合は、該当のエラー箇所の直上にコメントをつければOK

```
alert('foo'); // eslint-disable-line

// eslint-disable-next-line
alert('foo');

/* eslint-disable-next-line */
alert('foo');

alert('foo'); /* eslint-disable-line */

```

参考
- [Disallow empty functions (no-empty-function)](https://eslint.org/docs/rules/no-empty-function)
- [ESLintについてのメモ](https://qiita.com/makotot/items/822f592ff8470408be18#rules)
- [Rules - Disabling Rules](https://eslint.org/docs/user-guide/configuring/rules#disabling-rules)
【ジョブカン】残業したくないから、後何時間働けばいいか計算するブックマークレット作った

# フレックスであと何時間働けばいいのか計算したい！
フレックス制度を導入している企業増えましたね
そして、ジョブカンを使っている企業も多い事でしょう

1分、1秒でも残業したくない！
そこのあなたに朗報です！

## 【今月の勤務時間チェッカー】
今、勤務時間が何時間足りて居るのか、何時間不足して居るのか
平均何時間働けば、月の目標時間を達成できるのか
これらを計算することが出来ます

出勤簿ページにて利用してみてください
https://ssl.jobcan.jp/employee/attendance

```javascript:bookmarklet.js
javascript:!function(){function gt(text){return $("th:contains('" + text + "')").next()[0].innerText.split(':')[0]};sabun = gt('実労働時間') - gt('実働日数') * 8;if(sabun > 0){text1 = '現在目標より'+sabun+"時間多く働けてます"}else { text1='目標に'+sabun*-1+"時間足りていません" };n_day = parseInt(gt('所定労働日数').slice(0,2)) - gt('実働日数');ave = (gt('月規定労働時間') - gt('実労働時間')) / n_day;message = "【フレックスタイム計算】\n" +"今月働かないといけないのは" + gt('月規定労働時間') + "時間です\n" +"1日8時間勤務の場合" + text1 + "\n" +'残り' + n_day + '日で1日平均' + ave + "時間働きましょう \n";console.log(message);$("h2:contains('出勤簿')")[0].innerText = message; }();
```

## 出勤簿という文字が置き換わり、計算結果が表示されます
勤務時間が8時間ではない人は以下のソースコード公開しているので
少し読んで、数字変更してあげてみてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69647/fdab0243-165b-bf15-1fb2-c5404f5b8c47.png)


## 【ブックマークレットの使い方】
超簡単で超便利なので、一般的な知識として知っておくと便利です
ブックマークしてるリンクを右クリックで編集をクリック
移動先のURLの欄に上のプログラムを貼り付けて終わりです！


## クソアプリな理由
便利じゃん！と思う方も多いと思いますが
ジョブカンがUIを変更すると使えなくなります。

さらに会社によって表示している項目が違った場合動かない可能性があるなと感じております。

設計がクソです、ありがとうございました。

## ソースコード公開してます。
是非他の機能もつけてくれると嬉しいです
PRお待ちしてます

`function gt(text)` の　text にジョブカンの取得したい項目を入れると
その単語が含まれるテーブルセルの横の値を取得します。

独自のIDやClassがテーブルについていなかったのでこんな苦し紛れの実装になってます
クソです。

ここに関してもアドバイスがあれば是非いただけると嬉しいです:bow:




https://github.com/keisuke2236/jobcan-flex-calc
踏み台無しで SSH over Session Manager してみたかったので試した

# やりたかった事
* VPC private subnetで起動しているセキュアなEC2インスタンスにVPC外からSSHで接続したい
* インターネットに面する踏み台サーバーを用意したり、ポート解放はしたくない

# 前提

## ec2側
* ec2 はAmazonlinux2で作成
* ec2 にssm-agent 最新版を導入済み
* ec2 インスタンス自体はPrivat subnetにあってインターネットからアクセス不可能であっても、natgatewayやvpcエンドポイント経由でSSMエンドポイントにアクセス可能である
* ec2 作成時に指定した ec2-user のキーペア秘密鍵などssh接続に必要な情報は手元にある。
* ec2 のsshdでは鍵認証での接続が可能な状態にある

## 作業者端末側
* 接続元の端末は今回は macを使用して検証した
* 接続したいec2のインスタンスID、ユーザー名、接続用の鍵の情報は確保済み。
* aws cli環境は整備済みで使える状態にある。

という状態からレッツトライ

# まずは公式の情報源
* 公式doc: https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html

# やった事

## 1. EC2 に付与している インスタンスプロファイルの設定確認
* インスタンスプロファイル内に `AmazonSSMManagedInstanceCore` ポリシーがあるか。
* なければ追加する。

## 2. 手元の端末で .ssh/config に公式のDocから設定をコピペして追加
* ~/.ssh/config を編集。内容は最新のドキュメントを確認。

```
# SSH over Session Manager
host i-* mi-*
  ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
```

## 3. 手元の端末から sshで接続
* 接続したいEC2インスタンスのインスタンスIDを確認する。マネジメントコンソールでもcliでも好きな方法で。
* sshコマンドで osのユーザー名、インスタンスID、ユーザーの秘密鍵を使って接続。やったね。

```
$ ssh ec2-user@<i-から始まるインスタンスID> -i <秘密鍵>
```

# おま環で少しハマったところ
* aws cli 利用時に profileを指定する必要があったので ~/.ssh/config の設定を少し調整

```
# SSH over Session Manager
host i-* mi-*
  ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p' --profile <profile名>"
```

## 参考にした記事
* https://dev.classmethod.jp/articles/ssm-session-manager-support-for-tunneling-ssh-scp-on-windows10/

# その他
* IAMの設定でポリシーでアクセスを許可するインスタンス制御もできるっぽい。

# 感想
* 思ったより簡単に実現できてとてもよかった。満足
Pythonでのデータ埋める方法



#実装
```padding_formatter.py
def padding_formatter(item, padding, data_type):
    """ 引数で指定された桁数までデータを埋める
        埋める内容は以下の通り
        ・データ型[numeric: 数字]   先頭0埋め
        ・データ型[half: 半角]      後ろ半角スペース埋め
        ・データ型[full: 全角]      後ろ全角スペース埋め

    Args:
        item: 項目
        padding: 桁数(byte数ではない)
                例  全角で64byte項目の場合は「32」桁を指定
        data_type: データ型[numeric: 数字, half: 半角, full: 全角]
    Returns:
        固定長分埋めた項目
    """
    out_item = str(item)
    if data_type == 'numeric':
        out_item = str(item).zfill(padding)
    elif data_type == 'half':
        out_item = str(item).ljust(padding, ' ')
    elif data_type == 'full':
        out_item = str(item).ljust(padding, '　')
    return out_item
```

#参考文献
https://note.nkmk.me/python-zero-padding/

https://note.nkmk.me/python-rjust-center-ljust/
[JavaScript] 画面の再描画を待つ・画面を強制的に再描画する

WEB ブラウザ上での JavaScript で時間のかかる計算処理をするとき、直前で DOM の内容を変更してもすぐに画面に反映されないことがあります。

(理由に関しては少しややこしいため、本記事では不説明。)

従来の対処法として `setTimeout()` で `delay` を `0` にするというものがありますが、ブラウザや状況によって思い通りに動作しないことがあります。

本記事では他の方法を書きます。

# 1. 結論: `requestAnimationFrame()` を 2 回呼ぶ

```js
const repaint = async () => {
	for (let i = 0; i < 2; i++) {
		await new Promise(resolve => requestAnimationFrame(resolve));
	}
};
```

```js
await repaint(); // 直前の DOM 変更を画面に反映
```

# 2. 例

## 2.1. 時間のかかる計算処理をすると、直前の DOM 更新がすぐに画面に反映されない

```js
(() => {

	const calculate = () => {
		for (let i = 0; i < 10000000; i++) {
			new Date();
		}
	};

	(() => {

		const body = document.body;

		body.insertAdjacentHTML('beforeend', '<p>calculating ...</p>'); // メモ: すぐに画面に反映されない

		calculate(); // 時間のかかる計算処理

		body.insertAdjacentHTML('beforeend', '<p>finished</p>');

	})();

})();
```

理想的には「calculating ...」が表示されてから `calculate()` の処理をして欲しいですが、実際には `calculate()` が終わってから「calculating ...」と「finished」が表示されます。

## 2.2. `setTimeout()` は動作しない可能性あり

```js
(() => {

	const wait = (delay = 0) => new Promise(resolve => setTimeout(resolve, delay));

	const calculate = () => {
		for (let i = 0; i < 10000000; i++) {
			new Date();
		}
	};

	(async () => {

		const body = document.body;

		body.insertAdjacentHTML('beforeend', '<p>calculating ...</p>');

		await wait(); // setTimeout() により画面の再描画を促す ※動作しない可能性あり

		calculate(); // 時間のかかる計算処理

		body.insertAdjacentHTML('beforeend', '<p>finished</p>');

	})();

})();
```

`delay: 0` の `setTimeout()` によって画面の再描画を促すことができますが、ブラウザや状況によっては動作しないことがあります。

`delay` を `500` 等に増やすことによって改善する場合がありますが、それでも確実ではないようです。

参考「[#4575011 - javascript - Why is setTimeout(fn, 0) sometimes useful? - Stack Overflow](https://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful/4575011#4575011)」

## 2.3. `requestAnimationFrame()` を 2 回呼ぶ

```js
(() => {

	const repaint = async () => {
		for (let i = 0; i < 2; i++) {
			await new Promise(resolve => requestAnimationFrame(resolve));
		}
	};

	const calculate = () => {
		for (let i = 0; i < 10000000; i++) {
			new Date();
		}
	};

	(async () => {

		const body = document.body;

		body.insertAdjacentHTML('beforeend', '<p>calculating ...</p>');

		await repaint(); // 画面を再描画して待つ

		calculate(); // 時間のかかる計算処理

		body.insertAdjacentHTML('beforeend', '<p>finished</p>');

	})();

})();
```

`requestAnimationFrame()` はもともとブラウザの画面の再描画直前に何か処理をする機能を持つため、(待機しながら) 2 つ連続呼ぶことで以下の順に処理されます:

1. 描画前に何らかの処理をする (ここでは `resolve()` のみ)
1. 画面を再描画する
1. 描画前に何らかの処理をする (ここでは `resolve()` のみ)
1. 画面を再描画しようとするが、「時間のかかる計算処理」が先に行われる

よって、確実に画面を再描画することができ、また、その再描画を待機することができます。

`requestAnimationFrame()` 1 つだけだと、何もしない場合と同様に (その直後で) 再描画されません。

参考「[Window.requestAnimationFrame() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/Window/requestAnimationFrame)」
実家のネットワーク管理でやらかした話

## はじめに

この記事は ハンズラボ [AdventCalendar2021](https://qiita.com/advent-calendar/2021/handslab) 23日目の記事です。

みなさんこんにちは！
今月で入社1年経った中川です！

今回は我が家のネットワーク事情の話になります。
いつも以上に個人的なお話になりますのでそれでもよければ見ていって下さい！

## 事の始まり

ある日突然それはやってくる・・・
そう！アラートです。実家の一部のネットワークからアラートが飛んできていて対応しようと思いTeamViewerにログインしようとしたら・・・

デデドン！！
![スクリーンショット 2021-12-23 12.08.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/ffb49a4f-7f23-fd6d-0fdb-ccab78068af8.png)

TeamViewerユーザなら割とおなじみのこちら。
間違っても商用利用はしてないのですが、利用頻度が多いと？商用判定されてしまうんですよね。
通常時なら放置でOKなのですが、実家のネットワークの一部に異常があったので、急いでログインする必要がありこの画面になりとても困りました・・・。
※結局現地まで行って修理しました

## TeamViewerからMSのRemoteDesktopへ

安心安全Windows標準のRemoteDesktop！
TeamViewerほどのお手軽さはないものの、安心安全のMS製で必要十分な機能がつかえるのでこちらに移行しますた。
Port開放等ルータの設定は必要になるのですが、それ以外は不便はなく安定もしております！
サーバ側がライセンス上Pro以上じゃないといけないという制約もあったはずなのでご注意を・・・
![スクリーンショット 2021-12-23 12.22.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181414/270b4398-9c71-6086-405d-87e8fc35cb15.png)

## まとめというか教訓

* 便利なソフトを安定的に使いたいならやっぱり課金すること
* ネットワーク系の操作は必ず冗長化しておくこと(TVやRDPが死んだときに備える ChromeDesktopなど)
* Wake On LANは可能なら設定すること
* 障害時のマニュアル化と構成図は残すこと

いやぁ、業務ではさんざんやってることなのですが実家のネットワークなので完全にやらかしてました・・・。
これからは自宅でも実家でもネットワークの運用強化とセキュリティの改善に努めていきたいです！！
年末にやらかすと洒落にならないので・・・

本当は機械学習の話を書こうと思っていたのですが、検証してもうまく行かず急遽予備のネタから出したので内容が少なくなってしまい申し訳ございません。
出そうと思っていたネタは後日だしますので、もう少々お待ち頂ければ幸いです。

それでは皆様良いお年を！
ログラスの技術的負債を仕組みで返済していく戦略を紹介します

現在所属している株式会社ログラスでは技術的負債を貯めにくい組織運営をしており、その取り組みを紹介します。


https://qiita.com/advent-calendar/2021/present-calendar#kaonavi
また今年のアドベントカレンダーでは特定のトピックに関して記事を書くと、副賞がいただけるようなのでコッソリ狙っています。

基本方針は`「技術的負債は大きくなる前に叩く」`です。

## 技術的負債に対応する予算を取る
ログラスではあらかじめ技術的負債に対応するための予算SP（ストーリーポイント）を積んでいます。
下の図はチームのベロシティをトラッキングしているシートですが、毎週技術的投資（技術的負債）する予算を積んでいます。
ログラスでは技術的負債とは呼ばずに技術的投資と呼んでますが、似た概念なのでこの記事内では技術的負債と呼ぶことにします。

![Cursor_と_ベロシティ計測___SPわかる君_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17490/072283d7-482a-aca3-12ff-e87d7c5cb3e9.png)


## 技術的負債のリファインメントを行う
毎週技術的負債に取り組むので、チケットの整理する時間（技術的投資検討会と呼んでいます）を毎週30分積んでいます。
内容は新しい技術的負債チケットの確認と受入基準を定義です。その週に切られたチケットを確認し、受入基準を決めます。
今後数週間分のチケットが詰まっていることがわかっている場合は開かないこともあります。その都度柔軟に判断しています。

![Cursor_と_Loglass_-_カレンダー_-_2021年_12月_21日__火曜日_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17490/54dc191c-c40b-9e6e-d222-ca0bda3992ea.png)


## バージョンアップ会
使用しているライブラリにバージョンアップがある場合はDependabotが自動的にPRを作ってくれます。
下図は過去に使っていたAngularのバージョンアップしたときのPRです。
(現在はログラスではAngularは使っておりません。Angularからの移行に関しては[こちらの記事](https://note.com/yuitosato/n/n382f7dcc97c2)を参照ください。)
![スクリーンショット 2021-12-23 11.58.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17490/bca7b55a-be9c-3e0b-411f-d4124b729972.png)

作られたPRはマージする必要がありますが、その時間もライブラリバージョンアップ会として毎週30分確保しています。
バージョンアップといっても新しいバージョンに互換性があるものも多いです。そういったものは開発者が手元で動かしてこの時間内でマージしてしまいます。
中にはビルドが通らなくなったり、テストがこけるものがあり、それらの修正も軽ければこの30分で対応します。

バージョンアップは最新のバージョンと使用しているバージョンの差分が大きくなればなるほど大変になり、時間もかかります。

日頃からこまめにバージョンアップをしておけば、何かがあった時もサクッとバージョンをあげれるものです。
昨今のLog4jの問題も検知し、サクッとバージョンを上げることができました。これは日頃のバージョンアップ会の成果と言えるでしょう。

## もっと大きい技術的負債はどう扱うか
事業のコアの部分だったり、影響範囲が大きくなることがあらかじめわかっている場合は、OKRに組み込んで3ヶ月ぐらい長期的に取り組みます。
今クオータで言うとDBのテーブル名を10テーブルほど書き換える目標を積んでいます。


## まとめ

長々と書いてきましたが、まとめます。
1. 技術的負債を改善する時間をスプリントに組み込む
2. そのために日頃から技術的負債を
3. 小さいバージョンアップ系は開発陣全員が毎週30分「ライブラリバージョンアップ会」を行う
4. 大きめな負債はチケットを積んでスプリント内で行う
5. さらに大きいものはOKRとしてクオータの目標とする

こまめに返済していく仕組みづくりの共有でした。
DP750にログインできない

社内のIP phone としてワイヤレスを使いたいと要望あり。
以前試したWifi接続の製品は音質等で問題が多かった。
今回はコードレスの製品を試してみたがハマった。

Grandstrem DP720（子機）/DP750（親機）
1.親機の電源オン、LANを接続
2.子機の電源オン
3.子機を親機に登録
4.子機で親機のIP確認
5.親機をWebで設定

子機のBase Status で親機のIP確認
PCのブラウザーより接続し、マニュアル通り
username: admin  passwaord:admin
で接続するが繋がらない、5回間違えると15分接続できない。
工場出荷時に戻してもだめ、いろいろ試してもだめ...

返品も考え、本体の裏側を見ると　Password:XXXXXXXX
の表示が、それを使って見事ログインして
sip等の設定を終えることができました。

製品個体ごとにパスワードを変えてるのか、素晴らしい。
マニュアルは......
Sorceryでよく使うメソッド

##current_user
現在ログイン中のuserを返す。コントローラ、ビューで利用可能。

##require_login
ログインをしていないユーザーをアクション単位で弾く。
アクセスしようとしたURLをセッションに格納し、not_authenticatedを実行するメソッド。``before_action``で指定する。
アクションごとに変える場合は、``only: :action``を付ける。

```
#controller
before_action :require_login
```

##not_authenticated
require_login内で、このメソッドが実行される。
``デフォルトではredirect_to root_path（自動的にルートに飛ばされる）と定義されている``が、カスタマイズしたい場合はapplication_controllerで上書きをする。

```
class ApplicationController < ActionController::Base
  protected

  def not_authenticated
    redirect_to login_url, alert: 'ログインしてください'
  end
end
```

##logged_in?
require_loginと比べて、アクション内の分岐などもっと細かい単位で弾きたい場合に使用。

現在ログイン中かどうか、true or falseで返す。コントローラ、ビューで使える。
ログインしているかどうかによって場合分けをしたいときに使う。

```
#view
<% if logged_in? %>
  <%= link_to 'プロフィール', user_url(current_user) %>
<% else %>
  <%= link_to 'ログイン', login_url %>
<% end %>
```

##auto_login(user)
メールアドレスやパスワードを使わずuserとしてログインする。(オートログイン)
想定される使い方としては下記が挙げられる。
``・ユーザー登録後の自動ログイン``
``・ゲストユーザーログイン``
``・開発環境でのログイン``

**ユーザー登録後の自動ログイン**

```
#controller

def create
    @user = User.new(user_params)
    if @user.save
      auto_login(@user)
      redirect_to root_url, notice: 'ユーザーを登録しました'
    else
      flash.now[:alert] = 'ユーザーが登録できませんでした'
      render :new
    end
```

**ゲストユーザーログイン**

```
#controller

def guest_login
    guest_user = User.find_by!(role: 'guest')
    auto_login(guest_user)
    redirect_to root_path, notice: 'ログインしました'
  end
```

**開発環境でのログイン**

```
#controller

def login_as
    user = User.find(params[:user_id])
    auto_login(user)
    redirect_to root_path, notice: "#{Rails.env}環境でログインしました"
  end
```

```
#routes

if Rails.env.development?
    get '/login_as/:user_id', to: 'user_sessions#login_as', as: :login_as
  end
```

「/login_as/1」などにアクセスすると自動的にそのユーザーとしてログインする」ので、``if Rails.env.development?``は**必ず付ける**。

**[その他メソッドはここ](https://github.com/Sorcery/sorcery#api-summary)**

##参考記事
[【Sorcery】Sorceryで使えるようになるメソッドとその活用例](https://qiita.com/aiandrox/items/65317517954d8d44d957)
UniTaskに対応したStateMachine、UniTaskStateMachineを公開しました！

# はじめに

UniTaskを利用することで、コールバックを減らしコードの可読性が上がり様々な恩恵を受けてきました。
しかし、RecycleScrollViewやStateMachine、BehaviorTreeなどAPIの戻り値がUniTaskになっていないサードパーティーのパッケージがほとんどです。
そこで今回はStateMachineを対応してみようと思い、UniTaskStateMachineを実装しました。

# 何が便利なのか？
## OnEnter,OnUpdate,OnExitの戻り値がUniTask
StateMachineの詳細な説明は省きますが、以下のように戻り値がUniTaskで引数でCancellationTokenを渡すようにしています。

```c#
public interface IState
{
    UniTask OnEnter(CancellationToken ct = default);
    UniTask OnUpdate(CancellationToken ct = default);
    UniTask OnExit(CancellationToken ct = default);
}
```

例えばOnEnter内で非同期の初期化処理が必要になった時に、awaitをかければ処理が終了するまでOnUpdateが呼ばれなくなります。
OnUpdateでawaitをかけると次のフレームが来てもOnUpdateが前回の処理が終了するまで呼ばれることがありません。
OnExitでawaitをかけると処理が終了するまで次のステートに遷移しません。

このようにすることで戻り値がvoidの時と比べ、フラグ管理や呼び出し順に頭を抱える必要がなくなると私は感じています。

ベースの実装は以下の階層のファイルだけで完結できるので仕組みはシンプルです。

https://github.com/k-okawa/UniTaskStateMachine/tree/master/Assets/Bg/UniTaskStateMachine/Runtime/Base

## StateMachineEditor付属

しかし、それだけではパッケージとしての特色が少ないので、合わせてStateMachineEditorも実装しました。(こちらの方が実装大変)
![image](https://user-images.githubusercontent.com/49301086/137613577-d510a77c-0231-4e76-bf0f-a6f16a2ae506.png)

コード上でステートの遷移を実装すると各ステートの繋がりが分かりにくいので、把握に時間がかかったり不具合の原因にもなります。
グラフで遷移を視覚的に確認できるとそういった煩わしい時間を減らすことができると感じています。
またプレイ中には現在実行中のステートを確認することも可能です。

# UniTaskStateMachine

https://github.com/k-okawa/UniTaskStateMachine

## インストール
３通りのインストール方法を提供しています。
また、UniTaskはパッケージ内に含まれていないので本家様からのインストールが必要です。

https://github.com/Cysharp/UniTask

### GitHub経由でインストール(PackageManager)

Window/Package Managerを開き、add package from git URL...で以下を入力して追加してください。

```
https://github.com/k-okawa/UniTaskStateMachine.git?path=Assets/Bg/UniTaskStateMachine
```

### OpenUPM経由でインストール(PackageManager)

```
openupm add com.bg.unitaskstatemachine
```

### UnityPackageを展開してインストール
リリースページからダウンロード可能です。

https://github.com/k-okawa/UniTaskStateMachine/releases

## 使い方
今回の記事では詳細な使い方は説明しないので、詳細はREADMEをご参照ください。

https://github.com/k-okawa/UniTaskStateMachine/blob/master/README.ja.md

# 最後に
UniTaskStateMachineが初めて公開したオープンソースパッケージになりますので、私の発想が便利で役立つものになっているか・そもそも思想が間違っていないか心配なところはありますが、是非使っていただけると嬉しいです！
Macでのファイル圧縮について

少し前まではzipファイルにしてもらえるアプリを使っていたのですが、
OSアップデートしたタイミングでアプリが使えなくなり、
そのタイミングでターミナルのコマンドでのファイル圧縮に切り替えたのですが、
色々覚えておきたいことがあったので、自身の備忘録用に投稿しました。

## ①ファイルの圧縮方法(パスワード付き)
ターミナルで圧縮したいファイルがある階層まで移動して、
以下のコマンドを入力。圧縮する前のファイル名のところは必要に応じて拡張子を変えてください。
> zip -e 作成したいファイル名.zip 圧縮する前のファイル名.pdf

「-e」を抜けばパスワードなしで圧縮できます。

## ②フォルダの圧縮方法(パスワード付き)
> zip -e -r 作成したいファイル名.zip 圧縮する前のフォルダ名

こちらも同じく「-e」を抜けばパスワードなしで圧縮できます。
①と比べると「-r」が増えましたね！

## ③Macで圧縮→Windowsで解凍する場合の文字化け対処
普段Macでお仕事しているのであまり気にならなかったのですが、
Windowsの方にファイルを送信するとファイル名が文字化けしているとお声かけいただいたことがあり、
調べてみました。
> zip 作成したいファイル名.zip -e -r 圧縮する前のフォルダ名 -x "*.DS_Store"

こちらも「-e」、「-r」については①②と同じですね！
「-x」で除外するファイルを指定できるみたいです。目からウロコです・・・
参考：https://dorobachi.com/pcit/mac-zip/

## まとめ
お仕事してると地味にzipファイルを送る機会が多く、
この3つは最低限覚えときたいなと自身で改めて思いました！
【python】try-except使っても次の処理走るから気をつけろ

#備忘録です
エラー処理実装している時にすっかり頭から抜けていた知識の備忘録。

#内容
##try-exceptでエラー処理
基本の基本はこれ。
これを実行すると「エラーです！」ってちゃんとでる。

```py
def main():
    try:
        a = 1 / 0
    except:
        print("エラーです！")

main()
```
出力結果：

```
>>エラーです！
```

頭から抜けていたのがこの部分。
exceptに入れば以降の処理はされないっしょー！って思ってたら違った。
冷静になればそりゃそうなんだけど、集中しててすっかり忘れていた。

```py
def main():
    try:
        a = 1 / 0
    except:
        print("エラーです！")
    print("ここも処理されちゃう")
    print("だってまだmainの中だもん")

main()
```
出力結果：

```
>>エラーです！
>>ここも処理されちゃう
>>だってまだmainの中だもん
```

finallyがあっても同じ挙動。

```py
def main():
    try:
        a = 1 / 0
    except:
        print("エラーです！")
    else:
        print("ここはelse")
    finally:
        print("ここはfinally？")
    print("ここも処理されちゃう")
    print("だってまだmainの中だもん")

main()
```
出力結果：

```
>>エラーです！
>>ここはfinally？
>>ここも処理されちゃう
>>だってまだmainの中だもん
```

多分もっと良いやり方あるんだろうけど、一旦こういうやり方で実装。

```py
def main():
    try:
        do_main()
    except Exception as e:
        print("エラー："+str(e))

def do_main():
    try:
        a = 1/0
    except:
        raise Exception("わっしょい")
    print("ここは処理される？")
    print("mainの中だけど大丈夫？")

main()  
```
出力結果：

```
>>エラー：わっしょい
```
neosでlogix その36

#概要

niosでlogixやってみる。
On Collision Startノードを使ってみた。




#手順

- 新規->3d->box
- インスペクターを開く
- BoxCollierのインターフェースを取り出す
- ノードブラウザを表示
- On Collision Startをスポーン
- つなぐ


#結果

つなげない。バグか。


以上。
GR-ROSEをIoT Hubに接続

先日ALGYANのGR-ROSE IoTシステム開発コンテスト作品LT大会にて発表したシステムに関して、IoT Hubとの接続の部分について詳しく知りたいという声があったので曖昧な記憶を頼りにまとめておきたいと思います。

##  Azure側の準備

* IoT Hubにデバイスを登録
* デバイスプロビジョニングサービス（DPS）を追加してIoT Hubと紐付け

IoT Hubにデバイスを登録するところまでは他に参考記事がたくさんあると思いますので割愛させて頂きます。DPSの赤枠部分の情報が後ほど必要になってきます

![スクリーンショット 2021-12-23 11.44.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326104/b32dcf45-9518-1adf-87c6-d52496ea1a69.png)

左のリンク済みIoT HubよりIoT Hubを追加します

![スクリーンショット 2021-12-23 11.32.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326104/76ea6239-8f95-4046-93ed-1c6863c877b5.png)

IoT Hubに登録したデバイスの主キーとセカンダリキーをDPSに登録します

![スクリーンショット 2021-12-24 20.33.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326104/0ff18cbb-c414-2246-702c-47d8d6a52518.png)

個別登録の追加→対称キーを選択しデバイスの情報を入力します

![スクリーンショット 2021-12-24 20.37.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326104/2fb3587e-fa0e-5c4f-8703-a4ce53cc53ee.png)

## GR-ROSEのソースコード

ENDPOINTとID_SCOPEが先程のプロビジョニングサービスの情報になります

```cpp
#define ENDPOINT.            "rose-provisioning.azure-devices-provisioning.net" 
#define ID_SCOPE             "0ne003AD2F6"
#define REGISTRATION_ID　　　　　　　　　　　　"symm-key-rose-0001" // DPSで登録した対称キーの登録ID
#define DEVICE_SYMMETRIC_KEY "xxxxxxxxxx" // IoT Hubに登録しているデバイスの主キー
#define MODULE_ID.           ""
```
neosでlogix その35

#概要

niosでlogixやってみる。
Global Transformノードを使ってみた。

#写真

![2021-12-23 00.17.04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/a350db0f-8917-89be-6fef-c64d61a1457b.jpeg)

#Global Transform

```
Inputs
 	Slot	Instance
Outputs
 	Float3	GlobalPosition
 	FloatQ	GlobalRotation
 	Float3	GlobalScale
```

以上。
PHP の各バージョンを検証するための docker-compose

PHPのアップグレードのために細かい動作を確認したくて、
1つの docker-compose に検証用環境全部詰め込んでみました

## 検証用の docker-compose ファイル

``` docker-composel.yml
version: '3'
services:
  php-8.1:
    image: "php:8.1-cli"
    stdin_open: true
  php-8.0:
    image: "php:8.0-cli"
    stdin_open: true
  php-7.4:
    image: "php:7.4-cli"
    stdin_open: true
  php-7.3:
    image: "php:7.3-cli"
    stdin_open: true
  php-7.2:
    image: "php:7.2-cli"
    stdin_open: true
```

ファイルはこれだけ
`stdin_open: true` をつけているので実行プロセスが特になくてもコンテナが終了せず利用できます

```
inspect_php
- docker-compose.yml
```

## 実行

まとめて立ち上げてみます

```
$ cd inspect_php
$ docker-compose up
...
Attaching to study_php_php-7.4_1, study_php_php-8.0_1, study_php_php-8.1_1, study_php_php-7.2_1, study_php_php-7.3_1
php-7.4_1  | Interactive shell
php-7.4_1  | 
php-8.0_1  | Interactive shell
php-8.0_1  | 
php-8.1_1  | Interactive shell
php-8.1_1  | 
php-7.3_1  | Interactive shell
php-7.3_1  | 
php-7.2_1  | Interactive shell
php-7.2_1  | 
```

7.2から8.1まで起動しました
それぞれのバージョンも確認

```
$ docker-compose exec php-7.2 /bin/sh -c 'php -v'
PHP 7.2.34 (cli) (built: Dec 11 2020 10:44:02) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

$ docker-compose exec php-7.3 /bin/sh -c 'php -v'
PHP 7.3.33 (cli) (built: Dec 21 2021 22:01:38) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.33, Copyright (c) 1998-2018 Zend Technologies

$ docker-compose exec php-7.4 /bin/sh -c 'php -v'
PHP 7.4.27 (cli) (built: Dec 21 2021 21:28:03) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

$ docker-compose exec php-8.0 /bin/sh -c 'php -v'
PHP 8.0.14 (cli) (built: Dec 21 2021 20:34:57) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.14, Copyright (c) Zend Technologies

$ docker-compose exec php-8.1 /bin/sh -c 'php -v'
PHP 8.1.1 (cli) (built: Dec 21 2021 19:35:25) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.1, Copyright (c) Zend Technologies
```

大丈夫ですね
折角動いたのでバージョンごとの動きの違いも見てみましょう

## 検証

https://www.php.net/manual/ja/migration80.incompatible.php
PHP7.4 -> PHP8.0 で文字列と数値の比較に変更があったので試してみます

### PHP 7.4

```
$ docker-compose exec php-7.4 /bin/sh
# php -a
Interactive shell

php > var_dump(0 == "");
bool(true)
```

7.4 では 0 と非数値文字列の比較は true になります

### PHP 8.0

```
$ docker-compose exec php-8.0 /bin/sh
# php -a
Interactive shell

php > var_dump(0 == "");
bool(false)
```

8.0 では false になることが確認できました
サザエさんに出てくる”御用聞き”サブちゃんをLINEBotで再現して買い忘れを防ぐ！

##買い忘れを防ぎたい、サブちゃんに来て欲しい。
サザエさんに出てくる"御用聞き"三河屋のサブちゃんをご存じでしょうか？
自宅へ定期的に訪問、足りない食料品等を確認、補充してくれる。
ありがたい存在です。
普段の生活でしょうゆを切らしてしまったなどを防ぎたい。
今回はそんな課題を”御用聞き”サブちゃんのしくみをLINEBotで再現して解決しました。
##初心者でもつくれるLINEbot
LINEBotを選択した理由は~~単にNode-REDしか使えないから。~~コミュニケーションツールとして活用しており、家族で共有可能な為です。このLINEとNode-REDを活用してツールを作ることにしました。
#どこまで実現できるか？
サザエさんに出てくる"御用聞き"サブちゃんの行動と実装内容を考えました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/6d927e7f-82f8-e454-fad7-fd5d11484394.png)
今回は自宅の在庫確認機能を実現します！
#”御用聞き”からLINEが来る
こんな感じでメッセージが届きます！
![Qiita用.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/de71c672-0c11-d776-ddef-c4a81fabc319.png)
#Googleスプレッドシートで在庫管理する
今回はGoogleスプレッドシートで情報管理を行います。
![スクリーンショット (69).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/da5a0708-d5ed-eb31-a664-4bedef101e2d.png)
【しくみ】
B列：品目ごとの購入頻度を記載しておく
C列：LINEで品目を送信すると購入日（メッセージ受信日）が更新される
D列：購入日に購入頻度を加算することで次回購入予定を算出する
E列："購入日まで（日）"が０になると、メッセージで購入を促す

###ちなみに品目以外のキーワードを送ると、、、
こんな感じで返信がきます。
![Qiita用2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/778259e1-7499-3619-676c-7dedf33265e9.png)
Googleスプレッドシートに記載している品目を教えてくれます。

##参考までにNode-REDの構成図
![スクリーンショット (71).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811885/057f0418-be07-ad42-005e-a3945a2aa661.png)

###Amazonの定期購入があるとの声もありますが、、、
私が住んでいるのが沖縄なもので配達が意外と遅れたり、なにより昭和の古き良きレトロな感じを令和で再現したかったという思いから制作しました。
なによりプログラムなどが分からない人間でもこんなツールが作れますよということを多くの人に知って頂きたいと考えております。
今後は家族で活用していきます！

最後まで読んで頂き誠にありがとうございました。
【Flutter】"A splash screen was provided to Flutter, but this is deprecated."を解消する

先日Flutterのバージョンを2.2.3から2.8.0に上げてから、`A splash screen was provided to Flutter, but this is deprecated.`
とコンソール上にログが表示されるようになったので、少し調べてみました。
#概要
### 公式ドキュメント
> Previously, Android Flutter apps would either set io.flutter.embedding.android.SplashScreenDrawable in their application manifest, or implement provideSplashScreen within their Flutter Activity. This would be shown momentarily in between the time after the Android launch screen is shown and when Flutter has drawn the first frame. This is no longer needed and is deprecated – Flutter now automatically keeps the Android launch screen displayed until Flutter has drawn the first frame. Developers should instead remove usage of these APIs.

どうやらFlutter v2.5.0以前のFlutter製Androidアプリでは、デフォルトだとFlutterが最初のフレームを描画するまでの間に一瞬スプラッシュ画面を表示するようでした。
今後はFlutterが最初のフレームを描画するまでの間、Android側で起動画面を自動的に表示し続けるようになったので、`io.flutter.embedding.android.SplashScreenDrawable`のAPIが非推奨になったようです。
# 対処法

### AndroidManifest内の該当箇所を削除する

```main/AndroidManifest.xml
            <meta-data
              android:name="io.flutter.embedding.android.SplashScreenDrawable"
              android:resource="@drawable/launch_background"
              />
```

上記箇所を削除することで解消しました:relaxed:


#参考
https://docs.flutter.dev/development/ui/advanced/splash-screen#migrating-from-manifest--activity-defined-custom-splash-screens

https://stackoverflow.com/questions/69141338/flutter-v2-5-0-android-splash-screen
【30分でやってみた】pythonでEXCELを操作

#動作環境：
python3.10.1
EXCEL2016


#①pythonをインストールしてみた（10分）
ダウンロード元：https://www.python.org/downloads/
インストール後に、必要なライブラリのインストールする。

```
pip install openpyxl

```
この「openpyxl」はpythonの中でもメジャーなライブラリであり、EXCELを処理する速度が速いそうです。

以上で環境の準備は完了です。

#②EXCELを操作してみた(20分)

・EXCELのファイルを読み込む

Sample.xlsxにファイル内のsampleシートのA1を読み込みます。

```
wb = openpyxl.load_workbook('./Sample.xlsx')
sheet = wb['sample']
value = sheet['A1'].value
wb.close()
}
```

・EXCELにデータを書き込む

A2に10を書き込んでみる
```
wb = openpyxl.load_workbook('./Sample.xlsx')
sheet = wb['Sample']
sheet['A2'].value = 10
wb.save('./Sample.xlsx')
wb.close()
```

#感想
慣れた人なら、もっと早くできると思いますが、pythonでEXCELを操作することは思ったより簡単でした。
windowsやMACなどOSに依存せずに使用できるため、業務でも使用できると思います。
今後はもっと複雑な処理でも実行してみていきたいと思います。
2022年版 未経験でAWS SAAを受験する前に確認して欲しいこと


#はじめに
久々の投稿になります。<br>AWSソリューションアーキテクトアソシエイト(以下AWS SAAとする)を受験する前にこれだけを知っておけば対策ができて1発合格したかもしれないと後悔をしました。今後受験される方は是非参考にしてほしいです。

#投稿者の当時のレベル
経験年数 4か月
EC2の構築
RDSの構築
Route53のDNS設定
セキュリティグループのポート番号の役割
以上です。


#当時の試験対策
AWS Cloud Tech(有料会員)400問のみ
模試は90％以上を維持
無論、答えを丸暗記ではなく解説をしっかり読んで何故それが答えなのかを<br>答えれるレベルまで模試を繰り返し対策をしました。

`ここからが本題です。3つ大きく分けて説明します。`

#その1 AWS SAAの本当の試験範囲を知っていますか?
下記のURLを必ず見て下さい。試験範囲が公開されています
[公式より抜粋 AWS SAA試験範囲](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf)。<br>今、勉強している問題集が試験範囲に対応できているかどうかを必ず確認。対応していない問題集で勉強するといくら努力しても合格点に近づくことは難しいです。<br>因みに投稿者はAWS CloudTechのみで試験対策をしましたが試験範囲をカバーできていないことが受験後、分かりました。




#その2 採点対象外の問題があることを知っていますか？
`65問中15問は採点対象外です。`但し、どの問題が採点対象外かは受験者にわからないようになっています。なので分からない問題は採点対象外の可能性が非常に高いです。



#その3 自宅受験で130分集中できますか？
`自宅で集中できない方はテストセンターで受験する事をお勧めします!!`<br>私は試験途中で集中力が無くなり無理でした。テストセンターを勧める理由は４つあります。

1. `面倒な手続きや準備をする必要はありません。`全て試験監督がやってくれます。テストセンターに行くだけで受験が可能です。

2. `テストセンターのPCは最強のスペックなのでフリーズする心配はありません。`快適に受験できます。自前のPCのスペックが低いと試験中にフリーズして集中できない恐れがあります。

3. `各テストセンターによりますが試験中お手洗いに行くことが出来ます。`但し試験時間は止まらないので受験前にトイレを済ませること。

4. 他の受験生もいるので集中ができる。


以上です。
#最後に
私自身ほぼ未経験ですが2回目で合格しました。合格率は公開されてはいないですが40％ほどみたいです。ですが、しっかり対策を取れば未経験の方でも十分合格できます!!受験生の健闘を祈ります!!
割込み処理を使ってESP32と人感センサで人数を計測する


##はじめに
はじめましてT－Aと申します。
初のQiita投稿ということで緊張しております。

皆様、MicroPythonでの割込み処理をご存知でしょうか？

簡単そうに見えて複雑な割込み処理ですが、
今回は人を検知したらカウントされていくプログラムをご紹介致します

この記事では以下の環境で動作確認をしております。
MicroPython：v1.14
ハードウェア：ESP-WROOM-32 

2台のセンサを動かすプログラム
---
~~~python:sample.py
    from machine import Pin

      motion = False

    def handle_interrupt(pin):
      global motion
      motion = True
      global interrupt_pin
      interrupt_pin = pin 

    sensor1 = Pin(35, Pin.IN)
    sensor2 = Pin(34, Pin.IN)

    sensor1.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
    sensor2.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)

    num = 0

    while True:
       if motion:
       num = num + 1
       if num <= 50:
         state = machine.disable_irq()
         print(num)
         motion = False
         machine.enable_irq(state)  
       else:
         break
~~~
このプログラムについて説明致します。

##割り込みの紹介
割り込みが発生すると、メインプログラムの実行を停止して割込みを実行し、その後メインプログラムに戻ります。ようするに変更が検出されると、関数が呼び出されます。
![割込み.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2298143/b0a0fff1-98b5-2107-dd03-2056ac749d7c.png)

割り込みは、プログラムで物事を自動的に動かすのに活用しやすく、プログラムが実行されるタイミングの問題などを解決することが出来ます。割り込みを使用すると、現在のピン値を常にチェックする必要はありません。

#プログラムの解説
~~~python:sample.py
    def handle_interrupt(pin):
      global motion
      motion = True
      global interrupt_pin
      interrupt_pin = pin
~~~
ここがメインの割込み処理部分になります。
簡潔にいうと動きを検知した時に呼び出されるのがこの関数に当たります。

~~~python:sample.py　　
    sensor1 = Pin(35, Pin.IN)
    sensor2 = Pin(34, Pin.IN)
~~~
sensor1,2は何でも構いません。ここで入力ピンの設定をしています。
今回は35番と34番で設定していますので使っているESP32に合わせてピンを設定し直してください。

~~~python:sample.py　
    sensor1.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
    sensor2.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)
~~~
PIN.IRQ_RISINGはピンがLOWからHIGHになるたびに割り込みを行うという意味です。
他にもピンがHIGHからLOWになるたびに割り込みを行うPin.IRQ_FALLINGや、
両端で割り込み(変更が検出された場合)には3を指定します。

~~~python:sample.py　
    while True:
       if motion:
       num = num + 1
       if num <= 50:
         state = machine.disable_irq()
         print(num)
         motion = False
         machine.enable_irq(state)  
       else:
         break
~~~
今回は動きを検知したら50回まで計測できるプログラムになっています。
ここでstate = machine.disable_irq()とmachine.enable_irq(state)で囲むことをお忘れなく！
これがないと割り込みが終了せず、片方のpinしか動きません。

##終わりに
今回はESP32を用いてこの実験を行いました。
myclopythonはどうしてもpythonとの違いが分かりにくいところではありますが、
是非このプログラムを参考にして割込み処理をやってみましょう！

最後まで見ていただきありがとうございました。
参考になりましたら、LGTMを押していただけるとうれしいです(^▽^)/

---
参考文献
https://micropython-docs-ja.readthedocs.io/ja/latest/reference/isr_rules.html
GitHub Actionsでmakeの結果をキャッシュする

GitHub Actionsでは公式が依存ライブラリやビルド成果物をキャッシュするためのaction, [actions/cache](https://github.com/actions/cache)が提供されています。npmやpipなどの依存関係管理ツールがパッケージを保存するディレクトリをキャッシュすることで、各ビルド・テストの時間を大幅に削減することができます。ところが、公式のabout

> Cache dependencies and build outputs in GitHub Actions

の`build outputs`は例示がなく、これまで使ったことがありませんでした。

今回はこれをmakefileで管理するプロジェクトにあてはめ、いい感じにしてくれるようにしたので、ご紹介します。

## そもそもmakeの結果をキャッシュする... ?

そもそも論、せっかくクリアーな環境を毎回用意してくれるんだから、makeの結果をキャッシュするなんてナンセンスだ！という主張があると思います。全くその通りです。ただ、

- プライベートリポジトリで時間を少しでも節約したい
- 比較的重い処理があり、vCPUが2個だけだとキャッシュがないと辛い。
- ほとんど変わらないのにブランチへのプッシュを全部作りなおすのはちょっと...

というケースはあると思います。僕の場合、研究の解析に使うスクリプトをプライベートリポジトリに生データごと入れておいて、毎プッシュごとに自動ビルドしています。

データは50本のｸｿﾃﾞｶサンプルで、これのアンサンブルをとる処理になっています。具体的には、データから距離データやボロノイ体積を計算したりする比較的重めの処理があり、これらが計算時間をだいぶ使ってしまっていました。そのままでは研究室のオーガナイゼーションのビルド時間がひっ迫してしまうため、makeの結果をキャッシュすることにしました。

## 解決法

GNU makeは、`outputとinputのtimestampを比較して、inputの方が新しければ再ビルドする`という挙動をします。

[actions/checkout](https://github.com/actions/checkout)と[actions/cache](https://github.com/actions/cache)を使うと、timestampは全部最新のものになってしまうため、キャッシュされていてもmakeはすべて再ビルドしてしまいます。また、workflowをtriggerしたcommitのすぐ直前のビルド結果のキャッシュを使ってほしいです。いろいろ複雑

これを解消するために [cache-make](https://github.com/flat35hd99/cache-make) というactionsを作成しました。

https://github.com/flat35hd99/cache-make

## 使い方

`actions/checkout`で`fetch-depth: 0`を付けていつも通りcacheを呼んだあとは、`uses: flat35hd99/cache-make@v1.0.0`を宣言するだけで動くようにしてあります。Easy to use !

```yaml
jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0 # 履歴を全部取得
      - name: Setup cache
        uses: actions/cache@v2
        with:
          path: dist/
          key: ${{ runner.os }}-makefile-${{ github.sha }}-${{ hashFiles('**/makefile') }}
          restore-keys: |
            ${{ runner.os }}-makefile-
      - name: Change updated time
        uses: flat35hd99/cache-make@v1.0.0 # 読み込むだけ!

      - name: Build
        run: make
```

## 仕組み

1. checkoutする(actions/checkout)
1. cacheを取得する(actions/cache)
1. gitに記録されているファイルのtimestampを変更する(flat35hd99/cache-make)
    1. 前回のコミットなど(ref)との差分を取得
    1. 変更されていないファイルのtimestampを大昔のtimestampに変更する（1970/1/1)

こうすればmakeはgitのツリー上で新しくなったスクリプトの影響を受けるものだけmakeし直します。

## 終わりに

まだ微妙なところはたくさんある(ex: merge時の挙動、インターフェースの改善)ので、issueやpull requestいただけるととても嬉しいです。

そもそも論を繰り返させていただきますが、今回紹介したactionは大事なビルドなどでは使わないことを強く推奨します。せっかくクリーンな環境があるのに、それを無下にしてしまいかねません。実際、キャッシュの挙動が予測しきれておらず、ビルドが通らないということがありました。GitHub Actionsは自動で全部やってくれることが売りなのに、その挙動を開発者が考えなければならないのは愚かでしかないです。ビルド時間を早くする、他の解決法を見つけるなどして、できるだけこのツールは使わないようにすべきです。どうしてもというときに、リリース以外のPull requestのプッシュだけで有効にするなど、限られたケースでは有用ではないかと思います。

あと実はこれは「[身の回りの困りごとを楽しく解決！【PR】Works Human Intelligence Advent Calendar 2021](https://qiita.com/advent-calendar/2021/works-hi)」の記事なのですが、楽しさポイントは最近読んでいる[A Philosophy of Software Design](https://www.amazon.co.jp/-/en/gp/product/B09B8LFKQL/ref=ppx_yo_dt_b_d_asin_title_o01?ie=UTF8&psc=1)のインターフェースを減らして複雑性を減らそうという考え方を全面的に体現できるように実装したことです。学んで実践するプロセスができて僕は大変満足です。
CloudFrontの署名付きURLを使ってS3にファイルをアップロードする

# 概要
CloudFrontの署名付きURLを使ってS3にアップロードしたファイルをブラウザから直接ダウンロードする方法は調べるといくつか出てくるが、アップロードの情報が少なかったので備忘録として書いておく。

今回はS3のpresigned-urlを使ってファイルアップロードするのではなくCloudFront経由でファイルアップロードする必要があった。
BackendをGolangで作っており、署名付きURL実装もGolangで実装していたため、SDKのリファレンスを眺めていたが関連しそうなものがなかった。

# 結論
CloudFrontに署名付きURLの設定を行うと自動的にS3のバケットポリシーを追加してくれるが、そこにActionを追加してから生成した署名付きURLにputでリクエストするだけで良かった。

```json
{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity *****"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject"  ←これを追加
            ],
            "Resource": "arn:aws:s3:::S3のドメイン/*"
        }
    ]
}
```
QR Jengaを作った

https://twitter.com/asakura_dev/status/1472604567502475265

QRの黒い部分を消していくゲームがトゥイッターでバズってたので作りました。

ツイート主の方も作っていることに後から気づきました。

- 本家: https://makir0n.github.io/QRCodeJenga/
- 今回作ったやつ: https://ssssota.github.io/qr-jenga/

## 技術的な話

### 本家との差別化

どうせWebでやるならWebで完結させたかったので、自動判定を付けてます。

判定にはjsQRというライブラリを用いています。
このライブラリは汎用的なQRリーダで、スマホのカメラと合わせて使うことが多いですが今回は、内部で擬似的にレンダリングしたQRをjsQRに読み込ませてます。

これは若干冗長なプロセスで、できたQRをそのままデコーダに食わせることもできます。
ただ、デコーダは必要な部分しか読み取らず、位置補正や歪み補正のブロックが意味を持たなくなってしまいます。
これではゲーム性を著しく低下させるので敢えてレンダリングを挟んでいます。

ただチューニング不足か、精度が悪いのか、「ゲームでは読めない判定なのに、まだ読める。そうiPhoneならね」という事態が発生しました。
ここまでやっておいてなんですが、自動判定機能はオフにできます。

**やっぱスマホで撮って読めるかドキドキした方が楽しい。**

### SvelteKit

最近の趣味開発はもっぱらSvelteKitです。
今回も例に漏れずSvelteKitを採用しています。

CSS in JSや、状態管理ライブラリの検討をする必要がないです。
詳細は調べていただければと思いますが、

- Vue.jsのようにSFCで直接スタイルを書ける（賛否ありそう）
- Svelte組み込みのストア

の2つは地味ながらかなり強力です。

### ライブラリ

みなさんも作りたいでしょうから、QR Jengaのコア部分はnpmにリリースしました。

React/Vue.js/CLI版待ってます！

- https://npmjs.com/qr-jenga

今回ライブラリも一つのリポジトリに入れてるので[pnpm](https://pnpm.io)のWorkspaceを使っています。

### スタイル

勢いで1,2日で作ったのでスタイリングは手を抜いてます。

今回は、[water.css](https://www.npmjs.com/package/water.css)という class-less なCSS Frameworkを使いました。

## おわりに

世の中のQRをいたずらで白に塗りつぶすのはやめましょう（？）
Pioneerの固定電話TF-LU74の時刻合わせの方法

公式サイトからも既に取扱説明書のダウンロードができなくなっているため機能+任意のボタンの組み合わせを片っ端から試して発見しました。

- システム名：TF-EV32
- 親機名：TF-LU74

# 時刻合わせの方法
1. 機能ボタンを押す
1. 再ダイヤル／着信メモリボタンを押す
1. 音声ガイドが始まるのは後はそれに従い以下を操作
1. yymmddを6桁で入力
1. hhmmを4桁で入力
1. 機能ボタンを押す
GitHubへのpushが「fetch first」と表示されてrejectedとなったときの対処

 

# 原因
原因はリモートリポジトリーで変更した内容がローカルに反映されていないため、pushができない。

# 対処方法
```
① git fetch.    してから、
② git merge.    そして、
③ git branch.   で既存のbranchを確認してからpushをして終了。
````
# git fetchとは
gitの場合、リポジトリはリモートとローカルで2つある。
git fetchとはリモートリポジトリで更新された最新情報をローカル
リポジトリに持ってくるコマンドのこと。
しかしpullのようにファイルが更新されるわけではない。

ファイルが更新されるのではなく、
orgin/masterが更新される。

# git mergeとは
マージは、Git において分岐した履歴を戻して統合する手段です。
git merge コマンドは、 git branch を使用して作成された、独立した複数の開発ラインをひとつのブランチに統合するコマンドです。
[py2rb] set pop

# はじめに
移植やってます。
# pop (Python)
```python
kwa = kw_given.pop()
```
この`kw_given`は`set`っぽいのです。

https://docs.python.org/ja/3.7/library/stdtypes.html#frozenset.pop

> s から任意の要素を取り除き、それを返します。集合が空の場合、 KeyError を送出します

# どうする？ (Ruby)
```ruby
require 'set'

kw_given = (1..5).to_set

kwa = kw_given.first; kw_given.delete(kwa)
```
`Set`から任意の要素を取り出すメソッドってあまり無いようです。

https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/first.html

`first`はEnumerableモジュールのメソッドです。
# メモ
+ Python の pop を学習した
+ 道のりは遠そう
rsyncでファイルをコピーしただけなのに危うくSSHでログインできなくなりそうになった話

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

# 0. はじめに

もう、タイトルのとおりです。
ビックリしました。

# 1. 何をしたか

rsyncで以下のようにファイルをコピーしただけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/10cc8175-eddd-cf1f-9157-48aa361ed77d.png)

# 2. 突然SSHでログインできなくなった

SSHでログインできなくなりました...。
AWS EC2でSSHログインできないと終了フラグです。

たまたま、SSHで開いていたターミナルがありましたので対処できましたが、そうじゃなかったらインスタンスを作り直さないといけなかったかも。

# 3. 何が起こったか

犯人は複数要因でした。

1. SSHサーバーの設定では、/home/userB つまり、userBのホームディレクトリの権限が700でない場合ログインできなくなるというセキュリティー設定が入っています。
2. rsync -a はディレクトリパーミッションもコピー先のディレクトリに適用するという設定が入っています。

つまり、以下のコマンドは、

```
rsync –a DirA/ userB@hoge:/home/userB/ 
```

DirAのパーミッションを/home/userBディレクトリに適用するということになります 😱

そして、DirAのパーミッションは、750でした。。
rsyncコマンドにより/home/userBのパーミッションは750になり、SSHログインできなくなりました。。。。

# 4. まとめ

rsyncの `-a`オプションには気をつけよう。
MAMP htdocs開いてもエラーが出る

MAMPでwebサイトを開こうとしても
If you can see this page, MAMP has been properly configured & launched and is now all set to serve your web content. This placeholder page1 should be replaced or deleted.
[スクリーンショット 2021-12-23 10.15.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858841/0cfd9ac3-2907-5242-8c7d-3f57beea0274.png)

が出て、パス一覧が表示されない場合は、htdocs/index.php　のファイルを削除すると、エラー文が消える!
bootstrap-select　セレクトボックスにjavascriptで選択肢が反映されない、選択値が表示されない

### やりたいこと

bootstrap-selectを利用していたセレクトボックスに、他セレクトボックスを変更したタイミングで新しい選択肢をセットし、初期値設定して表示させたい。


### エラー内容

１．選択肢がうまく表示されない
２．初期値セットはできているようだが、表示されない「nothing selected」





### 原因

bootstrap-select , selectpickerを使ったセレクトボックスであること


### 解決策

１．refreshする必要がある
２．少し時間差（0.1秒）をつけて、セットするようにすればうまく動いた

```js
/**
 * 契約元セレクトボックス設定
 */
function setSelectList(contractorList) {
    // 一旦削除
    $('#contractor option').remove();

    // リストをセット
    $.each(contractorList, function(key, value) {
        $('#contractor').append($('<option>').html(value).val(key));
    })
    $('.selectpicker').selectpicker('refresh');

    // 「全て」を初期設定・表示する
    setTimeout(function () {
        $('#contractor').val('9999');
        $('.selectpicker').selectpicker('refresh');
    }, 100);
}

```


### 参考


https://techplay.jp/column/548
【VB.NET、C#】ゼロ埋めする方法（ゼロパディング）

VB.NET、C#でゼロ埋めする方法です。

#ゼロ埋め（ゼロパディング）とは？
ゼロ埋めとは、数値を文字として表現する場合に、指定された桁数に足りない桁を0で埋める方法です。ゼロパディングとも言います。

- 5桁固定
- 入力：123
- ゼロ埋め→00123

パディングというのが、「詰め物」や「水増し」という意味です。
IT分野では固定長としてデータを扱う時に、不足分を無意味なデータで補う行為を指します。
ゼロで埋めるならゼロパディングですが、別にゼロで埋める必要はありません。

#ゼロ埋めの方法
ゼロ埋めする方法はいくつかあります。

- PadLeft
- ToString
- Format

どれでもいい…と言ってしまうと乱暴ですが、好みの問題です。
コーディング規約でパディングの方法が規定されている現場もあると思いますので、それぞれ知識として知っておいたら良いと思います。

#実行確認用テストフォーム
ゼロ埋め確認用のフォームを作成しました。
![20211223_001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/8f204898-30f0-cfd7-6078-f4258e403dce.jpeg)

1. 左側のテキストボックスに数字を入力
2. 実行ボタンをクリック
3. 右側にゼロ埋めされた結果を表示

実行するとこうなります。
![20211223_002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2162017/55fdd518-907e-3275-5aad-c3fd6ef61a46.jpeg)



PadLeft、ToString、Formatのソースコードは以下です。

##PadLeft
StringクラスのPadLeftメソッドを用いてゼロ埋めする方法。

```vb
'【VB.NET】
Private Sub btnPadLeft_Click(sender As Object, e As EventArgs) Handles btnPadLeft.Click
    'PadLeftで5桁ゼロ埋め
    txtPadLeftAfter.Text = txtPadLeftBefore.Text.PadLeft(5, "0"c)
End Sub
```

```c#
//【C#】
private void btnPadLeft_Click(object sender, EventArgs e)
{
    //PadLeftで5桁ゼロ埋め
    txtPadLeftAfter.Text = txtPadLeftBefore.Text.PadLeft(5, '0');
}
```

##ToString
ToStringでゼロ埋めする方法。

```vb
'【VB.NET】
Private Sub btnToString_Click(sender As Object, e As EventArgs) Handles btnToString.Click
    'Integer型の変数に確保（ToStringを使うため）
    Dim iNum As Integer = Integer.Parse(txtToStringBefore.Text)
    'ToStringで5桁ゼロ埋め
    txtToStringAfter.Text = iNum.ToString("00000")
End Sub
```

```c#
//【C#】
private void btnToString_Click(object sender, EventArgs e)
{
    //Integer型の変数に確保（ToStringを使うため）
    int iNum = Int32.Parse(txtToStringBefore.Text);
    //ToStringで5桁ゼロ埋め
    txtToStringAfter.Text = iNum.ToString("00000");
}
```

##Format
StringクラスのFormatメソッドでゼロ埋めする方法。

```vb
'【VB.NET】
Private Sub btnFormat_Click(sender As Object, e As EventArgs) Handles btnFormat.Click
    'Integer型の変数に確保（Formatを使うため）
    Dim iNum As Integer = Integer.Parse(txtFormatBefore.Text)
    'Formatで5桁ゼロ埋め
    txtFormatAfter.Text = String.Format("{0:D5}", iNum)
End Sub
```

```c#
//【C#】
private void btnFormat_Click(object sender, EventArgs e)
{
    //Integer型の変数に確保（Formatを使うため）
    int iNum = Int32.Parse(txtFormatBefore.Text);
    //Formatで5桁ゼロ埋め
    txtFormatAfter.Text = String.Format("{0:D5}", iNum);
}
```


#参考
https://e-words.jp/w/%E3%82%BC%E3%83%AD%E3%83%91%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0.html

https://wa3.i-3-i.info/word16138.html

https://docs.microsoft.com/ja-jp/dotnet/api/system.string.padleft?view=netcore-3.1

https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/how-to-pad-a-number-with-leading-zeros

https://www.curict.com/item/d1/d171ae3.html

https://stellacreate.com/entry/vbnet-padding

https://www.sejuku.net/blog/43140
仮想環境下でpip install mysqlclientしたらERROR: Failed building wheel for mysqlclientが出た

# 目的
djangoでアプリ作成するためのDBをsqliteではなく、人気のMySQLにしようとしてそのために必要なmysqlclientというドライバをインストールしようとしている。

# 結論

```
conda install -c anaconda mysql-connector-python
conda install -c bioconda mysqlclient
```
anacondaを利用しているなら、この処理が必要となるようだ
# 実施環境
### ハードウェア環境
| 項目 | 情報 |
|:-:|:-:|
| OS  |macOS Catalina(10.15.7)   |
|ハードウェア   |  MacBook Air (11-inch, Early 2015) |
|プロセッサ   | 1.6 GHz デュアルコアIntel Core i5|
|メモリ   |  4 GB 1600 MHz DDR3 |
|グラフィックス   |  intel HD Graphics 6000 1536 MB |
### ソフトウェア環境
| 項目 | 情報 |
|:-:|:-:|
| homebrew  | 3.3.8 |
| mysql | Ver 8.0.27 for macos10.15 on x86_64 |
| python  | 3.8.12 |
| django  | 3.1.2 |
| anaconda  | 4.10.1 |
| pip  | 21.2.4 |



# 経緯


```
pip install mysqlclient
```
でちょちょっとドライバ入れさせてもろて〜と思ってたら、赤文字でめっちゃ長いエラーがっっ、、、

```
・
・
・
Use `sudo xcode-select --switch path/to/Xcode.app` to specify the Xcode that you wish to use for command line developer tools, or use `xcode-select --install` to install the standalone command line developer tools.
  See `man xcode-select` for more details.
  error: command 'gcc' failed with exit status 1
  ----------------------------------------
  ERROR: Failed building wheel for mysqlclient
```
# 原因究明
長すぎるエラー文に尻もちをついて腰を痛めたが、じっくり下の方を見てみるとどうやらgccに問題があるような気がする。

```
npm install gcc
```
してみるもエラー文は変わらず、、。


# 解決
[このコメント](https://github.com/PyMySQL/mysqlclient/issues/74#issuecomment-487009666)を参考にしてみると
anacondaを利用している人はこの処理が必要となるよう。

```
conda install -c anaconda mysql-connector-python
conda install -c bioconda mysqlclient
```

できた！！！
Githubの知らなかった雑学一選

 
      
#雑学
GithubのRepositoriをDeleteすると、
「60 contributions in the last year」のactive graphの緑マスが消えます。
「Total Commits」回数が消えます。

#結論
詳細に言うと、
DeleteしたRepositoriのアクティブ時だったcontributions(緑マス)が消えます。
DeleteしたRepositoriのCommit回数が消えます。
QAのお仕事を楽しむ

QA業務に携わっていて楽しいと感じていることをいくつか記載してみようと思います。
自分の経験が元となり主にゲームQAでの話になってしまうため主観が強く偏りがある点や
各項目とも反面悩みもあったりしますが、この記事はあくまで楽しみの面にフォーカスしている点はご了承ください。


## いち早く製品、新機能に触れる
好奇心が強めな自分はQAに関わって一番最初に感じた点がこれでした。
毎回どんな物なのだろうとドキドキ・ワクワクしながら触っています


## 不具合を見つける/修正される
次はこちら、不具合はプログラマーさんも残したくて残しているわけじゃないですが
触っているとほぼ間違いなく見つかるものです。不具合を見つけた時や、
複雑な再現手順を確定させたときなど難易度の高いゲームをクリアしたかのような
達成感を得られる瞬間がたまりません。

またときには不具合だけでなく、感じたことや閃いたことを提案として提出し
その内容が反映されることもモノづくりの一員として更に貢献できたと感じ
嬉しくなる瞬間でもあります。


## ユーザーの反応
一番一喜一憂の部分ではあるのですが、製品がリリースされた後のユーザーからのポジティブな意見が
SNSや問い合わせ情報などから見えるのはいつでも嬉しくなります。
わざわざ長文でお礼のメッセージや、感動的な話を熱量高く伝えてくれるユーザーさんも
いたりして、頑張って良かったと感じつつ相手へも感謝の気持が芽生える瞬間です。


## テスト計画/設計/進捗管理/振り返り
ある程度QA業務に慣れてくると携わるこの業務、最初のうちこそ悩みのほうが多いのですが
数をこなしていくと、振り返る度に以前と比較してより早くより正確(緻密)にまたは取捨選択の妙等
良くなった点が何かしら見えやすいく自分の成長を殊更感じやすい業務かなと思っています。


## コミュニケーション(1on1含)
リーダー以上とは限りませんが、リーダー以上になってくると断然機会が多くなってくる
他者とのコミュニケーション。
中の良いチームメンバーを始め、関連部署の方や上司、協力会社や他社QAの方々など
様々な接点が増えて来るかと思います。
中には緊張するものもありますが、別の視野や視点/視座を理解する一助となることばかりですし
新たな考え方や知識等が入っていくることで物事を発展させていく種を貰え活力が生まれます。



## チーム/組織運営
チームメンバーとして一通りの業務に慣れた頃に自然と、もしくは毅然と目指しながら行き着くこちらは
チームや組織に向けて知見を共有したりプロセスやフローを整えたり、ときには共に働くメンバーを
増やしたり成長を促したり……

直接的な品質向上とは少し違う、より先の未来に向けてどうすべきかを考慮しながら
改善や新しいことに挑戦し進める業務は短期的に結果が見えるものではありませんが、
その分良い結果をチームや組織単位で達成できたときにの達成感とても大きいものと感じています。


## 最後に
大枠の業務内容について感じていることを触れてみましたが
深堀りすればもっともっと数多くの楽しみがありますし、各々でポイントが異なると思います。
思い浮かばない人も、もっと色々浮かんでいる人も機会を設けて周りの人と
QAの楽しみを語り合ってみると想像していなかった観点の発見やモチベーションの向上に
繋がるのではないでしょうか。
この記事を読んでいただいた方々含め、これからもQAを楽しんでいければ幸いです。
BigQuery備忘録 : 直近1年を取得するユーザー定義関数(日本時間)

【BigQuery備忘録 : 直近1年を取得】

```
create temp function start_datesuffix() as (
  format_date('%Y%m%d',date_sub(date(current_timestamp,'Asia/Tokyo'),interval 1 year))
);

create temp function end_datesuffix() as (
  format_date('%Y%m%d',date(current_timestamp,'Asia/Tokyo'))
);
```
非ＩＴ企業に勤めているＩＴエンジニアの次なるステップアップ

　ITエンジニアたるもの、プログラムなどは出来て当たり前。さらにＩＴ企業に勤めれば、いろんな仕事にかかわって必要なスキルは磨かれるだろう。はたまた、理系の学生さんでＩＴを学び、そこそこの知識を得て企業勤めしているのであれば、すでにベースは出来ていて、いざという時の相談相手を作るすべも知っている。
　しかしながら、非ＩＴ企業に勤めているＩＴエンジニアはどうだろうか？　周囲を見渡してみても、ＩＴに関して会話できる人は皆無。そんな貴方は、まさに孤独との闘いである。この記事は、私のように非ＩＴ企業でＩＴエンジニアになりたいと、一念発起した方に何らかの参考にしていただければと思う。

# 情報源
　やはり典型的なサラリーマンなので、会社帰りの本屋のＩＴコーナが定番の寄り道かつ、情報源にはなりうる。もしくは、図書館のプログラムコーナだろう（しかし、はっきり言って、この情報を元に独学するのは、はっきり言えば修行僧並みに厳しいといえる。）
　同じような観点で、プログラム系の雑誌が定期購読も可能であるが、これも対象者が初級、上級で好みの分かれるところ。最初に買った雑誌でも、ちんぷんかんぷんな状態で、理解するのに数年かかるというケースも多々ある。

#SNS
　最近になってTWITTERはかなり便利だと思うようになった。特にお気に入りのフォロワーさんを追いかけると、その人のコメントや感想を元にして、情報を判断することが出来るようになる。他にもFACEBOOKなどもあるが、やはり個人視点で非力さを感じる人は、多勢を相手にせず、一人のエンジニアをメンターにした方が良い。

#ITブログ、質問サイト
　プログラミングがある程度できるようになると、QiitaやTeratailなどに、質問してある程度、ぶつかった壁には対処できるようになる。また他人の記事などを調べればソコソコ参考にはなるだろう。しかしながら、不特定の他人との距離は、縮めるきっかけにはならない。

#交流会
　少し人とITで交われるようになったら、やはり人と交流した方がいい。Compass,docker hubなどの集まりに参加して、最近はリモートで顔を合わさないケースもあるが、少なくとも人と知り合うことは、重要である。

#技術資料
　書籍で得られる情報にしても、結局は一定の閾値を超えないと世の中には出てこない。そんな時は、もっと手前の同人誌、技術書などが宝のありかかもしれない。またエンジニアがスライドショーを作っている場合は、情報源としては価値が高い。

　いま私は、下記の記事を読んで、今後の方向性を物色している
https://hr-tech-lab.lapras.com/knowhow/speakerdeck/

#結論
　○○で○○している人。結局はごく一部の人が、情報を握っている。
　そういう神様人材とのコネクションが今後は重要になってくる（自分も、いつか神様と呼ばれたいところである）

#参考
　いま機械学習で注目している方。

　Ｍ３　https://speakerdeck.com/nishiba

このリストは、今後継続して更新していきたいと思う。