OmniAICreator/Qiita-1.07M huggingface dataset:
グローバルIPアドレスとプライベートIPアドレスの違い

# グローバルIPアドレスとプライベートIPアドレスの違い
今回はIPアドレスについての記事です。
## IPアドレスとは？
IPアドレスの正式名所は「Internet Protocol Adress」の略で、ネットワーク機器一つずつ割り当てられる番号のことです。わかりやすく言うと、ネットワーク上のデバイスの住所のようなものです。
IPアドレスには複数のプロトコルや種類があります。それらを紹介していきます。
## IPアドレスの種類
- IPv4
- IPv6
- グローバルIPアドレス
- プライベートIPアドレス
### IPv4について
IPv4の正式名所は「Internet Protocol version 4」です。IPv4は一番普及しているIPアドレスの数字の羅列です。結構昔からあります。IPv4アドレスは32ビットで表します。また、「IPv4」はインターネットプロトコルの４番目のバージョンの意味です。43億ほどのアドレスを作れます。枯渇しています。
### IPv6について
IPv6に正式名所は「Internet Protocol Version 6」です。IPv6は最近、、、結構前に開発されていましたが、最近普及しはじめました。IPv6は通常、IPv4より通信速度が速い特徴があります。実はIPv6アドレスはIPv4アドレスが枯渇しているのを補うために作られたインターネットプロトコルなのです。IPv6アドレスは128ビットで表現されます。
ほぼ無限のアドレスが作れます。
### グローバルIPアドレスについて
グローバルIPアドレスは全世界で一つしかないIPアドレスです。ネット閲覧、メールのほかにも様々なサービスを使用することができます。一つの家に入っている回線に一つのみ割り当てられています。また、固定と動的というものがあります。これは、ルーターやHGW、モデムが再起動されたときにIPが変化するかどうかで変わります。変わったら動的、固まっていたら半固定や固定状態です。これは回線事業者によって変わります。

グローバルIPが使用可能なIPのレンジ
| クラス | アドレスの範囲 |
|:-----------|------------:|
| クラスA       | 1.0.0.0～9.255.255.255、11.0.0.0～126.255.255.255        | 
| クラスC     | 192.0.0.0～223.255.255.255      | 
| クラスD       | 224.0.0.0～239.255.255.255        | 
| クラスE         | 240.0.0.0～255.255.255.255          | 
### プライベートIPアドレスについて
LAN内のネットワークに存在するデバイスが自由に使用できるIPアドレスのことです。これはSwitchやパソコン、スマホ、ネットワークが使用可能なデバイスすべてに割り当てられています。自分のネットワーク内でのみ一意なので、別のネットワークでは同じIPアドレスが使用されることもあります。（ほぼそう）

プライベートIPが使用可能なIPのレンジ
| \ | アドレスの範囲 |
|:-----------|------------:|
| 1       | 10.0.0.0～10.255.255.255        | 
| 2     | 172.16.0.0～172.31.255.255      | 
| 3       | 192.168.0.0～192.168.255.255        |
重力空間における放物線の焦点とボールの軌跡

# はじめに
放物線状のアンテナに光線（電磁波）を入射させるとその反射波は必ず放物線の焦点を通る。つまり、その点に電磁波のエネルギーや信号が集中する。このようなモデルは、地面に置いてある凸状の放物面に対して上から球体を落とすことである程度再現することができる。そこで、今回はそのような力学モデルを弾性によるエネルギーロスがない理想的な空間で再現する。具体的には、Pythonを用いて質点の運動方程式と反発係数の式を立てることで、以下のようなシミュレーション動画を作成することを目的とする。

今回は以下のような動画を作成することを目的とする。

![放物線の焦点.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/acc58954-5459-c0a7-a69a-2176005f7811.gif)

フルバージョンは以下のgithubのリンクよりみることができる。

https://github.com/irucairuca/parbola/blob/main/%E6%94%BE%E7%89%A9%E7%B7%9A%E3%81%AE%E7%84%A6%E7%82%B9.gif

# 条件設定とアルゴリズム
今回の条件として、$y=x^2$の放物面に対して、$y>x^2$の範囲からボールを放物面に向かって初速度0で投げ下ろすものとする。

まず、ボールは放物面に衝突するまでは重力加速度$g$の等加速直線運動を行う。衝突後は、放物面の接線を基準として入射角と反射角が等しくなるような速度を維持しつつ放物面内側方向($|x|$が小さくなる方向)へ反射する。

このような衝突は、エネルギー保存上では永遠に行うことができる訳だが、シミュレーションなので有限の時間を設定してあげる必要性がある。そこで、ボールの初期座標を$(2,5)$とし、$0\le t\le 10$の範囲でシミュレーションを行うものとする。

# プログラム

```python parabola_ball.py
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import japanize_matplotlib

# アニメを作る初期設定
fig = plt.figure()
ims = []
#重力加速度
g=9.8
#放物線面の広さ
x_0=np.linspace(-3,3,100)

#ボールを落とす座標
x_1=2
y_1=5
#初速度
v_x=0
v_y=0
#加速度
a_x=0
a_y=-g

#時間
t=0
#時間の刻み幅
delta_t=0.01
while(t<10):
  im=[]
  #ボールが放物面に衝突したら反射する。決して放物面の下に行ってはならない。
  if (x_1)**2>y_1:
    #放物線の接線ベクトル(1+2j*x_1)を基準平面として反射する。（完全弾性衝突とは、入射角と反射角が等しい反射と同じ現象である）
    theta=np.angle((v_x+1j*v_y)/(1+2j*x_1))
    v=(((-1-2j*x_1)/abs(-1-2j*x_1))/(np.cos(theta)+1j*np.sin(theta)))*(v_x+1j*v_y)
    #反射する方向は、必ずy軸側に向かうようにする。つまり放物線の内部でのみ反射を繰り返すものとする。
    if x_1>0:
      v_x=-v.real
      v_y=v.imag
    else:
      v_x=v.real
      v_y=v.imag
  #ボールの速度と位置の更新
  v_x=v_x+a_x*delta_t
  v_y=v_y+a_y*delta_t
  x_1=x_1+v_x*delta_t
  y_1=y_1+v_y*delta_t
  #放物面の描写
  im1=plt.plot(x_0,x_0**2)
  #ボールの描写
  im2=plt.plot(x_1,y_1,"o",color="red")
  ims.append(im1+im2)
  #時間の更新
  t=t+delta_t

# 複数枚のプロットを 20ms ごとに表示
ani = animation.ArtistAnimation(fig, ims, interval=20)
#保存
ani.save("放物線の焦点.gif", writer="pillow")
```

これを実行すると以下のようなgifファイルが出力される。


![放物線の焦点.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1686019/acc58954-5459-c0a7-a69a-2176005f7811.gif)

https://github.com/irucairuca/parbola/blob/main/%E6%94%BE%E7%89%A9%E7%B7%9A%E3%81%AE%E7%84%A6%E7%82%B9.gif

たしかに、ボールの軌跡は放物面の焦点付近を何度も反射により通っていることがわかる。ただし、焦点付近とぼかしたのは、質点であるボールは重力の影響があり、光線のような完全な直進性を持ち得ていないからである。以下は、放物面の焦点に関する分かりやすい記事である。

https://manabitimes.jp/math/1000

# まとめ
今回は、Pythonを用いて放物面の上空から質点を落下させた場合に、それが描く軌道を描写するプログラムを書いた。具体的には、運動方程式と完全弾性衝突の速度式を用いてアルゴリズムを作成した。その結果、質点の軌跡は確かに焦点付近を通過するということが分かった。このように、Pythonは時間を変数にした力学的シミュレーションもアニメーションとして出力することができるため得意であると考えられる。
【JavaScript】 Clickしただけ 要素が回転して欲しい

# やりたい事

Clickしただけ 特定の要素が回転して欲しい
└transform: rotate(Xdeg);で、XがClickされただけ「-90」が追加されていく

![screen.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2727869/b91ce281-69c6-2c2f-cb83-dc510a8363df.gif)



# 書いたJavaScript

```JavaScript:JavaScript
upBtn.addEventListener('click', function(){       
      // 回転を適用
      document.querySelector("#circle").style.transform = "rotate(" + -90 + "deg)";
  }, false);
```

:::note warn
# つまずきポイント
* Clickしたら「-90度」が付与されるが、1回きりでそれ以降は-90度回転しない
:::


ここまで動いただけで感動したが、ここからどうやったら連続して回転してくれるかに頭を悩ました。

色々調べたが、なかなか解決しなかったのでGPT先生にご質問。


# GPT先生が書いたJavaScript

```JavaScript:JavaScript
  // イベントハンドラ
  let rotationAngle = 0;  // 初期角度を 0 に設定

  upBtn.addEventListener('click', function(){
      console.log('clicked');
  
      // 現在の角度から -90 度ずつ減らす
      rotationAngle -= 90;
  
      // 回転を適用
      document.querySelector("#circle").style.transform = "rotate(" + rotationAngle + "deg)";
  }, false);
```

一発。
そうか、rotationAngleという変数を使って、Clickされる度に値が追加さしていけば良いのか！！

自分にはなかった発想。

```JavaScript:JavaScript
 rotationAngle -= 90;
 ```
 この書き方、先日Udemyで習って記事書いたぞ！！w

 今日も学び。
3Dスキャンは人体に影響がありますか？

3Dスキャン技術の普及に伴い、人体をスキャンする際に健康に影響があるかどうか心配する人が増えています。医療、ファッションデザイン、芸術分野などで、3Dスキャナーは人体のモデリングに広く利用されています。そのため、3Dスキャナーが人体に与える影響について考えることは非常に重要です。

1. 3Dスキャナーの仕組み
3Dスキャンが人体に影響を与えるかどうかを理解するには、まず3Dスキャナーの動作方法を理解する必要があります。現在の多くの3Dスキャナーは、構造光やレーザー技術を使用して物体や人体表面をスキャンします。これらのスキャナーは特定の周波数の光を照射し、物体の表面から反射された光を記録して点群データを生成し、3Dモデルを再構築します。X線などの画像技術とは異なり、3Dスキャナーは電離放射線を使用せず、低エネルギーの光源を使用します。
![fcc7f05fce8406c8b0914248e69ca3d0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/7a9f6a47-5b90-e5fc-d42f-a8f22fb297cc.png)

2. 構造光やレーザーは危険ですか？
構造光3Dスキャナーは可視光または近赤外光を使用しており、通常は通常の光源と同等です。可視光は人体に既知の健康リスクがなく、近赤外光も安全と見なされています。これらの光は皮膚や組織を透過しないため、人体や顔のモデリングなどの表面スキャンには全く安全です。

レーザー3Dスキャナーはレーザーを使用していますが、通常は低出力で非電離性のレーザー光源を使用しています。工業用および民生用のレーザースキャナーは、IEC 60825-1などの国際安全基準に準拠しており、その出力は人体の目や皮膚に害を与えるほど強くありません。ただし、レーザースキャンを行う際には、レーザー光源を長時間直視しないようにすることが推奨されています。

3.3Dスキャンの安全性に関する研究
3Dスキャナーが人体に与える影響に関する研究によると、現在のところ、3Dスキャナーが健康に悪影響を与えるという証拠はありません。他の画像技術と比較して、3Dスキャンのリスクは非常に低いとされています。たとえば、医療分野では、3Dスキャンは正確な手術計画モデルを構築するために使用されています。医師は患者の全身または部分的なスキャンを行い、高精度の3Dモデルを生成し、外科手術や義肢設計に利用しています。

![4e6b8c96d66857374f06e93d3ecdaf38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3824290/8fe19035-830f-3f5d-57e2-3588d46b77f5.png)

https://www.revopoint3d.jp/products/standalone-3d-scanner-miraco
さらに、ファッションデザインやフィットネスの分野でも3Dスキャン技術の応用が進んでおり、体のサイズを測定してカスタム衣類を作成したり、体形の変化を追跡したりしています。これらの応用は、3Dスキャンの安全性と実用性を裏付けています。

4.注意事項と特別な場合
通常、3Dスキャンは安全ですが、特定の状況では注意が必要です。たとえば、赤ちゃんや子供にスキャンを行う場合、光自体は安全ですが、スキャン中の快適性を確保し、目に長時間直接照射しないようにすることが重要です。また、3Dスキャン装置を長時間使用するスタッフの場合、定期的なメンテナンスと操作環境の安全性を確認することも必要です。

5.まとめ
全体として、3Dスキャナーは人体に顕著な影響を与えません。構造光やレーザースキャンのどちらも安全と見なされ、その使用する光の種類は人体に有害なレベルをはるかに下回っています。ほとんどの使用場面では、3Dスキャンが健康に悪影響を与える心配はありません。医療、ファッション、工業の分野における3Dスキャン技術の広範な利用は、その安全性と有効性をさらに証明しています。日常の使用では、基本的な安全操作規程を守ることで、リスクのない3Dスキャン体験が可能です。
Adobe Illustrator スクリプト：選択したオブジェクトのサイズを中央に表示し、グループ化する

## 概要

このスクリプトは、Adobe Illustrator で選択したオブジェクトの幅と高さをミリメートル単位で計算し、そのサイズをオブジェクトの中央にテキストとして挿入します。さらに、挿入したテキストと選択したオブジェクトを同じグループにまとめます。

## スクリプト

```jsx
#target illustrator

// アクティブなドキュメントと選択されているアイテムを取得
var doc = app.activeDocument;
var selection = doc.selection;

// 選択されているオブジェクトがない場合、警告を表示
if (selection.length == 0) {
    alert("オブジェクトを選択してください。");
} else {
    // 選択されているオブジェクトに対して処理を行うループ
    for (var i = 0; i < selection.length; i++) {
        var item = selection[i];

        // オブジェクトの幅と高さを取得し、ポイントからミリメートルに変換（小数点1位まで表示）
        var width = (item.width * 0.352777778).toFixed(1); // pt to mm (1 pt = 0.352777778 mm)
        var height = (item.height * 0.352777778).toFixed(1); // pt to mm

        // テキストの内容を「幅 x 高さ mm」形式にする
        var textContent = width + "mm x " + height + "mm";

        // オブジェクトの中央の座標を計算
        var centerX = item.position[0] + (item.width / 2); // オブジェクトのX座標の中央
        var centerY = item.position[1] - (item.height / 2); // オブジェクトのY座標の中央

        // テキストオブジェクトを作成し、テキスト内容を設定
        var text = doc.textFrames.add();
        text.contents = textContent;

        // フォントサイズを12ポイントに設定
        text.textRange.characterAttributes.size = 12;

        // 作成したテキストをオブジェクトの中央に配置
        text.position = [centerX - (text.width / 2), centerY + (text.height / 2)];

        // グループを作成し、選択したオブジェクトとテキストを同一グループにする
        var groupItems = doc.groupItems.add(); // 新しいグループを作成
        item.moveToBeginning(groupItems);      // 選択されたオブジェクトをグループに追加
        text.moveToBeginning(groupItems);      // 作成したテキストをグループに追加
    }
}
```

## 説明

1. **選択されたオブジェクトの幅と高さを計算**:
    - 幅と高さは、Illustrator のデフォルトのポイント単位をミリメートルに変換しています（1 pt = 0.352777778 mm）。
    - 小数点以下1桁に丸めています。

2. **中央にテキストを配置**:
    - オブジェクトの中心座標を計算し、その位置にサイズ情報をテキストとして挿入します。

3. **グループ化**:
    - テキストとオブジェクトを新しいグループにまとめます。これにより、サイズのテキストとオブジェクトが一体となって移動や編集ができるようになります。

## まとめ

このスクリプトは、Illustrator でオブジェクトのサイズを簡単に可視化し、それをオブジェクトの中央に表示する方法です。グループ化をし、サイズ表示が邪魔にならないように一緒に管理できるようにしています。
【Three.js】Textureが反転してしまうのを直した

## 問題点
Three.jsではなぜかテクスチャを作成するとデフォルトで垂直軸に沿って反転される仕様になっています。どうして....

https://threejs.org/docs/#api/en/textures/Texture.flipY

```text:日本語訳
true に設定すると、テクスチャはGPUにアップロードされるときに垂直軸に沿って反転されます。
デフォルトは true です。
```

## 解決策

`flipY`を`false`に設定してあげると元に戻ります。

```javascript
const texture = new THREE.TextureLoader().load('なんか画像とか');
texture.flipY = false;
```

おしまい。
Go言語でsyslogを受信する方法

# はじめに

Go言語でsyslogを受信するためのパッケージgo-syslog

https://github.com/mcuadros/go-syslog

の使い方を説明します。

# syslogを受信するプログラムの作り方

## インストール

```terminal
$go get gopkg.in/mcuadros/go-syslog.v2
```



## 受信プログラム

```go

package main

import (
	"fmt"
	"log"

	"gopkg.in/mcuadros/go-syslog.v2"
)

func main() {
	channel := make(syslog.LogPartsChannel)
	handler := syslog.NewChannelHandler(channel)

	server := syslog.NewServer()
	server.SetFormat(syslog.Automatic)
	server.SetHandler(handler)
	err := server.ListenUDP("0.0.0.0:514")
	if err != nil {
		log.Fatalln(err)
	}
	err = server.Boot()
	if err != nil {
		log.Fatalln(err)
	}
	go func(channel syslog.LogPartsChannel) {
		for logParts := range channel {
			fmt.Println(logParts)
		}
	}(channel)

	server.Wait()
}

```

このプログラムのポイントは

### チャネルの作成とハンドラー登録

```go
channel := make(syslog.LogPartsChannel)
handler := syslog.NewChannelHandler(channel)
```

受信したsyslogを受け取るチャネルを作成してハンドラーに登録します。

### syslogの形式を自動判別

```go
server.SetFormat(syslog.Automatic)
```
です、フォーマットが決まっている場合は、

```go

RFC3164   = &format.RFC3164{}   // RFC3164: http://www.ietf.org/rfc/rfc3164.txt
RFC5424   = &format.RFC5424{}   // RFC5424: http://www.ietf.org/rfc/rfc5424.txt
RFC6587   = &format.RFC6587{}   // RFC6587: http://www.ietf.org/rfc/rfc6587.txt - octet counting variant
Automatic = &format.Automatic{} // Automatically identify the format

```

の指定ができます。

TCPで受信する場合は、

```diff_go
-	err := server.ListenUDP("0.0.0.0:8514")
+	err := server.ListenTCP("0.0.0.0:8514")
	if err != nil {
		log.Fatalln(err)
	}

```

のようにすればよいです。両方受信もできます。


# 実行結果

```terminal
$go run main.go
map[client:192.168.1.13:37943 content:/dev/root         30450024 8009816 21151964   28% / facility:1 hostname:raspberrypi priority:13 severity:5 tag:diskmon timestamp:2024-09-26 17:13:01 +0000 UTC tls_peer:]
map[client:192.168.1.13:37943 content:Mem:        3878088      114700     3137720      197104      625668     3436204 facility:1 hostname:raspberrypi priority:13 severity:5 tag:memmon timestamp:2024-09-26 17:13:01 +0000 UTC tls_peer:]
```

# 余談

このパッケージは、TWSNMP FC/FKの中で使っています。

https://note.com/twsnmp/n/na5c62f59833d

１日数GB受信するようなヘビーな環境でも問題なく使えています。
某セキュリティソフトによるWindowsブルスク問題の原因から学ぶカーネル

## 事象と原因について
2024年7月19日にWindowsPCがブルスクになるという報告があり、原因は米サイバーセキュリティ企業CrowdStrikeの製品が原因だった。
問題報告したユーザのスクリーンには、同社製品のドライバである「csagent.sys」が原因と記載。
法人向け製品の提供の為、今回の事象は同社製品を導入している企業PCで発症したと想定される。

https://www.itmedia.co.jp/news/articles/2407/19/news154.html

要約すると、米サイバーセキュリティ企業提供のCrowdStrike製品では、カーネルレベルで動作していたことが今回の事象原因と発表。
米Microsoftがカーネル外で動作するようにWindowsに変更を加える計画を2024年9月12日に発表。
https://www.itmedia.co.jp/news/articles/2409/13/news102.html

## ソフトウェアについて
カーネルを理解する為に、ソフトウェアから簡単に整理します。
ソフトウェアは大きく分けると「応用ソフトウェア」と「システムソフトウェア」の2つに分かれ、各ソフトウェアは以下のように分類できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3804239/0e0b5e9c-5731-b835-ca7e-50386f771033.png)

今回の要因として挙げられたカーネルというのはOSの中核であり、表で言うとシステムソフトウェア内の基本ソフトウェアの部分に該当します。
基本ソフトウェアは制御プログラム・言語プロセッサ・サービスプログラムの3つに細かく分類され、制御プログラムが所謂カーネルになります。
つまり、OSを広い意味で解釈すると「OS＝基本ソフトウェア」ですが、狭い意味に限定すると「制御プログラム」となります。

**＜制御プログラム＞**
ハードウェアを管理して、応用ソフトウェアやミドルウェアから、コンピュータが効率的に利用できるように制御されるソフトウェアです。
一般的に制御プログラムのことをカーネルと呼ぶらしいですが、厳密にいうと制御プログラムも、「カーネル」「デバイスドライバ」「ファイルシステム」の3つで構成されています。
カーネルは、ジョブ管理、タスク管理、記憶管理、割込み管理、データ管理などを行います。
 
**＜言語プロセッサ＞**
C言語やJavaなどのプログラミング言語で書かれたプログラムを、コンピュータが理解できる機械語に翻訳するプログラム
 
**＜サービスプログラム＞**
コンピュータの機能を補う、補助的なプログラムで、ユーティリティとも呼ぶ。ファイル圧縮プログラム等。

## まとめ
ソフトウェアの中でカーネルの位置を整理したところで、カーネルというのはOSの中核であり、少しのミスでシステムそのものを破壊しかねないデリケートな存在であることがわかるかと思います。
今回の事象は、セキュリティソフトの製品がカーネルレベルで動作していたことが原因であり、対策としてカーネルレベルへの接続回避とWindows変更計画とのことで、MicrosoftがCrowdStrikeやセキュリティ会社に向けたAPIを提供する方針でしょうか。
セキュリティソフトがカーネルで動作することはハイリスクハイリターンってイメージでしょう。
ブルスクを引き起こしてしまいカーネル外で動作させるしかないという判断だと思いますが、Micorosoftによると現在は必要最小限の部分だけカーネルモードで動作させ、その他の部分は回復が容易なユーザモードで動作するようなセキュリティ製品アーキテクチャを実現できるらしいです。
IT系専門学校で半年過ごして学んだこと

## はじめに
IT系専門学校に通い始めてからちょうど半年くらいになりました。
今回の記事ではこの半年間で自分がどんなことを学んだのかIT関連に絞って振り返っていきたいと思います。

## 2024年4月〜９月で学んだこと

### 学校でしたこと
1. ITパスポート資格,基本情報技術者資格授業(50分×2コマ×13週)
1. Python(50分×7コマ×13週）
1. HTML/CSS/JavaScript(50分×3コマ×13週）
1. Webデザイン(Adobe IllustratorとAdobe Photoshop)(50分×3コマ×13週）

私が通っている専門学校では、進度が遅い生徒に合わせて授業が行われるため、授業内に出された課題を全て完了すると、空いた時間で独学することになります。
実際に授業を聞いていた時間は体感、全体の60%くらいだったかな〜と思います。
それぞれの授業の概要は以下の通りです。

ITパスポート資格,基本情報技術者資格授業....その名の通り資格学習
Python....基礎的な文法〜Djangoを用いた記事作成アプリの開発
HTML/CSS/JavaScript....Webサイト制作（基礎的な文法,レスポンシブデザイン対応の実装,JavaScriptライブラリ/プラグインを用いた簡単なアニメーションの実装）
Webデザイン....Illustrator,Photoshopの基本操作,トレース,オリジナルデザイン（ロゴデザイン,名刺デザイン,バナーデザイン,ポートフォリオ用LP）

### 個人でしたこと
1. ITパスポート資格受験→6/9に合格
1. Linux環境でシェルスクリプトを利用したパスワードマネージャーを作ってみる
1. 以下のオフラインのGit勉強会に参加する
1. デイトラでのWebサイト制作学習（初級編終了）
1. HTML,CSS（Sass）,JavaScriptを用いて個人用ウェブサイトを作ってみる（途中）
1. 以下のイベントやハッカソンに参加,参加する中で必要だった技術に触れる
1. GitHubで草を生やす習慣をつける

https://primeanswer.connpass.com/event/318268/

https://progate.connpass.com/event/325648/

https://progate.connpass.com/event/325329/



使用言語およびフレームワーク: JavaScript、TypeScript、React、Node.js
使用ツールおよびサービス: OpenAI API、AWS、Supabase、Docker、Figma



## 全体的な振り返りと今後の抱負
学校外で学んだことの方が多く、特にハッカソンでは自分の技術力不足を痛感する良い経験となりました。ハッカソンでは、一部の機能実装にしか携われなかったことが悔しく、それを糧に現在は個人開発を始めています。10月中に個人開発を終わらせ、今年度中にWeb系の長期インターンに参加できるように、これから積極的に活動していきたいと考えています。

↓初めて参加したハッカソンの様子はこちらの記事で紹介しています

https://qiita.com/07aikiro/items/c1e418557b4329ccf16b
ラムダ式とメソッド参照 - 備忘録

## ラムダ式
簡単に言うと「短くかける関数」

### ラムダ式の構文
```:ラムダ式の構文
(引数) -> {実行したい処理}
```
・`->`は「～を使って実行する」というイメージ

#### 例 : 値を受け取って処理をする
```java:引数で受け取った値を2倍にする
(int a) -> { return a * 2; }
```

### ラムダ式を使う場所
ラムダ式は、関数型インタフェースという「メソッドが一つだけあるインタフェースを実装する」場合に使われる。
[関数型インタフェースチートシート](https://qiita.com/nakayamasou00/items/8052bff62d6fe2b0a3bb)

#### 例 : Runnableインターフェースの実装
Runnableインタフェースはメソッドが1つ (runメソッド) だけの関数型インタフェース

```java:Runnableインタフェースの匿名クラスでの書き方
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.print("hello");
    }
};
```
```java:ラムダ式での書き方
Runnable r = () -> {
    System.out.print("hello");
};
```
↑のように短く書ける

### ラムダ式の省略ルール
1. 型推論による型の省略
    インタフェースの宣言時に引数の型は決定しているため、明記しなくても推論できるため型名の省略が可能
    ```java:型名を省略した時の書き方
    (a) -> { return a * 2; }
    ```
2. 引数が1つの場合は()の省略が可能
    ただし、引数がない場合や複数ある場合は省略不可
    ```java:型名を省略した時の書き方
    a -> { return a * 2; }
    ```
3. 処理が1行であれば{}とreturnを省略できる
    ```java:{}とreturnの省略
    a -> a * 2;
    (a, b) -> a + b
    ```
[読書メモ]　リーダブルコード

# リーダブルコード

- **著者**: Dustin Boswell, Trevor Foucher
- **出版社**: オライリー
- **出版年**: 2012
- **読書期間**: 2024/09/21 ~ 2024/09/26

---

## 1. 概要

書籍の大まかな内容を簡潔にまとめます。全体のテーマや重要なトピックを記述しましょう。

---

## 2. 目次

- 第1章: 理解しやすいコード
- 第2章: 名前に情報を詰め込む
- 第3章: 誤解されない名前
- 第4章: 美しさ
- 第5章: コメントすべきことを知る
- 第6章: コメントは正確で簡潔に
- 第7章: 制御フローを読みやすくする
- 第8章: 巨大な式を分割する
- 第9章: 変数と読みやすさ
- 第10章: 無関係の下位問題を抽出する
- 第11章: 一度に一つのことを
- 第12章: コードに想いを込める
- 第13章: 短いコードを書く
- 第14章: テストと読みやすさ
- 第15章: 「分・時間カウンタ」を設計・実装する

---

## 3. 重要そうなポイント
フォーマット：項目 - (例)

### 第1章: 理解しやすいコード
- 読みやすさの基本定理「コードは他の人が最短時間で理解できるように書かなければならない」

### 第2章: 名前に情報を詰め込む
- 鍵となる考え「名前に情報を詰め込む」
- 明確な単語を選ぶ - Get→Fetch, downloadなどGet先に応じて抽象度を落とす
- 汎用的な名前を避ける - 慣習化しているものなどで例外あり
- 変数名に大切な情報を付加する - 単位
- スコープの大きい変数には長い名前をつける

### 第3章: 誤解されない名前
- 鍵となる考え「名前が他の意味と間違えられる事はないかと何度も自問自答する」
- 解釈の揺れを減らす命名 - lengthだとなんの長さかわからん→max_chars
- 適切な上下の限界値を選ぶ - 最後も含むならfirst-last, 最後を含まないならbegin-end
- 単語に対するユーザの期待にも注意 - getから始まるメソッドには、多くのプログラマが軽量なアクセサを期待するから計算コストの大きい処理を書かない

### 第4章: 美しさ
- 鍵となる考え「」
- 複数のコードブロックにわたり類似の構造が生じた場合シルエットも揃える
- 一貫性のあるスタイルで整列 - メンバ変数の順番、メソッドを論理グループ毎に段落化
### 第5章: コメントすべきことを知る
- 鍵となる考え「コメントの目的は、書き手の意図を読み手に知らせることである」
- 要らないもの - コードからすぐに抽出できること、ひどいコードを補完するもの(コード自体を修正すべき)
- 要るもの - なぜ他のやり方ではないのか、定数にまつわる背景、コードブロック単位での概観コメント
### 第6章: コメントは正確で簡潔に
- 鍵となる考え「コメントは領域に対する情報の比率が高くなければならない」
- コメントの意図を書く - 🙅‍♀️：「listをイテレートする」🙆‍♀️：「価格昇順に並び替える」
- インラインコメントによる名前付き引数 - Connect(/* timeout_ms = */ 10)

### 第7章: 制御フローを読みやすくする
- 鍵となる考え「制御フローはできるだけ自然にする」
- 比較演算は変化する値→安定な値の順に左から書く - while(bytes_recieved > butes_expected)
- if/elseは適切に並び替える - 肯定系、単純、目立つものを先に書く

### 第8章: 巨大な式を分割する
- 鍵となる考え「巨大な式は飲み込みやすい大きさに分割する」
- ドモルガンの法則、余事象の利用

### 第9章: 変数と読みやすさ
- 鍵となる考え「変数を操作する箇所が増えると、現在の状態を管理することが難しくなる」
- 中間結果を保存するためだけの変数は削除 - found フラッグなど、trueになるときに処理をすることで済むのならその方がいい
### 第10章: 無関係の下位問題を抽出する
- 鍵となる考え「無関係の下位問題を積極的に見つけ出し、抽出すること」
- モジュールが果たすべき本来の目的から見て、副次的な処理は別のコードとして抽出する - フォーマットやファイルの読み書き
- わずかに読みにくさが生じるからそれを相殺できる範囲で抽出を行う
### 第11章: 一度に一つのことを
- 鍵となる考え「コードは一つずつタスクを行うように」
- そのモジュールが行なっているタスクを全て列挙する→できるだけ異なる関数、少なくとも異なる領域に分割
### 第12章: コードに想いを込める
- ボトムアップで処理を積み上げていくのではなく、一度処理の流れをわかりやすく言語化してカラコードに落とし込む
### 第13章: 短いコードを書く
- 鍵となる考え「最も読みやすいコードは、何も書かれていないコードだ」
- 過剰な機能は持たせない
- 最も簡単に解決できるような要求を考える
- 定期的にAPIを読んで標準ライブラリに親しんでおく
### 第14章: テストと読みやすさ
- 鍵となる考え「大切で無い詳細はユーザーから隠蔽し、大切な詳細だけ見せる」
- テストのトップレベルは簡潔に - 入出力チェックは１行でかけるのが望ましい
- エラーメッセージの工夫
- 入力値を単純で有効なものに
### 第15章: 「分・時間カウンタ」を設計・実装する
- ユーザーフレンドリーなコードを書くために、外部の視点を得ることが重要
---

## 4. 要約
- 読みやすさとは「他の人が最短時間で理解できるように書かれていること」であること。
- 読みやすさの実現のためには1：表面的なもの 2：構成的なものの2点から考える必要があること。
- 1については主に1~9章に書かれており、2についてはそれ以降に書かれている
- 1→単一モジュールを対象範囲として、視覚的に、意味的に理解しやすいコードを書くやり方を説明している
- 主な改善対象としては、変数名、レイアウト、コメント、制御構造
- 2→モジュール間の統合・分割について。方針は以下
- モジュールのトップレベルから見て大切では無い詳細は抽象化して切り離す。
- 処理を言語化してからコード化する

---

## 7. その他メモ

[関連書籍：『文芸的プログラミング』](https://www.amazon.co.jp/%E6%96%87%E8%8A%B8%E7%9A%84%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-SOFTWARE-SCIENCE-Programming-Paradigm/dp/4756101909)

---
関数型インタフェースのチートシート

関数型インタフェースのチートシート
チートシートというより備忘録…のほうがいいかも…

### Runnable
メソッド：`void run()`
引数を取らずに何かを実行するためだけの処理を作るのに使用
```java:Runnable
Runnable r = () -> System.out.println("Hello");
r.run(); // Helloが表示
```

### Consumer\<T>
メソッド：`void accept(T t)`
引数を1つ受け取り、何かを実行するが、戻り値は返さない処理を作るのに使用
```java:Consumer<T>
Consumer<String> con = str -> System.out.println(str);
con.accept("Hello"); // Helloが表示される
```

### Supplier\<T>
メソッド：`T get()`
引数を取らずに、何かを返す処理を作るのに使用
```java:Supplier<T>
Supplier<String> sup = () -> "return Hello";
System.out.println(sup.get()); // return Helloが表示される
```

### Function\<T, R>
メソッド：`R apply(T t)`
引数を一つ受け取り、結果を返す処理を作るときに使用
```java:Function
Function<String, String> func = name -> "Hi! " + name;
System.out.println(func.apply("Jun")); // 「Hi! Jun」が表示される
```

### Predicate\<T>
メソッド：`boolean test(T t)`
引数を1つ受け取り、`true`か`false`を返す処理を作るのに使用
```java:Predicate
Predicate<Integer> pre = num -> 0 < num;
System.out.println(pre.test(11)); // 「true」が表示される
System.out.println(pre.test(-55)); // 「false」が表示される
```

### UnaryOperator\<T>
メソッド：`T apply(T t)`
引数を1つ受け取り、その引数と同じ型の値を返す処理を作るのに使用
```java:UnaryOperator
UnaryOperator<Integer> uo = num -> num * 2;
System.out.println(up.apply(2)); // 4が表示される
```

### BiFunction\<T, U, R\>
メソッド：`R apply(T t, U u)`
引数を2つ受け取り、結果を返す処理を作るのに使用
```java:BiFunction
BiFunction<Integer, Integer, String> biFunc = (a, b) -> a+"+"+b+"="+(a + b);
System.out.println(biFunc.apply(10, 10)); // 10+10=20と表示される
```
()で囲わないと文字列の連結となる

### BiConsumer\<T, U>
メソッド：`void accept(T t, U u)`
引数を2つ受け取り、値を返さない処理を作るのに使用
```java:BiConsumer
BiConsumer<String, Integer> printInfo = (name, age) -> 
    System.out.println(name + " is " + age + " years old.");
printInfo.accept("Alice", 30); // "Alice is 30 years old." が表示される
```

### BiPredicate\<T, U>
メソッド：`boolean test(T t, U u)`
引数を2つ受け取り、boolean型の値を返す処理を作るのに使用
```java:BiPredicate
BiPredicate<String, String> areEqual = (s1, s2) -> s1.equals(s2);
System.out.println(areEqual.test("apple", "apple")); // trueが表示される
```

### BinaryOperator\<T>
メソッド：`T apply(T t, T t)`
引数を2つ受け取り、引数と同じ型の値を返す処理を作るのに使用
```java:BinaryOperaor
BinaryOperator<Integer> multiply = (a, b) -> a * b;
System.out.println(multiply.apply(3, 4)); // 12が表示される
```
Gauge + Selenoid で自動テストを行うときに任意の階層を切って証跡動画を保存する

https://qiita.com/nobutak/items/1eaa61e5323cacec6a6a

https://qiita.com/nobutak/items/31d0d91fb336aebc75d5

上記の記事を参考にして構築してみた際に以下の点で詰まったのでメモ書きです。
 - `enableLog`, `enableVNC`, `enableVideo` の設定場所が変わった
 - ログファイルと録画ファイルを  `/Specification名/Scenario名/ブラウザ名.[log|mp4]` として保存したかった

```kotlin:Setup.kt
class Setup {

    @BeforeSuite
    fun beforeSuite() {
        // この時点では specification / scenario が決まっていないので取得できない
    }

    @BeforeScenario
    fun beforeScenario(context: ExecutionContext) {
        // specification 名, scenario 名を取得する
        val specName = context.currentSpecification.name
        val testName = context.currentScenario.name

        // ログファイルと実行動画の出力先ディレクトリ階層
        val fileDir = "$specName/$testName/".replace(" ", "_")
        // それぞれディレクトリが存在しなければエラーになるので事前に作成しておく
        val logPath: Path = Paths.get("selenoid/logs/$fileDir/")
        if (Files.notExists(logPath)) {
            Files.createDirectories(logPath)
        }
        val videoPath: Path = Paths.get("selenoid/video/$fileDir/")
        if (Files.notExists(videoPath)) {
            Files.createDirectories(videoPath)
        }

        val capabilities = DesiredCapabilities()
        val browserName = System.getenv("browser.name")
        capabilities.setCapability("browserName", browserName)
        capabilities.setCapability("browserVersion", System.getenv("browser.version"))

        // enable* などの設定は "selenoid:options" として設定する
        val selenoidOptions = mapOf(
            "enableLog" to true,
            // ログファイル名を指定
            "logName" to "$fileDir/$browserName.log",

            "enableVNC" to true,

            "enableVideo" to true,
            // 動画ファイル名を指定
            "videoName" to "$fileDir/$browserName.mp4",
        )
        capabilities.setCapability("selenoid:options", selenoidOptions)

        val driver = RemoteWebDriver(
            URI.create("http://localhost:4445/wd/hub").toURL(),
            capabilities,
        )
        WebDriverRunner.setWebDriver(driver)
    }
}
```
エンジニアリング

Neilsoft は、AEC/建設、製造、産業プラント分野の世界中のお客様にサービスを提供する、
エンジニアリング サービスとソフトウェア ソリューション (ER&D) に特化した会社です。
日本は当社にとって重要な市場であり、当社は日本向けの技術を開発しています。
日本の大学を卒業したばかりで、未経験または少しの経験しかない方も、この機会にご応募いただけます。
選考を通過された候補者の方には、最新のデジタル建設技術とソリューションに関する 3 ～ 6 か月間の広範なトレーニングが提供されます。

このポジションに応募するには、応募書類を sanat.samantray@neilsoft.com までお送りください。
詳細については、当社の Web サイト www.neilsoft.com をご覧ください。

#建築 #電気 #エンジニアリング #新卒 #DX建設

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3886906/8f4026c3-53f1-c075-2bf0-727972ca225a.png)
git コマンド備忘録

# コマンドと説明
使用シーンについては例です。

## `git init` 
新しいGitリポジトリを作成
実行ディレクトリがGitの管理対象になります。
```sh
$ git init
```
---
## `git clone リポジトリURL`
実行ディレクトリにリモートリポジトリからプロジェクトを自身のPCにコピー
```sh
$ git clone リポジトリURL
```
---
## `git add ファイル名`
commitに含める。
ステージングエリアに追加
```sh
$ git add ファイル名
```
全ての変更ファイルをステージングエリアに追加
```sh
$git add .
```
---
## `git commit -m "コミットメッセージ"`
ステージングエリアにある変更をスナップショットとして保存。
メッセージは自分で変更を簡潔に書きます。
```sh
$ git commit -m "コミットメッセージ"
```
---
## `git status`
現在のブランチでの変更差分のあるファイルパスとステージングにあるのかそうでないのかを表示
```sh
$ git status
```
---
## `git push`
ローカルブランチにあるコミットをリモートリポジトリに反映
```sh
$ git push リモート名 ブランチ名
```
リモートのリポジトリを強制的に更新し、コミットを取り除きます。

:::note warn
この操作はリモートリポジトリの履歴を書き換え、他開発者がコミットを取得している場合に問題発生する場合があります。
:::

```sh
$ git push --force
```
---
## `git pull リモート名 ブランチ名`
リモートリポジトリにある最新の反映を自身のローカルリポジトリに反映。
`git fetch`と`git merge`を1回で行う。
```sh
$ git pull リモート名 ブランチ名
```
---
## `git checkout`
別ブランチに切り替える。
```sh
$ git checkout 移動先ブランチ名
```
新しいブランチの作成とそのブランチへの移動を行います。
```sh
$ git checkout -b ブランチ名
```
---
## `git branch ブランチ名`
新しいブランチの作成。
この作成したブランチで作業をするためには`git checkout ブランチ名`を実行する必要があります。
```sh
$ git branch ブランチ名
```
---
## `git fetch リモート名`
リモートリポジトリから最新の変更をローカルに反映。(自身の作業ブランチに直接影響はありません。)
リモートでの変更がローカルリポジトリに反映されていない場合に使用。
```sh
$ git fetch リモート名
```
---
## `git merge リモート名/ブランチ名`
指定したブランチの変更を現在のブランチにマージ。
他のブランチにメインブランチを反映したい際に使用。
```sh
$ git merge ブランチ名
```
---
## `git log`
リポジトリの過去commit履歴を表示。`コミットID`もこのコマンドで調べます。
どの変更がいつ、誰によって行われたかを表示します。
```sh
$ git log
```
---
## `git reset`
コミット履歴をもどします。しかし、変更そのものは残します。
指定したcommitよりも後のcommitを取り消しますが、作業ツリーやステージングエリアの変更はそのまま保持します。
commitはしたが、pushしていない場合にcommitを取り消す際に使用します。
```sh
$ git reset --soft コミットID
```
リポジトリの状態を特定のコミットの状態に完全に巻き戻します。

:::note warn
`--hard`を使用した場合、変更取り消しができません。
:::

commitはしたが、pushしていない場合にcommitを取り消しかつ変更も削除する際に使用します。
```sh
$ git reset --hard コミットID
```
---
## `git stash`
現在の変更を一時退避します。
変更を取り消したり、反映せずにブランチの切り替えを行う際に使用。
```sh
$ git stash
```
メッセージをつけて`stash`できます。
あとで探す際に分かりやすくなる。
```sh
$ git stash save "メッセージ"
```
`stash`した履歴を表示
```sh
$ git stash list
```
---
## `git stash apply`
`git stash`した最新の内容を反映。
```sh
$ git stash apply
```
stashした内容を現在のブランチに反映。
上記`git stash list`で表示される`stash@{n}`(nには数字が入ります。)を使用して特定の`stash`履歴を現在ブランチに反映。
```sh
$ git stash apply stash@{n}
```
---
## `git rebase ブランチ名`
ブランチの履歴を変更する。
あるブランチのベースを別ブランチに変更します。(あまり使ったことないコマンドです。)
```sh
$ git rebase ブランチ名
```
---
## `git remote`
リモートリポジトリの一覧を表示します。
リモートリポジトリのURLと`fetch`と`push`に使用されるリモートの情報が表示。
通常は`origin`がリモートリポジトリの名前として使用されています。
```sh
$ git remote -v
```
現在設定されているリモートリポジトリを削除する。
リモートリポジトリとの接続解除しますが、ローカルの作業に影響はなし。
```sh
$ git remote remove origin
```
リモートリポジトリのURLを変更する。
リモートリポジトリが変わった場合等に使用。
```sh
$ git remote set-url origin リポジトリURL
```
---
## `git revert`
特定のコミットを取り消し、新しいコミットを作成します。
この方法ではリモートの履歴を壊さずにcommit内容を取り消したい場合に使用します。
```sh
$ git revert コミットID
```
【#if DEBUG】コンパイルディレクティブのススメ

## はじめに
Swift歴5ヶ月の新米プログラマーのメモ。

## コンパイルディレクティブとは
プログラミングにおいて、

コンパイル[^1]は、プログラミング言語（高水準言語）で書かれたプログラムを、それより低水準な言語や、コンピューターが理解できる言語（機械語）に変換すること。
また、コンパイルするソフトウェアのことを、コンパイラーと呼ぶ。

ディレクティブ[^2]は、コンパイル時にコンパイラーに指示や命令をするために、プログラム中に記述される要素のこと。
<br>

つまり、そのコンパイル時に特定の処理を行わせるための指示・命令をするために使用するのが、**コンパイルディレクティブ**である。

<br>

## コンパイルディレクティブの種類
Swiftで使用可能なコンパイルディレクティブは、主に以下の3つにカテゴライズがある。

1. 条件付きコンパイル
2. デバッグ・エラー処理
3. メタ情報 

その他、カスタムコンパイルフラグを作ることもできる。

<br>

## 1. 条件付きコンパイル
その名の通り、条件に応じてコンパイルするかどうかを決めるために使うもの。
``#if``, ``#else``, ``#elseif``, ``#endif``の4つと、制御したい条件のコンパイルフラグを使って記述する。

### ``#if DEBUG``
```Swift
#if DEBUG
    print("デバッグ用")
#else
    print("リリース用")
#endif
```
ビルドごとに異なるコードを実行したいときに使うコンパイルディレクティブ。
<br>
### ``#if os()``
```Swift
#if os(macOS)
    print("macOS用")
#elseif os(iOS)
    print("iOS用")
#elseif os(watchOS)
    print("watchOS用")
#elseif os(tvOS)
    print("tvOS用")
#elseif os(visionOS)
    print("visionOS用")
#elseif os(Linux)
    print("Linux用")
#elseif os(Windows)
    print("Windows用")
#endif
```
プラットフォームごとに異なるコードを実行したいときに使うコンパイルディレクティブ。
<br>
### ``#if arch()``
```Swift
#if arch(i386)
    print("32ビットのx86アーキテクチャ")
#elseif arch(x86_64)
    print("64ビットアーキテクチャ")
#elseif arch(arm)
    print("RISCアーキテクチャ")
#elseif arch(arm64)
    print("ARM64アーキテクチャ")
#endif
```
CPUアーキテクチャごとに異なるコードを実行したいときに使うコンパイルディレクティブ。
<br>
### ``#if swift()``
```Swift
#if swift(>=4.2)
    print("Swift 4.2以降")
#endif
```
特定のSwiftのバージョンでのみコンパイルしたいときに使うコンパイルディレクティブ。
<br>
### ``#if compiler()``
```Swift
#if compiler(>=5)
    print("コンパイラー 5以降")
#endif

#if canImport(UIKit)
    import UIKit
    print("UIKitが利用可能")
#endif
```
特定のSwiftコンパイラーのバージョンでのみコンパイルしたいときに使うコンパイルディレクティブ。
<br>
### ``#if targetEnvironment()``
```Swift
#if targetEnvironment(simulator)
    print("シミュレータで実行")
#elseif targetEnvironment(macCatalyst)
    print("macCatalystで実行")
#else
    print("実機で実行")
#endif
```
シュミレーターや実機で異なるコードを実行したいときに使うコンパイルディレクティブ。
<br>
### ``#if available()``
```Swift
if #available(iOS 15, *) {
    print("iOS15以降でのみ実行")
}
```
特定のバージョンのOSでのみ実行されるコードを書くために使うコンパイルディレクティブ。

<br>

## 2. デバッグ・エラー処理

:::note
Swift 5.9以降での変更
Swift 5.9から、``#warning``や``#error``といったコンパイルディレクティブの機能が、新しいマクロとして提供されるようになったため、将来的にはマクロ方式（``warning(_:)``や``error(_:)``）に移行していくことが推奨される可能性がある。

下記、新しいマクロ方式のドキュメント
[warning(_:)](https://developer.apple.com/documentation/swift/warning(_:))　[error(_:)](http://developer.apple.com/documentation/swift/error(_:))
:::

### ``#warning``, ``#error``
```Swift
#warning("警告")
#error("エラー")
```
コンパイル時に警告やエラーを表示させるために使うもの。

<br>

## 3. メタ情報
コード内でファイル名や関数名などの情報を取得したり、メソッドやプロパティを指定するために使うもの。

### ``#file``, ``#line``, ``#function``
```Swift
print("ファイル名：\(#file)")
print("行番号：\(#line)")
print("関数名：\(#function)")
```
現在のソースコードのファイル名、行番号、関数名などを取得したい時に使うコンパイルディレクティブ。
<br>
### ``#sourceLocation``
```Swift
#sourceLocation(file: "CompileDirective.swift", line: 10)
#sourceLocation()
```
そのコードが書かれている行番号とファイル名とは異なる行番号とファイル名に偽装したい時に使うコンパイルディレクティブ。

<br>

## 参考

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Conditional-Compilation-Block


[^1]:コンパイル（compile）とは、"集める"や"編集する"という意味の英単語。
[^2]:ディレクティブ（directive）とは、"指示"や"命令"という意味の英単語。
Next.jsのサーバーコンポーネントの実装練習(2) ~prisma導入~

昨日の続き。

**💡Prismaを導入しておく**

インストール
```
npm install prisma @prisma/client
```

初期化
```
npx prisma init
```

:::note info
自動生成：prismaフォルダ、prisma/schema.prisma ファイル
:::

`.env`にDATABASEURLを定義しておき、schemaでそれを参照する
```typescript
// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
```

**💡モデルを定義する**

仮のモデル定義
```typescript
// prisma/schema.prisma
model User {
  id    Int     @id @default(autoincrement())
  name  String
  email String  @unique
  posts Post[]
}

model Post {
  id        Int     @id @default(autoincrement())
  title     String
  content   String?
  published Boolean @default(false)
  authorId  Int
  author    User    @relation(fields: [authorId], references: [id])
}
```

**💡migration**

コンテナ環境のため、Next.jsのコンテナの中に入り、prismaのフォルダのパスまで移動したうえでmigrationのコマンドを実行する必要がある。
```
docker-compose exec next /bin/sh
cd prisma
npx prisma migrate dev --name <migration_name>
```

**💡prismaクライアントを定義するためのファイル作成**
```typescript
// /src/lib/prisma.ts

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default prisma;
```

**💡エンドポイント定義**

`app`ディレクトリの下に`api`ディレクトリを作成し、ここに各種エンドポイントを定義していく。
```
mkdir app/api
```
```
mkdir app/api/users
```
```
touch app/api/users/route.ts
```

一旦ここまで。
IT業界未経験、開発微経験、業務改善コンサルエンジニアもどきの案件獲得までのロードマップ

:::note 

この記事は非IT業界を対象に活動したいと考える、開発微経験の業務改善コンサル向けの内容です
僕がそうです
なので異論はあると思います
:::

## そもそも私の自己紹介から
北海道の田舎都市に住んでいます。
業務改善に目覚めたのは、バックオフィス業務を請け負う会社の契約社員SVとして、部署(？)の新規立ち上げとオペレーションに携わっていた時。

Excelなんて触ったことがなく、初めて数式にもチャレンジしたのですが、1か月もしないうちにVLOOKUP関数、INDEX-MATCHの数式が書けるようになり、顧客管理表をはじめとした様々なブックを作りました。
この時は考えたものがポンポン完成するのもあり、「Excelおもしろ」なんて思っていました。

ある日、顧客管理表にデータをコピペで移していると「コピペめんどくさ」とふいに思い、急に「Excel 自動化」で調べ始め、Excelマクロ(VBA)に出会いました。
そこからは狂ったようにVBAをゴリゴリ書きました。
周りにはVBAに明るい方は誰一人おらず、つまずいても一人で解決するしかなかったです。
(ちなみに今もそんな感じ)

開発自体楽しくて仕方ないですが、大したものを作ってきたわけではありません。
一応、これまで開発してきたものを抜粋したスキルシートなる記事を張り付けておきます。
https://qiita.com/ay01sec/items/1c4243c2c615f544ff2e

というわけで、長くなった自己紹介をまとめると次の項目になります。

## 実績を踏まえた上で自分にできること
- 自走する力
- プログラムを楽しむ
- めんどくさい気持ちで浮かんでくるアイデアをもとにした提案や開発

## 今の自分に足りないこと
- Webエンジニアとしての知識
- 交渉力？
- 自分に対する分析力

## 求められるであろう最低限のスキル
### コミュニケーション能力
これはもう言わずもがな。
正直、失礼すぎたりしなければ良いのかなと思います。
かしこまりすぎても堅苦しいだけで、先方にとっての相談役になりづらく、最終的に改善に成功した時、不完全燃焼になる。
失礼なことを言ったとしても、それをカバーできればモーマンタイです。
とはいえ、ここは初期段階で関係を構築できていることが前提なので、最初は探りましょう。
※あくまで僕の考え方なので、やりやすい方法でどうぞ

### ある程度の開発経験
弊社のコンサルが受注してきた案件は無理難題が・・・
なんて話よく聞きます。
まぁそりゃそうですよ、そのコンサル開発したことなくて、適当にハイハイできます！って言ってるんだから(すみません、僕の適当なシナリオです)
僕の場合、開発もしたからコンサルができるんだと思います。
無理難題いわれてもできないことが判断できれば「それは難しいのでこうしませんか」というのができるし、どうしたって無理な話は「すみません、その内容ならフローやツールを変えないと実現できません」といえる
こちらも要望は叶えたいし、代替案を提示して解決したいけど、なんでもはできないので😭

### 事務などの実務経験
どこに問題があるか、どこを改善できるかという観点では必要不可欠な要素です。
先方には、どこを改善できるかわからない方もいます。
どこをどう改善したいか見当が付かず、漠然と自動化がしたい！ということもあります。
その時、どこに課題があるのか、ポイントを見極めるのが業務改善コンサルの役割でもあるため、事務作業は経験としてやっておいた方が◎
「あの作業大変じゃないですか？」という提案や、「処理に手間がかかって～」という話に共感できる。

### 無理に自動化せず、効率化までで留めておくか効率化しないかを検討する
見極めが難しいところではあるのですが、僕がこれを考えているのには理由があります。
- 業務の本質を理解するためにあえて自動化しない
    - なぜこの処理をしないといけないのかを考えさせたい場合
    - 企業の発展を考えたときに後任が本質を理解しないまま業務を続けると経営が傾く可能性
- そもそもする必要がない
    - 優先順位としての理由
    - 改善前/後の工数や開発コストの問題

代表的な理由を挙げるとこの二つでしょうか。
業務改善が目的なのに、経営悪化は本末転倒ですよね。
下手をすれば、紙一重かもしれません。
その改善が、先方の取引先も巻き込んだシステムなら・・・
逆に成功すれば、先方の取引先からも依頼がもらえるかも・・・？

## 案件をとれた経緯
僕の中で印象深い一件を紹介します。
とあるマッチングサービスで、コーディング体験というものを見つけました。
HTML/CSSの体験会だったのですが、本当にHelloWorldから始める初心者向けの内容でした。
多少経験はあったのでそれなりにこなすと、担当の方から「見たことない速さで終わった」と。
そこから「今何の仕事しているの」「何ができるの」「うちの会社興味ない？」とあれよあれよとトントン拍子で話が進みました。
実際、その企業さんはWebエンジニアの募集が目的だったのですが、ある意味棚からぼた餅というような感じで、契約を交わすことに。
こんなこともあるんですねぇ～とは思っていますが、やはりこういった形でも最低限のスキルは大事でした。

## 考え方？(あくまで僕の)
ここまで来て少し考え方のお話になります。
- 最初の案件がお試し価格になるのは仕方ない
    - 本業があるなら、時間数を考えて納期のめどを立てましょう。
    - お試し価格だとしても、継続的な契約ができることもあります。
- 同じ時間を消費したとしても、自動で動くものならもう一人分仕事ができる
    - 事業拡大を考えると、ものすごく大事な考え方
    - 自動処理用のPCを買うのと、人を一人雇うのではコストが大きく変わる
    - ということも提案内容の中に入れられますよね

## まとめ
ここまで読んでいただきありがとうございました。
- 日本全体の業務が改善されて成果を上げやすくする
- 経済の循環が円滑になること

この二点が僕の野望です。
一人でも業務改善に特化した人材を増やして、日本の経済や価値を底上げしていきたいと考えています。
喉が痛い

#DockerでHello World
Docerの便利なところ
コンテナを利用することでどんな環境で実行しても同じ結果を得ることができる。


Dockerでコンテナを作る流れ
1.DockerfileでDockerイメージをbuild
2.コンテナレジストリにDockerイメージをpush
3.Dockerhubからpullして使えるようになる

コンテナの起動
docker run --rm --detach --publish ~~~ nginx:1.25.3
ローカルにドッカーイメージがなかったからライブラリから自動でpullしてくれた

Dockerイメージのビルド
docker build ~~~
html Dockerfileを作ってビルドできる
Dockerfileでは命令が大文字、引数が小文字らしい

run
docker runでコンテナ実行
 --rm コンテナ停止するとコンテナ消える
 --detach　バックグラウンドで動くようになる的な
 --publish　ポートフォワードを行う（なんだろう）
Androidで、カウントダウンを

Androidで、カウントダウンを実装しようと思ったのですが、CountDownTimerが微妙な感じで、代わりになるものがないか検討したので、記事にしたいと思います。

### 結論

postDelayedで、実装することにしました。
ポイントとしては、postDelayedにthisを渡して、runnableを繰り返すことでカウントダウン出来ます。

```kotlin
    private var selfTimerCount = 10
    private val handler = Handler(Looper.getMainLooper())
    private val runnable = object : Runnable {
        override fun run() {
            if (selfTimerCount == 0) {
                // 何かを実行する
                return
            }
            selfTimerCount--
            handler.postDelayed(this, TIMER)
        }
    }

    override fun onResume() {
        super.onResume()

        handler.post(runnable)
    }

    override fun onPause() {
        super.onPause()

        handler.removeCallbacks(runnable)
    }
    
    companion object {
        private const val TIMER = 1000L
    }    
```
【TypeScript】TypeScriptでHTMLElement: style プロパティに代入する方法

## 動作環境
TypeScript: 5.4.5
VSCode: 1.93.1
# 起きている問題
 JavaScriptで書かれた以下のコードをTypeScriptに書き換えた際、``読み取り専用プロパティであるため、'style' に代入することはできません。ts(2540)``または``error TS2540: Cannot assign to 'style' because it is a read-only property.``というエラーが表示されてしまう。
 ```ts:エラーが出るコード
 document.getElementById("send").style = "cursor: not-allowed";
 ```
 ![vscodeでの警告画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632168/531e4d76-f0c0-eacf-f6d7-cfd778a350f1.png)
 ちなみにこのコードを実行すると、ブロック上にマウスカーソルが来ると操作禁止を意味する``not-allowed``に変更するcss文に上書きできる。
# 解決方法
　TypeScriptにて先ほどの動作を警告無しに実装する場合、以下のようにstyleが持つcssTextへ代入します。
 ```ts:解決したコード
 document.getElementById("send").style.cssText = "cursor: not-allowed";
                                    //    ↑これを追加
```
## JavaScriptでstyleに代入すると何が起きていたのか
なぜTypeScriptでは読み取り専用プロパティであるstyleにJavaScriptは代入し、インラインスタイルを設定することができていたのだろうか。この疑問を解消する説明が[MDN web docs](https://developer.mozilla.org/ja/)の[HTMLElement: style プロパティ](https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/style)にある。
>このプロパティは読み取り専用であり、CSSStyleDeclaration オブジェクトを代入することはできません。**とはいえ、style プロパティに文字列を直接代入してインラインスタイルを設定することは可能です。この場合、文字列は CSSStyleDeclaration.cssText に転送されます。** この方法で style を使用すると、要素上のすべてのインラインスタイルが完全に上書きされます。
>*HTMLElement: style プロパティ - Web API | MDN* より引用

https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/style

強調されてい文章から、styleプロパティにJavaScript上で文字列を代入するとその文字列はCSSStyteDeclaration.cssTextに転送されているようです。そのため型付けが無いJavaScriptでは、読み取り専用とはいえ代入すると転送されているため始めに出したコードが動作するようです。
解決方法で挙げたものでは、転送先のCSSStyleDeclaration.cssTextに直接代入するようにしています。HTMLElementのstyleは動的なCSSStyleDeclarationオブジェクトの形であるため、style.cssTextに代入することで元のJavaScriptで書かれたコードと同じ動作を行えます。
Homebrewのインストール方法（mac）

# Homebrewとは？
Homebrewとは、macOSやLinuxでパッケージ管理を簡単に行うためのパッケージ管理ツールです。
これがあるだけでめんどくさい環境構築をコマンド1つで行うことができます！

例えば、以下のツールがインストールできます。
- Git (ソースコード管理システム)
- Node.js (JS実行環境)
- Python
- Docker (コンテナ化ツール)
- MySQL/PostgreSQL (データベース)
- nginx (webサーバー)
- OpenJDK (Java開発環境)
- GCC（CやC++のコンパイラ）

# インストール方法

以下のコマンドをターミナルで実行して、Homebrewをインストールします。
```bash:bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

### 環境変数`PATH`にコマンドを登録する
正しくインストールができていれば、`Next steps:`というログが出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794632/639c14a1-04ca-4da9-5427-b72f5ac0bbc9.png)
`printf`から始まるコマンドと`eval`コマンドをコピーしてターミナルで実行します。

### インストールができているか確認
```bash:bash
brew -v
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3794632/f782a1d5-8aea-01c4-b098-495160b4f3e7.png)
このようなバージョンが表示されたら成功です！
これで`Homebrew`のインストールが完了しました！

# 余談
### 環境変数`PATH`とは？
よく、「PATHを通す」と言われることがありますが、PATHとはなんなのでしょうか...

`PATH`は、環境変数です。
`環境変数PATH`には、さまざまなコマンドが設定されています。
ターミナルでコマンドが実行された時、PATHからコマンドが登録されている場所を探します。

つまり、「PATHを通す」とは、「環境変数PATHにコマンドを登録する」ということです。
先ほどコマンドを登録したのも、コマンドを登録しないとHomebrewが使えないためなのです。
Androidで、DataStoreを導入

Androidの設定情報を保存する方法として、SharedPreferencesが主流でしたが、DataStoreに移行した方が良さそうなので、導入手順を記載します。
また、DIのHiltを使用する前提で記載します。

### DataStoreの導入

```gradle

  implementation("androidx.datastore.datastore-preferences:1.1.1")

```

### Hilt

AppModuleとしてますが、別のModuleとしても問題ありません。
preferencesDataStoreFileで指定しているのが、ファイル名になります。

```kotlin:AppModule.kt
@Module
@InstallIn(SingletonComponent::class)
class AppModule {

    @Singleton
    @Provides
    fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore<Preferences> {
        return PreferenceDataStoreFactory.create(
            produceFile = {
                context.preferencesDataStoreFile("preferences")
            }
        )
    }
}
```

### キーを作成

キーは、保存したい値の型で作成します。

```kotlin:PreferencesKeys.kt
object PreferencesKeys {
    val SAMPLE = intPreferencesKey("sample")
    val SIMPLE = stringPreferencesKey("simple")
}
```

### 値の保存

DataStoreに値を保存する方法と使い方を記載します。

```kotlin:PreferencesRepository.kt
class PreferencesRepository @Inject constructor(
    private val dataStore: DataStore<Preferences>
) {

    suspend fun saveSample(value: Int) {
        dataStore.edit { preferences ->
            preferences[PreferencesKeys.SAMPLE] = value
        }
    }
}
```

```kotlin:MainViewModel.kt
@HiltViewModel
class MainViewModel @Inject constructor(
private val preferencesRepository: PreferencesRepository
) : ViewModel() {

    fun setSample(value: Int) {
        viewModelScope.launch {
            preferencesRepository.saveSample(value)
        }
    }
}
```

### 値の取得

同じPreferencesRepositoryとViewModelで実施しますが、分けて記載します。
emitすることで、UIに通知します。


```kotlin:PreferencesRepository.kt
class PreferencesRepository @Inject constructor(
    private val dataStore: DataStore<Preferences>
) {

    suspend fun readSample(): Int {
        return dataStore.data.map { preferences ->
            preferences[PreferencesKeys.SAMPLE] ?: 0
        }.first()
    }
}
```

```kotlin:MainViewModel.kt
@HiltViewModel
class MainViewModel @Inject constructor(
private val preferencesRepository: PreferencesRepository
) : ViewModel() {

    private val _sampleState = MutableSharedFlow<Int>()
    val sampleState = _sampleState.asSharedFlow()
    
    fun getSample() {
        viewModelScope.launch {
            val value = preferencesRepository.readSample()
            _sampleState.emit(value)
        }
    }
}
```

### まとめ

DataStoreは、非同期で動作するので少し癖がありますが、DataStoreへの移行を勧められてますので、是非移行していきましょう。
CloudFrontのキャッシュ削除の仕様変更への対応

# はじめに

こんにちは、Gakken LEAP のエンジニアの shogawa です。
今回は、CloudFrontでのキャッシュ削除について、仕様が変更されたようでキャッシュが残ってしまう事象が発生したため、調査および対応方法についてまとめます。

# 前提

- AWSの環境が整っていること
- CloudFrontのディストリビューションが設定されていること
CloudFrontのオリジンはS3のバケットに設定されており、すべてのキャッシュを削除したい場合の仕様となります。

> 参考：https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/Invalidation_Requests.html

# キャッシュ削除の手順

AWSのコンソールから、CloudFrontから対象のディストリビューションを選択、キャッシュ削除のタブから「キャッシュ削除を作成」をすることでキャッシュ削除を実行することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455950/df75e976-6bad-05e6-25e1-dd9015e0afcb.png)

そこで、キャッシュ削除対象のオブジェクトパスを指定し、「キャッシュ削除を作成」をして実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455950/1450e6c6-1b31-8896-734d-7763c683abfe.png)

# 仕様

2024年6月頃までは、オブジェクトパスに"/"を設定することで対象ディレクトリのキャッシュ削除ができていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455950/b7143274-9b4b-7b3e-5952-6903026ac436.png)

2024年9月時点では、オブジェクトパスに"/*"を設定しないとキャッシュ削除ができないように変更されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455950/a82b82bc-9555-a80f-06b7-2bcc9c2bd246.png)

# GithubActionsでの注意点

GithubActionsから実行する場合は、node-version20でsetup-node@v4を利用し、以下のように設定する必要がありました。

```sh
        # 抜粋
      - name: Setup node
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Delete Cloudfront Cache
        run: aws cloudfront create-invalidation --distribution-id ${{ env.CLOUDFRONT_DISTRIBUTION_ID }} --paths '${{ env.CLOUDFRONT_TARGET_PATH }}'
```

※手元の環境では、元々node-version17で、setup-node@v3を使用していました
※その場合はオリジンとは別のオブジェクトパスに対してのキャッシュ削除が実行されてしまうようなので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3455950/b2392251-a830-575f-7286-e1d1c8b12f2e.png)

# エンジニア募集中

Gakken LEAP では教育をアップデートしていきたいエンジニアを絶賛大募集しています！！

https://gakken-leap.co.jp/recruit/
windowsからUbuntuに接続する

# はじめに
windows PCからUbuntu PCに接続する

# Ubuntu に接続できるように設定を行う
1. Ubuntu のIPとhost名を調べる
   1. Ubuntuを起動して`ctrlキー + t` でターミナルを起動
   1. ipコマンドで アドレスを確認する
      ```
      ip -4 a
      ```
      - 今回はwlp2s0のIPを採用
      - ![1_ip.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/7871891e-087b-6cb2-e01b-d3ee459d4552.png)
      - コマンドについて
        - `ip` でIPアドレスを確認
        - `-4` IPv4の表示
        - `a` ネットワークIPアドレスを確認 
      - 出力値について
        - `lo` ローカルループバック 自分自身を示す仮想的なIPアドレス
        - `enp1s0`
          - `en` イーサネット
          - `p1` 1番目のバス
          - `s0` 0番目のスロット
        - `wlp2s0`
          - `wl` WLAN(無線LAN)
          - `p2` 2番目のバス
          - `s0` 0番目のスロット
   1. Host名を調べる
      ```
      hostname
      ```
1. Ubuntu にsshサーバーをインストールする
   1. SSHサーバーが起動しているか確認する
      ```
      sudo service sshd status
      ```
      - Unit sshd.service could not be found. が表示されたらsshサーバーの導入を行う
   1. open-ssh-serverをインストールする
      ```
      sudo apt install openssh-server
      ```
   1. 再度 SSHサーバーが起動しているか確認する
      ```
      sudo service sshd status
      ```
      - ![2_ssh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/d2cd8f84-b1f4-fb3e-b71d-f526151adaa6.png)
      - active (running) になっていればOK
    1. sshについては以下ページなどを参照
       - https://wa3.i-3-i.info/word11722.html

# windowsから Ubuntuに接続する
1. 管理者実行でPowershellを起動
1. sshでubuntuに接続する
   - ` Ubuntu のIPとhost名を調べる`で確認した[hostname]@[ip]を使用してssh接続を行う
   ```
   ssh <hostname>@<ip>
   ```
   ![3_ssh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3895022/d1c4c72c-4b7f-59c7-deaa-f00fd54bec2e.png)
   - 初回の場合はフィンガープリントの確認をされるので[yes]で接続を行う
1. ssh鍵を設定する
   1. windows上で 鍵を作成
      1. 鍵をセットするフォルダを作成する
         ```
         mkdir c:\Users\XXXXX\.ssh
         ```
      1. 鍵を生成する
         ```
         C:\Users\XXXXX> ssh-keygen
         ```
      1. 公開鍵を確認する
         ```
         ls C:\Users\XXXXX\.ssh
         ・・・
         -a----        2024/08/31     18:12            740 id_rsa.pub
         ```
      1. 公開鍵(id_rsa.pub)の中身をコピーする
         ```
         (例)
         ssh-rsa AAA...
         ```
   1. Ubuntuに公開鍵の内容を覚えさせる
      1. ~/.ssh/authorized_keys ファイルを作成する
         ```
         mkdir ~/.ssh/
         touch ~/.ssh/authorized_keys
         ```
      1. 公開鍵(id_rsa.pub)の中身をauthorized_keysに書き込む
         ```
         vim ~/.ssh/authorized_keys
         ```
         - vimの操作方法
           - `i` で挿入(書き込み)モードになる
           - `右クリック` でクリップボードの内容を貼り付け
           - `Esc`で挿入モードを抜ける
           - `:wq`で保存して閉じる
           - `:q`で終了
           - `:q!`で保存せずに終了
           - 参考ページ:https://qiita.com/et_good_eng/items/96603b753eb438a7c5c3
       1. ディレクトリ、ファイル権限を変更する
          ```
          sudo chmod 700 ~/.ssh
          sudo chmod 600 ~/.ssh/authorized_keys
          ```
       1. windowsからssh接続を試してみる
# 参考ページ
  IPコマンドについて: https://qiita.com/ponsuke0531/items/b61eeefdad9bb5e2ac28
  SSHについて: https://wa3.i-3-i.info/word11722.html
  vimコマンドについて: https://qiita.com/et_good_eng/items/96603b753eb438a7c5c3

# まとめ
  windowsからubuntuへの接続を行った。
  次回はVSCodeの拡張機能を使ってVScode上で接続できるようにする
pandasをインストールしようと思ったらインストールできなかった

# 開発環境
・Mac M2 
・python3.9.1
・pip 20.2.3
## 問題の発生
pandasを使いたいため以下のコマンドでバージョン指定をしてインストールを試みました
```
pip install pandas==1.4.0
```
しかし、以下のエラーメッセージが表示されました。
```
WARNING: You are using pip version 20.2.3; however, version 24.2 is available.
You should consider upgrading via the <ディレクトリ名> -m pip install --upgrade pip' command.
```
と、エラーが出ました。この警告からpipのバージョンが古いため問題が発生していることがわかりました。
## 解決方法
以下のコマンドでpipを最新バージョンにアップグレードしました。
```
pip install --upgrade pip
```
その後、pipのバージョンを再度確かめるとアップグレードできていることがわかりました。
```
pip 24.2
```
そして、再度pandasのインストールを試みると無事にインストールできました。
```
pip install pandas==1.4.0
```


## 学び
pipのバージョンが古いと、特定のライブラリのインストール等に失敗することがあるようです。開発環境を整える際は、pipのバージョンを最新に保つことが重要でだと感じました。特にPython初心者の方は、pipのアップグレードを怠らないようにしましょう。この記事がどなたか特に初心者の方の助けになれば幸いです。

::: note
pipのバージョンがv20.0代と24.0代では、だいぶ仕様が違うようです。依存関係？とやらも大幅なアップデートがあったみたいです。
Taskを返すeventをawaitで待ってはいけない（気付きづらいうっかりミスの紹介）

# 概要

C#のeventは割と基本的な機能なので、気軽に使っていると思います。しかしawaitと組み合わせたら、意外なところで罠にはまったので、気をつけましょうという事で紹介です。

# 最初に結論まとめ

Taskを返すタイプのeventをawaitで待った場合、eventに登録されたデリゲート全ての完了を待たず、1つでも完了したら処理が進んでしまいます。これはおそらく、意図と違う動きになっていると思います。気をつけましょう。

良く考えてみれば当たり前の動きですが、見た目には次のような感じで普通に見えるので、コードをぱっと見ただけだとなかなか気付きませんでした。

```csharp
event Func<Task> action1Async;

await action1Async();
```

# 詳しく紹介

Taskを返すタイプのeventとawaitを組み合わせた場合、一見、eventに登録されたデリゲート全ての完了を待機しているように見えます。しかし、実際には1つしか待機していない。という話です。

C#のeventは、Observerパターン的なものなので、複数のObserverを登録できます。複数の登録がある場合は、Invoke()を呼び出した時に、登録されたメソッドが同期で順番に呼ばれ、全ての処理が終わったら制御を返します。こんな感じです。

```csharp
event Action action1;
action1 += () => Console.Write("1");
action1 += () => Console.Write("2");

//この状態でInvokeを呼び出すと
action1();
Console.Write("3");
//必ず"1"と"2"が出力されてから制御を返すので、コンソール出力は
//>123
//になる
```

※eventは本来はイベント登録とInvoke()を行える場所が異なりますが、本記事ではコードをシンプルにするため同じ場所から呼び出すコードを書きます

そのため、「Invoke()が制御を返したら、全ての登録済みデリゲートの処理は終わっている」と期待して使うと思います。

しかし、その感覚のままでawaitと組み合わせると、書き方によってはデリゲートの処理が終わる前に制御が返ってきてしまいます。こんな感じの場合です。

```csharp
event Func<Task> action1Async;

async Task Func1()
{
    await Task.Delay(3000);
    Console.Write("1");
}
async Task Func2()
{
    Console.Write("2");
    await Task.CompletedTask;
}

action1Async += Func1;
action1Async += Func2;

//ここで、action1Asyncの完了をawaitしようとすると・・・
await action1Async();
Console.Write("3");
//"1"が出力されるより前に制御が返ってくるため、コンソール出力がこうなる
//>23
```

完了をawaitで待機しているはずなのに、なぜ完了前に制御が返ってきてしまうのでしょうか？

実は、よく考えてみると当然の動きだったりします。eventとawaitという便利な構文によって見えづらくなっているだけで、このコードはデリゲート1つ分の完了しか待機していません。ポイントは、eventをInvoke()した場合、全てのデリゲートの実行が終わった後に、「戻り値を1つだけ返す」という動作です。

このケースではFunc1とFunc2がasyncなので、「全てのデリゲートの実行が終わった」時点では、Taskを作成しただけであって処理は完了していません。返ってきたTask全ての完了を待つ必要があります。しかし、eventのInvokeは戻り値を1つしか返しません。つまり`await action1Async();`の部分を分解すると、次のようなコードになっていることになります。

```csharp
Task result = Func1();
result = Func2();
await result;
```


Func1が返したTaskは待機せずに放置されています。当然、そちらで例外が発生したとしてもcatchできません。

このように考えていくと当たり前なのですが、 `await action1Async();` という記法があまりにも正しそうに見えるので、うっかり見逃してしまいがちです。気をつけましょう・・・。