OmniAICreator/Qiita-1.07M huggingface dataset:
ウェブサイト作成用備忘録・１６号：スマホのソフトウェアキーボードとOrbitControls.jsの不具合の解消

今回は自主課題の作成中に起きた問題を自分なりに解決する為に考えた内容について記録に残しておきたいと思います。

####問題：three.jsにOrbitControls.jsを適用して、canvasタグ内で自由にカメラ操作が可能な状態で、HTMLにinputタグやテキストボックスに文字を入力する際、スマートフォンの場合はソフトウェアキーボードを展開時に入力位置を調整する為の矢印ボタンがカメラのパン移動（カメラの角度を変えずに平行に移動すること）に割り当てられてしまう為、操作時に物凄くストレスになる。

####解決策１（カメラのパン移動を制限しても良い場合）：javascriptでOrbitControls.jsの設定時にenablePan = false;を加える。

この方法はカメラのパン移動を制限するので、画面中央に立体物を配置するようなレイアウト限定ですが、一行で問題を解決する事が出来ました。

本当は**HTMLのinputタグがフォーカス状態になった時にOrbitControls無しでカメラを再設定、フォーカス状態解除でOrbitControls有りでカメラを再設定**をプレビュー用のHTMLとセットで紹介してみようと思ったのですが、実際にやってみると現在の自分の実力ではカメラがパン移動した場合のカメラの座標を取得する事が出来ず断念。

####解決策２（カメラのパン移動を制限したくない場合）：HTMLのinputタグがフォーカス状態になった時に3Dオブジェクトの親要素となるcanvasタグ自体にpointer-eventsをnoneに設定し、フォーカス解除時にはpointer-eventsをautoに戻す。

```Javascript

// フォーカス
$("input").focus(function () {
  $("canvas").css("pointer-events", "none");
})

// フォーカス解除
$('input').blur(function() {
  $("canvas").css("pointer-events", "auto");
});

```

こちらの方法ならinputタグフォーカス中はcanvasタグへの全ての操作を制限するので、パン移動も維持しつつ快適な入力が可能です。

今回は以上です。最初はもっと長い記事になるはずだったのですが、試行錯誤するうちにあっさり完結してしまいました。

自分の為の備忘録ですが、誰かの参考になれば幸いです。
Fessのデータストアクロール CsvListDataStore を設定する

# 何をしたいか

対象ファイルパスをリスト化したcsvファイルを用意し、Fessにそのファイルを読み込ませてクロールさせたい。
Fess公式に詳しい解説があるが、若干のわかりづらさを感じたため、実際に確認した内容のまとめ記事にする。


# バージョン等

Fess 13.13.0
Elasticsearch 7.13.0
CentOS 8.4


オープンソース全文検索サーバー Fess
https://fess.codelibs.org/ja/index.html
Elasticsearch
https://www.elastic.co/jp/elasticsearch/


# 公式の解説

公式の解説 データストアクロール
https://fess.codelibs.org/ja/13.13/admin/dataconfig-guide.html


# csv作成

## フォーマット

```:csv
modify,smb://servername/data/testfile1.txt
modify,smb://servername/data/testfile2.txt
modify,smb://servername/data/testfile3.txt
```

カラム1はそのファイルがどう操作されたのかのアクション。テストならmodifyにすると新規でも更新でも動く。
>create：ファイルが作成された
>modify：ファイルが更新された
>delete：ファイルが削除された

カラム2はファイルパス。区切り文字はデフォルト`/`。Windowsサーバーでも`/`で書くこと。
fileプロトコルでも書けるらしいのだが、うまくいかない。ファイルクロールの場合はfileでもsmbでもうまくいったのだが…。あえてfileで書く意味は特にないので、smbを使うことにする。

ダブルクォーテーション囲みは無しにする。パラメータ指定で囲みあり＋囲み文字を無視する設定がうまくいかなかっため。この件は別途確認したい。

## 文字エンコード

今回はLinux版なのでUTF-8で保存。


# クロール設定

名前はただの名前なので適当に。
ハンドラー名は`CsvListDataStore`を選択。

## パラメーター

```:パラメーター
files=/home/crawletest.csv
fileEncoding=UTF-8
crawler.file.auth=servername
crawler.file.auth.servername.scheme=SAMBA
crawler.file.auth.servername.username=username
crawler.file.auth.servername.password=password
```

### files / directories

1ファイルの場合はfiles指定。
directoriesで指定するとディレクトリ内の.csvと.tsvを全部読む。`directories=/home/taro/csv`など。

### fileEncoding
`UTF-8`と書かないと読めない。Utf-8やutf-8やutf8ではだめ。
シフトJISは`Shift_JIS`。

### crawler.file.auth
クロール先ファイルサーバの認証情報。公式解説だとどこに記述するかわかりづらいがこれはパラメータに設定する。
passwordは暗号化されて保存される。

## その他の設定
今回の確認では使わなかったパラメータ設定
https://news.mynavi.jp/itsearch/article/devsoft/4761

### quoteDisabled=false
csv内で囲み文字が使われている場合に設定…らしい。
囲み文字`"`入りのcsvで正常に動作させることができなかったため、別途調査と確認する。

### skipLines=1
csv先頭から指定行数を読み飛ばす。1行目がカラム名になっていて読み飛ばしたい場合など。

## スクリプト

```:スクリプト
event_type=cell1
url=cell2
```

これは公式コピペでいい。csvの中身が何なのかを指定している。
【BizRobo】 DAのComponentに変数を設定する

## はじめに
私が知った内容をみなさんに知って頂きたいため記事を書いています。

今回はBizRoboのDAでComponentに変数を設定したい場合の方法をご紹介します。
ぜひ参考にしていただければ幸いです。

## 設定方法

- 下記の1を変数に変えたい場合

　　　　　　　　　　![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/4ea598a2-c758-37db-6829-bd59085ffe78.png)
①下記画像の赤枠部分をクリックして「＝」を付ける
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/6d3561e0-ecae-4163-0738-9457927473cc.png)
②式の両端に「”」（ダブルクォーテーション）を付ける
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/da467fa4-fc61-74d2-b9d0-7dc4150468da.png)
③変数に変えたい箇所を「＋」で囲う（今回は1を変数に変えます）
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/1a22986e-cf72-139f-435e-4ca620a12218.png)
④「＋」で囲った箇所を変数に変える（今回は1をAという変数に変えています）
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/982423ea-bd23-aba8-254c-03853d7618e5.png)
⑤変数に変えて、下に表示されたと思ってもこれは正確に認識出来ません。
なぜなら、今回の変数に変えた箇所の「1」が文字列となっているためです。
　　　　　　　　　　![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/4ea598a2-c758-37db-6829-bd59085ffe78.png)

⑥文字列である場合は、文字列だと認識させるために「￥"」を使用して囲わなければなりません。
最終的に以下の通りになります。
"button[name=￥""+ 変数 +"￥"]"
　　　　　　　　　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902544/5c0abdce-a3ac-f099-fdd4-929781a19086.png)

みなさんいかがでしたでしょうか。

ぜひ今後の開発の参考にしていただければ幸いです。
最後までご覧頂きありがとうございました。
vscode-neovimで折り畳んだコードを跨ぐとき展開しない

vscodevimのvim.foldfixに相当する設定です
vimrcまたはinit.vimに以下を追加することで、折り畳んだコードを跨ぐ時に展開しなくなります

```vimscript
nnoremap j :call VSCodeCall('cursorDown')<CR>
nnoremap k :call VSCodeCall('cursorUp')<CR>
```


日本語で言及している人がいなかったので。
参考：https://github.com/asvetliakov/vscode-neovim/issues/58
javascript・CSSを使って要素を表示・非表示にする。

javascriptを使ってhtmlの要素を表示・非表示にする方法。

<h2>表示されているものを非表示にする方法</h2>

```html
<div class='test1'>
　　非表示にさせたい。！
</div>
```
```css
.test1{
  display: none;
}
```
非表示にさせたい要素にclassまたはidをつけて上げて display: none;をcssに記述してあげることによって非表示にすることができます。

<h2>非表示にさせたものを表示したい。</h2>
```html
<div class='test1' id='test1'>              <!-- id名は自由にどうぞ -->
　　非表示にさせたい。！
</div>
<input type='button' value='表示' id='btn'>　  <!--例としてinputを使用しています。 -->
```
```css
.test1{
  display: none;    /* ページが読み込まれた時点で非表示 */
}
```
```javascript
 const Btn = document.getElementById('btn') 　　          // htmlで作成したid=btnを取得
 const test1 = document.getElementById('test1')        // htmlで作成したid=test1を取得

 Btn.addEventListener('click', function(){             // イベントにclickを記述する事によりbtnがクリックされた時というアクションになる
    test1.setAttribute('style', 'display:block;')      // クリックアクション内に記述しているため、クリックされたらcssの記述を追加される
  });
```
今回はjavascriptとcssを使った記述方法になります。！　個人的には表示・非表示はviewを作るにあったって画面に動きをつけるのによく使うので覚えておくと様々な応用に使えると思います！
Nugetで取得したパッケージのライセンスファイルを取得するツールを作ってみた

タイトルの通り。

Nugetで取得したパッケージのライセンスファイルをダウンロードしてくるツールを作った。

**【悲報】2021/08/19 直前で気まぐれにメソッド化した処理がバグっており、動かない模様｡｡｡｡現在修正中｡｡｡ -> 致命的なのは直した**

ソースは以下。

https://github.com/piyo0320/ListNugetLicense


自動化したかった操作は以下。

- (1) Nugetのページでパッケージを検索(例えばNewtonsoft.Jsonの場合は以下)

https://www.nuget.org/packages/Newtonsoft.Json/

- (2) InfoのSource Repositoryをクリックして、リポジトリのURLを開く。

https://github.com/JamesNK/Newtonsoft.Json

- (3) リポジトリ内のライセンスファイルを取得。

Newtonsoft.Jsonの場合はLICENSE.md。


## 使った技術
### nuspecファイルの解析
以下のページを参考にプロジェクトのURLを取得した。
https://docs.microsoft.com/ja-jp/nuget/reference/nuspec

### GitHubのAPI
以下のAPIでコンテンツを取得した。
https://docs.github.com/ja/rest/reference/repos#community

## できなかったこと
とりあえず100万以上DLされているパッケージを対象に実行してみたが、jQueryだけダメだった。

jQueryはプロジェクトURLがGithubじゃなかったので、GitHubのREST APIじゃライセンスファイルがとれなかった模様。

うーん、これ頑張れるのかなぁ････
Couchbase Server N1QL解説: JSONデータにおける存在しない値の扱い

SQL利用者にとって、「NULL」という予約語や、`IS [NOT] NULL`という比較演算は、馴染みがあるところです。
NULLは、データが存在しないことである、と言ったりします。より正確には、値が存在しない状態を表しています。ここで、データと値の違いはどこにあり、なぜ後者がより正確なのでしょうか？「データ」という表現は曖昧に取れる一方、「値」という言葉には、数学でいうところのXの値という使い方に見られるように（もちろん、プログラミングでいうところの、変数の値、でもいいわけですが）、単にそれ自体で存在しているデータを超えた含意があります。データベースのコンテクストでいえば、テーブルスキーマにおけるカラムは、一定のデータ型を持ちますが、数値型であれば0、文字列型であれば空文字（長さ0の文字）のようなデータ型固有の表現とは別に、値そのものが存在していない状態がNULLで表現されます。
JSONにおいても、「フィールドの値が未定義」であることを意味する「null」という予約語が定義されています。一方、JSONのように、データ自体にデータ構造の情報が含まれる（データとは別にスキーマが存在していない）、データにあっては、「フィールドが未定義」の場合を考慮する必要があります。

### `MISSING`

JSONデータに対して、N1QLによるクエリを実行した場合、他のドキュメントには存在するフィールドが、一部のドキュメントには存在しないことがあり得ます（RDB/SQLでは、テーブル内のすべてのレコードが同一のスキーマに従うため、このような状況が起こりません）。
N1QLには、そのようなギャップを埋めるため、`MISSING`というキーワード（データ型）が用意されています。以下、N1QLにおけるデータ型としての、　`NULL`と`MISSING`の定義を確認した後に、N1QLにおける、存在しない値に対する比較演算について見ていきます。

## データ型の側面から見た場合

### `MISSING`

N1QLにおいて`MISSING`は、JSONドキュメントでフィールド（名前と値のペア）が存在していない（欠落している）ことを表します。
N1QLにおけるSELECT文で、検索結果として返されるフィールドが存在しない（MISSINGである）データがある場合、（クエリ処理において、内部的にはMISSINGはリテラル式で扱われますが）、最終的な結果の配列中では、（JSONデータにおける未定義の値である）NULLに変換されます。

### `NULL`
N1QLは、キーワードNULLを使用して空の値を表します。データ挿入、更新時に、フィールドの値をNULLにすることができます。

NULL値は、ゼロ除算や間違ったタイプの引数の受け渡しなど、特定の操作によっても生成され得ます。

NULLでは大文字と小文字が区別されません。たとえば、null、NULL、Null、およびnUllはすべて同等です。



https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/datatypes.html#datatype-missing

## 存在しない値に対する比較演算

### `IS [NOT] NULL|MISSING`
`IS [NOT] NULL|MISSING`ファミリー演算子を使用すると、データ・セット内の属性の存在（または不在）に基づいて条件を指定できます。

これらは、データ型の定義から導かれる通りの挙動となります。

具体的なクエリと結果の例を見るのが、理解に役立つでしょう。

#### IS NULL

```sql
SELECT fname, children
    FROM tutorial
       WHERE children IS NULL
```



```json
{
  "results": [
    {
      "children": null,
      "fname": "Fred"
    }
  ]
}
```

#### IS MISSING

```sql
SELECT fname
   FROM tutorial
      WHERE children IS MISSING
```



```json
{
  "results": [
    {
      "fname": "Harry"
    },
    {
      "fname": "Jane"
    }
  ]
}
```

### `IS [NOT] VALUED`

NULLとMISSINGは、JSONデータ上明らかに異なる状態であり、区別される必要がある一方、アプリケーションにおける検索条件としては区別する必要がない場合が考えられます。その際にANDやORを使って複数の検索条件を並置する代わりに、N1QLでは、`IS [NOT] VALUED`という比較演算が利用可能です。

- `IS VALUED`は、値が'MISSING'でも'NULL'でもない場合、TRUE（真）になります。
- `IS NOT VALUED`は、値が'MISSING'あるいは'NULL'である場合、TRUE（真）になります。




https://docs.couchbase.com/server/current/n1ql/n1ql-language-reference/comparisonops.html
deviseの導入

##gemfileにdeviseを追加

```gemfile
gem 'devise'
```

##bundleをインストール
```
$ docker-compose run web bundle install
```

gemfileが変更されたので、buildする

```
$ docker-compose build
```

##deviseをインストール
```
$ docker-compose run web rails g devise:install
```

##モデルの作成
```
docker-compose run web rails g devise モデル名
```

##アラートの表示
bodyタグ内に

```application.html.erb
<body>

    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    
    <%= yield %>
</body>
```

##deviseのビューの作成
```
docker-compose run web rails g devise:views 任意でビュー名
```

これでdevise導入完了！
Gitコマンド一覧

## セットアップ
```
git init
```
・ディレクトリ下で使用する。

## ユーザー名とメールアドレスを確認&再設定

```
$ git config user.name
$ git config user.email
$ git config --global user.name "Your Name"
$ git config --global user.email "your.mail.account@gmail.com"
```
・--globalオプションは、ユーザごとの設定を行う ~/.gitconfig ファイルに対して、サーバー全体に値を設定するという意味
・--localにすると、ディレクトリ下限定の設定となる。



## ステージ、コミット、プッシュ
```
$ git add sample.php
$ git add -A
$ git commit -m "commit message"
$ git remote add origin https://github.com/user/repository.git
$ git push -u origin branchname
```
・pushは、ブランチごとに２回目以降は「git push」のみでOK


## ブランチの編集
```
$ git checkout -b <branch>               # チェックアウトし、ブランチを新規作成
$ git branch --merged                    # マージ済みブランチの一覧
$ git branch -d                          # マージ済みブランチの削除
$ git branch -D <branch>                 # 強制的なブランチの削除
$ git fetch -p                           # リモートブランチの最新状態を取得（リモートブランチの削除も同期）
$ git for-each-ref refs/remotes --merged # マージ済みリモートブランチの一覧
$ git push --delete                      # リモートブランチの削除
```


## プル
```
$ git pull origin master
$ git pull
```

# アクセストークン設定
参考URL
https://qiita.com/shiro01/items/e886aa1e4beb404f9038

・アクセストークンとは？
→パスワードを暗号化したもの。passwordを聞かれたとき、普通に読める文字列の代わりに入力する。

Settings → Developer settings → Personal access tokens

# 参考URL
https://qiita.com/2m1tsu3/items/6d49374230afab251337
https://qiita.com/Toshimatu/items/f71a935612a55d6e674e

# ローカルブランチの一括削除
例： `develop`, `main` のみ残したい場合
```
$ git checkout develop
$ git branch | grep -v 'develop\|main' | xargs git branch -d
```
Mosquitto 2.0 に外部からアクセスする

Mosquitto 2.0 に外部からアクセスする方法です。

Ubuntu 21.04 に Mosquitto をインストールすると 2.0 系になります。

```text
$ mosquitto -h
mosquitto version 2.0.10

mosquitto is an MQTT v5.0/v3.1.1/v3.1 broker.
```

インストールしたままでは、外部からアクセスができません。
次のようなログが出ます。

```text:/var/log/mosquitto/mosquitto.log
1629166056: mosquitto version 2.0.10 starting
1629166056: Config loaded from /etc/mosquitto/mosquitto.conf.
1629166056: Starting in local only mode. Connections will only be possible from clients running on this machine.
1629166056: Create a configuration file which defines a listener to allow remote access.
1629166056: For more details see https://mosquitto.org/documentation/authentication-methods/
1629166056: Opening ipv4 listen socket on port 1883.
1629166056: Opening ipv6 listen socket on port 1883.
1629166056: mosquitto version 2.0.10 running
```

そこで、設定を変更します。

```text:/etc/mosquitto/mosquitto.conf
（省略）
listener 1883
allow_anonymous true
```

mosquitto の再起動

```bash
sudo systemctl restart mosquitto
```

これで外部からのアクセスができるようになります。

参考ページ
[Authentication methods](https://mosquitto.org/documentation/authentication-methods/)
3.18(標準) カイ二乗分布

## 方針

カイ二乗分布について書く．

```math
Z_1,...,Z_n:iid\sim\mathcal{N}(0,1)
```

の時，

```math
X=Z_1^2+...+Z_n^2\sim\chi_n^2=Ga(\frac{n}{2},\frac{1}{2})
```

で，確率密度関数は，

```math
f_{X}(x)=\frac{(\frac{1}{2})^{n/2}}{\Gamma(\frac{n}{2})}x^{\frac{n}{2}-1}\exp(-\frac{1}{2}x)
```

である．積率母関数は

```math
\begin{align}
M_X(t)&= \mathbb{E}_{X\sim\chi_n^2}[e^{tX}]\\
&= \int_0^\infty\frac{(\frac{1}{2})^{n/2}}{\Gamma(\frac{n}{2})}x^{\frac{n}{2}-1}\exp\{-(\frac{1}{2}-t)x\}dx\\
&= \frac{(\frac{1}{2})^{n/2}}{\Gamma(\frac{n}{2})}\frac{\Gamma(\frac{n}{2})}{(\frac{1}{2}-t)^{n/2}}\int_0^\infty\frac{(\frac{1}{2}-t)^{n/2}}{\Gamma(\frac{n}{2})}x^{\frac{n}{2}-1}\exp\{-(\frac{1}{2}-t)x\}dx\\
&= \frac{1}{(1-2t)^{n/2}}
\end{align}
```

である．まずは

```math
Z_1^2\sim\chi_1^2
```

を示す．

```math
Y_1=Z_1^2,\ Y_2=Z_2^2,\ ...,\ Y_n=Z_n^2
```

と置くと

```math
\begin{align}
f_{Y_1}(y)&= f_{Z_1}(\sqrt{y})\frac{1}{2\sqrt{y}}-f_{Z_1}(-\sqrt{y})(-\frac{1}{2\sqrt{y}})\\
&= \frac{1}{\sqrt{y}}\frac{1}{\sqrt{2\pi}}\exp(-\frac{y}{2})\\
&= \frac{(\frac{1}{2})^{1/2}}{\Gamma(\frac{1}{2})}y^{\frac{1}{2}-1}\exp(-\frac{1}{2}y)
\end{align}
```

ゆえ，

```math
Y_1,...,Y_n:iid\sim\chi_1^2
```

が示された．次に，

```math
X=Y_1+...+Y_n
```

と置くと

```math
\begin{align}
M_X(t)&= \mathbb{E}_X[e^{tX}]\\
&= \mathbb{E}_{Y_1,...,Y_n:iid\sim\chi_1^2}[e^{t(Y_1+...+Y_n)}]\\
&= \mathbb{E}_{Y_1\sim\chi_1^2}[e^{tY_1}]...\mathbb{E}_{Y_n\sim\chi_1^2}[e^{tY_n}]\\
&= \frac{1}{(1-2t)^{1/2}}...\frac{1}{(1-2t)^{1/2}}\\
&= \frac{1}{(1-2t)^{n/2}}
\end{align}
```

より，

```math
X=Y_1+...+Y_n=Z_1^2+...+Z_n^2\sim\chi_n^2
```

が示された．問題はカイ二乗分布の期待値演算なので，ガンマ分布の時と同様に計算すれば良い．

## 1.答案

```math
\begin{align}
\mathbb{E}_{X\sim\chi_n^2}[X^\nu]&= \int_0^\infty\frac{(\frac{1}{2})^{n/2}}{\Gamma(\frac{n}{2})}x^{\nu+\frac{n}{2}-1}\exp(-\frac{1}{2}x)dx\\
&= \frac{(\frac{1}{2})^{n/2}}{\Gamma(\frac{n}{2})}\frac{\Gamma(\nu+\frac{n}{2})}{(\frac{1}{2})^{\nu+\frac{n}{2}}}\int_0^\infty\frac{(\frac{1}{2})^{\nu+\frac{n}{2}}}{\Gamma(\nu+\frac{n}{2})}x^{\nu+\frac{n}{2}-1}\exp(-\frac{1}{2}x)dx\\
&= \frac{2^\nu\Gamma(\nu+\frac{n}{2})}{\Gamma(\frac{n}{2})}
\end{align}
```

## 2.答案

自由度nのカイ二乗分布に従う確率変数をX_nと置くことにする．

```math
X_n\sim\chi_n^2
```

この時，X_{n+2}の確率密度関数は

```math
\begin{align}
f_{X_{n+2}}(x)&= \frac{(\frac{1}{2})^{\frac{n}{2}+1}}{\Gamma(\frac{n}{2}+1)}x^{n/2}\exp(-\frac{1}{2}x)\\
&= \frac{\frac{1}{2}x}{\frac{n}{2}}\frac{(\frac{1}{2})^{\frac{n}{2}}}{\Gamma(\frac{n}{2})}x^{\frac{n}{2}-1}\exp(-\frac{1}{2}x)\\
&= \frac{x}{n}f_{X_n}(x)
\end{align}
```

と表せ，

```math
\begin{align}
f_{X_n}(x)&= \frac{n}{x}f_{X_{n+2}}(x)\\
f_{X_n}(x)&= \frac{x}{n-2}f_{X_{n-2}}(x)
\end{align}
```

が成り立つ．ゆえ，

```math
\begin{align}
\mathbb{E}_{X_n\sim\chi_n^2}[h(X_n)]&= \int_0^\infty h(x)f_{X_n}(x)dx\\
&= \int_0^\infty h(x)\frac{n}{x}f_{X_{n+2}}(x)dx\\
&= n\mathbb{E}_{X_{n+2}\sim\chi_{n+2}^2}[\frac{h(X_n)}{X_n}]\\
\mathbb{E}_{X_n\sim\chi_n^2}[h(X_n)]&= \int_0^\infty h(x)f_{X_n}(x)dx\\
&= \int_0^\infty h(x)\frac{x}{n-2}f_{X_{n-2}}(x)dx\\
&= \frac{1}{n-2}\mathbb{E}_{X_{n-2}\sim\chi_{n-2}^2}[X_{n-2}h(X_{n-2})]
\end{align}
```

## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
Goの構造体に連想配列を入れる。（可変長）

以下のような構造のJsonを生成したかったのだけど、
自分にはあまりいい記事がなかったので書くことに。
Responseキーの中のリストは、可変します。

```bash
{
  "header": {
    "error_message": "",
    "status": "222"
  },
  "Response": [
    {
      "code": "111",
      "name": "1"
    },
    {
      "code": "111",
      "name": "2"
    },
    {
      "code": "111",
      "name": "3"
    }
  ]
}
```

```bash
{
  "header": {
    "error_message": "",
    "status": "222"
  },
  "Response": null
}
```


### とりあえずコードです
※一部修正しました。

```struct.go
package main

import (
	"encoding/json"
	"fmt"
	"strconv"
)

type CommonHeader struct {
	ErrorMessage string `json:"error_message"`

	Status string `json:"status"`
}

type ResultList struct {
	Header   CommonHeader `json:"header"`
	//Response ListB //親構造体で配列であることを示したほうが良い
	Response []ListB
}

type ListB struct {    //type ListB []struct { こういう書き方はあまりよくない
	Code string `json:"code,omitempty"`
	Name string `json:"name,omitempty"`
}

// 構造体に以下のようなデータを付けてJsonにしたい
// [{code:"111",name":"hoge"},{code:"222",name":"fuge"}]

func main() {
	//var aaa ListB 構造体変更したため、宣言方法も変更
	var aaa []ListB
	// 不定長のデータ構造をつける。
	for i := 1; i < 4; i++ {
		//fmt.Println(i)
		aaa = append(aaa, struct {
			Code string "json:\"code,omitempty\""
			Name string "json:\"name,omitempty\""
		}{Code: "111", Name: strconv.Itoa(i)})

	}
	//fmt.Println(aaa)
	//j, _ := json.Marshal(aaa)
	//fmt.Println(string(j))

	////// struct生成（head）
	head := CommonHeader{
		ErrorMessage: "",
		Status:       "222",
	}
	// headとaaaを構造体にセット
	result := ResultList{
		Header:   head,
		Response: aaa,
	}

	//fmt.Println(result)
	//json化する
	result_j, _ := json.Marshal(result)

	fmt.Println(string(result_j))

}
```

Forループ内でaaaに連想配列をループ回数分（好きな）だけAppendします。

Print部分は確認用としてあえて残してあります。
変数名なんかも、どこがどこにつながるかわかるように分けてます。
（キー名と変数名が同じものとか、自分には見にくいので・・・。）

うまく書くと、いい感じに変数名とか省略されるので、一足飛びでGoを学ぼうとすると躓くことが多いです…。
[Ruby] Array#sum　メソッド

##はじめに
sumメソッドってすごく馴染みがあるように思っていたんですが、使い方をみたら、全然使ったことなかったと思いまして、簡単に記事にまとめておこうと思います。

##sumメソッド

配列に対して使います。配列に入っている要素を全部がっちゃんこしてくれるイメージ。

```ruby
[1, 2, 3, 4].sum
=> 10
```



> 引数に明示的に指名すると数値以外にも使用できます。
https://docs.ruby-lang.org/ja/latest/method/Array/i/sum.html

なかなか表現が思いつかなかったのでリファレンスの表現をお借りします。

```ruby
["お", "は", "よ", "う"].sum("")
=> "おはよう"

[[1], [[2]], [3]].sum([])
=> [1, [2], 3]
```
bin/rails db:drop実行に失敗した時の対処法

## 症状


ターミナルで$ bin/rails db:dropコマンドを入力したら以下のような画面が表示された(データベース名はセキュリティ上伏せてある)

```terminal:terminal

PG::ObjectInUse: ERROR:  database "XXXxxxx" is being accessed by other users
DETAIL:  There are 3 other sessions using the database.

rails aborted!
ActiveRecord::StatementInvalid: PG::ObjectInUse: ERROR:  database "XXXxxxx" is being accessed by other users
DETAIL:  There are 3 other sessions using the database.

```


## 原因と対応

原因は作成中のアプリ以外に接続しているアプリなどはないのに接続されっぱなしになっている模様。
$ bin/rails db:migrate:resetしても改善されなかった。
PostgreSQLの再起動で回復に成功。
DBを再起動すると**他のDBを使用しているアプリまで切断される**ことになるので実行には注意が必要。


```terminal:terminal

$ brew services stop postgresql  # postgresqlの停止
$ brew services stop postgresql  # postgresqlの起動

# 以下のコマンドでDBアプリの状態を確認できる
$ brew services list

```
基本情報技術者　ネットワーク編②

#初めに
[前回](https://qiita.com/reo0612/items/0425d1e8694c4b2b26eb)の続きです。

#プロトコルとOSI基本参照モデル
ネットワークを通じてコンピュータ同士がやり取りするための約束事を`プロトコル`と呼びます。

英語が分からない人に対して英語で話しても通じません。

コンピュータも同じで、どんなケーブルを使って、どんな形式でデータを送り
それをどうやって受け取って、どのように応答するかは全部共通の約束事があります。

これらを7階層に分けてみたのが`OSI基本参照モデル`と呼びます。

基本的には、この第1階層から第7階層までの全てを組み合わせることで
コンピュータ同士のコミュニケーションが成立するようになっています。
![OSI基本参照モデル.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743730/8dd0afcc-6187-b10e-1cad-5af3c081efe5.jpeg)
※ [第10回　OSI基本参照モデル――7階層による道案内で，データを迷わせない](https://xtech.nikkei.com/it/article/COLUMN/20070914/281963/) 参照

何故このように階層で分けているのかというと、プロトコルを一部改変したい時なんかに
どの機能を差し替えたいのかが一目瞭然だからです。

現在は、インターネットの世界で標準とされているのが`TCP/IP`というプロトコルです。

#なんでパケットに分けるのか
TCP/IPを使うネットワークでは、通信データをパケットに分割して通信路へ流します。

なんでわざわざ分割して流すのかというと、通信路上を流せるデータ量が`有限`だからです。
例えば、100BASE-TXのネットワークだと、1秒間に流せるのは100Mbitまでです。

仮にパケットにせず、そのまま流すと他のコンピュータは誰もネットワークを利用できなくなります。

これを避けるために、小さなパケットに分割して流しています。

#ネットワークの伝送速度
ネットワークの伝送に要する時間は計算式で求める事ができます。

```
伝送時間 = データ量 ÷ 回線速度
```
しかし、この計算式はあくまで`理論値`なので実際は違ってきます。

例えば、100Mbpsの回線があったとします。

ですがこれは規格上の理論値であり
一般的な使用法で実際に出る速度は90Mbpsだとします。

このような速度を`実効速度`と呼びます。
つまり、実効速度は90Mbpsということになります。

そして理論値に対して実際に出る速度の割合を表すのが`伝送効率`と呼びます。

実効速度・伝送効率どちらも求める計算式があります↓

```
実効速度 = 理論値 × 伝送効率
伝送効率 = 実効速度 ÷ 理論値
```
今回の場合、伝送効率は0.9となります。

ネットワークを流れるパケットも分割したサイズが
そのまま流れる訳ではありません。

例えば、1つのパケットが128バイトだったとしても、そこから宛先情報などがくっついて元の128バイトからプラスされていくので計算する場合は注意が必要です。

#おわりに
今日はここまでです。

間違っている部分や気になるところがあればコメントして下さい。
Building Mobile Apps at Scaleの自動テストの部分で知らなかったところメモ

世界的な会社がどうテストしているのか、ちょっとテスト関連のベストプラクティスを探して読んでみています。

個人的にはrobot pattern testingはちょっとした収穫でした。
またかなりSnapshot testが行われていることが印象的でした。
詳しくは以下

https://www.mobileatscale.com/



(ユニットテストは大事的なのが書いてあるんですが、知らなかったところ中心で書いているので飛ばしています)

### Snapshot test

IntegrationテストやUI/E2Eテストの特別な形。スクショをとって、保存されている画像と比較する。データは通常モックが使われる。違うとテストが失敗する。失敗の理由として画像が使われる

Snapshot testのUberでの事例

* iOSではFacebookからiOSSnapshotTestCaseを引き継いで、多用していた
* デバイスのサイズが多様だったのでAndroidで適切なスナップショットを行うための労力がこのプラットフォームでは高すぎると考えたのでAndroidでは行わないことを決定した
* リポジトリにスナップショットの画像を保存していたが、チェックアウトや更新が遅くなったので、リポジトリ外に画像を移動させ、mainブランチの変更をCIが追跡する形になった。
* CIでは変更が検出されるとタスクを作成し、変更が予期されるものである場合は開発者はチケットを閉じ、そうでない場合は問題を解決するための差分を作成する。
* リポジトリ内にない画像への参照をチェックされないようにするワークアラウンドを行うツールを構築した。

Snapshot testについて

* 様々なアプリで使われるが、どんなアプリにもフィットするわけではない。有用性の多くはアプリに依存する。
* 気づかないうちに変更されたくない「core」フローをカバーすることが良いスタートになる


### Automated UI testing

大きくスケールしたアプリではかなりツールが制限される。
Appleの UI testing out of the boxはマニュアル動作を保存して再生できる。少しのケースではうまくいく。
https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/09-ui_testing.html
大きなアプリではもっと頑丈な解決策や、robotやpage objectのようなアプローチのエンジニアリングが必要になる。robotやpage objectを作るのは難しくなく、スケールする。
robot pattern testing
https://www.capitalone.com/tech/software-engineering/robot-pattern-testing-for-xcuitest/
(Androidの人は元になったこっちがいいかも)
https://jakewharton.com/testing-robots/
page object pattern
https://medium.com/wantedly-engineering/introducing-page-object-pattern-in-ios-74e46c664d26
20〜30個以上のUIテストを書いているチームはテスト実行にどれだけ時間がかかるかという問題に直面する。またこれをmasterにマージする前に実行するかしないのかというジレンマに陥る。
この問題は2つのことを浮かび上がらせる

* テストピラミッドの中でどこに力をそそぐのか考える。UIテストは重要だが、最もコストがかかる。他のテストに適切なレベルの投資をしているかを考える必要がある。
* 大規模なUIテストは多くの利点がある。[Two Years of UI testing](https://www.youtube.com/watch?v=kO2XwAd9RaA)ではそのためのいくつかの解決策を紹介している。UberではUIテストを並行に実行するために、flakey testを検知するために、また効果追跡するためにかなりの時間を費やした。

データをモックすることのメリデメがある。
メリット:スピード、エッジケース、信頼性、繰り返し利用できる。デメリット: データが古くなる、テストデータを管理する必要がある。データの変更のテストができない。

テスト戦略は企業やチームによって大きく異なる。

Spotify ~32,000 ユニットテストとインテグレーションテスト, ~1,600 スナップショットテスト, ~500 UIテスト
Airbnb ~10,000 ユニットテスト and ~30,000 スナップショットテスト
Shopify had ~8400 ユニットテスト, ~2300 スナップショットテスト and ~20 E2Eテスト
Uber 数千のユニットテスト, 数千のスナップショットテスト, 少しのUI tests と 手動テスト
Lyft 数千のユニットテスト, いくつかのスナップショットテスト, いくつかのUIテスト と 手動テスト
...
Gradleプロジェクトのインポート時ビルド実行中に固まってハマった話

実行環境。
・Eclipse
　Version: 2021-06 (4.20.0)

・Gradle

```
------------------------------------------------------------
Gradle 6.7
------------------------------------------------------------

Build time:   2020-10-14 16:13:12 UTC
Revision:     312ba9e0f4f8a02d01854d1ed743b79ed996dfd3

Kotlin:       1.3.72
Groovy:       2.5.12
Ant:          Apache Ant(TM) version 1.10.8 compiled on May 10 2020
JVM:          11.0.2 (Oracle Corporation 11.0.2+9)
OS:           Windows 10 10.0 amd64
```

Eclipseを起動し、既存のGradleプロジェクトをインポートします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879666/29198d26-7117-dcc0-5503-92b8666c6c5a.png)

オプションを上記の通り設定して、次へをクリックするとインポート構成を確認します。
インポート構成を確認したら完了をクリックするとインポートを実行するのですが、
ビルド実行のところで止まってしまいます。


https://qiita.com/tonionagauzzi/items/be93308ab324e4d8319f
を参考にして、インポートしたいプロジェクトのbuild.gradleに以下のようにbuildscanブロックを追加しました。

```gradle:build.gradle
buildScan {
    termsOfServiceUrl = 'https://gradle.com/terms-of-service'
    termsOfServiceAgree = 'yes'
    publishAlways()
}
```

上記対応後、再度インポートしたら無事完了しました。

※今回の環境ではGradleのバージョンが6.7を使っているので問題は起きないはずなのですが、なぜかは不明。。わかり次第追記します。
ruby on railsでのユーザー管理機能について

この記事ではruby on rails 6.0.0を使用しています。！

今回はdeviseのgemを紹介したいと思います。

<h1>deviseって何？</h1>
devisとはユーザー管理機能を実装するためのgemです。
会員登録やログイン・ログアウト機能を簡易に実装することができるgemです。！

<h1>導入方法</h1>
導入は簡単です。！

![05ca375321ad0851c0be9c6b3a07691b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1902434/e791767e-878d-e529-cc2d-c73d9f4d8fab.png)


Gemfileに　gem 'devise'　と記述してbundle installをするだけです。！!
YamlDotNetでインデント幅を設定する

YamlDotNetのDefaultだとインデント幅2だけども、仕様でインデント幅4を要求されたので(インデント幅4前提のレガシーツールがあるっぽい)インデント幅の変更方法を探してみたけど、まるで見つからなかったのでここに残す。

```csharp
using YamlDotNet.Core;
using YamlDotNet.Serialization;

// Default Serializer
var serializer = new Serialiser();

using (StreamWriter sw = File.CreateText(path))
{
    // Indent Width 4
    var e = new Emitter(sw, 4);
    serializer.Serialize(e, root);
}
```

## 解説
`Serialize`の出力先として`TextWriter`ではなくインデント幅を設定した`Emitter`を使うだけ。
とはいえ`YamlDotNet.Core.Emitter`の[ドキュメント](https://github.com/aaubry/YamlDotNet/wiki/Core.Emitter)がTODO状態(2021/08/17現在)なのもあり、なかなか分からなかった。
AtCoderログ：0080 - ABC 214 B


# 問題

https://atcoder.jp/contests/abc214/tasks/abc214_b

## 問題文
> $a+b+c \le S$ かつ $a \times b \times c \le T$ を満たす非負整数の組 $(a,b,c)$ はいくつありますか？

## 制約
> ・$0 \le S \le 100$
> ・$0 \le T \le 10000$
> ・$S,T$ は整数である。

# 回答
## 回答1 (AC)
非負の整数 $a,b,c$ は $a+b+c \le S \le 100$ を満たすので、$a,b,c$ の最大値は $100$ です。そこで $a,b,c$ をそれぞれ $0$ から $100$ まで変化させ、2つの条件を満たす組を数えるという、全検索の問題として解くことが出来ます。繰返し回数は $100^3=10^6$ となるので、時間内の処理が可能です。コードは以下のようになりました。

```C++:abc214b-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int s, t;
  cin >> s >> t;

  int answer = 0;
  for ( int a=0; a<101; a++ ) {
    for ( int b=0; b<101; b++ ) {
      for ( int c=0; c<101; c++ ) {
        if ( a+b+c<=s && a*b*c<=t ){
          answer += 1;
        }
      }
    }
  }

  cout << answer << endl;
}
```

## 回答2 (AC)
解答1のコードをちょっとだけ改良します。$a+b+c \le S$ より $a$ の最大値は $S$ であることがわかるので、a に関する for 文は a=0 から (a<101 ではなく) a<s+1 まで変化させれば十分です。$S \le 100$ なので、検索範囲が狭まっていることがわかります。

同様に、$b$ の値の最大値は $S-a$ なので、b に関する for 文は b=0 から b<s-a+1 まで変化させれば十分です。$c$ についても同様です。以上をまとめたコードは以下のようになりました。

```C++:abc214b-2.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int s, t;
  cin >> s >> t;

  int answer = 0;
  for ( int a=0; a<s+1; a++ ) {
    for ( int b=0; b<s-a+1; b++ ) {
      for ( int c=0; c<s-a-b+1; c++ ) {
        if ( a*b*c<=t ){
          answer += 1;
        }
      }
    }
  }

  cout << answer << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc214/tasks/abc214_b/editorial) → [公式解説](https://atcoder.jp/contests/abc214/editorial/2437)
回答2と同じ方針です。サンプルコードの8行目の「for(int b = 0; a+b <= S; b++){」という書き方を初めて知りました。

## [AtCoder の解説](https://atcoder.jp/contests/abc214/tasks/abc214_b/editorial) → [ユーザ解説](https://blog.hamayanhamayan.com/entry/2021/08/15/034508
)
回答1と回答2の中間くらいの方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0079 - ARC 096 C](https://qiita.com/RoadLynton/items/68d14f29ff1e8492e865)
frameworkプロジェクトでAssets.xcassetsの画像をUIImageでnilにならずに使う方法

## 環境
- xcode: 12.4
- swift: 4.2
- Frameworkプロジェクトのファイル（Cocoa Touch FrameworkのTarget Membershipにチェックが入っているファイルの中での話）

## 問題
- Assets.xcassetsの登録した画像を通常通り取得しようとすると、nilが返ってくる。

``` .swift
let image = UIImage(named: "image_name")
>> imageはnil
```


- 軽く調べると
  - namedで指定するファイル名を間違えていないか
  - Target Membershipにチェックがついてるか
- などがヒットするが、それでは解決しなかった


## 解決策
- `UIImage(named: )`の第二引数に、frameworkプロジェクトのBundle identifierを指定してあげればよい。

``` .swift
let image = UIImage(named: "image_name", in: Bundle(identifier: "my.framework.bundle.identifer"), compatibleWith: nil)
```
OBS: Discord StreamKitのVoice Widgetの解像度を上げるカスタムCSS

Discord StreamKitのVoice Widgetの解像度を上げる方法を紹介します。

Discord StreamKitのVoice Widgetは、OBSの映像サイズが2560x1440など大きめだと、アイコンや名前が小さくて配信上見えにくくなったり、OBS上で拡大表示すると、ジャギジャギした表示になってしまうことがあります。

OBSでカスタムCSSを用いて、StreamKitの大きさを上げることでこの問題を解決できます。

## カスタムCSS

```css
body {
  transform: scale(4);
  transform-origin: left top;
}
```

![CleanShot 2021-08-17 at 09.36.26@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/3a181e66-8abd-27b7-d3fe-8e620d3bd93d.png)
AtCoderログ：0079 - ARC 096 C/ABC 095 C

# 問題

https://atcoder.jp/contests/arc096/tasks/arc096_a

https://atcoder.jp/contests/abc095/tasks/arc096_a

## 問題文
> ファーストフードチェーン「ピザアット」のメニューは「A ピザ」「B ピザ」「AB ピザ」の $3$ 種類です。A ピザと B ピザは全く異なるピザで、これらをそれぞれ半分に切って組み合わせたものが AB ピザです。A ピザ、B ピザ、AB ピザ $1$ 枚あたりの値段はそれぞれ $A$ 円、$B$ 円、$C$ 円です。
> 中橋くんは、今夜のパーティーのために A ピザ $X$ 枚と B ピザ $Y$ 枚を用意する必要があります。これらのピザを入手する方法は、A ピザや B ピザを直接買うか、AB ピザ $2$ 枚を買って A ピザ $1$ 枚と B ピザ $1$ 枚に組み替える以外にはありません。このためには最小で何円が必要でしょうか？なお、ピザの組み替えにより、必要な量を超えたピザが発生しても構いません。

## 制約
> ・$1 \le A,B,C \le 5000$
> ・$1 \le X,Y \le 10^5$
> ・入力中のすべての値は整数である。

## 収録されている問題セット
- [AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067) ([第08問類題](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-8-%E5%95%8F--abc-085-c---otoshidama-300-%E7%82%B9))

# 回答
## 回答1 (AC)
この問題の難しいところは、ピザを余って購入しても良いという点です。A ピザを入手するには「A ピザ」を購入する場合と「AB ピザ」を購入する場合がありますが、余るのは「AB ピザ」を購入した場合だけです。例えば A ピザの入手枚数が x 枚を越えた場合、越えた分は「AB ピザ」に由来します。というのも、越えた分が「A ピザ」ならば、越えた分の「A ピザ」を買わない方が代金が安くなるからです。

この問題はピザを購入する枚数に関して全検索するのが良いのですが、「A ピザ」を i 枚購入したとすると、A ピザを x 枚揃えるにはあと x-i 枚必要なので、残りは「AB ピザ」を購入することになります。しかし最終的にピザは余ってもよいため、「AB ピザ」を購入する枚数は定まらず、この枚数も全検索する必要が生じてしまいます。「B ピザ」の購入枚数を i 枚として考えても同様です。

これに対し「AB ピザ」の購入枚数を i 枚とすると、「A ピザ」や「B ピザ」はわざわざ余らせて購入することはないので、「A ピザ」はあと x-i/2 枚、「B ピザ」はあと y-i/2 枚を購入することになり、全体の処理がすっきりします。コードは以下のようになりました。

```C++:arc096c-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int a, b, ab, x, y;
  cin >> a >> b >> ab >> x >> y;
 
  int price = 0, pmin = INT_MAX;
  for ( int i=0; i<=2*max(x,y); i+=2 ) {
    price = max(0,x-i/2)*a + max(0,y-i/2)*b + i*ab;
    pmin  = min(pmin,price);
  }

  cout << pmin << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/arc096/tasks/arc096_a/editorial) → [ユーザ解説](https://blog.hamayanhamayan.com/entry/2018/04/21/224451)
回答1と同じ方針でした。

## [AtCoder の解説](https://atcoder.jp/contests/arc096/tasks/arc096_a/editorial) → [コンテスト全体の解説](https://img.atcoder.jp/arc096/editorial.pdf)
回答1と同じ方針でした。$O(1)$ の解答もあるのだそうです。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0078 - ABC 214 A](https://qiita.com/RoadLynton/items/f9484704e348f334ea22)
【超初歩的】プログラミングに必要な数学知識

#1　10進法　２進法 の計算

### 1100 を２進法に分解すると
1 x 2<sup>3</sup> 
1 x 2<sup>2</sup> 
0 x 2<sup>1</sup> 
0 x 2<sup>0</sup>  

この式を分解すると10進法に変換できるね！
1 x 2<sup>3</sup> +
1 x 2<sup>2</sup> +
1 x 2<sup>1</sup> +
1 x 2<sup>0</sup> +
=  8 + 4 + 0 + 0
=  12

### 12 を10進法に分解すると
12 % 2 = 6 余り0
6  % 2 = 3 余り0
3  % 2 = 1 余り1
1          余り1

・下から書いて1100

１０進法の場合は１０が基数、２進法の場合は２が基数
変換することを基数変換
express.js・fastify の ETag: 実装

Node.js で、Express・Fastify のレスポンスヘッダ ETag: の実装を確認してみると、`SHA-1` や `FNV-1a ` ハッシュ関数が使われていた。

## Express.js

express.js や koa.js は内部で [etag](https://www.npmjs.com/package/etag) モジュールを使っていて、静的ファイルではなくてダイナミックコンテンツの場合は SHA-1 ハッシュを返す。

```js
const express = require("express");
const app = express();
app.use("/", (req, res, next) => res.send(""));
app.listen(3000);
```

レスポンス：　※デフォルトで `W/` 付き weak。

```
$ curl -I http://127.0.0.1:3000/
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 0
ETag: W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"
Date: Mon, 16 Aug 2021 23:54:02 GMT
Connection: keep-alive
Keep-Alive: timeout=5
```

https://github.com/jshttp/etag/blob/master/index.js

```js
  var hash = crypto
    .createHash('sha1')
    .update(entity, 'utf8')
    .digest('base64')
    .substring(0, 27)
```

## Fastify

Fastify はデフォルトでは ETag: が生えず、[fastify-etag](https://www.npmjs.com/package/fastify-etag) モジュールにより ETag: が生える。SHA-1・SHA-256 などのアルゴリズムを指定できる。デフォルトは `fnv1a` アルゴリズム (FNV-1a)。

```js
const Fastify = require("fastify");
const Etag = require("fastify-etag");
const app = Fastify();
app.register(Etag);
app.all("/", async (request, reply) => "");
app.listen(3000);
```

レスポンス：　※デフォルトで `W/` なし strong。

```
$ curl -I http://127.0.0.1:3000/
HTTP/1.1 200 OK
content-type: text/plain; charset=utf-8
etag: "ztntfp"
content-length: 0
Date: Tue, 17 Aug 2021 00:17:31 GMT
Connection: keep-alive
Keep-Alive: timeout=5
```

https://github.com/fastify/fastify-etag/blob/master/index.js

デフォルトの `fnv1a` は 32bit のコンパクトなハッシュ関数で、[MurMur 並みの性能](https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed/145633#145633) らしい。ちなみに MurMur は [tkrzw](https://mikio.hatenablog.com/entry/2020/05/16/222755) の HashDBM でも使われてる関数で [チェックサム並みの性能](https://mikio.hatenablog.com/entry/2021/06/23/011402) らしい。

```js
function buildHashFn (algorithm = 'fnv1a', weak = false) {
  const prefix = weak ? 'W/"' : '"'
  if (algorithm === 'fnv1a') {
    return (payload) => prefix + fnv1a(payload).toString(36) + '"'
  }

  return (payload) => prefix + createHash(algorithm)
    .update(payload).digest().toString('base64') + '"'
}
```

fasitfy でも SHA-1 を指定できるが、etag モジュールの ETag 値には先頭にバイト長が付くので、fastify と express.js は同じレスポンスボディでも同じ ETag 値にならない。
IBM Cloud: Classic Infrastructure(BMS)のIPMIインターフェースをdisabledにする方法

#1. はじめに
Bare Metal ServerのIPMIインターフェースを通じた管理は便利なのだが、脆弱性にも繋がるので有効化したままにしておかず、普段は無効化しておき必要時に有効化したいという場合もある。本記事ではIPMIインターフェースを無効化する方法を紹介する。

#2. 設定準備
IPMIインターフェースは、APIもしくはCLI(`slcli -v hw toggle-ipmi`)を使って有効化・無効化を切り替えることができる。よって、[ここ](https://qiita.com/testnin2/items/8c2bf7990ef55b4abf7d)などを参考にslcliをまず導入しておく。

#3. 動作確認

##3-1. デフォルトではIPMIインターフェースは有効化（Active)されている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/647b54fd-2214-6216-d0d5-9f8202ffc89f.png)

pingも通る。

```
(python368) [root@syasudacentos7 ~]# ping 10.193.72.251
PING 10.193.72.251 (10.193.72.251) 56(84) bytes of data.
64 bytes from 10.193.72.251: icmp_seq=1 ttl=57 time=1.61 ms
64 bytes from 10.193.72.251: icmp_seq=2 ttl=57 time=1.34 ms
64 bytes from 10.193.72.251: icmp_seq=3 ttl=57 time=1.37 ms
64 bytes from 10.193.72.251: icmp_seq=4 ttl=57 time=1.41 ms
64 bytes from 10.193.72.251: icmp_seq=5 ttl=57 time=1.36 ms
^C
--- 10.193.72.251 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 1.342/1.421/1.611/0.108 ms
```

##3-2. `slcli hw list`で対象物理サーバーのIDを取得する。

```
(python368) [root@syasudacentos7 ~]# slcli hw list
:.........:................:.................:................:............:........:
:    id   :    hostname    :    primary_ip   :   backend_ip   : datacenter : action :
:.........:................:.................:................:............:........:
: 1705285 :     host0      :  xxx.xxx.xx.xx  : 10.193.72.206  :   tok05    :   -    :
:.........:................:.................:................:............:........:
```

##3-3. IPMIインターフェースをDisableにする。

```
(python368) [root@syasudacentos7 ~]# slcli hw toggle-ipmi --disable 1705285
True
```

ステータスが`User off`になった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/5c40688e-58c4-0fe7-0a60-4835b580b735.png)

pingも通らなくなった。

```
(python368) [root@syasudacentos7 ~]# ping 10.193.72.251
PING 10.193.72.251 (10.193.72.251) 56(84) bytes of data.
^C
--- 10.193.72.251 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 8999ms
```

##3-4. 必要に応じてIPMIインラーフェースを再度有効化する。

```
(python368) [root@syasudacentos7 ~]# slcli hw toggle-ipmi --enable 1705285
True
```
GitHub SSH接続

#なぜSSh接続をするのか
リモートリポジトリにpushする際にHTTPS通信だとGitHubアカウントのパスワードを求められることがあり、入力するのは面倒だから

#SSH接続の手順

##Gitの初期設定

https://qiita.com/ucan-lab/items/aadbedcacbc2ac86a2b3
を参考にしてまずはgithubにemail, nameを登録

##GitHubの秘密鍵、公開鍵を作成して、<br>GitHubに公開鍵を登録する

https://gist.github.com/g-empr/fc793caf3a0a18c31d8c708787bdf5f0
を参考に行う

鍵を作成するフォルダに移動

```
cd ~/.ssh
```
鍵の作成

```
ssh-keygen -t rsa
```
GitHubに登録をするため鍵をコピーする

```
pbcopy < ~/.ssh/id_rsa.pub
```

##git clone 

cdで移動してgit clone リポジトリ名

#便利なコマンド
##pbcopy
```
pbcopy < コピーしたいファイル名
```
でクリップボード（コピー&ペーストの一時的な保存領域）に保存される
【Ruby on Rails】新規登録時のエラーメッセージ発生後にリロードするとルーティングエラーになる問題を解決した話


#解決したい課題

* 新規会員登録時に、エラーメッセージ表示後に、リロードすると発生するRunningErrorを解決したい


#結論

* [GET]/userを呼び出していたので、そのまま入力する

#原因と対策
###1.エラー文

![スクリーンショット 2021-08-17 8.40.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681213/6c8a0029-314c-1447-0b3c-ab116be75de3.png)

###2.rails routesルーティング確認

![スクリーンショット 2021-08-16 21.41.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1681213/47f20649-a8ae-9aad-1232-c1f9586a167b.png)

そもそもGETがない、、、！



###3.routes.rbに記載

resourcesを使っていたのでindexを追加

````routes.rb
resources :users, only: [:index, :show, :edit, :update ]
````

これでGETが呼び出せる


###4.Controllerにも忘れす記載

```users_controller.rb
class Public::UsersController < ApplicationController
   before_action :authenticate_user!, except: [:index] #追加
   before_action :set_user, except: [:index]　　#追加
   before_action :correct_user, only: [:edit, :update]

　　　#追加
  def index
    redirect_to new_user_registration_path
  end

:
:

end
````

indexアクション追加して、新規登録画面に遷移するように設定しました。

####投稿者コメント
単純なミスですが自分のエラーは公開して、同じ間違いしないように十字架を背負うことにします、、、

####My Profile
プログラミング学習歴３ヶ月目のアカウントです！
プログラミングスクールで学んだ内容や自分が躓いた箇所等のアウトプットの為に発信しています。
また、プログラミング初学者の方にわかりやすく、簡潔にまとめて情報共有できればと考えています。
もし、投稿した記事の中に誤り等ございましたら、コメント欄でご教授いただけると幸いです。
全く役に立たない小ネタ(Java)

変数定義時に自身を参照できる  

```java
	static String foo = foo = "ABCD";
	String bar = bar = "ABCD";
	void hoge() {
		String baz = baz = "ABCD";
	}
```


実行結果(IDEONE)  
https://ideone.com/48OXMp
ネットワーク上のサービス

UPD(Uder Datagram Protocol)
通信プロトコルのひとつで、速度重視

TCP
安全性重視

HTTP（Hyper Text Transfer Protocol）
Webページの転送に利用するプロトコル。

FTP(File Transfer Protocol)
ファイル転送サービスに利用するプロトコル。

NTP(Network Time Protocol)
コンピュータの時刻合わせを行うプロトコル。

Telnet
他のコンピュータにログインして、遠隔操作を行う際に使うプロトコル。
PHAssetから動画データを取り出して再生する

# はじめに
今回の記事では`PhotoKit`を使って取得した`PHAsset`オブジェクトより動画データを取り出し、再生する方法について紹介します。
ざっくりとした手順は次のような感じです！
1. `PhotoKit`を使って`Photo Library`よりアセットデータを取り出す
2. `PHImageManager`を使って動画データを取り出す
3. 取り出した動画データを`AVPlayerLayer`に設定する

完成イメージは次のような感じです！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551042/ee1ea2a5-bf49-59ee-f723-c9355c0f536a.gif" width="300" />


全体のソースコードは次です！
https://github.com/h-taro/PhotoApp/tree/fce3da609fc8ded949d09b9cc77639b47d0f3720


# 環境
`Xcode 12.5.1`
`Swift 5.4.2`
`macOS Big Sur 11.5.2`

# 具体的な実装方法
今回の肝となる箇所は次のコードです！

```swift:AssetViewController.swift
@IBAction func playVideo(_ sender: Any) {
    if playerLayer != nil {
      playerLayer?.player?.play()
    } else {
      let options = PHVideoRequestOptions()
      options.deliveryMode = .automatic
      PHImageManager.default().requestPlayerItem(forVideo: asset, options: options) { playerItem, _ in
        guard let playerItem = playerItem else {
          fatalError("playerItem is nil")
        }

        // playerItemに動画データが含まれています
        let player = AVPlayer(playerItem: playerItem)
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.videoGravity = .resizeAspect
        playerLayer.frame = self.view.layer.bounds
        self.view.layer.addSublayer(playerLayer)
        playerLayer.player?.play()
        self.playerLayer  = playerLayer
      }
    }
  }
```


# 参考リンク
https://developer.apple.com/documentation/photokit/browsing_and_modifying_photo_albums
Snowflakeのクレジットの残高を見る方法

Snowflakeのクレジットがあとどれくらい残っているのかを確認する方法が公式ドキュメントからではわからなかったのでメモ。

例えば過去10日の一日の終わりの残高を知りたければ以下のSQLで取得できます。`CAPACITY_BALANCE`が一日の終わり時点での残高です。下の例では2021/08/15の残高は$42.50になっていることが確認できます。

もし、繰越があれば`ROLLOVER_BALANCE`に記載され、残高は`CAPACITY_BALANCE`と`ROLLOVER_BALANCE`の合計になります。

```sql
select * from SNOWFLAKE.ORGANIZATION_USAGE.REMAINING_BALANCE_DAILY order by date desc limit 10;
+-------------------+-----------------+------------+----------+--------------------+------------------+-------------------------------+------------------+
| ORGANIZATION_NAME | CONTRACT_NUMBER | DATE       | CURRENCY | FREE_USAGE_BALANCE | CAPACITY_BALANCE | ON_DEMAND_CONSUMPTION_BALANCE | ROLLOVER_BALANCE |
|-------------------+-----------------+------------+----------+--------------------+------------------+-------------------------------+------------------|
| COMPANY1          | 12345678        | 2021-08-15 | USD      |               0.00 |            42.50 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-14 | USD      |               0.00 |            42.93 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-13 | USD      |               0.00 |            42.98 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-12 | USD      |               0.00 |            54.84 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-11 | USD      |               0.00 |            61.30 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-10 | USD      |               0.00 |            77.17 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-09 | USD      |               0.00 |            83.87 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-08 | USD      |               0.00 |            83.93 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-07 | USD      |               0.00 |            83.99 |                          0.00 |                0 |
| COMPANY1          | 12345678        | 2021-08-06 | USD      |               0.00 |            84.05 |                          0.00 |                0 |
+-------------------+-----------------+------------+----------+--------------------+------------------+-------------------------------+------------------+
```

## 注意
- 公式ドキュメントにも書いてありますがデータ反映まで24時間の遅れがあります。
- 公式ドキュメントにはこのビューにアクセスができるのはORGADMINロールと書いてあるのですが自分の環境ではACCOUNTADMINロールでしかアクセスできませんでした。`show grants`で見てみるとたしかにACCOUNTADMINロールになってました。誰かが変えたのかな？もしORGADMINでアクセスできない場合にはACCOUNTADMINで試してみるか`show grants on SNOWFLAKE.ORGANIZATION_USAGE.REMAINING_BALANCE_DAILY;`で誰に権限があるのかを確認してみましょう。



## 公式ドキュメント
https://docs.snowflake.com/ja/sql-reference/organization-usage/remaining_balance_daily.html
電子メールプロトコル

電子メールを送信するプロトコル(SMTP)
ポスト投函から相手の郵便受けに届けるまでの役割

電子メールを受信するプロトコル(POP)
郵便受けから取り出す

POPは受信者のパソコンにダウンロードされるのに対し、IMAPはメールごとに受信や破棄を選択することができる。
NATとIPマスカレード

LANの中ではプライベートIPアドレスを使うのが一般的、外のネットワークとやり取りするためにグローバルIPが必要。

NAT
グローバルIPとプライベートIPを１対１で結びつけて相互に交換。グローバルIP個数分のみインターネット接続可能。

IPマスカレード（NAPT）
グローバルアドレスに複数のプライベートIPアドレスを結びつけて、１対複数の変換を行う。１つのグローバルアドレスでも複数のコンピュータが同時接続可能。


ファイアウォール
LANの中と外を区切る壁
【画像処理解説】ポスタリゼーション（Javaソース付き）

#はじめに
画像処理を簡単に解説していきます。
下部にはJavaでのソースコードも載せているのでぜひご参照ください。
不定期にはなりますが、随時更新していく予定です。

#ポスタリゼーションとは？
階調変更アルゴリズムであり、色の階調を変更する画像処理です。
一般的な画像は0から255の256階調で成立しています。
これをルックアップテーブル（LUT）を用いて、任意の階調数に変更します。

似たような処理として減色処理があります。
減色処理では、階調を減らすというよりも、画像情報を残しつつ情報量を減らすことが目的となります。
ポスタリゼーションは画像を加工してアートみたいにできるのが特徴ですね。

#LUTとは？
画素値変換用の参照テーブルのことです。
ポスタリゼーションの場合、階調数を$t$とするとLUTは以下の式で定義されます

```math
lut(i) = \left[\left[\frac{i\times t}{256}\right]\times\frac{255}{t-1}\right]
```

階調数が4の時、画素値100は85に、画素値200は255に変換されます。
いろいろ試してみると面白い画像が生まれるかもしれませんね。

#アルゴリズム
1. 上記の式を用いてLUTを生成する。
2. 画像をラスタスキャンし、各画素においてLUTによる値変換を行う。

#ポスタリゼーションの例
元画像（カラー画像）
![imori_256x256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655420/7c01d0e9-33e1-cdae-eb3a-77a57b9ef27b.png)


結果画像（ポスタリゼーション画像）
![out06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655420/6595c3ce-b4c4-f70a-09a4-43b37eae32dc.png)


#ソースコード
```Color.java
public static SImage posterization(SImage oriImg, int tone) {
    // 階調数を2から128に制限する
    if (tone < 2)
        tone = 2;
    else if (tone > 128)
        tone = 128;

    // LUTの生成
    int[] lut = new int[256];
    for (int i = 0; i < 256; i++)
        lut[i] = (int) ((int) (i * tone / 256.0) * 255.0 / (tone - 1));

    // ポスタリゼーション画像用を生成
    var posterImg = new SImage(oriImg.width(), oriImg.height(), oriImg.channel);

    // グレースケール画像の場合
    if (oriImg.channel == 1) {
        // 画像をラスタスキャン
        for (int y = 0; y < oriImg.height(); y++)
            for (int x = 0; x < oriImg.width(); x++) {
                // 値を取得
                int v = oriImg.getGray(x, y);

                //LUTで変換した値をを出力画像にセット
                posterImg.setGray(x, y, lut[v]);
            }

        // RGBカラー画像の場合
    } else if (oriImg.channel == 3) {
        // 画像をラスタスキャン
        for (int y = 0; y < oriImg.height(); y++)
            for (int x = 0; x < oriImg.width(); x++) {
                // 値を取得
                int[] rgb = oriImg.getRGB(x, y);

                // LUTを用いて変換
                int[] newRgb = new int[]{lut[rgb[0]], lut[rgb[1]], lut[rgb[2]]};

                //LUTで変換した値をを出力画像にセット
                posterImg.setRGB(x, y, newRgb);
            }

        // アルファチャネルを持つ場合
    } else {
        // 画像をラスタスキャン
        for (int y = 0; y < oriImg.height(); y++)
            for (int x = 0; x < oriImg.width(); x++) {
                // 値を取得
                int[] argb = oriImg.getARGB(x, y);

                // LUTを用いて変換
                int[] newRgb = new int[]{lut[argb[0]], lut[argb[1]], lut[argb[2]], lut[argb[3]]};

                //LUTで変換した値をを出力画像にセット
                posterImg.setARGB(x, y, newRgb);
            }

    }
    return posterImg;
}
```
[8/13 GitHub仕様変更]パスワードをパーソナルアクセストークンに変更

# 問題
githubからcloneしてみるとエラーが出ます

```bash:
$ git clone https://github.com/xxxxxxxx/repository.git
Cloning into 'repository'...
remote: Password authentication is temporarily disabled as part of a brownout. Please use a personal access token instead.
remote: Please see https://github.blog/2020-07-30-token-authentication-requirements-for-api-and-git-operations/ for more information.
fatal: unable to access 'https://github.com/username/repository.git/': The requested URL returned error: 403
```

上記のようにエラーが起きます。
パスワードをパーソナルアクセストークンに変更してくださいということなので従います。

#解決方法

##パーソナルアクセストークン

以下のドキュメントを参考に取得します。
https://docs.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token

###取得手順
1.Developer settings（https://github.com/settings/tokens ）をクリック
2.[Generate new token]をクリック
3.トークンにわかりやすい名前をつけます
4.権限を選択
5.[Generate token] をクリック
6.トークンをコピー　(このトークンがパスワードの代わりになります)
7.パスワードの代わりにトークンを使用

#まとめ
急に仕様が変更されていたので焦りました。
TCP/IPを使ったネットワーク

IPアドレスは、32ビットの数値で表される。
８ビットずつに区切って、10進数にし、.でつなぐ。
ex:192.168.1.3

サブネットマスク
IPアドレスのどこからどこまでをネットワークアドレスとみなすか指定する。
ex: 255.255.254.0の場合、2進数にすると11111111 11111111 11111110 00000000　右から９個分がホストアドレス　1の部分がネットワークアドレス

ネットワークアドレス
IPアドレスを2進数に変換し、サブネットマスクの1の部分はそのまま残し、残りのホストアドレスを0にして再度10進数に変換
GitLab(またはGitHub) Issueを用いた開発手順

[GitLabでmasterへのコミットを防ぐ - Qiita](https://qiita.com/no-use-kuro/items/810895688d508f699ae9) をおこなったうえで、[GitHub Issueを用いた開発手順](https://zenn.dev/ogakuzuko/articles/2250f7c7331106) と同様、手順を整理したもの。

## Issueの作成
1. GitLab上の該当プロジェクトのタブからIssuesを選択する。
2. New issueを選択する。
3. Issueのタイトルと内容を記入してCreate issueを押す。（Issueが追加される）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/270c719a-4cc1-2d2f-78af-979407ca1515.png)


## Issueを用いた修正手順

### 登録されているIssueから新たにブランチを作成する

`Create merge request` ボタンから作成できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/11d33b5f-6738-cc25-906e-310da160fa8c.png)

### 作成したブランチに移動する

### 修正する

コミット `git commit -m "refs #issue番号 コミットメッセージ `

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/8c3627ce-46b7-7099-6364-94c7d2d6b534.png)

対応するissue番号を付け加えることで、そのIssueに関するコミットだということを関連付けることができる。

### 作業が完了したらgit pushする

作業が全て完了したらMerge Request（Pull Request）を作成し、リモートのmainブランチにmergeする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/d1356102-fb1e-c901-a4f6-3e85756066db.png)

上の通り、`Merge`.。


## まとめ

[GitLab(またはGitHub)でIssue Templateを作る - Qiita](https://qiita.com/e99h2121/items/2690103fce58cdbdc714)

https://qiita.com/e99h2121/items/e9941211d9780d5b68c9


上と合わせて運用できるとよし。
ひとまず簡単に以上です。
東京駅周辺における気象予報値をCSVに保存し、Webサイトで閲覧できるようにしたので、これをPandasで読み込んで可視化してみる。

# はじめに

先日、島根県松江市の気象予報値をCSVで取得できるようにしたという以下のような記事を書いたら、東京のデータを見てみたいという要望があったので、同じように東京の気象予報値も取得できるようにしてみた。

https://qiita.com/mix_dvd/items/133310a3ac669b304b43

CSVを直接ダウンロードしたい方は以下のリンクをご利用下さい。

[tokyo.csv](https://blueomega.jp/20210812_gRfm/tokyo.csv)

# 可視化

詳細は前述の記事を参照して頂くこととして、早速以下のようなスクリプトを作成して実行してみる。

```py:
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv("https://blueomega.jp/20210812_gRfm/tokyo.csv")
df.index = pd.to_datetime(df.pop("datetime"))

df.TMP.plot(figsize=(15,5))
plt.show()

df.DSWRF.plot(figsize=(15,5))
plt.show()
```

実行結果。

![Unknown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114240/72bcd6ba-01e1-2c9c-9867-bc6cc9c0b8fa.png)

![Unknown-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114240/856c84ad-ca06-82ad-9b49-018bfafda733.png)

できた。

データを作成したのが16日だから2日後の18日の予報値が入っています。
毎日23:30にデータが更新されるので、明日同じスクリプトを実行すると19日の予報値が入っているはずです。

もし他の都市のデータが欲しいという方や違う期間のデータを同じように取得したいという方がおられましたらご相談下さい。
無償ではないかもしれませんが、ご協力できるかもしれません。

これからしばらく記録してみて、実績値と比較しようかな。
現在のレンタルサーバーがCentOSかどうかを判断する方法

レンタルサーバーで、OSはLinuxと明示してあっても、どのディストリビューションかは明示されていない場合がある。
そんなとき、CentOSかどうかを調べる方法がわかったので、残しておきたい。

## 手順１　SSH接続する
レンタルサーバーにより方法は様々。
MacOSの場合はターミナル、Winの場合はTeraTermを使うとよい。

## 手順２　prmコマンドを使う

下記のコマンドでリストを表示する

```
@cat rpmlist.txt
```

その中に「centos-」で始まる記載があったら、それはCentOSです。