OmniAICreator/Qiita-1.07M huggingface dataset:
IBM Cloud Pak for Dataでデータの仮想化

　DXの中で”データ仮想化”というのを最近聞くようになってきたのでどんなものだろうかとりあえず触ってみました。
https://japan.zdnet.com/bigdata/sp_21data_virtualization/
プラットフォームはIBM CloudのSaaS, Watson Queryを使ってみました。
https://www.ibm.com/jp-ja/analytics/data-virtualization
ライトプランがあるので無料で試せます。

手順は
1. 仮想化で使うデータソース、データベースを構築
　（今回はIBM CLoudの別アカウントにあるDB2 on Cloudを使いました。これも無料のライトプランで使えます）
2. IBM CLoudでWatson Queryをオーダー、サービスを作成
3. Watson QueryからDB2への接続を設定する。

1. 仮想化で使うデータソース、データベースを構築
　こちらは今回はIBM CLoud上の無料データベースを使いました。具体的な使い方は
https://qiita.com/Asuka_Saito/items/c40a17f02a588953f576
を参考にしました。作成したら資格情報の
　データベース名、DBホストのIPアドレス、ポート、ユーザー名、パスワード
になります。それらをメモしておきました。

2. IBM CLoudでWatson Queryをオーダー、サービスを作成
 IBM CLoudにログインしてカタログ（https://cloud.ibm.com/catalog)　からWatson Queryを選んでオーダー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/52aab009-95d0-5980-c858-bf6e35d8b5dd.png)
無料のLiteが選択されていることを確認して”作成”
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/d8708896-ca06-c1d6-ef59-c6e8af2d666c.png)
"Launch in IBM CLoud Pak for Data"をクリックするとCloud Pak for Dataの画面になりデータ仮想化のWatson Queryを使えるようになります。

3. Watson QueryからDB2への接続を設定する。
 こちらがCloud Pak for Dataの画面です。(Watson Query以外のサービスでも使っていたのでその時のカタログやプロジェクトがありますが）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/bf118511-0335-ea08-0317-8e6e9aefe384.png)
データ仮想化は左側のメニューから選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/9bd1baaa-b0b7-6d16-eddd-04e85dbf3701.png)
右側の”接続の追加”でデータソース（今回はIBM CLoud上のDb2データベース）に接続します。接続の追加--> 新規接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/e4e2c041-a068-3875-5b68-49be89e79c4e.png)
データソースのタイプを選びましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/e4444326-8f22-c9f8-30e0-44ce05e252b1.png)
　1（仮想化で使うデータソース、データベースを構築）で得られた値を入力します。
*ポートはSSL対応はチェックします。証明書はいらない
(注：証明書いらないのはIBM cloud上のDb2かDb2 Warehouseです。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/c44ebde9-f52b-4591-4d19-cf2f74f10801.png)
右上の”接続テスト”をクリックして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/65180eb3-36b5-c1ad-1c81-2cf4d2436eda.png)
問題なければ以下のようなメッセージが出ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/2113508b-c4ac-ecdd-0350-a654420fd105.png)
右下の”作成”でデータソースとつながりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59741/b676f550-73fa-0461-7069-c744cc648596.png)

この後以下の記事を参考に仮想化を勉強しました。
https://qiita.com/tags/watsonquery
【AWS】Lambda関数でEC2の情報を取得する、ということ

# 初めに

閲覧いただきありがとうございます。

突然ですが、私は最近クラウド未経験からAWSシステム担当のエンジニアに転職を果たしました！

そんな私ですが、コスト削減として社内の研修環境の不要なEC2削除をするために
EC2の情報を取得するLambda関数を作成するお仕事をする機会がありました。
そこで、かなり沼った＆あまりクリティカルな記事がネットになかったので備忘も兼ねて記事にしたいと思います。

最終的には結構複雑なことをするLambda関数を作成したいのですが、
段階的に、まずは**EC2の情報を単純に引っ張ってくるだけのLambda関数を作りたい**と思ったので
今回のゴールとしてはそれを実施し問題なく取得した情報を確認できることとしたいと思います。

ちなみに私のレベルは以下程度で、かなり初学者的な詰まり方をしているので、
その前提で温かく読んでいただければと思います。。
・AWS実務経験ほぼなし
・SAAは2022年10月取得済み
・VPCやLambdaの機能は机上で学習しているが、具体的な挙動をきちんと理解できていない


# 実施すること

やること自体は非常に簡単です。
ランタイムPython3.9で以下のようなLambda関数を作成します。
boto3というライブラリでEC2の情報を取得することができるみたいです。([こちらの記事](https://blog.serverworks.co.jp/tech/2019/08/21/post-73231/)を参考にしました)

```lambda_function.py
import json
import boto3

def lambda_handler(event, context):
    ec2 = boto3.client('ec2')
    response = ec2.describe_instances()
    return json.dumps(response, default=str)
```


あとは関数URLから関数の実行結果を確認するだけです。
たったこれだけなのですが、私はたいそう沼ったので
気を付けるべきポイントを記載していきます。

### 沼りポイントその①：関数URLの仕組みとreturnの型
私は最初return文がなく、print(response)としていました。
Lambdaの関数URLはLambda関数のレスポンスを解析して最終的なHTTPレスポンスを作成します。
Lambda 関数のレスポンスとは return で返される値です。
そのため、print 文で文字列を出力しても関数 URL では値を取得できません。
ここは単純にlambdaの仕組みを理解できていなかっただけなので
沼でもなんでも無いのですが、一応共有で、、、

### 沼りポイントその②：describe_instancesの返り値はdict型
当初responseをそのままreturnしていたのですが、エラーが返ってきてうまくいきませんでした。
boto3のドキュメントをきちんと確認したところ、dict型で返ってくるとのことでしたので
無理やりjsondumpsで出力して事なきを得ました。


### 沼りポイントその③：EC2の情報取得はEC2に直接取りに行くわけではない

ここに気付くのが一番時間がかかり、またネットにもクリティカルな記事がなかったので苦戦しました。
当初、EC2の情報が欲しいのだからlambdaを対象EC2があるVPCに紐づけて
そこからlambdaを実行すればええやろと思い、VPCに接続させていたのですが、
実際は下図のようにAWS管理のEC2 APIにアクセスして対象EC2の情報を取りに行くというものでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2920715/335c31b2-1494-ec25-c805-1e2716c419f2.png)

VPC Lambdaはネット環境へのアクセスができないので
vpcに紐づけるならエンドポイントを作成するかNAT Gatewayを作るかしないといけないのですが
そもそもVPCに紐づける必要がないので紐づけを解除してタイムアウト値を少し伸ばすことで
問題なくEC2の情報を取得することができました。

# 最後に

AWSのサービスの知識はある程度資格勉強でついたかなと思っていましたが、
実際に実装しようとしたときには細々とした不明点がいくつも出てきて、
それらが積み重なって沼になるという一連のシークエンスを体験できました。
(そもそも関数URLで実行結果を確認するのも今考えたら変ですね、、、)

今後も資格勉強を継続しつつ実装業務を経てこういった不明点を減らしながら
AWSエンジニアとしてレベルアップしていきたいと思います。
この1年で見てきたエンタープライズIoT事例

# 2022年のエンタープライズIoT事例
個人的に鋳造業など製造現場のIoTを多く見てきたので興味深いものをいくつか紹介します。データの作り方やデータ可視化が多いです。密かに2021年の事例も含んでいます。動画があるので色々説明するより見てもらった方が分かりやすいと思います。

# 鋳造IoTLT #3
2021/03/09(火)16:00〜18:00開催
https://iotlt.connpass.com/event/204515/

以下の皆さんが登壇しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178685/81d55e6e-f0f4-734c-0e15-bf9590827ef6.png)

その中から興味深いものをいくつか紹介します。

- 新東工業　佐藤さん：ばらつきデータの可視化

https://www.youtube.com/watch?v=BcGBAsgv_UU&t=3468s

- （株）キャスト　若林さん：電力ロガー２台買った

https://www.youtube.com/watch?v=BcGBAsgv_UU&t=883s

- 錦正工業　長島さん：データをつないで可視化

https://www.youtube.com/watch?v=BcGBAsgv_UU&t=1391s

# 鋳造IoTLT #4（初級・入門編）
2021/08/26(木)16:00〜18:00開催
https://iotlt.connpass.com/event/218747/

以下の皆さんが登壇しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178685/6e6efb3b-2bdb-0fb9-7130-6e35c337a4a4.png)

- 高和製作所　たかざわさん：データを収集して見やすく

https://www.youtube.com/watch?v=L14rLHpkJSE&t=1945s

- アサゴエ工業　おのさん：新入社員が液温可視化をつくった

https://www.youtube.com/watch?v=L14rLHpkJSE&t=4294s

- 栗田産業　もりしたさん：砂タンクの砂が切れるはなし

https://www.youtube.com/watch?v=L14rLHpkJSE&t=2834s

# 鋳造IoTLT #5
2022/03/08(火)16:00〜18:00開催
https://iotlt.connpass.com/event/238661/

以下の皆さんが登壇しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178685/7e2ca591-0006-8b3f-cad2-557f63cdc2db.png)

- 錦正工業　ながしまさん：木型にBLE温度計つけて現物管理

https://www.youtube.com/watch?v=1kmmNC2B5eU&t=460s

- 木村鋳造所　あおやまさん：電流センサーで可視化して気が付いた

https://www.youtube.com/watch?v=1kmmNC2B5eU&t=3377s

# 鋳造IoTLT #6
2022/08/26(金)16:00〜18:00開催
https://iotlt.connpass.com/event/252940/

以下の皆さんが登壇しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178685/2ef456cd-d701-26bc-5732-78cbd740b8af.png)

- 渡辺鉄工　まてぃーさん：社内デジタル人材教育

https://www.youtube.com/watch?v=jEKa-8DPHts&t=4077s

- 協和製作所　はらさん：分析データ活用

https://www.youtube.com/watch?v=jEKa-8DPHts&t=5128s


- 錦正工業　ながしまさん：Philips Hueを3色灯の代わりに使った話

https://www.youtube.com/watch?v=jEKa-8DPHts&t=5528s

# 鋳造IoTLT #6
2022/12/15(木)19:20 〜 21:30開催
https://iotlt.connpass.com/event/266436/

以下の皆さんが登壇しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178685/0a41b531-f32d-fca3-1c55-bfc8f7194d70.png)

全般的に面白かったのでフル尺で見てください！

https://youtu.be/eOYEZn5X5ns?t=843


# おまけ：クランプ１つで内訳を推測する
この前、展示会で面白いサービスを見つけたので紹介します。EnergyColoringと言うそうです。

https://www.energy-coloring.com/

デモ用のダッシュボードが分かりやすいかもです。これがクランプ1つで出来るらしいです。

https://circuit.energy-coloring.com/?k=baccd941-ff2f-422a-a7f1-992c69c20a90

FAQが豊富なのがいいですね！

https://tayori.com/faq/0c4f6d4417e8c6a77c1bf61351436d25a6ca1351

***
来年も「仕事現場で自分で作る」の事例を多く見て行こうと思います！
Spring BootでFontAwesomeを使う

## はじめに
Spring BootでFontAwesomeを適用させる方法です。
簡単な内容です。
### HTMLテンプレートのheadタグ内にリンクを記述
```
<head>
<link rel ="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">    
</head>
```

これだけでFontAwesomeが使えます。

## FontAwesomeのバージョンを指定
バージョンを正しく指定しないと画面にアイコンを表示できません。
先ほどのHTMLテンプレートのリンクタグで指定したバージョン6.2.1をFontAwesomeのページで指定します。
![スクリーンショット 2022-12-20 15.35.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/6f1a0ef3-d56c-ed28-0789-935416997860.png)


これで、アイコンを使うことができるようになりました。
COALESCE関数で、欠損値にデフォルト値を設定しておく。

# COALESCE関数とは
引数を順番に評価し、引数内でNULLと評価されない最初の式の現在の値を返す。


# 例
（例）
* ```select coalesce(null, '鈴木', null) ```
→鈴木

* `select coalesce(カラム名, '') from テーブル名`
→指定したカラムでnullのフィールドがあった場合、そこに空白を挿入したうえでデータを抽出する。

* `select case when coalesce(カラム名, '') <> '' then True else False end`
→まず、指定したカラムでnullのフィールドがあった場合、空白を挿入する。
そして、フィールドが空白ではない場合、「True」を格納し、空白の場合「False」を格納したうえでデータを抽出する。
（指定したカラムのフィールドがnullまたは空文字ではなかった場合「True」を格納し、
そうでなければ「False」にする。）

`user_id`がNULLであれば、`guest`。`user_id`が存在した場合は`membership`という値を格納するなどの活用方法がある。
Unity2021.3.1f1のc#でEnum型同士の比較で常にFalseを返すバグが。

例えばこんなコードが
~~~
        Debug.Log((Enum)AnimationCullingType.AlwaysAnimate == (Enum)AnimationCullingType.AlwaysAnimate);
~~~
~~~
False
~~~
と返してくれちゃいます。

いろいろ書き方を変えてみると
~~~
        var v0 = (Enum)AnimationCullingType.AlwaysAnimate;
        var v1 = (Enum)AnimationCullingType.AlwaysAnimate;
        var v2 = AnimationCullingType.AlwaysAnimate;
        var v3 = AnimationCullingType.AlwaysAnimate;
        Debug.Log(v0 == v1);
        Debug.Log(v2 == v3);
        Debug.Log(v0.Equals(v1));
        Debug.Log(v0.Equals(AnimationCullingType.AlwaysAnimate));
        Debug.Log(v0 == (Enum)AnimationCullingType.AlwaysAnimate);
        Debug.Log((int)(object)v0 == (int)AnimationCullingType.AlwaysAnimate);
~~~
~~~
False
True
True
True
False
True
~~~
こんな感じ。

Enum型にするとボックス化が発生するので通常は使わないのですが、
c#のジェネリックでの制限から使わざるを得ない状況がわりとあります。

そんな状況で比較をするとハマったと。。

Equalsで比較すると問題ないのでインタプリタの単純なバグだとは思うのですが、こういう挙動のバージョンがリリースされている以上常に対策を入れる必要がありそうです。

これがVisualStudioでデバッグしているとデバッガのインライン評価では正しく出るのにステップ実行をすると挙動が異なるという厄介な問題が出ます。

最適化をかけた結果とかなら理解できるけれどエディタ拡張を書いててこんな言語レベルの非互換性に遭遇するとは。。

気になって古いバージョンでも確認したら2018でも再現。。昔からこうだったんですね。
何か言語的な歴史でもあるのでしょうか。

## コメントをうけて確認したところ==とEqualsは別物である事が判明！
参照型に対して==もEqualsもデフォルトは参照比較になりますが、
オーバーライドはそれぞれ独立に行うことができ、
c#的には==は参照比較、Equalsが値の比較を期待するというもののようです。

私は==が内部的にEqualsを呼んでいると勘違いしていたのが間違いでした。

で、問題はUnityにVisualStudio2017のデバッガを接続してステップ実行したとき
デバッガ上で間違った結果を表示してくれる事こそがバグだったようです！！

まぁ仕様を正しく理解していなかった私もバグってたわけで。。

私は参照型でも値型に準じた扱いをしたい場合はEqualsと==を共にオーバーライドして
値の比較をするようにしたりしていましたが、人のコードにそれを期待するのは無理なので
安全に組むには==は使わないで明示的にEqualsとReferenceEqualsを使い分けるのがよさそうです。
参照比較を行いたいときは常にReferenceEqualsを使っていましたが足りてませんでしたね。

しかしEnumなんて参照型としての比較にはまったく意味がないんだし
値型としての扱いを期待するものなんだから==も値比較にしていてほしかったです。。
あと(int)へのキャストもね。。

Type型なんかはボックス化ではなく常に同じインスタンスを返してくれるので
参照型の==比較でも型の比較が行えて値型のように見える使い方ができますよね。

いっそ==を参照型に使ったら警告を出すオプションが欲しい。。

### 追記
よく考えたら==はstaticにしか宣言できなくってvirtualにできないわけで、
それのデフォルト実装がEqualsを呼んでくれていないとなると
継承関係によってさらに混乱が生じかねないんですね。。

### 追記２
デバッガでの不具合について、念のためもう少し調べてみたら
おかしいのはEnum型に対してのみでした。
普通のclassに対してはきちんと==が未定義の場合参照比較、
定義済みならその定義コードが正しくインプレース評価でも表示されました。
Enum型の時のみ何故か内包するenumの値による値比較になってるんですね。

問題を整理しておくと見た目の挙動では
・EnumはEquals(object)のみオーバーライドし==はデフォルトの参照比較のまま
・==のデフォルト実装は参照比較、Equalsと独立しているためEqualsのみを書き換えると挙動が食い違う事に。
・Unity経由でVisualStudio2019に接続した場合、Enumの==のデバッガ上での評価が値比較になるバグ？がある。(.Netコンソールだと大丈夫、unityでも普通のclassで間違えることはない)

==もEqualsもユーザーによるオーバライドが可能なので期待したものと必ずしも一致しないのは仕方ないのだけれど、
デフォルト実装がそれを助長する仕組みなのはある意味仕様バグともいえるような。
==のデフォルトでEqualsを呼んでくれてるのが一番素直だった気がします
今更かえられないけれど。

Enumは何故かEquals(object)しかオーバーライドしてないのも面倒・・
パフォーマンス的に読みやすさ的にもEquals(Enum)と==(Enum,Enum),==(Enum,int),(int)くらいは用意しておいてほしかったかも。

C#って楽でそこそこ便利なんだけれど変なところで罠があったりしますよね。
そんなときはデバッガ頼りなんだけれどデバッガの挙動まで期待と違ってしまうとほんとしんどい。
技術的負債への向き合い方(お気持ち編)

:::note info
この記事は『[LITALICO Advent Calendar 2022](https://qiita.com/advent-calendar/2022/litalico)』 19日目の記事です。
:::

はじめまして、LITALICOの@joy04dと申します。
寒さが苦手で布団に包まりながら仕事していたり、続編が絶望視されていたゲームの[新作](https://www.armoredcore.net/)が10年ぶりに発表されてテンションが上がったりして日々を過ごしています(=ω=)

我が家では親族交流の一環として、子供の写真や動画を親族各々の様々な環境から集め、また配信(オンラインからオフラインまで)するシステムを運用しているのですが、そろそろ年末だしこれも見直すか、と考えたところでふとその気持ちをまとめてみたくなったので、この記事を書いてみました。
(このシステムについても、そのうち機会あれば記事にしてみたいと思います)

前置き長くなりましたが、この記事ではシステム開発に携わるものなら誰にとっても身近であり、また切っても切れないテーマである技術的負債について少し語ってみたいと思います。

弊社[AdventCalendar](https://qiita.com/advent-calendar/2022/litalico)でも様々な記事が上がってますので、こちらも良ければ是非御覧くださいm(_ _)m
- [ビジネス変化に適用する為にリアーキテクティングを行うまでの話](https://zenn.dev/katzumi/articles/re-architecting-rezept)
- [レガシーシステムから新システムにデータ移行をした話](https://qiita.com/euonymus/items/8f14464decf5773c82cb)

## 技術的負債と何か
`技術的負債(Technical Debt)`とは、wikiの創案者・開発者であり、[アジャイルソフトウェア開発宣言](https://agilemanifesto.org/iso/ja/manifesto.html)の提唱者の1人でもある Ward Cunningham 氏によって生み出された概念です。

その概念の広さと腹落ち感から、様々な形で引用され、また理解されている言葉ですが、元々の捉え方としては、ドメイン知識とその複雑性への向き合い方であり、コードの保守性のようなテーマは薄かったと思われます。
- 理解が不完全な状態でも、まずはソフトウェアを世に出し、その中でドメイン知識を深めよう、得られた知識や理解を常にプログラムに反映し続ければ、構造はシンプルで実態を反映したものになり、開発はスムーズに。
- これを怠るのは借金を返済しないようなもので、プログラムから知識や理解はどんどん失われて実態と乖離し、利子のように複雑性が増して手がつけられなくなるぞ。

というような話と理解しています。ここから負債がもたらす結果として
- 5日で終わる開発が10日かかるようになった、
- 不具合の発生頻度が増えた
- 関わる人のモチベーションが下がった、採用が難しくなった
 
などの現象面と、 `負債`という言葉の印象から、コードの保守性やシステムの老朽化、さらにはスピード優先で品質を犠牲に(借金)すれば一気に前に進めるのでは、というような話まで概念が広がったのだと思われます。

このテーマの難しいところは、放置した時にもたらす結果はネガティブだという共通認識がありながら、それを定量的に表すことが困難で、またそれぞれの置かれている状況で因子も重さもバラバラだというところではないでしょうか。
諸々研究されている分野でもありますし、そのうちAIがベストプラクティスを教えてくれる時代が来るのではないかと思いますが、現時点では最後は関わる人の意思ひとつで立ち向かうしかない問題かと思います。

議論様々なテーマではありますが、そんな中で今回は自分の向き合い方を気持ちベースで書いてみたいと思います(=ω=)

## 技術的負債への向き合い方
### 1. 感謝と祈りを
まずは日々お世話になっているシステムに感謝の念を送ります🙏

手がかかり悩みのタネになることも多く、どうしてもネガティブな気持ちを持ってしまいますが、そんな中でも頑張ってくれているシステムです。
道の先もわからない中、100km走ってくれればそれで良いつもりで作られた車が、今1000kmも10000kmも走ってくれているようなものです。

今走ってくれているシステムにも、これまで関わってくれた人にも感謝を持って向き合いましょう。

### 2. 日々のお手入れ
次は日々のお手入れをできることからやっていきます。
車で言うならオイル交換や掃除ですね。

定期的に時間が取れると良いと思います。
形骸化してしまったエラー通知の整理や、依存するライブラリのアップデートなど、手を付けやすく影響が少ないところから少しずつ触っていきましょう。

### 3. 整理整頓
段々キレイになってきたら、次は整理整頓します。
今のシステムは、当初想定していた走行距離や積載量を超えた性能を発揮しており、そのために様々な形で改造されているかと思います。
その中で、今となっては既に意味を失ったパーツがあったり、同じ機能を持ったパーツがあったりもするはずです。

次を考える上で出来る限り軽量化し、コンパクトにしていきましょう。
APIからService、テーブルなどを整理していけると良いと思います。
(と簡単に書いてますが、ここが既存理解も含めて一番大変なところかと思います。出来る範囲で頑張りましょう(=ω=)

### 4. 次の目標
整理整頓が一段落ついたら、目指す目標を定めましょう。
これまで走ってきてくれたシステムのおかげで、今は道の状況もライバルの情報も、その中での自身の強みや求められている性能も、走り出す前に比べて段違いに理解が深まっているかと思います。
最高速度、燃費、積載量、悪路走破性など、次の目標に向かって重視する性能を決めてみましょう。

また置かれているシステムや組織の状況によっては、先にこちらをまとめて向き合う時間を確保する必要がある場合も多いかと思います。
その場合はこちらを2番に行っていきましょう。

### 5. 改造タイム
ワクワクの改造タイムです。
次世代の夢と希望を乗せて、システムをアップグレードしましょう。

走りながら大改造を行ったり、組織全体を巻き込んだ大規模PJになることも多いですが、ここは腕の見せどころ。
また、CTOやアーキテクトと呼ばれる方々は4や5の専門家であることも多いです、こちらも存分に巻き込んでいきましょう。

### 6. 1に戻る
ここまで進めたら、また最初に戻って繰り返しです。
変化と複雑性への向き合いは終わることがありません、楽しんで行きましょう(=ω=)

# 最後に
技術的負債について、想いベースで語らせていただきました。
ご笑覧いただければ幸いです。

これからの年末年始にかけて、是非日々向き合っているシステムに対しても、今年もありがとう・来年もよろしく、という想いを送ってみてください。
ここまでありがとうございましたm(_ _)m
【個人開発】GitHubリポジトリを簡単に見つけるサービス作った

## はじめに
サポーターズさん主催の技育CAMPハッカソンで、GitHubリポジトリを簡単に見つけるサービスを作ったので紹介したいと思います！

![スクリーンショット 2022-12-20 13.12.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1087368/ff6032f8-ddaa-31e4-ae05-0d708461c42e.png)

### アプリURL
https://getory.netlify.app/

### GitHubURL
https://github.com/sayyyyyy/Getory


## 開発のきっかけ
Vueを使ってみたいと思って、Vueで書かれているプロダクトを探したんですよ。ですが、なかなか見つからず…
そこで、指定した言語のリポジトリを簡単に発見できるサービスが欲しいと思ったわけです

ちなみに、Github公式にその機能があると知ったのは後の話()
ただ個人的にGitHub公式の検索機能が使いにくいと思ったのでそのまま作りました

## アプリ概要
指定した言語で書かれているプロダクトを見つけるサービスです

## 開発期間
1週間程度

## 使用技術
- Nuxt3
- TypeScript
- TailwindCSS
- vue-i18n
- Netlify
- Docker
- GithubAPI

期間短かったので今まで使ったことある技術をベースに、今回TailwindCSSを初めて使いました
ローカル環境汚したくないのでDockerは手放せません笑

## 主な機能
### 言語による検索
プログラミング言語のボタンを押すことで、その言語が含まれているリポジトリを検索できます
![画面収録-2022-12-20-13.24.15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1087368/9cd36494-1f5e-358d-f465-bcd0359b1a87.gif)


### ランダム検索
ランダム検索ボタンを押すことで、ランダムなリポジトリを検索できます
![ランダム検索.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1087368/f9a14525-bfa8-0d40-c3d9-ceea2a2f2947.gif)


### 最新リポジトリの表示
ホーム画面では常に最新のリポジトリが表示されます
![画面収録-2022-12-20-13.24.15_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1087368/520b20a5-868e-aa22-fc76-470fe12d10f1.gif)


### 多言語対応
日本語と英語を切り替えることができます
![言語切り替え.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1087368/b51a20bc-bef5-9315-865e-a68bcf7bb226.gif)


### ダークモードへの切り替え
ダークモードとライトモードを切り替えることができます
![ダークモード.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1087368/af01141a-d635-bc05-6689-2537e48b8781.gif)


## こだわり
- 簡単に検索できるように
- シンプルなレイアウトに

1人での開発、また開発期間的に簡単さやシンプルさを売りにするべきと判断

## 大変だったところ
- Nuxt3対応していないものが多い
検索の際にNuxt2の情報が出てきたり、そもそもNuxt3の情報が少ない
特にi18nで詰まりました….

- GitHub API v4の情報があまりない
GraphQLを初めて利用したかつ情報があまりなかったので辛かったです…
公式ドキュメント豊富で良かった

- Vercelでデプロイしようとしてましたが、何故かできずNetlifyですることに

## 今後

- リポジトリを取得するときに時間がかかってしまい、クリックしたかわからない状態になっている
    - ローディング画面を追加する
    - レスポンスが返ってくる前にDOMの操作をしておく
- 検索結果が現在新着順しかないので並び順を変更する
- 検索できる言語を増やす

## おわりに
1週間で満足いくところまで作り切ることができ、努力賞をいただけました！
プログラミング始めてもうすぐ2年ですが、ようやく始める時に憧れてた人に一歩近づけたのかなあ….と思います。
sshでログインしたら「（ドット絵風）アーニャでおはやいます！」してほしい！

こんにちは、あるいはこんばんは。

先ほど会社のブログに **[sshでログインした際にドット絵表示させる記事](https://tech-blog.rakus.co.jp/entry/20221213/ssh)** を投稿したのですが、どうしてもsshでログイン時にはアーニャちゃんに会いたい！

:::note warn
この記事はアーニャのドット絵表示に特化して記述しており、詳しいオプションの説明等は同じなので、記事の詳細は **[こちら](https://tech-blog.rakus.co.jp/entry/20221213/ssh)** を参照してください。
**背景色やサイズ、ドット絵への変換等も可能となっています**
:::

https://tech-blog.rakus.co.jp/entry/20221220/ssh


では早速アーニャちゃんに特化してやり方を以下に記載しよう！
会社ブログでは丁寧に記載したが、ここでは必要最低限のコマンドベースでメモしておきますね！


```zsh
# ImageMagickをインストールする
$ yum install -y ImageMagick

# 画像をいい感じにmotdに変換してくれるコマンドをダウンロードする
$ wget --no-check-certificate "https://raw.githubusercontent.com/taclose/mkmotd/main/mkmotd" -O mkmotd

# アーニャのドット絵をダウンロードする（私は https://togetter.com/li/1703931 さんのサイトからお借りしました）
$ wget --no-check-certificate "https://pbs.twimg.com/media/EzdyRmqVcAMwiqa.png:medium" -O anya.png

# アーニャちゃんをmotdに変換する
$ mkmotd.sh -p "anya.png"

# アーニャちゃんのmotdをサーバにアップロードする(※your-name, your-serverは各自のユーザ名やドメイン名にしてくださいね
$ scp tmp/dot_image your-name@your-server:/etc/motd
```

これでもう検証サーバと開発サーバを間違える心配はありません！！
確認してみましょう！

![ssh-success.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9872/2adf3bcd-55f1-3cd0-71ab-792227706593.gif)

**おめでとう！そしてこんにちはアーニャ！**
みなさんも好きなキャラクターを設定して色々試してみてくださいね！
参考文献に詳しい使い方のリンクを張っておきました。
**背景色やサイズ、ドット絵への変換等も可能となっています**

でわでわっ

# 参考文献

https://tech-blog.rakus.co.jp/entry/20221220/ssh

https://tech-blog.rakus.co.jp/entry/20221213/ssh

https://togetter.com/li/1703931
https://qiita.com/S_SenSq/items/2d005b700322e317cb9f
https://github.com/taclose/mkmotd
【復刻版】黒帯のためのLOOP(3) ～C言語やJavaScriptのfor文はどう書く?～

はじめに
========

この連載ではCommon LispのLOOPマクロをサンプルを使って紹介する。
LOOPマクロは (cl-loopを用いることで) Emacs Lispでも利用可能である。

【[Common Lisp: loopマクロ用法抄](http://smpl.seesaa.net/article/29800843.html)より引用】
> Grahamの _ANSI Common Lisp_ では嫌われていて碌に説明のないloopマクロ。一方、 _実践Common Lisp_ では対照的に好んで用いられていて、全編に渡って頻繁に使われている。しかしloopマクロは難しいという意識があるのかその説明は第22章とかなり後回しにされており、ちぐはぐな感を受ける。ここでは、 **黒帯のためのLOOP** という題のつけられたその章で解説されているloopマクロの用法を整理してみた。
> 
> _ANSI Common Lisp_ での黒魔術扱いに敬遠していたloopマクロだったが、こうして整理してみるとそれほど難しく考えずとも便利に使うことができそうだ。
> 
> [実践Common Lisp](http://www.amazon.co.jp/exec/obidos/ASIN/4274067211/)
> 作者: Peter Seibel,佐野匡俊,水丸淳,園城雅之,金子祐介
> 出版社/メーカー: オーム社
> 発売日: 2008/07/26
> メディア: 単行本（ソフトカバー）

LOOPのパーツ(**黒帯のためのLOOP**より)
============

LOOPの中では次のようなことができる。

* 数値的な変数や多様なデータ構造にわたる変数を更新していく
* ループしている間に見える値を収集(collect)、計数(count)、合計(sum)、最小化(minimize)、最大化(maximize)する
* 任意のLisp式を実行する
* いつループを終了するかを決定する
* それらを条件付きで実行する

上記に加えて、LOOPは以下のようなシンタックスを提供する。

* ループ内で使用するローカル変数の生成
* ループの前後に実行する任意のLisp式の指定

サンプル (GNU Emacs 28.2 で動作確認しています)
=======

また、@javacommons さんの以下の記事内の xpand-macro/xpand を用いてマクロ展開結果を取得しています。

https://qiita.com/javacommons/items/8fb62f9052df31582168


今回は…
========

今回は、「C言語やJavaScriptのfor文はどう書く?」という話題です。

## 教科書的には・・・

* `for ～ from ～ to ～ (by ～)` を用いるのが一般的だと思います。

```elisp
(cl-loop for i from 1 to 50 by 5 collect i)
    |
    |
    v
(let* ((i 1)
       (--cl-var-- nil))
  (while (<= i 50)
    (setq --cl-var-- (cons i --cl-var--))
    (setq i (+ i 5)))
  (nreverse --cl-var--))

(1 6 11 16 21 26 31 36 41 46)
```

## 私がおススメするのは・・・

* `for i = 初期値 then (+ i 増分) while (<= i 最終値) collect/do 本体` です。

```elisp
(cl-loop
 for i = 1 then (+ i 5)
 while (<= i 50)
 collect i)
    |
    |
    v
(let* ((i nil)
       (--cl-var--_1 nil)
       (--cl-var--_2 t))
  (while (progn
           (setq i (if --cl-var--_2 1 (+ i 5)))
           (<= i 50))
    (setq --cl-var--_1 (cons i --cl-var--_1))
    (setq --cl-var--_2 nil))
  (nreverse --cl-var--_1))

(1 6 11 16 21 26 31 36 41 46)
```

これなら i の増分を求める処理を複雑化したり、whileの終了条件を複雑にしたりできますね。
マクロ展開してみるとちょっと前者よりはわかりにくいですが、普通は展開なんてしませんからｗ

今回は、これだけ！
もっとよい書き方等ありましたらコメントで教えてください。
それでは！
Dataverse の選択肢列の情報 (テキスト) を Power Automate の通知で表示させる


# 何が問題か

例えば、Dataverse で以下のような選択肢列を作成していたとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/b10122be-e905-d1d4-6e97-ddceed0565be.png)

Power Automate で、以下のようなフローを作成し、データが登録されたら Teams のチャネルなどに通知させようとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/f67ab896-34ff-12aa-2650-23bc92775a38.png)

しかし、通知の内容を見ると、内部的な値が表示されてしまいます。
これでは、通知を見た人は何のことだか分かりませんよね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/17caecff-38a1-864b-c54c-03163241f0d1.png)

私自身も良く忘れるので、今回は、このようなケースにおける対処策を説明します。

# 対処策

まず、こちらのリンクの情報に助けられました。ありがとうございます。

https://softchief.com/2021/07/13/get-choice-field-text-in-power-automate-from-microsoft-dataverse-cds/

ちょっと面倒ですが、一旦、以下のようなフローを作成し、実行します。
取得するレコードは何でもいいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/f107e0e6-2338-846f-bb87-b2b85ef39493.png)

以下の箇所を控えておきます。

```
cr841_plan@OData.Community.Display.V1.FormattedValue
```

続いて以下のように、取得したい選択肢列を変数に入れて、[コードのプレビュー] を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/ec1b1428-d963-961a-9196-8a601b0f39d1.png)

以下の箇所を控えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8a537032-258b-4e25-0131-16fc6c6daf56.png)

```
"@{outputs('ID_で行を取得する')?['body/cr841_plan']}"
```

上記二つを以下のように結合します。

```
outputs('ID_で行を取得する')['body/cr841_plan@OData.Community.Display.V1.FormattedValue']
```

試してみます。
正しく動作したようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/1d831f9f-79eb-a0c9-9957-80b2cc8e730a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/51f6edf6-bf6b-e567-4ad3-d2652d02fc92.png)

元のフローも修正してみます。

※確認する限りでは、[行が追加、変更、または削除された場合] では、
　"cr841_plan@OData.Community.Display.V1.FormattedValue" が取得できなかったため、
　ID で行を取得するの処理を入れています

上手く行ったようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/78568a1b-c781-8fd7-2e18-fc50d6f0a712.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3074511/8af925e5-00c2-d570-76f9-f94624473277.png)
AndroidをJavaで実装するんですけど色々と分からなかったところまとめます

# Androidってなあに？

Androidは、スマートフォンなどの携帯情報端末のために、Google社が開発したOSです。
毎年バージョンアップした端末が発売されるのでそれに伴ってアプリもバージョンアップしなければいけません（汗）

この記事は**自分が詰まって学んだことをツラツラ書いていきます**
少しでも誰かの役に立ちますように・・・

# Androidに出てくるJavaの機能
**onCreateメソッド** : プログラムを起動したとき最初に呼び出される
onCreateメソッド内に
```
super.onCreate(savedInstanceState);
```
このコードが書かれています。
ここで書かれている**super**というのは、**スーパークラス**を意味します。スーパークラスは、継承する元になっているクラスのことです。

スーパークラスにあるonCreateメソッドを最初に呼び出して、スーパークラス側の処理を全部済ませてから、自分の処理を行うようにしています。このように、superは、スーパークラスを示すものとして、そのままメソッドやフィールド名を続けて書いて呼び出すことができます。
# ログの出力

[AndroidStudio](https://developer.android.com/studio?hl=ja&gclid=Cj0KCQiAtICdBhCLARIsALUBFcHshNfm05DsgR76r1DoQ4mrBz5NZLltV0LteRC3R2g1euuH_9c_SqIaArZdEALw_wcB&gclsrc=aw.ds)を使っている場合、ターミナルとは別で**Logcat**と言われるログを出力してくれるものがあります。
![スクリーンショット 2022-12-19 19.40.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545871/7a75f01e-4400-b194-d185-fe7dace476c3.png)


Log出力は、ログレベルに応じて、Logクラスで用意されている、次のログメソッドを利用します。

```
Log.v：VERVOSE（すべてのログ情報）
Log.d：DEBUG(デバッグ情報）
Log.i：INFO(情報）
Log.w：WARN(警告）
Log.e：ERROR（致命的な問題）
```

```例
Lod.d(tag, msg)
```

**tag**：キーを指定します。
キーには、〇〇.javaファイルのログを確認したい場合は、○○を指定する。

**msg**：ログ出力する際にわかりやすくするためのメッセージを指定

# adbコマンドでapkファイルをインストールする方法

①apkファイルをダウンロード（わかりやすいディレクトリに保存）
②使用したいエミュレータを起動
![スクリーンショット 2022-12-19 20.10.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545871/e9c27e17-1c94-635c-3e2b-b80984e438a6.png)

③指定したエミュレーターにapkファイルをダウンロード
**platform-tools**にapkファイルをダウンロードします！
```
cd /Users/USER_NAME/Library/Android/sdk/platform-tools
```
```
./adb install /Users/USER_NAME/自分が保存したapkのディレクトリ/〇〇.apk
```
## インストールするデバイスを指定する場合
```
./adb devices
```
このコマンドで現在接続・起動しているデバイス名を確認します！
ここで確認したデバイス名をダウンロードの際に指定します

# メディア権限について
 Android 13 以上をターゲットとし、他のアプリが作成したメディア ファイルにアクセスする必要がある場合は、**READ_EXTERNAL_STORAGE**権限ではなく、以下のような詳細なメディアの権限をリクエストする必要があります！
画像や写真：**READ_MEDIA_IMAGES**
動画：**READ_MEDIA_VIDEO**
音声ファイル：**READ_MEDIA_AUDIO**
![スクリーンショット 2022-12-20 12.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1545871/450ce3c4-e4bc-7789-a1a5-049b27aaf79c.png)
↑READ_MEDIA_AUDIO 権限をリクエストするとユーザーに表示されるシステム権限ダイアログ
初心者向けgitコマンドの使い方

gitのコマンドについて忘れることが多いのでメモとして投稿させて頂きます。

# リモートリポジトリへの登録の流れ
1.作業フォルダのファイルをステージングエリアに**add**する。
2.ローカルリポジトリに**コミット**する
3.ローカルリポジトリのコミットしたファイルをリモートリポジトリに**プッシュ**する

# gitコマンドの使い方
* git状況の確認
    * git status
* ステージングエリアに追加
    * git add -A or ファイル名
* ステージングエリアから削除
    * git rm 
* コミットファイルとステージングエリアのファイルとの差分
    * git diff --cached
* ローカルリポジトリにコミット
    * git commit -m "修正タイトル"
* 直前のコミットの取り消し(コミットの削除、ステージングエリアからも削除) 
    * git reset --soft HEAD^
* コミットIDの確認(コミット履歴の確認)
    * git log 
* 指定コミットの取り消し
    * git revert コミットID
* リモートリポジトリ(githubなど)の登録
    * git add remote  `リモートリポジトリ名`　リモートリポジトリURL
* リモートリポジトリへのプッシュ
    * git push `リモートリポジトリ名` ブランチ名
SQLでログデータから、アクションUUと利用率を算出する（WINDOW関数のCOUNTではDISTINCTを使えない）

下記のテーブルから、
`アクションUU(action_uu)`と`アクションUUの全体のUUに対しての利用率(usage_rate)`を算出したかった。

**action_logテーブル**
|session|action|date|
|:-:|:-:|:-:|
|001|view|2022-12-20|
|001|favorite|2022-12-20|
|002|view|2022-12-23|
|003|view|2022-12-25|
|003|add_cart|2022-12-25|

## 失敗例
最初に下記のクエリを書いてみたのだが、
ウィンドウ関数のCOUNTでは、DISTINCTを使用することができなかった。
```
with master as (
    select
        session
        , action
        , count(distinct session) over() as total_uu   -- 全体のUU
    from
        action_log
)
select
    action
    , count(distinct session) as action_uu             -- アクションuu
    , count(distinct session) / total_uu as usage_rate -- 利用率
from
    master
group by
    action
    , total_uu
;
```

## 成功例
下記のクエリで抽出したいデータを抽出できた。
※まず、WITH句で全体のUU数を取得しておき、
　最終的にcross joinをして、すべての行に対して全体のUU数の値を結合していくイメージ。
```
with master as (
    select
        count(distinct session) as total_uu
    from
        action_log
)
select
    l.action
    , count(distinct l.session) as action_uu -- アクションuu
    , count(l.session) as action_count -- アクションカウント
    , m.total_uu -- 総uu
    , count(distinct l.session) / m.total_uu * 100.0 as usage_rate -- 利用率
from
    action_log as l
    cross join master as m
group by
    l.action
    , m.
```
結果、下記のようにデータを抽出することができた。
|action|action_uu|action_count|total_uu|usage_rate|
|:-:|:-:|:-:|:-:|:-:|
|view|3|3|3|100.0|
|favorite|1|1|3|33.3|
|add_cart|1|1|3|33.3|
メモ：Yamaha RTX1200 静的DNSレコード 登録

メモメモ

社内DNS用にRTX1200に静的DNSレコードを登録しためも。

### 静的DNS登録（Aレコード）

```shell
ip host main.example.internal 172.16.1.10
```
- `ip host FQDN IPアドレス`
- ip host コマンドは、dns static コマンドで a と ptr を両方設定することを簡略化したもの。

### 静的DNS登録（CNAME）

```shell
dns static cname test.example.internal main.example.internal
```
- `dns static type FQDN`

### 静的レコードの確認

```shell
# show config | grep "ip host"
Searching ...
ip host main.example.internal 172.16.1.10

# show config | grep "dns static"
dns static cname test.example.internal main.example.internal
```
自分用　コマンド一覧

# 基本のコマンド
### 1.ファイルを作成する**touchコマンド**
```:例
touch test.txt
```
### 2.ファイルの中身を表示させる**catコマンド**
```:例
cat test.txt
```
>結果　
test.txtの内容が表示される
:::note info
少し打ってからTabキーを押すことで、補完機能が起動し、打ち間違いを防ぐ
:::

### 3.フォルダ(ディレクトリ)を作成する**mkdirコマンド**
```:例
mkdir html
```
>結果
htmlフォルダが作成される

| 重要オプション | 説明 |
|:-:|:-:|
|  -p | 階層ディレクトリを作成するときつける  |


### 4.ファイルを移動する**cdコマンド**
```:例
cd html
```
>結果　
今見いるフォルダからhtmlフォルダに移動する
:::note info
cdだけで実行するとホームディレクトリに移動する
(ホームディレクトリ…
　　　ユーザが起点にするディレクトリで「~」で表される)
:::

### 5.今見ているカレントディレクトリを表示させる**pwdコマンド**
```:例
pwd
```
>結果 
今のフォルダまで階層構造で見せる

### 6.ディレクトリの中身を表示させる**lsコマンド**
```:例
ls
```
### 7.ディレクトリを移動させる**mvコマンド**
```:例
mv test.txt html
```
>結果　
test.txtがhtmlフォルダに移動する
:::note info
mvコマンドは移動させるだけでなく、ファイルの名前の変更もできる!!
mv 現在のファイル名 　新しいファイル名
:::
### 8.ファイルやディレクトリのコピーができる**cpコマンド**
```:例
cp test.txt project.txt
```
>結果　
test.txtをコピーしたproject.txtができる
:::note warn
cpコマンドでは「-r」を付けることで、ファイルだけでなくディレクトリもコピーすることができます。
:::
### 9.ファイルやディレクトリの削除ができる**rmコマンド**
```:例
rm -r html
```
>結果　
htmlフォルダが削除される
:::note warn
rmコマンドでもディレクトリの編集には「-r」が必要
:::
交差(インターセクション)型と共用体型(ユニオン)型

# 交差(インターセクション)型
複数の型を`&`でまとめたもの。

例）
```typescript:typescript
type Type1 = {
    name: string
    age: number
}

type Type2 = {
    age: number
    hobby: string
}

type Type3 = Type1 & Type2 // `Type1`と`Type2`を `&` でまとめる。

const testObj:Type3 = {
    name: "test",
    age: 32,
    hobby: "basketball"
}
```
上記の例で、`Type1`では`name`と`age`のプロパティがあり、`Type2`では`age`と`hobby`のプロパティがある。
共通で持っているプロパティは`age`のみ。
この二つを'&'でまとめた`Type3`の型は以下の通りになる。
```typescript:typescript
type Type3 = {
    name: string
    age: number
    hobby: string
}
```

なお、共通のプロパティがあるが型が異なる場合はどうなるか。
```typescript:typescript
type Type1 = {
    name: string
    age: number
}

type Type2 = {
    name: string
    age: string
    hobby: string
}

type Type3 = Type1 & Type2

const testObj:Type3 = {
    name: "test",
    age: 32,  // 絶対あり得ない型になるため`naver`エラーになる。
    hobby: "basketball"
}
```
では、共通するプロパティの片方の型がユニオン型だとどうなるだろう。
正解は、共通する方のみが採用される。

```typescript:typescript
type Type1 = {
    name: string
    age: number
}

type Type2 = {
    name: string
    age: number | string
    hobby: string
}

type Type3 = Type1 & Type2

const testObj:Type3 = {
    name: "test",
    age: 32,
    hobby: "basketball"
}
```

上記の例だと、`Type3`の`age`の型は`number`のみに共有しているので、`number`のみになる。


# 共用体型(ユニオン)型
複数の型を`|`で区切って`or`を表現したもの。
```typescript:typescript
type Type1 = {
    name: string
    age: number
}

type Type2 = {
    age: number
    hobby: string
}

type Type3 = Type1 | Type2 // `|`で区切って`or`を表現

const testObj:Type3 = {
    age: 32,
    hobby: "basketball"
}
```
ここで`Type3`の型は、`Type1`もしくは`Type2`になる。
よって、`testObj`は`Type1`もしくは`Type2`の型に合致すれば、エラーは出ない。
逆に`Type1`にも`Type2`にも合致しなかった場合は、エラーになる。
例）
```typescript:typescript
type Type1 = {
    name: string
    age: number
}

type Type2 = {
    age: number
    hobby: string
}

type Type3 = Type1 | Type2

const testObj:Type3 = { // `Type1`と`Type2`２は`age`のプロパティがあるが、`testObj`にはないためエラーになる
    name: "test",
    hobby: "basketball"
}
```
【TypeScript】{} で初期化したいけど，後からプロパティに値が入る可能性があるとき

TypeScript で，{} で初期化したいけど後からプロパティに値が入る可能性がある場合，型アサーションを使って`{} as 型` のように書けばよいらしいです．とても基本的なことだと思うのですが，自分の勉強のためにまとめておきます．

以下コード例です．

```typescript
type Foo = {
    bar: string;
    hoge: string;
};

let foo = {} as Foo;
foo.bar = "Bar";
```
ちなみにこれは，以前私が書いた[【TypeScript】Unknown型を絞り込みたい！](https://qiita.com/mayukorin/items/530d68ba2636689a1273) で登場した Record でも書けることに気づきました．でも，わざわざこれで書きたいケースはほぼないと思います．
```typescript
type Foo = {
    bar: string;
    hoge: string;
};

let foo = {} as Record<keyof Foo, string>;
foo.bar = "Bar";
```
担当BtoBサービスで行った主だったテクニカルSEO施策

## はじめに
この記事は [エムスリーキャリア FY22 AdventCalendar](https://qiita.com/advent-calendar/2022/m3c) の21日目の記事です。

弊社では、事業場の従業員が50人以上になった企業に対して「産業医」を紹介するサービスを行なっています。
当サービスでは[企業集客のためのBtoBサイト](https://sangyoui.m3career.com/service/)（WordPressで構築）が存在し、そのサイト経由のお問い合わせ数を増やす目的で、外部のSEOコンサルタント会社様にご協力いただき、検索順位向上を目的とした施策を行なってきました。
その中の「テクニカルSEO※」に属する施策の中から、主だったものをご紹介したいと思います。

※SEO対策には「テクニカルSEO」と「コンテンツSEO」が存在し、前者がクローラー向けに内部構造を整える施策になり、後者がユーザー向けにコンテンツの質を高めるための施策になります。

## 大前提
### Googlebotはモバイルファーストインデックス
[モバイルファーストインデックス(MFI)とは | Google 検索セントラル  |  Google Developers](https://developers.google.com/search/mobile-sites/mobile-first-indexing?hl=ja)に
>2019年7月1日以降、すべての新規ウェブサイトでは、デフォルトでモバイル ファースト インデックス登録が有効化されます。

とあるように、新しく作成されたサイトに関しては、**Googlebotはモバイル版のサイトを見てページのクロールとインデックス登録を行なっている**ようです。
（2019年7月1日以前に作られたサイトでは、順次モバイル ファースト インデックス登録に切り替わり、切り替わった日付がSearch Consoleでサイト所有者に通知されるとのこと）

業種にもよるかと思いますが、BtoBサイトの場合、基本PCユーザーをメインターゲットにしてサイト運用を行なっている事が多いと思います。
弊社サービスの集客サイト（2019年7月1日以降に作成）でもSEO対策以外の集客施策はPCファーストで行なっていましたが、SEO対策に関しては、モバイル表示でどうなっているかを確認し、必要な施策を洗い出しました。

## 施策内容
### 内部リンクを増やす
トップページには**記事系ページ**（BtoBサイトの場合、「お役立ちコラム」や「導入事例」など）、
記事系ページには同じカテゴリの別の記事への導線を貼り、内部リンクを増やす施策を行いました。
**内部リンクを増やすとGooglebotがクロールしやすくなるためです。**
その際、特定の記事にリンクが偏るのではなく、**満遍なくリンクが供給される**のが望ましいようです。（記事詳細ページの場合、同じカテゴリ内の記事の中で、「そのページを起点にidが後ろのものを●件表示」など）
本施策を行うことでユーザー自体の回遊性も高まるので、SEO効果が出るまでの間にもページビュー数の向上が期待できると思います。

### ページネーションの最適化
`①前のページ` `②最初のページ` `③現在のページの前●件` `④後ろ●件` `⑤最後のページ` `⑥後のページ`へのリンクがあるページングが望ましいようです。
（③④は5P未満の場合はあるだけ表示）
これにより、後方のページにもリンクを供給できるため、Googlebotがクロールし易くなります。

▼PC表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70593/c3be9629-4aa7-a37b-47be-8fe5004f82cb.png)

元々弊社サイトでは一時期流行っていた（？）「次の●件を表示」ボタンで次のページのコンテンツを表示するUIを採用していましたが、この形式に変更しました。
ここで「どうしよう！」となったのがSP版の表示。PCでは現在のページの前後5ページのリンクを設置していたのですが、
SP版では1行の中に5ページ分もリンクを入れることができず、ページネーションが2行に渡るのもスマートではありません。
こういう場合は、前後のリンク数はPCより少なくして良いそうなので、1件（前述のようにGooglebotはSP表示でみているので、数はもっと多い方が望ましいと思います）表示にしました。また前と後ページへのリンクと一緒に入れていた「＜」「＞」のアイコンも、SPでは場所を取るので非表示にしました。

▼SP表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/70593/520fb9ad-1109-5576-1ee8-257464495204.png)

## E-A-Tを意識したページの作成
E-A-Tとは、Expertise（専門性）、Authoritativeness（権威性）、 Trustworthiness（信頼性）の頭文字を取ったもので、これらが高いサイトがSEO的にも高く評価されるとされています。
「専門性」の部分はコラムにて産業医に関する記事を多数掲載しているため、ある程度まかなえていますが、「権威性」と「信頼性」を担保できるページがなかったため、
親会社であるM3（全国の医師の約9割が登録している日本最大級の医療従事者専用サイトを運営）が提供しているサービスへのリンクを掲載したページを作成し、EATを高める施策を行いました。

## 施策を行うにあたり感じたこと
### SEO効果を狙ったものとUI改善を狙ったものは分けて考える
SEO対策をしているはずなのに、一緒にUI改善のための案も多数出てきて、思った以上に工数がかかり、施策の完了が想定より遅れるケースも出てくるかと思います。
どちらもゴールは「お問い合わせ数を増やすこと」なので一緒くたに考えがちですが、SEO対策は結果が出るまで時間がかかるため、先に行なった方が良いです。
「この施策はSEO対策とUI改善のどちらに当てはまるのか？」ということを整理し優先度をつけた上で、SEO施策が終わった後にUI改善案を行なっていくのが良いかと思います。

## 最後に宣伝
エムスリーキャリアでは、積極的にエンジニアを採用しています。
カジュアル面談も行っていますので、是非お気軽にお問い合わせください！

- toC,toBシステムを担当する、Webアプリケーションエンジニア、
- SFA&CRMの開発を手掛ける、社内システムエンジニア、
- QAエンジニア

[エンジニア｜中途採用｜エムスリーキャリア採用サイト](https://career.m3career.com/midcareer/engineer)
Databricks にて 値の前後に空白を含むすべてのカラムを trim する Python関数の作成方法

## 概要

Databricks にて 値の前後に空白を含むすべてのカラムを trim する Python関数を共有します。

```python
from pyspark.sql.functions import expr
 
 
def trim_space_values(
    tgt_df,
    trim_option='BOTH',
):
    cur_dtypes = tgt_df.dtypes
 
    # `string`のカラムのみを対象とする
    tgt_cols = []
    for tgt_dtyp in cur_dtypes:
        if tgt_dtyp[1].lower() == 'string':
            tgt_cols.append(tgt_dtyp[0])
    for tgt_col in tgt_cols:
        case_state = f"trim({trim_option} FROM {tgt_col})"
        tgt_df = tgt_df.withColumn(tgt_col, expr(case_state))
    return tgt_df

```

Spark 3.3 以降であれば、下記の関数を利用してください。

```python
from pyspark.sql.functions import expr


def trim_space_values(
    tgt_df,
    trim_option='BOTH',
):
    cur_dtypes = tgt_df.dtypes

    # `string`のカラムのみを対象とする
    tgt_cols = []
    for tgt_dtyp in cur_dtypes:
        if tgt_dtyp[1].lower() == 'string':
            tgt_cols.append(tgt_dtyp[0])
    with_conds = {}
    for tgt_col in tgt_cols:
        case_state = f"trim({trim_option} FROM {tgt_col})"
        with_conds[tgt_col] = expr(case_state)
    tgt_df = tgt_df.withColumns(with_conds)
    return tgt_df
```

`trim_option`にて、ドキュメントに記載のある`str`より前の箇所（例：`LEADING`）を指定できるようにしてあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/280371cc-103d-37b9-028e-7c4060df73ce.png)

引用元：[trim 関数 (Databricks SQL) - Azure Databricks - Databricks SQL | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/databricks/sql/language-manual/functions/trim)

`trim_option`にて`LEADING`を指定する方法を下記に示します。

```python
result_df = trim_space_values(df,'LEADING')
 
print(result_df.toPandas().to_dict())
result_df.display()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/685a97fb-d677-7d80-4961-b23fee840ff9.png)


## 動作確認
### 1. 関数を定義

```python
from pyspark.sql.functions import expr
 
 
def trim_space_values(
    tgt_df,
    trim_option='BOTH',
):
    cur_dtypes = tgt_df.dtypes
 
    # `string`のカラムのみを対象とする
    tgt_cols = []
    for tgt_dtyp in cur_dtypes:
        if tgt_dtyp[1].lower() == 'string':
            tgt_cols.append(tgt_dtyp[0])
    for tgt_col in tgt_cols:
        case_state = f"trim({trim_option} FROM {tgt_col})"
        tgt_df = tgt_df.withColumn(tgt_col, expr(case_state))
    return tgt_df
```

### 2. データフレームを作成

```python
data = [
    {
        "col_001": "a",
        "col_002": "a ",
        "col_003": " a",
        "col_004": " a ",
        "col_005": 1,
    }
]
 
df = spark.createDataFrame(data)
print(df.toPandas().to_dict())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/19fb4c61-f768-d6a4-a50b-fca21b1439d6.png)

### 3. 関数の利用

```python
result_df = trim_space_values(df)
 
print(result_df.toPandas().to_dict())
result_df.display()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/fb3a8d51-9151-f821-8d97-8ba83510240c.png)
Windows 11 Home から Pro へアップグレードして、余計な手間がかかった話

クライアントPC。 
Windows Pro で揃えたいけど、Windows Home がプレインストールされているものでないと入手できない場合。
色々解決策があるが、Windows Store から Pro にアップグレードする方法を試してみた。

# 環境 

- Windows 11 Home
- ローカルアカウントで設定

# 必要なもの

- Microsoft アカウント
- クレジットカード
- 費用 ￥13,824 (2022/12/20現在)

# 作業の流れ

Windows 11 Home の OS の初期設定が終わった状態

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/1a5e8125-09c6-1788-eebc-bdce34e8ebcf.png)

Microsoft Store を選び、「Windows」で検索すると Windows 10/11 Pro へのアップグレードの広告が出てくるので「さらに詳しく」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ca0fe604-24a0-6781-6ade-6f5e24ae9858.png)

「購入」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/32b60ec5-4f34-36fd-7add-e5d824fc4370.png)

Microsoft アカウントにサインインして、支払いをします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/398af362-7409-4618-f869-68e6be9f49f5.png)

クレジットカードで購入した後、「インストール」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/62c7dcdb-c3df-96e5-5c2d-f2407c962ba8.png)
進めましたが・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d8bc2dc9-1d55-ad49-7a7a-8cc0fd7c5683.png)
エラーが出てしまいました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f206f0f1-df20-32ab-0426-dd2960551147.png)

Windows Update が邪魔していたかな? とりあえず、再起動してみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/af47661d-c6a2-f33e-24ab-b8d3b45b5bed.png)

再起動後、Microsoft Store から再開。購買情報は引き継がれていたみたいで再度「インストール」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/cc71d290-088c-9562-e4b9-daf3557f37b6.png)

先程の作業があったからか、0% からすぐに 100% になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/0cf71de5-9b53-418d-29dd-2298d89e115a.png)

5分ほどで作業が終わり、再起動したところです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/64e7d037-af36-7f28-033f-f434b3af1bbc.png)

Windows11 Proになりました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/451a15c5-4861-213d-9941-b3cc17698fd7.png)

アップグレード自体は手間もなく終わりましたが・・・

# Microsoft アカウントの紐付けを解除する

Proライセンスを購入するときに Microsoft アカウントにサインインしました。これを解除します。
Microsoft Store から「サインアウト」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/abd2be09-dabc-7bd5-7abf-324dda4d6d1f.png)
Edge にも登録されてしまったので「サインアウト」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/2ee1391f-7d4b-3a11-de77-35ee2eab5653.png)
ケシカランことに OneDrive と、クレジットカード情報も登録されてしまってました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/c347e00f-ee20-1892-ddcb-78af3058fccf.png)
OneDrive の設定から、「この PC のリンク解除」を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/cdd12782-d532-61eb-cf85-8870e9635ebd.png)

まだ一部で過去のログイン履歴としてアカウントがあらわになってますが、実害に結びつく上記3点のみ解除しました。とりあえずはこんなものかな。
SourceTreeでpre-commit hookが失敗する時の対処法

## 先に結論だけ

macOSのSourceTreeでpre-commitに関する問題が発生したら、SourceTreeの設定を内蔵GitからSystem Gitへ切り替えてください。

## はじめに

この記事は、SourceTreeでのコミット時に、pre-commitフックが失敗する問題の記録、および対処方法を共有するためのものです。

### 対象とする環境

- macOS 12.6.1
- SourceTree v4.2.1 (248)
- git version 2.39.0

### 対象とする読者

- Gitを使っている
- SourceTreeを使っている

各ツールのインストールガイドなどは、それぞれの公式ドキュメントをご参照ください。

## 問題の詳細

Gitの[pre-commitフック](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF)を設定し、SourceTreeからコミットすると、pre-commitフック内のnode.jsに関連するコマンドが実行できずに失敗します。

```
.git/hooks/pre-commit: line 2: npx: command not found
```

pre-commitフックを手動で製作しても、自動生成するツールを使ってもSourceTreeからコミットする場合同じ問題が発生します。

https://github.com/typicode/husky

https://github.com/toplenboren/simple-git-hooks

ターミナルからコミットする場合はこの問題が発生しません。また、VSCodeやWebStormなどのアプリケーションからコミットしても問題は発生しません。SourceTreeからコミットする場合のみ、この問題が発生します。

## 対処法

この問題は、SourceTreeがGitを内蔵しているために発生します。内蔵Gitからは外部コマンドのパスが通っていないため、フックの実行に失敗します。

### Gitのインストール先を確認する

ターミナルを開き、以下のコマンドでインストール済みのgitのバージョンとインストール場所を確認します。

```bash
% git --version   
git version 2.39.0
% which git       
/usr/local/bin/git
```

### SourceTreeの内蔵Gitから、System Gitに切り替える

SourceTreeの環境設定を開きます。

![](https://www.evernote.com/l/AAk1W495TIxPPITle919m1CpOlYHAuTbgPkB/image.png)

「Git」設定タブを開き「Gitのバージョン」内の「システムのGitを使用する」ボタンを押します。

![](https://www.evernote.com/l/AAl_rDpkY59EPrGr7mLXhGURQviNNhWk9B4B/image.png)

`which git`コマンドで確認したパスの通りに、ファイル選択ダイアログでgitを選択します。

:::note warn
Gitのインストール先は環境によって異なります。

- macOS内蔵のGitを使っている
- homebrewでインストールしたGitを使っている
- M1 macでhomebrewを使いインストールしたGitを使っている

これらの場合でGitのインストール先が異なります。必ず`which git`コマンドでご自身が使用してるGitのインストール先を確認してください。
:::

以上、ありがとうございました。

## 参考記事

https://community.atlassian.com/t5/Bitbucket-questions/SourceTree-Hook-failing-because-paths-don-t-seem-to-be-set/qaq-p/274792#M88583

https://github.com/typicode/husky/issues/904#issuecomment-1231338418

https://qiita.com/SayCheeese/items/97149938e17930bd9ac1

https://qiita.com/hagmon/items/f7b8f36d15ff9d166b3a
GlobalProtect端末のWSL2からインターネットへ出る方法

GlobalProtect端末にインストールしたWSL2からインターネットに出ようとしても以下のようにアクセスできません。

```
$ curl https://www.google.com
curl: (6) Could not resolve host: www.google.com
```

PowerShellを管理者として実行し、以下コマンドを実行するとWSL2からインターネットに出られるかもしれません。

```
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "PANGP Virtual Ethernet Adapter"} | Set-NetIPInterface -InterfaceMetric 6000
```

ただ、上記コマンドを実行すると本来GlobalProtect経由でアクセスしたいページ（社内WEBサービス等）にWindowsからもアクセスできなくなります。そういったページにアクセスしたい時は上記コマンドのメトリクス値を「1」に変えて再実行するとアクセスできると思います。
JIRAでエピックとエピック下のタスクを別プロジェクトに移行する方法


# 本記事について
Jiraを使ってタスク管理をしている場合、別チーム（別プロジェクト）で起票したタスクをエピックごとごっそり別プロジェクトに移行したいことが年に２回ほどあるのですが、毎回細かな注意点を忘れるため、メモとして残しておきます。

:::note warn
移行元、先のプロジェクト間において、フィールド定義やワークフローが大幅に異なる場合、移行時に情報が欠落する場合があります。
なお、移行作業には課題の移動と一括変更の両権限が必要です。一括変更の機能にアクセスできない場合は、プロジェクト管理者に必要な権限を付与するようにご依頼ください。
:::


# 手順

- Jira画面右上の「課題の高度な検索」をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/f0d8334a-8bde-0845-6c5e-19109668f35b.png)

- 検索窓で、JQLにより検索を行います。`KGM-590` に該当する部分に、移動させたいエピックのキーを入力してください。`order by` はなくても構いません。また、"Epic Name"に移動させたいエピック自身を設定します。こちらの設定を漏らすと、エピックと子タスクの関係性が失われてしまいますので、ご注意ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/3a2f66ba-7429-ac5b-d343-1e018588e142.png)


（コピー用）
```
"Epic Link" = KGM-590  or "Epic Name" = [移動させたいエピックのタイトル] order by created ASC
```

- 画面右の上の・・・ボタンから「xx個の全課題を一括変更」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/bcbc22b4-2d98-6fe7-a6be-f1d108a63ea7.png)

- 移行したいチケットにチェックをつけます。一番上のチェックボックスで、全部のチケットにチェックがつきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/a6a6e289-69f1-9581-9f22-3ff057357fe4.png)

- 課題の移動を選択します。"Epic Name"に移動させたいエピック自身を設定していない場合、ここで警告が出てきますのでご注意ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/81248ee5-f2a3-56ec-8b9f-912cc0e398d2.png)


- 移行元、先のプロジェクト名と課題タイプをマッピングします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/bc24f074-e644-47af-67cf-20ec2d210a29.png)

- 「この更新をメールで通知」のチェックは空白のままにしておきましょう。大量にメール送信されてメンバーに迷惑をかけることになります（メールが飛んだとしても、五月蠅い以外の問題はありません）
- この画面はエピックの説明ですが、移動しようとしている課題タイプの種類分、同様の画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/9f0130ad-31e0-4530-3309-e8cfb5d9be38.png)

- 最後に確認画面が表示されますので、内容を確認の上、「確認」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/770eeced-b66f-caff-00e0-65979223f2af.png)

- 移行が開始されます。地味に時間がかかります。更新が完了すると、「更新」ボタンが「確認」に変わります。これで移行は完了です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439519/efb2656a-ee15-e6c8-9986-8d9271f63fa2.png)

- なお、移行前のURLでアクセスしても、Jiraがよしなに移行後のURLにリダイレクトしてくれるため、リンク切れは起こりません。便利ですね。

# 公式ドキュメント

https://ja.confluence.atlassian.com/jiracoreserver/editing-multiple-issues-at-the-same-time-939937916.html
[React]型 '○○'の引数を型 'SetStateAction<○○>'のパラメーターに割り当てることはできません。 の解決方法

# 概要
システム開発中にタイトルのようなエラーが発生した。

## やりたかったこと。
```react
const [value, setValue] = useState(itemType[0]);

// (略)

  onChange={(event: any, newValue: string | null) => {
    setValue(newValue);
  }}
```

## 発生したエラー

```terminal
型 'ItemType | null'の引数を型 'SetStateAction<ItemType>'のパラメーターに割り当てることはできません。
```

## やったこと

ItemTypeは今回使用した変数です。
中身はこう。
```react
type ItemType = { label: string };
```

コンソールログで `ItemType` の型を調べる。

```react
console.log(typeof(Itemtype)):
```

結果： `object` と出た。

次に、useStateを編集。

これを...
```react
const [value, setValue] = useState(itemType[0]);
```

こう...。
```react
const [value, setValue] = useState<object | null>(itemType[0]);
```


これでも、まだエラーは出る。


## 解決方法

こうではなく、
```react
const [value, setValue] = useState<object | null>(itemType[0]);
```

こうしてあげるのが正しい書き方だった。
```react
const [value, setValue] = useState<itemType | null>(itemType[0]);
```


## まとめ
いろんな方がこのエラーの解決方法は書いていたが、今回のように型をこっちで用意して当てはめているパターンを見かけなかったので少し時間がかかった。
reactではtypeを自分で作成することができるのでこのエラーは今後も現れそうなので自分用にも( ..)φメモメモ。
Ubuntu22.04 wpa_supplicantで認証できない(解決)

# はじめに
こんにちは。私はとある高専で情報工学を学んでいる学生です。最近，研究室内の有線LANでも802.1x認証が導入されたためUbuntu Server 22.04のネットワーク設定の対応をしていました。
そのとき3日間くらい詰まったのでQiitaで共有させていただきます。

~~(卒業研究の忙しい時期になてことをしてくれたんだ)~~
# 発生した問題
```
$ sudo wpa_supplicant -c /etc/wpa_supplicant/hoge.conf -D wired -i enp3s0
...
SSL: SSL3 alert: write (local SSL3 detected an error):fatal:internal error
...
```
まぁ、シンプルに802.1x認証を実行しようとしたわけですがSSL3がうんたらかんたららしいです。そういうことなんで，
/etc/ssl/openssl.cnfを編集したら直るみたいなことが海外フォーラムで触れらてたので試してみました。
``` /etc/ssl/openssl.cnf
...(最後の5行くらい)
[system_default_sect]
MinProtocol = SSLv3
CipherString = DEFAULT@SECLEVEL=0
```
結果これでもだめでした。
# 解決
[wpa can't connect to servers using TLS 1.1 or older](https://bugs.launchpad.net/ubuntu/+source/wpa/+bug/1958267/comments/51)
上記のページのリプライを参考にしました。
内容はwpa_supplicantのバージョン 2.10にバグがあるっぽいので2.9に落とせば”とりあえず”解決はできる内容でした。

ではまず Ubuntu 22.04の場合
```
$ sudo vim /etc/apt/sources.list.d/impish.list
deb http://old-releases.ubuntu.com/ubuntu impish main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu impish-updates main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu impish-security main restricted universe multiverse
```
Ubuntu 21.04の場合はこちら
```
$ sudo vim /etc/apt/sources.list.d/impish.list
deb http://archive.ubuntu.com/ubuntu/ impish main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ impish-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ impish-security main restricted universe multiverse
```

以下は共通
``` bash
$ sudo apt update
$ sudo apt -y --allow-downgrades install wpasupplicant=2:2.9.0-21build1
$ sudo apt-mark hold wpasupplicant
```

これで恐らく解決するでしょう。

``` bash
$ ping google.com
64 bytes from hoge.net (xxx.xxx.xx.xxx): icmp_seq=1 ttl=118 time=29.7ms
```

# さいごに
https://hgot07.hatenablog.com/entry/2020/07/16/190315

hgot07 Hotspot Blogさんのおっしゃる通り，本当ならRADIUSサーバの管理者に連絡し，TLSv1.1以上にアップデートしてたら私がここまで詰まることなかったと思います。
今回紹介した解決法も一時的なものでずっとこのままではいけない気がするので、まぁって感じでした。