OmniAICreator/Qiita-1.07M huggingface dataset:
Python における内包表記

Pythonでの内包表記について学習したのでここに記録として残す。

Pythonの内包表記とは、簡潔にリストや辞書を作成することができる機能でコード文が短くメモリ処理を少なくすることができるかつ、可読性も高めることができる。

# 内包表記の種類

内包表記には、

リスト内包表記、辞書内包表記、集合内包表記、ジェネレータ式がある

# リスト内包表記
```Python:qiita.py
t = (1,2,3,4,5)

#通常処理
r = []
for i in t:   
    if i % 2 == 0:
        r.append(i)

print(r)
#内包表記

r = [i for i  in t if i % 2 == 0]   
print(r)

```
上記コードのように空のリストを作成して、タプルのt,t2をリストの中に格納して,偶数のみをリストに核の黄酒流処理を書くときに、for文でも処理を行えるが（#通常処理）、内包表記を行うと一文で書くことができる。
基本構文としては以下のようになる。
```Python:qiita.py

[式 for 変数 in イテラブル if 条件]
```
処理としては、r=[]に二つ目のiにfor文でtを順番に代入していき、そのiを２で割ったものの余りが０の時に一つ目のiに代入され、rのリストが完成する。

また、ネストした内包表記も行うことができる。

```Python:.py

t = (1,2,3,4,5)
t2 = (5,6,7,8,9,10)



for i in t:  #通常処理
    for j in t2:
        r.append(i*j)

print(r)

r = [ i * j  for i in t for j in t2 ]#内包表記

print(r)
```
この内包表この処理の場合、rの中のforから処理を行い、iにt,jにはt2をそれぞれ代入していく最終的にfor文手前の掛け算が行われ、出力としては、通常処理と同じものになる。

```.出力
[5, 6, 7, 8, 9, 10, 10, 12, 14, 16, 18, 20, 15, 18, 21, 24, 27, 30, 20, 24, 28, 32, 36, 40, 25, 30, 35, 40, 45, 50]
```
# 辞書内包表記

```Python:.dict
w = ["mon","tue","wed"]
f = ["coffee","milk","water"]

d = {}
for x , y in zip(w,f):
    d[x] = y
print(d)

d= {x:y for x,y in zip(w,f)}
print(d)

```
 空のリストdを作り、for文で繰り返し処理を行う場合、zip関数を用いて、変数wとfのペアをタプルで作る。その後forループでペアを一つずつ取り出し、xとyにそれぞれ代入していく、dの中のxをキー、yを値として、dの辞書をプリントする。

 内包表記では、キーと値のセットを作らなくても、x:yで認識され、for文で繰り返し処理を行いxとyにそれぞれw、fが代入され、キーと値の処理がされて出力される。

 ```Python:出力.
 {'mon': 'coffee', 'tue': 'milk', 'wed': 'water'}
 ```

 # 集合内包表記

 ```Python:set.
 s = set()

for i in range(10): #通常処理
    if i % 2 == 0:
        s.add(i)
print(s)
s={i for i in range(10) if i % 2 ==0} #内包表記
print(s)

```
set()とは重複のないデータを管理するデータ型である。
リストやタプルとは違い、同じデータを格納はできない。

add()は新しい要素を追加する関数でsetと組み合わせてよく使われる。
すでに存在する要素を追加してもその要素は無視される。

この処理は、forループで０から９までの数字をiに代入していき、偶数のみをadd()を使いs代入していく。
内包表記では、addを使わずに、sをset()と定義しているため、forループを描くことで、重複するデータを排除し、出力される。
最初に定義した、変数iを飛び越えて、for文から先に処理を行い、最終的な処理結果を、一番はじめの変数に要素が格納され、出力される。

```Python:出力.
{0, 2, 4, 6, 8}
```
# ジェネレーター内包表記
ジェネレーターとは、() を使ってジェネレーターオブジェクトを作成し、必要なときに1つずつ値を取り出せるのが特徴。リストやタプルと違い、要素全ての処理をせずnextやyieldで一つずつ処理をされるので、メモリ効率が良い。
試しにジェネレーターを書いてみる。

```Python:
def g():
    for i in range(10):
        yield i
g=g()
print(next(g))
```

```Python:出力.
0
```
iに９までの数字を格納したのちにyieldで一つずつ要素を取り出している処理を行い、変数gに格納する。
それをprintで呼び出し、nextで出力すると、一番はじめの要素0が取り出され出力される。

これを内包表記でやってみる。

```python:
g= (i for i in range(10)if i % 2 == 0)
print(type(g))
print(next(g))

for x in g :
    print(x)
```
タプルと間違えやすいためtypeを出力してある。
また、forループで全ての要素を最後に取り出しているため、後にnextで呼び出してもエラーになるため注意。

```Python:出力
<class 'generator'>
0
2
4
6
8
```
基本的に他の内包処理と書き方は同じだが、一度取り出した要素は使えないため、for文の後に要素を取り出そうとしても、取り出せない。

通常通りジェネレーターを書くときと違って、yieldを使い関数を定義しなくてもいい。

処理としては、forループで９までの数字をiに格納し偶数のみをiにTrueとして格納する。

print(next)で出力し０を出力。
その後、forループを使うと自動でnext()を呼び出しプログラムが終了する。

※タプルとして呼び出したい時はg＝の後にtupleと宣言する

# まとめ

リスト内包表記	[式 for 変数 in イテラブル if 条件]	list
辞書内包表記	{キー: 値 for 変数 in イテラブル if 条件}	dict
セット内包表記	{式 for 変数 in イテラブル if 条件}	set
ジェネレータ式	(式 for 変数 in イテラブル if 条件)	generator
C#でSpan<byte>の全ての要素が同じ値かを素早く判断する

# 結論
`IndexOfAnyExcept`を使えば速い
（追記：有り無しを調べるだけなら`ContainsAnyExcept`があるみたいです）

# 動機
`ReadOnlySpan<byte>`があったとして、その要素がすべて`0xff`かどうかを判断したかった。

# やってみたこと
## `foreach`を使う
一番シンプルなやり方は`foreach`を使うやり方。
```cs
public bool ForeachLoop()
{
    var span = data.AsSpan();
    foreach (var byteData in span)
    {
        if (byteData != 0xff)
        {
            return false;
        }
    }
    return true;
}
```

## `foreach`ではなくて`for`を使う
`foreach`を使わずに`for`を使ってインデックスで参照した場合
```cs
public bool ForLoop()
{
    var span = data.AsSpan();
    for (var i = 0; i < span.Length; i++)
    {
        if (span[i] != 0xff)
        {
            return false;
        }
    }
    return true;
}
```

## `IndexOfAnyExcept`を使う
この記事の本命。引数で与えられた数値**以外**のデータが見つかったらそのインデックスを返すという関数。見つからなかった場合は-1を返します。`MemoryExtensions`の中にあるみたいです。他にも便利そうなやつが色々定義されてました。
```cs
public bool IndexOfAnyExcept()
{
    var span = data.AsSpan();
    return span.IndexOfAnyExcept((byte)0xff) == -1;
}
```

# ベンチマーク
.NET 9でBenchmarkdotnetを使って計測してみました。32KBの大きさの全てが`0xff`バイト配列を渡してます。
```
// * Summary *

BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.3194)
Intel Core i5-14500, 1 CPU, 20 logical and 14 physical cores
.NET SDK 9.0.101
  [Host]     : .NET 9.0.0 (9.0.24.52809), X64 AOT AVX2
  DefaultJob : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2


| Method           | Mean       | Error    | StdDev   |
|----------------- |-----------:|---------:|---------:|
| ForeachLoop      | 9,071.5 ns | 93.23 ns | 82.64 ns |
| ForLoop          | 9,069.3 ns | 82.11 ns | 76.81 ns |
| IndexOfAnyExcept |   391.2 ns |  7.70 ns |  7.57 ns |

// * Hints *
Outliers
  Bench.ForeachLoop: Default      -> 1 outlier  was  removed (9.29 us)
  Bench.IndexOfAnyExcept: Default -> 1 outlier  was  removed (415.33 ns)

// * Legends *
  Mean   : Arithmetic mean of all measurements
  Error  : Half of 99.9% confidence interval
  StdDev : Standard deviation of all measurements
  1 ns   : 1 Nanosecond (0.000000001 sec)
```

`IndexOfAnyExcept`が圧倒的に速かったです。byte型でしか試していませんが、他の数値型でも速くなるのかな。
関数とは

### 関数の定義

以下の図のように```function()```と書き、その後ろの中括弧```{ }```の中にまとめたい処理を書くことで関数を用意することができます。
また、このように関数を用意することを```関数を定義する```と呼びますので覚えておきましょう。

<br>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514659/08972084-9e4d-444b-9907-9119ed6c0441.png)

### 関数の呼び出し

関数を定義しただけでは、その中の処理は実行されません。

図のように、関数を定義した際に使用した定数名を用いて、```定数名()```と書くことで関数の中の処理を実行できます。

このことを```関数を呼び出す```と言います。

まずは練習問題で、実際に関数を呼び出してイメージをつかんでみましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514659/3711da4d-2c5c-4c0c-a30f-ce7517a3acc8.png)

## 例題
今回の例題では、すでにgreetという名前の関数が定義されています。
まずはこの状態では何も処理が行われないことを確認してみましょう。

確認できたら、関数を呼び出す処理を追加してみましょう。
①```greet```を用いて、定義されている関数を呼び出してください。

もう一度コンソールを確認しましょう。
今回は関数の中の処理が実行され、文字が出力されたかと思います。

```javascript:qiita.js
const greet = function() {

    console.log("こんにちは！");
    
    console.log("関数を学習していきましょう！");
    
};

// 関数を呼び出してください
```

### 関数の代入
関数の定義を少し詳しく見てみましょう。
関数の定義で、実際に関数を表している部分は以下の図のオレンジ線で囲んだ部分です。
その関数を定数```introduce```に代入することで、関数を定義しています。
次は、関数の呼び出しだけでなく、関数の定義から書いてみましょう！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3514659/eb86a2e3-f844-4f4f-8d6d-f06bf9b43ab6.png)

## 例題
今回は自分で関数の定義から書いてみましょう。

①定数helloを定義し、関数を代入してください。
②関数の中でこんにちは！と出力してください。
③また、私の名前は○○ですと出力してください。（〇〇の部分はあなたの名前に変えてみてください。）
④定義した関数を呼び出してみましょう。

```javascript:qiita.js
// 定数helloに関数を代入してください

// 定数helloに代入された関数を呼び出してください
```
「No named parameter with the name 'primary'」エラーとその対処法

## はじめに　
今回は、個人開発で発生した、ElevatedButton.styleFrom メソッドで primary パラメータが使えなくなった場合のエラーについて詳しく解説します。

## エラーメッセージの内容
以下は、発生したエラーの例です。

```sql
lib/main.dart:898:27: Error: No named parameter with the name 'primary'.
                          primary:                          ^^^^^^^
```

このエラーは、`ElevatedButton.styleFrom` に`primary`という名前のパラメータが存在しないために発生します。

## エラーの原因
Flutter のアップデートにより、ボタンのスタイル設定で使われていた`primary`プロパティが廃止され、代わりに`backgroundColor`が導入されました。以前は以下のように記述していたコードが

```dart
ElevatedButton.styleFrom(
  primary: Colors.blue, // 旧プロパティ
)
```

新しいバージョンでは以下のように修正する必要があります
```dart
ElevatedButton.styleFrom(
  backgroundColor: Colors.blue, // 新プロパティ
)
```

## 対処法
1. コードの更新
primary を backgroundColor に置き換え、同様に onPrimary は foregroundColor に変更します。

2. Flutter のバージョン確認
プロジェクトの Flutter バージョンを確認し、最新の API ドキュメントを参照してください。

## まとめ
- Flutter の API は進化しているため、アップデート内容を常にチェックすることが大切
- エラーメッセージをよく読み、対応する新しいプロパティを適用することでエラーを解消できる
[win11]バッテリー駆動かAC駆動か確認したい

# きっかけ
電源接続中なのにバッテリーが減る場合があるので，まず状態を確認したい．
減る場合っていうのはこれ↓

https://qiita.com/hynn_nnn/items/ae28a6882ce282120f4e

# コマンド
PowerShellでコマンドを実行する．

    WMIC Path Win32_Battery Get BatteryStatus /Format:List
    
https://blog.matthewskelton.net/2009/12/29/wmic-command-line-control-of-wmi-functions/


# 表示結果
結果はこんな感じ

    BatteryStatus=2

# で，何？
数字だけ出されても意味わかんないよ～

https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-battery?redirectedfrom=MSDN

BatteryStatus

    Data type: uint16

    Access type: Read-only

    Qualifiers: MappingStrings ("MIF.DMTF|Portable Battery|002.14")

    Status of the battery. The value 10 (Undefined) is not valid in the CIM schema because in DMI it represents that no battery is installed. In this case, the object should not be instantiated.

    This property is inherited from CIM_Battery.

Other (1)

    The battery is discharging.

Unknown (2)

    The system has access to AC so no battery is being discharged. However, the battery is not necessarily charging.

Fully Charged (3)

Low (4)

Critical (5)

Charging (6)

Charging and High (7)

Charging and Low (8)

Charging and Critical (9)

Undefined (10)

Partially Charged (11)

# つまり？
BatteryStatusが
1：バッテリー駆動
2：AC駆動

# 実際の現象に対して
電源繋いでるのにバッテリー減る問題がまだ発生していないので，全く活かされていない
❗要検証❗
USBハブ繋いだら電気が足りてなさそうなんだが(検証した)

# ドッキングステーション/USBハブを買った

出力にUSB-AとHDMIとイヤホンジャックがある置き型ハブを求めて，サンワサプライの400-HUBC14BKを購入．ノートPCと家のモニター＆イヤホン＆周辺機器を繋ぎ直す手間がハブとの1本で済むようになって，その点は完全に満足だった．

https://direct.sanwa.co.jp/ItemPage/400-HUBC14BK

https://cdn.sanwa.co.jp/support/setsumeisyo/pdf/direct/400-HUBC14BK_ver1-0.pdf

## 残念ポイントがちょっとあった
モニターがDP Altモードに対応していて，このハブもPC接続のUSB type-CポートがDP Altモード対応なのでケーブル1本で接続できると期待していたが，さすがに無理だった．周辺機器接続用のポートはDP Alt非対応の模様．結局モニターはHDMIをハブに繋ぎ，電源を別のACアダプターから取ってくることになった．

もうひとつの残念ポイントが，機器をいくつも繋ぐと電力(電圧？)が足りなくなることだった．

# 全部繋ぐと充電が安定しない
バスパワーとはいえたくさん繋ぐと供給しきれないのか，スマホ2台同時給電は安定しなかった（接続は認識される）．この点は注意書きのとおりなので仕方ないが，さらにPCへの供給も足りないようで充電しているのにみるみるバッテリーが減っていく．また，機器に繋がっていないケーブルが刺さっている場合でもこの足りてなさそうな挙動になった．
電源はACアダプターの2口あるtype-Cから取っている．もう1つのポートに何にも繋がってないケーブルが刺さっている場合も足りてないようだった．
USBって機器が電気要求してなくてもケーブルが繋がってるだけで電気通ってるのか？ハードのこと知らなすぎｒ

環境は
* ハブにはPDで給電，最大60W
* ACアダプターは A1口・C2口合計65W，C2口は同時使用の場合45W+18W
* ノートPCは LIFEBOOK WU-X/H1
* 接続機器は iPhone 12 ProまたはiPhone XS Max・Xperia 1 II・Keychron V8 Max

どれもそんなに要求電力は大きくないと思う．iPhoneXSは18W，12は20W，XperiaはPD21Wが最大
V8Maxはわからなかった，チェッカーで調べる必要がありそう
PCの充電の仕様，これがいつ読んでもわからない．

    最大5V/1.5A給電です。USB Power Delivery対応機器への充電が可能です。7.5W（5V/1.5A）以上を供給可能な機器であれば、本体に充電が可能です。
    パソコンを使用しながら本体に充電する場合は、45W（20V/2.25A）以上を供給可能なものが必要です。ただし、すべての対応機器の動作を保証するものではありません。

最大5V/1.5A給電というのはこのPCから別の機器に給電する場合を指しているのか？それとも"最低"の誤植でようは7.5W必要ということ？
少なくともAC駆動＆バッテリー充電には45Wあれば足りるように読めるが，最大で何Wで駆動・何Wで充電するのかはわからない．

# チェッカーで調べる
実際の電力が見えないことには埒が明かないので電流電圧チェッカーで調べることにした．
❗チェッカー届いたら追記する❗
変なことになったので別記事立てました

https://qiita.com/hynn_nnn/items/14efe948ca8649e906b3

電力足りない問題が起きないし，AC駆動＆バッテリー充電しないはずの電力でも充電してるという話
nestjsでエンドポイントを叩かれたときにデータを受け取る(Query)

# @Queryの使い方
Todoという機能を作っている前提で書きます

### 目的
引数を一つ以上受け取りたい

### 本文
Queryをimportして、@getデコレータにくっつける関数の引数に、@Queryデコレータをくっつけるだけ。
以下のような形式で書く

```typescript
@Query('エンドポイントで受け取るときの名前') 引数の名前:引数の型
```
引数の型はデフォルトでstring。
型注釈つけるだけでは、string以外にはならない。パイプってのを使えばstring以外でも受け取れる。
(https://zenn.dev/toshinobu/articles/168666b2b1b1dc#%E6%9C%AC%E9%A1%8C%E3%81%AE%E5%95%8F%E9%A1%8C)
```typescript:todo.controller.ts
import {
  Controller,
  Get,
  Query, //@Query
} from '@nestjs/common';

@Controller('todo')
export class TodoController {
  constructor(private readonly prisma: CustomPrismaService) {}

   @Get('getTodos')
  async getTodos(
    @Query('done') done:boolean
    @Query('name') name:string
    @Query('importance') importance:number
  ){
  //ここに処理を書くとき、done,name,importanceが引数として使える
  }
```
エンドポイントはこんなかんじ(ローカル想定)
TRUE,lunch,3を渡したいとする。
```url
http://~~~~~:3000/todo/getTodos?done=TRUE&name=lunch&importance=3
```
30分記事＜2025/02/26＞　ポリモーフィックデー！！！

# 1.はじめに
・この記事は記載者の自己満足による物です。
・30分で完全に切り上げるために、完全に途中で切れても終わります！笑
（このはじめにを書くのは毎回テンプレとし、このコピペの時間帯は時間に入れないものとする。）
・間違えている可能性あり！！！あまりこの記事信用しないほうがいい気がする！笑

# 2.なんで始めようと思ったか？
・「時間がないから記事が書けない」を言い訳に書いていなかった自分を律するため
・「意味もない記事でもいいから30分で書いて、書く練習をしてみよう！そうすりゃアウトプットにもなる」と思ったため。

# 内容がなくともとにかく書こう。
・いいんですよ。中身すっからかんでも。練習になりゃぁ。

ってことで2025/2/19からスタート！！

# 30分アウトプット開始
ちょっと空いちゃった。30分記事以外に題名つけようかな。
夜中遅くまで勉強していて「明日やろう」とするとやっぱりできなくなってしまう。
夜1時だけどかいていこー！！
（けど進展がなかったりするとやっぱり書きづらいっていうのがあったり。。。）

今日はポリモーフィックデー！！
٩( ᐛ )وﾌｧ???と思うところが沢山あったけど、ひとまず復習がてら書いていこうと思う。

ひとまずポリモーフィックというのは…
一つの物体（記事）に対して、複数の物を紐づけようとする行為。。。といえばいいのかな。
まーーーじでわかり辛え(● ˃̶͈̀ロ˂̶͈́)੭ꠥ⁾⁾ｗｗ

モデルを書くと
```
class Article < ApplicationRecord
  has_many :article_blocks, -> { order(:level) }, inverse_of: :article
  has_many :sentences, through: :article_blocks, source: :blockable, source_type: 'Sentence'
  has_many :media, through: :article_blocks, source: :blockable, source_type: 'Medium'
  has_many :embeds, through: :article_blocks, source: :blockable, source_type: 'Embed'
```

 - 「Article」１：多「sentences」、「media」、「embeds」で関係があって、
 - 中間テーブルとして「article_blocks」がある。
 - 「source: :blockable」→blockableというテーブルが先がないけど、
　「article_blocks」テーブルの中に「blockable_id」「blockable_type」というカラムがつけられる。

<br>

 - 「blockable」テーブル自体は存在しないが、「article_blocks」という中に存在している「blockable_id」「blockable_type」によって仮想上のテーブルが作成されている？

…言っている事意味不明と言われても仕方ないじゃん。
テーブル検索しても無いし、ましてや以下モデルの「belongs_to :blockable」ってどこさしてんのよ！？ｗ

```
class ArticleBlock < ApplicationRecord
  belongs_to :article
  belongs_to :blockable, polymorphic: true, dependent: :destroy
```

・「Article_id」：「Blockable_id」で中間テーブルの多：多を表していて
　さらにそこに「Blockable_id」：「Blockable_type」　にする事で、多：多の多を表している？？

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3949025/67e09e84-f833-422e-b526-e60bf9e8c887.png)

ここで意味わからんようにしているのが

Sentences,Media,Embedsのモデルの存在。
こいつらのModelを見てみると
```
・class Sentence < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block
end

・class Medium < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block

  has_one_attached :attachment

  enum media_type: { image: 0 }

  validates :attachment, attachment: { purge: true, content_type: %r{\Aimage/(png|jpeg)\Z}, maximum: 10_485_760 }, if: :image?
end

#

・class Embed < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block

  enum embed_type: { youtube: 0 }

  validates :identifier, length: { maximum: 200 }
end
```

・・・全部「has_one :article」。。。だと？？？
articleでは「has_many」なのにどういうこっちゃワレェ！！！ｗｗ

かつ、頭がこんがらがってるから、

多：多のテーブルの場合だったら、（まあhas_oneだから違うけど。）
「Blockable_type」に「sentences」、「media」、「embeds」が入り
「Blockable_id」に上記3つのテーブルの情報がid=1からそれぞれ入る。と思いきや。

まず、「sentences」を3つ入れる
　「sentences」のid　→ 1−3
 「Blockable_type」→Sentence
 「Blockable_id」→1−3

 次に「embeds」を1つ入れるｓ
 「embeds」のid → 1
 「Blockable_type」→ Embed
 「Blockable_id」　→ 4

 ٩( ᐛ )وﾌｧｯｯｯ?????

まーーーじでどうゆう事っすかｗ
ひとまず。記事も出てないから人気ないという認識でいいのだろうか…笑

勉強は終わらないっっ＼＼\\٩( 'ω' )و //／／ｗ

本日は1分半残ってるとこだけど終了！
ではまたっ(● ˃̶͈̀ロ˂̶͈́)੭ꠥ⁾⁾！
【VSCode】僕のカスタムキーボードショートカット集

## 背景
キーボードショートカットをカスタムするようになったきっかけは、インターン先の上司がvimを使っていたことです。

「マウスとトラックパッドと矢印キーを使ったら負けだよ」と冗談混じりで話す様子に憧れて、vimmerになる中間段階としてVSCodeのキーボードショートカットを多く活用するようになりました。

結果、VSCodeでもキーボードオンリーで通常のコーディングくらいならできるようになったので、一部を紹介したいと思います。

## 私のカスタムキーボードショートカット集
| 動作 | ショートカットキー | アクション名 |
| --------------- | --- | ---------- |
| エディタ内のカーソル移動（上下左右） | ctrl + k / j / h / l | cursorUp/Down/Left/Right |
| 単語単位でカーソル移動（左右）| ctrl + cmd + h / l | cursorWordLeft/EndRight |
| エクスプローラー上での移動（上下）| ctrl + k / j | list.focusUp/Down |
| ファイル検索時の候補の選択（上下） | ctrl + k / j| workbench.action.quickOpenSelectNext/Previous |
| ファイルの一番上/下に移動 | ctrl + cmd + k / j | cursorTop/Down |
| ページアップ/ダウン | ctrl + u / d | cursorPageUp/Down |
| 行の先頭に移動 | ctrl + 4 | cursorHome |
| 行の終端に移動 | ctrl + ^ | cursorEnd |
| エディタ内の文字の選択（上下左右） | ctrl + shift + k / j / h / l | cursorUp/Down/Left/RightSelect |
| 現在から行の先頭まで選択 | ctrl + shift + 4 | cursorHomeSelect |
| 現在から行の終端まで選択 | ctrl + shift + ^ | cursorEndSelect | 
| 定義へ移動 | ctrl + Enter | editor.action.revealDefinition |
| 新しいディレクトリをエクスプローラー上に作成 | cmd + d | explorer.newFolder |
| 新しいファイルをエクスプローラー上に作成 | cmd + n | explorer.newFile |
| コメントアウト | ctrl + / | editor.action.commentLine |
| インデント（上げ下げ）| ctrl + [ / ] | editor.action.in/outdentLines |
| 保存済みのファイルタブを閉じる | ctrl + cmd + w | workbench.action.closeUnmodifiedEditors |
| 選択中の範囲を任意のタグで囲む | option + d | editor.emmet.action.wrapWithAbbreviation |
| 右のファイルタブに移動 | ctrl + , | workbench.action.nextEditor |
| 左のファイルタブに移動 | ctrl + m | workbench.action.previousEditor |
| キーボードショートカットの設定タブを開く | option + , | workbench.action.openGlobalKeybindings |

これに追加して、既存ショートカットの活用・削除することで、個人的にとてもスムーズにコーディングができています。

既存ショートカットの一覧は、以下が参考になりました。
[【Windows版】VS Code キーボードショートカット一覧 （オススメ付き）](https://qiita.com/TakahiRoyte/items/cdab6fca64da386a690b)
※とても綺麗にまとまっているものがwindows版しかなく、適宜読み替える必要あり


## 解説
移動系はほとんど常に`ctrl`キーを押している状態です。

vimっぽくいうなら、`ctrl`を押している間は`normal`モード、`ctrl`を離すと`insert`モードという感覚だと思います。

過去にvimの拡張機能を入れることも検討したのですが、`esc`や`i`, `:`を入力し分ける必要なく、押しやすい場所にある`ctrl`の押す押さないで移動を入力を切り替えられる現在の方が快適だと感じ、そこまで重いアプリケーションも扱っていないのでVSCodeを使い続けています。

個人的に、保存済みのタブを全て閉じるショートカットと、新しいディレクトリ/ファイルをエクスプローラー上に作成するショートカットはとても便利だなと思っています（デフォルトはおそらくボタンをポチポチしないとできない）。

## 最後に
トラックパッドとマウスを使わず、最低限のポジションチェンジだけでコーディングできると、思った以上に効率が上がるなと感じます。

一方で、頑張ってエディタを育てた分PCが変わった時にまた一から設定し直すようなことはしたくないので、設定のjsonファイルをバックアップする必要もあります。

最後に、私のVSCodeのキーボードショートカットが設定された`keybindings.json`を含めた`dotfiles`をgithub管理しているので、暇な方はご覧ください。
https://github.com/okki-0417/dotfiles


※.vimrcなどh人に見せられるほどのものではないと自覚しているので、ご覧いただく場合は温かい目でご覧ください
2DスプライトのNormal texture を作る

Unity URPの２Dパイプラインでは、法線付きスプライトを使用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/a121074f-927e-4b05-b3e1-e4d2c1e53e0b.png)

スプライトのSecondary Texturesに_MaskTex　と _NormalMapを用意することで、
同じマテリアルを複数のスプライトに適用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/00395b7c-a637-4bb0-abb9-d0d410dd3b58.png)

モデルのNormalMapはBlenderを使用することで作ることができるのですが、
<iframe width="560" height="315" src="https://www.youtube.com/embed/pMwOB8Hi6-8?si=EvHZD4vpz8iIhZHP&amp;start=458" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
ぶっちゃけ面倒ですよね。。

Unituのみで３DモデルからNormal画像を作成する場合、下記のようなShader Graphになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/2127aac6-4f66-4b68-acfa-165ca30d9179.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/5ca1deda-628c-4fe2-80eb-6d431e9326d1.png)

また、こちらのシェーダーを使用したNormal/Mask作成ツールをAssetStoreで販売しています。
NormalMapだけでなくMaskMapも簡単に作成することができます
<a href="https://assetstore.unity.com/packages/tools/utilities/modeltobump-171138"><img src="https://assetstorev1-prd-cdn.unity3d.com/package-screenshot/77ea4adc-d3d7-4edf-9ef2-112db1e64e8c.webp"></img></a>
rex0220 印刷屋プラグイン 見積書のCSSカスタマイズ

[rex0220 印刷屋プラグイン](https://qiita.com/rex0220/items/9be2d9b20a3a1f016c76) 見積書のCSSカスタマイズを行ってみます。

# 概要

サンプルの見積書は、シンプルなデザインですので少し CSS で装飾をしてみます。

- 見積明細部分のヘッダー部の色
- 明細部について偶数・奇数行で背景色を交互にして視認性アップ

![2025-02-27_00h23_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f2b78753-dbf4-4058-9b44-cf3c6776b4f6.png)

- CSS カスタマイズ前後の比較

![2025-02-27_00h10_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4ddf66cf-4e11-4534-9b35-fc6d51d0865f.png)


# CSS カスタマイズ

共通CSSは、そのままで個別CSSに CSSを設定します。
帳票には、共通CSS＋個別CSSが適用されますが、個別CSSの効果が優先されます。

![2025-02-27_00h13_37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/15009ae5-7bdc-4515-8a87-5442de8e6a84.png)

![2025-02-27_00h29_06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/befe40bf-2cbd-4772-af33-3cfae255323d.png)

見積明細部へのCSS適用内容

```css:
.pcraft-inv-item-table thead {
    background-color: #2c3e50;
    color: white;
}

.pcraft-inv-item-table th,
.pcraft-inv-item-table td {
    border: 1px solid #ddd;
}

.pcraft-inv-item-table tbody tr:nth-child(even) {
    background-color: #f2f2f2;
}
```
ヘルプデスク業務にて学んだこと②

こんにちは、水野です。
以前[こちら□](https://qiita.com/pesysyon/items/9a538fad8d3b83151202)でヘルプデスク業務にて学んだことを記載させていただいたのですが、
今回はそちらの続編を記載していこうかと思います。


## 否定をしない話し方
ユーザの方から「プリンター設定がうまくいかない」、「システムが正常に起動しない」などといったお問い合わせをよくいただくのですが、
８割方手順書通りに操作をしていないことがほとんどです。
#### 具体例
突然ですが「何度もプリンター設定しなおしているのですが、印刷ができないのでリモートで画面を見てもらえますか？」という問い合わせが来たとします。

原因は、ユーザが設定作業をする際、
項目Aを選択するべきであるところで、項目Bを選択してしまったため。
#### 案内例

- そちらの欄でAを選択されているのですがBを選択してください

- こちらでAを選択しそうになるのですが、ここはBを選択してください

別に特に違いはないと思う方のほうがほとんどだと思いますが、前者の場合、相手が焦っている・イラついている場合
結構な確率で相手のリアクションが悪くなることが多いです…

後者の方は、対応終わりに「お忙しいところ大変失礼しました～」と言っていただけることが多いんです。

## 結論
例で挙げた２通りの伝え方の違いは、【相手を否定したか】にあると思います。

単純に考えて自分の実施したこと、正しいと思ったことを否定されたら、少なくともいい気分はしないと思います。
むしろ共感的理解を示すことの重要性は、カウンセリングの勉強をする際必ず目にするくらい、相手の話を聞くうえで大切なことみたいです。

### 最後に
今回は自分がヘルプデスク業務の中で学んだこととして、相手を否定しない話し方について記載させていただきました。

あくまで一例であり、時と場合を選ぶかとは思うのですが
エンジニアの方も会議等で使えると思うので、ぜひ試していただけたらと思います。

以上、水野でした。
Windowsしか使ってこなかったエンジニアは今すぐLinuxをやれ　飛ぶぞ

# Windowsしか使ってこなかったエンジニアは今すぐLinuxをやれ

## 飛ぶ理由

![quiita1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166218/34d17e4f-2d2a-44ec-8f45-60a9bac87938.png)

## 飛び方

Windowsの場合はMSが提供してるWindows用Linuxを入れるのが一番楽。  
Microsoft Storeの一番先頭にあるUbuntu入れとけ。

https://apps.microsoft.com/detail/9PDXGNCFSCZV?hl=neutral&gl=JP&ocid=pdpshare

## とりあえず開く
インストールしてるからちょっと待てと出てくるので、大人しく待つとユーザー名を要求される。

![2025-02-26_23h24_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166218/b7843b08-111a-4b94-978e-dcd1c7538c3f.png)

ユーザー名を打ってもいいし、打たずに閉じてもOK。  
Ubuntuを開き直すとこの画面になる。  

![2025-02-26_23h24_45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166218/c58a40e2-1a16-4848-8d9d-ab120cfcc62f.png)
※画面スクショのためだけに22を入れていますが、最新版を入れた方が吉

## ひとまず開発作業をしたいフォルダーに行く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166218/556c6bc0-80d6-4905-871d-a7a707625237.png)
※ファイルシステム＝Linuxのデータ管理の仕組み

いつも使っているCドライブは```/mnt/c```にある。  
大好きなデスクトップは```/mnt/c/Users/{ユーザー名}/Desktop```だ。  
他、好きなフォルダーに行け。

## 試しにRedisを使ってみる

Redisのコミュニティエディションという無料版を使ってみることにする。  

https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/install-redis-on-windows/

こういうものは大抵WindowsOSでインストールしようとするとWSLのインストールから書かれている。  
おれ達はすでにインストール済みなので、Redisのインストールから開始できる。


```コマンド:Ubuntu：インストールコマンド
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list

sudo apt-get update
sudo apt-get install redis
```

公式サイトのコマンドを丸まるコピペして叩くとインストールが完了する。
なぜならコマンドプロンプトではなくUbuntuを使っているからだ。

```コマンド:Ubuntu：起動→確認コマンド
sudo service redis-server start
sudo systemctl status redis-server
```

起動すると起動できる。
可愛いね。

ちなみにsystemctlコマンドでサービスの起動（start）、状態確認（status）、停止（stop）などができる。
とりあえずcd（フォルダー移動）、ls（フォルダー内をリスト表示）の次くらいに覚えておくと便利。
sudoは管理者権限でコマンド実行するので、ドキュメント読んでついてたら一旦おまじない的に付けとけばOK。（オタク特有の早口）

## Ubuntuでうまくインストールできなかった時

だいたいはドキュメントと現行バージョンの齟齬か、どこにあるかわからないconfigファイルの設定違いでエラーが発生する。
ググるかAIにしぶとく聞くと何とかなることが多い。
ちなみにLinuxの設定ファイルは大抵```/etc/```に入っているので、まずそこから確認するのもあり。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166218/90054755-d78f-46f0-8ad9-12a2f445a9ed.png)

## まとめ
ここまで雑に書いたけど、Linuxを本やUdemyで体系的に学ぶとわかることが広がって本当に楽しくなるので、ちょっとずつでも慣れていくとQOE（クオリティ オブ エンジニアリング）が上がる。多分。

## sudo
あなたはシステム管理者から通常の講習を受けたはずです。
これは通常、以下の3点に要約されます:

    #1) 他人のプライバシーを尊重すること。
    #2) タイプする前に考えること。
    #3) 大いなる力には大いなる責任が伴うこと。

[sudo] [初心者] のパスワード:つよくなりてぇ~~~
Pythonで簡単に馬券投票を行う

## はじめに

機械学習の結果で自動的に馬券を買いたい時、ありますよね。私はありました。
各種言語での馬券投票をサポートする「IpatHelper.dll」を紹介します。

## [IpatHelper.dll](https://github.com/Mikimini9627/ipathelper_dll)について

C++で書かれたDLL（ダイナミック リンク ライブラリ）です。
DLLのソースコード自体は非公開なのですが、簡易的な関数仕様は[こちら](https://github.com/Mikimini9627/ipathelper_dll/blob/main/builds/%E9%96%A2%E6%95%B0%E4%BB%95%E6%A7%98%E6%9B%B8.md)に書かれています。

:::note warn
DLLの使用は自己責任でお願いします。
:::

今回はPythonでの使用例の紹介となりますが、その他プログラミング言語でも利用可能です。
動作を確認しているのは下記の5つです。

- [Python](https://github.com/Mikimini9627/ipathelper_dll/tree/main/sample_app/python)
- [C++](https://github.com/Mikimini9627/ipathelper_dll/tree/main/sample_app/cpp)
- [C#](https://github.com/Mikimini9627/ipathelper_dll/tree/main/sample_app/csharp)
- [Julia](https://github.com/Mikimini9627/ipathelper_dll/tree/main/sample_app/julia)
- [Java](https://github.com/Mikimini9627/ipathelper_dll/tree/main/sample_app/java)

## 利用方法

下記コマンドでインストールできます。
PyPiのページは[こちら](https://pypi.org/project/ipathelper/)。
```
pip install ipathelper
```

<details>
  <summary>コード全体</summary>

```
from ipathelper import *

def main():

    try:
        # モジュールのイニシャライズ
        returnValue = init()
        if returnValue == False:
            return

        # ログイン処理(各自自分のIDに変えてください)
        returnValue = login('********', '********', '****', '****')
        if (returnValue & 1) != 1:
            print("ログインに失敗しました。")
            return

        # 馬券購入用のインスタンス取得
        betData = ST_BET_DATA()
        returnValue = get_bet_instance(KAISAI_NAKAYAMA, 11, 2020, 12, 27,
                        HOUSHIKI_FORMATION, SHIKIBETSU_TRIO, 100, "1,9-2,3,13-7,3,8,10", betData)
        if (returnValue & 1) != 1:
            print("馬券購入情報の取得に失敗しました。")
            return

        # 馬券購入処理実行
        betDataList = (ST_BET_DATA * 1)()
        betDataList[0] = betData
        returnValue = bet(betDataList, 1, 0)
        if (returnValue & 1) != 1:
            print("馬券購入に失敗しました。")
            return

        # 馬券購入用のインスタンス取得(WIN5)
        betDataWin5 = ST_BET_DATA_WIN5()
        returnValue = get_bet_instance_win5(100, 2020, 12, 27, "1,14-9,13-12-2-1,1,3,5", betDataWin5)
        if (returnValue & 1) != 1:
            print("馬券購入情報(WIN5)の取得に失敗しました。")
            return

        # 馬券購入処理実行(WIN5)
        returnValue = bet_win5(betDataWin5, 0)
        if (returnValue & 1) != 1:
            print("馬券購入(WIN5)に失敗しました。")
            return

    finally:

        # ログアウト処理
        logout()

        # モジュールのファイナライズ
        uninit()

if __name__ == '__main__':
    main()
```

</details>


## 余談
IpatHelper.dll自体は約5年前から開発していました。
新人プログラマーだった自分にとって、プログラミングを学ばせてくれるいい教材でした。
サイトリニューアルや細かい仕様の変更に対応するのも今では楽しみの一つです。

そのうち[UMACAスマート](https://www.jra.go.jp/kouza/beginner/umaca/smart/)にも対応しようかなーと画策しています。
いつかコードサイニング証明書を購入して付与したいなあ。
atcoder_水色精進記録9_ABC245e

# Atcoder水色精進記録
ABC245
E - Wrapping Chocolate
https://atcoder.jp/contests/abc245/tasks/abc245_e

# アルゴリズム・データ構造
SortedList, SegmentTree, 尺取法

# 考察
とりあえずA,BとC,DをペアにしてA,Dをkeyにしてsortしておく
A,Cだけなら2分探索で実施できるが、B,Dはsortされていない状態

尺取法の考えでできないか？
A,Cはsortされているので、Aが入るCのindexは2分探索で求めることが出来る。
求めたindexより右側Cなら使ってOK。
二つ目のAではindexはさらに右側にずれるので、使える個数が減る。
使える個数が少ない状態から考えた方がわかりやすいので降順にsortして考える。
一つ目のAで求めたindexより左側なら使ってOK
二つ目のAではindexが右にずれる
IndexまでのDを覚えておいて、Bがギリギリ入るDを使うようにすればいける?

ギリギリ入るDはどうやって見つければ良い?
segtreeの構造でいけそう。
Segtreeでmax値を覚えておいて、有効indexの中でmax値がDを超えている小さい方に降りていくとどうなる？
使用したindexは0に書き換えを実施
→TLE..

C++ならSortedSetでいけそう。
pythonで探したらlibraryを発見

# 提出
https://atcoder.jp/contests/abc245/submissions/63172269

# 感想
SegmentTreeで座標圧縮での方法を思いつくべきだった。
圧縮したidxが使用できるカウントをSegmentTreeに覚えさせておくと、下限がlogNで求めることが可能。
Excelの名前の定義

# はじめに
テンプレートファイルを使ったExcel出力を行うことになりました。
テンプレートの変更を容易に行えるようセルに名前を付けてプログラムで指定しようと思います。

そこで、Excelの「名前の定義」について掘り下げてみます。

# 名前の定義の基本
名前の定義は範囲を「ブック」「シート」の2種類で指定することができます。
　ブック：Public変数
　シート：Private変数
のように考えるとイメージがしやすいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/945b8c47-0d68-4777-8568-0226246c594d.png)

範囲で指定したシートと参照範囲は同じシートにする必要はありません。
使い道は思いつきませんが…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/3662c72f-061e-459d-89ae-1857407145f4.png)


# 同じ名前の定義
同じ名前で定義するとエラーになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/30f074fc-7f0a-49c2-baa8-13483f5f8226.png" width=30%>　⇒　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/ae54b9fa-5d66-4aa4-a555-745a60a65cc5.png" width=50%>

シート範囲でも同じです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/6ac65d50-25a7-45ee-91e9-3b5e3989eec5.png" width=30%>　⇒　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/ae54b9fa-5d66-4aa4-a555-745a60a65cc5.png" width=50%>


範囲が異なれば同じ名前で定義することが出来ます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/9b90ca0b-807a-4c69-9227-eb086597a0d5.png)
※範囲がシート、ブック両方ある場合はシートが優先されます。


# シートのコピー

「Sheet1」をコピーします。
すると、ブック指定、シート指定の定義が共にシート指定の定義としてコピーされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/d9b82b26-65e9-4dec-b6dd-9549a903c758.png)

### :thinking: と言うことは…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/e16f5359-7610-4f26-9f8b-8188d9305da6.png)
このような指定をしたシートをコピーするとどうなるでしょうか。
↓
↓
↓
↓
↓
何やら、見たことあるダイアログが出ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/819a81bf-b998-47cb-aaec-a35d690b62c6.png)

##### 「はい」を選択
「はい」を選択するとシート指定の定義のみがコピーされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/777d7719-53ca-4efd-a33d-992441010f74.png)

##### 「いいえ」を選択
「いいえ」を選択すると名前の変更ダイアログが表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/96d8b755-fc85-4bc1-b65a-cfd8fbe1be70.png)
そして、ブック指定の定義が別名でブック指定の名前定義となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/4a51298e-9d89-4984-ab50-8423506aba71.png)


# おわりに
偶にこのダイアログが表示されることがありましたが、見なかったことにして右上の[×]で閉じていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3779420/819a81bf-b998-47cb-aaec-a35d690b62c6.png)
これからはダイアログの意味を理解したうえで、[×]で閉じようと思います。
【Git】追跡されていないファイルを削除する方法

`git clean`を使用すると追跡されていないファイルを削除できます。

https://git-scm.com/docs/git-clean

## ドライラン

`git clean`で削除対象となるファイルの一覧を確認したい場合には以下のコマンドを実行します。

```terminal
git clean -n
```

```terminal
$ git clean -n
Would remove img/iconFacebook.png
Would remove login.html
Would remove docs/README.md
```

## ファイルの削除

以下のコマンドでファイルを削除します。

```terminal
git clean -f
```

フォルダも含めて削除する場合には以下のように実行します。

```terminal
git clean -fd
```

## インタラクティブ

対話モードに入るには以下のコマンドを実行します。

```terminal
git clean -i
```

https://git-scm.com/docs/git-clean#_interactive_mode
PCからルーター経由で外部サーバーにデータ送信する際のIPパケットとフレームの構造

ネットワーク通信において、PCが外部のサーバーにデータを送信する際に、どのようにIPアドレスやMACアドレスが処理されるのかを学びました。ここでは、PCからルーターを経由して外部サーバーへデータが送信される過程を詳しく見ていきます。

## シナリオ
PC（IPアドレス: 192.168.1.10）が、外部サーバー（IPアドレス: 203.0.113.10）にHTTPリクエストを送信したいと考えています。このサーバーはPCのネットワーク外に存在するため、デフォルトゲートウェイ（ルーター）のIPアドレス（例えば、192.168.1.1）を宛先として設定します。

## ステップ1:アプリケーション層からトランスポート層へ
1.**アプリケーション層**で、HTTPリクエストが生成されます。
    ・送信したいターゲットがウェブサーバーなので、その情報はHTTPリクエスト内に含まれます。

2.**トランスポート層**で、TCPセグメントが作成され、送信元ポートと宛先ポート（例えば、HTTPのポート80）などが設定されます。

## ステップ2:ネットワーク層で宛先IP設定
3.**ネットワーク層**では、作成されたTCPセグメントにIPヘッダが追加されます。ここで、**宛先IPアドレス**が設定されます。
    ・送信したいターゲットは、203.0.113.10ですが、PCは自分のネットワーク外にデータを送信するため、**宛先IPアドレス**として**デフォルトゲートウェイのIPアドレス（192.168.1.1）**が設定されます。
    ・ここで、**元々のターゲットIP（203.0.113.10）**はIPヘッダに含まれませんが、**TCPセグメント内**のデータ部には保持されています。

## ステップ3:データリンク層でフレーム作成
4.**データリンク層**では、IPパケット（ネットワーク層）の中身をフレームとして作成します。フレームには、送信元と宛先のMACアドレスが設定されます。
    ・宛先MACアドレスは、**デフォルトゲートウェイのMACアドレス**に設定されます（例えば、192.168.1.1のMACアドレス）。
    ・そのため、フレームの中には、デフォルトゲートウェイのMACアドレスが宛先MACとして設定され、**IPパケット**（ペイロード）の中に元々送信したいターゲットのIPアドレス（203.0.113.10）が保持されています。

## ステップ4:ルーターによる処理
5.ルーターがフレームを受け取ると、まず**MACアドレス**を確認し、データリンク層のフレームを解読します。次に、ネットワーク層のIPパケットを取り出します。

6.ルーターは、受け取った**IPパケット**の宛先IPアドレス（デフォルトゲートウェイのIPアドレス: 192.168.1.1）を確認し、それが自分の宛先であることを認識します。

7.ルーターは、元々のターゲット（203.0.113.10）を保持している**TCPセグメント**（IPパケットのペイロード）を解釈し、適切なルーティングテーブルを参照して、目的のウェブサーバーに向けて新しいフレームを作成します。

## ステップ5:最終転送
8.ルーターは最終的に、宛先のウェブサーバー（203.0.113.10）に向けて新しいIPパケットを送信します。ここでは、IPパケット内の**宛先IPアドレス**は203.0.113.10に設定されます。

## まとめ
・フレームの中に保持されるのは、元々のターゲットIP（203.0.113.10）ではなく、デフォルトゲートウェイのIPアドレス（192.168.1.1）がネットワーク層の宛先として設定されます。

・その後、ルーターがフレームを受け取ると、元々のターゲットIPアドレス（203.0.113.10）はTCPセグメント内に保持されているので、それを利用して次の転送先を決定します。
LogoMateとは

LogoMateとは
LogoMate（https://www.ailogogenerator.sh/）は、デザイン経験がないユーザーでもプロレベルのブランドロゴを簡単に作れる、革新的なAIロゴ生成プラットフォームです。

解決したい課題
一般ユーザー（AI分野に詳しくない各業界のほとんどの人）がAIGCを使う際、プロンプトをうまく書けないことが最大のハードルです。特に画像生成では、良い結果を得るには専門的な語彙と正確な記述が必要で、そのハードルは結構高いです。

ターゲットユーザー
セルフメディアのブロガー、バンドプロデューサー、インディーズ開発者、一般商店主、スタートアップ創業者、フリーランサー、マーケティング担当者など、誰でもLogoMateを使えば、プロのブランドロゴを素早く手に入れられます。
![Screen Shot 2025-02-23 at 12.03.50 AM(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4022199/d450719c-f2a5-44fa-8d80-506b88be9e37.png)

競合との違い
テンプレート化を導入し、ユーザーのハードルを大幅に下げました。複雑なプロンプト技術がなくても、アイデアをロゴに変えられます。テンプレートはデザイナーのプロの審美眼で選ばれており、視覚的な重複がなく、競合の単純な組み合わせロゴよりずっと洗練されています。
![Screen Shot 2025-02-25 at 11.56.10 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4022199/2dfd5545-f667-4ca7-8892-47e33ea3cfb4.png)

主な機能
業界テンプレートライブラリ：飲食店、カフェ、バンド、ウェディング、ゲーム、SNS、テクノロジーなど、多様な業界向けテンプレートがあり、さまざまなビジネスシーンに対応します。
簡単な作成プロセス：ブランド名と簡単な説明を入力するだけで、複雑な指示は不要です。
スマート生成：ブランド業界の知識に基づいてAIモデルを調整し、業界基準に合った高品質なロゴを自動生成します。
コミュニティ展示：UGCモジュールを統合し、ユーザーの作品を展示して創作のインスピレーションを提供します。
特徴
デザインのハードルを下げる：プロが作ったテンプレートで、デザイン初心者でも優れたロゴを作成可能。
高品質な出力：生成されたロゴはプロの基準を満たし、色彩の調和と構図のバランスが取れています。
効率重視：テンプレート選択から完成まで、シンプルでスピーディな流程です。
パーソナライズ対応：プロ品質を保ちつつ、ユーザーの入力でブランドの個性を反映します。
プラットフォーム
LogoMateはウェブアプリで、https://www.ailogogenerator.sh/ にアクセスすれば使えます。デスクトップPC、ノートパソコン、タブレット、スマートフォンなど、さまざまなデバイスに対応しています。

価格
無料枠を提供しており、どのテンプレートも試せます。さらなる枠や商用利用の著作権が必要な場合は有料で取得可能です。
ファイルがどこで使用されているかつながりを可視化するツールを作ってみた

# ファイルがどこで使用されているかつながりを可視化するツールを作ってみた
## 概要
### 開発理由
プロジェクトでファイル数が増えてくると、どこで呼び出されているかを追っていくのが億劫になるのでそれを一瞬で解決できるようなものがほしくAIと共に作ってみました。

### Repree
React Dependencies Treeをもじったのが由来

### トップ画像
![repree-top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865740/a4010084-4df3-4b99-90af-f033d98cb281.png)

### サイトURL

https://repree.net

### Githubリポジトリ

https://github.com/mitate-gengaku/Repree

コード汚い・page.tsxにべた書きはお許しください。

## 機能・画面
`js・ts・jsx・tsx`を抽出します。

### サイドバー
サイドバーにはファイルの各種情報が表示されます。accordionコンポーネントを使用することで見たいファイルの情報のみ見れるようにしました。
![repree-sidebar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865740/ea37b4eb-25a6-433a-847d-393aec927bd0.png)

### ノードの選択時
ノードを選択すると選択されていることがわかるように色付きborder, アニメーションのある接続エッジを表示するようにしました。以下のサイトに感化されてオプションの意味とか調べながら何とか実装できました。

https://liambx.com

![repree-select-highlight.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865740/0a4993f7-6be3-4c38-872c-736b5f492a94.gif)

### 関係のあるノードのみ表示
ノードを選択した状態で👁ボタンをクリックすると、選択したノードとつながっているノードのみ表示することができます。つながっている全階層の全ノードを可視化することができます。
![repree-related.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865740/da50c459-131b-4f5d-b9cc-82d9cbd904eb.gif)

### ダークモード
もうおなじみのダークモード。`next-theme`を使用することでさくっと実装可能。

![repree-darkmode.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865740/3e9887f3-e5b0-4104-a236-51c4722bc9f3.gif)

### アップデート
1. node_modulesも表示できるようになりました

![f8dd6ba40bf4450c05d28198a9cb5132.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3865740/5d076d48-85b9-4f05-9af8-9c30ee2daa53.gif)


### 今後の展望
現在はファイルのみつながりを表示するようになっているので、`node_modules`から呼び出したモジュールも対象にできればいいなと思ってます。

## 最後に
改善点、感想などをお教え頂ければ幸いです。よろしくお願いいたします。
mod_rewriteのリダイレクト設定を試して学んだこと

## はじめに
業務の中で、特定のページを別のURLにリダイレクトする必要があり、mod_rewrite の動作を実際に試しながら学びました。本記事では、その備忘録として`mod_rewrite`の基本的な使い方と、設定時につまづいたポイントと解決方法について紹介します。

なお、今回は以下のようなリダイレクトを設定しようと考えていました。
- `https://dev.hogehoge.jp/old-path`にアクセスがあった場合、
`https://test-app.example.com/new-path`にリダイレクトする

## 1. mod_rewriteとは？
### 1. 概要
`mod_rewrite`はApacheに標準で搭載されているモジュールの一つで、リクエストされたURLを動的に書き換えたり、特定の条件に基づいてリダイレクトを行うことができます。

### 2. 基本構文
#### RewriteEngine On：
- `mod_rewrite`を使用するには、まず`.htaccess`に`RewriteEngine On`を記述して、機能を有効にする必要があります。
- この設定を .htaccess の先頭に記述しないと、`RewriteRule`などのルールが適用されません。
```apache
RewriteEngine On
```

#### RewriteRule：

- `RewriteRule`を使うことで、指定したパターンのURLを別のURLにリダイレクトできます。

```apache
RewriteRule パターン 置換先 [オプション]
```

##### 例：特定のページをリダイレクト
```apache
RewriteEngine On
RewriteRule ^old-page$ /new-page [R=301,L]
```

- この設定では、`example.com/old-page`へアクセスすると`example.com/new-page`に301リダイレクトされます。

  -  `[R=301]`：301リダイレクト（恒久的なリダイレクト）
  -  `[L]`　　 ：このルールで処理を終了（Last）

#### RewriteCond：

- `RewriteCond`は `RewriteRule`を適用するための条件を設定する際に使用します。

##### 例：HTTPからHTTPSへリダイレクト
```apache
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
```

- `%{HTTPS} off` で、HTTPSではないリクエストを検出
- その場合、HTTPSへリダイレクト

#### `<IfModule>`：

- `mod_rewrite` がサーバーで有効になっているかを確認するために、`<IfModule>` を使用できます。
- この記述を `.htaccess` に入れることで、`mod_rewrite` が無効の場合でもエラーを回避できます。

```apache
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^old-page$ /new-page [R=301,L]
</IfModule>
```

## 2. よく使う `mod_rewrite` の設定
- 私が今回やりたかったことに加え、他にも色々な設定があるようだったので、よく使いそうなものを備忘がてら記載します。

### 1. HTTP → HTTPS のリダイレクト
```apache
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
```

### 2. `www` なしのURLを `www` ありに統一
```apache
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
```

### 3. 特定のディレクトリをリダイレクト
```apache
RewriteEngine On
RewriteRule ^old-folder/(.*)$ /new-folder/$1 [R=301,L]
```

## 3. 実際につまづいたポイント

#### 問題：リダイレクトが適用されず、意図した動作にならなかった
- 既存の設定ファイルにリダイレクトの設定を追加した際に、正しく動作しないという問題が発生しました。
- 具体的には`.htaccess` にリダイレクト設定を記述したところ、404エラーが発生しリダイレクトできずに躓いていました。


#### 原因
- `ProxyPreserveHost On`やその他の設定値の後に`RewriteRule`を記述していたため、意図したリダイレクトが機能しなかった。
- `.htaccess`や設定ファイルに追記する際は、どこに書いても良いわけではなく、設定の順番が動作に影響を与えることを理解していなかった。
- `RewriteEngine On`の記述位置も重要で、適切な場所に書かないと`mod_rewrite`が有効にならない。



#### 誤った記述
```apache
RewriteEngine On
ProxyPreserveHost On
# その他の設定値
RewriteCond %{HTTP_HOST} ^example\.com$
RewriteRule ^/old-path$ https://example-storage.test-server.com/new-path [R=301,L]
```
→ `ProxyPreserveHost On`やその他の設定が`RewriteRule`より先に書かれていたため、リダイレクトが正しく動作しなかった。

#### 正しい記述
```apache
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$
RewriteRule ^/old-path$ https://example-storage.test-server.com/new-path [R=301,L]

ProxyPreserveHost On
# その他の設定値
```
→ `RewriteEngine On`を先に記述し、`ProxyPreserveHost On`などの設定を後ろに移動したことで、期待通りの動作になった。

## まとめ
今回、初めてサーバーのリダイレクト設定を行い、普段あまり意識していなかった`mod_rewrite`の仕組みについて学ぶことができました。

かなり初歩的なところに躓いてしまいましたが、既存の設定ファイルに追記する場合、どこに書くかが非常に重要であり、記述の順番や他の設定との関係を考慮することが必要だと学ぶことができました。
将来の不安に襲われた駆け出しエンジニアが"武器"を見つけにいく話

Qiitaでの記事作成は1本目となります。
nagiと申します。

# 私について
### これまでの経歴
新卒は公務員
→1年弱で退職後、スクールを経てWebデザイナーに転職(SES1年→Web制作会社2年)

1年前の転職を機にフロントエンドエンジニアへ転身し、現在はWeb制作/開発の中間の企業でフロントエンドやコーディングに携わっています。

### 現在の状況
今の会社に入社してから半年強のうちに携わった主な業務です。
* デザインソフトを用いたWebコンテンツの実装、クリエィティブコーディング
* Webサイト(LP)のコーディング
* CMS関連の運用・保守業務

様々な経験を積ませていただいている一方で、他のエンジニアのスキルセットや業務内容を見ていると「このままで自分のキャリアは大丈夫なのだろうか」という不安に襲われてくることがありました。

また、「技術レベルに合わせて社内タスクを振る」方針の会社のため、スキルを上げないと社内でもやれることの幅が広がらない状況と感じています。


## 勉強しないと...。でもどうやって？何を？
1年近くエンジニアとして勤務してきて、現状のスキルの低さに思い悩む日々が続いております。その不安を解消するためには勉強するしかありません。

帰りの時間を使って技術書を読んだり、Udemyを見たり、プログラミング系のWebサービスを使ってコードを書いてみたりもしました。
しかし、半年間で「知識」は身についても「技術」は身についている実感がありませんでした。

同時に「何をすればいいか」も見失っている部分もありました。
フロントエンドエンジニアとして求められる技術の領域が膨大すぎてどこから手をつければいいかわからなくなっていたからです。


## 「何をすべきか」の軸を定めたい
勉強しなくてはいけない焦りはある、でも何をすればいいかわからない。

暗中模索を繰り返した際に**JISOU**のサービスと代表の方の記事に出会いました。
記事を読んでいくたびに、"これをすればいい"というロードマップの軸が少しずつ見えてきました。

フロントエンドエンジニアとして活躍できる場所を広げるためには、現代フロントエンドで使用頻度の高いReactの習得が一番の軸になると感じました。


## なぜやるのか/今後の目標
これからReact学習をはじめる目的は2つあります。

1つ目は**今後フロントエンドエンジニアとして羽ばたくための武器が欲しいため**です。
今後のキャリアを考えた時にReactとその周辺分野の知識の有無はキャリア形成に大きく関わってくると感じています。エンジニア人生を実りあるものにするためにも習得したいです。

2つ目は**自分の作りたいものを作れるようにするため**です。
何となく「アプリを自作できるようになりたい」という思いを胸の内に秘めており、React習得により個人開発ができるようになれば仕事だけでなく人生の実りも増やせると感じたためです。

### 目標
#### 短期
* React内で自分の作りたいものを作れるようになる
* 学習習慣を継続させる

#### 中期
* React以外の周辺分野の技術も使いこなせるようにする
* 「どんなものを作りたいか」「何を作れば役に立つか」を明確化・具現化させる

#### 長期
* Reactや周辺スキルを実務で活かし、社内外で携われる業務や案件の幅を広げる
* フロントエンドエンジニアとして長く活躍できる人材になる


これから頑張っていきたいと思います。
よろしくお願いします！
Cloudflare Pages + pnpm で Internal Error: Cannot find matching keyid に遭遇したときの解決法

## エラーの内容

pnpm プロジェクトを Cloudflare Pages にデプロイしようとしたらエラーに遭遇した。

![Screenshot 2025-02-26 at 22.28.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3816889/90956157-1fc0-4a3f-9e31-a9e835707458.png)

> Preparing pnpm@10.5.0 for immediate activation…
> Internal Error: Cannot find matching keyid: {"signatures":
> ...

wrangler.toml で node.js v22 以上、pnpm v10 以上を指定していた:

```toml
NODE_VERSION = ">=22"
PNPM_VERSION = ">=10"
```

デプロイ時に指定されたバージョンはこれ。

> Detected the following tools from environment: nodejs@22.8.0, pnpm@10.5.0
> 

## 回避策

調べてみると、原因は corepack が新しいバージョンのパッケージマネージャーの署名キーIDを検証できず、エラーになっているということだった。

回避方法として corepack v0.31.0 を使う方法があり、それには nodejs v23.7.0 以上を使う必要がある。

そこで wrangler.toml を `NODE_VERSION = ">=23"` のように変更し、再度デプロイしたところ、nodejs v23.8.0 がインストールされた:

> Detected the following tools from environment: nodejs@23.8.0, pnpm@10.5.0
> 

そして無事デプロイが通った。

## まとめ

この問題は Cloudflare Pages へのデプロイ時に遭遇したものだが、corepack と pnpm を使っている環境なら、他の状況でも遭遇する可能性がある。

同様のエラーに遭遇した方の参考になれば幸いだ。

## 参考

- [Newly published versions of package managers distributed from npm cannot be installed due to key id mismatch #612](https://github.com/nodejs/corepack/issues/612)
- [Corepack and pnpm@10.2.0 failing on build](https://answers.netlify.com/t/corepack-and-pnpm-10-2-0-failing-on-build/138964/5)
Google Colab の Spark にて Hadoop Catalog の Apache Iceberg の動作検証

## 概要

Google Colab の Spark にて Hadoop Catalog の Apache Iceberg の動作検証をした結果を共有します。 Valinlla Spark にて Apache Iceberg を動作させたかっため本検証を実施しました。

## 検証結果

### Spark のバージョンを確認

```bash
!pyspark --version
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/dd58b0d2-9fd7-4597-a57f-378ac2c016c3.png)


### SparkSession を定義

Spark のバージョンに応じて`spark.jars.packages`で指定するライブラリのバージョンを変更する必要あり。

```python
from pyspark.sql import SparkSession

spark = (SparkSession.builder
    .appName("IcebergExample")
    .config("spark.jars.packages", "org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.8.0")
    .config("spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions")
    .config("spark.sql.catalog.spark_catalog", "org.apache.iceberg.spark.SparkCatalog")
    .config("spark.sql.catalog.spark_catalog.type", "hadoop")
    .config("spark.sql.catalog.spark_catalog.warehouse", "/iceberg")
    .getOrCreate()
)
spark
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/eb68f60c-f42a-49fb-aab3-dfe6d612b511.png)

### Namespace を作成

```python
spark.sql("CREATE NAMESPACE IF NOT EXISTS  iceberf_gc ;")
```

```python
spark.sql("SHOW NAMESPACES").show()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/823d4341-285b-4a9b-b0b9-1e5bac1864d8.png)

### テーブルを作成

```python
spark.sql("""
CREATE OR REPLACE TABLE iceberf_gc.first_table (
  id INT,
  name STRING
)
USING iceberg
;""")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/a8c88770-c450-4200-a5d1-445c0b975d1b.png)


### テーブルにデータを書き込み

```python
data = [(1, "Alice"), (2, "Bob"), (3, "Charlie")]
columns = ["id", "name"]

df = spark.createDataFrame(data, columns)
display(df.toPandas())
```

```python
df.write.mode("overwrite").format("iceberg").saveAsTable("iceberf_gc.first_table")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/dd9fe795-e135-41d6-a5ca-c0bc62d60e28.png)

### テーブルのデータを確認

```python
display(spark.table("iceberf_gc.first_table").toPandas())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/f4cf9c0f-c772-4417-97be-58c1e9fe4197.png)


### テーブルの snapshots の確認

```python
display(spark.table("iceberf_gc.first_table.snapshots").toPandas())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/e0700a16-fb0e-4191-a6da-e1dec9099dea.png)

### ストアードプロシージャ（Comapaction）の実施

```python
res_df = spark.sql("CALL spark_catalog.system.rewrite_data_files('spark_catalog.iceberf_gc.first_table')")
display(res_df.toPandas())
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/20178a54-37a8-43f7-a81e-fa26eaccc24c.png)
react-hook-formのhandleSubmitとその後のrouter.pushがうまく働かなかった時

## 事象
**以下のコードで期待していた挙動が起こらずに困っていた**

🧐 **期待していた挙動**
1. react-hook-formの`handleSubmit`を使って、フォームのデータを取得
2. フォームのデータを使って、データベースに値を保存
3. 叩いたレスポンスのidを使って、`router.push`を使って、ページ遷移

❌ **実際の挙動**
1. react-hook-formの`handleSubmit`を使って、フォームのデータを取得ができた
2. データベースに値が保存されない
3. ページ遷移はされずに、同じページが表示されつづけ、URLにはフォームデータがクエリパラメータとして渡されている

```typescript

const OnSubmit = () => {
    handleSubmit((data)=>{
        何かのAPI(data).then(res=>{
            router.push(`/${res.id}`)
        })
    })
}

<form onSubmit={OnSubmit}>
    <input type="text" vale="name" ...register("name")/>
    <button type="submit">submit</button>
</form>
```

## 問題点

#### 1. `<form>`タグを使用した時に起こるブラウザのデフォルト機能

- `<form>`タグの`onSubmit`は、ブラウザはデフォルトの動作としてフォームを送信し、ページをリロードする
- この時、フォームのデータは URL のクエリパラメータとしてエンコードされ、送信される
- これが、URLにフォームデータが表示され、ページ遷移が行われない「実際の挙動の③」の原因

#### 2. react-hook-formの`handleSubmit`の返り値の仕様

- handleSubmitは、引数で関数を受け取り、さらにその処理を走らせる新たな関数を返り値として返す
- そのため、返された関数に対して()で実行命令を与えることで、関数が呼ばれるようになる

## 解決策
- `handleSubmit(function)`でOnSubmitを囲ってあげる（2に関する問題の解決）
- また、`handleSubmit(function)`を使うことで、フォームのデフォルト動作がキャンセルされる（1に関する問題も同時に解決する）（event.preventDefault()と同じ効果）

```typescript

const onSubmit = () => { 
    何かのAPI(data).then(res=>{
        router.push(`/${res.id}`)
    })
}

<form onSubmit={handleSubmit(onSubmit())}> ///eventを引数に
    <input type="text" vale="name" ...register("name")/>
    <button type="submit">submit</button>
</form>
```

## 参考
https://qiita.com/zksytmkn/items/ff3c454a905e81100ec6

https://qiita.com/tky8522/items/e07b85a436279ae19df5
Reactのbuildについて学ぶ　～webpack～

# 目的
webpackを用いたbuildで何が起こっているのかをざっくり理解する


## webpackとは？
webpackはモジュールバンドラの一種

:::note
バンドラ
ファイル間の依存関係を解決しながら、複数のjsxファイル（モジュール）等を結合することでWEBリソースを最適化する
一般的にはバンドル処理を行うことでページの読み込み速度向上が見込める
:::

また、単純なページ読み込み速度向上だけではなく様々な最適化処理を行ってくれる。

・静的解析
・トランスパイル
・Minify処理
・ツリーシェイキング
・難読化


### 静的解析
コード上のベストプラクティスに沿ってない記述などを警告してくれる機能

例えば

a == b　を　a === b　にしなさい
や
関数名がキャメルケースになってない
や
関数ｈ一度に渡す引数が多すぎる(20個とか)
など


この静的解析をクリアできないとビルドが行えないことがある
（現にgithub Actions上ではデフォルトだと却下されてしまった）

最低限のコードの質が担保される上にチーム内での記述に統一感が出るのでしっかりと静的解析はクリアすべきか。


### トランスパイル
開発においては一つの言語の特定のバージョンで開発を進めていくのが一般的。
しかし、最新バージョンでもすべてのブラウザ等で互換性があるとは限らない。
最新の言語機能を使ったが、全然動いてくれない。。。など

最新のJavascript(ES6)やTypescriptなどを広範なブラウザ互換性を持つ古いバージョンのJavascriptに変換してくれる機能がトランスパイル。
最新の言語機能を使用してもある程度、古いバージョンと互換性のあるコードに変換してくれるので動作保証性を向上してくれます。（どこまで担保されるかはわからん。。。）


### Minify処理
コードの無駄な箇所を取り除いてファイルサイズを小さくしてくれる機能

・無駄な改行の削除
・コメントの削除
・変数名をa,bなど簡略にする（マングリング）


また、Minify処理の際には難読化も同時に行われる
この難読化はbuildファイルと同じ階層のSourceMapファイルで復元可能
ただし、コードが復元可能で生で読める状態で提供するとコード上の脆弱性の特定が容易になってしまうために基本的にNG

SourceMapはクライアント側からアクセスできない箇所に保管するなどして難読化を解除できないようにするのが理想

参考にさせていただいたサイト：Fintan様
>https://fintan.jp/page/1596/


### ツリーシェイキング
利用されていない不要なコード（デッドコード）を取り除いてくれる機能
自分も使ったことないし、理解できていない


### 難読化
ソースコード自体を一般ユーザ側から簡単には読めない形にすること

難読化を行うメリットは以下の通り

・ソースコードのコピーなどによる製品/仕様の流用を防ぐ
　⇒特に重要なアルゴリズムなどが含まれているコードの場合はその部分がコピー/解析されると大きな損害となるので難読化の重要性が高まる

・ソースコードの脆弱性の特定を困難にする
　⇒ソースコードが生で閲覧できると、脆弱性の特定が容易になる


難読化の強度はおいておいて、難読化自体は行うべきだと思われる
ただし、世に出回ってる難読化ツールによる難読化はすぐ解読されるケースも
AWS LambdaとEventBridgeを使ってDiscordに画像を送ってみた

背景
====

「毎日なにかを定期的に行ってくれる仕組みを作ってみたい」ということで、
AWS LambdaとEventBridge画像送信アプリを作ることにしました。

画像は「[Lorem Picsum](https://picsum.photos/)」を使わせてもらっています。

概要
====
- AWS LambdaとEventBridgeで毎日送信する
    - 日に一度動けばよかったので、サーバーを借りるより安価な上記２つを使います

- Discord webhookを使う
    - ウェブクライアントの代わりです

コード
====

```python3
import os
import urllib.request
from discordwebhook import Discord

def lambda_handler(event, context):
    target_url = os.environ.get('discordUrl')

    with urllib.request.urlopen('https://picsum.photos/300/300') as req:
        data = req.read()

        discord = Discord(url=target_url)
        response = discord.post(
          content="おはよう、今日の写真はこれ。",
          file={
            "test.png": data 
          }
        )
```

デプロイ
===

aws consoleから、LambdaとEventBridgeをよしなに設定します。

結果
===
想定した通り、Discordの特定チャンネルに画像が毎朝届くようになりました。

ちょっと脇道
===

「Lorem Picsum」へのリクエストを見てみる
---

さて、今回使用した「Lorem Picsum」へのリクエストを見てみると、以下の動きを見せました。

1. 「https://picsum.photos/300/300」にGETリクエスト
1. 「302 Found」のレスポンスと`https://fastly.picsum.photos/id/xxx/~~~` への「Location」を受け取る
1. `https://fastly.picsum.photos/id/xxx/~~~` というLocationにGETリクエスト
1. 「200 OK」のレスポンスと「画像データ」を受け取る

どうやら「picsum.photos」のドメイン直下に画像の本体は存在せず、[fastly](https://www.fastly.com/jp/)というサービスを介して画像を配信しているようですね。
不特定多数のリクエストをさばく意思が感じられます。
「Lorem Picsum」のインフラ代はどこから来ているんでしょうね。

まとめ
====

検証と実装で3時間くらいでした。
AWS LambdaとEventBridgeを使えば、サクッと作れていいですね。
このツール自体に大きな価値はないですが、きれいな写真が送られてきたときはちょっと気分がよくなりました。