OmniAICreator/Qiita-1.07M huggingface dataset:
rubocopの備忘録①

## はじめに

業務でrubocopを知ったので備忘録を残しておきます

## キーワード

ruby, rubocop, lint

## 目次

1. rubocopとは
2. rubocopの基本
3. 使ってみる
4. まとめ
5. 参考

## rubocopとは

読み方は「るぼこっぷ」らしいです。

rubocopとは、rubyのリントのためのgemです。rubyで書いたコードを予め決められたルールに基づいてチェックしてくれて、主な目的はチーム開発における可読性の向上だと思います。

参考

[https://blog.solunita.net/posts/relean-rubocop-options/](https://blog.solunita.net/posts/relean-rubocop-options/)

## 基本

公式のgetting started的なのです。

[https://rubocop.org/](https://rubocop.org/)

- オプションなし　カレントディレクトリの全てのrubyファイルをチェックしてエラーを表示します

```ruby
$ rubocop
```

- ‘-l’オプション　rubyのコマンドラインオプション - W(大文字)と同じ動きをします

```ruby
$ rubocop -l

# ruby -W 
```

- ‘-a’ オプション　autocorrectの略で、エラー箇所の自動修正を行います。

```ruby
$ rubocop -a
```

- `-x`オプション　layoutのみに自動修正を行います

```ruby
$ rubocop -x
# rubocop --fix-layout
```

他にもオプションはたくさんあります。

一覧はこちらです。

[https://docs.rubocop.org/rubocop/1.50/usage/basic_usage.html#command-line-flags](https://docs.rubocop.org/rubocop/1.50/usage/basic_usage.html#command-line-flags)

## 使ってみる

まずrubyの環境が構築されていることは前提です。

私の環境にはなぜか入っていました。

rubyが入っていない方はどこかから落としてみて下さい

[https://www.ruby-lang.org/ja/documentation/installation/](https://www.ruby-lang.org/ja/documentation/installation/)

rubyの環境が整った方は次のように進めてください

rubocopをインストールします

```ruby
$ gem install rubocop
```

テストするコードがないので作ります

```ruby
# test.rb

print 'hello world'
```

そして、rubocopと打ってみます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3092463/58415ebd-2b73-b91a-87e2-54d225d9b9cb.png)


1行書いただけなのに三つも指摘が。

まず一つ目のエラー

```ruby
Layout/EndOfLine: Carriage return character missing.
```

改行コードがCRLF(OS依存。winはこれ)になっているため指摘されています。

[https://qiita.com/HiMinmeg/items/10b741608cf217aad68c](https://qiita.com/HiMinmeg/items/10b741608cf217aad68c)

二つ目のエラー

```ruby
Style/FrozenStringLiteralComment: Missing frozen string literal comment.
```

文字列をイミュータブルにするマジックコマンドが書かれていないぞ、と言っています。

冒頭にマジックコマンドを書くと良い気がします

[https://qiita.com/YutoYasunaga/items/98111ef50927ecb4135d](https://qiita.com/YutoYasunaga/items/98111ef50927ecb4135d)

三つ目のエラー

```ruby
Layout/TrailingEmptyLines: Final newline missing.
```

最後の行に改行が無いと言っています。

改行して三つ目のエラーを消そうとしたらなぜか一つ目のエラーも一緒に消えました。

マジックコメントを追加したら、#の後ろのスペースだとかマジックコメントの次の行は空行に、とか言われたので `rubocop -a`を実行したら治りました。すごい。

[correctable]がついているエラーは自動修正が可能なようです。

## ぼやき

rubocopを本当に軽く使ってみましたが、1行printするだけでこんなにも警告を出してくれます。丁寧な先輩だと思うことにしています。

次回は`.rubocop.yml`や`.rubocop_todo.yml`のカスタマイズとreviewdogとの組み合わせ、みたいなことをしたいと思います。

具体的にはこの記事を参考に書きます。

[https://zenn.dev/o_ku/articles/1c5b6f1c9eac9a](https://zenn.dev/o_ku/articles/1c5b6f1c9eac9a)

ではまた。

## 参考

- [https://docs.rubocop.org/rubocop/1.50/index.html](https://docs.rubocop.org/rubocop/1.50/index.html)
- https://zenn.dev/aosan/scraps/c38209947414c2
【Git】Gitの草が消えた！？時の対処

# 経緯
　お久しぶりです。初投稿から約２か月空いてしまいました💧

現職を行いつつ、転職活動をしていたのですが、気づいたらGitの草が丸々消えていました。

これはマズイと思いながらも現職の兼ね合いでなかなか時間が取れずやっと対処できたので備忘録として投稿したいと思います。

デプロイする際にエラーの対処をしていて設定を変えてしまったのかもしれない...

# 環境
AWSのCloud9でRuby on RaylsをメインにPFとしてネットショッピングECサイトを開発。
バージョン管理ツールとしてGitHub使用。

# 概要
1. GitHubのリモートリポジトリのPushlog確認
2. ユーザー名変更の前にリモートリポジトリとローカルリポジトリの状態を合わせる
3. デフォルトユーザーからGitのユーザー名に変更する
3. 歴史改変の前にワンクッション置く（リスク回避）
3. いざ歴史改変！すべての歴史にユーザー名を反映して強制push
3. おわりに（反省）
## やったこと
### 1.GitのリモートリポジトリのPushlog確認
かなり時間が空いているため、直接GitHubからどうなっているか再確認。

すると最後にRead.meの編集をしていたことがわかり、これ自体はGitHubから直接変更したものなのでユーザー名で草の反映もされていた。

Pushされたログを見るとアカウント名ではなくデフォルトユーザーとして操作していることになっていた。

過去の自分何やってんだ？と思ったものの考えても進まないので早速検索をかけた。

### 2.ユーザー名変更の前にリモートリポジトリとローカルリポジトリの状態を合わせる
検索かけている途中
[GitHubで編集したREADME.mdをローカルからgit push -fで上書きしてしまった場合の元に戻し方](https://hackmd.io/@nat-chan/BJrugld1_)

という記事を見つけ、まさに自分もこうなるところだった。
（READMEファイルで大した変更はかけていないですが手間には変わりないので）
とりあえず `$git pull origin ブランチ名`を行いリモートとローカルの状態を合わせる。

### 3.デフォルトユーザーからGitのユーザー名に変更する
そしていよいよユーザー名変更。
こちらの記事[GitのCommitユーザを修正する方法](https://qiita.com/y10exxx/items/dcea0e39788d649ca8ba)に倣い一度確認すると今回の場合はデフォルトユーザーのため
`user.name EC2 DefaultUser/user.email　（出力なし）`
となっていた。
それぞれGitHubの設定画面などから情報確認して修正。

もう一度それぞれ入力し確認すると、設定したアカウント名とメールアドレスが出力され変更されていることを確認。

### 4.歴史の改変の前にワンクッション🐶（リスク回避）
ユーザーの名前とメールアドレスを変更できたため、歴史を改変する前に一度普通に`git init`から始めて最新のものだけpushしてみる。（すべての歴史改変をいきなりするの怖かったので…）
すると最新のだけユーザー名が変わってた！（良いね）
```
$ git log -3
commit 30670c11dd43b697d0153d3ab54af9d39fd8037e (HEAD -> main, origin/main)
Author: *************************************
Date:   Wed May 3 09:21:26 2023 +0000

    [Add]デフォルトユーザー名になって草が生えていなかったため修正

commit a11f7cd593b805f3cbcfb850a518c9420f899c47
Author: ************************************
Date:   Sun Apr 2 23:31:28 2023 +0900

    Update README.md

commit 9948b7440b565dde15b4858704b7d2d6d7a72e69 (develop)
Author: EC2 Default User <ec2-user@ip-**************************>
Date:   Thu Mar 23 06:32:35 2023 +0000

    [Add]イメージサイズを200,150から200,300に変更
```

### 5.さぁ、過去を改変しよう！すべての歴史にユーザー名を反映して強制push
[【Git】 過去コミットのAuthorとCommitterを一括変更する【歴史改変】](https://zenn.dev/wabeshew/articles/ee9119a16e3458bbc3d7)に倣いユーザー名とメールアドレスを設定していく。

ただ、最初この`{{USERNAME}}`など変更するときに波括弧を消さないでやってしまったためまた違うアカウント名として反映されてしまった。

波括弧外して` $ git push -f origin ブランチ名`をやればしっかりGitのアカウントとして認識され、無事草も生えた。
![無事草生えた](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3203627/3d02014c-2413-6731-6067-27d2b52f86ac.png)

よかったよかった......😌

# おわりに（反省）
これが実務とかでチームで行っていたらもっと恐ろしいのかもしれない......

歴史改変、言葉としてはなんだか悪役っぽくてかっこいい響きだと個人的には思うものの、実務で起こさないように気を付けたい......
Databricksが提供する新たなエキスパート主導の大規模言語モデル(LLM)のedXコースに登録しましょう

[Enroll in our New Expert\-Led Large Language Models \(LLMs\) Courses on edX \- The Databricks Blog](https://www.databricks.com/blog/enroll-our-new-expert-led-large-language-models-llms-courses-edx)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

edXの[入門コース](https://www.edx.org/course/large-language-models-application-through-production)に登録しましょう！このコースは2023年の夏にスタートします。

# edXによる新たな大規模言語モデルコース

大規模言語モデルのアプリケーションが様々な業界を破壊するにつれて、生成型AIは重要な基盤技術となっています。LLMベースのアプリケーションの需要は鰻登りであり、それらを構築できるエンジニアに対する需要も同様なものとなっています。

本日、モダンなアプリケーションにおける言語モデルの構築と活用にフォーカスした史上初のエキスパート主導のオンラインコースである新たな[Large Language Models program](https://www.edx.org/professional-certificate/databricks-large-language-models)を発表できることを嬉しく思っています。業界のリーダーや研究者によるダイナミックな講義、デモ、ハンズオンラボを通じて、生徒はLLMアプリケーションの開発と本番運用への投入方法を学びます。また、生徒はDatabricksの[Dolly](https://www.databricks.com/jp/blog/2023/04/12/dolly-first-open-commercially-viable-instruction-tuned-llm)を含む基盤モデルの背後にある理論とキーとなるイノベーション、ファインチューニングの方法を学び、LLMを通じて容易かつ安価にビジネスに価値を付与することが可能となります。このコースでは、(LangChainを用いた)プロンプトエンジニアリング、エンベディング、ベクトルデータベース、モデルチューニングのようなLLM領域における最新の技術をカバーします。

LLMプログラムは2つのコースから構成されます: *LLMs: Application through Production*と*LLMs: Foundation Models from the Ground Up*です。コースにおける講師には、スタンフォード大学教授である[Matei Zaharia](https://cs.stanford.edu/people/matei/)や、DatabricksのDollyモデルを構築した技術チームが含まれています。AIの民主化という我々のゴールと一貫性を持って、コースのマテリアルは誰でも聴講することができます。また、生徒はコースのラボ、模擬試験、認定試験におけるマネージドの計算環境に対するわずかな費用を支払うことができます。
![](https://www.databricks.com/sites/default/files/inline-images/dolly_conv_blog_post.png)

最初のコースである[LLMs: Application through Production](https://www.edx.org/course/large-language-models-application-through-production)は、最新かつ最も人気のあるフレームワークを用いてLLM指向のアプリケーションを構築しようとしてる開発者、データサイエンティスト、エンジニアをターゲットとしています。さらに、これは以下のトピックをカバーします:

- Hugging FaceやLangChainのような人気のライブラリを用いたNLPにおける現実世界の問題にどのようにLLMを適用するのか。
- エンベディングとベクトルデータベースを用いてどのようにドメイン知識と記憶をLLMパイプラインに追加するのか。
- 事前トレーニング、ファインチューニング、プロンプトエンジニアリングにおけるニュアンスの理解と、カスタムチャットモデルをファインチューニングするためのその知識の応用。
- LLMの効率性とバイアスの評価方法。
- LLMワークフローにおけるLLMOpsとマルチステップ理由づけの方法。

二つ目のコースである[LLMs: Foundation Models from the Ground Up](https://www.edx.org/course/large-language-models-foundation-models-from-the-ground-up)は、トランスフォーマーベースのモデルの増加に繋がったキーとなるイノベーションと基盤モデルの詳細にダイブしようとしているデータサイエンティストをターゲットにしています。これは以下をカバーします:

- アテンション、デコーダー、エンコーダーを含む理論と基盤モデルがどのようにGPT-4に繋がったのか。
- LLMのパフォーマンスを維持しつつもサイズを削減するための、ワンショット、数ショット学習、知識蒸留のような転送学習技術の活用方法。
- 現行のLLM研究開発によって前進しているドメインはどこか。

プログラムの最後には、学習者は自身のエンドツーエンド、プロダクションレディのLLMワークフローを開発することになります。学習者はレジメやLinkedInで共有できるプログラムの認定試験のプロフェッショナル証書を受け取ることになります。

edXの[入門コース](https://www.edx.org/course/large-language-models-application-through-production)に登録しましょう！このコースは2023年の夏にスタートします。

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
脳卒中とはどんな病気？

「脳卒中」とは、脳の血管が破けたり、詰まったりして、その先の細胞に栄養が届かなくなり、脳の働きに障害が起きる疾患です。「脳血管障害」ともいわれます。
脳卒中は原因により、「脳の血管が詰まるタイプ（脳梗塞、一過性脳虚血発作）」と「脳の血管が破れるタイプ（脳出血、くも膜下出血）」の大きく2つに分けられます。
![fig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920958/cd92a36c-e78f-a9a8-0318-954581e75d95.png)
脳動脈の一部が詰まったり、破れたりする症状のことを言います。このような状態になって、血液が運ばれなくなると、半身麻痺や手足の麻痺、言葉を話すことができなくなったり、意識を失うなどの症状が出てきます。これが脳卒中、もしくは脳血管障害と言います。
脳卒中の患者は、とくに生活習慣病（高血圧、脂質異常症、糖尿病）を発症している方が多く、これらの症状はいずれも動脈硬化を進行させるので、脳卒中を招きやすくするのです。

一言で脳卒中と言いましても、脳血管に障害が起きた状態によって疾患名は異なります。
具体的には、脳の血管が詰まったり、狭まったことが原因の場合は脳梗塞、脳の中で脳の血管が破れて出血した場合は脳出血、脳の表面の大きな血管にできた瘤（脳動脈瘤）が破裂して、くも膜の下に出血した場合は、くも膜下出血と言います。この中で一番患者が多いのが脳梗塞で、脳卒中全体の約7割を占めます

脳の血管が詰まったり、狭まったりして血流が悪くなることで起きる疾患が脳梗塞です。ただ詰まるといいましても主に2つのタイプに分かれます。ひとつは、動脈硬化を起こして血管が狭くなり、やがて詰まっていく脳血栓症です。なお脳血栓症には、首や脳の比較的太い動脈で起きるアテローム血栓性脳梗塞、脳の細い血管が詰まることで起きるラクナ梗塞に分類されます。もうひとつが、心臓などでできた血のかたまり（血栓）が流れてきて脳の血管を塞いでしまう脳塞栓症です。このほかにも、一時的に脳の血管は詰まります が、すぐに血流が再開するという脳梗塞の前触れとして起きる一過性脳虚血発作もあります。
症状としては、いずれも同じで舌が麻痺して呂律がまわらない、体の片側の手足が麻痺する、しびれがなどです。検査及び診断をする方法としては、頭部MRI、CTなどを用いて診断するほか、心電図や血液検査も行います。
治療法については、脳梗塞を発症してから4～5時間以内であれば、t-PAという血栓を溶解する薬を用います。また、発症後時間が経過してしまったり、t-PAの効果が認められないと判断した場合は、手術やカテーテルを用いた血栓除去などが行われることがあります。さらに後遺症を抑えるために治療の早い時期からリハビリテーションも行います。

脳の中にある細かい血管が破れて出血している状態が脳出血です。高血圧の症状がある方に多く、高血圧で動脈硬化を進行させたことで血管が脆くなり、そこにさらに血流の圧力がかかることで血管が膨れ、やがて破れてしまうことで脳の内部に出血が起きてしまいます。主な症状としては、頭痛、めまい、吐き気や嘔吐、片方の手足の麻痺およびしびれ、しゃべりづらさ、歩きづらさなどがあります。診断では、頭部CTなどを用いて出血している場所は出血の量などを調べます。
治療については、命を失う危険のある場合は手術を行うこともありますが、多くの場合は薬物療法とリハビリになります。薬物治療では、降圧薬や出血で腫れた脳のむくみを取る薬を処方します。リハビリでは、しびれや麻痺などにより動かしづらくなった手足やしゃべりづらさを解消することを目的に行います。このほか、高血圧の治療も行います。

https://www.otsuka.co.jp/health-and-illness/stroke/types/
https://www.yokohama-shintoshi.jp/brain/stroke.html
https://stemcellthailand.org/therapies/stroke-ischemic-hemorrhagic/
https://www.toyoko-stroke.com/explain/stroke1.html
[Python3] Zen of Python

メモ:
pythonでimport thisするとPythonを書く上での基本原則を表示することができる

```shell
 % python
Python 3.8.15 (default, Oct 11 2022, 21:31:25) 
[Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```
CSS でボックスを横に並べるのに top,left を使ってダメだった話

ボタン2つを左に、黒いボックスを右に配置しようと安直に作ったら


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/4a81235a-df33-69c6-260e-1e106dfdd9c3.png)

微妙にずれているし、コンテンツが無いのに右側にスクロールバーが出てしまいました。

さくっと直しましたが一応記録。

# 環境

- Google Chrome 103.0.5060.114
- Ubuntu Linux 20.04 LTS


# コード

html:

```
<!DOCTYPE html>
<HTML>
<HEAD>
<META CHARSET="UTF-8">
<link href="style.css" rel="stylesheet">
</HEAD>
<BODY>
<DIV class="controls">
<DIV class="button1">
<FORM ACTION=. METHOD=POST>
<INPUT TYPE=SUBMIT VALUE="" >
</FORM>
</DIV>
<DIV class="button2">
<FORM ACTION=. METHOD=POST>
<INPUT TYPE=SUBMIT VALUE="" >
</FORM>
</DIV>
</DIV>
<DIV>
<DIV class="status">
</DIV>
</DIV>
</BODY>
</HTML>

```

style.css:
```
.status{
border: 3px solid #0000FF;
width: 100px;
height: 200px;
position:relative;
background-color:#000000;
top:-200px;
left:100px;
}


.button1 input[type="submit"]{
width:100px;
height:100px;
border: 1px solid #FF0000;
border-radius: 18px;
outline:none;
box-shadow:0 0 0 0 0;
}


.button2 input[type="submit"]{
width:100px;
height:100px;
border: 1px solid #00FF00;
outline:none;
box-shadow:0 0 0 0 0;
}


```


としています。安直に黒のボックスを以下のように指定していますが、根本的に間違っているようです。。
```
top:-200px;
left:100px;
```

# 解決

top,left 指定をやめて float:left で指定しました。


```

.controls {
   float: left;
}
.status {
   float: left;
}
.status{
border: 3px solid #0000FF;
width: 100px;
height: 200px;
position:relative;
background-color:#000000;
}


.button1 input[type="submit"]{
width:100px;
height:100px;
border: 1px solid #FF0000;
border-radius: 18px;
outline:none;
box-shadow:0 0 0 0 0;
}


.button2 input[type="submit"]{
width:100px;
height:100px;
border: 1px solid #00FF00;
outline:none;
box-shadow:0 0 0 0 0;
}


```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/3a5e2a6a-e1ea-62fb-c3c5-25c2ecd05b1a.png)
うまくいきました。
ブラウザゲームを作ってみよう(その14:サンプルゲーム作成その7)

# はじめに
[その13](https://qiita.com/noji505/items/1c6c614a1333d08d8b43)ではサウンド再生のサンプルを行いました。
今回はサンプルゲームにサウンド処理を組み込んでみたいと思います。

# 追加サウンドについて
以下のサウンドを追加したいと思います。

| サウンド番号 | 説明 | 使用シーン |
|:-:|:-:|:-:|
| 1 | 決定音 | メニュー決定 |
| 2 | ゲームBGM(その1) | ゲーム中BGM |
| 3 | ゲームBGM(その2) | ゲーム中BGM | 
| 4 | コイン取得 | コイン取得 |
| 5 | 失敗音 | コイン取得失敗 |
| 6 | ランクイン | ランクイン時 |
| 7 | ランク外 | ランク外だった時 |

ゲームBGMは2曲用意し、開始時にどちらかをランダムで再生するようにします。

# サウンドファイル指定について
前回のサンプルでは、playAudio( 0, false )といった形で番号で指定していましたが
変数にした方が分かりやすいので以下のようにしました。

```javascript:サウンドファイル指定
const AUDIO_KETTEI = 0;
const AUDIO_BGM_01 = 1;
const AUDIO_BGM_02 = 2;
const AUDIO_COIN = 3;
const AUDIO_MISS = 4;
const AUDIO_RANKIN = 5;
const AUDIO_RANKOUT = 6;

playAudio( AUDIO_KETTEI, false );
```

このようにしておくことで、指定ミスをしにくくなるのと、
途中でサウンドファイルの順番を変更した際に上記の変数の番号だけ変更すれば対応可能になります。

# サンプル
今までのサンプルにサウンド処理を追加しました。

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="WNzgRgN" data-user="noji505" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/WNzgRgN">
  Qiita25_sample01</a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 最後に
今回はサウンド再生を追加しました。
BGMやSEが鳴るとゲームが華やかになりますね。
Webサイトではあまり使用することはないかもしれませんが、上手く使うとインパクトのあるサイトが作れると思います。
【GAS】Googleフォームで連携したスプレッドシートの行に関数をいれる

## 目的　
XLOOKUPでslack シートのB列のユーザー名に対応したD列のclassの値を取得したい
Googleフォームとスプレッドシートを連携すると、新しい行が追加されるため事前にセルにXLOOIUPなどの関数を事前にいれることができない

![1slack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2640876/f3fdefa6-6950-0636-3333-d2df8727cc5d.png)





## 実行したこと
GASを使い対象の行にsetFormulaで指定したセルに式を代入する

## コード
```javascript
function getClass(){
  //アクティブシート取得
  var sheets = SpreadsheetApp.getActiveSpreadsheet();
  
  //「"フォームの回答 1"」のシート情報を取得し「fmSheet」に代入
  var fm =sheets.getSheetByName("フォームの回答 1");
  

  //A列の最終行取得
  var fmlastRowA = fm.getRange(fm.getMaxRows(), 1).getNextDataCell(SpreadsheetApp.Direction.UP).getRow();

  //C列の最終行取得
   var fmlastRowC = fm.getRange(fm.getMaxRows(), 3).getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
  
  for (i=fmlastRowA; i<=fmlastRowC; i++){
  
    //値を入れたいセルを指定　最終行、O列
    var cell = fm.getRange(i, 15);
    
    //XLOOKUPで参照したいのでsetFormulaでXLOOKUPの関数をセルに入れる
    //検索するデータの列,探す範囲の列,参照で取り出したいデータの列
    cell.setFormula("=XLOOKUP(C:C,slack!B:B,slack!E:E)");
    
    //A列のフラグに文字を入力する
    fm.getRange(i, 1).setValue("SlackOK");

  }
}

```


## 結果
O列にslackのシートから値を取得できた
![2slack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2640876/44ac80c0-26cf-2aeb-8412-b82012cabd61.png)
【Swift】列挙型の省略表記

# はじめに
OSSのコードを見ていたら知らない文法で書かれていたので記録しておきます。

列挙型をIntに準拠させた時に使える技です。
かなり限定的です笑

# 基本形
```swift
enum SampleEnum: Int {
    case one = 1
    case two = 2
    case three = 3
    case four = 4
    case five = 5
    case six = 6
    case seven = 7
    case eight = 8
}
```

# 省略表記
```swift
enum SampleEnum: Int {
    case one = 1, two, three, four, five, six, seven, eight
}
```

# おわり
最初だけ指定すれば良いみたいです。
めっちゃ簡潔に書けるので便利です。
【SwiftUI】角丸のImageに枠線をつける

# 角丸じゃない写真の場合

これは簡単にできる。

```swift
struct BorderImage: View {
    var body: some View {
        Image("monkey")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 350)
            .border(.red, width: 10)
    }
}
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/d129791d-2b61-1b43-2fb3-3d7e898418e8.png" width="300">

# 角丸の写真の場合

角丸部分の`border`が消えてしまう。

```swift
struct BorderImage: View {
    var body: some View {
        Image("monkey")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 350)
            .border(.red, width: 2)
            .cornerRadius(50)
    }
}
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/b59292a8-ffcb-3640-97e4-003d8e9f5d7b.png" width="300">

# overlayを使って実現する

```swift
struct BorderImage: View {
    var body: some View {
        Image("monkey")
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 350)
            .cornerRadius(50)
            .overlay(
                RoundedRectangle(cornerRadius: 50)
                    .stroke(.red, lineWidth: 2)
            )
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2633746/fe716489-33ad-a0b1-5a01-5147121ec7bd.png" width="300">

# おわりに

写真は何の関係もないです。
@ObservedObjectについて学ぶべし

@ObservedObjectは、SwiftUIにおけるプロパティラッパーの一つです。@ObservedObjectを使うことで、ObservableObjectプロトコルに準拠したオブジェクトの変更を監視し、ビューの再描画をトリガーすることができます。

具体的には、以下の手順で@ObservedObjectを使用します

##### １、監視したいクラスや構造体を作成し、ObservableObjectプロトコルに準拠させます。このクラスや構造体は、ビューで使用されるデータや状態を保持。
### その際には@Published var という形で変数を宣言します。

```swift
class MyData: ObservableObject {
    @Published var count = 0
    
    func increment() {
        count += 1
    }
}
```



##### ２、ビュー内で@ObservedObject属性を使用して、監視したいオブジェクトを宣言します。
```swift
struct MyView: View {
    @ObservedObject var myData = MyData()
    
    var body: some View {
        VStack {
            Text("Count: \(myData.count)")
            Button("Increment") {
                myData.increment()
            }
        }
    }
}
```


##### ３、@ObservedObject属性を使うことで、ビューはmyDataオブジェクトの変更を監視し、その変更があった場合にビューを再描画します。
上記の例では、MyDataクラスをObservableObjectプロトコルに準拠させています。その中には、@Published属性が付けられたcountプロパティと、そのプロパティを変更するincrementメソッドがあります。

MyViewでは、@ObservedObject属性を使ってmyDataオブジェクトを宣言しています。これにより、ビューはmyDataの変更を監視し、countの値が変更されるたびにビューを再描画します。ボタンをタップすると、incrementメソッドが呼ばれてcountの値が増え、ビューが再描画されて新しい値が表示されます。

@ObservedObjectは、オブジェクトの変更を監視するための重要な機能であり、データの変更をリアルタイムに反映させるのに役立ちます。

以前学習した、@Stateの場合は、@Bindingで渡していましたが、＠ObservedObjectの場合は、インスタンスで渡してあげると全てのデータまとめて渡すことができます。


#### @Bindingとの使い分け

一旦おさらい。

@ObservedObjectは、ビューが特定のオブジェクトの変更を監視するために使用されます。監視するオブジェクトは、ObservableObjectプロトコルに準拠している必要があります。
一般的に、@ObservedObjectはビューとオブジェクトの間の一対多の関係を表します。つまり、ビューが1つのオブジェクトを監視し、そのオブジェクトの状態変化に応じて再描画を行います。

### 使い分けの例：

親ビューから子ビューに値を渡す場合は、@Bindingを使用します。子ビューが値を変更すると、親ビューにも反映されます。
親ビューが特定のオブジェクトの変更を監視する場合は、@ObservedObjectを使用します。オブジェクトの状態が変化すると、ビューが再描画されます。
要約すると、@Bindingは値の双方向の通信に使用され、ビュー間の関係を表現します。一方、@ObservedObjectはオブジェクトの変更を監視し、ビューを再描画するために使用されます。適切なプロパティラッパーを選択することで、データフローとコミュニケーションの効率性を高めることができます

最初は@Bindingなのか@ObservedObjectのどちらを使えばいいのかわかりませんでしたが、アプリを作るうちに少しずつ慣れてきた気がします。SwiftUI独自の宣言方法に慣れる必要がありますね。
HackTheBox v4 APIの基本的な使い方

## HackTheBox API
HackTheBox(HTB)自体は割と有名？なので知っている人は多そう。。
んで、一応HTBにもAPIはあってユーザ情報を取得したり色々出来る。
↓以下は公式doc↓
https://documenter.getpostman.com/view/13129365/TVeqbmeq

## 使い方
色々と沼ったわけだが、
どこで沼ったかをグダグダ書くよりも先に結論から書いておくと動いたコードは以下。
今回は該当ユーザーの接続状態を取得するEPを叩いてみた。
`python
import http.client
import json

# ログイン情報を設定する
login_payload = {
    'email': 'ログイン用メールアドレス',
    'password': 'ログイン用パスワード',
    'remember':'true'
}

# ログインリクエストを作成する
login_conn = http.client.HTTPSConnection("www.hackthebox.com")
login_headers = {
    'Content-Type': 'application/json'
}

login_conn.request("POST", "/api/v4/login", json.dumps(login_payload), login_headers)

# ログインレスポンスからトークンを取得する
login_res = login_conn.getresponse()
login_data = login_res.read()
login_json = json.loads(login_data.decode("utf-8"))
auth_token = login_json['message']['access_token']

# ログイン後にAPIにアクセスするリクエストを作成する
api_conn = http.client.HTTPSConnection("www.hackthebox.com")
api_headers = {
    'Authorization': f'Bearer {auth_token}'
}

# 使用したいエンドポイント
api_conn.request("GET", "/api/v4/user/connection/status", headers=api_headers)

# APIからのレスポンスを取得する
api_res = api_conn.getresponse()
api_data = api_res.read()
print(api_data.decode("utf-8"))
`
出力結果↓
`
{"status":"0","connection":"not connected"}
`

こんな感じなんかな

## どこで沼ったか
実行したいAPIを呼ぶ前処理がよく分からんかった。
`python
# ログイン後にAPIにアクセスするリクエストを作成する
api_conn = http.client.HTTPSConnection("www.hackthebox.com")
api_headers = {
    'Authorization': f'Bearer {トークン情報}'
}

# 使用したいエンドポイント
api_conn.request("GET", "/api/v4/user/connection/status", headers=api_headers)

# APIからのレスポンスを取得する
api_res = api_conn.getresponse()
api_data = api_res.read()
print(api_data.decode("utf-8"))
`
最初は上記のような感じでこれだけやって実行すればいいんじゃないの？と思っていた。
んで、トークン情報はマイページの以下の情報貼ればいいんかなって。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355973/e374792c-edb1-4663-1c60-f1a40f4d839b.png)

ただ、そういうわけではないっぽい？？
必ず、初めにログインリクエストを実行してレスポンスで得られたトークンを使って呼ぶっぽい。

2時間位沼ったー。
Rによる統計的学習入門　演習解答 【2章・理論編】

# はじめに

最近「Rによる統計的学習入門」を読み始めました。各章の最後に演習問題が用意されているので、自身の解答の備忘もかねて、記事として残しておきます。
ご参考になれば幸いです。
また、間違い等ありましたらコメントいただけるとありがたいです。

# 2章演習問題（理論編）
__※問題文は載せておりません__

(1)
a)
　柔軟な統計的学習法
　十分なデータがある場合は、柔軟でない方法より柔軟な方法の方が優れたfitとなる

b)
　柔軟でない統計的学習法
　　小さなデータセットの場合、柔軟なモデルover fitを起こして、汎化性能が下がる可能性が高い

c)
　柔軟な統計的学習法
　線形回帰のような柔軟でないモデルでは非線形を表現することは難しいため、非線形の関係に対しては、柔軟な手法が適している
　
d)
　柔軟でない統計的学習法
　柔軟なモデルでは、誤差項に含まれているノイズに対して過剰にfitしてしまい、分散が大きくなる

(2)
a)
　回帰問題　n:500社分のデータ　p:利益、従業員数、業界の3つの変数
b)
　分類問題　n:20この過去事例データ　p:製品の価格、マーケティング費用、競合製品の価格を含む13個の変数
c)
　回帰問題　n:2012年の52週分のデータ　p:アメリカ、イギリス、ドイツの3つの株式市場の上下割合

(3)
a)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660703/af52bfdf-6b8e-c48d-953a-2aebe283fb68.png)

b)
　訓練誤差：自由度が増すに連れて、データに対する適応具合も向上するため、訓練誤差は自由度に伴って減少する
　二乗バイアス：バイアスは学習において前提とした仮定に対する誤差となるため、自由度が増すに連れて減少する
　分散：分散は異なる訓練データにより、学習モデルがどの程度変化するかを示している。自由度が大きくなるほど、データに対して良く適合することを考えると、自由度の増加に伴って分散は大きくなる。
　ベイズ誤差：データ自体が内包する誤差のため、自由度によらず一定の値を取る
　テスト誤差：テスト誤差は二乗バイアスと分散、ベイズ誤差の和となり、どれだけ誤差を最小化してもベイズ誤差を下回ることはなく、U字の形をしている。

(4)
a)
デフォルト予測　過去の入出金データをもとにデフォルトするかどうかを予測する
異常検知　製品の画像をもとに異常があるかどうか判定を行う
大学への入学推定　現在の学力データをもとに大学への入学可否を推定する。推定によって、各学力データの効果量を測り、改善可能性を探る。

b)
農作物の収穫量予測　生育データやハウス内の環境データ、気象データなどを説明変数として収穫量を予測する
需要予測　流通データなどからトレンドを予測する
賃貸価格の予測　間取り等の賃貸情報から適正価格を推定する

c)
顧客データのクラスタリング　顧客の購買データをクラスタリングにより分割し、戦略立案に活用する
患者データのクラスタリング　患者データをクラスタリングにより分割し、病気と患者情報との関連性を探る
製品データのクラスタリング　不良製品を含んだデータをクラスタリングにより分割し、不良の原因を探る

(5)
柔軟な手法は、複雑な関数を近似できるが、一方で少数データやノイズの大きなデータに対してはover  fitしてしまう問題がある。データが豊富にあり、予測精度が求められる場合においては柔軟なアプローチが優れている。一方で説明性を求められる場合や、データのノイズが大きい場合、データが少ない場合には柔軟でないアプローチが優れている。

(6)
パラメトリック法はfを推定するために、"線形"のように仮定を置く。その仮定のもとでデータからfを推定する方法となる。一方でノンパラメトリック法は特にfについて仮定を置かず、なめらかにデータに適合するfを推定する。
パラメトリック法の場合、解釈性が高いという利点があるため、推論が目的である場合、優れた方法となる可能性がある。一方で、パラメトリック法はfを推定する過程で、制約を持たせているため、その制約の外に関しては上手くfで表現することはできない。

(7)
a)
1:3 
2:2 
3:√10 
4:√5
5:√2 
6:√5 

b)
5のgreen

c)
最も近い点を3つ取得すると、5のgreen,2のred,4のgreen,6のred(4,6は同じ距離)となり、greenとredの確率が同じとなる。そのため、最も近い点で判断すると、5のgreenとなる。

d)
Kが大きくなるにしたがって、決定境界の柔軟性は下がる。そのため、決定境界が非線形である場合はKは小さい方が適している。

# 2章演習問題（応用編）
RではなくPythonで解答を作ってみています。

[2章演習問題 jupyter notebook](https://github.com/ShinyaT1994/ISLR/blob/master/notebook/section2.ipynb)

# 参考文献

[[1]Rによる 統計的学習入門](https://www.amazon.co.jp/R%E3%81%AB%E3%82%88%E3%82%8B-%E7%B5%B1%E8%A8%88%E7%9A%84%E5%AD%A6%E7%BF%92%E5%85%A5%E9%96%80-Gareth-James/dp/4254122241/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1KWVPQDHHQDVR&keywords=r%E3%81%AB%E3%82%88%E3%82%8B%E7%B5%B1%E8%A8%88%E7%9A%84%E5%AD%A6%E7%BF%92%E5%85%A5%E9%96%80&qid=1683116314&sprefix=r%E3%81%AB%E3%82%88%E3%82%8B%E7%B5%B1%E8%A8%88%E7%9A%84%E5%AD%A6%E7%BF%92%E5%85%A5%E9%96%80%2Caps%2C206&sr=8-1)

# 最後に

最後まで読んでいただきありがとうございます。
今回は2章の解答でした。
次回は3章の解答を作成しようと思います。
Laravel の Collection クラスに重複を削除するメソッド deduplicate() を追加する拡張機能を作った

# laravel-collection-deduplicate

## 機能概要

php 7.4 以上
Laraevel 8.0 以上

Collection クラスの重複を削除するメソッド deduplicate() を追加します。

## 既存メソッド unique() と uniqueStrict()

コレクションの重複を削除するメソッドとして、既に [unique()](https://readouble.com/laravel/10.x/ja/collections.html#method-unique) や [uniqueStrict()](https://readouble.com/laravel/10.x/ja/collections.html#method-uniquestrict) が用意されています。この２つのメソッドは、ネストした配列やオブジェクトを取り扱いたい場合、一意であることを決めるキーを指定する必要があります。

## unique(), uniqueStrict()

### example

```php
$collection = collect([
    ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
    ['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'phone'],
    ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'],
    ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
    ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'],
]);

// 'brand' キーで重複を判断し削除する
$unique = $collection->unique('brand');

$unique->values()->all();

/*
    [
        ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
        ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
    ]
*/
```

指定したキーの値さえ一致していれば、他のキーが一致していなくても重複として削除されてしまいます。

一意であることを決めるキーを指定するのではなく**配列の中身が完全に一致しているとかオブジェクトのプロパティや値が完全に一致しているとか**そういう場合に削除して欲しいんです…！！！！


と言いましても無いものは仕方ありませんので、そういう重複を削除できるメソッド deduplicate() メソッドをコレクションクラスに追加する拡張機能を作りました。


## deduplicate() メソッド

全てのキーやプロパティの値が一致していれば重複として削除します。

### example
```php
$collection = collect([
    ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
    ['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'phone'],
    ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'],
    ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
    ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'],
    // 1つ目のキーと全く同じ配列を格納しまくる
    ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
    ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
    ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
]);

$deduplicate = $collection->deduplicate();

$deduplicate->values()->all();

/*
    [
        ['name' => 'iPhone 6', 'brand' => 'Apple', 'type' => 'phone'],
        ['name' => 'iPhone 5', 'brand' => 'Apple', 'type' => 'phone'],
        ['name' => 'Apple Watch', 'brand' => 'Apple', 'type' => 'watch'],
        ['name' => 'Galaxy S6', 'brand' => 'Samsung', 'type' => 'phone'],
        ['name' => 'Galaxy Gear', 'brand' => 'Samsung', 'type' => 'watch'],
        // 以降3件は1つめのキーと同じ値のため、重複として扱われ削除される
    ]
*/
```

※サンプルは配列を格納して比較していますが、格納されているのがオブジェクトでも数値でも文字列でも問題なく動作します。

## 使い方

composer でインストールするだけ。
Collection クラスに deduplicate() メソッドが追加されます。

```bash
composer require kanagama/laravel-collection-deduplicate
```



## github
https://github.com/kanagama/laravel-collection-deduplicate

## packagist 

https://packagist.org/packages/kanagama/laravel-collection-deduplicate
Spring Validationの実装

# Validation機能
WEBアプリケーションにおいて、POSTするリクエスト内の相関チェックを行いたい場合、使用する。

## 実装手順
1, プロジェクト管理ツール（Maven、Gradle）のdependencesにvalidationの依存関係を追加する。
2, 相関チェックしたいFormの項目に、アノテーションを付与し実装する。
~~~ java
@Data
public class IssueForm {

    @NotBlank
    @Size(max=256)
    private String summary;

    @NotBlank
    @Size(max=256)
    private String description;

}
~~~

3,Controller側のフォーム内容を受け取るメソッドにて、バリデーション処理を実装する。

* @Validated
Formクラスに付与している相関チェック内容を受け取り時に適用する。
* BindingResult
相関チェック結果を格納する。
下記例では、エラー時に入力画面に遷移するように処理を実装。

~~~ java
    @PostMapping
    public String create(@Validated IssueForm form, BindingResult bindingResult, Model model){
        if(bindingResult.hasErrors()){
            return showCreationForm(form);
        }
        issueService.create(form.getSummary(),form.getDescription());
        return "redirect:/issues";
    }
~~~

4,
ubuntu20.04  ROS1 Noetic install memo

ROS1(Ver.Noetic) install
=

    sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

    sudo apt install curl 　　　　　　# if you haven't already installed curl

    curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

    sudo apt update

    sudo apt install ros-noetic-desktop-full
op:apt search ros-noetic

    sudo apt-get install python3-rosdep
    #sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator 

    python3-wstool build-essential
    #sudo apt install python3-rosdep

    sudo rosdep init

    rosdep update

    echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc

    source ~/.bashrc

    source /opt/ros/noetic/setup.bash

    sudo apt-get -y install python3-rosinstall

    sudo apt-get install -y python3-catkin-tools

test
=
ターミナル1>> 
    
    roscore
ターミナル2>> 
    
    rosrun rospy_tutorials talker.py
ターミナル3>> 
    
    rosrun rospy_tutorials listener.py

make work space
=
    
    mkdir -p catkin_ws/src

    cd catkin_ws/src

    catkin_init_workspace

create pkg
=
~~~~~~~~~~~~~~~~~
cd catkin_ws/src

catkin_create_pkg pkg_name depend

exp.:catkin_create_pkg my_robot std_msgs rospy roscpp
~~~~~~~~~~~~~~~~~
The depend selection will be written to "package.xml" and "CMakeLists.txt",effect building or running.

![Screenshot from 2023-05-07 19-08-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3181208/484f91ed-07f2-604c-33d0-61ad9a438c99.png)

###########finish
Rustで一時ディレクトリを扱う

現在フリーランスエンジニアとして活動していて、今今携わっている案件ではRustとTauriを使ってExcelファイルを出力するデスクトップアプリを開発しています。

予め環境変数にファイルの出力フォルダを設定することで、Excelファイルの出力機能で出力フォルダを取得しファイルを書き出します。

上記機能の自動テストを実装するために、一時ディレクトリを作成し、出力フォルダに作成したディレクトリを指定しています。一時ディレクトリを作成して指定するのは自動テストが完了したら作成したファイルを削除するためです。

今回Rustで一時ディレクトリを作成するために`tempfile`というクレート

https://docs.rs/tempfile/latest/tempfile/

と環境変数を設定するために`envtestkit`というクレート

https://docs.rs/envtestkit/latest/envtestkit/

を使用します。

早速、上記クレートを使用したCSVファイルを出力するサンプルコード（&テストコード）の載せます。

```:Cargo.toml
[dev-dependencies]
envtestkit = "1.1.2"
tempfile = "3.5.0"
```

```Rust:Rust
use std::{env, io};
use std::fs::File;
use std::path::PathBuf;

use csv::Writer;

fn write_csv() -> io::Result<()> {
    let export_folder = env::var("EXPORT_FOLDER").map_err(|_| {
        io::Error::new(io::ErrorKind::NotFound, "環境変数 EXPORT_FOLDER が設定されていません。")
    })?;

    // CSVファイルの出力先パスを生成
    let file_path = PathBuf::from(export_folder).join("output.csv");

    // CSVデータの例
    let records = vec![
        vec!["header1", "header2", "header3"],
        vec!["row1_col1", "row1_col2", "row1_col3"],
        vec!["row2_col1", "row2_col2", "row2_col3"],
    ];

    let file = File::create(&file_path)?;
    let mut writer = Writer::from_writer(file);

    for record in records {
        writer.write_record(record)?;
    }

    writer.flush()?;
    Ok(())
}

fn main() -> io::Result<()> {
    // CSVファイルにデータを書き込む
    write_csv()?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use io::prelude::*;
    use std::ffi::OsString;

    use envtestkit::lock::lock_test;
    use envtestkit::set_env;
    use tempfile::tempdir;

    use super::*;

    #[test]
    fn test_should_write_csv_when_export_folder_is_set() -> io::Result<()> {
        // Arrange
        // テストための一時フォルダを作成
        let temp_dir = tempdir()?;
        let _lock = lock_test();
        // 環境変数に作成した一時フォルダのパスを指定
        let _test = set_env(OsString::from("EXPORT_FOLDER"), temp_dir.path().to_str().unwrap());
        let file_path = temp_dir.path().join("output.csv");

        // Act
        write_csv()?;

        // Assert
        let mut file = File::open(&file_path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let expected_contents = "header1,header2,header3\nrow1_col1,row1_col2,row1_col3\nrow2_col1,row2_col2,row2_col3\n";
        assert_eq!(contents, expected_contents);

        // Cleanup
        temp_dir.close()?;
        Ok(())
    }
}
```

上記テストコードを実行すると、`/var/folders/sj/gd26nn_j6hs40wglhq7flq9r0000gn/T/.tmp1dapCq/output.csv`のように一時ファイルを作成してテストが完了したらファイルを削除します。

以上で自動テストを実行することで無駄にファイルが残ってしまうのを防止できるようになりました。
VOICEVOXのRuby版を動かしてみた

## はじめに - VOICEVOXとは

日本語を喋らせることができるソフト。Rustで実装されている。内部では[ONNXRuntime](https://github.com/microsoft/onnxruntime)とか走っているようだ。

https://ja.wikipedia.org/wiki/VOICEVOX

https://github.com/VOICEVOX/voicevox_core

## Ruby版 - voicevox.rb

[sevenc-nanashi](https://github.com/sevenc-nanashi) さんが作っている。[Ruby-FFI](https://github.com/ffi/ffi)を使っている。

https://github.com/sevenc-nanashi/voicevox.rb

## インストール

VOICEVOXのインストール方法はクセが有る。今後も方法が変わるかもしれないので、最新の情報を当たってほしい。まず、公式からダウンローダーを入手する。そして、ダウンローダを実行すると必要なファイルが入手される。

具体的には[公式のREADME](https://github.com/VOICEVOX/voicevox_core)を読んでほしい。

#### Windowsの場合

```
Invoke-WebRequest https://github.com/VOICEVOX/voicevox_core/releases/latest/download/download-windows-x64.exe -OutFile ./download.exe
./download.exe
```

#### Linux/macOSの場合

```sh
binary=download-linux-x64
curl -sSfL https://github.com/VOICEVOX/voicevox_core/releases/latest/download/${binary} -o download
chmod +x download
./download
```

実行すると、`open_jtalk_dic_utf_8` `voicevox_core-linux-x64-cpu` がダウンロードされ、
`voicevox_core` ディレクトリが得られる。ひょっとすると他のプラットフォームでは異なるのかもしれないが、Linuxではこんな感じだ。

```
voicevox_core
├── libonnxruntime.so.1.13.1
├── libvoicevox_core.so
├── model
├── open_jtalk_dic_utf_8-1.11
├── README.txt
├── VERSION
└── voicevox_core.h
```

これのインストール方法であるが、`libvoicevox_core.so` は `libonnxruntime.so.1.13.1` に依存している。しかし、この2つの共有ライブラリだけコピーすると、modelがないと言われてしまう。何らかの環境変数による設定が可能なのかもしれないが、デフォルトでは `model` は `libvoicevox_core.so` と同じディレクトリに存在すると想定されているようだ。なので`/usr/local/lib` などにコピーでインストールするのはやめて、このディレクトリ適当な場所に配置した上で `LD_LIBRARY_PATH` に含めるのが良さそうでさる。

```sh
export LD_LIBRARY_PATH="/path/to/voicevox_core:$LD_LIBRARY_PATH"
```

実は今まであまり気がついていなかったのだが、Ruby-FFIは`LD_LIBRARY_PATH` で指定したディレクトリの中の共有ライブラリを見にいってくれるそうだ。知らなかった。筆者の自作のライブラリはもっぱらpkgconfigで `.pc` ファイルを見に行くことにより、共有ライブラリの位置を割り出すようにしていたので、`LD_LIBRARY_PATH` には対応できていないかもしれない。

個人的には、`vendor` ディレクトリの中に、共有ライブラリなどすべて必要なファイルを梱包して、GemにインストールできるようにするAnkaneさん方式のGemが好きなのだが、VOICEVOXは依存ファイルが多いため、その方式が難しいと思われる。またパッケージマネージャーを通した配布ではなく、`download`コマンドの実行という特殊な配布形式となっているため、現行の方法がまだ一番マシかもしれない。

それから openjtalk の場所も教えてあげる必要がある。この環境変数は正式なものがまだ決まっていないらしく、例えば次のようにする。

```sh
export OPENJTALK_DICT="/path/to/voicevox_core/open_jtalk_dic_utf_8-1.11"
```

これでexampleが動くようになる。

```sh
bundle install
bundle exec ruby examples/repl_wrapper.rb
```

この記事は以上です。良きRubyライフを！
rails7×docker立ち上げ時にCould not find ~ in locally installed gemsというエラーの解決方法

rails7とdockerを使って開発環境を立ち上げている時に起きたエラーでしょーもない事で無駄に解決せずにハマっていたのでタイトルのエラーが出た時の解決方法をメモとして書いておきます。
## エラー内容

```
#実行コマンド
docker-compose up
#エラー
Could not find sprockets-rails-3.4.2, pg-1.5.3, puma-5.6.5, importmap-rails-1.1.6, turbo-rails-1.4.0, stimulus-rails-1.2.1, jbuilder-2.11.5, bootsnap-1.16.0, debug-1.7.2, web-console-4.2.0, capybara-3.39.0, selenium-webdriver-4.9.0, webdrivers-5.2.0, sprockets-4.2.0, msgpack-1.7.0, irb-1.6.4, reline-0.3.3, bindex-0.8.1, addressable-2.8.4, regexp_parser-2.8.0, xpath-3.2.0, rubyzip-2.3.2, websocket-1.2.9, public_suffix-5.0.1 in locally installed gems
```

## 解決方法

```
docker-compose build
docker-compose up
```
`docker-compose build`をしたつもりですが、出来ていませんでした。
ちなみに、私の場合はなぜかキャッシュのせいで一発では解決しなかったので
`docker-compose build --no-cache`を実行しました。

## まとめ

docker大好き🐳
利用したサイトの備忘録

日々、いろんなサイトのサービスを利用していますよね。

弊社でも様々なネットサービスに登録していますが、今日はそれがどんな仕組みになっているのか

ファーストインプレッション程度の感想ですが、ここに殴り書きしてみようかなと思います。

・photAC
https://www.photo-ac.com/profile/24351565
ここは写真素材サイト。投稿者もオリジナルの写真がアップできて利用者も使える。ダウンロードは基本無料だが有料素材や制限なしのダウンロードサブスクなど用意。提供側もこのプラットフォームを使ってオリジナル写真の販売が可能。

・activo
https://activo.jp/users/115924
ボランティア募集サイト。無料でボランティアを募集できる。また企業であればインターン生の募集にも使える。サイト自体はPRなどを有料でできるようだ。ただし、ボランティアという性質上、マネタイズに少し苦労するか？

・こくっち
https://kokutch.tomiryu.com//pr/erunet/7362.html
かなり古いテイストのサイト。実際に歴史は長い。無料でなんでも告知できる掲示板。さっきのボランティアサイトもそうだが、こうしたサイトで今一番稼働しているのはジモティかな？最近資金調達したような話しも聞いたような？

BLOG RANKING
https://blog.with2.net/blog/2101598
ブロガーの間では、アクセスがもらえることで有名なブログランキングサイト。2000年くらいまではこうしたランキングサイト流行ってたよね。それもSNSの台頭もあり、昔ほどの勢いはない？「逆アクセス」とかって言葉ももう死語になりつつあるのかもね。
JavaScript 分割代入

# JavaScriptの分割代入

## はじめに
JavaScriptの分割代入を備忘録として残しておきます。
自身React学習中でJavaScriptある程度できるつもりだったのですが、分割代入の動きをしっかりと把握できてなかったので改めて確認しましたのでアウトプットとして記事にさせていただきます。

## 分割代入とは
>オブジェクトや配列からプロパティを取り出し変数として定義し直す構文

上記が分割代入を簡単に説明したものです。
学習されている方であればなんとなくわかるかと思いますが、初学者が分割代入使われたソースコード見てしまうとパニックです、、、
少なくとも私は最初パニックでした、、、
```react:App.jsx
//propsでvalue1とvalue2を引数に分割代入しアロー関数を使用している。
const Square = ({value1, value2}) => {
  return (
    <>
      <p>{value1}</p>
      <p>{value2}</p>
    </>
  );
}
```
Reactでは上記のような分割代入とアロー関数を使った変数や関数式がよく出てきます。
JavaScriptのこのような文法理解がないと苦労します。。。
({value1, value2})この部分が分割代入になります。
## 分割代入を確認してみる
[参考資料：JavaScriptPrimer](https://jsprimer.net/basic/function-declaration/)
下記のようなシンプルな関数userIdがあり、引数にuserオブジェクトを受け取ります。
そして、関数内でconsole.logでuser変数のidを表示するという関数です。
```javascript:index.js
function userId(user) {
    console.log(user.id);
}
const user = {id: 1};
userId(user);
```
上記を分割代入行うと引数として受け取ったuserオブジェクトのidプロパティをid変数として再定義しております。

```javascript:index.js
// 第1引数のオブジェクトから`id`プロパティを変数`id`として定義する
function userId({ id }) {
    console.log(id);
}
const user = {id: 1};
userId(user);
```

分解してみると下記の定義をしているのと同意義になります。
```javascript:index.js
const { id } = user;
```
このようにプロパティが増えても問題ありません。また配列も可能になっています。
```javascript:index.js
function userId({ id, name }) {
    console.log(id);
}
const user = {id: 1, name: alice};
userId(user);
```

## おわりに
下記参考資料になります。非常にわかりやすいのでご一読お勧めいたします！
[参考資料：JavaScriptPrimer](https://jsprimer.net/basic/function-declaration/)
まだまだ駆け出しから抜け出せません、、、
早く一人前になりたいですね、、、、
【RDB】選択肢リスト保存の最適解

:::note
本記事は、選択肢リストの保存方法について紹介します。
:::

# はじめに
選択肢リストとは、範囲や選択肢が限定された値のことです。例えば、"Active"・"Deleted" といったユーザーの会員状態や、"東京都"・"千葉県"など都道府県のことを指します。

本記事では、ユーザーの会員状態の保存を例に、選択肢リストの値をRDBに保存する複数の方法と、それぞれのメリット・デメリットについて紹介します。

# 1. マスタテーブルを作成する
**データの厳密性が必要な場面で強みを発揮する方法です。** マスタテーブルとは、システムの運用上で必要な情報が格納されたテーブルのことです。今回の例では、会員状態のリストがこれにあたります。親テーブル側では、マスタテーブルの外部キーIDを保存します。

![スクリーンショット 2023-05-01 101920.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2147470/b0f934c4-f9cc-5a00-d296-93dbf25748d4.png)

**この方法のメリットは、データの厳密性を担保出来ることです。** 外部キー制約を用いることにより、意図しない値の混入を防ぐことが出来ます。また、マスタテーブルにカラムを追加することで、追加情報を加えることも出来ます。都道府県の場合、関東・東北といった地域情報がこれにあたります。

**一方、デメリットはパフォーマンス面で若干劣る点です。** この方法では、データ取得や保存をする際に親テーブルとマスタテーブルの両方を読み込む必要があります。また、絞り込みを行う場合、親テーブルとマスタテーブルを結合しなければなりません。親テーブルからマスタテーブルへの参照が増えていくと、段々とパフォーマンスが悪くなり、さらにアプリ側のコードも複雑になる可能性があります。

## 2. アプリ側で選択肢リストを定数化する
**パフォーマンスを優先したい場面で、強みを発揮する手法です。** ymlや連想配列などを使用して、アプリ側に選択肢リストを定数として持たせるようにします。データベースに保存する際には、アプリ側で選択肢を数値に変換したものを保存します。

![スクリーンショット 2023-05-01 104311.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2147470/12544ced-119e-6370-f4da-70553a9339f1.png)

**この方法のメリットは、パフォーマンスに優れることです。** データの保存や取得の際にデータベースへのアクセスが不要なため、先程の方法よりも高速です。

**一方、デメリットは厳密性と変更のしにくさです。** 外部キー制約が使えないため、データベースレベルで不正な値が入る可能性を許容してしまいます。また、複数のアプリで同じリストを使いたい場合、それぞれが別々に定数を管理しなければならず、変更の際は一貫性が崩れないよう注意しなければなりません。

# 3. 履歴テーブルを作成する
**リストの変更履歴を記録したい場面で強みを発揮する手法です。** これまで紹介した１と２のどちらの方法も、状態の変更履歴を保存することは出来ませんでした。そこで、テーブル構造を行持ちにすることで、リストの値を変更するたびにレコードが作成されるようにします。

![スクリーンショット 2023-05-01 103102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2147470/f289944c-a9c1-5bf1-2ce9-5cfd769d2cb7.png)


**この方法のメリットは変更履歴を追跡出来ることです。** 配送状態など、そもそもリスト値の遷移がアプリ側で必要な場合もありますし、他にもトラブルシューティングや統計取得の際にも、変更履歴は役に立つことがあります。

**一方、デメリットは設計が複雑なこととパフォーマンスが悪いことです。** まず、この方法はテーブル数が多くなります。加えて、アプリ側で履歴テーブルを上手く取り扱うための処理が必要になります。また、レコード数が漸進的に増えていきますので、段々とパファーマンスも悪化していく傾向にあります。

## 4. カラムに直接値を保存する
**簡単な反面、欠点も多い方法です。** 選択肢リストの値を親テーブルに直接保存します。

![スクリーンショット 2023-05-01 103429.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2147470/fa26484e-048e-dfe6-423b-fb2fe851ee95.png)


**この方法のメリットは、設計がシンプルなことです。** 選択肢リスト用のテーブルを作成する必要がないため、テーブル数は最小限で済みます。また、保存される値が文字列なので見やすくはあります。

**一方、デメリットは、柔軟性に欠けることです。** 選択肢リストの値が変更された場合、関連する親テーブルのレコードを一括更新しなければなりません。また、カラムに制約が存在しないため、意図しない値が混入するリスクがあります。データベースによっては、Enum型やCheck制約などが使用出来ますが、SQLアンチパターンでもあるため扱いには注意が必要です。

# まとめ
**大切なのは、選択肢リストの用途に応じて適切な手法を選択することです。** どの方法にも何かしらのデメリットは存在します。ですので、何が必要で、何を犠牲にしてもいいのかを考えて設計手法を選択するようしましょう。
学校の先生はスクラムマスター!?、学級運営はスクラム!?異業種からの転職だからこそ気付ける視点だってあるのだから自信を持つんだ！

どうもエンジニア２年目を迎える元教員です。

https://note.com/hajimari_nagano/n/nd39730300afc?from=notice

この記事は

「チームに異業種からのエンジニアに転職した人がいる人」
「採用担当者」
「教育に興味ある人」

に読んでほしいなと思います。

今の会社に入って「アジャイル」って言葉をよく耳にするようになりました。

「スクラムマスター」と名乗る組織作りのプロが居たりと興味を抱いたこの頃・・・。

そこで色々書籍を読んだのですが

**スクラムマスターがやっていることってクラス運営と同じやん！！**

これが感想でした。

# 今回のまとめ

忙しい人のため、先に結論です。

**「教員はスクラムマスターに向いている。ただ最低限の技術はちゃんと学べ」**
**「これからの世代からがスクラム人材豊富」**
これでこの記事閉じてもらっても良いですが詳細気になる方いれば・・・・・・

# 現在の学校教育
昔は学級運営もトップダウン思考が強く、

**生徒は先生の言うことを絶対に聞く！！**

って風潮がありました。
おそらく軍国主義的なところから根付いたのだと思います。
これはトップダウン的な側面のあるウォーターフォール型の開発に似ているのではと思います。

しかし教育は変わりつつあります。
今の学習指導要領では
- **「知識及び技能」**
- **「思考力、判断力、表現力等」**
- **「学びに向かう力、人間性等」**

この３点に趣きを置いています。
昔は **「点が取れれば優秀である」** というイメージが強くありました。しかし現在はそのこと以上に
「自分で考え、どのように行動していったか」
というプロセスが重要視されています。
この高校での変化と共に大学入試も変わりつつあります。
今では「総合型選抜（昔のAO入試）」が広がりつつあります。
この試験で「この子はどのように考え、高校生活を歩んできたのか」という点が評価されるようになりました。
結果よりプロセスが評価される時代になったのです。
**「探究学習」「アクティブラーニング」**
そんな言葉をメディア等で耳にしたことないでしょうか？
これらが変化した学習体系の一例となります。

https://shiruto.jp/global/3897/



一般職に転職して気づいたのですが、学生時代に重要視されていた項目が変わりつつあることを一般企業が知らないケースが多いようです。
「私の学生時代はこうだったから」
の考え方は通用しない子達が社会へ飛び出していることを人事や採用担当者は感じ取るべきだと思います。

# 現在の教員の姿勢

生徒へ身につけてほしい力が変わったことで、教員のやるべきことも変わりつつあります。

・その子がどういう子なのかを見極める
・やりたいことがある場合は、実現可能なようにサポート
・クラスや集団行動ではその子の力を発揮できるように、適材適所へ配置できるように促す。
・できる限り表には出ず、陰でサポート（サポートされている感がないのがベスト）

簡単に言うと担任はクラスメンバーが動きやすいようにサポートするのが仕事となります。ティーチングというよりコーチングの要素が強くなりつつあります。
こちらの記事でコーチングとティーチングの違いについてわかりやすく説明されています。

https://qiita.com/rf_p/items/2480ad77c856e42b19b3

３０人以上の集団であるクラス内で、それぞれの強みが活かせるようにコーチングしていく必要があるのです。
強制力を働かしすぎてもダメ
何もしない子を作ってもダメ
![nagedasu_man.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3287130/ae70aa73-0eef-7560-c2cb-1a5c0da578d9.png)

こんな風に投げ出したくなっても、生徒のため頑張ります。


# スクラムマスターと教師

アジャイル開発のスクラムにおいて、PMやスクラムマスターに求められる力と教師が求められる力は同じではないかと思います。

こちらの記事でスクラムマスターについて詳しく書かれていました。

https://qiita.com/gold-kou/items/90ba982a14ca79d843c9

こちらの方も「学校の先生みたい」って書かれていました。
同じと感じたのは僕だけやないみたいなので、一安心（笑）


# これから社会に出る人たちはスクラムが当たり前

現在の学校教育を受けた子たちは我々おじさん、おばさんの世代に比べ

**「個人でもチームでも自ら必要なことは何かを考え、行動していく」**

が自然にできる子たちになります。

そのためスクラムを組んでの開発思想が当たり前になるのではと思います。

トップダウン手法、ウォーターホール開発に違和感を感じる世代になるはずです。
スクラムを組んでのアジャイル開発を自然とできる組織で新しい世代の子たちを迎えることが大切となります。


# スクラムが正義？

さてこういう話をすると、

**「教員はみんなスクラムマスターになれる」**
**「トップダウン的な考え方やウォーターホール開発は悪」**

とかいう人がいます。それは違います。

教育現場のプロである教員が医療現場に入って医者へ指示出しできると思いますか？

医療現場の当たり前や医療の知識なく指示を出すと、医療ミスにつながりかねません。

それと全く同じことが言えます。畑が変われば、最低限畑の知識を持つ必要があります。

また、トップダウンで指示をした方が短時間で終わることだってあります。そのため、必ずスクラムの形でやらないといけないわけではないのではと考えます。どういった形がベストなのかを、自ら考え、選択することが大切なのだと思います。

# 最後にプロフェッショナルな皆さんへ

教育現場に１０年ほどいたからか、いまだに

**エンジニアの当たり前に違和感**

エンジニア１年目にいた会社は異業種からの転職者が大半だったため、社内ではそういった違和感はほとんどありませんでした。
しかし社外の強強エンジニアばかりのチームに入ったときとかかなり違和感が強かったです。

現在社会的にDX化の促進を目指しています。エンジニアの皆さんはDXのプロとなるのですが、これからDXする人たちは違います。

**私の当たり前はあなたの当たり前ではない**

これを理解した上で良い組織づくりを目指してほしいと思います。

お読みいただき感謝！！
AWS Amplifyを使ってWebアプリを構築してみた#2

# 第2回：フロントエンドプロジェクトの作成とAmplifyの設定

この記事では、フロントエンドのプロジェクトを作成し、Amplifyを使用できるように準備します。使用するツールは以下の通りです。

- Vite
- React
- TypeScript
- AWS Amplify

## プロジェクト作成

まず、新しいViteプロジェクトを作成します。ターミナルで以下のコマンドを実行します。
`npx create-vite@latest`


## プロジェクト設定

次に、プロジェクトの設定を行います。以下の設定を選択してください。

- テンプレート：React×TypeScript
- Project Name：好きな名前を入力

## プロジェクトの起動

プロジェクトを起動するには、以下の手順を実行します。

1. ターミナルでプロジェクトのディレクトリに移動します。
`cd {Project name}`


2. 必要なパッケージをインストールします。
`npm i`



3. 開発サーバーを起動します。
`npm run dev`


4. ブラウザで[http://localhost:5173](http://localhost:5173)にアクセスし、プロジェクトが正常に起動していることを確認します。

## Amplifyの設定

次に、Amplifyの設定を行います。

1. ターミナルで`Ctrl+C`を押して開発サーバーを停止します。

2. プロジェクトのルートディレクトリで、`amplify init`コマンドを実行します。

3. 設定が表示されるので、特に変更することなく進めてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2439059/9d615432-1b3f-361c-33b5-1c86de1ad652.png)

4.最後に、AWSプロファイルを選択します。これは、本シリーズの第1回で作成したプロファイルを使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2439059/7d8d9840-3608-f5de-f9f2-5923dd9dabeb.png)

5.デプロイが完了するのを待ちます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2439059/5dc0e380-1ca2-00b5-10d5-f32dd400e1e6.png)


6.デプロイステータスが`Succeeded`になっていれば、デプロイが正常に完了したことが確認できます。
   ※以下の画像は参考のため、実際の画面では状況に応じたステータスが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2439059/8c96ced7-c6e0-c989-bedc-f4496fc3e623.png)


これで、フロントエンドプロジェクトの作成とAmplifyの設定が完了しました。

# まとめ

この記事では、Viteを使用してReact×TypeScriptのフロントエンドプロジェクトを作成し、Amplifyを設定する方法を紹介しました。これで、Amplifyを使用した開発が可能になります。今後の記事では、Amplifyを使用してさまざまな機能を実装していきますので、お楽しみに！

# 参考サイト

(ここに参考サイトをリンクで挿入してください)
マネジメント検定(旧経営学検定)を勉強してITストラテジスト試験に繋げる

GWに勉強したマネジメント検定3級（旧経営学検定）について記載します。
下記の様に経営関連の資格は他にもありますが、取得するとなると結構ハードルが高いため、手軽に経営学を学ぶという意味でマネジメント検定はお勧めです。検定の概要や学んだ内容、その先について記載します。

# 経営関連の資格

* 中小企業診断士
コンサルの国家資格ですが、1次試験短答式7科目、2次試験論述式、3次試験口述式、合格後実務補習が必要等、取得するにはかなりハードルが高いです。

* ITコーディネータ
試験の他に研修が必要です。また1年毎に講習が必要なので取得費用、維持費用が高いです。

* ITストラテジスト
情報処理技術者試験の一つです。ITと経営の知識が必要で難関は午後2の論文（4000字以内）です。

# マネジメント検定について

経営学は会社の仕組みについて学ぶ企業論（株式会社って何？、取締役って何？など）、経営戦略、競争戦略、事業戦略（マーケティング含む）について学ぶ戦略論、会社の組織や人について学ぶ組織論などがありますが、3級はこのあたりの基礎が幅広く学習出来ます。なお試験は6月に受ける予定なのでどんな感じの問題かはまだ分かりません。検定の基本的な情報を下記に記載します。[マネジメント検定](https://www.mqt.jp/)のHPも参照下さい。

* 現在は3級と2級が年2回（6月と11月）実施
* CBT方式、マークシート
* 公式テキストと公式問題集が発売されている

# 学習してみて
 結構前に前身の経営学検定の勉強をしたことがありますが、その時の内容は実務的というよりもより学術的な内容が多かった気がします。今回勉強してみると、より実務的に利用出来るものに改定されている気がしました。また、経営学の考え方も時代とともに変化していきますが、どの様に変化してきたかがしっかり記載されているので、理解がしやすいです。例えばマーケティングを例にすると下記のような感じですね。

* 需要＞供給の時代
ものが売れるため、作ったものをどう売るか（プロダクトアウト）の考えでした。

* 供給＞需要の時代
ものが余る時代となり、売れるものを作る（プロダクトイン）という考えになってきました。

* 現代
ただ売るだけではなく環境問題など企業の社会的責任を考える時代となりました。

# 業務に活かす
戦略論では[資格を60個以上取得してみて。 中長期的に役にたった場面～コンセプチュアルスキルの向上～](https://qiita.com/infra365/items/5985241d9c5d981751e0)に少し記載しましたが、SWOT分析やPPMなどの経営学のフレームワークを学習することは論理的かつ効率的に物事を考えるのに有効かと思います。また組織論ではマネジメント、リーダーシップ、動機付け理論などを通して管理的側面からどの様なことが必要か、どの様な手法があるかを学ぶことが出来ます。これらも時代とともに変化していくものですが、その変化してきた歴史を学ぶことでこれから何が必要かを自分なりに考えて組み立てていくことが出来ます。ここに記載させて頂いたのは一例ですが、その他にも業務に役立ちそうな理論は色々とありました。

# 今後
まず6月に3級を受けてみようと思います。その後11月に2級を受験予定です。タイトルに記載したITストラテジスト試験ですが、この試験の合格には```ITスキル```、```経営系スキル```、```論文試験になれる```の3つが必要だと考えています。そのため、マネジメント検定で```経営系スキル```の学習をして```論文の勉強```をすればITストラテジスト試験はいけそうな気がしてきました。また論文については、論文の書き方を勉強するのと、普段から自分の考えを持って業務にあたっていくということが重要だと考えています。
defer基本使い方

# 基本的な使用方法

deferキーワードは通常、リソースのオープン後に配置され、後でリソースを閉じることを忘れないようにします。
deferで宣言されたコードは、実際には関数が終了するまで実行されません。

```go
func demo_defer_0() {
	fileName := "./test.txt"
	f, _ := os.OpenFile(fileName, os.O_RDONLY, 0)
	defer f.Close()

	contents, _ := ioutil.ReadAll(f)
	fmt.Println(string(contents))
}
```

## 複数のdefer呼び出しの順序：先入れ後出し（FILO）

```go
func demo_defer_1() {
	for i := 0; i < 3; i++ {
		defer fmt.Println("defer:", i)
	}
}

// defer: 2
// defer: 1
// defer: 0
```

## スコープは現在の関数に制限されます
｀
異なる関数には異なる関数スタックがあります。

```go
func demo_defer_2() {
	func() {
		defer fmt.Println(1)
		defer fmt.Println(2)
	}()

	fmt.Println("defer action")

	func() {
		defer fmt.Println("a")
		defer fmt.Println("b")
	}()
}

// 2
// 1
// defer action
// b
// a
```

# deferの後の関数パラメータは値渡しです

```go
func demo_defer_3_1() {
	num := 0
	defer func(n int) {
		fmt.Println("defer:", n)
	}(num)

	for i := 0; i < 10; i++ {
		num++
	}

	fmt.Println(num)
}


// 10
// defer: 0
```

```go
func demo_defer_3_2() {
	num := 0
	p := &num
	defer func(p *int) {
		fmt.Println("defer:", *p)
	}(p)

	for i := 0; i < 10; i++ {
		num++
	}

	fmt.Println(*p)
}

// 10
// defer: 10
```

```go
func demo_defer_3_3() {
	num := 0
	defer func() {
		fmt.Println("defer:", num)
	}()

	for i := 0; i < 10; i++ {
		num++
	}

	fmt.Println(num)
}

// 10
// defer: 10
```

##  returnはdeferより先に実行されます

```go
func demo_defer_4_1() (int, error) {
	defer fmt.Println("defer")
	return fmt.Println("return")
}

// return
// defer
```

```go
func demo_defer_4_2() (num int) {
	num = 10
	defer func() {
		num += 5
	}()

	return 2
}

// 7
```
最初に(num int)で、numは初期値0です。
その後、num = 10として、値が10に設定されます。
次に、return 2で、numが2に設定されます。
最後に、deferの中でnumが計算され、結果は7です。

```go
func demo_defer_4_3() int {
	num := 10
	defer func() {
		num += 5
	}()

	return 2
}

// 2
```
ここでは、numとreturnの値は関連していません。

## panicが発生した場合、既に宣言されたdeferはスタックから実行されます

```go
func demo_defer_5_1() {
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)

	panic("panic call")

	defer fmt.Println(4) // 実行されません
}
```

```go
func demo_defer_5_2() {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()

	panic("panic call")
}
```