OmniAICreator/Qiita-1.07M huggingface dataset:
サザエさんの全自動卵割り機から学ぶプロダクト開発のアンチパターン

## 前提知識

### 参考用リンク

ご存知でない方もいると思います。ということで、サザエさんの全自動卵割り機回
をリンクで貼っておきます。各自ご参照ください。

https://w.atwiki.jp/aniwotawiki/pages/12370.html

※Youtubeで本編を見ることが出来ますが、グレーゾーンすぎるので今回リンクはこちらにて紹介はしません。

## ストーリーの流れ

上記リンクが分かりやすく簡潔にあらすじを説明されているのですが、自分の方からもこちらで今回記事用の目線で見たあらすじをはさみます。

1. 波平が全自動卵割り機を買ってくる
	1. 卵をセットしてレバーを引くと卵を割ってくれるという機械
2. その他家族は亭主関白な波平をおだてる
3. ノリスケは知らずに波平をこき下ろす
4. 紆余曲折してノリスケに全自動卵割り機が渡る
5. 『おもちゃ』としては最適だったがコストが大きいので波平に返す
6. 波平と復縁し、今度は鰹節を鉛筆削りのように削るマシーンを考える
	1. 欠点としては「鉛筆サイズになるまで手で削るようにする必要がある」
7. 波平・マスオ・ノリスケは大絶賛で取り組む
	1. マスオはイエスマンなので波平を立ててただけかもしれないが・・・
8. 客観的な視点を持つサザエの意見を聞かなかったり、第三者を入れないように「関係者以外立入禁止」の立て札をして、情報を秘匿してしまう

## アンチパターン

### 一番の利害関係者の意見を聞いていない

劇中でも語られている通り、波平はほとんど料理をしませんし、したことがありません。

それもそのはず、昭和の世界観なので**料理は女性がするもの**という前提のもと物語は進んでいます。

そして問題なのは、そんな料理をほとんどしたことがない波平が**料理をする人が便利になる**と思って**全自動卵割り機**を買ってきたことです。

料理する人が楽になると思って・・・という考え方は素敵です。 ~~そもそも波平が料理すればいいだけですが~~

ここで伝えたいのは、 **一番影響を受けるであろう人の意見を聞いていない**ことが問題だと言うことです。

事前にこの全自動卵割り機の存在を伝え、フネやサザエと対話をすることができていれば、購入せずに本当に料理に役立つ機器を購入できる別の未来が見えていたでしょう。

それを行わずに思いつきで買っていってしまったため、実際の現場に役立つものではなく、自己満足で終わってしまう結果に繋がったのだと思います。

もしプロダクト開発を行うのであれば、一番の利害関係者の存在を忘れずに、定期的に見てもらい、フィードバックを行えると良いプロダクトに繋がると思います。

### 最高権力者が存在する

全自動卵割り機は磯野家においては完全に無用の長物です。

しかしそんな無用の長物であるのに対して、**家族は絶賛します**（カツオは一部疑問を浮かべてましたがまともに扱われませんでした）

これは**波平が亭主関白である**という前提から生み出された状況です。

この状況下では何を言っても響かないですし、亭主関白である波平の気分を害したら、制裁をくだされるかも知れません。

この状況で波平以外に残された選択肢は一つ「従う」しかありません。

（劇中では作ってはいないですが）そんな状況で作られるプロダクトは良いものにはなりません。

最高権力者の意思しか反映されず、自分たちの意見は捨てられ「やらされている」

良いプロダクトを作っていくには、メンバーが自己組織化していけるような環境であることが第一前提として必要になってきます。

また、全自動卵割り機は「料理を普通にできる人」には無用の長物ですが、身体的に不自由な人が使う場合にはありがたい商品かもしれません。

本当に身体的に不自由な人が使う分に役立つのかは疑問ですが、どこにペルソナを置くかによってプロダクトの方向性は大きく変わることには変わりないと思います。

### 解決したい課題を見ず、要件だけ見てしまっている

鰹節を鉛筆削りのような機械で鰹節を削る作業を楽にする「グルグルダシトール」というプロダクト企画をノリスケが持ち込みます。

この機械が解決したかった課題はおそらく「鰹節を手作業で削るのが面倒」ということだったのだと思います。（憶測ですが）

しかし、最終的に行き着いているのは「グルグルダシトール」という名のプロダクト。

**前提として、鉛筆サイズまで鰹節を手作業で削る必要がある**代物です。

本来は「鰹節を手作業で削るのが面倒」だから思いついたものの、商品開発がメインになってしまい「鰹節を削れればいい」という要件だけ見るようになってしまったのです。

実際に使う人からしたら、手作業で鰹節を削ってからグルグルダシトールを使おうとなる人はほとんどいないはずです。

プロダクト開発においても「なんのために」作っているのかを日頃から見失わずに持っておく必要があります。

むきなおりをしたり、実際に自分が解決したかった課題は何だったのかを再認識することが重要なのだと思います。

### 情報を秘匿する

波平・マスオ・ノリスケは『関係者以外立ち入り禁止』という札でプロダクト開発における情報を秘匿してしまいます。

**良いプロダクトを作っていくには『透明性』が必要になります。**

透明性がないプロダクト開発では、自分たちがどこに向かっているかもわからなくなりますし、見当違いなものを作っていた時にそれを正してくれる方法がありません。

完璧に完成するまで秘匿し、世に出してみた結果「アレ？思っていたのと違う」「これが出来ないのは不便」「この機能いらなくない？」と反応が返ってきます。

それもそのはず、自分たちの感覚で進めてしまったがために、自分たちを満たすためだけのプロダクト開発になってしまったのです・・・。

## あとがき

会社で雑談をしていた際に意外といいネタだったと感じたため、簡略的にですが記事として書きました。

いかに早く失敗し、一番の利害関係者に検査してもらってプロダクトを正しい方向へ舵を戻す。これを忘れずに実践出来ているプロダクトこそが、世の中で成功しているプロダクトなのかもしれません。
AtCoderの検証用プログラムをPythonで自作した(雑)

AtCoderってinput()で入力を受け取って、print()で結果を出力しているので
- 入力元をファイルにして
- 出力先をio.StringIOにすれば

検証用プログラム自作できるよね、ってことで、ちょっと雑なプログラムですが作ってみました。

# try.py
- 検証用プログラムを特定の位置にコピペするっていう雑なやり方
- 日本語の正規化にneologdn使ってます(AtCoderなら要らないはず）
- data/in*.txtに入力データ、data/out*.txtに正解データが出力されており、それらを検証に使用しています。

## badなノウハウ
- 最初はNotebookでやろうと思ったんですが標準入力と標準出力を切り替えられなかったので断念しました。
- .pyファイルで作っています。

## というわけでソースはコチラ(try.py)

```python
import glob
import sys, os
from io import StringIO
import neologdn

in_path_all = sorted(glob.glob("data/in*.txt"))

def try1_func():
    # ここに提出コードをコピペする。
    # input()はinXXX.txtに、print()はStringIOにそれぞれリダイレクトされ、検証されます

def try_all():
    error_count = 0
    for in_path1 in in_path_all:
        out_path1 = in_path1.replace("in","out")
        # print(out_path1)
        stdout_io = StringIO()
        
        with open(in_path1,"r") as f_in:
            sys.stdin = f_in
            sys.stdout = stdout_io # 標準出力を io に結びつける
            try1_func()
            sys.stdout = sys.__stdout__ # 標準出力を元に戻す
        
        with open(out_path1,"r") as f_out:
            all_output = f_out.readlines()

        all_temp = stdout_io.getvalue().split('\n')
        for out_str1 in all_output:
            stdout_str1 = neologdn.normalize(all_temp.pop(0)) # neologdnで正規化してから比較する
            out_str1 = neologdn.normalize(out_str1) # neologdnで正規化してから比較する
            if out_str1 != stdout_str1:
                print(f"Error! temp={stdout_str1}, answer={out_str1}, in_path={in_path1}")
                error_count += 1
            else:
                print(f"OK temp={stdout_str1}, answer={out_str1}")
                pass

    print("AC" if error_count == 0 else "WA")


if __name__ == "__main__":
    try_all()
```

## 徒然なる補足
- 日本語の正規化が不要な場合はそっくりそのまま取り外してください。
- 入力データと出力データは、先に正解のプログラムを作っておいて、ファイル出力しています。
- 途中で”Error”とか"OK"とかprint文で出していますが、邪魔なときはコメントアウトして使ってます。

# 感想
- 採点が楽になりました。
- 時間があるときに今度はsubprocessで作ります [→ 作りました](https://qiita.com/yasubei/items/b55e2374c4d630cd56dc)
【Snowflake】テーブルコピーするときに便利なCLONEとLIKEとCTASの使い分け

# はじめに
Snowflakeにはテーブルをコピーするのに非常に便利だと感じたオプションでCLONEとLIKEがあり、従来のCTAS(CREATE TABLE table_name AS SELECT・・・)と比べても便利なので使い分けを紹介していきます。特にCLONEはDISKが二重持ちにならないメリットが非常に大きいと思います。

# 各コピー方法の概要

+ CLONEでの作成・・・データ含むテーブル構造のコピー
  + コメントや項目に設定されたデフォルト値やNOT NULL、primary key(<font color=green>※</font>)などの制約もコピーされる
  + データはマイクロパーティション単位で元表と共有され、<font color=red>DISKが二重持ちにならない。</font>
  （更新されたパーティション分だけDISKを使用する）
  + CTASと比べて高速
  + Secure Data Sharingで共有された表には使用できない
+ LIKEでの作成・・・テーブル構造のみのコピー（0件の表になる）
  + コメントや項目に設定されたデフォルト値やNOT NULL、primary key(<font color=green>※</font>)などの制約もコピーされる
  + Secure Data Sharingで共有された表には使用できない
+ CTASでの作成・・・従来型の手法
  + SELECT句でコピーするデータや構造を指定できるため汎用性は高い

<font color=green>※Snowflakeでprimary keyやuniqueは制約としては有効にはならない。desc table等でデータの特性を理解できる情報としてのみ利用できる</font>

# 使い分け

+ CLONE
元表からデータを含むテーブル丸ごとコピーしたい場合はこれ一択。
+ LIKE
元表からテーブル構造のみコピーしたい場合。一部（少数）のデータのみが入った表を作りたい場合はLIKEで作成した後、INSERT SELECTするのが効率的。
+ CTAS
上記CLONEとLIKEが使えない場合（元表がVIEWやSecure Data Sharingで共有された表）や複数の表をjoinした結果をテーブルとして作成したい場合

# 構文サンプル
### CLONE（テーブルを丸ごとコピー）
```sql
CREATE OR REPLACE TABLE TABLE_A_CLONE
CLONE TABLE_A
;
```

### LIKE
```sql
CREATE OR REPLACE TABLE TABLE_A_LIKE
LIKE TABLE_A
;
```

### CTAS（SQL結果をテーブルにする）
```sql
CREATE OR REPLACE TABLE TABLE_AB_CTAS
AS 
SELECT A.COLUMN1,A.COLUMN2,B.COLUMN3
  FROM TABLE_A A
       INNER JOIN TABLE_B B
          ON A.COLUMN1 = B.COLUMN1
;
```

参考：CTASでテーブル定義のみ作成したい（空の表を作成したい）場合、SELECT句に```WHERE 1=0```を指定すると0件の表となります。

# おまけ
上記のような元のテーブルからのコピーでCREATE TABLEする際にオプションで```COPY GRANTS```を付けると権限を引き継ぐことができる・・はず、なのですが、筆者の環境では安定せず、こちらはもう少し詳しくわかったら書き足したいと思います。

# おわりに
CLONEはイミュータブルなマイクロパーティションと権限のポリシー管理により実現できた機能だと想像しています。
SnowflakeはCLOUDの特性を活かしたデータベースだとつくづく思います。
この記事も誰かのお役に当てたら幸いです。

参考URL：
https://docs.snowflake.com/ja/sql-reference/sql/create-table.html#create-table-like
MySQLで対象カラムを削除する

# 背景
業務においてGUIでSQLを叩くことがしばしば。
個人ではCUIが多めであったため初歩的なものですが、一点のみ注意すべきこととし、備忘のため残しておきます。

# 対象カラムを削除する（△）
至ってシンプル。

```SQL:MySQLWorkbench上で実行
ALTER TABLE menu DROP CULUMN smile;
```
>ALTER TABLE テーブル名 DROP COLUMN 削除したいカラム名

こちらを入力し誤りと指摘されました。

# 対象カラムを削除する（○）
至ってシンプル。

```SQL:MySQLWorkbench上で実行
ALTER TABLE nomac.menu DROP CULUMN smile;
```
>ALTER TABLE テーブル名 DROP COLUMN 削除したいカラム名

こちらで正しく実行出来ました。

ポイントは一点。
- スキーマ名（データベース名・BigQueryなどではデータセット名）.テーブル名とする。

※前者のコマンドはスキーマ名（データベース名）を
```SQL:コマンドプロンプト、ターミナルetc
USE スキーマ名;
```
と指定していれば、間違いではないので△とさせていただきました。


## 終わりに

下記のようなカラム名を意識せずに扱う*などは推奨されないことは認識しておりましたが、今回のようなスキーマ名はそれに該当するのか、新たに疑問も湧いてきました。自分に限り言及すると、細かいことを意識した方が誤りとなる原因を特定できるため、また叩くクエリを明確にするため、今回のような書き方が合っていると思いました。
```SQL:SQL
SELECT * FROM table;
```
>SLECT * FROM テーブル名;

ご覧いただきありがとうございました。
プログラマがPower Automate for Desktopを使う(1)フロー作りで何が起きるか

※「Power Automate for Desktop／初心者がWebサイトを操作するフローを作って気づいたこと」を改訂し「プログラマがPower Automate for Desktopを使う」というシリーズ記事にしました。　[記事一覧へ](#シリーズの記事一覧)
# フロー作りで何が起きるか
**Power Automate for Desktop**を使って自分用のフローを作って気づいたこと紹介します。

:::note
フロー作りで次の現象が起きました。
> **フロー デザイナー**では動くのに**コンソール**からだと動かない
> 昨日動いたフローが今日は動かない

操作対象のサイトには次の特徴があります。
* ログインのつどURLが決まる
* 同じタイトルの複数のタブが出る
* ページ内の要素のクリックで表示内容が変わる

私は次のシナリオを2つのログインアカウントについて使います。
* あるサイトにログインして幾つかのページで帳票をダウンロードする

フローでは主に**Web自動化**のアクションを使いますが、拡張機能の操作では**UIオートメーション**のアクションも使います。
:::
:::note
想定読者
* Web操作のフローをこれから作る人
* Web操作のフローが動かなくなって困っている人
* プログラングの作法を流用してフロー作りで楽をしたい人

:::
---
<a id="シリーズの記事一覧"></a>
###### シリーズの記事一覧
[(1)フロー作りで何が起きるか](https://qiita.com/jzephyr/items/3ba3b02bfdb3d6a32442)
　　（本記事です）
[(2)エラーの事例](https://qiita.com/jzephyr/private/3ee32aaecb809a3dcc49)
　　フロー デザイナーでは動くのにコンソールからだと動かない　昨日動いたフローが今日は動かない
　　WindowsUpdate後に動かなくなった
[(3)実行時にURLが決まり同一タイトルの複数タブが出る動的サイトの扱い方](https://qiita.com/jzephyr/private/48057f4f8a7acc39fd7c)
　　タブに接続　タブを閉じる　リンクを操作　待機する　タブ外の操作
[(4)アクションの操作対象を整理して分かりやすいフローにするには](https://qiita.com/jzephyr/private/8d7344cac40104d13295)
　　ブラウザ変数は何を指すか　ブラウザ変数のマージ
　　UI要素の括りは何を指すか　UI要素の括りをまとめる方法
[(5)フローを安全に保つには](https://qiita.com/jzephyr/private/3d5cd18c1045aee9054e)
　　モジュール化すべきか　フロー保守の方法
[(6)フロー作りの小技と雑学](https://qiita.com/jzephyr/private/4c20256d19c59888c54a)
　　フロー作成の効率を上げる手段　**Power Automate for Desktop**に関する予備知識

---
:::note
私の環境は次の通りです。
・OS: Winodws 11 Pro (22H2)
・Power Automate: Power Automate for Desktop (無償版)（2.29.00258.23041）
・Chromeの拡張機能: Microsoft Power Automate(2.31.0.14)
・個人のマイクロソフトアカウントを使用
:::
::: note
マイクロソフトのページを挙げます。
 [Microsoft Power Automate ドキュメント](https://learn.microsoft.com/ja-jp/power-automate/) 　…Microsoft Powerの説明
　　[デスクトップフローの概要](https://learn.microsoft.com/ja-jp/power-automate/desktop-flows/introduction)  …for Desktopの部分
　　　　・コンソール画面のツールバーのヘルプから概要に行けます。
　　　　・デザイナー画面の「詳細」から該当箇所に行けます。
[重要なことに時間をかけてその他のことは自動化しましょう。](https://powerautomate.microsoft.com/ja-jp/)　…導入まで
:::
Rails のフロントエンドツールに vite_rails を使う

Rails7からフロントエンドで使えるツールのオプションが増えました。jsのデフォルトは`importmap-rails`、モジュールバンドラーを使いたい場合は`jsbundling-rails`で`webpack`, `esbuild`, `rollup`が選べます。

ビルドが早いと言われている`esbuild`を使うのも良いですが、まだ開発中の機能もあります。
開発環境は高速化して、安定して本番ビルドできるツールを探したところ`vite_rails`が良さそうでしたので試してみました。

## vite_rails とは

ビルドツール Vite を Rails に最適化したライブラリです。基本的に Webpacker でできることは網羅しています。

### 特徴

- エントリーポイントを自動検出
    - `app/frontend/entorypoints`以下のファイルを自動で検出してビルドします。
- 高速なHMR（Hot Module Replacement）ができる
    - 事前ビルドに`esbuild`を使っている
- `assets:precompile`と自動的に統合
    - 本番ビルドのフローの変更をしなくて良いので、Webpacker からの移行も簡単
    - `rollup`を使ってビルドする
- script, link のタグヘルパーがある
    - `vite_javascript_tag`, `vite_stylesheet_tag`
- デフォルトの設定が充実している
    - 複雑な設定をしなくても使える

## 使ってみる

まずはgemをインストールします。

```rb:Gemfile
gem 'vite_rails'
```

```
$ bundle install
```

gemインストール後に、初期設定します。

```
$ bundle exec vite install
```

- 初期設定では以下を行います。
    - 開発サーバーの起動スクリプト`bin/vite`の追加
    - `vite`, `vite-plugin-ruby`のインストール
    - 設定ファイル`vite.config.ts`, `config/vite.json`の作成
    - エントリーポイントの`application.js`作成
    - `application.html.erb`にタグヘルパー挿入

開発サーバーを立ち上げれば、いままでどおり開発ができます。

```
$ foreman start -f Procfile.dev

...

11:33:37 web.1  | * Listening on http://127.0.0.1:5100
11:33:37 web.1  | * Listening on http://[::1]:5100
11:33:37 web.1  | Use Ctrl-C to stop
11:33:37 vite.1 |
11:33:37 vite.1 |   VITE v4.0.1  ready in 150 ms
11:33:37 vite.1 |
11:33:37 vite.1 |   ➜  Local:   http://127.0.0.1:3036/vite-dev/
11:33:37 vite.1 |   ➜  press h to show help
```

## 初期設定後のファイルを確認

初期設定されたファイルを確認してみましょう。

`foreman`で Rails と Vite の開発サーバーを起動するため、`Procfile`が作成されます。
```:Procfile
vite: bin/vite dev
web: bin/rails s
```

jsのエントリーポイント `app/frontend/entrypoints` が作成されます。Webpackerなどで`app/javascript`ディレクトリがある場合は、`app/javascript/entrypoints`になります。
```
$ tree app/frontend
app/frontend
└── entrypoints
    └── application.js
```

設定ファイルも作られます。ポートやプラグインの設定ができますが、特に変更しなくても問題ありません。
プラグイン`vite-plugin-ruby`がimportされていますが、Railsの場合`vite-plugin-rails`にするとerbがホットリロードできるようになるので便利です。

```json:config/vite.json
{
  "all": {
    "sourceCodeDir": "app/frontend",
    "watchAdditionalPaths": []
  },
  "development": {
    "autoBuild": true,
    "publicOutputDir": "vite-dev",
    "port": 3036
  },
  "test": {
    "autoBuild": true,
    "publicOutputDir": "vite-test",
    "port": 3037
  }
```

```ts:vite.config.ts
import { defineConfig } from 'vite'
import RubyPlugin from 'vite-plugin-ruby'

export default defineConfig({
  plugins: [
    RubyPlugin(),
  ],
})
```

Vite 用のヘルパータグが layout に設定されます。これでビルド時に script タグに変換されます。
スタイル用の`vite_stylesheet_tag`、アセット用の`vite_asset_path`などのヘルパーも利用できます。

```erb:app/views/layouts/application.html.erb
...

<%= vite_javascript_tag 'application' %>

...
```

## まとめ

簡単にセットアップできましたね。新しい概念が追加されているというより、機能はそのままで、新規、既存どちらでも導入が簡単なことがメリットになりそうですね。
最近のフロントエンドの技術進化は速く、使うツールも変わることが多いので、その時の状況に合わせて試していきたいと思います。

## References

https://ja.vitejs.dev/

https://vite-ruby.netlify.app/
GitHub ActionsでActiveRecord::ConnectionNotEstablished: Can't connect to MySQL server on 'db' (115)のエラーが発生する

# 概要
- 以下ファイルを用いてGitHub Actionsを起動した場合、`rails db:create`実行時に表題のエラーが発生してしまう。
- ローカルでは同様の流れで実行できていたため、GitHub Actions特有の問題だと判断した。

```.github/workflows/rspec-and-rubocop.yml
name: Run rspec, rubocop-rails

on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: docker-compose build
        run: docker-compose build

      - name: docker-compose up -d
        run: docker-compose up -d

      - name: setup db   # rails db:createが失敗してしまう
        run: docker-compose run --rm backend rails db:create db:migrate

      - name: rspec
        run: docker-compose run --rm backend rspec

      - name: rubocop
        run: docker-compose run --rm backend rubocop

      - name: docker-compose down
        run: docker-compose down
```
```docker-compose.yml
version: '3'

services: 
  db:
    image: mysql:8.0
    ports:
      - "3306:3306"
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: root
    
  backend:
    build:
      context: ./backend/
      dockerfile: Dockerfile
    stdin_open: true
    tty: true
    volumes:
      - ./backend:/review-app
      - bundle:/usr/local/bundle
    command: bash -c "rm -rf tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    depends_on:
      - db
    ports:
      - "3001:3000"
    environment:
      TZ: Asia/Tokyo

  frontend:
    build:
      context: ./frontend/
      dockerfile: Dockerfile
    volumes:
      - ./frontend:/usr/src/app
    command: sh -c "npm start"
    ports:
      - "3000:3000"

volumes:
  db:
    driver: local
  bundle:
    driver: local
```

# 結論
- .github/workflows/rspec-and-rubocop.ymlに以下の処理を追記することで解消。

```.github/workflows/rspec-and-rubocop.yml
name: Run rspec, rubocop-rails

on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: docker-compose build
        run: docker-compose build

      - name: docker-compose up -d
        run: docker-compose up -d

      - name: sleep for waiting launch db  # ここを追加
        run: sleep 1m

      - name: setup db
        run: docker-compose run --rm backend rails db:create db:migrate

      - name: rspec
        run: docker-compose run --rm backend rspec

      - name: rubocop
        run: docker-compose run --rm backend rubocop

      - name: docker-compose down
        run: docker-compose down

```

# 原因
- backendコンテナの起動時点でdbコンテナが立ち上がっていないことが原因。
- ローカル環境ではすぐにdbコンテナが立ち上がるのか、`depend_on`を記述するのみで良かったが、CI環境ではうまくいかない模様。
- そのため`sleep 1m`を追加し、`rails db:create`の実行を1分待つことで解決。

参考になれば幸いです。

# 参考サイト
- [RailsアプリCICDパイプライン構築の手順（備忘録）（Docker+Rspec+GitHubActions+heroku）](https://qiita.com/nofate8785/items/09d1d20c518aa6c55287)
- [Docker+MySQL "Can't connect to MySQL server on"の原因と解決方法](https://qiita.com/shun198/items/a66d6214cdab5629029d)
TeraTermで起動時のウィンドウサイズを保存

# 概要

TeraTerm起動するたびに右下ドラッグドロップしてウィンドウサイズ広げてる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/3b411c20-35bd-7dcf-671b-3749d8b3f72b.png)

自分で打ったコマンドやレスポンスがちょっと長いとき、折り返されると見にくいからそうしてる。
でも次回起動時、同じウィンドウサイズで起動してくれない。

TeraTerm起動するたびにやるの面倒だからウィンドウサイズを覚えさせたい。

# やり方

ウィンドウサイズ変えたら…
設定 ⇒ 設定の保存 。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/c1bb89dd-a1a7-92af-fb2c-9dc115ce6306.png)

INIファイル上書き。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/56da2403-f5d0-1f85-c191-21a060d3b9ee.png)

# バージョン

Windows 10 Home 21H2 19045.2364
TeraTerm 4.106


TODO:ウィンドウサイズ以外に保存できる設定まとめる
【Xcode】ホーム画面に表示されるアプリ名の設定方法

# ホーム画面に表示されているアプリ名を変更
現在「App名」となっていますが、こちらを任意のアプリ名に変更していきます。
![Simulator Screen Shot - iPhone 14 - 2022-12-18 at 13.34.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/46ff6292-a85f-1833-cb87-0004561891d4.png)

# App名はどこで決まるのか？
デフォルトで新規プロジェクト作成時に入力する**Product name**が**Display Name**(ホーム画面に表示されるアプリ名)として利用される。

# じゃあDisplay Nameを変更するのが正解？
**Display Name**を変更するとプロジェクトファイルの`PRODUCT_NAME`が変更される。
もし「**sample**」という**Product name**の場合、**Display Name**を「**sample2**」と変更すると
アプリケーションファイル名も変更されてしまいます。

そんな時のために**Bundle display name**という設定があります。
これはアプリケーションファイル名を変更せずに、ホーム画面のアプリ名だけを変更できる設定です。
ターゲット設定のinfoタブを開き、設定を追加してアプリ名を決めます。
![スクリーンショット 2022-12-18 13.52.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/8890855d-1c38-3c9e-a6d7-a02f12d266b9.png)

# 表示確認
変更されていることを確認できました。
![Simulator Screen Shot - iPhone 14 - 2022-12-18 at 13.58.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604036/d2ccddd0-2540-09fa-56a5-33a949fdf4a5.png)
MacからVPSサーバー内のファイルを参照する方法

# はじめに
最近はバックヤードやWeb側の実装など色々みているのですが、先日Xserverが提供しているVPSサーバー内のファイルにアクセスする方法で少々手間取ったので、解決する術を簡単に記事としてまとめておこうと思います。

# 参照方法
サーバー内のファイルを参照するための手順は以下になります。
ちなみに冒頭でも述べている通り、XServerのサービスを使用しているため、こちらのサービスを基準にお話します。

① Cyberduckを使用するため、以下からダウンロードします。
https://cyberduck.io/download/

② ダウンロード後、起動後画面左上の新規接続を選択
③ 以下スクリーンショットの入力画面が表示される為、スクリーンショット上部の選択項目をSFTP（SSHによる暗号化FTP）を選択します。

![スクリーンショット 2022-12-18 13.43.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/86a9a063-40a6-0186-a25f-2e36e4a22c52.png)
④ 上記スクリーンショットの番号1から3までの入力欄を入力
 
1番の入力欄はvpsサーバーのIPアドレスになります。
入力するとURLと記載されたところにURLとして表示されます。

2番、3番はコンソールへアクセスする際のID,Passになります。
パスワードは契約時に決めたもの、IDは特に指定がなければroot等になっているのではないかと思います。

⑤ 接続を選択し、接続完了

以上になります。
もし上記で参照できないようであれば、入力項目が間違っていないかなど確認していただくと良いと思います。

# さいごに
不慣れな作業を行うとちょっとしたことでも躓いたりしますよね。
特にバックヤードはまだまだ未熟な点が多いので、引き続きトライを続けながら知見をためていこうと思います。
【Splatoon】イカって100mどのくらいで走れるの？

# Splatoonとは
Splatoon（スプラトゥーン）は、任天堂から発売されているアクションシューティングゲーム。

2015年5月にWii U用が発売、2017年7月にはNintendo Switch用として『スプラトゥーン2』が発売された。最近ではシリーズ3作目となる『スプラトゥーン3』が発売されめちゃくちゃ盛り上がってますね～
![splatoon-3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982411/52dd7876-7f3f-a401-8750-45fd21a5bcb2.jpeg)


# 分かっていること

今回の検証でカギになってくることは一つ。それは**100mをどれだけ正確に測れるか**です。
長さのことで公式から出ている情報はたったの二つだけで
- テンタクルズの二人の身長
- イカたちのヒト状態の垂直飛びの最高到達点が150cm

この二つだけになります。
![IMG_6137.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982411/58c0a7dc-54a0-c5a2-b4a7-56824be96990.jpeg)
# 注意事項
![IMG_6141.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982411/5eb3120a-9297-281a-c82b-a601b5866893.jpeg)
バンカラ街のロビーに入ると、ロビー内で武器のため仕打ちができます。
今回の検証ではロビー内の試射場の下の線を使って100m測っていきます。
試射場の下の線に人状態のイカを横にして並べると約イカ2匹分だということがわかるので、3ｍ間隔で線が引かれてあるということがわかりました。しかし、試射場は線が10本までしかひかれていないため30ｍしか測れません。よって計測した値に「10/3」を掛けた値を100mの記録とします。

# 検証へ
では検証に入っていきたいと思います！
ヒト状態で走るのは、パブロでの移動が一番早かったため、パブロを使用します。
![IMG_6140.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982411/477bd408-8ab2-278f-8811-aa1896749d89.jpeg)
検証では、30mのタイムを5回測定して平均値を出していきます。
- 4.64
- 4.64
- 4.73
- 4.66
- 4.77
平均値は4.688秒となりました。
この値に「10/3」を掛けると15.6266...となり、イカが100ｍを走ると約16秒くらいで走れるということがわかりました！
# 最後に
今回の検証で一番考えたことが、ヒト状態のイカの身長です。
youtubeで「イカ　身長」で検索すると、一番上にイカの身長が何センチなのか検証している動画があります。この検証動画ではデボン海洋博物館というステージにある人間の化石の大きさを手掛かりにイカの身長を推定していました。この動画ではイカの身長は約60,6cmから66,0cmと結論が出ていました。
なぜこの値を使わなかったかというとスプラトゥーンの公式から出ていた情報で,テンタクルズのヒメの身長は145㎝とあり、ヒト状態のイカと並ばせてみると、ヒメのほうが身長が低く辻褄が合わないとおもったので、今回の検証では150㎝としました。

この100ｍ約16秒というタイムはどのくらいなのか調べてみると、中学二年生の男子ぐらいであることが分かって、武器持ちながらこのくらい走れるのはさすが軟体動物だとおもいました。みなさんも、パブロをもって100ｍを全力で走ってみましょう！

人間の化石の大きさを手掛かりにイカの身長を推定していた動画のリンクを最後に貼るのでもしよかったら見てみてください！
https://www.youtube.com/watch?v=JMouk6UTIYg
はじめてのVelodyne

最近購入したVelodyne VLP-16について紹介したいと思います。Velodyneの購入を考えている人の参考になればと思います。

# Velodyne is 何？
3D LiDAR。自動運転の車とかについてるやつ。細かいところは以下を参考にしてください。
[VLP-16 User Manual](https://velodynelidar.com/wp-content/uploads/2019/12/63-9243-Rev-E-VLP-16-User-Manual.pdf)
[Product brief](https://www.amtechs.co.jp/product/VLP-16-Puck.pdf)

# 購入してみた
さすがに新品だと$4k以上するので今回はeBayで購入することにした。
今回購入したのはノーマルVLP-16。$275のベストオファーを出して承認されたので購入した。一応動作確認が取れているものを選定した。PayPalからの請求は¥49,178になった。
ちなみに裏でオークションのやつにも手を出していたが負けてしまった。
![IMG_5568.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/a7cd110d-2240-75fe-37fe-6679ff17ac43.jpeg)

# 届くまで
アメリカからの発送という事もありなかなか不安な日々を過ごした。

- 11/18 アメリカ合衆国コロラド州から発送される
- 11/19 FedEXに渡される
- 11/21 国際配送拠点があるアメリカ合衆国ケンタッキー州に到着する。
- 11/25 国際配送拠点から発送される
- 12/6  日本に到着して佐川に渡される
- 12/8  自宅に到着

# いざ開封
届いた箱の写真は撮り忘れた。
![F5560D4C-D2C4-4B5E-8872-88A11FF25E39.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/37ee6b78-33a1-ec76-5bad-6720a93da61e.jpeg)
特に大きな傷もなく問題無さそうであった。そしてありがたい事ことに業者の人がVelodyneのIPとかが書かれた紙も入れてきてくれた。

# 配線
とりあえずこのコネクタは使わないので切ってしまう(一度も動かさずに切落とすのは心臓に悪い...)

![IMG_5569 Large.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/8e62098b-6419-2975-650b-94d1d505e875.jpeg)


User Manualに従って配線を行う。なお購入した物は日に焼けていたのかLT ORANGEと ORANGEの違いが全くわからなかった。

![IMG_5570 Large.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/e0643b76-cf6a-28f2-135a-f779a100b3ff.jpeg)

![IMG_5571 Large.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/40440e63-0f62-127c-c489-5f457e5dabb4.jpeg)


# いざ電源投入
"ウィーン"とモーターが回転する音がした。結構音がでかい。ACアダプタは12V2Aのものを使用。

![IMG_5572 Large.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/4431b1b2-47b6-1f7e-8204-b87b6ae1eba0.jpeg)


ルーターに接続。すると... ネットワークスキャナーツールに反応あり！& Wiresharkも見るとブロードキャスト宛のパケットあり！
Velodyneのipを叩くと以下の画面が...

![35073EB6-1364-4281-8DAF-535BEA268002.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/1f247cfc-7db2-5f31-c94b-56d8cf43434c.jpeg)

きたーー！ここまでくれば勝利したも同然。


# ROS2(RViz)で見る
以下のリポジトリにROS2ブランチがあるのでそれをクローンしてcolcon build。

https://github.com/ros-drivers/velodyne

そしてlaunch
```shell
ros2 launch velodyne velodyne-all-nodes-VLP16-launch.py
```
そしてRviz2を起動。Fixed frame をVelodyneにしてPoint Cloudでtopicを指定する。そうすると以下のような点群が見れるはず。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/3bd82810-4895-e8d4-2f91-9f26ba8ebbe3.gif)

# 最後に
想像よりデカいし重かった。まぁ辛いことがあっても家に帰ればVelodyneあるしとなるのでOKです。
Node.jsで巨大なXMLファイルを扱う

# はじめに

ファイルサイズが数十GB程度あり、ファイルから読み込んだデータを全てメモリ上に展開するには大分無理のあるXMLファイルを扱う機会がありました。そんな時に便利なライブラリ`node-xml-stream`を見つけたので使い方をご紹介していきます。

今回、Node.jsのバージョンは`18.12.0`、`node-xml-stream`のバージョンは`1.0.2`を使用しています。

# node-xml-streamとは

XML/HTMLファイルを軽量かつ高速に処理するパーサーライブラリです。Node.jsの標準APIである`Stream`を使用して作られています。
通常のファイル読み込みではデータを一気にメモリ上に展開してから後続の処理に進むのに対し、`Stream`を使用したファイル読み込みでは`chunk`と呼ばれる単位でファイルを読み込みながら順次処理することができるため、物理メモリサイズを超えたファイルの処理も可能になります。その反面、階層構造が複雑なファイルの読み込みにはあまり適していません。理由は以降で説明します。

https://github.com/snappyjs/node-xml-stream

# 振る舞い

ファイルを開いた`Stream`とパーサーインスタンスを`pipe()`で接続すると、ファイルを順次読み込みながら開始タグや終了タグ等が見つかったタイミングでイベントが発火されます。これをハンドリングしてお目当てのデータを取得していくのが基本的な使い方です。

試しに、次のようなイベントを拾うだけのプログラムを作り、サンプルXMLファイルを読み込ませてイベントの発火順序を見てみましょう。

```js:sample1.js
import { Parser } from 'node-xml-stream'
import fs from 'fs'

const parser = new Parser()

// 開始タグが見つかった
parser.on('opentag', (name, attrs) => console.log(`${name} has opened`))

// 終了タグが見つかった
parser.on('closetag', name => console.log(`${name} has closed`))

// テキストが見つかった
parser.on('text', text => console.log(text))

// 読み込みが完了した
parser.on('finish', () => console.log('finish!'))

// Streamとパーサーを接続してファイルを読み込んでいく
const stream = fs.createReadStream('./sample.xml')
stream.pipe(parser)
```

```xml:sample.xml
<?xml version="1.0"?>
<root>
  <parent>
    <child>foo</child>
    <child>bar</child>
  </parent>
  <parent>
    <child>hoge</child>
  </parent>
</root>
```

```plain:stdout
open: root
open: parent
open: child
text: foo
close: child
open: child
text: bar
close: child
close: parent
open: parent
open: child
text: hoge
close: child
close: parent
close: root
finish
```

実行結果を見ると分かる通り、各イベントはそれぞれ「何のタグの始まり/終わりが見つかった」「何のタグのテキストが見つかった」等、タグ単品についての情報は教えてくれますが、「親、子、兄弟にはどのようなタグを持つ」といった**タグの文脈を教えてはくれません**。データの取得時にはだいたい階層構造の決まった位置にあるテキストを取得したいケースがほとんどであると思うので、自前実装で見つかった開始タグと終了タグの名前や出現回数を見ながらデータを取得していく必要があります。

# サンプル

タグの開始/終了をフラグ管理し、お目当ての箇所のテキストが見つかったらテキストを取得する例です。これに先程のサンプルXMLファイルを読み込ませると、期待どおりの位置のテキストが取得できていることが確認できます。

サンプルのような小さなXMLファイルではほとんどライブラリによる恩恵は受けられませんが、数GBから数十GBクラスのファイルを読み込ませても、このプログラムが使用する物理メモリ量は高々数百MB程度におさえることができます。

```js:sample2.js
const isOpened = {
  root: false,
  parent: false,
  child: false,
}

parser.on('opentag', (name, attrs) => {
  if (!typeof(isOpened[name]) !== 'undefined') {
    isOpened[name] = true
  }
})

parser.on('closetag', name => {
  if (!typeof(isOpened[name]) !== 'undefined') {
    isOpened[name] = false
  }
})

parser.on('text', text => {
  // root > parent > childのテキストを取得する
  if (isOpened.root && isOpened.parent && isOpened.child) {
    console.log(`child: ${text}`)
  }
})

const stream = fs.createReadStream('./sample.xml')
stream.pipe(parser)
```

```plaintext:stdout
child: foo
child: bar
child: hoge
```

# まとめ

巨大なXMLファイルを扱える`node-xml-stream`をご紹介しました。あまりこのようなユースケースは多くはないとは思いますが、日本語の記事を探しても見当たらなかったので思い切って自分で書いてみました。記載した内容に誤り等があればご指摘ください。また、もっと便利な使い方があるよ～なんてご意見等あればぜひお寄せいただけると嬉しいです。ではでは。
【python】勉強メモ-その6　辞書について


### 1．はじめに
今回は、完全に自分用のメモとなります。

##### value（値）の取得方法
```sample_01.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

ans = favorite_languages["Jane"]
print(ans)

```

```result.txt
python
```

##### .get() 存在しないキーにアクセスした場合のエラーハンドリング

`dict.get("key", "返すメッセージ")`
第二引数を省略した場合は、`None`が返される。

```sample_02.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

ans = favorite_languages.get("Taro", "そのキーは存在しません")
print(ans)

```

```result.txt
そのキーは存在しません
```

#### .items() キーと値のループ取得

```sample_03.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

for key, value in favorite_languages.items():
    print(f"\nキー： {key}")
    print(f"値： {value}")
```
```result.txt
キー： Jane
値： python

キー： Sarah
値： c

キー： Ed
値： ruby

キー： Philip
値： python

```

#### .keys() キーを取得

```sample_04.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

for key in favorite_languages.keys():
    print(key)
```

```result.txt
Jane
Sarah
Ed
Philip
```

なお、キーの取得は、ループを使わなくても可能

```sample_05.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

print(favorite_languages.keys())

```

```result.txt
dict_keys(['Jane', 'Sarah', 'Ed', 'Philip'])
```


#### .values()　値の取得

```sample_06.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

for value in favorite_languages.values():
    print(value)
```

```result.txt
python
c
ruby
python
```

なお、値の取得は、キーと同様に、ループを使わなくても可能。


```sample_07.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

print(favorite_languages.values())

```

```result.txt
dict_values(['python', 'c', 'ruby', 'python'])
```

#### set() 辞書の値重複排除について
辞書の値を取得する時、重複した値があることがあります。重複した値の排除については、
`set()`を利用します。**sample_06.py**と**sample_08.py**を比較してみてください。

for value in **set**(favarit_langes.values()):

```sample_08.py
favorite_languages = {
    "Jane": "python",
    "Sarah": "c",
    "Ed": "ruby",
    "Philip": "python",
}

for value in set(favorite_languages.values()):
    print(value)
```

```result.txt
python
c
ruby
```
renderでのデプロイに失敗した

# 取り組んでいたこと
アプリケーションをrenderにデプロイしたときにエラーが出たときのことを書きます。
このアプリは初めはAWSでデプロイする作業をしていましたが、
作業途中で、都合によりrenderにデプロイするという方向転換をしています。


# エラーの内容
※renderを登録したときにGithubと連携をしています。
GitHubからRenderにコードが自動的にプルされ、デプロイが実行されます。

Githubでコミット・プッシュをすると自動でデプロイ作業が行われます。
しばらく待つと、
![a63816b1e031aa0968a0694f0dd998cf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2845625/062204b3-5d72-62dc-399d-a1e2cda70831.png)
failed...つまり失敗しましたよと表示されました。


# 解消するために行ったこと
何が原因か調べるために、エラーログを確認します。

赤い雲マークの横のDeployをクリックすると、ログを表示させることができます。
Maximizeをすることで拡大表示をしてからエラー文を探すと調べやすかったです。

```:renderのエラーログ
active_storage/service/configurator.rb:23:in `block in config_for': Missing configuration for the :amazon Active Storage service. Configurations available for [:test, :local] (RuntimeError)
```

Active Storage service...
:amazon...

これを見てハッとしました。
AWSでデプロイする作業をしていたため、そのときに設定した記述を元に戻していないところがありました。
（全て元に戻したと思い込んでいたのです。）

私の場合、
config/enviroments/production.rbファイル内の記述を変更しました。

```ruby:config/enviroments/production.rb
# 変更前
config.active_storage.service = :amazon
```
```ruby:config/enviroments/production.rb
# 変更後
config.active_storage.service = :local
```

この後コミット・プッシュをし、自動デプロイが始まりました。
すると、今度は成功しました。

解決して良かったです。
Ender 5 S1事始め④（円のカクつき改善）

## 円カクつき問題の原因の考察
[前回](https://qiita.com/fmax/items/a4f97c7925ecd829fc5f)で#FDMTestを実施し、円がカクつく問題が出た。
これは何が悪かったのか？

* STLデータ
公式が出しているSTLデータを使っており、流石にそのセンは無さそう
* gcodeデータ
Ultimaker Cura 5.2.1を使用してスライスしている。
可能性は大いにあるが、プレビューを見る限りだとカクついていない。
しかしメッシュ修正→最大解像度を見ると**デフォで0.25mm**であり、これはかなり怪しい。
怪しいが、安易に細かくするとgcodeサイズが膨れ上がり[このような問題](https://signal-flag-z.blogspot.com/2020/11/Cura-XY-2-PRO-Issue.html)が起こるらしい。
とりあえず後回しにする。
* 通信速度
前回、実はUltimaker CuraからUSB経由で印刷を行っていた。
通信速度が遅ければ、バッファが間に合わずにカクつくかもしれない。

## 解決策の検討
通信速度の問題に関してはUSB経由で印刷せずにSDカードで印刷すれば解決しそうな話だが
毎回SDカードでPCとやりとりするのは**正直面倒くさい**。
そのため、Wifi内蔵のSDカードを購入した。
技適付きのものが東芝FlashAirのみで、新品では8GBで1万6千円、フリマで3,500円だったためフリマで落札。
まだ届いていないが、今後はそちらで対応したい。

それはそれとして、その前にUSB経由で印刷できないのかも一応検討してみる。

3Dプリンタデフォルトのボーレートは115.2kbps。
一般的なボーレートの範囲内での最高速度だが、これで速度が足りるのか？

* 必要ボーレートの計算
Dimensional Accuracyの円の最下段は直径25mm程度のため、円周は78.5mm。
250mm/sで動作するとして、0.314秒の時間で1周している。
Ultimaker Cura 5.2.1は**円を直線に分割しG1コードで送信**する。
転送されるG1コードは25mmの円で43回送信されているようだ。
G1コード一回につき約30バイト送信されているため、1周あたり約1290バイト=10320bps。
1秒あたり32866bps=32.9kbps。スタート/ストップビットを考えると40kbps弱ぐらい。
単純に見ると一応足りてはいる。
しかし、PCはリアルタイム性が無いため数百msの通信停止が入ることがある。
マイコンのメモリは合計数十kBなので2kBバッファできれば良いところだろう。
一番転送量の大きい瞬間では50msぐらいのバッファになるので、数百ms止まるとアンダーランしてしまう。
50mm/sの印刷速度(250msバッファ)ぐらいだったらギリ表面化しなさそうではあるが…。
何か、**印刷速度が高速化したため問題が顕在化しそう**で見えてる地雷臭がする。
受信バッファサイズとPCの送出停止時間が根本的な問題なため
これはボーレートが仮に上がったとしても解消しない。
**現状、高速印刷は安定性のためにSDカードで印刷が安牌**のようだ。
FlashAir化は正解だったということか（自画自賛）。

* 円の円弧化検討
速度を変えられないのであれば、データ自体をスリム化すればいいじゃない！
ということでUltimaker CuraにArc Welderプラグインを導入してG1の線分を円弧に近似してG2/G3命令に変換する。
[ここ](https://note.com/newspeak/n/n4277f8493a43?after_purchase=true)や[ここ](https://note.com/newspeak/n/ne3099053636e?after_purchase=true)で（有料記事だが）説明がある。
G2/G3命令であれば外壁の途中で止まることが原理上無くなるし、ファイルサイズも減り、転送負荷が減るはず。
#FDMTestをそのまま印刷すると4時間ぐらいかかってしまうため
テスト用として#FDMTestのDimensional Accuracyの部分を[それっぽく切り出した](https://www.thingiverse.com/thing:5719188)データを
FreeCADで作り、そのstlデータからgcodeを生成した。
![D.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1391167/a91f3e26-380a-d636-ad2b-e060d11a3bef.png)
上記はとりあえず10μmでメッシュ化している。
で、円弧化の結果がこちら

|  | デフォルト | Arc Welder使用 |
|:-:|:-:|:-:|
| ファイルサイズ | 824kB | 219kB |

かなりスリム化した。
これは期待できる。
ちなみに上記モデルは通信路の負荷が足りないためか、印刷するとデフォルトでもきっちりした円になり
現象は再現できなかった。

## Arc Welderの結果
印刷した結果がこちら。
ちなみにUSB経由で印刷している。
* Arc Welder有効化前
![DSC_0054.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1391167/b034308c-6602-9393-f898-c74c29b386a2.jpeg)
* Arc Welder有効化後
![DSC_0053.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1391167/4af396d6-b66f-3237-665e-27c0dddec9ce.jpeg)
お分かり頂けただろうか？

スマホカメラのマクロ性能が死にかけなので分かりづらいが
壁面のカクつきが減少している。
ちなみにそれでも0.2mm隙間のピンは抜けなかったのだが、効果はあったと言えるだろう。

## 結論と雑感
今回の結論と雑感
* 高速3Dプリンタは今のところUSB経由での印刷はやめといた方がいい
* 3Dプリンタにも2Dプリンタのような大容量プリンタバッファが必要になりそう
SDカードをプリンタバッファ化できないものか？
* 通信路はUSBシリアルが手軽なのは分かるが、115.2kはもう限界かもしれない
* Arc WelderによるG1化→G2/G3化は円形状に効果がある。でも0.2mmのピンは抜けない
* FreeCAD→メッシュ化(stl)→G1命令連打→G2/G3化は迂遠過ぎる
step/igesデータ→G2/G3命令のロスレス変換が欲しい
[この記事](https://note.com/newspeak/n/n4277f8493a43?after_purchase=true)の有料部分に深く同意する

次はあまり手を入れたくなかったが最大分解能を修正してみたい。
AtCoder Beginner Contest 282 A〜C問題をPythonで解いてみました

ABC282(AtCoder Beginners Contest 282)
A〜C問題をPythonで解いてみました。

- コードは雑めです。ゆるしてー
- 競技プログラミングの勉強一切したこと無いので、テクニックは知らないよ。ごめんねー

## A問題
[提出コード](https://atcoder.jp/contests/abc282/submissions/37369834)
```python
k = int(input())
print("ABCDEFGHIJKLMNOPQRSTUVWXYZ"[:k])
```

文字コードを1ずつ増やしながらループで出してもいいですね

## B問題
[提出コード](https://atcoder.jp/contests/abc282/submissions/37370327)
```python
n, m = map(int,input().split())
int_s = []
for s_i in range(n):
  s_i = input()
  int_s_i = 0
  for s_i_ch in s_i:
    int_s_i <<= 1
    if s_i_ch == 'o':
    	int_s_i |= 1
  # print(f"{s_i}={bin(int_s_i)} len(s_i)={len(s_i)}")
  int_s.append(int_s_i)
 
all_bit = (1<<m)-1
pair = 0
for n1 in range(n):
  for n2 in range(n1+1,n):
    if (int_s[n1] | int_s[n2]) == all_bit:
      pair += 1
 
print(pair)
```

制約で問題数が30までだったのでbit演算で行けると思って書きました。
'o'のところでbitを立てて、bit演算のORを取るとどちらかが1のときbitが立ちますね
あとは全bit立っているかどうかを比較するだけで全問正解できるかどうかがわかります。

## C問題
[提出コード](https://atcoder.jp/contests/abc282/submissions/37371234)
```python
n = int(input())
s = input()
kukuri_flag = False
s2 = []
for ch in s:
  if ch == '"':
    kukuri_flag ^= True
  elif not kukuri_flag and ch == ',':
    ch = '.'
  s2.append(ch)

print("".join(s2))
```

Pythonのstringはimmutable、listはmutableなので、stringの連結は遅いだろうなぁと思いまして。
単純にstringを連結していくよりはlistをappendしていってjoinした方が速いって情報をいくつか見つけたのでそのように実装しました。

## 感想
アプリサイズ10Kbyte制限のアプリ作った時に、bit演算で論理演算するようなことしてサイズを縮小していたので、その時のことを思い出しました。
条件分岐はJUMP命令があるのでアドレス格納する分データがでかくなるからやっていたノウハウですが、今は使用することのない変態ノウハウですねｗ
16色のゲームを作った時とか、昔はbit演算はよく使ったんですけど、最近はあまり使いませんねー。

### ツッコミ
- **Q** B問題、わざわざbit演算しなくてもいいのではって気持ちになった(余計こんがらがりそう)
- **A** わたしはbit演算のほうがイメージしやすいんですよ。ちょっと変なのかもしれない
【Snowflake】Organizationで複数アカウント管理

# はじめに
SnowflakeもAWSのようにOrganization機能を使用してアカウント作成・複数アカウント管理が可能です。ざっくりと紹介していきます。
※2023年7月にOrganizationについてユーザ側で操作できることが増えており、記事訂正しています

# Organizationを使ってアカウントを作れると何が嬉しいのか
+ 本番環境と完全に分離した開発・検証環境を自由に作成できる
  - アカウントパラメータのテストができる
  - 変更バンドルの事前適用テストができる
  - Secure Data Sharingの構成をテストできる
  - ネットワークポリシーを分けた環境を作成することができる
+ 異なるリージョンにアカウントを作成することができる
+ ライセンスもメインアカウント以下の内容で作成できる（例えばメインアカウントの契約がBusiness Criticalで、追加したアカウントはEnterpriseにもできる。逆は不可。変更はサポートへの連絡が必要）
+ 複数のアカウントを一つの請求に集約できる
+ ORGANIZATION_USAGEスキーマで複数アカウントを一括で監視・監査もできる
+ サポートケースを複数アカウントに跨って参照できる

# 使い始めまで
1. サポートにOrganizationw有効の申請
~~特段フォーマットなどはなく、Organizatonを有効にしてほしいという旨のCaseを挙げれば即日有効にしてくれます~~
↓
2023年7月よりユーザ自身でOrganizationを有効にできるようになりました。
orgadminは少なくとも最初に発行されたアカウントでは利用できました。
```sql
USE ROLE orgadmin;
ALTER ACCOUNT my_account1 SET IS_ORG_ADMIN = TRUE;
```

2. Organization機能を利用できるロール```orgadmin```を付与
```sql
-- 作業はaccountadminで行う
use role accountadmin;

-- ユーザに付与する場合
grant role orgadmin to user ユーザ名;

-- ロールに付与する場合
grant role orgadmin to role ロール名;
```

# アカウントの作成
snowsightに「組織」というメニューが出てくるようになり、そこからアカウントの追加が可能です。

:::note warn
警告
追加したアカウントはユーザやネットワークポリシーが引き継がれているわけではないため、都度設定を忘れないようにしてください。
:::
※アカウントの複製も可能ですのでこちらはまた別途紹介したいと思います。

# 複数アカウントの管理
+ アカウント一覧
snowsightのメニュー「組織」からアカウント一覧の参照が可能です。
または```SHOW ORGANIZATION ACCOUNTS```でも参照できます。
+ コスト管理
例えばアカウントごとのウェアハウス使用量の月ごとの合計を見たい場合は以下のようなSQLになります。
```sql
SELECT ACCOUNT_NAME,
       TO_CHAR(START_TIME,'YYYY-MM') AS DATE_YM,
       SUM(CREDITS_USED) AS SUM_CREDIT_USED
FROM SNOWFLAKE.ORGANIZATION_USAGE.WAREHOUSE_METERING_HISTORY 
GROUP BY ACCOUNT_NAME ,TO_CHAR(START_TIME,'YYYY-MM')
ORDER BY DATE_YM,ACCOUNT_NAME;
```
+ アカウントの削除
~~アカウントを削除は当記事執筆時点（2022/12）時点ではユーザでは削除はできません。
削除したいアカウントが出てきた場合はサポートに連絡して削除してもらいましょう。
なお、削除申請から完全に消えるまで2か月くらいかかります。~~
↓
2023年7月よりユーザ自身でアカウントをDROPできるようになりました。
```sql
DROP ACCOUNT my_account GRACE_PERIOD_IN_DAYS = 14;
```
+ アカウントをまたぐサポートケースの参照
こちらは参照したいロールやユーザに対して以下のように権限のGRANTが必要です。
```sql
GRANT MANAGE ORGANIZATION SUPPORT CASES ON アカウント TO ロール名orユーザ名;
```

# おまけ
~~organization権限を有効にできるアカウントは自分で追加したアカウントも有効にすることができますが、私が申請した時点（2022/6）では1組織内で2アカウントまでしか有効にできないようでした。organizationsの追加もサポートへの連絡により実施してもらえます。~~
↓
2023年7月時点で8アカウントまでorganization権限を持てるように変更されたようです

# おわりに
複数のアカウントを管理できるようになると構成の選択肢が増え、とても便利です。
まだお使いでない方は是非申請し、利用してみてください。

参考URL：
https://docs.snowflake.com/ja/user-guide/organizations-gs.html
未経験からWebエンジニアに転職して3か月が経った苦悩

未経験から独学を経てWebエンジニアに転職して、2ヶ月が経った。
まだ2ヶ月といえど、様々な苦労を経験できた。
未経験からエンジニアを目指す人にとって、リアルで参考になると思うので、ぜひ読んでいってほしい。
あくまで**転職はスタート地点**です。

▼転職活動の記録はこちら
<a href="https://qiita.com/Nine-777/items/2be528cb9ab459140590">**アラサー未経験が独学半年でエンジニア転職するまで**</a>

# 自己紹介
文系アラサー

+ 29歳
+ 大卒(文系)
+ 前職は医療系団体職員
+ PC経験はOfficeソフトの基本は問題ないくらい

# 転職先

+ Web系自社開発企業
+ 社員数10名程度のベンチャー企業
+ フルリモート
+ 業務委託

# 1. 仕事が難しい

未経験に合わせたタスクを振ってくれるが、それでも自走ができないくらい難しい。
コラッタを倒してねって草むらに入るとカイリューが出てくる感じ。

+ #### **コードやファイル量が膨大**
実際に運用されているプロダクトのコードやファイルが想像以上に多い。
自分の想像していた10倍以上のコードとファイルがある。
Railsを学習している方なら伝わるかもしれないが、modelが200個以上あったりする。

+ #### **使っている技術が多い**
自分が触れてこなかった技術がたくさんあり、それらは仕事しながら学習しないといけない。
自分の場合、恥ずかしながらRSpec(テスト)、JavaScript、Vue.js、Dockerなどは仕事しながら学んでいる。
経験がない技術を扱うタスクは普通に渡されるので、質問や学習しながらこなさないといけない。

+ #### **ロジックが複雑**
今思うと、自分のポートフォリオが知育おもちゃに見える。
複雑なロジックが網目状に絡み合っていて、解読に時間を要する。
参考書に書いてある単純なロジックとは比にならないので、当たり前だが参考書を読むだけでは意味がない。
自分で読んで書いて理解していくしかない。



# 2. リモートワークが難しい

未経験からのリモートワークは様々な部分で工夫が必要。
自立していない分、周囲に頼らなければいけない場面が多く、リモートワークは対面より頼り方が独特。

+ #### **質問の要領が掴めない**
大半はこれに尽きる。
質問のタイミングや方法が掴めなくてかなり苦労した。
当初はコミュニケーションを図れて、画面共有しながら早く質問できるので、主に通話をしていた。
しかし通話の場合、相手の状況や繁忙度が図れないので、かけて良いタイミングで気を遣って手が止まる。
頻繁に通話をかけていたところ、1日1時間以上先輩の時間を奪う日が出てしまった。
答えまで教えてもらうケースもあったので、チャットをメインにしてヒントをもらう形に変更することになった。
チャットは、手隙の時に返してもらえるのでハードルは下がり、割り込みせず、回答が来るまで別の作業ができるのでおすすめ。
しかし文脈が伝わらなかったり、望んだ回答より簡略な回答が来ることも多いので工夫が必要。


# 3. 数値目標に届かない

自分が働いている企業では、**1週間ごとに仕事の目標値**が定められる。
1つ1つのタスクに数値が定められ、1週間で処理した合計値が目標値を上回らなければいけない。
自分には3ヶ月後の目標値を定められていたが、2ヶ月と1週間経った時点で及んでいない。

いくら学習して頑張ったと思っても、数値がすべて。
業務委託なので数値の結果は自分の将来にも関わり、届いていない現状への焦りが強くなる。
裏を返せば数値を出せば認められるので、結果を出すしかない。

# 4. すべて自己責任
他責的になると楽かもしれないし、自己責任て割り切るのも結構大変。
言い訳ができない環境は厳しいと感じる時もあるし、プライドを完全に捨てるのは思っているより難しい。
でも結局はすべて自己責任。
自分がプログラミングできるようにならないと何も解決しない。
そもそも環境は恵まれている。
+ ##### **生産性が低くても、お金をもらいながらプログラミングできている**
+ ##### **独学の時お金を払ってメンターに質問していたが、今は無料で質問できる**
+ ##### **必要な本は購入してもらえている**

# 終わりに

未経験からエンジニアに転職すると、苦労がたくさんあった。
想像とは違ったなんてことも沢山あるし、体験しないと分からない。
自分の場合、これらの苦労は<font color="red">**技術力の不足**</font>が元凶なので、泥臭くやりきる。
未経験からエンジニアを目指している方々には、ぜひ**転職後のイメージ**も膨らませておいて欲しい。
行動に役立つこと間違いなし。
untyped int の思いがけなかった挙動

# これは何？

先日、untyped int の挙動で驚いたことがあったので書いておく。

Go アドベントカレンダー

https://qiita.com/advent-calendar/2022/go

の カレンダー3 の初日が空いていたので参加してみた。

# コード

こんなコードがある。

```go:go
const x = 9876543210
log.Printf("%v", x) // 32bit 環境ではコンパイルエラー
```

いつもは 64bit 環境で動かしていたんだけど、久々に 32bit 環境向けのバイナリを作ったらコンパイルエラーになってびっくりした。

x は untyped int。
`log.Printf` で `%v` で受けるんだから、型は何でもいい。
しかし、`log.Printf` には untyped int のままでは渡せない。仕方ないので `int` に変換を試みるもオーバーフローでエラー。

`v ...any` に渡したいのに `int` にされるのが、言われてみればまあそうだよねということだけれど、思いがけなかった。

# いろいろ試してみる

## const int でシフト

```go:go
const x = 9876543210
const s = int(3)
log.Printf("%v", x>>s)
```

これはOK。エラーにならない。
untyped のまま shift できるのだろう。

## const int で割る

先ほどと実質的に同じ計算だが、

```go:go
const x = 9876543210
const s = int(1 << 3)
log.Printf("%v", x/s) // 32bit 環境ではコンパイルエラー
```

こちらはエラー。untyped のままでは int での除算はできない模様。


## switch に入れる

```go:go
switch 9876543210 { // 32bit 環境ではコンパイルエラー
case 1:
	log.Println("one")
default:
	log.Println("not one")
}
```

`switch` に入れても勝手に `int` にされる。`switch int64(9876543210) {` だとエラーにならない。

## case を `int64` にしてみる。

```go:go
switch 9876543210 { // 32bit 環境ではエラー
case int64(1): // mismatched types int64 and int
	log.Println("one")
default:
	log.Println("not one")
}
```

`case` の値から `switch` の方の型を推論することはできないらしい。

## コンパイルエラーにならない場合

ここまでは幸いにしてコンパイルエラーになっていたが

https://qiita.com/Nabetani/items/495da28ee31c660f7331

と混ぜるとエラーにならなくなる。

```go:go
const x = 100000001
s := 10
log.Println((x << s) % 1000) //=> 64bit 環境では24、32bit 環境では -80
```

わかりにくいし、わりと恐ろしい。

# Zig ではどうなの？

「コンパイル時にしか扱えない、ビット長が確定していない値」という機能を持つ、go 以外の唯一の言語（私調べ）、Zig でどうなるか。


## untyped のようなものを `Printf` のようなものに渡す

Zig ではこう。

```zig:zig
const x=987654321098765432109876543210;
try stdout.print("{}\n", .{x});
```

go だと「`Printf` に untyped のままでは渡せないので int に変換して渡す」という処理なのでエラーになっていた。
zig だと、`comptime_int` int のままで print に渡しているのでそういうトラブルは発生しない。

## 計算

同様にシフトと除算を試した。

```zig:zig
const x=987654321098765432109876543210;
const ys:i32 = 10;
const zs = x>>ys;
try stdout.print("{} {}\n", .{zs, @TypeOf(zs)});
// => 964506172948013117294801311 comptime_int

const yd:i32 = 1024;
const zd = x/yd; // 除算の結果が i32 に入らないのでコンパイルエラー
try stdout.print("{} {}\n", .{zd, @TypeOf(zd)});
```

## switch〜case のようなもの

```zig:zig
const x = switch (987654321098765432109876543210) {
    i64val, i32val, i16val, i8val, i4val => 1,
    else => 0,
};
const y = switch (i64val) {
    i32val, i16val, i8val, i4val => 1,
    else => 0,
};
const z = switch (i64val) {
    9876543210 => 1,
    // 987654321098765432109876543210 => 2, // エラー: type 'i64' cannot represent integer value '987654321098765432109876543210'
    else => 0,
};
```

zig の場合、安全であれば型が違う値でも問題なく比較できるので、あんまりエラーにならない。
ただ、go でいうところの `case` にある値が `switch` に渡す型で表現できない場合はエラーになる。変換できないという趣旨ではなく、どうせマッチしないからエラーにしといたよ、という話だと思う。

# まとめ

untyped int が int になるタイミングはときどきわかりにくくて、32bit 環境と 64bit 環境で異なる動きをすることがあるから気をつけよう。
コンパイルエラーになる場合が多いものの、そうではないパターンもある。

zig の場合、comptime_int のままで処理が進むし、そもそも処理系依存のビット長の型を使う機会が少ないのでほとんど心配なさそう。
Windows10のHDD不具合でSSDへクローン換装

古くから使用しているWin10マシンのHDDが故障しかけたため、SSDへクローンして換装したときの備忘録です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696263/b5e63aec-4b5c-7938-ddf6-bf65bc431c73.jpeg" width="300">

# 1.HDDの故障状況
PCの挙動がおかしかったためCrystal Infoで状況をチェックすると下記の２項目が注意勧告あり。
- 代替処理保留中のセクタ数
- 回復不可能セクタ数

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696263/a6693661-d67a-01df-6590-00d4719f99db.jpeg" width="450">

流石に長年使ってきたので、寿命かと考えましたが買い替えはまだ控えたく、Win10のサポートが終了するまで今の環境のまま手軽に継続利用したいと考えて、SSDへクローンし換装することにしました。

# 2.使用機器
PCはアメリカ購入のDell XPS L502XというノートブックPCで、当初はWin7であったものをWin10へアップグレードした経緯があり、Win11のMin条件を満たせていない状態のものになります。
故障したHDDは、Seagateの2.5" HDDで一般的な寿命以上に使えたことに敬意を表します。

|項目 |スペック |
|---|---|
|型式 |ST9750420AS |
|サイズ |2.5インチ |
|容量 |750GB |
|回転速度 |7200 RPM |
|キャッシュ |16MB  |
|インターフェイス |SATA 3.0Gb/s |
|高さ |9.5mm |

# 3.交換パーツ
SSDは色々あって悩みましたが、手軽にAmazonで買えるシリコンパワー製にしました。
購入してみて、その軽さに驚きました。これまでのHDDと桁違いに軽いのです。ケーブル接続して使っても、ケーブルのたわみで動いてしまうほどの軽量にビックリしました。

|項目 |スペック |
|---|---|
|型式 |SP512GBSS3A55S25 |
|サイズ |2.5インチ |
|容量 |512GB |
|最大読込速度 |560MB/s  |
|最大書込速度 |530MB/s  |
|インターフェイス |SATA III 6.0Gb/s |
|高さ |7mm |

※インターフェイス仕様が一致しませんが低速規格であるSATA II 3Gb/sにも互換性ありと記載

[Amazonリンク - シリコンパワーSSD 512GB 3D NAND採用 SATA3 6Gb/s 2.5インチ 7mm PS4動作確認済 3年保証 A55シリーズ SP512GBSS3A55S25](https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%91%E3%83%AF%E3%83%BC-NAND%E6%8E%A1%E7%94%A8-2-5%E3%82%A4%E3%83%B3%E3%83%81-A55%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-SP512GBSS3A55S25/dp/B079JW4ZB8?th=1)
※ Amazonの情報は2022/12/16現在のものです。

# 4.クローン作成作業
昔、HDDのイメージファイルを作るのに複数のフリーソフトがあった印象だったので完全に油断していました。
主だったベンダーのクローン作成ソフトは、期間課金制の有料がほとんどであり、いろいろ探した結果、Macrium Reflect Freeというソフトを使用してみることにしました。

[Macrium社HP](https://www.macrium.com/reflectfree?mo)

インストール画面が独特でしたが、クローン作業のUIはとても使いやすく、クローン開始後６時間ほどでSSDへのクローン作業が完了。
今回クローンしたパーティションは、RecoveryとOSの２つで、OSパーティションのサイズもSSD残容量に合わせてMaximumサイズへ同時に調整できました。（大変優秀なソフトですね！）

# 5.SSD換装作業
HDDの場所はネットにあった同PCのマニュアルを参考にキーボード回りのカバーを外し該当のHDDを取り出しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696263/e29b923a-080e-ce16-8386-8ef2f5f3c826.jpeg" width="300">

その後、クローン作業をしたSSDに固定金具を取り付けて、HDDが格納されていた場所へ換装。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696263/a129a37c-5dde-0c92-7a88-5ea07abc76cd.jpeg" width="300">

これでめでたくSSDへ交換完了。。。

# 6.ブート修復
と、思いきや、電源ONすると、Win10のブートローダーに不具合があるようで起動せず。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696263/aa1ca40e-e679-07d0-8f59-de5597be8589.jpeg" width="300">

すかさず、HDDに戻して、SSDをケーブル接続して、system32のファイルを比較してみても、エラー表示されたファイルはSSDにも存在することを確認。

では、ということで、スタートアップ修復を実行してみたものの、修復せず。

う～ん、今回のクローンではブートローダーが認識されない、であれば、ブートローダーを修復すれば良いと考えて下記を実行。

(1)回復ドライブを立ち上げてコマンドプロンプトを実行
(2)コマンドプロンプトから「bootrec /rebuildbcd」を実行 ⇒ 無事完了
(3)同様に「bootrec /fixmbr」を実行 ⇒ 無事完了
(4)同様に「bootrec /fixboot」を実行 ⇒ Access Deniedと表示

困り果ててネットで検索すると、「ITおじさん様」の下記記事を発見して「対処１：CHKDSKを実行する」を実施。
[bootrec /fixbootで「アクセスが拒否されました」が出た時の対処 – Windows10](https://itojisan.xyz/trouble/17752/)

結果、リブートしてみると、無事にWin10が爆速で立ち上がりました。

思えば、元HDDに不良セクタが発生してSDDへクローンしたのですが、その不良セクタの情報を受け継いでbootrec /fixbootコマンドで「アクセス拒否」されていたのが、CHKDSKで不良セクタの情報が解消されたように考えられます。

これでしばらくはこのまま使用することができます。

とにかく、ITおじさん様、ありがとうございます！
FireFox Timeout 設定(忘備録)

# Nginxから499エラーが表示された場合の対応

https://qiita.com/wk0012345/items/9bfec5ea5718d2e1ff7d

- 前回の記事で`ALB`、`Nginx`のタイムアウトを設定しても、3分後、`499`のエラーと一緒に落ちてた

# 499 エラーとは？
- サーバ側の処理の途中、クライアント側から連結を切った場合、Nginxから499エラーを表示する

# 対策
- ブラウザー(Chrome)の開発者モード`(F12)`で確認し、`Err Connection close`(?)というメッセージを確認した
- [調べた結果](https://stackoverflow.com/questions/39751124/increase-timeout-limit-in-google-chrome)Chromeからは設定できないらしい

> Firefox: You can set the value of network.http.connection-timeout in about:config

1. Firefoxブラウザーの検索のところに、`about:config`を入力
1. `network.http.connection-timeout`を検索する
1. 上記の設定を`ALB`と`Nginx`で設定した値と合わせる


# 解決完了
gms.common.api.ApiException:10と12500の対処法

新しいプロジェクトを作成したときにハマってしまいました。
対処法のメモです。

# エラーメッセージ
```
sign_in_failed com.google.android.gms.common.api.ApiException: 10
sign_in_failed com.google.android.gms.common.api.ApiException: 12500
```

- 10の場合
Firebase フィンガープリント
- 12500の場合
GCP OAuth 同意画面
Firebase サポートメール
GCP API 有効

# Firebase フィンガープリント
ApiException: 10 の場合
フィンガープリントとは開発PCで実行すると出力されるハッシュ値(SHA1)のことです。
他人が勝手にAPKを差替えられないようにするのが目的です（たぶん）

## Step1 構成ファイルをアプリに同梱

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/390ce5ff-2387-2128-d217-485b9922e82c.png' width=80%>

1. Firebase にログインします。
https://console.firebase.google.com/u/0/
1. プロジェクトを作成します。
1. アプリを追加します。
1. 以下の構成ファイルをダウンロードします。
  google-services.json (android)
  GoogleService-Info.plist (ios)
1. 構成ファイルを Flutter プロジェクトにコピーします。
:file_folder:android
&emsp;:open_file_folder:app
&emsp;&emsp;:notebook:build.gradle
&emsp;&emsp;:notebook:google-service.json :arrow_left::arrow_left:
:file_folder:ios
&emsp;:file_folder:Flutter
&emsp;:file_folder:Runner
&emsp;&emsp;:notebook:AppDelegate.swift
&emsp;&emsp;:notebook:GoogleService-Info.plist :arrow_left::arrow_left:
&emsp;&emsp;:notebook:Info.plist

## Step2 ハッシュ値をFirebaseに登録
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/f4298566-dcd9-7109-5f78-cfb26a89d92b.png' width=80%>

```
cd android
gradlew signingReport （または gradle signingReport）
```

1. androidフォルダでコマンドを実行します。
  成功するといっぱい出てきますが SHA1 は同じ値です。
1. FIrebaseのアプリにSHA1を登録します。 
- 注：別のPCでビルドすると、そのPCのハッシュ登録が必要になります。

# GCP OAuth 同意画面
ApiException: 12500 の場合
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/9f2c6920-b33d-924d-c631-5d3a32e801a4.png' width=80%>

1. GCP (Google Cloud Platform) にログインします。
1. Firebaseで作成したプロジェクトがGCPにも作成されているので、それを選びます。
1. OAuth同意画面の「アプリを編集」で編集します。

# Firebase サポートメール
ApiException: 12500 の場合
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/56a41d15-beeb-c6a5-2c01-3f36692c3246.png' width=80%>

- プロジェクトの設定（SHA1を設定したページ）でサポートメールを設定します。
この情報はネットで検索すると出てきました。私は登録済なので未検証です。

# GCP API 有効
ApiException: 12500 の場合
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253995/954a65b8-c7eb-2079-a57b-7242c721350a.png' width=80%>

- GCPでAPIの有効無効を確認します。
私の場合は Google Drive API を使うのでそれを有効にします。
ちなみに無効にしてもできました。ダメ元です。

# あとがき
新しいプロジェクトを作成したときにハマりました。フィンガープリントは知っていましたが、OAuth 同意画面はいつのまにかやっていたのでしょう。AWS も GCP もこの手のごにょごにょが多いですね。