OmniAICreator/Qiita-1.07M huggingface dataset:
neovimでpylspを入れると```error failed to create python3 virtual environment```が出る

# 発生した問題

masonとmason-lspを使用し、```:MasonInstall pylsp```をすると、
```failed to create python3 virtual environment```が出ました。

# やったこと

```:checkhealth```を確認します。


## 1. python3_host_progのパスが通っていない

```python3_host_prog:```を読み込んでいないと出てきました。
まずは、python3のパスを確認します。
```
which python3
```
私の環境では```usr/bin/python3```が出てきました。
読み込ませたいので```init.lua```に以下を記述します。

```lua:init.lua
-- recognize python3_host_prog to pass checkhealth
vim.g.python3_host_prog = '/usr/bin/python3'
```

成功しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261812/892dfbc2-48c6-20eb-8da7-ce4ff78adcd6.png)

参考

https://neovim.io/doc/user/provider.html

### 2. nvim用のpython仮想環境を作る

調べてみると、nvim側が使用するpython仮想環境が必要という情報がありました。
そこで、以下を参考にuserをneovimにして仮想環境を作成します。

https://github.com/deoplete-plugins/deoplete-jedi/wiki/Setting-up-Python-for-Neovim

```python
pip2 install --user neovim
pip3 install --user neovim
```

### 3. venvのインストール
上記を試しましたが、まだエラーがとれません。
よく見ると、```checkhealth```のvenvの左側にOKが出ているのに、no environmentのような表示が出ていました。

venvをインストールします。
```sh
sudo apt-get install python3-venv
```

これを試すと、pylspが使えるようになりました！

参考
https://askubuntu.com/questions/1465992/error-installing-pylsp
AWS SSM Agent v2からv3へアップデートする手順

# はじめに
EC2(Linux)のSSM Agentをv2からv3にアップデートしたので、備忘録的に書いていきます。
やり方は色々ありますが、今回は実際にやったRun Commandを用いた手順を記載します。

# 手順

1. AWSコンソールから`AWS Systems Manager`へ移動する。

2. `Run Command`のボタンをクリックする。

3. キーワード検索で`SSMAgent`を入力する。

4. `AWS-UpdateSSMAgent`を選択する。
![SSMAgent-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1391445/98be7132-6559-047f-a759-769596dc1298.png)

5. `コマンドを実行する`をクリックする。

6. `コマンドのパラメータ`から、versionを指定する(入力なしならlatest)。
![SSM Agent-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1391445/a983598d-faa1-a945-3563-49f9271fc6d1.png)

7. ターゲットの指定をする(アップデートする対象)。
![SSM Agent-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1391445/819af0e4-e363-23f1-1df8-a9e4a03e110d.png)

7. 画面最下部の`実行`をクリック。

以上です。

自分の環境では初回のみ失敗することがありましたが、再度実行で成功になりました。
参考までに。

# さいごに
誰かのお役に立てれば幸いです。
neovim mason-lspconfigの自動インストールと有効化(setup_handlers)

# 概要

いちいちlspを```:MasonInstall```するのは面倒です。
そのため、自動インストールと設定の有効化をします。

# mason-config.luaの設定

mason-config.luaで設定をしました。ファイル名は好きに変えてください。

```lua:mason-config.lua
require("mason").setup()
require("mason-lspconfig").setup {
	ensure_installed = {
			"lua_ls",
			"bashls",
			"clangd",
			"cmake",
			"cssls",
			"dockerls",
			"docker_compose_language_service",
			"gopls",
			"html",
			"jsonls",
			"tsserver",
			"marksman",
			"nimls",
			"pylsp",
	}
}

-- auto lspconfig setting
require('mason-lspconfig').setup_handlers {
  function(server_name)
    require('lspconfig')[server_name].setup {}
  end,
}

```

```init.lua
require('mason-config')
```


# 参考

こちら素晴らしい記事です。

https://coralpink.github.io/commentary/neovim/lsp/mason-lspconfig.html


https://github.com/williamboman/mason-lspconfig.nvim/blob/2997f467881ac4faa6f8c5e7065e3a672297c8ad/doc/mason-lspconfig.txt#L242

```:h mason-lspconfig.setup_handlers()```
STM32G031ボード I2S波形を出してみる

こんなボードがありまして...

- https://github.com/WeActStudio/WeActStudio.STM32G0xxC0xxCoreBoard

I2S波形をきちんと見たことがなかったので，見てみました。

# とにかく波形を出してみる

```
          GND  A3 
          5V   A2 I2S1_SD
 I2S1_WS  A4   A1 I2S1_CK
          A5   A0 
I2S1_MCK  A6   NR
          A7   GND
          A8   3V3
          A11  C15  OSC_EN OSC32_OUT
          A12  C14 TIM1_BK2 OSC32_IN 
          B6   B7
```

ioc設定 クロックは64MHzに変更

まずは16ビットで試す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/38d084bb-08fd-ec3d-fe7d-d6d5e81e4a1c.png)

0 1 2 3 ... と送ってみる。

```main.c
  /* USER CODE BEGIN 2 */
  uint16_t data[256];
  for (int i=0; i<256; i++) {
	  data[i]=i;
  HAL_I2S_Transmit(&hi2s1, (uint16_t *)&data, 16, HAL_MAX_DELAY);
```
成功！ PulseViewは I2S Philips で読むようだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/d7b744d2-c873-e701-d367-8a56d6d8f499.png)

32ビットフレーム24ビットに変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/3557080b-9301-a758-d22e-01507734d94a.png)

ビットの切れ目がわかりやすいようにデータも変更します。

```main.c
  uint16_t data[256];

  for (int i=0; i<256; i++) {
	  data[i]=0;
  }

  data[2]=0x1234;
  data[3]=0x5678;
  data[4]=0x9abc;
  data[5]=0xdef0;
```

成功したようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/05bc8ef7-6ce9-1f63-2549-1be7e845f70b.png)

RM0444によれば，24ビット扱う場合，最初のデータでMSB 16ビット送信，次のデータのMSB 8ビットのみを使ってあとは0で埋めるとのことですので，`data[3]=0x5678;` の 78 の部分が捨てられました。その時のI2Sのデータは24ビットで `0x12345600` となりました。

# どのくらいデータを準備したらいいのか

44.1kHzサンプリング 20Hzのデータを準備するとします。
44100/20=2205個のサンプリングデータが少なくとも必要です。
1サンプルで16ビットのデータが4つ必要なので，
2205x4=8820個の16ビットデータとなります。
8820x2=17640バイト -> 約 17kbyte

STM32G031F8P6 は RAM:8KB ROM:64KB なので ROM領域に置くことになりますね。転送間に合うのだろうか？

# 見直し

24ビット 44.1kHzサンプリングを指定したのですが，-5.3%という表記が気になっていました。
基準信号ぐらいなので，16ビットで十分だし，使おうと思っていたDACはMCKが不要なのでちょっと見直してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533274/00184b8e-0ce3-f76a-3353-e0a9e0217307.png)

同様に計算すると9.3kbyteです。まだまだ足りませんが，帯域を絞ればなんとかなるか...
PHPの今を語る！4社合同勉強会を振り返る

# はじめに
普段主にPHPを使ってアプリ開発をしている@HaruKado777といいます。
7/26（水）に[【PHP Tech Talk】PHPの今を語る！4社合同勉強会](https://colopl.connpass.com/event/286658/)に参加しました。
勉強会で学んだことのアウトプットも兼ねて記事を書きたいと思います。

当日は下記のスケジュールで実施されました。

```
19:10	PHP の新しいバージョンはどのようにして生まれるか ／ インフィニットループ
19:25	コロプラはなぜゲームアプリケーションで PHP を使い続けるのか ／ コロプラ
19:40	サイボウズとGaroonとThe PHP Foundationと私 ／ サイボウス
19:55	ふつうのpixivの作り方 ／ ピクシブ
20:10	パネルディスカッション・質疑応答
```

「PHP の新しいバージョンはどのようにして生まれるか」についてがとても興味深かったので、今回はその記事について書きたいと思います。

# PHP の新しいバージョンはどのようにして生まれるか


## 新しいバージョンはなぜ生まれるのか？

主にバグ修正・セキュリティ修正・環境への追従のために、新しいバージョンが生まれます。
言語も処理系も人が作っているものため、バグは避けることができないものです。
また、依存するライブラリに問題が見つかる場合もありますので、その場合も対応が必要になります。
CPUやOSの新機能を使って高速化するなどポジティブな環境追従などで新しいバージョンが生まれる場合もあります。

### 言語改訂
普段使っている言語をさらに便利にしたいという要望に応える為、新たな言語機能が導入されます。
また使ってみて問題を起こしやすい言語機能があれば改訂・廃止されます。
言語改訂に対応するのは面倒です。しかし、プログラミング言語は多くあるので、使いづらい言語は徐々に使われなくなってきます。

## 新しいバージョンはいつ生まれるのか？
リリースの種類は、ポイントリリース、マイナーリリース、メジャーリリースの3つがあります。
3つのリリースをPHPのバージョン8.27を例に分類すると下記になります。

#### ポイントリリース
- 8.2.7の7の部分
- 原則的に言語改訂を含まない
- バグ修正やセキュリティ修正のみが行われる
- ほぼ毎月のペースでリリースされる

#### マイナーリリース
- 8.2.7の2
- 機能追加のような言語改訂を含む
- スクリプトについて後方互換性のない修正は基本的に入らない
- 年一回のペースでリリースされる
- サポート期間は大体3年

#### メジャーリリース
- 8.2.7の8
- 機能追加のような言語改訂を含む
- スクリプトについて後方互換性のない修正も入る
    - マイナーリリースで非推奨化されてきた機能が一気になくなったりする
- リリース感覚に決まりはない


## 新しいバージョンはどこで生まれる？
まず、処理系のソースコードはGitHubの[php/php-src](https://github.com/php/php-src)で管理されています。
不具合があった際は、isuuesで不具合報告をすることができます。
些細な修正に関してはコミット権を持つコア開発者が直接コミットしたりすることもあるそうです。

言語改訂には合意形成が必要になるため、internals　MLを通してどのような改訂が必要かを議論します。
議論の参加は自由で、RFCプロセスに従って改訂が提案され、投票が行われます。
MLに参加していない人でもアーカイブサイトで議論の経緯が追えます。


## 新しいバージョンはどのように作られているのか？
### RFCプロセスの概要
RFC(Request For Comments)とは、言語改訂を提案→議論→決議するためのプロセスです。
phpはよく言えば民主的な言語で、全ての方針を決定づけるような個人がいません。

下記RFCプロセスの詳細です。
- php.net のWikiでRFCを書く
- internals MLでアナウンス
- 言語改訂の提案には告知から最低2週間の議論が必要
- MLで投票開始をアナウンス
- 2/3 以上の賛成で承認
- 投票権を持つのは一部の人々
    - リポジトリへのコミット権を持つコア開発者
    - internalsでの議論意欲参加するコア開発者に認められた人 


## 新しいバージョンは誰が作っているのか？
PHPはOSSプロジェクトのため、多様な人々が開発に参加しています。
PHPの言語処理系の開発に余暇で関わりたい個人や、PHPのの改善から利益を得る会社の従業員、言語処理系の作られ方を学びたい学生などが参加しているようです。


### ネブラスカ問題
現代のシステム開発は至る所でOSSを利用しており、OSSはさらに別のOSSに依存しています。重要なシステムが一個人に依存していたりします。


### PHP Foundation
PHP Foundationとは、2021年11月に設立した、寄付を集めてphpのコア開発者を雇う団体です。
現在までに100万USDを調達し、現在は6人のフルタイム・パートタイム開発者を雇っているそうです。

## 感想
普段利用しているPHPが、なぜ、いつ、どこで、どのように、誰が作っているのかざっくりと知ることができました。
普段PHPを利用しているのものあまり、この辺を意識して開発をしたことがなかったので良い機会になったと思います。
せっかくの機会ですので、PHPのRFCの詳細だったり、GitHubのコードを読んでみたりしてみたいと思います。
【Xcode】ファイル検索の便利なショートカット

# はじめに
これを知ってるか知ってないかで開発効率がめっちゃ変わります

# やりかた
`Command` + `Shift` + `O(オー)`
<img width="1247" alt="スクリーンショット 2023-08-23 18 54 27" src="https://github.com/SNQ-2001/SNQ-2001/assets/84154073/66aac7e9-b0a5-4e11-b4d7-d75987d72736">

# おわり
ショートカットを使いこなして効率化したいですね
【PowerAutomate】Azure DevOps の特定の組織に対する操作で失敗（"TF400813: The user is not authorized to access this resource"）する時の対処法

# 結論から

現象の発生している組織の Organization Settings > Policies > **Third-party application access via OAuth** が Off になっているときタイトルのエラーが発生するのでこれを **On** にします。

組織、プロジェクトにおけるユーザー権限設定に問題がなさそうなのにエラーが発生してしまう場合はこちらの設定をチェックしてみると解決するかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174132/883d7940-8e12-74d5-e429-3bd808367555.png)

# 参考情報と補足

下記の stackoverflow のポストに対する回答が同様の内容になっています。私はこちらにたどり着いて解決しました。

https://stackoverflow.com/questions/72957809/powerautomate-flow-fails-with-tf400813-the-user-is-not-authorized-to-access-th

こちらの Forum のポストも同じ内容です。

https://powerusers.microsoft.com/t5/Using-Connectors/Power-Automate-errors-connecting-to-Azure-DevOps-but-only-one/td-p/442614

Power Platform 側の Azure DevOps コネクタに対する公式リファレンスです。任意のアクションあるいはトリガーの「組織名」に関する説明に今回対処法が記載されています。

https://learn.microsoft.com/ja-jp/connectors/visualstudioteamservices/

Azure DevOps 側の当該機能に対する公式ドキュメントです。下記のように既定では Off になっているようです。

>  このポリシーは、すべての新しい組織で既定で オフ になっています。

https://learn.microsoft.com/ja-jp/azure/devops/organizations/accounts/change-application-access-policies?view=azure-devops

下図のようにフロー作成時に **組織名** 入力欄にマウスオーバーしたときにそれらしいメッセージが表示されていました。これは Power Platform 側のリファレンスにある説明と同様です。ただ実際にはエラーが発生するのは 組織名 を選択したのちの プロジェクト名 になります（組織の一覧と選択自体は可能）ので気づきにくいかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174132/19941d66-d673-fbb5-2431-d0534fd24b50.png)

エラーコードやメッセージでｇｇれば上記らにアクセスできるので解決できるかと思いますが、日本語でストレートにヒットする情報源が発見できなかったので誰かの役に立てば良きです。
AWS上のWebサービスからお客様内部のSMTPサーバーにメール通知する

## はじめに
BtoB向けのWebシステムでは、何かしらの通知をメールで行う事があります。
イントラ内に構築されたシステムであれば、Web/APサーバーから、お客様の内部SMTPサーバー宛にメール送信すればよいのですが、SaaSとしてWebサービスを提供している場合は、公開SMTPサーバー宛にインターネットメールを送信する事になります。

しかし、企業によっては、セキュリティの観点から、一部社員などについて、インターネットメールを受信できなくしている場合があります。

このような場合に、どのような解決策があるのか、整理してみたいと思います。

## 取りうる手段
インターネットメールを受信できない場合、インターネット経由で送信したメールを、お客様社内にある内部SMTPサーバー宛にメール送信できるようにする必要があります。

WebサービスがAWS上にある場合、上記を解決する方法として、以下の3つが考えられます。
1. お客様ネットワークに、インターネット(Webサービス)からのメール通知を受け取るためのグローバル(パブリック)IPアドレス(GIP)を用意してもらい、NAT変換するなどして、お客様内部SMTPサーバーに受け渡す。
1. お客様AWS環境(ある場合)のパブリックサブネットにNetwork Load Balancer(NLB)を構築し、NLBのターゲットグループに、お客様内部SMTPサーバーのプライベートIPアドレスを指定。
1. お客様の公開SMTPサーバーからメールリレーして内部SMTPサーバーに転送。

以下に、1、2のパターンについての構成を記載します。

#### 1. お客様GIP宛にメール送信し、NAT変換などして内部SMTPサーバーにメール送信
この構成では、お客様に新たにGIPを追加いただく必要があり、またネットワーク設定も変更が必要になるため、手間はかかりますが、お客様AWS環境が無い場合は検討の余地があると思います。

ただし、SMTPSなどを利用しない場合、インターネットをメールが平文で送信されることになるので、メールの内容によっては、セキュリティ面での考慮が必要になる場合があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2554521/5d15d814-ee1b-9699-d368-8cb03c5019ec.png)
この構成の場合、以下のようなメール通知の流れになります。
- Webサービスからメール送信する際の宛先は、お客様環境のGIP(パブリックIPアドレス)を指定(プロトコル/ポートはTCP/587等)
- お客様ファイアウォールでは、WebサービスのNAT GatewayのパブリックIPアドレスからのTCP/587等の通信を許可
- お客様環境では、受け取った通信をルーターやL3スイッチ等でNAT変換して内部SMTPサーバーに受け渡す

#### 2. お客様AWS環境のNLB経由で内部SMTPサーバーにメール送信
お客様AWS環境がある場合は、以下のような構成をとることができます。

AWS環境同士では、Internet Gatewayから出ていく経路であっても、インターネットは経由せず、AWS内のネットワークでの通信となるため、1のパターンよりも敷居が低くなるかもしれません。

やっている事はパターン1とほぼ同じですが、管理コンソールでの操作で簡単に構成を作り、検証できるのはありがたいですね。

また、2023年8月からNLBでもセキュリティグループが利用できるようになったので、通信制御もよりやりやすくなりました。

※ルートテーブル、セキュリティグループなどの設定はよしなに行ってください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2554521/1d8406e6-ba48-64ea-3003-daab89dc77c8.png)
この構成の場合、以下のようなメール通知の流れになります。
- Webサービスからメール送信する際の宛先は、お客様AWS環境のNLBのパブリックIPアドレスを指定(プロトコル/ポートはTCP/587等)
- お客様AWS環境では、セキュリティグループやネットワークACLで、WebサービスのNAT GatewayのパブリックIPアドレスからのTCP/587等の通信を許可
- お客様AWS環境のNLBでは、受け取った通信を内部SMTPサーバーに受け渡す

NLBのターゲットグループで、オンプレミス環境も含めたIPアドレスを指定できるのが、このような場合とても助かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2554521/46af76ef-ece7-67ea-97e4-161357b32b10.png)

## おわりに
AWS環境のWebサービスから、インターネットメールが受信できないお客様環境宛にメール通知する方法について簡単にまとめてみました。
【Neovim】TypeScriptとVue.jsの開発を行うために必要なcoc.nvimの設定

## coc.nvimのインストール

基本は公式通り。
https://github.com/neoclide/coc.nvim

インストールしたら、

```vim:command-mode
:CocInstall coc-tsserver
```

シンプルなtypescriptファイルなら、
これだけでも使えたはず。

## Vue.jsに適用させる
Vue.jsの場合、htmlの部分と混在しているのと、
拡張子が、.vueなので、
上記の設定だけだとうまくきいてくれない。

なので、veturとかを入れる。
(ついでにeslintやprettierなども)

```vim:command-mode
:CocInstall coc-vetur coc-eslint coc-prettier
```

ちなみに、
```vim:command-mode
:CocList extensions
```
で、インストールされている拡張機能を確認する。


## coc-setting.json

```vim:command-mode
:CocConfig
```
で、coc-settings.jsonの編集画面を出す。
下記のように記載する。

```json:coc-settings.json
{
  "eslint.filetypes": [
    "javascript",
    "typescript",
    "vue"
  ]
}
```

## 補足

主にvue3で
veturだと、templateタグと、
script setupタグとのまたがる変数とかで、
'hensu' is declared but its value is never read. (vetur 6133)とかの
エラーが出るので、volarの方がいいかもしれない。

入れる場合は、
```vim:command-mode
:CocInstall @yaegassy/coc-volar
```
https://github.com/yaegassy/coc-volar

それでveturを消すには、
```vim:command-mode
:CocUninstal coc-vetur
```
Clean Code

# 命名
- 意味のある対比を行う
→対比される対象がある場合に、違いがはっきりと分かる名前を付ける。
２つのクラスに ProductInfo、 ProducetData のような名前を付けてはいけない。
２つのメソッドに、 getAccount() と getAccountInfo() のような名前を付けてはいけない。

# 変数
- 変数の寿命(変数を宣言してから使用するまでの行数)を短くする
→10行程度ならまとめて宣言してもOK

- 小さなスコープで変数を定義する
→スコープが大きいほど確認しなければならない範囲が増えてしまう。

- レキシカルスコープは極力使わない
→できるだけ引数を通して値を受け渡す。コードが追いやすくなる。

# 関数

- 関数は小さい事が重要
→20行以上の長すぎる関数を作成しない

- 関数は1つの機能のみ実装する(責務を限定する)

- 条件分岐はなるべく書かない

- DRY原則で
→ただし目的の違う関数は共通化しない

- 引数が多い場合はオブジェクトにまとめる(3個以上)

- 論理和（||）よりデフォルト引数を使う

- フラグ引数は使わない
→関数内での条件分岐は極力避ける。true/falseの場合で、それぞれ関数を定義すべき。if文などを排除することにより、関数が小さくでき、デッドロジックもなくなる。


- 副作用を避ける(関数が1つの事を行なう事を保証しつつ、隠れて別の事を行なう事を避ける)

# ループ分
- ループの処理は複雑化せずに１つのループに１つの機能として記述する
→ループ処理を分けてもパフォーマンスは気にするほど下がらない。

# 条件分岐

- 基本的に厳密透過演算子（===）を使う

- 境界条件のカプセル化
→変数で条件をまとめる。長すぎる場合は関数に切り出してもいい。

- ヨーダ条件式
→条件文（if文など）の中で、変数よりもリテラル値を前に配置する。

```
if (5 == x) {
  // 何らかの処理
}
```

- 条件分岐・swich分よりも連想配列でまとめられないか検討

- 早期return

- if文ではなくクラスやコールバック関数の利用を考える

# コメント

##### 前提
- コメントが必要になるときはそもそも、処理が大きくなり過ぎている可能性が高い
- コードで解決できる部分はコードで解決する
- コードが見づらいことをコメントで解決することは根本的な解決にはならない
- コメントと処理内容が食い違っていた場合はかえって混乱を招く

##### 良いコメントとは
- 使用上の注意・警告
- パフォーマンスなどに関わるコメント
- 正規表現の意図を表すコメント
- TODO、FIXME、NOTEなどのアノテーションコメント
【Vue.js x AWS】CodeBuildのエラー「Did you mean to enable the 'allowJs' option?」の原因と解決方法

# 概要
`Vue.js`を扱ったプログラムをAWScodepipelineで自動デプロイしたら、ビルドステージで`Did you mean to enable the 'allowJs' option?`というエラーが表示されて失敗していました。
本記事では本エラーの解決方法を記します。

## エラー内容

CodeBuildのエラーログは以下の通り。

```
error TS6504: File '/codebuild/output/src1493754208/src/xxx/app/src/views/Sample.vue.js' is a JavaScript file. Did you mean to enable the 'allowJs' option?
  The file is in the program because:
    Matched by include pattern 'src/**/*' in 'tsconfig.app.json'
ERROR: "type-check" exited with 2.
```

エラーメッセージの内容を見ると、`Sample.vue.js`というファイルがJavaScriptファイルであることが示されており、TypeScriptファイルとして処理するために`allowJs`オプションを有効にするかどうかが聞かれています。

`tsconfig.app.json`は以下の通り。

```json
{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
```

ちなみに、Codebuildステージで「失敗しました」と赤字で表示されていたのですが、アプリケーションを確認するとマージ分は反映されているようでした。つまり、ビルド自体は成功しているが、TypeScriptのコンパイルエラーが発生しているために`type-checkプロセス`が終了し、AWS CodeBuildのビルドプロセスはエラーとして報告されているよう。

## 原因
エラーメッセージの中にある`allowJs`オプションとは、JavaScriptファイルをTypeScriptプロジェクト内で許可するかどうかを制御するためのオプション。このオプションはデフォルトでは`false`になっています。つまり、JavaScriptファイルはTypeScriptプロジェクト内で扱われることはない状態でした。これが問題となっていたようです。

## 解決方法
解決策は二つあります。

①`Sample.vue.js`をTypeScriptファイルとして扱うようにする = 拡張子を`.ts`に変更する
②`Sample.vue.js`をJavaScriptファイルとして扱うようにする = `"allowJs": true`という設定を追加する

今回は②で対応しました。

結果、以下に変更すると、CodeBuildが正常に完了しました。

```json
{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "allowJs": true,
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
```

### 補足：`tsconfig.app.json`とは
`tsconfig.app.json`は、Vue.jsアプリケーションなどのTypeScriptプロジェクトに関連する設定を格納するファイル。

Vue.jsアプリケーションは、通常、

・TypeScriptで書かれたファイル（`.ts`拡張子）
・Vueファイル（`.vue`拡張子）

で構成されています。Vueファイルにはテンプレートやスクリプトが含まれており、これをTypeScriptと統合して開発するために、適切なTypeScriptコンパイラの設定が必要です。

TypeScriptでコンパイルの設定を行うファイルが`tsconfig.app.json`です。
【React | Next.js】あまり面倒くさくない開閉アニメーション付きアコーディオンを作る

※本記事は [Zennに投稿した内容をそのまま複製](https://zenn.dev/masa5714/articles/52b7639ac3da61)しています

開閉アニメーションの付いたアコーディオンって実装面倒くさいですよね......。
っていうのは実は思い込みで、 `max-height` と `CSS Variables` を組み合わせれば超簡単に実装できます。

※動作確認はWindows各種ブラウザとAndroid Chromeのみです。試した方がいれば、コメ欄でSafariの挙動バグが無いか教えていただけると嬉しいです！

# 完成イメージ

[CodeSandboxでサンプルを見る](https://codesandbox.io/p/sandbox/max-heightdeakodeion-n2rfmw)

※なぜか埋め込みできなかったのでリンクで失礼します。

![](https://storage.googleapis.com/zenn-user-upload/9647f2491bb3-20230823.gif)

※この記事のコードでは不要なスタイルを取り除いているので、この見た目通りにはならないかと思います。

# 必要なライブラリをインストールする

```bash
npm install clsx react-resize-detector
```

- clsx： JSX内でclass名の分岐が簡単に記述するために使います。
- react-resize-detector： リサイズ処理をお任せするために使います。

# 【本題】開閉アニメーション付きのアコーディオンを書く

```tsx: Accordion.tsx
import { useState } from "react";
import clsx from "clsx";
import { useResizeDetector } from "react-resize-detector";

// アコーディオンのコンテンツの型
export interface ContentsProps {
  question: string;
  answer: string;
}

// 描画用のコンポーネント
const Accordion = () => {
  const contents: ContentsProps[] = [
    { question: "質問１", answer: "質問１の回答です。"},
    { question: "質問２", answer: "質問２の回答です。"}
  ];

  return (
    <div>
      <AccordionContainer contents={contents} />
    </div>
  );
};

// アコーディオンの項目を縦並びで整列しておく。
const AccordionContainer = ({ contents }: { contents: ContentsProps[] }) => {
  return (
    <div className="flex flex-col">
      {contents.map((theItem) => (
        <AccordionItem key={theItem.question} item={theItem} />
      ))}
    </div>
  );
};

const AccordionItem = ({ item }: { item: ContentsProps }) => {
  const [ isOpen, setIsOpen ] = useState(false); // 【状態】開閉を記憶
  const { height, ref } = useResizeDetector(); // react-resize-detector
  
    return (
    <dl className="overflow-hidden bg-white">
      <dt className="flex items-center cursor-pointer select-none" onClick={() => { setIsOpen(!isOpen); }}>
        <span>{item.question}</span>
      </dt>
      <dd
        style={{ "--content-height": height + "px" } as React.CSSProperties}
        className={`
	  overflow-hidden transition-[max-height] duration-500 ease-out-expo
	  ${clsx( isOpen === true ? "max-h-[var(--content-height)]" : "max-h-0")}
	`}
      >
        <div ref={ref}>
          <p className="border-t border-gray">{item.answer}</p>
        </div>
      </dd>
    </dl>
  );
}

export { Accordion }
```

たったこれだけで transition付きのアコーディオンが実現可能です。

※ ease-out-expo はtailwind.config.tsにて transitionTimingFunctionに `"out-expo": "cubic-bezier(0.16, 1, 0.3, 1)",` を追加しています。

# 実装のポイント

max-height の transition でアニメーションを行っています。
Tailwind CSSで言うと、`max-h-0` から `max-h-[var(--content-height)]` に切り替わることでアニメーションが動くという仕組みです。

CSS変数への値の登録は `style={{ "--content-height": height + "px" } as React.CSSProperties}` で行っています。

コンテンツの高さは padding を含めたいので、空divに `ref={ref}` を付けて取得しています。

# いかがでしたか。

いかがでしたか。
max-heightは神！！
いかがでしたか。
Tinkerboard2sのセットアップ

# はじめに
RaspberryPiは2023年6月では一般では在庫不足&高価格なため代わりにTinkerboard2sを使うことにしたがいかんせん情報が少ない。
今回はTinkerboard2sのosインストールやパッケージについて。
# 目次
<!-- タイトルとアンカー名を編集 -->
1. [Tinkerboardについて](#Chapter1)
1. [OSインストール](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="Chapter1"></a>
# 環境
Tinkerboard 2s
os:Debian 10.13

<a id="#Chapter1"></a>
# Tinkerboardについて
[公式サイト](https://tinker-board.asus.com/jp/)
Asusが開発しているが明らかにラズパイを意識している。
Tinkerシリーズということでいくつか製品があるがラズパイの互換などを考えると主にTinkerboard(以下、無印)とTinkerboard2/2s(以下、2)が使われると思う。2と2sはストレージ部分が違うだけでそれ以外の使用は同じ。注意しなければならないのがネット上の情報だと無印と2がごっちゃにされていることが多い。

<a id="#Chapter2"></a>
# OSインストール
今回は公式から出されているTinkerboard用のosを使用する。Tinkerboard用ではあるが基本的にはDebianなので問題はない。以下リンクからダウンロード。
https://tinker-board.asus.com/jp/download.html#os
製品によって微妙に中身が異なるので注意。今回は　Tinker Board 2 / Tinker Board 2S Debian 10 V2.1.11　を使用した。
これを解凍したらimgファイルをWin32DiskImagerなどでマイクロsdに書き込む。ソフトはos書き込み用であればある程度何でもよさそう。私はラズパイのimagerを使いました。sdカードは最低8GBは必要。

osインストールした後はsshがすでに使えるようになっているのでsshで操作もできる。アカウント名、パスワードはどちらも初期状態ではlinaro。wifiは5,2.4Ghzどちらも使用可能。もちろんlan端子もある。

<a id="#Chapter3"></a>
# ASUS.GPIO
Tinkerboardはラズパイ同様、GPIOピンを使うことができる。プログラム中でこれを制御するためのパッケージとしてASUS.GPIOがある。ラズパイにおけるRPI.GPIOと同じようなもので書き方もほとんどおなじ。
これをインストールしなければいけないが無印の場合は[公式](https://www.asus.com/jp/networking-iot-servers/aiot-industrial-solutions/tinker-series/tinker-board/)のとおりGithubからダウンロード、ビルドでいいらしい。**ただし2Sはこれではないので注意。**githubのものは無印ようで2Sにダウンロードしても使えない。しかも正しいパッケージと競合することもあるためお試しでも入れないほうがいい。
2S用のパッケージはosにプリインストールされている。なぜGithubなどにしなかったのかよくわからないがこれしかないのだからしょうがない。osをTinkerboard公式のosにしなかった場合にRPI.GPIOなどでGPIO制御が可能化はよくわからない。おとなしく公式に従っておこう。
[こちら](https://github.com/TinkerBoard/gpio_lib_python/issues/7)を参考にすると/usr/local/share/gpio_lib_python_rk3399/にパッケージがあることがわかると思う。そしたら
```
python3 setup.py
```
でインストールが行なわれる。これはpyhon版のパッケージでC版もあるらしいけどCのインストールとか使い方はわかりませんでした。
```
import ASUS.GPIO
```
でエラーが出なければ成功！

## GPIOピンの配置
GPIO制御パッケージはインストールできたがGPIOピン配置がわからなければ使えない。公式サイトには無印のGPIOピン配置は載っているが2Sのは掲載されていない。
```
gpio readall
```
このコマンドでGPIOのピン配置と電圧とかが見れる。


<a id="#reference"></a>
# 参考文献
- [Tinkerboard公式ページ](https://tinker-board.asus.com/jp/index.html)
- [Tinkerboard Github](https://github.com/TinkerBoard/gpio_lib_python)
- [The blog of H.Fujimoto](https://www.h-fj.com/blog/archives/2017/08/16-122100.php)
ReactのuseMemoとは何か？

# useMemo
```useMemoフック```は、***計算結果をキャッシュし、その結果を再利用するためのもの***で、
***計算に時間がかかる関数の結果をメモ化***するために使われます。

useMmeo構文
```
useMemo(() => 値を計算するロジック, 依存配列);
```
例えば以下のように使います。
```jsx
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
```
***computeExpensiveValueは計算コストの高い関数***で、***aとbがその関数の引数***です。
useMemoの第二引数には、この計算が依存する値（aとb）が含まれています。
***これらの値が変更された場合にのみ、computeExpensiveValueが再計算***されます。
それ以外の場合は、以前の結果がキャッシュされ、再計算されません。


```jsx
import React, { useState, useMemo } from 'react';

const ExampleComponent = () => {
  const [count, setCount] = useState(0);

  // 偶数の場合は "Even"、奇数の場合は "Odd" を返す
  const evenOrOdd = useMemo(() => {
    return count % 2 === 0 ? 'Even' : 'Odd';
  }, [count]);

  return (
    <div>
      <div>Count: {count}</div>
      <div>{count} is {evenOrOdd}</div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

export default ExampleComponent;
```
***countという状態変数を管理***し、それが***偶数か奇数かを表示***します。
useMemoフックは、***countが変更されたときにのみ、偶数か奇数かを計算し直します***。
その結果は***evenOrOddという変数に格納され、画面上に表示***されます。

***useMemoの第二引数***には、***countが含まれており、countが変更された場合にのみ再計算***されます。これにより、***偶数か奇数かの計算がcountが変更されない限り、同じ結果を再利用***します。

⚫︎補足
***useMemoの第二引数は[count]***。
この場合、***countが変更されたときにのみ、useMemo内の関数が再評価***されます。


# 有益資料
この資料だと詳しく載っています。

https://qiita.com/soarflat/items/b9d3d17b8ab1f5dbfed2#usememo


# 資料

ChatGPT

https://zenn.dev/chot/articles/react-when-to-use-memo
ITエンジニアの年収差は能力差では無い

長年エンジニア採用に関わって来て、ITエンジニアの年収差は決定的な能力差では決して無いと思います。

もちろん個人の努力の差はあるかもしれませんが、もっと影響力が大きい要素は、商流、工程と旬な技術に取り組めているかだと思います。

ITエンジニアとして、年収を上げていくには、この「商流」「工程」「旬な技術」大きなポイントになると言えます。


やはり2次請け、3次請けより、
プライムに近い方が年収は高い
-----------------------------------------------------

これはビジネス上当然な結果だと思います。
どんなに2次請けや3次請けの会社で努力しても、会社自体の収益性が悪くては、なかなかそこで働くエンジニアのお給料は上げづらいのが現実です。

特にIT業界未経験の方は、最初のステップとして、2次請け、3次請けの会社でキャリアをスタートした方もいるとは思いますが、年収アップのためなら、基本的な業務経験が身に付いたら、よりプライムに近い案件を多く扱う会社への転職を検討してみるのも一つの手です。


上流工程にチャレンジできるかどうか
---------------------------------------------
開発やテスト・運用保守よりも、基本設計や要件定義などの上流工程に関わっている方の方が年収は高い傾向があります。これも会社によっては、なかなか上流工程の案件にチャレンジできない会社もあります。

上司や、内勤社員、営業担当とコミュニケーションを取り、なかなか自分の会社では上流工程にチャレンジできるチャンスが無ければ、やはり転職も一つの選択肢に入れても良いのではないでしょうか。


旬な技術に関われているかどうか
-------------------------------------------------
例えばの話、Pythonをメインに開発をしているエンジニアと、COBOLをメインの言語としているエンジニアで根本的な能力差ってあるでしょうか？

（私は採用担当なので、実際にコーディングしたことはありませんが、Pythonのほうが簡単と言っているエンジニアに多く出会いました。。。）

でも結果的に言うと、COBOLエンジニアより、Pythonエンジニアの方が平均的に年収が高いのが現実です。同じ努力量ならより旬な技術に関われた方が年収は確実に上がります。
※どの技術にチャレンジするかを判断したり、情報収集する能力は必要だと思いますが。


最後に
---------------------------------
もちろん年収だけが全てでは無いですが、置かれている環境や仕事内容によって、同じ努力をしていて、能力開発をしていても、年収の差が出てしまうのも現実的には多くあります。

定期的にキャリアの棚卸や情報収集をしながら、転職も選択肢にいれて考えてみるのも良いかもしれませんね。


★こちらのセミナーもご検討ください！
-----------------------------------------

▼市場価値1,000万円超エンジニアの“課題解決力”
　～エンジニアリング×コンサルティング～
《8/24（木）19:30～20:30 ウェビナー》
https://akkodis-co-jp.zoom.us/webinar/register/WN_AlghgX65T26S2V_m0CsWtA#/registration

▼「エンジニアとして目指すキャリアプランを実現する」
　キャリアアドバイザー×エンジニア　オンライン座談会
《8/30（水）20:00～21:00 ウェビナー》
https://akkodis-co-jp.zoom.us/webinar/register/WN_ZCARrPJVRK-GgzMIQodvxw#/registration
【Flutter】TextFieldのカウンターを消す方法

`TextField`に`maxLength`を指定した際に、デフォルトでフォームの右下に入力した文字数のカウンターが表示されます。
これいらないんだよね。。ってときの対処法を教えます。

## 結論

`TextField`の`decoration`プロパティに、`InputDecoration(counterText: '')`を渡すだけ！！超簡単！！

```dart
@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample'),
      ),
      body: const Padding(
        padding: EdgeInsets.symmetric(horizontal: 30.0),
        child: Center(
          child: TextField(
            maxLength: 10,
            decoration: InputDecoration(
              hintText: 'TextField',
              counterText: '', // ここを追加！！
            ),
          ),
        ),
      ),
    );
  }

```

## 動作

counterTextをつけていないとき

<img width="300" alt="スクリーンショット 2023-08-23 18.13.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524065/5f4ad39f-9f6e-6f15-bc2a-21c4bf4c42f3.png">

counterTextをつけたとき

<img width="300" alt="スクリーンショット 2023-08-23 18.12.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524065/eb0b1dfa-ecc7-17b7-3630-11eb5d638f9e.png">
Gitコマンドチートシート

# 背景
最近TerraformでAWS環境を触っているのですが、terraformのコード管理にGitを使っています。忘れがちなので、自分への備忘録として残しておきます。

# ざっくりとしたGit構成のイメージ

pushまでの流れ
![git.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3161388/585256fd-9390-c40e-a8cf-cd46d4c0e828.png)
diffの対象
![git2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3161388/1d544a3c-5ef7-a8fe-5787-27c3c810378d.png)
git resetの対象
![スクリーンショット 2023-09-08 135710.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3161388/afd8494b-a942-3b47-d308-1d695fdd59b2.png)


# コマンド一覧
```
#ローカルにgitリポジトリを作成する
$ git init
　➡ステージングやローカルリポジトリが作成される
```

```
# リモートリポジトリをローカルに落とす
$ git clone "リモートリポジトリのURL"

# リモートリポジトリ構造ごとをローカルに落とす
$ git clone --mirror "リポジトリのURL"
　➡git設定ファイルやログなども丸ごと落とせる
　　落としたフォルダに対してcloneすれば通常通り使用できる
```
```
# ブランチ新規作成＆切り替え
$ git checkout -b "ブランチ名"

# 既存のブランチに切り替える
$ git checkout "ブランチ名"
```
```
# 適用されているブランチを表示
$ git branch

# 全てのブランチを表示
$ git branch -a

# masterからmainブランチに変更
$ git branch -m master main
```
```
# ステージング
$ git add "ステージングする対象ファイルのパス"

$ git add . 
　➡カレントディレクトリ以下を対象にする
```
```
# ワークツリーとステージ比較
$ git diff

# ステージとローカルリポジトリ比較
$ git diff --staged
```
```
# 作業ディレクトリの状態とステージング エリアの状態を表示する
$ git status

➡下記3点を表示
・git add されているけどまだ git commit されていないファイルの一覧
・編集・変更・削除されているが、まだ git add されていないファイルの一覧
・git管理されていない、かつ .gitignore で管理除外対象にもされていないものの一覧
```
```
# -m でコメントを記載してcommit
$ git commit -m "コメント"
```
```
# 現在のリモートリポジトリURLを確認
$ git remote -v
```
```
# リモートリポジトリを登録
$ git remote add origin ${リポジトリのURL}
```
```
# リモートリポジトリの変更
$ git remote set-url origin ${新しいURL}
```
```
# ローカルリポジトリからリモートリポジトリにpushする
$ git push ${反映したいリモートリポジトリ} ${ローカルのブランチ}

$ git push origin main 
　➡originはgit remote -vで確認可能
```

```
# commitの取り消し(コミット・ステージ・作業ディレクトリ取り消し)
$ git reset -hard

# commitの取り消し(コミット・ステージ取り消し)
$ git reset -mixed    

# commitの取り消し(コミット取り消し)
$ git reset -soft    
```

```
# リモートリポジトリのファイル削除(ローカルリポジトリはそのまま)
git rm --cached ${削除したいファイル}
➡コマンド実施後pushで反映
　.gitignoreファイルにリモートに反映したくないファイルを追加
```

```
# ログ確認
git log --graph
```

```
# ブランチ確認
git branch

# ブランチ作成
git branch <ブランチ名>

# ブランチ切り替え
git checkout <ブランチ名>

# ブランチ作成＆切り会え
git checkout -b <ブランチ名>
```

```
# マージ
git merge <取り込みたいブランチ>
　# 統合先のブランチにいることを確認
```

参考
https://www.r-staffing.co.jp/engineer/entry/20191129_1
native-baseのModalでスクロールした際に、checkboxやradioボタンだとクリックした箇所にスクロールしてしまう

【前提】
・nativebaseのModalを使っている。
・そのモーダルは表示内容が多く、スクロールさせるようになっている。
・checkboxかradioボタンがそのモーダルに存在している

【事象】
①native-baseのModalを使って、何か初期表示の箇所のcheckboxやradioボタンをクリックする。
②その後、Modalのスクロールを行い、別のcheckboxかradioボタンをクリックする。
※InputやSelectでは発生しない
③①でクリックした箇所に勝手にスクロールが戻ってしまう。

【解決策】
```
<Modal.Body p="0" _scrollview={{ focusable: false }}>
　　　{children}
</Modal.Body>
```
_scrollview={{ focusable: false }}
をModal.Bodyに入れると解決する。

【備考】
そもそもnativebaseをReact環境で使うという変わった状態かもしれませんが、そういう状況が起きました。
【Laravel】formのaction属性に設定したURLがhttp始まりでPOSTメソッドの処理がうまくいかなかったときにやったこと

## 環境
 - PHP 8.0.28
 - Laravel 9.52.15
## 事象について
POSTメソッドで実行されるフォームを動かしたところ
なぜかGETメソッドで実行されてしまう事象が発生。

### 実行結果
submitボタンを押したら見慣れない画面が出てきた…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737484/ed636678-74b3-77ef-e11a-b516a4d0a677.png)

このまま送信をしたら、なんかGETで呼び出されてる…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737484/abe13051-7c8b-da96-39e6-9d64b56a9d74.png)



## 原因
フォームのaction属性に定義されてるURLがhttps始まりではなくhttp始まりになって
混合フォームとなってたことで想定外の処理結果となってた模様。
このまま送信を押した後に、開発ツールでリクエストの内容を確認したらGETで送られてたので
確認画面のボタンを押したときにGETに置き換えられてしまったみたい。

### Viewに書いたコード
```
<form action="{{ url('send') }}" method="POST" class="form-horizontal">
```

### HTML出力結果
```
<form action="http://*******/send" method="POST" class="form-horizontal"></form>
```

### 混合フォームって？
WEBページへのアクセスにはHTTPSが使われてるけど
そのページ内にあるフォームの送信先などがHTTPで定義されてる場合のことを指す。



### 解決策
こちらの記事を参考にapp/Providers/AppServiceProvider.php内のboot関数内にURL::forceSchemeを追記したところ解決した。(URLがHTTPS始まりになりPOSTメソッドでリクエストされるようになった)
[Laravelのrouteがhttpになる【HTTPS化】]('https://rapicro.com/laravel%E3%81%AEroute%E3%81%8Chttp%E3%81%AB%E3%81%AA%E3%82%8B%E3%80%90https%E5%8C%96%E3%80%91/')

```app/Providers/AppServiceProvider.ph
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\URL;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot() {
        if (App::environment('production','staging','local')) {
            URL::forceScheme('https');
        }
    }
}

```
Javaで「テキストをファイルに書き込む」の動作を確認してみた

# 概要
Javaで「テキストをファイルに書き込む」の動作を確認してみました。以下のページを参考にしました。

https://www.javadrive.jp/start/stream/index4.html

# 実装
以下のファイルを作成しました。
```StreamTest4.java
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

class StreamTest4{
  public static void main(String args[]){
    try{
      File file = new File("test.txt");

      if (checkBeforeWritefile(file)){
        FileWriter filewriter = new FileWriter(file);

        filewriter.write("こんにちは\r\n");
        filewriter.write("お元気ですか\r\n");

        filewriter.close();
      }else{
        System.out.println("ファイルに書き込めません");
      }
    }catch(IOException e){
      System.out.println(e);
    }
  }

  private static boolean checkBeforeWritefile(File file){
    if (file.exists()){
      if (file.isFile() && file.canWrite()){
        return true;
      }
    }

    return false;
  }
}
```
以下のコマンドを実行しました。
```
$ javac StreamTest4.java 
$ java StreamTest4
```

# まとめ
何かの役に立てばと。
C#とVB.NETでPDF を Excel に変換する

## はじめに
PDFはデータの保存や転送には非常に便利ですが、データを処理する場合はExcelがより適しています。そのような場合には、PDFをExcel形式に変換することができます。これにより、PDFからデータを抽出したり、編集したり、分析したりすることが非常に便利です。以下に、詳細な手順をご紹介します。
## ツール
* Visual Studio 2022 
* [Free Spire.PDF for .NET](https://www.e-iceblue.com/Introduce/free-pdf-component.html)

このライブラリは、無料でPDFファイルを作成、編集、変換することができますが、ページ数の制限があります。または、有料版の製品の無料トライアルを申し込むこともできます。
[Spire.PDF for .NET](https://www.e-iceblue.com/Introduce/pdf-for-net-introduce.html)

## インストール方法
1. [Free Spire.PDF for .NET](https://www.e-iceblue.com/Download/download-pdf-for-net-free.html)をダウンロードします。
2. Visual Studioで新しいプロジェクトを作成します。
3. 「Solution Explorer」で「References」を右クリックし、「Add Reference」>「Browse」を選択します。
4. BINフォルダ内のdllファイルを見つけて、「OK」をクリックします。

## コード
**C#**:
```c#
using Spire.Pdf;
using Spire.Pdf.Conversion;
namespace ConvertPdfToExcel
{
    class Program
    {
        static void Main(string[] args)
        {             
            //PdfDocumentクラスのインスタンスを初期化する
            PdfDocument pdf = new PdfDocument(); 

            //PDFドキュメントをロードする
            pdf.LoadFromFile("sample.pdf");              

            //PDFドキュメントをXLSXに保存する
            pdf.SaveToFile("PdfToExcel.xlsx", FileFormat.XLSX);        
        }    
    }
}
```
**VB.NET**:
```VB
Imports Spire.Pdf
Imports Spire.Pdf.Conversion

Namespace ConvertPdfToExcel
    
    Class Program
        
        Private Shared Sub Main(ByVal args() As String)
            'PdfDocumentクラスのインスタンスを初期化する
            Dim pdf As PdfDocument = New PdfDocument

            'PDFドキュメントをロードする
            pdf.LoadFromFile("sample.pdf")

            'PDFドキュメントをXLSXに保存する
            pdf.SaveToFile("PdfToExcel.xlsx", FileFormat.XLSX)
        End Sub
    End Class
End Namespace
```
このコードでは、PdfDocument クラスのインスタンスを初期化します。次に、PdfDocument.LoadFromFile() メソッドを使用して 「sample.pdf」をロードします。そして、PdfDocument.SaveToFile() メソッドを使用してPDF を Excel に保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/ec23c186-f7e4-9211-edfb-7320f1086d23.png)
aws-portal廃止に伴い請求関連の権限を整理しました

AWSからリマインドメールが来ました。
サービスプレフィックス`aws-portal`を廃止して新しく細分化するので、2023年12月までにポリシーのIAMアクションを修正して下さい、とのこと。

https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/migrate-granularaccess-whatis.html

現状のIAMポリシーは次の通りです。

```json:現状
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "aws-portal:*Billing",
                "aws-portal:*Usage",
                "aws-portal:*PaymentMethods"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Deny",
            "Action": "aws-portal:*Account",
            "Resource": "*"
        }
    ]
}
```

これは経理部門向けに僕が作ったポリシーでした。
このポリシーに紐づくIAMアカウントでAWSコンソールにログインすると、請求（支払い）に関する殆どの操作を実行できます。逆に言うと、それ以外のことは権限を与えていないので出来ません。

定義を修正したので、以下に手順を残します。

# 修正手順
▼ IAMダッシュボードで「影響を受けるポリシーを表示」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/f807e0f6-adc4-74f5-8848-355c762b5676.png)
▼ 新しいアクションを有効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/9bcfbdec-7cf1-f8f1-b65e-5e15adda5d49.png)
▼ YES をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/6b439960-479b-55db-94d6-14323c70d66f.png)
新しいアクションが有効になりました。
いつでも、この画面から古いアクションに戻せます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/af2fe5fa-5f3f-74a5-9526-159baf56bdcb.png)
ちなみに、この状態で、経理のアカウントで請求画面に行くと「アクセス拒否」となります。
古いアクションが無効になっているからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/1d39ccbf-52d6-aceb-99b6-caec64866cd8.png)
古いアクション`aws-portal`を、新しいアクション`account`、`billing`、`payments`、`freetier`、`invoicing`、`tax`、`consolidatedbilling`に置き換えます。

新しいアクションでは、きめ細かい制御が可能です。

経理部門の実際の運用に照らし合わせると、

- 請求書
- 支払い
- 請求設定
- お支払いの詳細設定

のみにアクセスできれば良いので、この機会に権限を整理します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236222/34978045-0467-7408-dae2-513bde9fdecd.png)

修正後のIAMポリシーは次の通りになりました。

```json:修正後
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
				"account:GetAccountInformation",
				"account:GetContactInformation",
                "billing:*",
                "cur:*",
                "invoicing:*",
                "payments:*",
                "purchase-orders:*",
                "consolidatedbilling:*",
                "tax:List*",
                "freetier:Get*"
            ],
            "Resource": "*"
        }
    ]
}
```

明示的なDeny（拒否）はありませんが、暗黙のDenyが適用されるので問題ありません。
文系出身が1年エンジニアしてみたけど実際どうなん？話

# はじめに
前回の記事でも書いていますが、私は文系出身未経験インフラエンジニアです！
大学では太宰治の研修なんかをしていたど文系です……
そんな私が昨年4月に入社し、約1年3か月経った今実際どうなったのか
どこまで成長したのか正直にお話ししたいと思います。

# 最初の私
エンジニア配属になって1番最初の私はほんっとうに何も知りませんでした！！！
IPアドレスとは何ぞや、Gitってなに、クラウドって雲？？？ってくらい無知です。
開発を志望してエンジニアになったわけでも正直なかったので、技術大好き！
プログラミング楽しい！というタイプでもありません（笑）


# 1年でやったこと
入社して半年は社内研修をしました。
弊社はエンジニアだけでなく、コンサルと営業の研修もするので社会人の基礎的な研修を受け、エンジニアとしての研修を受けました。
その後、自部署での研修を受けて、10月に正式にチームに配属されました。

以下配属されてから取り組んだことです。
* 商用環境の死活監視
* 商用環境の障害復旧、調査
* AWS周りの開発
* Jenkinsを使ったジョブ開発
* 既存ツールのBugFix（3件くらい）

どれも小さい案件ではありますが、ざっとこのくらいだと思います。

# キャッチアップ
初心者すぎるので、案件1つ1つに対していちいちキャッチアップが必要でした。
キャッチアップ方法は以下大きく3つです。
***

**自分で情報を集める→わからないところ切り出す→聞くを繰り返す**
***
わからな過ぎて質問の場を設けてもらっても、質問内容がわけわからんみたいなことが多発しました。
これでは先輩の時間も奪ってしまうな、、と思ったので、間違っていてもまずは情報収集する。<br>そして仮設を立てて答え合わせしてもらうようにしました。
何も準備せずに質問するより何倍も効率的なでした。（今思うと当たり前ですが…）

**週1で同期とatcoderを解く会を実施** 
***
最初はコードを見るだけでアレルギーでした。
なので、1人だと絶対頑張れない…！と思い、同期にお願いして一緒にatcoderの問題を解き始めました。
今でも読み始めるまでは嫌だな～と思いますが、前よりアレルギーはマシになったかなと（笑）

**テストケースを書いて、とにかくレビューをもらう**
***
私のチームは自分でコードを書いて、自分でテストするというフローになっています。
もちろんテストってなんぞや状態だったので、まずは色々な方のテストケースを見ました。
そして最初は見よう見まねで書いて、レビューをもらうの繰り返しでした。
今でもレビューで指摘はもらいまくるのでまだまだテストは苦手です。。。

# 成長したのか
正直成長している実感はあんまりないです。。。
ですが、**これ前回対応したな → 応用でやってみよう**という場面が出てきたのは成長かなと思います。
どこまでできたら1人前なのか、
どこを目標として目指すのか考えておかないと、いつまでもできない自分に絶望すると思います（笑）
1年後どういう状態の自分になりたいのか考えないとなと思っています。

# 1年エンジニアしてみて実際どう？
開発は特に好きになっていないですね（笑）
正直向いてるとも思ってないです！！
でも、開発できたら今後の人生強いよねと信じて今は勉強の時だと思っていますし、
できるようになった時に少しは楽しくなるところを目指しています。
上司には、「まだ1年くらいしかやってないから諦めるのは早いよ～」と言ってもらえたので、英語だって1年じゃ習得できないもんね…！と思うことにしました。
正直開発は分からないことと、できない自分との戦いだと思います。。。
逆に分からないことを解いていくのが楽しい人は向いているのかなと思います。
結構ネガティブな感想が多いですが、働く環境としてはとても満足しています。
一言でいうと、
**できない自分と向き合うのつらー！！！！**
という感じですかね（笑）

来年あたりには結構分かること増えてきた！と言えるように精進したいです。
MSTESTでconfigファイルが読み込めないときの対処

背景：MSTESTを使って単体テストを実行しようとしたところ、テスト対象のクラスでエラー。該当の箇所は設定ファイル（.config）を呼び出したコードだった。
単体テストはテスト対象のクラスで右クリック>「単体テストを作成」で作成したMSTESTプロジェクト。
MSTESTプロジェクトでApp.configを置いていたものの、エラーが発生した。

```:テスト対象クラス
//ここでエラー 'System.NullReferenceException: 
//Object reference not set to an instance of an object.'
ret = ConfigurationManager.AppSettings["キー名"].ToString();
```

原因：ではどの設定ファイルを呼んでいるか、ということを次のコードで発見した。

```:テスト対象クラス
var configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
```

このconfigFileという、インスタンスのFilePath変数に読み込んでいるconfigファイルが記載されていた。私の場合はテストプロジェクトのbinの中にある（ことになっている）testhost.x86.dll.configだった。

だが、ConfigurationManager.AppSettings["キー名"]　での取得はConfig\machine.configという値になっていて不明なファイルを取得していた。
testhost.x86はテストユニットをx86で実行した際に作成されるものだそう。つまりプラットフォームがAny CPUで実行したときのような挙動をしていなかったため、App.configは読み込まれていなかったようだ。

対処法①　置き換え
最も安易な対処法としてはそのconfigファイルを作ってApp.configの内容をそのままコピペすることだろう。

対処法②　コード上で修正
以下のコードを書くことで読み込むconfigファイルを指定できる。

```
var configFile = @"Hoge.config";
            var exeFileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile };
            var config     = ConfigurationManager.OpenMappedExeConfiguration(exeFileMap, ConfigurationUserLevel.None);
```
(cf. https://devlights.hatenablog.com/entry/20110203/p1)
この後に
var settings = configFile.AppSettings.Settings;
settings["キー"].Value = "";
とすればキーが持つ値の書き換えもできる。

対処法③ プロジェクトファイルで指定
ややこしそうなので試していないが、プロジェクトファイルに読み込むconfigを指定すればコードなどを追加することなく指定できそう。
(cf. https://araramistudio.jimdo.com/2023/07/30/c-app-config%E3%82%92debug%E3%81%A8release%E3%81%A7%E4%BD%BF%E3%81%84%E5%88%86%E3%81%91%E3%82%8B/)

結論：今回はプラットフォームの違いで既定のconfigファイルが読み込まれていなかった模様。どのファイルを使用しているかを知るにはconfigファイルの内容だけでない、OpenMappedExeConfiguration()の使用が必要だった。
スッキリわかるJava入門 第３版を読んでみて- part14 - Javaを支えるクラスたち

# はじめに
こんにちは(・ω・）ﾉ
今回はObjectクラスや静的メンバについて学びました！
## 第１４章　Javaを支えるクラスたち
### 1.Javaが備えるAPI群
これまでJavaの基本文法とオブジェクト指向の概念について学びました。
規模の大きなプログラムでも現実世界を模して混乱せずに開発することが可能になりました。
しかし、大規模なプログラムを１人で開発するのは時間とお金の無駄になる...
そこでJavaに標準添付されているJacaAPIを使います。

API活用に欠かせない基礎知識について学んでいきます。

### 2.すべてのクラスの祖先
すべてのクラスがtoString()を持っている
⇨メソッドもフィールドもいっさい定義していないクラスのtoString()を呼び出せるはなぜ？

:sparkles: 暗黙の継承
あるクラスを定義するときextendsで親クラスを指定しなければ、
java.lang.Objectを親クラスとして継承したとみなされる

extendsを指定しなくても必ずObjectを継承する
⇨Javaでは親なしのクラスを定義できないということ
様々なクラスも親クラスを辿っていくと、最終的にはjava.lang.Objectクラスに到達する

APIリファレンスを調べると全クラスの祖先のObjectクラスには次のメソッドが定義されている
・equals()　あるインスタンスと自分自身とが同じかを調べる
・toString()　自分自身の内容の文字列表現を返す

toStringを呼び出せるのは暗黙の親クラスであるObjectクラスから継承しているため

:question:なぜObjectクラスがあるのか
1.多態性を利用できるようになるから
2.すべてのクラスが最低限備えるべきメソッドを定義できるから

:sparkles: 等値と等価
等値　同一の存在であること
　「==」を使った判定
等価　同じ内容であること
　「equals」を使った判定

:sparkles: toString()とequals()のオーバーライド
新しくクラスを開発したら、toString()とequals()をオーバーライドする必要性がないかを検討する

### 3.静的メンバ
__静的メンバ__...staticキーワードが付けられたフィールドやメソッドのこと

##### 静的フィールド
staticキーワードを指定したフィールドのことで３つの特殊な効果をもたらす

1.フィールド変数の実体がクラスに準備される
:pencil2: 静的フィールドへのアクセス方法
`クラス名.静的フィールド名`

2.全インスタンスに箱の分身が準備される
:pencil2: 静的フィールドへのアクセス方法
`インスタンス変数名.静的フィールド名`

3.インスタンスを１つも生み出さなくても共有の箱が利用可能になる
:sparkles: public static fainal コンビネーション
多くの場合、staticはfinalやpublicと一緒に指定され、
「変化しない定数を各インスタンスで共有するため」に利用される

##### 静的メソッド
staticキーワードがついているメソッドのことクラスメソッドとも呼ばれる
以下の３つの効果が現れる

1.メソッド自体がクラスに属するようになる

2.インスタンスにメソッドの分身が準備される
:pencil2: 静的メソッドの呼び出し

3.インスタンスを１つも生み出すことなく呼び出せる

##### 静的メソッドの制約
静的メソッドの中に記述するコードでは、
同一クラス内のstaticがついていないフィールドやメソッドは利用できない

## まとめ
javaにおいてすべてのクラスはObjectクラスの子孫である。
そのためすべてのクラスはObjectからtoString()やequals()を継承している。
フィールドやクラスにstaticをつけて宣言すると静的メンバとして扱われる。
静的メソッドを使うことで、クラス名とインスタンス名のどちらからでも同じ実体にアクセスすることができたり、インスタンスを生成していなくても利用することができる

今回もありがとうございました！
ではまた〜　＊˙︶˙＊)ﾉ"
Apache2のインストール手順

## はじめに
Ubuntu20.4にApache2をインストールする手順です。現状の最新バージョンはApacheではなくApache2です。Apacheは1998年に登場して2002年にApache2が登場しました。バージョンのリリース時期については、下記に詳しく載っています。
https://trios.pro/apache-version-list/

ApacheからApache2がバージョンアップされたことで、ディストリビューションによっては、大きな変更が加えられています。旧バージョンのApacheにおいては、CentOSでもUbuntuでもサービス名は**httpd**でしたが、Apache2になって、Ubuntuだけサービス名が**apache2**になっています。

コンフィグファイルがあるディレクトリも、CentOS、Ubuntuともに **/etc/httpd**でしたが、Apach2になって、Ubuntuだけ **/etc/Apache2**になっています。

## 環境
Ubuntu20.4
Vagarant

## インストール

Ubuntu20.4にはApache2はプレインストールされていません。Apache2をインストールする前に、確かにインストールされていないことを確認します。
```
$apt list --installed | grep apache
```

Apache2はAPTでインストールします。APTのリポジトリにApache2が確かに存在していることを確認します。
```
$apt list | grep apache2
```

Apache2をインストールします。このとき、開発ヘッダも一緒にインストールします。インストールは割と早く終わります。
```
$sudo apt-get update
$sudo apt-get install apache2 apache2-dev
```

インストールできたことを確認します。どちらのコマンドでも同じようにバージョンが確認できます。
```
$apache2 -v
$apachectl -v
Server version: Apache/2.4.41 (Ubuntu)
```

サービスの状況を確認します。 **Active: active (running)** となっていればサービスが起動されています。起動されていなければ **Active: inactive (dead)** と表示されます。インストールすれば、サービスも自動で起動されるようになっています。
```
$systemctl status apache2
```

Ubuntu環境で次のコマンドを入力すれば、そのようなサービスは存在しませんと表示されます。サービス名がApache2ではなくhttpdであるのはCentOSの方だけです。
```
$systemctl status httpd
Unit httpd.service could not be found.
```

## 動作確認

サービスが既に起動しているため、ブラウザを起動してURLにIPアドレスを指定すると、Apache2の初期画面が表示されます。自分の環境はVagrantであるため、URLに192.168.10.33を指定すると、次の画面が表示されます。

![apaceh2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94029/9d939efc-0081-5cba-f2ac-0568a80e28f2.png)

試しに、サービスを停止して、ブラウザをリロードすると「このサイトにアクセスできません」と表示されます。
```
$systemctl stop apache2
```

再度、サービスを開始して、ブラウザをリロードすると、Apache2の初期画面が再度表示されるようになります。
```
$systemctl start apache2
```

## 参考サイト

https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-ubuntu-20-04-ja

https://tutorialcrawler.com/ubuntu-debian/ubuntu-20-04%E3%81%ABapache-web%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/

http://www.yamamo10.jp/yamamoto/comp/home_server/WEB_server3/apache/index.php#BASIC
WSL2環境でのfish-shellが、選択したpromptによっては動作が重く感じるとき

## TL;DR

自分はMercurialでバージョン管理を行っていないので、その`hg`コマンドを実行しないようにしたことで動作を軽くしました。

1. `funced`コマンドで、`fish_vcs_prompt`を開く

   ```shell
   funced fish_vcs_prompt
   ```

2. `fish_vcs_prompt`の中身を以下`fish_hg_prompt`関数をコメントアウトする

   ```diff
   function fish_vcs_prompt --description "Print all vcs prompts"
       # If a prompt succeeded, we assume that it's printed the correct info.
       # This is so we don't try svn if git already worked.
       fish_git_prompt $argv
   -    or fish_hg_prompt $argv
   +    #or fish_hg_prompt $argv
       # The svn prompt is disabled by default because it's quite slow on common svn repositories.
       # To enable it uncomment it.
       # You can also only use it in specific directories by checking $PWD.
       # or fish_svn_prompt
   end
   ```

3. 保存するか聞かれるので、`y`を入力して保存する

## どういうときに重く感じたのか

ターミナル上でEnter(Return)キーを連打したとき、行移動が連打に追いついていない感じがしていました。
調査したところ、`fish_vcs_prompt`関数が原因でした。

もう少し具体的には、以下の条件のときに重く感じていました。

- `fish_config`で、git等の状態を表示するpromptを選択しているとき
- カレントディレクトリがバージョン管理されていないとき (rootディレクトリなど)

## 比較

`time fish_vcs_prompt %s`コマンドを実行して、実行時間を比較します。
コメントアウト前後と、リポジトリの有無で比較します。

| ファイルの編集 | リポジトリの有無 | 実行時間 |
| --- | --- | --- |
| 変更前 | あり | 26.54 millis |
| **変更後** | あり | 24.40 millis |
| 変更前 | **なし** | 117.09 millis |
| **変更後** | **なし** | **1.89 millis** |

## 確認環境

- WSL

  ```pwsh
  > wsl --version
  WSL バージョン: 1.2.5.0
  カーネル バージョン: 5.15.90.1
  WSLg バージョン: 1.0.51
  MSRDC バージョン: 1.2.3770
  Direct3D バージョン: 1.608.2-61064218
  DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
  Windows バージョン: 10.0.22621.2134
  ```

- OS

  ```bash
  $ cat /etc/os-release
  NAME="Ubuntu"
  VERSION="20.04.6 LTS (Focal Fossa)"
  ID=ubuntu
  ID_LIKE=debian
  PRETTY_NAME="Ubuntu 20.04.6 LTS"
  VERSION_ID="20.04"
  HOME_URL="https://www.ubuntu.com/"
  SUPPORT_URL="https://help.ubuntu.com/"
  BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
  PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
  VERSION_CODENAME=focal
  UBUNTU_CODENAME=focal
  ```

- fish

  ```bash
  $ fish --version
  fish, version 3.6.1
  ```

## 参考リンク

- [fish_vcs_prompt - output version control system information for use in a prompt](https://fishshell.com/docs/current/cmds/fish_vcs_prompt.html)
- [funced - edit a function interactively](https://fishshell.com/docs/current/cmds/funced.html)
やはりlogicoolしか勝たん。最強のマウスとキーボード

# logicoolが結局最高なのよ
Qiitaの[100万人に届けたい！私のお気に入りガジェット](https://qiita.com/official-events/8644e9719b0040cc1817)キャンペーンに則って、
私の相棒たちを紹介したいと思います。

![IMG_3365.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2734332/f567b51c-4965-7f45-e088-33a1f9d13eb5.jpeg)


- [ERGO K860 ワイヤレススプリットエルゴノミックキーボード](https://www.logicool.co.jp/ja-jp/products/keyboards/k860-split-ergonomic.920-010115.html)
- [MX ERGOアドバンス ワイヤレス トラックボール MXTB1s](https://www.logicool.co.jp/ja-jp/products/mice/mx-ergo-wireless-trackball-mouse.910-005183.html)

結局この子らが最強なんです。
もう**logicoolしか勝たん**と思っています。

偏見に満ちた記事ですが本編をどうぞ。

# [ERGO K860 ワイヤレススプリットエルゴノミックキーボード](https://www.logicool.co.jp/ja-jp/products/keyboards/k860-split-ergonomic.920-010115.html)

## エルゴノミック スプリットキーボード
タイピング時の姿勢を改善し、手首や前腕の筋肉緊張を軽減する曲線的なキーフレームが特徴

**とことん入力に関するストレスが少ない！記事の執筆もプログラミングも生産性爆上がり！**

## パームレスト付き  手首や手のひらを快適にサポートする3層構造のパームレストが付属、高さ調節も可能

**手首の置き所が宙ぶらりんにならず楽・・・**

わ、私こんなに手首を支えるのに力を使ってたのね、あらやだと思うくらい、ストレス軽減

## ワイヤレス接続

BluetoothやUSBレシーバーを使って、最大3台のデバイスとワイヤレスで接続、
**切り替えも簡単**

今の時代PCなんて何台あっても足りませんわ！
そんなときにこれ一台でさっと切り替えて最高の入力体験！

### 総じて最高

とにかくデカさに面喰いますが、一方でホントに**超快適**
**この大きさと多機能であることは全てを解決する**

# [MX ERGOアドバンス ワイヤレス トラックボール MXTB1s](https://www.logicool.co.jp/ja-jp/products/mice/mx-ergo-wireless-trackball-mouse.910-005183.html)

## エルゴノミックデザイン
- 手の形状に合わせて作られ、高速で精確なトラッキングが可能
- 調節可能な傾斜角度
    - 0°または20°の独自の傾斜角度で、手と手首の位置を調整、長時間使用でも快適

自分に合わせた角度調節って、何ってワガママ仕様！！！

でも嬉しいんです、自分に合った角度なんて人それぞれだから！
**愛のままにわがままに このマウスだけはワイを傷つけない**

## 筋肉疲労の軽減
 - 通常のマウスに比べて、手、手首、前腕の筋肉疲労を20%軽減(公式曰く

腱鞘炎は天敵。PC主体で仕事をする世の中、マウスで手を痛めるなんてもってのほか!!
そんな問題とはオサラバ！ナイスなマウス🐀

## カスタマイズ可能
 - 使用しているアプリに応じて完全にカスタマイズが可能

Logi Optionsによってサポートされているアプリに応じた機能が自由に設定できる！！
ごめんなさい、この機能あんまり使っていない・・・

## 長持ちするバッテリー
- フル充電後、最長4ヶ月間持続、31分間の充電で最長1日使用可能

やっぱり充電式。安心ですよ。
**うおっ！電池忘れた！！** というリスクとオサラバですもの。

しっかりとPCでバッテリー残が少ない通知も来ますし、USBでスグに充電。
持続的よね。

### 総じて最高

この**圧倒的高級感**。機能性。
**King Of Mouse🐀**


# 彼らを支えるサポーター Unifying
Bluetoothは稀につながらなくなったりしますが、logicoolには
[Unifying](https://www.logicool.co.jp/ja-jp/resource-center/what-is-unifying.html)があります。

製品を買うたびに付属しているケースが体験では多いので、増殖しますが
- **ワイヤレス接続で最大10メートルの接続**
- **サクっと差し込んですぐ使用！**

といった利点があります。すぐモノをなくす私ですが、このレシーバーは**安価で安心**
なくさない方がいいですが・・・💦

# logicool製品最高！

ということで自分の大好きなガジェットをお伝えしました！
購入に迷う方に伝われば幸いです! Good bye!