OmniAICreator/Qiita-1.07M huggingface dataset:
AWSの一時クレデンシャルを使ってAWSコンソールにアクセスする方法

## はじめに

AWSへのアクセス管理のためにAWS SSOを導入している場合など、IAMロールベースで複数のAWSアカウントを運用するシチュエーションでは、スイッチロールの起点となるAWSアカウントをあまり増やしたくないなどの課題から、[ロール連鎖](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_terms-and-concepts.html)の形で権限を振り出す運用方法を取りたい場合があります。
しかし、ロール連鎖で得た権限を扱う際の実運用上の大きな問題として、AWSコンソールがロール連鎖のスイッチロールに対応していない、という点があります。
APIベースではロール連鎖に対応しているので、AWS CLIなどで一時クレデンシャルベースでAssumeRoleしていけば、最終的に目的のIAMロールの一時クレデンシャルを得ることは可能ではありますが、AWSに対する操作を行ううえで、すべてCLIなどで賄うのは大分つらいものがあります。

幸いAWSは、一時クレデンシャルを元に、そのクレデンシャルの権限でコンソール操作を行えるAWSコンソールのログイン用URLを生成するための仕組み及び利用手順を[ドキュメント](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html)で公開しています。
が、その利用手順の中には、エンドポイントにリクエストを送って受け取った値の中身を再度エンドポイントにリクエストする、であったり、エンドポイントのURLに付けるパラメータをURLエンコードしておく必要があったり、と地味に面倒な部分があります。

本記事は、その面倒さをサクっと軽減するシェルスクリプトを書いたので、そのシェルの紹介をするものになります。
シェルの機能としては、「一時クレデンシャルを渡すとAWSコンソールのログイン用URLを返してくれる」というものになります。
ブラウザで、生成されたログイン用URLへアクセスすれば、そのままAWSコンソールへアクセスでき、権限を得た状態でAWSコンソール上での操作を行うことができます。


## 作ったものと解説
作成したシェルスクリプトは以下になります。 (`nkf`や`jq`などが必要です)
<details><summary>シェルスクリプト</summary><div>

```bash
#!/bin/bash

function urlencode {
  echo "$1" | nkf -WwMQ | sed 's/=$//g' | tr = % | tr -d '\n'
}

echo "access key IDを入力してください"
read sessionId
echo "secret access keyを入力してください"
read sessionKey
echo "sessionTokenを入力してください"
read sessionToken

encodedSessionId=$(urlencode $sessionId)
encodedSessionKey=$(urlencode $sessionKey)
encodedSessionToken=$(urlencode $sessionToken)

SigninToken=$(curl "https://signin.aws.amazon.com/federation?Action=getSigninToken&Session=%7B%22sessionId%22%3A+%22${encodedSessionId}%22%2C+%22sessionKey%22%3A+%22${encodedSessionKey}%22%2C+%22sessionToken%22%3A+%22${encodedSessionToken}%22%7D" | jq .SigninToken -r)

echo "https://signin.aws.amazon.com/federation?Action=login&Issuer=https%3A%2F%2Floginurlgeneratepage.yourcompany.com&Destination=https%3A%2F%2Fconsole.aws.amazon.com%2F&SigninToken=${SigninToken}"
```

</div></details>

流れとしては、まず一時クレデンシャルをユーザーから対話的に受け取ります。
次に、一時クレデンシャルをAWSフェデレーションエンドポイントに`getSigninToken`アクションを指定してリクエストすることで、レスポンスとして`SigninToken`を受け取ります。
最後に、受け取った`SigninToken`を元にAWSコンソールにアクセスするURLを組み立て、echoで標準出力する、というものになっています。

フェデレーションエンドポイントに引き渡すパラメータはURLエンコードが必要なので、[参考URLに載せたfunction](https://qiita.com/ik-fib/items/cc983ca34600c2d633d5)を流用させていただいています。

また、最終的なログイン用URLのパラメータについて。
`Destination`は認証情報の受け渡し先を示すパラメータで、つまりAWSコンソールへのサインインである、ということを示すためのものなので、URLエンコードされたAWSコンソールのURLを渡せばよい、ということになります。
`Issuer`は認証情報の発行者を示すパラメータです。AWSのドキュメントにも`the form-urlencoded URL for your internal sign-in page`とあるように、このAWSコンソールログイン用URLの生成をWebベースのアプリケーションの機能として提供するような場合に、そのアプリケーションのURLを指定しておけるものです。
(今回のように、個々のユーザーの手元においてシェルベースなどでURL生成を行う場合は、`Issuer`としては任意の値を指定すればよいです。)
`Issuer`にURLエンコードされたURL文字列を指定することで、例えばセッション有効期限切れページ内に、以下画像のようにリンクが表示されるようになります。
![スクリーンショット 2022-08-04 205923.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/375883/f69ba6fa-fc5b-091b-f760-ceb542c2a4f5.png)




## 参考URL
https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html

https://qiita.com/ik-fib/items/cc983ca34600c2d633d5
CMake で install の RPATH 設定を相対にやりたいメモ(Linux)

```
build/bin/myapp  # libmyapp.so と絶対パスでリンクしている
build/lib/libmyapp.so
```

みたいなケースで, install して

```
dist/bin/myapp
dist/lib/libmyapp.so
```

のようになると libmyapp.so へのリンクが絶対パスなので
cmake で install すると .so のリンクが not found になる...

Linux を考えます. 
また, build 時と install 時でディレクトリの構成は変わらないものとします.

## 再現 repo

再現テスト用の repo を作りました.

https://github.com/syoyo/cmake-rpath-experiment

## 原因

デフォルトでは, ビルド時は `RPATH` (runtime) が使われ, インストール時は RPATH なしで処理されます.

https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling

そのため, install すると RPATH のパスが空になり, binary と .so でディレクトリを分けている場合 .so not found になります.

また, build 時も基本は絶対パスでのリンクになっていますので, build フォルダをコピーして install 相当にして対応というのもできないです.

## 解決方法(絶対パス)　

https://dev.my-gate.net/2021/08/04/understanding-rpath-with-cmake/


構成にもよりますが, 最低限 `CMAKE_INSTALL_RPATH` を設定すればよいようです.

```
cmake_minimum_required(VERSION 3.16)
  
  project(MyApp C CXX)
  
  set(LIB_SOURCES mylib.cc)
  
  set(CMAKE_SKIP_BUILD_RPATH FALSE)
  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
  set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
  
  add_library(mylib SHARED ${LIB_SOURCES})
  
  set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
    set_target_properties(mylib PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
  )
  install(TARGETS mylib LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
  
  add_executable(myapp myapp.cc)
  target_link_libraries(myapp PRIVATE mylib)
  
  install(TARGETS myapp RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
```

Install 時, ログに

```
Set runtime path of "/home/syoyo/work/cmake-rpath-experiment/dist/lib/libmylib.so" to "/home/syoyo/work/cmake-rpath-experiment/dist/lib"
```

のようになってきちんと runtime path 処理されているのを確認しましょう.

## ORIGIN で相対パスにする(推奨)

上記だとしかしインストールディレクトリでの絶対パスで処理されるため, さらにインストールディレクトリを移動したりしたときは .so が見つからなくなります.

より汎用には, `$ORIGIN` を利用して相対にするのが推奨でしょう.

https://www.semipol.de/posts/2012/02/relative-rpath-settings-with-cmake/

```
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib"
```

(↑のリンクにあるように, `CMAKE_INSTALL_RPATH` でグローバルではなく target の property で設定するのが推奨ではある)

`$ORIGIN` 利用だと以下のような感じになりました.

```
libmylib.so => /home/syoyo/work/cmake-rpath-experiment/dist/bin/./../lib/libmylib.so (0x00007f3a3e266000)
```

ただ, ビルド構成によっては `/path/to/bin/../bin/../lib` みたいなややこしいパスになってしまうようですので, 単に `../lib` でもいいかもしれません.

```
set(CMAKE_INSTALL_RPATH "../lib")
```

```
libmylib.so => ../lib/libmylib.so
```
【Laravel】中間テーブルのcreated_atだけに値を入れる方法

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## 前提

中間テーブルのidやcreated_atに値が入らない状態で、updated_atには値を入れたくない（カラムが存在しないため）とき

## 解決法

各モデルでリレーションを定義するとき、```withPivot```で渡したいカラムを入れる。
これで```created_at```がちゃんと保存されるようになる。

```php

# group model
public function userGroups(): BelongsToMany
{
    return $this->belongsToMany(UserGroup::class)
                ->withPivot('id', 'group_id', 'user_id', 'user_group_id', 'created_at');
}

# user model
public function userGroups(): BelongsToMany
{
    return $this->belongsToMany(UserGroup::class)
                ->withPivot('id', 'user_group_id', 'group_id', 'user_id', 'created_at');
}

# user-group model
public function users(): BelongsToMany
{
    return $this->belongsToMany(User::class)->withPivot('id', 'group_id', 'user_id', 'user_group_id');
}

public function groups(): BelongsToMany
{
    return $this->belongsToMany(Group::class)->withPivot('id', 'group_id', 'user_id', 'user_group_id');
}
```

## ちなみに
```created_at``` ```updated_at```両方とも値を持たせたい場合は下記でオッケー。

```php
return $this->belongsToMany(User::class)->withTimestamps();
```

https://readouble.com/laravel/8.x/ja/eloquent-relationships.html?header=pivot%60%25E5%25B1%259E%25E6%2580%25A7%25E5%2590%258D%25E3%2581%25AE%25E3%2582%25AB%25E3%2582%25B9%25E3%2582%25BF%25E3%2583%259E%25E3%2582%25A4%25E3%2582%25BA

## 参考

https://qiita.com/fagai/items/02f0c95b1deaf73a9c5a
Webサイトを作る際に超参考になったデザインのサイトまとめ

## はじめに
仕事でWebサイトを作った際に、
デザイン案で非常に参考にさせて頂いたサイト様をまとめました。


## Parts.
SaaSのサービスサイトやLPを中心としたデザインの参考サイトです。
部分ごとにパーツやセクションごとのデザインが載っているので、
探しやすくとても参考になりました。

https://partsdesign.net/mainvisual

## 動くWebデザインアイディア帳
「動かしたいパーツ」ごとの逆引きリストを扱っているサイトです。
機能的 or 印象的で有効なデザインが多数載っており参考になりました。

※注意として
>動くWebデザインアイデア帳のサイトは、書籍に明記している通り「3年間の期限付き」です。
（※書籍の売れ行き次第で変わります。）

ちなみに実践編の方ですが、私も書籍を購入させて頂きました。

https://coco-factory.jp/ugokuweb/

## Web Design Trends(ウェブデザイントレンド)
>Webに関わる全ての人のためのメディアです。ウェブサイトの制作やデザインに役立つ情報、最新トレンド、チェックすべきサービスなどを配信しています。

すでにご存じの方も多いかと思いますが、
ウェブサイトの制作やデザインに役立つ情報を発信してくださっているサイトです。
トレンドや細かなテクニックが参考になりました。

https://webdesign-trends.net/entry/13228

## MUUUUU.ORG（ムーオルグ）
>後発ならではの見やすさ、使いやすさ、載って嬉しいギャラリーサイトを目指して運営している、非営利目的のWEBデザインポータルサイトです。
情報設計の参考にしやすく、現場レベルでWEBデザイナーが参考にし易いであろう、
縦に長くオーソドックスなレイアウトでかつ、非常にデザインが優れたサイトを厳選して掲載しております。

思わず感心してしまう厳選されたオシャレなサイトが閲覧できます。ポートフォリオなどの作品の参考にもできると思います。

https://muuuuu.org/category/taglist/parallax

## SANKOU!
国内のサイトを集めたギャラリー･リンク集のサイトです。
ビジュアルやコンテンツが魅力的やUI/UXに優れているサイトがご紹介されています。

https://sankoudesign.com/

## 実は知られていない、人の心理を考慮した料金表のデザイン
https://blog.studio.design/posts/pricing-interfaces-design

こちらの記事の翻訳記事なのですが、
料金表のデザイン案について、個人的にとても為になりました。


https://blog.studio.design/ja/posts/pricing-interfaces-design-jp
Tips: RubyでURLのクエリパラメータをいい感じに書き換える

## これは何
- RubyでURLのクエリパラメータを書き換える方法がちゃんとまとまっているところがなかったので、まとめたものです
- 実装するので、よかったら使ってください

## RubyでURLのクエリパラメータを書き換える時の問題点
RubyでURLのクエリパラメータを書き換える場合、`URI`モジュールを使うことが多いのではないでしょうか。

```rb:例
uri = URI('https://example.com')
uri.query = 'a=1'
uri.to_s #=> "https://example.com?a=1"
```

しかし、これだと以下のような問題が発生します。

### クエリパラメータがすでに付与されている場合、上書きをしてしまう
クエリパラメータが初めから付与されている場合、このような実装だと上書きをしてしまい、情報が欠損してしまいます。

```rb:例
uri = URI('https://example.com?b=1')
uri.query = 'a=1'
uri.to_s #=> "https://example.com?a=1"
```

### 付与したいクエリパラメータと同じパラメータがすでに付与されていると、重複して付与されてしまう　
上書きをしてしまう問題を解決するため、以下のような実装をしたとします。

```rb:例
uri = URI('https://example.com?b=1')
uri.query += '&a=1'
uri.to_s #=> "https://example.com?b=1&a=1"
```

これで一件落着したように見えますが、この実装はまた別の問題が発生します。
問題が発生するのは付与したいクエリパラメータと同じパラメータがすでに付与されている時です。
本来は既存のクエリパラメータの値を更新するのが正しいのに、重複して付与される状態になってしまいます。

```rb:例
uri = URI('https://example.com?a=2')
uri.query += '&a=1'
uri.to_s #=> "https://example.com?a=2&a=1"
```


## RubyでURLのクエリパラメータをいい感じに書き換える
Rubyで以下のような条件でURLのクエリパラメータを書き換えたい場合を考えます。

- すでに付与されているクエリパラメータはそのまま残す
- 新しく設定したいクエリパラメータがすでに付与されている場合は、追加の代わりに更新をする

このような実装を実現するのが以下のメソッドです。

```rb
def create_link_url(url)
  uri = URI(url)
  query = URI.decode_www_form(uri.query.to_s).to_h
  query['a'] = '1'
  uri.query = URI.encode_www_form(query)
  uri.to_s
end
```

このような実装をすることで、クエリパラメータのURLをいい感じに書き換えられます。

## 最後に
もし僕に興味を持っていただいた方がいらっしゃったら、ぜひDevトークから「話したい」をお願いします！

https://jobs.qiita.com/employers/qiita-inc/dev_talks/27
新卒ITエンジニア4ヶ月間の知識量


# はじめに
今回は、私が大学卒業後に新卒入社したIT企業で学んできた事を洗い出す目的で記事に残していきます。

入社前の技術レベルは
- HTML/CSS　プロゲートの無料コースを学んだレベル
- JavaScript(VanilaJS)/Node.js
- PHP(Laravel)  echoを使えるレベル

成果物としては、HTML/CSSのみで作ったポートフォリオ。
就活時代、ポートフォリオを出す必要があったのですが、無事低レベル過ぎて書類審査も通らず苦労しました(笑)
エンジニアというより、デザイナーみたいな学習内容ですね(笑)
このようなレベル感から現在何をしているのかを紹介していきます。
## 新人研修
私の会社の新人研修は広く浅く色々な事を知って知見を増やしてほしいという目的で進められていきました。
- HTML/CSS
- Javascript/React.js
- Ruby(環境構築)/ネットワーク
- Git/GitHub
- SQL/DB
- UML
- Java(オブジェクト指向）/RESTAPI
- 開発ライフサイクル（要件定義、設計、開発、運用、保守）

箇条書きすると、これらを学びました。
この時点で苦手だったこと
苦手分野：ネットワークのHTTP通信、Dockerの理解、非同期処理

## 配属後
- バックエンド：Nest.js/GraphQL/TypeScript
- フロントエンド：Vue.js/Nuxt.js/React.js/TypeScript
## おわりに
今年の4月に新卒入社して早い事４か月が経過しました。
感想としては、まだまだ技術が身についたという実感もなければ一人で仕事ができるような気もしない。だが、地道に勉強を続けて一刻でも早く先輩社員に追いつきたいと思う。

最後に、最近学んだ技術を箇条書きして終わりにしたいと思います。
- JSの分割代入
- スプレッド構文で作るイミュータブルなオブジェクト
- interfaceの理解
- typeORMとprismaの違い

未来の自分へ、入社後4か月間はこのような事を学んでたよー
以上になります。最後まで読んでくれた方はありがとうございます！
【Laravel】timestamps()実行後、updated_atのみ削除する方法

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## 前提
最初のマイグレーション時の
```
$table->timestamps();
```

で```created_at```と```updated_at```カラムが入っている状態。
```updated_at```カラムが不要になったので削除したい。


## 方法
新たなマイグレーションファイルを作成して、下記でマイグレーション実行する。
downメソッドも書き忘れずに！
```php
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropColumn('updated_at');
        });
    }

    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->timestamp('updated_at');
        }
    }
```

https://pisuke-code.com/laravel-disable-timestamps/
【Laravel】401エラーでリダイレクトせずに任意のメッセージを返す方法

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## 前提
401エラー時に、```middleware auth```がログインのエンドポイントにリダイレクトするようになっているのを

```
{
  "message" => "Unauthorized"
}
```
と返ってくるようにしたい。


## 方法
```Handler```に下記を追記。
```AuthenticationException```の```unauthenticated```メソッドをオーバーライドする。
これでやりたいエラーメッセージの形と401コードを返してくれる。

```app/Exceptions/Handler.php
  use Illuminate\Auth\AuthenticationException;

  protected function unauthenticated($request, AuthenticationException $e): JsonResponse
  {
    $errorMessage = [
      'message' => "Unauthorized",
    ];

    return (new ErrorResource($errorMessage))->response()->setStatusCode(401);
  }
```

```ErrorResource```を使ってエラーレスポンスを統一した記事は↓

https://qiita.com/kat0/items/6e925e2d365a28588a19

## 参考

https://qiita.com/fuubit/items/fea41e173fa1bdf70736
Pythonが嫌いなのでC++版のPytorchで画像認識をやってみる 5日目

# module.hは後回し
またまた時間が経ってしまった。毎日更新とはいかないな。今日は大雨で大変だった。家の前の道路が冠水しとる。それはともかくforward関数がどうやって呼び出されるのかソースでは俄かに分かりそうにない。exeが走るようになったらデバッガで調べてやろう。ということで「どうやって呼び出されるか問題」は後回し。

# forward関数とは何ぞや
"must override"とmodule.hに書いてあるのでコンストラクタに匹敵する重要な関数なのだろう。ニューラルネットのクラスなので大体想像つくが調べることにする。[公式ドキュメント](https://pytorch.org/docs/stable/generated/torch.nn.Module.html?highlight=forward#torch.nn.Module.forward)にはこう書いてある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464633/7ab8f4d7-f618-119c-1275-ee8f0e8ed012.png)
「すべての呼び出しで実行される計算を定義します。すべてのサブクラスでオーバーライドする必要があります。
ノート:フォワード パスのレシピはこの関数内で定義する必要がありますが、後でこれの代わりに Moduleインスタンスを呼び出す必要があります。前者は登録されたフックの実行を処理し、後者は静かにそれらを無視するためです。」
分かりにくい英語だが、名前から想像つくようにニューラルネットのforward処理を定義する関数ということだろう。昭和のおじさんはこれでも大学でAIを習ったのだ。30年前だが。当時はパーセプトロンと言ってせいぜい入力層、中間層、出力層の3つの層しかなかったけどね。AIの説明はここが分かりやすかったので載せておく。https://www.hpc.co.jp/library/commentary/aboutdeeplearning/
```c++:
torch::Tensor forward(torch::Tensor input);
```
引数のinputは入力層に入れるテンソルで間違いなさそうだが、torch::Tensorがポインタ(ポインタ定義をオーバーライドした型)なのかインスタンスなのか気になるなあ。[公式ドキュメント](https://pytorch.org/cppdocs/api/classat_1_1_tensor.html)にはこう書いてあるので、インスタンス型でいいようだ。名前空間が違うのが気になるがいくら検索してもtorch::Tensorというのは出てこないので何か謎の仕組みでオーバーライドされているのかもしれない。これもexeができたらデバッガで調べよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/464633/bb8d76e0-6f4c-b2ef-9cdc-d354c5f9be11.png)

# 謎の構文
modele.hに戻って続きを読んでいくと、謎の構文が現れる。なんとclass定義の中でメンバ変数が初期化されている。そんなんアリか・・・
```c++:modele.h
    private:
    Conv2d conv1 = nullptr;
    BatchNorm2d bn1 = nullptr;
```
まあ意味は分かるが、nullptrはヌルポか。とするとConv2dというのはポインタ型? けどmodele.cppのコンストラクタの中では普通に代入処理が行われている。何がどうなっているのか。
```c++:modele.cpp
 conv1 = Conv2d(Conv2dOptions(in_channels, width, {1, 1}).stride(1).bias(false));
```
[C++のドキュメント](https://cpprefjp.github.io/lang/cpp11/nullptr.html#:~:text=nullptr%20%E3%81%AF%E3%80%81%E3%83%8C%E3%83%AB%E3%83%9D%E3%82%A4%E3%83%B3%E3%82%BF%E5%80%A4,%E8%A1%A8%E3%81%99%E3%81%93%E3%81%A8%E3%82%92%E6%8E%A8%E5%A5%A8%E3%81%99%E3%82%8B%E3%80%82)によるとnullptrはまさしくヌルポらしい。サンプルコードもまさしくポインタである。
```c++:C++のドキュメント
  int* p = nullptr;
```
しかしconv1がポインタなら↓こんな文はあり得ない。
```c++:
 Conv2d conv1 = nullptr;
 conv1 = Conv2d(Conv2dOptions(in_channels, width, {1, 1}).stride(1).bias(false));
```
conv1がポインタなら↓こう書かないとダメなはずだ。
```c++:
 Conv2d conv1 = nullptr;
 conv1 = new Conv2d(Conv2dOptions(in_channels, width, {1, 1}).stride(1).bias(false));
```
明日調べよう。疲れたので今日はここまで。
つづく

https://qiita.com/pipimaru1/items/ff7c868ff798cbbe88b5
アジャイルにおける心理的安全性を考えてみた

### ここで言う「心理的安全性」とは

「心理的安全性」でググると

>「チームメンバーに非難される不安を感じることなく、安心して自身の意見を伝えることができる状態」

https://research.lightworks.co.jp/psychological-safety 

ふむふむ


>「チームは、対人関係のリスクをとっても安全な場所であるとの信念がメンバー間に共有された状態である。」

https://achievement-hrs.co.jp/ritori/psychological-safty/

ええ、ええ

「心理的安全性」というワードは一見とてもわかりやすい日本語なのですが、上記のようにニュアンスのブレがあったり多要素なので、向き合えば向き合うほどわかり辛くなってくるように感じています。

先日たまたま「建設的な衝突」というキーワードを目にし、それすなわち心理的安全性が担保されている状態（仲良しグループから一歩進んだ状態）だなぁと連想したのですが、上記引用で「非難される不安を感じることなく〜」「自分の考えを自由に〜」「対人関係のリスクをとっても〜」と書かれているところを見ても、心理的安全性なくして「建設的な衝突」は生まれづらいと言えそうです。

今回ここで言う「心理的安全性」とは、上記の通り、保守的な仲良しグループを卒業し、リスクを取りつつも建設的なコミュニケーションを取れるレベルのものを指しています。

### どうなると建設的じゃなくなるか
さて、どんなときでも建設的に議論できるチームは理想ですしそうしたいのは山々なのですが、実際には「心理的安全性の高い状態を目指している」チームが世の大半だろうと想像しますし、達成しても維持できるかどうかはまた別の話で。どの状況においても「心理的安全性は担保されていない」と考えたほうが良さそうだなと。

では、心理的安全性が高く建設的なコミュニケーションを得るためにはどうすれば良いのでしょうか。

ここで思い浮かんだのが「鶏と卵」の話。
「問いかけの作法」というとても好きな本があるのですが、その著者である安斎勇樹さんの、とても好きなくだりがあります。
>僕は「それってどうやるんですか？　いつ誰がやってくれるんですか？」ということに問題意識を持ちました。考え方を変えて、心理的安全性が高いから意見が出るのか、意見が出るから心理的安全性が高まるのか。これは、いわゆる「鶏と卵」の関係性だと思うんですよね。
>そこで『問いかけの作法』は、問いかけを変えて意見が出てきやすい会議をやっていくうちに、「気付いたら心理的安全性が高まっていました」というシナリオを目指して、1つの処方箋として書きました。そのほうが建設的なんじゃないかと思ったので。

https://logmi.jp/business/articles/326587

これに私のバイアスを掛けると「安全が大事、安全が大事、言うてるけれども、じゃあそれは一体誰が作るんです？あなた自身ですよ」という話ですね。「心理的安全性が低いと建設的に話せない」ではなく「建設的に話して心理的安全性を高めていこう」と考えれると、次に「ではどうすれば建設的に話せるのか」と、前に進むことができそうです。

が、しかし！建設的であることをどうやって形成するかを考えたものの、非常に沢山の要素がありそうでしたので、すぐに断念。そこで逆から攻めてみました。「どうなると建設的じゃなくなるか」「なぜ感情的な議論や衝突が起きるのか」ですね。
いろんなケースが頭に浮かびましたが、やはり共通して「イライラする」はかならずセットで付いてくる気がします。ではそのイライラはどこから生まれてくるのでしょうか。

最初に浮かんだのは「利害関係」。そもそも利害が一致していれば、自然とゴールに向かって団結できるのではないかなと。逆に利害が一致していないと、当然対立しやすいですし、どれだけそれが正論であっても受け入れがたく反発心も産まれますよね。

ただ、ここで例外に気づきます。それは「合意の有無」です。

### 合意形成の重要性
仮に利害が一致していなくても「メンバーが望まない方向になぜ進む必要があるのか」をきちんと説明し了承を得れば、メンバーのほうでも望みの形が変わる可能性もありますし、進行後に余計なフラストレーションを抱えにくくなります。

逆に、チームメンバーとの合意をスキップして推進すれば、当然そのメンバーは意見を反映する機会を失い主体性を損なう要因になります。体制がトップダウンであれば「上からの指示」として渋々でも納得できる部分もありますし関係性もあるので衝突しづらいでしょうが、自律性を求められるアジャイルでフラットな関係性の中、メンバーに対し合意のない一方的な方針説明があり、且つメンバーの望まない影響があるとなると、そりゃ衝突しやすくて当然ですよね。


すなわち、<b>アジャイルに置いて「合意形成」というのは「心理的安全性に大きく影響する重要作業」</b>ではないかなと。合意形成の軽視が主体性や自律の重視と矛盾することをしっかりと覚えておきたいです。

ついでに、合意形成をどこまで細かくやる必要があるかについても考えてみました。
これもケースバイケースだと思いますが、その時に意識するのは「利害関係」や相手に与える「影響度」ですかね。合意したその判断によってメンバーがその程度影響を受けるかを考慮し、その影響度に応じた説明から合意を得る必要があるという話ですが、タイミングを計るのにも判断コストが掛かるので、細々と進捗するものについてはノイズにならない程度にテキストで逐一状況共有しておいて損はないかもしれません。小まめな共有意識はスムーズな合意形成の種になったりするので。

### 仲良しグループの正体
最後に、期待する状態のことを先に語っても確かに引っ張られる部分はありますが（心理的安全性を意識すればそれなりに心理的安全性が高まる）、メンバーの心理に気を配れないようだと結局は心理的安全性が低下する場面が発生するわけで、これが「表面的には心理的安全性の高い状態 ＝ 仲良しグループ」の正体なのかなと、これを書きながらそう感じました。私が思っていた「アジャイルにおける心理的安全性」というのは、意外なほどに泥臭く、一人一人が効率的かつ積極的にコミュニケーションをとりつつも気配りや配慮を丁寧に行う事で初めて成り立つものなのかもしれません。
三角関数「福岡大学2008年2月11日（理・工・医・薬）第１問(3)」をwolframalphaとsympy でやってみたい。

以下。怪しいです。教えて下さい。replace(sin(Θ),tan(Θ)*cos(Θ))

オリジナル
cos(Θ)**2,sin(2*Θ)---> tan(Θ)

https://mathmathmass.exblog.jp/32123558/

大学入試数学問題集成＞

https://mathexamtest.web.fc2.com/2008/200816071/2008160710800mj.html#top-0803

# wolframalphaで

https://www.wolframalpha.com/input?i=cos%28%CE%98%29%5E2&lang=ja

https://www.wolframalpha.com/input?i=sin%282%CE%98%29&lang=ja

# sympyで（Pycharmで)ベストに近い手順でやってみたい。


```python
from sympy import *
from sympy.simplify.fu import TR11
from sympy.simplify.fu import TR16
var('Θ t')
a1=cos(Θ)**2
a2=1/TR16(1/a1).replace(tan(Θ),t)
print("#",a1,"=",a1.replace(tan(Θ),t))
print("#",a1,"=",a2)
b1=sin(2*Θ)
b2=TR11(b1).replace(sin(Θ),tan(Θ)*cos(Θ)).replace(a1,a2).replace(tan(Θ),t)
print("#",b1,"=",b1.replace(tan(Θ),t))
print("#",b1,"=",b2)
# cos(Θ)**2 = cos(Θ)**2
# cos(Θ)**2 = 1/(t**2 + 1)
# sin(2*Θ) = sin(2*Θ)
# sin(2*Θ) = 2*t/(t**2 + 1)
```

# sympyで（live.sympyで)

Θをxに置換えました。貼り付けて,実行できます。(Θは実行できません）
Evaluateです。

https://live.sympy.org/

```python
from sympy import *
from sympy.simplify.fu import TR11
from sympy.simplify.fu import TR16
var('x t')
a1=cos(x)**2
a2=1/TR16(1/a1).replace(tan(x),t)
print("#",a1,"=",a1.replace(tan(x),t))
print("#",a1,"=",a2)
b1=sin(2*x)
b2=TR11(b1).replace(sin(x),tan(x)*cos(x)).replace(a1,a2).replace(tan(x),t)
print("#",b1,"=",b1.replace(tan(x),t))
print("#",b1,"=",b2)
```
live.sympyの実行結果
```
('#', cos(x)**2, '=', cos(x)**2)
('#', cos(x)**2, '=', 1/(t**2 + 1))
('#', sin(2*x), '=', sin(2*x))
('#', sin(2*x), '=', 2*t/(t**2 + 1))
```


# 参考

TR16,TR11

https://docs.sympy.org/dev/modules/simplify/fu.html#sympy.simplify.fu.TR0

https://qiita.com/mrrclb48z/items/fa4c295cf877206889e6

https://www.researchgate.net/publication/2356933_TRIGSIMP_A_REDUCE_Package_for_the_Simplification_and_Factorization_of_Trigonometric_and_Hyperbolic_Functions
【VSCode】VSCodeでExcelVBAを何とかするための拡張機能を作りました

# 概要

VSCode拡張機能 **Barretta** を作成しました。

https://marketplace.visualstudio.com/items?itemName=Mikoshiba-Kyu.vscode-barretta


Visual Studio Code でのVBA編集サポーターとして、Excelファイルとの連携を各コマンドより行うことができます。
GoogleAppsScriptにおける **clasp**(留め金)に対して、ExcelVBAにおける **Barretta**(髪留め) となりました。

# なぜ作ったか

VBAに対しても、claspのようなものがないものかと思っていました。
最近、XVBAというVSCode拡張機能を使ってみて何となく可能性のようなものを感じました。
XVBAの作者の方にお手伝いさせてくれないかとコンタクトを試みましたが、
開発自体が止まっているようなので、自力で作ることを選択しました。
(なお、XVBAのソースも拝見させていただきましたがレベルが高すぎて参考になりませんでした…C#とかも使っているっぽい)

現時点での開発はPhase1とし、モジュールの入出力とマクロの起動のみ対応しました。
一応のclasp相当にはなったと思われます。
Phase2ではVBAの言語機能としてVSCode LanguageServerまわりの実装を行う予定です。
Phase3ではソースコードを公開し、そこからは有識者を巻き込んだ開発に移行できればと思っています。

# 大まかな機能

基本的にはコマンドベースの拡張機能です。

![commands_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219708/806c647d-7b58-639e-974a-51aa16160a32.gif)

`Barretta:` から始まる4種のコマンドがあります。

* **Barretta: Init** (SC : Alt + Ctrl + N)
    
    対象のフォルダをBarrettaプロジェクトとして初期化し以下の構成を行います。
    
    * /barretta-core
    * /code-modules
    * /excel_file
    * .gitignore
    * barretta.code-workspace
    * barretta-launcher.json

    初期化したフォルダをBarrettaプロジェクトフォルダと定義します。
    excel_fileフォルダには単一のxlsmファイルを格納することができます。
    `.gitignore` はテンプレートとして `excel_file` フォルダのみ除外する状態です。
    `barretta.code-workspace` はbasやclsファイルに言語設定 `vb` を付与しています。
    そのため、上記のworkspaceを開いて作業することが推奨されます。

* **Barretta: Push** (SC : Alt + Ctrl + I)
* **Barretta: Pull** (SC : Alt + Ctrl + E)

    それぞれ、`code_modules` 内のVBAモジュールファイルを対象のExcelファイルにインポート、エクスポートします。
    実際には Pull の際に `code_modules` には UTF-8 エンコードされたテキストとして出力され、
    Push の際には `code_modules` のファイルを Shift-JSに変換したものが `barretta-core/dist` に生成され、
    それらのファイルが入力されます。

* **Barretta: Open** (SC : Alt + Ctrl + O)

    対象のExcelファイルを開きます。

# サイドパネル機能

Barrettaは専用のサイドパネルを備えています。

![launcher_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219708/28d06929-f0d6-dece-b4bb-0356b6d346b7.gif)

`Commands` セクションではInit以外のコマンドをボタンから実行できます。

`Macro Runner` セクションにはマクロのランチャーを `barretta-launcher.json` から定義できます。
VBA開発時に関数を実行したい場合、イミディエイトウィンドウから実行することは多いと思いますが、
例えば引数がある場合、その引数のパターンをいくつか試したい場合など大変なことがあります。

`barretta-launcher.json` はキックするマクロ、その引数、メモを記載し任意の名前を付けて保存しておくことができます。
場合によってはjsonファイル自体を用途ごとに保存しておくという使い方も考えられます。
関数のテスト用途にも使えそうな気がしています。

:::note info
現時点ではBarrettaプロジェクトのルートに設置されている `barretta-launcher.json` のみが読み込み可能です。
任意にリネームし別の場所に保存しておく運用が必要があります。
:::

詳細は拡張機能のチュートリアルを参考にしていただければと思います。

# GitHub Repository 

Phase3まで開発が進んだ際にはソースコードを公開し、有識者を巻き込んでの開発を進めていきたいと思います。

https://github.com/Mikoshiba-Kyu/vscode-barretta
Android Studio Flutter環境設定

android studioにflutter pluginを利用する開発環境の設定例。
iMacBigSur11.6に
Android Studio Chipmunk | 2021.2.1 Patch をdownload install
flutter_macos_3.0.5をdownload 解凍
flutterフォルダをホームの直下にDeveloperと言うフォルダ作成その中に移動。
ターミナルを使い.bash_profileを編集し、パスを通す。
vi .bash_profile
export PATH="$PATH:/Users/[ホームフォルダ名]/Developer/flutter/bin"
上記追加後下記実行でパスが通る。
source .bash_profile
which flutterにて
/Users/[ホームフォルダ名]/Developer/flutter/bin/flutter
と表示されればOK。
更に、flutter  --versionにて
Flutter 3.0.5 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f1875d570e (3 weeks ago) • 2022-07-13 11:24:16 -0700
Engine • revision e85ea0e79c
Tools • Dart 2.17.6 • DevTools 2.12.2
等表示にて確認。
android studio Preferences にてAndroid SDK SDK Tools Hide Obsolete Packagesのチェックを外し
Android SDK Tools(Obsolete)をinstall
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/ef14edfb-d424-e8c3-bcef-7b00d83abb4d.png" width="70%">

更にPluginsにてFlutterをInstallし、Android Studioを再起動かけ、Flutter Projectの開発可能になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/7e668909-268b-628e-a894-f01051f17fe9.png" width="70%">
Salesforceでフローを作成しよう～キャンペーンメンバー登録されたリードにチェックをつける方法

こんにちは。本橋孝昭です。


今回はフローの作成方法を教えます。
Saelsforceのリードはキャンペーンメンバーとして登録することが可能です。

では、キャンペーンメンバーに登録したリードにカスタム項目にチェックをつける項目自動更新フローを作成しましょう


## フロー全体図

フロー全体像はこのようになります

「起動条件」キャンペーンメンバーレコード作成時

「アクション」リードの更新
・起動条件で使われたキャンペーンメンバーのリードIDを検索してリードを探す
・探したリードのチェックボックス項目を更新する

![フロー０３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/59ab3527-819b-3074-4db8-bd677de371f8.png)

では、それぞれ見ていきましょう

### フロー起動条件
フローの起動条件はこのようになっております

![　開始条件.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/6f340903-6932-a9bd-c44d-cfd610964825.png)

### レコード更新条件

レコード更新条件はこのようになっております
![フロー０２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9b953909-a865-ad09-af16-7f21c986516c.png)


更新する項目「Check01__c」はチェックボックス項目のAPI参照名です。

これでリードからキャンペーンメンバー登録時、カスタムチェックボックスにチェックを入れることが可能です
![キャンペーン紐づけ０１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9b188c6f-342f-75e9-e257-19139b59a445.png)
yolov5のモデルをオフラインで使用する


```python
self.model = torch.hub.load('yolov5ディレクトリのパス', 'custom', path='使用するモデルのパス',source='local')
```
- 第一引数：yolov5ディレクトリのパス
    - 厳密には[hubconf.py](https://github.com/ultralytics/yolov5/blob/master/hubconf.py)が存在するディレクトリのパス
- 第二引数：`'custom'`
- 第三引数：使用するモデルのパス
- 第四引数：`'local'`

## 具体例
- pipでインストールしたyolov5を参照
- 絶対パス

の場合

```python
self.model = torch.hub.load("/usr/local/lib/python3.6/dist-packages/yolov5", 'custom', path=os.environ['HOME']+'/catkin_ws/src/ros_pkg/config/yolov5/yolov5s.pt',source='local')
```
【Tableau Data Saber挑戦記】売上などの数値を予測したいとき〜予測〜

# はじめに
過去の売上実績から将来の売上予測を立てたい、というときってあると思います。売上だけじゃなく経費だったりとか色々場面はあると思います。
そんなときにtableauの「予測」を使えば一瞬で表示させることができます。

2016年までのデータがある状態↓
2017年の売上の予測を出したい
![予測1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417218/dde13c79-a46f-d764-1e88-328edfb1c9a8.png)



# アナリティクスペインの「予測」
こちらの動画（予測）を見てください。

https://www.tableau.com/ja-jp/learn/tutorials/on-demand/forecasting?_ga=2.247900878.896275091.1654932077-2026627769.1654932077&ssologin=true&check_logged_in=1


アナリティクスペインの「予測（予想）」を右側にドラッグして画像のようにドロップすると一瞬で予測部分が表示されます。



冒頭の売上推移のvizで試してみるとこうなります。
![予測3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417218/5b73c52d-76e1-f21e-db6e-c6fc7c8e3ee3.png)


一瞬で2017年以降の推移が追加されました。
その推定で行くと、2017年Q4ではセカンドクラス（青）をファーストクラス（オレンジ）が追い抜いていますね。
このようなことがドラッグ&ドロップするだけですぐにわかります。

ちなみに予測部分を表示させないときは右クリックで[予測] > [予測の表示] でチェックを入れたり外したりするだけで表示を変えることができます。
詳しくはこちらのtableauの公式リファレンスを御覧ください。
予測の作成 - Tableau
https://help.tableau.com/current/pro/desktop/ja-jp/forecast_create.htm

キャンペーンの着地予測とかにも良いかもですね。

以上、お粗末さまでした。
【Next.js】Warning: Prop xxx did not match. Server: aaa Client: bbbへの対応


## やろうとしたこと

配列をシャッフルしてから表示しようとしました。

ざっくりと下のような感じです。

```Sample.tsx
import { useState } from 'react'

export const Sample = () => {

    const [numberArray, setNumberArray] = useState<number[]>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    const shuffleArray = () => { 配列をシャッフルする処理　};    

    shuffleArray(numberArray);
    setNumberArray([...numberArray])

    return (
        <div>
            {numberArray.map((number, index) => {
                <p key={index}>{number}</p>
            })}
        </div>
    )
}

```

## エラー

```
Warning: Prop xxx did not match. Server: aaa Client: bbb
```
という内容のエラーが表示されました。

## 原因

ReactではSSRした内容とCSRした内容を比較し、もし同じ場合はSSRした値をそのまま利用する（これをhydorateという）。
上記では配列をシャッフルしているため、SSRした内容とCSRした内容が異なっていたことが原因。

> ReactDOM.hydrate()はReactDOMServer、つまりサーバサイドで作成されたHTMLをクライアントサイドで再利用するメソッドです。
> ReactDOM.hydrate()はサーバサイドとクライアントサイドのレンダリング結果が一致することを期待します。
> 結果が一致する場合はクライアントサイドでのレンダリングをスキップ、不一致の場合はクライアントサイドで再度レンダリングをします。

[【Next.js】Hydration時にReact.hydrate()による警告が発生するケースとその解決方法](https://nishinatoshiharu.com/next-hydration-warning-resolution/#:~:text=%E5%AE%9F%E8%A1%8C%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82-,ReactDOM.,%E3%81%93%E3%81%A8%E3%82%92%E6%9C%9F%E5%BE%85%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)

↓ こんな感じ
```
SSRで生成された配列： [1, 5, 7, 3, 4, 0, 2, 8, 9, 6]

CSRで生成された配列： [5, 9, 2, 3, 1, 8, 0, 4, 6, 9]
```

## 対処

useEffect内で処理を実行する。

```Sample.tsx
import { useState, useEffect } from 'react'

export const Sample = () => {

    const [numberArray, setNumberArray] = useState<number[]>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    const shuffleArray = () => { 配列をシャッフルする処理　};    

    useEffect(() => {
        shuffleArray(numberArray);
        setNumberArray([...numberArray])
    },[])
    

    return (
        <div>
            {numberArray.map((number, index) => {
                <p key={index}>{number}</p>
            })}
        </div>
    )
}

```

流れとしては下のようになります

エラー時

```
初期状態：　[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
↓
SSR: [1, 5, 7, 3, 4, 0, 2, 8, 9, 6] // シャッフルされた
↓
CSR(hydration実行)： [5, 9, 2, 3, 1, 8, 0, 4, 6, 9] // SSRの結果と異なる
↓
Warning（一応CSRの内容で画面描画はされます。）

```

useEffect使用時

```
初期状態：　[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
↓
SSR: [1, 5, 7, 3, 4, 0, 2, 8, 9, 6] // シャッフルされた
↓
CSR(hydration実行)： [5, 9, 2, 3, 1, 8, 0, 4, 6, 9] // SSRの結果と異なる
↓
useEffectが呼び出され、再レンダリングされる。： [3, 6, 7, 1, 0, 9, 2, 5, 4, 8] // 別の配列が生成される
↓
画面描画：[3, 6, 7, 1, 0, 9, 2, 5, 4, 8]
```

ただし、公式によると、この方法はパフォーマンスの低下を招くので注意してくださいとのことです。

> このアプローチでは 2 回レンダーが発生することによりコンポーネントのパフォーマンスが低下しますので、注意して使用してください。

[hydrate()](https://ja.reactjs.org/docs/react-dom.html#hydrate)

## 参考

・[React Hydration Error](https://nextjs.org/docs/messages/react-hydration-error)

・[【図解】Next.jsのSSRが画面反映されるまでの具体的な流れ](https://nishinatoshiharu.com/next-server-render-flow/)

・[【Next.js】Hydration時にReact.hydrate()による警告が発生するケースとその解決方法](https://nishinatoshiharu.com/next-server-render-flow/)
【Mac】500x750みたいな任意のサイズの画像を簡単につくる方法

今日特定のサイズの画像を作りたくなったので調べた

## やり方

* 適当な画像をダウンロードしてくる
* Macのファンダー上でダブルクリックしてプレビューを開く
* CMD + A で選択して CMD + X で切り抜き、サイズ０のpng画像に変換
* 上のメニューの「ツール」・「サイズを調整」で好きなサイズにする
* 上のメニューの「ファイル」・「書き出す」でjpg指定をする

あら不思議！真っ白な画像が完成しました！
`200x200` の画像とか簡単に作れます！


## スクショ


![スクリーンショット 2022-08-04 19.49.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/ff02cd69-074d-84de-e168-139aa8d672b1.png)
![スクリーンショット 2022-08-04 19.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/55391fd5-1de1-ff34-9496-0d3c65034f19.png)
![スクリーンショット 2022-08-04 19.51.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/b98aeb92-fec9-6db9-85df-8a983f26a086.png)
![ダウンロード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/290e658a-243e-f516-6846-f50d1db8ee18.jpeg)

## 番外編

こんな感じでツールを使って枠いれたり文字入れたりも簡単です！

![スクリーンショット 2022-08-04 19.55.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/1c0cd681-9d51-a3f7-aef2-81b3ac4844a7.png)

![ダウンロード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/112929/2279528a-d6ab-f10a-8db9-102b4f0d83c6.jpeg)
[備忘録]サーバー上で起こった例外をまるごとハンドリングしてDiscordに送る

# コード

```Python:main.py
import json
import os
import traceback
from urllib import request
import dotenv
dotenv.load_dotenv()

DC_WEBHOOK_URL = os.getenv('DC_WEBHOOK_URL')

def standalone_discord_traceback_messenger(): # もっと良いネーミング募集中
    req = request.Request(
        url=DC_WEBHOOK_URL,
        headers={'User-Agent': '', 'Content-Type': 'application/json'}
    )

    data = {
        'content': '',
        'embeds': [{
            'type': 'rich',
            'title': traceback.format_exc(0)[:-1],
            'description': '```\n' + traceback.format_exc() + '\n```',
            'color': 0xDD3333 # 優しい赤
        }]
    }

    request.urlopen(req, data=json.dumps(data).encode())

def main():
    # ～～～すべての処理～～～
    three = 1 + 1

if __name__ == "__main__":
    try:
        main()
    except:
        standalone_discord_traceback_messenger()
        raise
```

---

# 補足

### 13行目 `headers['User-Agent'] = ''`

`urllib.request` では明示的に `User-Agent` を空にしないと `'User-Agent' = 'Python-urllib/3.9'` となり、これは Discord 側で弾かれる。

### 20行目 `traceback.format_exc(0)[:-1]`

`traceback.format_exc` の第一引数はトレースバックの上限。`0` にすると最初の一行 `HogeError: fuga message` だけ表示される。しかし `traceback` の仕様（たぶん）で最後に `\n` が入るので、`[:-1]` で一文字削っている。

### 21行目 `'description': '```\n' + traceback.format_exc() + '\n```'`

Discord の md っぽい仕様のおかげで ` ``` ` で囲むことでコード扱い、つまり等幅フォントになる。例外が見やすい。

### 35行目 `except:`

例外の種類を指定 (`except HogeError as err:`) せず、すべての例外を取得することはしない方が良いって聞いたことあるけど... (次に続く)

### 37行目 `raise`

`raise` って単体でも使えることを最近知った。これで `try:` で保留中のすべての例外を **raise** できるので、例外の種類を指定しないことは問題にならない...はず。

---

# 注意

このコードの `main()` 以外の箇所で例外が発生することは想定されていません。

以下のような例外が考えられます。

- モジュール `dotenv` がインストールされていない。
- 環境変数 `DC_WEBHOOK_URL` が `.env` またはサーバーの環境変数で定義されていない
- Discord の Webhook サーバーに何らかの障害が発生している

こればかりはサーバー上のコンソールをチェックする他ありません。
職務経歴書をオンラインマークダウンエディタHackMDでWeb上にまとめてみた

## 概要

最近、職務経歴書を更新する機会があったのですが、オンラインマークダウンエディにまとめることで色々良い点があったので、共有します。

## モチベーション
- 転職サイトに複数登録しているが、記載内容が共通していることが多く、更新が大変
- 一般的に職務経歴書をWordやExcel用いて表形式で作成することが多いが、管理が大変&見栄えが悪い&フォーマットの調整が難しいため、マークダウンで書きたい
- 職務経歴書は特定URLを知っている人のみ公開したい。この観点だとGithubのREADME.mdにまとめる方法だと、常にパブリックで公開する必要があるため、使えない

## 解決策
- HackMDというオンラインのマークダウンエディタを用いる
    - https://hackmd.io/
- 限定URLでメモを公開できるため、転職サイトや企業の人事にのみ共有が可能
- 限定URLのパスをいつでも変更できるため、UUIDなどのランダムな識別子を混ぜることで、限定URLがなるべく特定されにくくできる
- Githubのように更新の度にgit add -> git commit -> git pushをしなくて良いため、更新が楽

## 解決策による効果
- 人事から「職務経歴書を送ってください」と言われた時に、サクッと経歴を共有できるようになった
- 企業やエージェントが用意したフォーマットに合わせて職務経歴書を書く必要がなくなった
- Wantedlyなどで気になる企業にメッセージをする際に、職務経歴書のURLを共有することで、企業からの返信率が良くなる(はず)
- 転職サイトの情報を更新する手間がなくなる(大元のWebの職務経歴書を更新するだけで良くなるため)

## 職務経歴書を書く上で工夫した点

### アピールしたいプロジェクトを詳細に書く
- 仕事をしていて色々なプロジェクトを経験してきてると思いますが、アピールしたいプロジェクトにフォーカスして詳細に書くのが良いと思います。
- 理由は、プロジェクト数が多すぎても読み手へのインパクトが薄れますし、あまり成果を出せていないプロジェクトでいろいろと突っ込まれてももったいないからです。
- アピールしたいプロジェクトに関して詳細に書くことで、読み手に深い印象を与えられますし、色々とつっこまれても困らないと思います。

### 課題・打ち手・成果を分けて書く
- 転職ドラフトで業務経歴書をレビューしてもらった際にいただいたアドバイスです。
- (わたしが思うに)就転職活動は「企業の課題を解決できるかどうか」がみられると思うので、明確に見出しで課題・打ち手・成果を分けて書くとわかりやすいと思います。

### 目次を入れる
- 上記で説明したように、各プロジェクトに詳細に書くと全体的に長くなってしまうかもしれません。
- そこで、Webの職務経歴書の利点を生かして、職務経歴書の冒頭に目次を入れました。
- 目次をみて気になる箇所を読んでいただくことができ、職務経歴書全体が長くても問題ない状態としました。
【Tableau Data Saber挑戦記】予実管理や達成具合を知りたいとき〜対比とブレットグラフ〜

# はじめに
予算と実績や前年の実績と今年の実績の進捗を比較したいとき、よくあるのは棒グラフを2つ並べて可視化する感じだと思います。達成具合を見たいとき（たとえば90%のラインを超えたかとか）ブレットグラフを使うとスッキリしてとても見やすいグラフができます。

よくあるグラフ↓
予実対比のグラフを見やすくする | Excellent仕事術
https://analytic-vba.com/tips/target-actual-graph/

# ブレットグラフ（ブレットチャート）とは
ブレットグラフは、あるデータを棒グラフの形で展開し、そこに比較したい基準データ（目標値など）を線の形でプロットしたものになります。 少ないスペースで、２つのデータを比較することが可能です。

この記事に出てくるやつ↓
フィールドとチャートのタイプ〜Tableauでブレットグラフを作成する | DevelopersIO
https://dev.classmethod.jp/articles/tableau_qualified_associate_bulletgraph/

# リファレンスラインを使う
とりあえず動画で作っているところを見てみます。
Tableau 10 ブレットチャート
https://www.youtube.com/watch?v=9L4pRTykvkE

動画では2020年の売上と2019年の売上を比較しています。
2020年の売上が青いバーで比較したい2019年のものが背景にうっすら見えるベージュのバーになっています。また、2019年のものは80%、90%、100%とそれぞれラインがわかるようになっています。

上記のようにリファレンスラインは「線」だけではなく「分布」を使うことで幅？で達成度合いをグラフィカルに見ることができます。
下は50%のラインまでを濃い灰色、100%までを薄い灰色で示しています。

先の記事（予実対比のグラフを見やすくする | Excellent仕事術）を見ていただくとエクセルでわかりやすいグラフを作る方法が記載されていますが、セルでif関数を使っていたり色の塗り分けを設定したりと少し手間です。
先の動画は2分ほどの動画でしたがtableauなら直感的にささっとグラフ化できてしまいます。

以上、お粗末さまでした。
【Tableau Data Saber挑戦記】２つの事柄（指標）の関係性を知りたいとき〜相関係数と傾向線について〜

今回はちょっと趣旨を変えて、実際にData Saberで学ぶ中でいいなと思ったtableauのテクニックなどを紹介していきたいと思います。
tableauのテクニックについてがっつり紹介というよりは実務の分析の場面で起こりうるような状況で使えそうなテクニックにはこんなのがあるよ、って感じのものになります。

# はじめに
売上と品目カテゴリ、クリック数と時間帯など何かと何かの関係に意味があるのかを考える場面は普段の業務でも多くあると思います。
そのような場面で活用いただきたいのが「相関係数」です。


# 相関係数とは
相関係数とは「2種類のデータ間の関連性（相関関係）の強さを示す指標」のことです。x軸、y軸に各々データを並べたときにどのような分布になるかで相関の強さがわかります。

参考記事）相関係数とは？意味や求め方、エクセルでの計算方法をわかりやすく解説
https://data-viz-lab.com/correlation-coefficient



プロットされた点がまとまりがあって線形のようであれば関係が強いと言え、
逆にばらばらだと相関は弱いと言えます。（このプロットされた図を「散布図」と言います。）

さらに、直線が右上がりだと正の相関で右下がりだと負の相関となります。学生の頃にならった一次関数ですね。
関係の強さを表す指標が「相関係数」と言い
1に近ければ強い正の相関、-1に近れば強い負の相関、ゼロだと関係なしということになります。



# 相関係数、tableauなら一瞬でできる！
先程の記事 「相関係数とは？意味や求め方、エクセルでの計算方法をわかりやすく解説」
にかかれているように、相関係数はもちろんエクセルでも算出できます。
ですが、tableauならドラッグ&ドロップで散布図を作るだけですぐにできちゃいます！

こちらの動画で実際に散布図を作っているのでご覧いただけたらと思います。
Tableauタブロー入門　散布図とヒストグラム
https://youtu.be/bsR3gvcODro?t=188

※注意
この動画を見て注意が必要だと思ったのは、「交番の数」と「犯罪の発生件数」の相関が強いとしているのですが、
あくまで「交番の数」と「犯罪の発生件数」の相関であって、「因果」ではないことに注意しておく必要があります。
つまり、動画の説明では「交番の数」が多いと「犯罪の発生件数」が多くなる傾向があるとも思えなくもないですが、そういうことではないということです。（現実的にそんなことあってたまるか。）
むしろ「犯罪の発生件数」が多いから「交番の数」も多くしているというのが実情かと。

今回の動画はとりあえず散布図を作る様子がわかるのでその点だけ抑えていただけたらよいかなと…


散布図ができたら
画面左の「アナリティクス」ペインから「傾向線」を選ぶと一瞬で線が入れられます。
そして、線をクリックすると表示が現れ、「R−2乗」という表記が出ます。これが相関係数です。（この図では0.109…なのであまり関係性はないという感じです）


参考記事）Pearson 相関 タブロー編 | smalldata
https://data-analyzer.net/2021/01/03/person-tableau/

以上、お粗末さまでした。
pycordのドキュメントの読み方。

# Pycordのドキュメントの読み方
きっかけ：自分がbot作りを始めた時に読み方がよくわからなかったから。

---

classの軽いおさらいから。(あくまでとらえ方であって正しいものかどうかはわかりません。)

インスタンス(instance): classを使って組まれたものを変数に収める。
```py
class Hoge:
    def __init__(self):
        self.name = "peco2282"

    def huga(self, name):
        print("I am " + str(name) + ".")

# -----

hoge = Hoge()
```
ここでいう変数 `hoge` がインスタンスです。

メソッド(method): インスタンスから呼び出せる関数
ここでは
```py
hoge.huga("piyo")
# とすることで、

# I am piyo.
# と表示されます。
```

ここでは `huga()` がメソッドになります。

---
ここでは、[pycordのドキュメント](https://docs.pycord.dev/en/master/api.html) を参考に記しますが、discord.pyのドキュメントでも同じように見ることができます。



よく使われる [`discord.Client()`](https://docs.pycord.dev/en/master/api.html#client)

感覚的には
`Attributes` はインスタンスに含まれている情報を取り出す。
`Methods` はインスタンスから呼び出せるメソッド

例えば、
```py
import discord


client = discord.Client()

guilds = client.guilds
```
こうすることで `client` (ここでは自分が動かしているBot)に所属しているサーバーのリストを受け取ることができます。

type欄に [List[Guild]](https://docs.pycord.dev/en/master/api.html#discord.Client.guilds)
と書かれていることからわかるように、guilds 変数にはすべてのサーバーの情報がリストになって入っています。len()を使えばサーバー数がわかるし、for文を使えば1個ずつ取り出せます。

他にも、
`latency`(よくping-pongで使われるやつ), `users`, `voice_clients`
などがあります。
帰ってくる型は `type` 欄に書いてあります。


次はメソッドです。
メソッド名の横に `def` や `async` などがあり、基本的に `インスタンス.メソッド名()`
の形で呼び出します。

例えば [`def run(*args, **kwargs)`](https://docs.pycord.dev/en/master/api.html#discord.Client.run)
botを動かすのに必要な部分です。
皆さんはここにbotのトークンを入れると思います。
つまり、`client.run("Your_Bot_Token")` なわけです。
ここでいう `.run()` がメソッド、"Token" が引数になります。

もう一つ見てみましょう
あまり使いませんが、[`await fetch_channel(channel_id)`](https://docs.pycord.dev/en/master/api.html#discord.Client.fetch_channel)
というものがあります。

await というのは、このメソッドが非同期であるということです。細かいところは`非同期`、`コルーチン` などと調べると出てきますが割愛します。
呼び出すときには文の前に `await` を付けないといけません。

つまり、
```py
channel_id = 987654321987654321
channel = await client.fetch_channel(channel_id)
```
のような感じです。 
これで指定したチャンネルを取得できます。(普段はclient#get_guild()を使うと思います。)
ついでに説明の部分を見てみましょう。

raise: このメソッドの呼び出しで発生するエラー。(try-exceptでキャッチできます。)

return: 何を返すか。(ここでは channelのIDDからchannelの内容を渡します。)

return type: 返したものの型(クラス名)。 (ここでは `Union[abc.GuildChannel, abc.PrivateChannel, Thread]` と書かれていますが、簡単に言うとサーバーのチャンネルやスレッドのデータを返します。)

# 終わりに
今回は `discodr.Client()` について記しましたが、discord.Guild() やdiscord.Embed() も同じような感じで見ることができます。

ドキュメントを理解できるようになればもっと発展したBotを作れるようになると思います。
頑張ってください。
WireMockでカスタムtransformerを追加

WireMockには組み込みの```ResponseTemplateTransformer```がありこれと同様のtransformerを追加する方法。ここではspring-bootの```spring-cloud-starter-contract-stub-runner```前提で書いてるのでそれ以外の環境では読み替えが必要。

# ソースコード
transformer追加用のconfigクラスを作る。

```java
import org.springframework.cloud.contract.wiremock.WireMockConfigurationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.tomakehurst.wiremock.core.WireMockConfiguration;

@Configuration
public class WireMockConfig {

  @Bean
  WireMockConfigurationCustomizer optionsCustomizer() {
    return new WireMockConfigurationCustomizer() {
      @Override
      public void customize(WireMockConfiguration options) {
        options.extensions(new MyTransformer());
      }
    };
  }
}

```

適当にレスポンスヘッダーを追加するtransformerを作る。

```java
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
import com.github.tomakehurst.wiremock.common.FileSource;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.extension.ResponseDefinitionTransformer;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.ResponseDefinition;

public class MyTransformer extends ResponseDefinitionTransformer {

  @Override
  public String getName() {
    return "my-transformer";
  }

  @Override
  public ResponseDefinition transform(Request request, ResponseDefinition responseDefinition, FileSource files,
      Parameters parameters) {
    ResponseDefinitionBuilder newResponseDefBuilder = ResponseDefinitionBuilder.like(responseDefinition);
    return newResponseDefBuilder.withHeader("new-header", "sample-value").build();
  }

}

```

マッピングファイルで上で作成したtransformer ```my-transformer```を指定する。

```yaml
{
  "request": {
    "method": "GET",
    "urlPathPattern": "/(.*)"
  },
  "response": {
    "status": "200",
    "bodyFileName": "sample/foo.json",
    "transformers": ["my-transformer"]
  }
}

```

実行時のログの様子。

```
Response:
HTTP/1.1 200
new-header: [sample-value]
```

# 参考
* https://cloud.spring.io/spring-cloud-contract/reference/html/advanced.html#customization-wiremock-configuration
mysqlとlaravelで文字列の自動採番実装した時のメモ

# はじめに
mysqlとlaravelで文字列としてオートインクリメントな自動採番を実装する際に少し詰まったのでそれをメモしていきたいと思う

# 目次
1. [前提の仕様](#Chapter1)
1. [調べて分かったこと](#Chapter2)
1. [解決方法](#Chapter3)
1. [参考文献](#reference)

<a id="#Chapter1"></a>
# 前提の仕様
・IDとは別で自動採番する必要のあるカラム「hoge」があった
・「hoge」カラムはmysql側でvarchar型として保存されている
・1から順に数を増やして登録していくが、「’001’」,「’002’」といった形式で行う

<a id="#Chapter2"></a>
# 調べて分かったこと
まず最初にmysql側でオートインクリメントで登録できないかと考えたが、それができるのは数値(int)で登録しているカラムのみで、できないようだった。
なので自動採番のロジックはlaravel側で行うのが最も良さそう。
また、ロジックにおいては、DBの「hoge」カラムから最大値をとって、プラス１して０を左詰めするやり方で実装できそうだった。
最大値はmax関数を使うことができた。

以下、まとめ
・mysql側でのオートインクリメントは数値しか扱えない
・↑なので文字列でのオートインクリメント自動採番はlaravel側で実装する必要がある
・laravel(php)で、varchar型のカラムに対してでもクエリビルダのmax関数が使える

<a id="#Chapter3"></a>
# 解決方法
mysqlの設定はそのままで、laravel側の保存処理に自動採番ロジックを加えた。
以下ロジック
```
$hoge_max = DB::table('tbl_hoge')->max('hoge');
$hoge_id = str_pad($hoge_max + 1, 3, 0, STR_PAD_LEFT);
```
上記は、最初に「hoge」カラムの最大値を取得している。
その後にその数値プラス1をして、STR_PADで0を左詰め。

<a id="#reference"></a>
# 参考文献
- [MySQL 5.6 リファレンスマニュアル](https://dev.mysql.com/doc/refman/5.6/ja/example-auto-increment.html)
- [PHP:max-Manual](https://www.php.net/manual/ja/function.max.php)
SQLを使ってCSVファイルをBQにインサート

## 前提
BQに取り込みたいデータをGCSにファイルをアップロード
※今回はCSVファイルで置きました

## SQL ワークスペース(BQ)

#### インサート

    LOAD DATA INTO フォルダ名.フォルダ名
    PARTITION BY date
    FROM FILES (
    format = 'CSV',
    uris = ['GCSオブジェクト詳細にある　gsutil URL']);

`2022-06-01`から`2022-07-01`のデータが入っているCSVをBQに格納する

#### 削除

    DELETE 
    FROM `xxxxxxxxxxxxxxxxxxxxxxxxx` 
    WHERE date between "2022-06-01" and "2022-07-01"

インサートする前に`2022-06-01`から`2022-07-01`の誤ったデータを削除しておく

## インサートのSQLを実行でエラー

    Could not parse 'date' as DATE for field date (position 0) starting at location 0 with message 'Unable to parse'

CSVファイルの日付が`2022/1/01`のようになっていたので、`2022-01-01`に変更
また、カラムをスキップしていなかったのでCSV側で削除

再度、実行でインサートできました！

## 最後に

SQLを書くだけでGCSに置かれたファイルをBQに格納することができるということを知りました。
ターミナルからでも同様のことができるようなので、試してみます。(参考文献に置いてます)

 ## 参考文献

https://cloud.google.com/bigquery/docs/loading-data-cloud-storage-csv?hl=ja#sql

https://cloud.google.com/bigquery/docs/reference/standard-sql/other-statements?hl=ja#load_data_statement

https://qiita.com/komiya_____/items/509a8743f6c45e4abd7c
Pixi.jsのAnimatedSpriteのコマ送り速度をAsepriteでのコマ送り速度と合わせる

# 困っていたこと

Pixi.jsでは、AnimatedSpriteというオブジェクトを用いることで、簡単にアニメーションする画像を表示できます。
ドット絵制作ソフトの「Aseprite」から生成されたファイルからでも生成が可能でゲーム開発にとても便利です。
しかし、再生速度は無視されてしまい、60fpsで毎回画像が更新されてしまいます。
これを何とかしましょう。
今回の解決方法はコマ送りが等速の場合のみ有効です。違う場合はtickerを使う必要が出てくるでしょう。

# 下準備

sample
　├img
　│　├sample.aseprite
　│　├(sample.json)
　│　└(sample.png)
　├index.html
　└index.js

ファイル構成はこんな感じ。

## json,pngファイルの生成

まず、表示したい画像のasepriteファイル(sample.aseprite)からjsonファイルとpngファイルを生成します。
[このサイト](https://www.mizukinoko.com/entry/2020/12/01/225536)の「Exportする」までをやれば大丈夫です。

## ソースを書く

```html:index.html
<html>
    <head>
        <meta charset="utf-8" />

        <title>pixi.js test</title>
        
        <link rel="stylesheet" href="index.css" />

        <!-- jQueryの読み込み -->
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

        <!-- pixi.jsの本体の読み込み -->
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.1/pixi.min.js"></script>
    </head>
    <body>
        <main id="app">
            <!-- ここに表示される -->
        </main>

        <script type="text/javascript" src="index.js"></script>
    </body>
</html>
```

```js:index.js(修正前)
window.addEventListener('load', () => {
    app = new PIXI.Application({
        width: 600,
        height: 600,
        backgroundColor: 0x1099bb,
    }); // global

    $('#app').append(app.view);

    app.loader.add('Piyo', './img/sample.json');
    app.loader.load(setup);
});

function setup() {
    let textures = app.loader.resources.Piyo.textures;
    let textureArray = Object.keys(textures).map(id => textures[id]);
    
    let sprite = new PIXI.AnimatedSprite(textureArray);
    app.stage.addChild(sprite);
    
    sprite.play();
}
```

この状態だと、画像は60fpsで毎回画像が更新されてしまいます。

# 解決方法

これを解消するためには、まず、元の再生速度を取得する必要があります。
Asepriteでの再生速度は、jsonファイルにちゃんと記録されています。

```json:sample.json(例)
{ "frames": {
    "sample 0.aseprite": {
    "frame": { "x": 0, "y": 0, "w": 32, "h": 32 },
    "rotated": false,
    "trimmed": false,
    "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
    "sourceSize": { "w": 32, "h": 32 },
    "duration": 100 // ←これ。単位はms
   },
   ...
}
```

次にsprite.animationSpeedをいい感じにいじる必要があります。
これは、値が1のとき1フレームに1回、0.1のとき10フレームに1回と、間隔フレーム数の逆数を指定する必要があります。
このdurationの値をtとすると、60*(t/1000)が間隔フレーム数です。
よって、約分して指定するのは、50/(3*t)となります。
修正後のコードは、

```js:index.js(修正後)
...
function setup() {
    let textures = app.loader.resources.Piyo.textures;
    let textureArray = Object.keys(textures).map(id => textures[id]);

    $.ajaxSetup({async: false});
    $.getJSON('./img/sample.json', (jsonData) => {
        textureArraySpeed = 50 / (3 * jsonData.frames['sample 0.aseprite'].duration);
    });
    $.ajaxSetup({async: true});

    let sprite = new PIXI.AnimatedSprite(textureArray);
    app.stage.addChild(sprite);

    sprite.animationSpeed = textureArraySpeed;
    
    sprite.play();
}
```

となります。
以上！！
ラズパイ3で作成したイメージがラズパイ4で起動しない時の対処法

昔作っておいたラズパイのイメージを、ラズパイ4で動かそうとしたところ、起動しないという現象に遭遇。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/94a93b8e-b41e-f0e0-c792-330b0412ca82.png)
何とかならないかと調べてみたところ、こちらによさそうな情報があったので、参考にしながら試してみた。
https://blog.hitsujin.jp/entry/2020/06/25/120000
***<font color="#FF0000">※まだ解決していません</font>***

# Raspberry Pi OS 32bitをSDカードに書き込む
Raspberry Pi Imagerを使用して、32bitのOSをSDカードに書き込みます。
※おそらく古いイメージが32bitのOSであるという前提
https://blog.hitsujin.jp/entry/2020/06/25/120000

# SDカードの内容を保存する
SDカードに書き込んだ、Raspberry Pi OS 32nbitの内容を、いったんPCなどに保存しておきます。
これは後で必要なファイルを上書きするときに使用します。

ちなみに、参考URLにあるように、Githubからダウンロードしてきてもよさそうです。
https://github.com/raspberrypi/firmware/tree/master/boot

# 古いイメージをSDカードに書き込む
Raspberry Pi Imagerなどを使用して、起動しない古いイメージをSDカードに書き込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/43d1bd4c-f974-24da-d119-2ece042b089e.png)

# 保存したファイルを上書きする
SDカードに、保存しておいたRaspberry Pi OS 32bitのファイルをいくつか上書きします。
上書するファイルは以下の通りです。
- *.dat
- *.elf

# Raspberry Piを起動する
作成したSDカードをRaspberry Piに挿し、起動します。

# その結果
デスクトップが立ち上がるところまで来たのですが、すぐにシャットダウンされてしまいます。
![ダウンロード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130771/56340c8e-0e33-c452-2c19-ed9df519325b.gif)
こちらはまだ解決していませんが、とりあえずここまでの情報を共有しておきます。

もし上記の問題の解決方法が分かる方がいらっしゃいましたらコメントいただけるとありがたいです m(_ _)m
sftpをバッチモードで動かすときは、known_hostsが追加済みでないといけない

# 概要
sftpでファイル転送するスクリプトを展開したら、動かないと言われた
ログには Host key verification failed. としか出ていない
原因は以下だった
sftpコマンドをバッチモードで実行し、かつ対象サーバがknown_hostsに含まれていない時は、 `Are you sure you want to continue connecting (yes/no/[fingerprint])? ` のメッセージが出ることなく認証失敗となってしまう

# 対策

「実行前に、サーバへ一旦接続してknown_hostsに入れておいてください」で済めばいいのですが、今回はそれでは難しかったので、スクリプトの引数によってテストモード実行ができるようにしました。

## コード

引数によってテストモードに振り分ける部分

```shell:スクリプト冒頭部
# パラメータ取得
while getopts tl: OPT
do
	case $OPT in
		"t" ) IS_TEST_MODE="TRUE" ;;
	esac
done

# -tパラメタ 他のパラメタを無視して接続テストをする
if [[ "$IS_TEST_MODE" = 'TRUE' ]]; then
	communicationTestMain
	exit
fi
```

接続テスト部分
テストという体ですが、やりたいことはknown_hostsへの追加です。

```shell:接続テスト実施部分
# -------------------------
# 接続テスト全体
# -------------------------
communicationTestMain() {
    
    cmd_sftp_server1='sftp -v -oPort=22 -i /home/user/.ssh/id_rsa user@192.168.0.21'
    cmd_sftp_server2='sftp -v -oPort=22 -i /home/user/.ssh/id_rsa user@192.168.0.22'

	echo "--------------------------------------------"
	communicationTestOne "$cmd_sftp_server1" 'サーバー１'
	echo "--------------------------------------------"
	communicationTestOne "$cmd_sftp_server2" 'サーバー２'
	echo "--------------------------------------------"
	echo "接続テスト完了です。すべて接続成功であれば後続作業を行えます。"
	echo "成功しなかった環境がある場合、後続作業は行えません。個別に調査してください。"
	echo "--------------------------------------------"
}

# -------------------------
# 接続テスト個別
# $1=接続コマンド
# $2=サーバ名
# -------------------------
communicationTestOne() {
	echo "$2サーバへの接続テストを行います。"
	echo "接続するかどうかというメッセージが出たら、yesあるいはその旨の選択肢で答えてください。"
	echo "「sftp> 」が出たら接続成功です。exitと入力して、sftpを終了してください。"
	echo "「sftp> 」が出ない場合は失敗です。"
	read -p "上記を確認して準備ができたら、enterを押してください。"
	eval $1
	read -p "$2サーバへの接続テスト完了です。成功か失敗かを確認したら、enterを押してください。"
}
```