OmniAICreator/Qiita-1.07M huggingface dataset:
brew コマンドで unknown or unsupported macOS version: :dunno (MacOSVersionError) がでました

brew コマンドを実行したら `unsupported macOS version` というエラーがでました。

```zsh:brewコマンド
% brew doctor
Traceback (most recent call last):
	11: from /usr/local/Homebrew/Library/Homebrew/brew.rb:31:in `<main>'
	10: from /usr/local/Homebrew/Library/Homebrew/brew.rb:31:in `require_relative'
	 9: from /usr/local/Homebrew/Library/Homebrew/global.rb:80:in `<top (required)>'
	 8: from /usr/local/Homebrew/Library/Homebrew/vendor/portable-ruby/2.6.3_2/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'

略

	 3: from /usr/local/Homebrew/Library/Homebrew/os/mac.rb:28:in `version'
	 2: from /usr/local/Homebrew/Library/Homebrew/os/mac/version.rb:33:in `from_symbol'
	 1: from /usr/local/Homebrew/Library/Homebrew/os/mac/version.rb:33:in `fetch'
/usr/local/Homebrew/Library/Homebrew/os/mac/version.rb:33:in `block in from_symbol': unknown or unsupported macOS version: :dunno (MacOSVersionError)
```
brew コマンドが古くなっているかもしれません。
`brew upgrade` や `brew doctor` でも失敗するので困りました。

# brew update-reset する
`brew update-reset` はヘルプによるとすべてのリポジトリを最新にしてくれるそうです。

```zsh:
brew update-reset
```

こちらを実行の後、`brew doctor` ほかコマンドも実行できるようになりました。
やったね(☝ ՞ਊ ՞)☝

# 参考

> Homebrew fails on MacOS Big Sur - Stack Overflow 
https://stackoverflow.com/questions/64821648/homebrew-fails-on-macos-big-sur
MySQLのrootパスワードを強制的に変更する手順

# ●はじめに
MySQLのrootパスワードを忘れてしまった時の対処法を記載します。
セキュリティ的にはちょっぴり微妙なので、本番環境等では推奨してません。。

## 1.認証の無効化

```bash
# パスワード認証を求めない設定を入れる
vi /etc/my.cnf

# 以下を記入
[mysqld]
skip-grant-tables

# 設定の反映
systemctl restart mysqld
```
・[mysqld]の文字列は、デフォルトで書かれていない場合のみ記述。あれば記述不要

## 2.パスワードの変更

```bash
# mysqlにログイン
mysql

# 権限の反映
mysql> flush privileges;

# パスワードを任意のパスワードに変更
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';
mysql> quit
```
・password の部分に、自分で決めたパスワードを記述

## 3.設定の反映
```bash
# パスワード認証無効化の一文を削除
vi /etc/my.cnf

# 手順1で書いた「skip-grant-tables」を削除
# 設定の反映
systemctl restart mysqld

# ログイン確認
mysql -u root -p

Enter password:password
```
ATC対応速度計を動かしてみる

地下鉄丸の内線の02系の速度計と思われるATCメーターを動かしてみましょう
# 参考サイト
今回は、以下を参考にしました。
* CS-ATC系対応速度計をいろいろ調べた。
http://blog.livedoor.jp/stop_pattern/archives/speedometer.html
* 地下鉄用の速度計でLチカ！
https://elchika.com/article/d4b69ae0-d6d2-4c7a-978e-ebd0a2681b42/

## 速度計
書泉や東急ハンズで販売されていた速度計になります。
速度計は、電流制御の為、抵抗を挟むことで電圧に応じてメーターが動くようになります。
下記電流計と同じ手法で動かすことができます。

https://qiita.com/usashirou/items/4a57c976fb4771e29ca8

![DSC_0513 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/a6a6cd1e-4e49-8114-d000-c0f1686d2e76.jpeg)
## ステーの製作
ステーを3Dプリンターで製作しました。
![DSC_0506 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/e988f1e7-c2d5-4054-0c1c-87facb428ab6.jpeg)
3Dプリンターのサイズ制限の為に、カットしています。
## 組立
製作したステーにメーターを取り付けました。
![DSC_0525 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/02b01726-238b-18cd-4a58-0627b33c1ec5.jpeg)
## ハーネスの製作
速度計とマイコンをつなぐハーネスを製作します。

https://qiita.com/usashirou/items/6bfd3805519f9160aa7d

![DSC_0527 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/e80b9633-cad9-a10d-85a8-7919ef40bde1.jpeg)
# マイコンの準備
今回はESP32を使用します。
ESP32には2つのDACがあり、DACと無線機能が使えるから選択しましたが
メータを3種類使用する為、途中からPWMに変更しています。
上記「電流計をスピードメーターとして動かしてみる」を参考にしてください。
このため通常の使用であればPWMやAnalogWriteが使える普通のマイコンの方が良いといえます。
本章ではこの後、Raspberry Pi Picoを使用したものを使用しています。
# 制御抵抗の追加
ESP32のDACと速度計の間に、抵抗を挟みます。
抵抗値は確定していない為、可変抵抗を入れることをお勧めします。
今回は、速度計の規定電流から２KΩの可変抵抗を使っています。
# プログラム
プログラムはESP32のdacWriteを使用します。

```
/*
   Copyright (c) 2018, circuits4you.com
   All rights reserved.

   ESP32 DAC - Digital To Analog Conversion Example
*/

#define DAC1 26
int Value = 255; //255= 3.3V 128=1.65V

void setup() {
  Serial.begin(115200);
}

void loop() { // Generate a Sine wave
  dacWrite(DAC1, 255);
}
```
![DSC_0529 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/3b85679f-1dd5-5aa9-8daa-7b5c9d004723.jpeg)

以上で速度計として使用可能となりました。
# ATCメータを使えるようにする
次はATCメータとして使えるようにしましょう。
ATCメータは背面の端子台に２４Vを入力することで使用可能です。
しかし、24Vを直接マイコンでは制御できません。
また、0Vにしても同じです。（大きな電流は制御できません）
このため、制御できる部品を使用する必要があります。
# 大きな電圧や電流を制御するには
大きな電圧や電流扱えるリレーやトランジスタがあります。
これらを使えば24Vの出力、入力を扱えます。
ただし、これらを扱うには1個ずつON-OFFの制御が必要となるものが多いと思います。
02系のATCの表示種類は20個程度です。
ほかに、速度計などを扱おうとすると普通のマイコンではGPIOの数が足りません。
この為にGPIOの数の多いマイコンを探す必要があります。
今回はRaspberryPi Picoを使用しました。
# RaspberryPi Picoで24V制御
RaspberryPi Picoに２４Vが制御可能なトランジスタアレイを接続しコントロールします。
今回選定したのは東芝のトランジスタアレイTBD62083とTBD62783です。
これにより24Vの出力と入力を制御できるようになります。
RaspberryPi Picoを選定したのはGPIOの数が多いうえに、価格が安いためです。
TBD62083とTBD62783は24VとGNDを切り替えることでどちらも同じ基板で使用可能としました。
# 製作した基板
![DSC_0172 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/ecf95b97-9318-3168-bf5e-70392565e578.jpeg)
# プログラム
各GPIOをHIGH/LOWにすることで使用可能なものとなっています。
# ATC用ハーネスの準備
24Vを出力、GNDを入力するピンをそれぞれ用意していきます。
今回は８Ｃhのトランジスタアレイを３個扱うため４ピンのコネクタを6個使用しています。
メーター側の端子ははいつも通り絶縁被覆付圧着端子を使用しています。
この辺りは他の速度計と同じにしています。
![DSC_0528 (2).JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/4e7c1b86-20fa-d084-d319-447d08e5ea14.jpeg)
以上でATCメータを動かせるようになったと思います。
次はこれをBVEで使えるようにしましょう。
Ruby で Natural Language API を叩く

# ゴール
以下を Ruby から叩く。

https://cloud.google.com/natural-language?hl=ja

# API 呼び出すための準備
[ドキュメント](https://cloud.google.com/natural-language/docs/setup?hl=ja)見ながら「SDK と認証をテストする」をやってみる

基本的には、Google Cloud Console からポチポチするだけ
Cloud SDK のインストールで pyenv を入れるところ少しハマった
個人記事ではなく[ドキュメント](https://github.com/pyenv/pyenv#installation)見ましょう（自戒）

# Gem から API を叩く
- 前提
    - [エンティティ分析で試す](https://cloud.google.com/natural-language/docs/analyzing-entities?hl=ja)
    - [リクエスト・レスポンス仕様](https://cloud.google.com/natural-language/docs/reference/rest/v1/documents/analyzeEntities?hl=ja)
-  ドキュメントに倣う
    -  [ドキュメント](https://cloud.google.com/natural-language/docs/reference/libraries?hl=ja)には、[google-api-client](https://github.com/googleapis/google-api-ruby-client) を使うよう書かれている
    -  API キーを使うので、[Google Cloud Console から発行](https://cloud.google.com/docs/authentication/api-keys?hl=ja)
        -  諸々決まったら、利用制限は設定した方がいい

```ruby
require 'google/apis/language_v1'

# Doc: https://googleapis.dev/ruby/google-api-client/v0.23.6/Google/Apis/LanguageV1/CloudNaturalLanguageService.html
service = Google::Apis::LanguageV1::CloudNaturalLanguageService.new
service.key = '...'

# リクエスト仕様を確認しつつ設定
attrs = {
  document: {
    type: 'PLAIN_TEXT',
    language: 'ja',
    content: 'テスト',
  },
  encoding_type: 'UTF8'
}

# Doc: https://googleapis.dev/ruby/google-api-client/v0.23.6/Google/Apis/LanguageV1/AnalyzeEntitiesRequest.html
request = Google::Apis::LanguageV1::AnalyzeEntitiesRequest.new(attrs)

# Doc: https://googleapis.dev/ruby/google-api-client/v0.23.6/Google/Apis/LanguageV1/AnalyzeEntitiesResponse.html
response = service.analyze_document_entities(request)
response.entities[0].type
response.entities[0].salience
response.entities[0].metadata['wikipedia_url']
...
```

# それ以外のやり方
- 他にも [Gem](https://github.com/googleapis/google-cloud-ruby/tree/master/google-cloud-language) がある
    - こっちはサービスアカウントでの認証が出来た
    - ダウンロードした json パスの環境変数を読み込んでくれるので、別途 API キーを指定する必要がない

```ruby
# Doc: https://googleapis.dev/ruby/google-cloud-language-v1/latest/index.html
require "google/cloud/language/v1"

# Doc: https://googleapis.dev/ruby/google-cloud-language-v1/latest/Google/Cloud/Language/V1/LanguageService/Client.html
# .configure から、リトライ・タイムアウト等設定できるっぽい
client = ::Google::Cloud::Language::V1::LanguageService::Client.new

# リクエスト仕様を確認しつつ設定
attrs = {
  document: {
    type: 'PLAIN_TEXT',
    language: 'ja',
    content: 'テスト',
  },
  encoding_type: 'UTF8'
}

# Doc: https://googleapis.dev/ruby/google-cloud-language-v1/latest/Google/Cloud/Language/V1/AnalyzeEntitiesRequest.html
request = ::Google::Cloud::Language::V1::AnalyzeEntitiesRequest.new(attrs)

# Doc: https://googleapis.dev/ruby/google-cloud-language-v1/latest/Google/Cloud/Language/V1/AnalyzeEntitiesResponse.html
response = client.analyze_entities(request)
```
【vSphere 7】VCSAのインストール手順　画面遷移

![000017.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/73434de4-67a1-f50d-2b96-6e2a869c88a4.jpeg)

![000018.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/ebdc2af6-3f04-ffe9-f33b-6ac62a01a94c.jpeg)

![000019.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/c37a1f3a-d735-8b7f-da5d-ccb3a9d86725.jpeg)

![000021.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/34095359-bb3d-8541-122d-44ffe2d90b77.jpeg)

![000022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/5cab672e-1030-4dd3-6ed2-e34082770ae7.jpeg)

![000023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/26cebf90-a26e-3fb2-e980-d34b0648b751.jpeg)

![000024.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/cb3e34ff-1f58-751e-7536-3760c4d4efb0.jpeg)

![000025.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/fdeedb13-8d46-51bc-8d1f-2367c9d4ac63.jpeg)

![000031.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/2f3bc0cf-9020-a9f1-32f0-563d3e57fdcb.jpeg)

![000032.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/16d70ca4-9e32-28a2-568c-11164e2d995e.jpeg)

![000033.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/7633df6d-fc90-4804-00cf-03f0f783b682.jpeg)

![000034.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/b4cd8c0f-2d58-8e85-6f05-7bde9c2ccf4d.jpeg)

![000035.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/93233215-05f6-7e08-cbc5-7e408a19c950.jpeg)

![000036.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/6a1dab31-6283-6941-2acf-f0515a7a964f.jpeg)

![000037.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/dc09fd46-1c25-e788-324e-bb7964903191.jpeg)

![000040.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/3fd5c0ed-205c-41c7-c371-a37b24b5e165.jpeg)

![000042.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/7108abab-5f57-a1ac-530e-b603b027d263.jpeg)

![000044.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/d7c280c5-c60d-b683-61ff-43fe2134f276.jpeg)

![000046.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/2c336dba-8e2f-6412-cdc7-170eed225fe2.jpeg)

![000047.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/4a497f5c-5e53-e03b-5440-c5c9e512d3dd.jpeg)

![000049.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/0d541f19-cbc8-8824-5c44-b0f32df87fc0.jpeg)

![000050.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/4eee1356-343a-cc90-b626-378a0773ac11.jpeg)

![000052.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/7ca15630-24b2-8768-9c93-f9405ec0e698.jpeg)

![000053.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689747/2365af84-8179-9240-7863-c95db896f8d7.jpeg)
Spring Batch Chunk型実装方法まとめ

### Chunk型実装で詰まったポイント

#### 複数のレコードをまとめて処理したい場合

Chunk型で実装する場合、以下のような流れで実行される。
そのため、ItemProcessorにおいて、Chunkのコミットインターバル数分だけまとめて処理を行う（貯めておいてまとめてAPI送信など。）といったことができない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472670/9d3131fe-6645-7583-dcd6-919622531ecf.png)

##### 解決策①：ItemWriteListenerクラスのbeforeWrite(List<? extends S> items)メソッドを利用する。
##### 解決策②：ItemWriterをOverrideした別クラスを作成し、itemsを受け取りつつ、処理して、itemsを書き換え、書き換えたitemsでDBに書き込む。
##### 解決策③：該当JobのみTaskletで作成する。※前提条件は一時テーブル→一時テーブルの処理であること。
SQLアンチパターンを読んで

## 読んだ本
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472670/932ffea4-f907-ffe4-c852-208856e05098.png)

---
## 2章 Naive Trees(素朴な木)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472670/b6a3e14d-7aee-6848-4960-df5edd669e01.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472670/1276c883-cb09-cf39-fe5e-e3b0a1d22403.png)

→深さに制限がない場合、ノードの数（スレッドのコメント数など）を数える場合など対応できない場合がある。

---
## 代替ツリーモデルを使用する
#### 経路列挙
親からのパスを格納する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472670/f0270ca4-2baf-b7ee-de46-5a3f493c4159.png)

---

#### 閉包テーブル
ツリー全体のパスを別のテーブルに格納する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/472670/b41075bd-87d1-da9c-e5e5-b1df7c9852fc.png)

---
## 16章 Poor Man's Search Engine(貧者のサーチエンジン)

```SQL:LIKE句を利用した中間一致検索
SELECT * FROM Bugs WHERE description LIKE '%crash%';
```

以下で中間・後方一致検索の性能を高められる。
基本的な解決策：ベンダー固有の全文検索エンジン

```SQL
CREATE TABLE Bugs (
  bug_id SERIAL PRIMARY KEY,
  summary VARCHAR(80),
  description TEXT,
  ts_bugtext TSVECTOR
  -- 他の列. . .
);
```
```SQL
CREATE TRIGGER ts_bugtext BEFORE INSERT OR UPDATE ON Bugs
FOR EACH ROW EXECUTE PROCEDURE
  tsvector_update_trigger(ts_bugtext, 'pg_catalog.english', summary, description);
```

```SQL:GINインデックス
CREATE INDEX bugs_ts ON Bugs USING GIN(ts_bugtext);
```

```SQL
SELECT * FROM Bugs WHERE ts_bugtext @@ to_tsquery('crash');
```
nginxでSSLクライアント証明書による認証を行う

nginxにてクライアント証明書による認証を行う場合は [ssl_verify_client](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_verify_client)の設定値にて処理することが可能。

いくつかのパターンによる実装を下記に列挙する。

## クライアント証明書による認証を必須にする

`on`で設定をすれば、SSLクライアント証明書による認証が行われる。
`/path/to/ca.crt` で許可されている証明局となるとクライアント証明書が紐付いているかを確認している。

```
server {
    ....
    ssl_verify_client on;
    ssl_client_certificate /path/to/ca.crt;
    ....
}
```

認証局にて失効した証明書を拒否するには `ssl_crl` を設定する

```
server {
    ....
    ssl_crl /path/to/crl.pem;
    ....
}
```

## 証明書がある場合のみnginxにて認証を行う
`optional` で設定をすれば、証明書がある場合のみSSLクライアント証明書による認証が行われる。
証明書がないリクエストは認証失敗とならない。証明書がないリクエストは `$ssl_client_verify`変数は`NONE`となる

```
server {
    ....
    ssl_verify_client optional;
    ssl_client_certificate /path/to/ca.crt;
    ....
}
```

## SSLクライアント証明書を要求するが、認証はしない

`optional_no_ca`と`error_page`でフォールバックすることで実現する。
`optional_no_ca`は証明書が信頼されていない時は認証エラーが発生しないが、それ以外の証明書周りのエラーは発生する。
nginxのSSL認証はopensslに依存しているため、エラーの種類としてすべてを把握するのは難しいが、
少なくとも期限切れの証明書でリクエストした場合はnginxにて495エラーが発生した。
そのため`error_page`でフォールバックについても設定が必須となる。フォールバックする際は`=` をつけるとプロキシ先のレスポンスコードが優先されるようになる。
(495エラー全てでフォールバックするので、`optional`で設定しても問題なさそう)

```
server {
    ....
    ssl_verify_client optional_no_ca;
    ssl_client_certificate /path/to/ca.crt;

    error_page 495 = @fallback;

    location @fallback {
        proxy_pass http://$your_domain;
    }
    ....
}
```

## アプリケーション側にてクライアント証明書を受取り、追加の認証処理を行う場合

mTLSでいう`Certificate-Bound Access Tokens`などを実装したい場合が該当する。
nginxのL5レイヤーにて認証処理をしつつ、プロキシ先に認証結果や証明書情報を渡す必要がある。
`on`で設定を行い、`$ssl_client_verify` や `$ssl_client_escaped_cert`などをヘッダ情報に付与した上で、アプリにproxyするようにする。

参考: [SSLクライアント証明書の変数周り](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_verify)

```
server {
    ....
    ssl_verify_client on;
    ssl_client_certificate /path/to/ca.crt;

    location @fallback {
        proxy_pass http://$your_domain;
        proxy_set_header X-Client-Verify $ssl_client_verify;
        proxy_set_header X-Client-Escaped-Cert $ssl_client_escaped_cert;
    }
    ....
}
```

`$ssl_client_cert` はdeprecatedになっているため、今後は使わない方が良さそう。

## おわりに
仕事で設定することがあったので、忘れないようにメモをした。
`Certificate-Bound Access Tokens`あたりとかの実装イメージも少し湧いた。アプリ側の処理はトークン発行時の証明書とfingerprintが一致しているか、とかになると思われる。
DataFrame型のデータのカラム名が変更できない場合に確認したいこと

## 今回の内容
二つのDataFrame型のデータそれぞれに設定されている日時カラムをもとにマージしたかったのですが、
マージをするためにデータを加工する段階でカラム名が変更できず詰まってしまったので備忘メモとして残したいと思います。

## 結論
今回の原因を先に記載しますと、DataFrame型のpandas.Indexはimmutableなのでインデックスとして設定しているカラム名をrenameで変更しようとしてもできません。
そのため、インデックスに設定しているカラムを変更する場合は一度インデックスを削除する必要がありました。

## 動作環境
・Google Colaboratory
使用言語&バージョン
・Python 3.7.13
・numpy 1.21.5
・pandas 1.3.5
・matplotlib 3.2.2など

## 使用データ
[こちら](https://www.data.jma.go.jp/gmd/risk/obsdl/)の気象庁の過去の気象データ・ダウンロードのページから2021年の横浜の平均気温のcsvファイルをダウンロードしGoogle Driveにアップロードして使用しました。

## 検証
``` python:サンプルコード

# 2021年の平均気温データファイルの取得
drive_file.GetContentFile("横浜の平均気温.csv")

average_temperature = pd.read_csv('横浜の平均気温.csv', encoding="shift-jis", header=1)
print(average_temperature.head())

#実行結果
       DATE  平均気温(℃)
0       NaN      NaN
1  2021/1/1      6.0
2  2021/1/2      6.5
3  2021/1/3      5.0
4  2021/1/4      6.7

average_temperature.dropna(inplace=True)
print(average_temperature.head())

# 試しにDATEをindexに設定する
a_temp = average_temperature.set_index("DATE")
print(a_temp)

#実行結果
            平均気温(℃)
DATE               
2021/1/1        6.0
2021/1/2        6.5
2021/1/3        5.0
2021/1/4        6.7
2021/1/5        6.9
...             ...
2021/12/27      3.6
2021/12/28      4.5
2021/12/29      5.8
2021/12/30      7.9
2021/12/31      3.6

[365 rows x 1 columns]

# renameを実行
a_temp.rename(columns={"DATE": "年月日"},
          inplace=True)
print(a_temp)

#実行結果
            平均気温(℃)
DATE               
2021/1/1        6.0
2021/1/2        6.5
2021/1/3        5.0
2021/1/4        6.7
2021/1/5        6.9
...             ...
2021/12/27      3.6
2021/12/28      4.5
2021/12/29      5.8
2021/12/30      7.9
2021/12/31      3.6

[365 rows x 1 columns]
```

カラム名が変更できていない

## やってみたこと
コピーしてからリネームする
→コピーしたはずがNULLになってしまう

## 解決方法
一旦インデックスを削除してから変更する
``` python:サンプルコード
# 一度インデックスをリセットしてからrenameする
a_temp =average_temperature.reset_index(drop=True)
a_temp.rename(columns={"DATE": "年月日"},
          inplace=True)
print(a_temp)

# 実行結果
            年月日  平均気温(℃)
0      2021/1/1      6.0
1      2021/1/2      6.5
2      2021/1/3      5.0
3      2021/1/4      6.7
4      2021/1/5      6.9
..          ...      ...
360  2021/12/27      3.6
361  2021/12/28      4.5
362  2021/12/29      5.8
363  2021/12/30      7.9
364  2021/12/31      3.6

[365 rows x 2 columns]
```

無事カラム名の変更ができました。
もしかしてインデックスが設定されている場合変更できないのではと思い公式ドキュメントを調べてみたところ、しっかりimmutableだと記載されていました。
>「Immutable sequence used for indexing and alignment. The basic object storing axis labels for all pandas objects.」

やっぱり公式ドキュメントを読むことは大事ですね。

## 参考
[Pandas DataFrame インデックスを削除](https://www.delftstack.com/ja/howto/python-pandas/pandas-remove-index/)
[公式ドキュメント](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Index.html)
Nginxでディレクトリに応じたリダイレクト処理

Nginxにリダイレクト処理を書くことは多々あるかと思います。Nginxはお手軽にconfファイルにリダイレクト処理を書くだけでとてもかんたんです。
例えば、https://onodera.com へのアクセスをすべてhttps://hogehoge.comにリダイレクトしたい場合はconfファイルに
```rewrite ^/(.*) https://hogehoge.com/ redirect;```
と書けばいいだけです。
シンプルなリダイレクトだと設定もシンプルなのですが、条件付きだとけっこう書き方がややこしかったりします。
実際に「このディレクトリ配下はリダイレクトせず、そのまま表示したい」みたいなことがありました。
具体的には、**「onodera.comの/newsと/blogsはリダイレクトさせず、それ以外はhogehoge.com　にリダイレクトしたい」**
というような内容です。

まずこう書けば行けるかなと思ったのですが、

```
if ($request_uri ！~ ^/news　&& $request_uri ！~ ^/blogs){
    rewrite ^/(.*) https://hogehoge.com/ redirect;
}
```

だめだった。

理由はこちら。

 <a href="https://qiita.com/ukitazume/items/ab1c929783e87227e466">Nginxで複数条件のIF文を書く方法がすごいｗ</a>

複数条件を書くのができないみたいです。

なので突貫工事的ではありますが、以下のような書き方をしました。
変数を使う方法。


```
set $flg 1;
if ($request_uri ~ ^/news) {
      set $flg 0;
}
if ($request_uri ~ ^/blogs) {
      set $flg  0;
}
if ($flg = 1) {
      rewrite ^/(.*) https://hogehoge.com/ redirect;
}
```
$flgの値に応じてリダイレクトするかしないかを判断させてます。

おわり。

質問あればtwitter経由で連絡ください。
Effective Java 第3版まとめ（項目1）

# 項目1.コンストラクタの代わりにstaticファクトリメソッドを検討する

## 例

```java
public class EffectiveJava1 {

    // コンストラクタ
    public EffectiveJava1() {
    }

    // staticファクトリメソッド
    public static EffectiveJava1 newInstance() {
        return new EffectiveJava1();
    }
}
```

## 長所

1. 名前を持つこと
1. その呼び出しごとに新たなオブジェクトを生成する必要がないこと
1. メソッドの戻り値型の任意のサブタイプのオブジェクトを返せる
1. 返されるオブジェクトのクラスは、入力パラメータの値に応じて呼び出しごとに変えられる
1. 返されるオブジェクトのクラスは、そのstaticファクトリメソッドを含むクラスが書かれた時点で存在する必要さえない

## 短所

1. publicあるいはprotectedのコンストラクタを持たないクラスのサブクラスは作れない
1. staticファクトリメソッドを見つけるのが難しい

## staticファクトリメソッドに共通する命名規約

* from
* of
* valueOf
* instanceあるいはgetInstance
* createあるいはnewInstance
* getType
* newType
* type
スターリンソートをGPUで爆速にする。その2

前回はこんな記事を書きました。

https://qiita.com/tommyecguitar/items/26c49fa11dec3990ea88

前回記事では役に立たないアルゴリズムとしてスターリンソートを例に挙げ、GPUで爆速化しようというチャレンジの結果、数万要素規模の入力配列でCPUよりも最大で8倍ほど高速な粛清を達成しました。

しかしながら、前回のコードはNVIDIA公式のCUDAのヘッダーライブラリCUBに頼り切っていたため、いまいち真の最適化にたどり着いた感が個人的にはありません。

というわけで、CUBに頼らずにもっと高速粛清できないかに取り組んでみました。

# 1. カーネルをなるべく一つにする。

今回は高速化のために、前回のコードに出てきたカーネルを1つのカーネルに束ねました。

GPUプログラミングに触れていない方には、よくわからないと思うので、その理由を簡単にまとめておきます。

前回はCUBをそのまま使うというヌルゲーだったので以下のようなタイムラインになっていました。

1. Inclusive scanでmaxオペレータを使い、入力配列のmax値をスキャンする。結果を中間出力として配列に格納する。CUBのDeviceScanを使う。
1. 入力配列と中間出力を比べて、入力に対し中間出力のほうがおおきい値なら0、そうでなければ1をフラグ配列に格納する。ここはフラグ立てるだけなのでオリジナルの関数。
1. フラグ配列をintと解釈してExclusive Sumをとる。`flag == 1`の場合はその入力配列要素をExclusive Sumの値と一致する出力インデックスに格納する。この処理はCUBのDevicePartitionで一発でやってくれる。

CUDAにおいてはグローバルメモリとのやり取りはなるべくしないほうがよいとされています。グローバルメモリとは、CPUとのデータのやり取りに使われ大容量だが、スレッドとの通信が遅いというメモリです。カーネルを分けてしまうと、次のカーネルに何か値を渡すときに、どうしてもグローバルメモリに格納しないといけません。上で言う中間出力とかフラグ配列とかです。
カーネルを半ば無理やりにでも一つにまとめることで、グローバルメモリとの通信量が抑えられ、高速化を図れます。

また、カーネルを分けることには同期の問題もあります。CUDAでは、カーネルを抜けるときに必ず全スレッドの同期がとられます。各スレッドはおしなべて同時に動いてるわけではないので、カーネルの始動直後と終了直前は、どうしてもスレッドの動作密度が下がります。これを回避するためにも、カーネルを一つにすることは重要なのです。

# 2. コード

今回のコードを見せたい気持ちは山々なのですが、最適化のために読みづらすぎるのと、長大なコードになってしまったので、どういうことをやったかの説明をしておきます。

まずInclusiveScanやExclusiveScanについてはCUBとほぼ同じことをやっています。

https://research.nvidia.com/publication/single-pass-parallel-prefix-scan-decoupled-look-back

1スレッドあたりの値の持ち方は以下の論文を参考にしています。

https://arxiv.org/abs/1604.04815

カーネル内の処理内容は以下の通りです。

1. 入力配列のInclusive scanでmax値をスキャンする。
1. max値と元の値を比べて、元の値 >= max値 なら`flag = 1`とする。
1. `flag`のExclusive scanをとる。
1. `flag == 1`なら出力の`idx = flagのExclusive scan`に入力要素を格納する。

やってることはあまり変わってないですが、1カーネル内にすべてを詰め込んだのでグローバルメモリとのやり取りが減りました。

# 3. 粛清時間

前回と同じ条件で粛清時間を計測しました。結果は以下の通りです。CPUのコードは変更なしですが、一応今回のも載せておきます。

| 要素数 | CPU粛清時間(前回)[ms] | CPU粛清時間(今回)[ms] | GPU粛清時間(前回)[ms] | GPU粛清時間(今回)[ms] |
|:-:|:-:|:-:|:-:|:-:|
| 10 | 0.005 |0.004 | 16.0113 | 8.11213 |
| 100 | 0.077  | 0.063 | 16.3853 | 8.98253 |
| 1000 | 0.573  | 0.895 | 17.8869 | 9.79082 |
| 10000 | 10.58  | 7.313 | 25.0143 | 10.6441 |
| 100000 | 87.223  | 91.487 | 24.2178 | 13.5576 |
| 1000000 | 893.693  | 886.729 | 121.326 | 25.3233 |
| 10000000 | 6487.83  | 5733.1 | 1046.07 | 169.816 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530192/ebc5dd1a-65ab-2a14-dcbb-616fd9afa74e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/530192/55ce9467-f070-dfb1-fa70-e84b62d4cf29.png)

なんとカーネルを束ねることをするだけで最大で35倍程度の速度で粛清できるようになりました。まだまだ並列数の最適化や、コード内の冗長性を削減できれば高速化の余地があります。

ただ、小さい配列の時は前回同様CPUのほうが速いという結果ですね。ここばかりはしょうがないところです。

# 3. まとめ

カーネル関数の工夫だけでかなりの高速化が達成できました。CUBのコードを読むのはかなり大変で僕も完璧に理解できませんでしたが、一度読んでみると勉強になりますね。
乃木坂46メンバー一覧をwikidataから出力する

SPARQLの練習で、乃木坂46メンバー一覧をwikidataから出力してみました。
現メンバーを把握するために、加入日、脱退日でソートします。
ただし当初、脱退日など元データに欠損値はありましたが、だんだんデータの補完が進んでいるようです。

# SPARQLのプラットフォーム
wikidata を検索するには、
Wikidata Query Service https://query.wikidata.org/
を使うのが楽ですが、履歴を残すのが面倒なので、
python の SPARQLWrapper を jupyter notebook で使いました。
SPARQLWrapperは普通に以下で入りました。
```
pip install sparqlwrapper
```
詳細は、https://github.com/RDFLib/sparqlwrapper にあります。

# SPARQLクエリ
以下のクエリを、Wikidata Query Service に貼り付ければ、一覧が表示されます。
https://w.wiki/538A
```
SELECT ?member ?memberLabel ?startyear ?endyear
WHERE
{
  ?member wdt:P463 wd:Q185226 .
  ?member p:P463 ?statement1 .
  ?statement1 ps:P463 wd:Q185226 .
  OPTIONAL { ?statement1 pq:P580* ?startyear FILTER(BOUND(?startyear) && DATATYPE(?startyear) = xsd:dateTime).}
  OPTIONAL { ?statement1 pq:P582* ?endyear   FILTER(BOUND(?endyear) && DATATYPE(?endyear) = xsd:dateTime).}
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],ja". }
}
order by ?endyear ?startyear
```

# SPARQLクエリの説明

- wd:Q185226（乃木坂46）の　wdt:P463（所属メンバー）を変数?memberに代入 
- ?member がp:P463（所属メンバー）のノードとなっている団体を変数?statement1に代入
- wd:Q185226（乃木坂46） が目的語となっている（ps:P463） ?statement1 を探す
- ?statement1 が修飾子 開始日（pq:P580）を持って入れば ?startyear に代入
- ?statement1 が修飾子 終了日（pq:P582）を持っていれば ?endyear に代入
- アスタリスク (*) をパス要素の後につけると、その要素のゼロ回以上の繰り返し

なお、p:,ps:,pq: は、ウィキデータ:SPARQLチュートリアルhttps://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial/ja によると以下のとおりです。
> 接頭辞 p: は目的語を指し示すのではなく、「ある文というノード」を指し示します。そしてこのノードが他のトリプルの主語になります。接頭辞 ps: (property statement の略です) は文を目的語として指し示します。接頭辞 pq: (property qualifier) は修飾子を指し示し、

# SPARQLWrapper
これを、SPARQLWrapperで実行するには、以下のようにしました。

```python
from SPARQLWrapper import SPARQLWrapper, JSON
sparql_wikidata = SPARQLWrapper("https://query.wikidata.org/sparql", returnFormat='json')
sparql_wikidata.setQuery("""
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX pq: <http://www.wikidata.org/prop/qualifier/>
SELECT ?member ?memberLabel ?startyear ?endyear
WHERE
{
  ?member wdt:P463 wd:Q185226 .
  ?member p:P463 ?statement1 .
  ?statement1 ps:P463 wd:Q185226 .
  OPTIONAL { ?statement1 pq:P580* ?startyear FILTER(BOUND(?startyear) && DATATYPE(?startyear) = xsd:dateTime).}
  OPTIONAL { ?statement1 pq:P582* ?endyear   FILTER(BOUND(?endyear) && DATATYPE(?endyear) = xsd:dateTime).}
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],ja". }
}
order by ?endyear ?startyear
""")
sparql_wikidata.setReturnFormat(JSON)
results = sparql_wikidata.query().convert()
print(results)
```

SPARQLWrapper では、出力フォーマットを、XML,JSON,CSV,json-ldなどが選べ、pandasのDataFrameに変換することも簡単なので、再利用には便利だと思います。

# おまけ
```
FILTER("2011-08-22"^^xsd:dateTime <= ?endyear && ?endyear < "2020-01-01"^^xsd:dateTime).  
```
というクエリを加えるといつからいつまでに脱退したメンバーをフィルタできます。
【3Dエクセル】リレーショナルデータベースを理解し、作業効率を200倍にするビジネステクニック。リレーショナルデータベース -解説編

# はじめに
普段の業務に「エクセルを使いVLOOKUPで値を抽出して、COUNTIFで数えて、視覚化して…」という作業していませんか！？
その作業、リレーショナルデータベースを使えば一瞬で終わるかもしれません！
今回はデータ分析人材には必須スキルとも言えるリレーショナルデータベース（RDB）の構造を解説したいと思います。


# リレーショナルデータベース（RDB）とは
リレーショナルデータベース（RDB）とは複数のテーブルを「関係（リレーション）」という概念でつなげ、データの抽出や結合をらくらく行えるデータベース（DB）の事です。エクセルのテーブルがいくつも重なり合っているというイメージを持っていただければイメージしやすいかもです。一般的にデータベースといえばこのRDBを指し、右下の図の様にホットケーキを重ねた様な描画をされます。

![DB-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/b0196de7-3865-a723-8647-e8d9d58a19dd.png)

# 用語集
- **Entity（実体）**: 実体、DBの全体
- **Attribute（属性）**: データの属性、列で表される
- **Record（レコード）**:1行のデータ
- **Table（テーブル）**:テーブル、AttributeとRecordの集合。原則1テーブル1テーマ。
-例）部署テーブルには部署以外のデータ（課長の電話番号、部長の入社歴等）は入れない

![DB-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/91c6ae26-b4f2-682d-f854-187328a30aa8.png)

# 「key」という概念
DBはkeyという概念でテーブルとテーブルの間に関係を生み出します。その名の通り、RDBの鍵「key」という概念について説明します。

### 2種類の「key」
- Primary Key:テーブルにおいて、１レコード毎に振り分けられるユニークなID
- Foreign Key:外部のテーブルとの関係をつなげる為のキー

例えば、部署テーブルにおいて、部署IDがPrimary Keyであり、社員テーブルにおける部署IDがForegin Keyとされます。
この場合、部署テーブルの部署IDと社員テーブルの部署IDの関係性は「One to Many」と呼ばれ、鳥の足のような記号で表します。（部署テーブルの部署IDはユニークであり重複しませんが、社員テーブルにおいては重複が発生するためです。）

![DB-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/eee6c8f6-1203-a3e6-786c-7420f7d7ab8f.png)


「ちょっとちょっと！これじゃあエクセルの*VLOOKUP*でできちゃうじゃん！」と思っている方、安心してください。RDBは**正規化**という手法を取り入れる事でデータ作業効率が格段によくなるのです！

# Normalization（正規化）
引き続き社員情報DBを使いましょう。例えば、1人の社員が2つ以上の部署に所属しているとき、みなさんはどの様にデータを組みますか？
良いデータベースの定義を意識して、考えていきましょう。

### 1つのカラムに複数の部署IDを入れる
![DB-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/beff4956-d8b1-0c54-0067-bfb0e6580c02.png)


これは直感的に「あかんやろ、、」と思う人もいるのではないでしょうか。**良いデータベースは１つのセル（マス）に1つのデータしか入れてはいけません**。さらに、これをするとふたつのテーブルの関係（リレーション）が壊れてしまいます。


### 社員テーブルの部署IDカラムを増やす
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/de2c8ac4-3cdc-adb4-1e3e-2e7fd67f12fd.png)
一見すると、これで良いかと思われがちなのですが、**データベースの世界では空欄のセルは良しとされません**。また、とても忙しい社員1人が10部署を兼務するとなると、社員テーブのカラムの数がその分伸びてしまいます。

### 社員テーブルの行を増やす

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/a180e753-d32f-090c-bc70-00d5376f1243.png)
これは、社員テーブルにおいてのIDが重複してしまうので、**Primary Key**の原則に反してしまします。

上記の問題を全て解決してくれるのがAssociative Table（連想テーブル）というものです！

# Associative Table（連想テーブル）
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1044781/7ef532aa-aed6-a418-a1bd-4a18faa1dcc5.png)
Associative Table（連想テーブル）とは、2つのテーブルのPrimary Keyを参照し、重複や欠落が発生している両テーブルの関係を崩す事なく、マッピング（表現）してくれるテーブルです。これはMapping Tableまた、Junction Tableなどとも呼ばれます。このテーブルをテーブルとテーブルの間に置くことで、テーブルの原則、keyの原則、正規化の原則を全て守る事ができます。


# おわりに
リレーショナルデータベース（RDB）は様々な原則の本整理されたデータで、データを綺麗に長期間保存する事を可能にします。直には実装編という事で、**SQL（Structured Query Language）** というRDBを自由自在に操れるプログラミング言語を使い、なぜRDBが作業効率を200倍にしてくれるのかという所を見ていきます。

次回↓

https://qiita.com/Shu25/items/6b01b8bccf5994cd3f2a


### 関連記事はこちら

https://qiita.com/Shu25/items/8a5d3293fc177689ee9c

https://qiita.com/Shu25/items/6b01b8bccf5994cd3f2a

https://qiita.com/Shu25/items/40e8b86f1e83602e3fee
Flutter WebのdubugでApiを呼ぶとCORSでエラーになる対処法

Flutter Webを開発しています。
開発PC上で他のWebApiを実行するとCORSでエラーになります。
その対処法を紹介します。

# 手順

## (1) flutter_tools.stamp を削除
...\FlutterSDK\bin\cache
flutter_tools.stamp を削除します。
このファイルはビルドすると再作成されます。
'FlutterSDK' はプロジェクトが参照しているFlutterのSDKです。

## (2) chrome.dart に --disable-web-security を追加

...\FlutterSDK\packages\flutter_tools\lib\src\web
chrome.dart を編集します。
--disable-extensions を削除
--disable-web-security を追加

```
193行目
  final int port = debugPort ?? await _operatingSystemUtils.findFreePort();
  final List<String> args = <String>[
    chromeExecutable,
    // Using a tmp directory ensures that a new instance of chrome launches
    // allowing for the remote debug port to be enabled.
    '--user-data-dir=${userDataDir.path}',
    '--remote-debugging-port=$port',
    // When the DevTools has focus we don't want to slow down the application.
    '--disable-background-timer-throttling',
    // Since we are using a temp profile, disable features that slow the
    // Chrome launch.
    //'--disable-extensions',　＜＜＜削除  
    '--disable-web-security',　＜＜＜追加
    '--disable-popup-blocking',
    '--bwsi',
    '--no-first-run',
    '--no-default-browser-check',
    '--disable-default-apps',
    '--disable-translate',
```
## (3) 実行

```
flutter run -d chrome
```

実行すると localhost の chrome に以下のような警告が表示されました。
```
コマンドラインフラグ --disable-web-security を使用しています。これにより、安全性とセキュリティが損なわれます。
```

# ポイント
- FlutterSDK はFlutterのSDKの場所です。プロジェクトのことではありません。
- 実行するのは flutter run -d chrome のままです。ここにオプションは不要です。

# あとがき
Flutter Webは流行るのでしょうか。今回の記事のようにWebApiを使い出すと心配になってきました。GoogleはChromeも出していますし期待しています。
FlutterはアプリとウェブでUIが使いまわせるのが魅力ですよね。それほど流行ってないのがむしろ不思議です。
Web技術の基本

## web技術の基本についてのメモ
本記事は、自己学習のための記事であり、誤った情報が含まれている恐れがありますが、ご了承ください。

## 参考文献

この記事は以下の情報を参考にして執筆しました。

- [プロになるためのweb技術入門](https://gihyo.jp/book/2010/978-4-7741-4235-7)
- [SSHとは？](https://blog.senseshare.jp/ssh.html)

## リクエスト・レスポンス
- クライアント（webブラウザ)からの要求のことをリクエストと呼ぶ。
- リクエストに対してサーバーからの応答をレスポンスと呼ぶ。


## プロトコル
プロトコルとは、情報をやり取り、伝達するためのルール（取り決め）のこと。
インターネット上には、様々なコンピュータがつながっているため、あらかじめ通信のルールを取り決めておかないと異なるコンピュータ間で情報の伝達ができない。
プロトコルにはいくつか種類があり、HTTPプロトコルはwebクライアントとwebサーバーが通信するためのプロトコル（ルール）である。

## ポート番号
プロトコルにはいくつか種類があるため、受信した情報がどのようなプロトコルで、どのようなアプリケーションが処理するべきかは、TCP/IPには分からない。そこで登場するのがポートという考え方である。
インターネットで情報を届けるにはIPアドレスで宛先を指定して、さらにポート番号でどのようなアプリケーションが処理するのかを指定する必要がある。
よく使われるプロトコルについては標準で使用するポートが決まっており、HTTPプロトコルなら80番など。
また、URLに記載するべきポート番号は省略できる。そのため、HTTPリクエストのURLにポート番号を省略してもあらかじめ設定されたポート番号（80番）を参照しているおかげで普段のHTTP通信でポート番号まで意識しなくて通信ができている。

## ステートフル・ステートレス
そもそもステートとは、日本語で状態のことである。webで言う状態とは、前回のリクエストの情報である。
HTTPは状態を持たない、持てないプロトコルつまりステーレスなプロトコル
FTPは状態を持つプロトコルつまりステートフルなプロトコル
ステートレスとステートフルを美容室で表すと、ステートレスな美容室は前回のお客さんの情報を記憶していない、ステートフルな美容室は前回のお客さんの情報を記憶していると表せる。
前回のリクエストの情報を記憶していないHTTPは、前回のリクエストの情報を記憶していないので、どのクライアントからのリクエストか識別ができない。

## cookie
HTTPはステートレスなプロトコルな為状態を保つことができない。その為、cookieと言う仕組みを用いることで状態を保つことができる。webサーバーからwebブラウザへのHTTPレスポンスのヘッダにcookieと呼ばれる情報・キーを送信して、webブラウザは受け取ったcookieを次回同じwebサーバーにリクエストを送る際にHTTPリクエストヘッドにcookieを入れて送ることで、webサーバーがcookieを調べてアクセスしてきた相手を特定することができる。
また、cookieを受け取ったwebサーバー以外には、cookieを送らないことで意図しない情報が他のwebサーバーに送られてしまうのを防いでいる。

## セッション
cookieはInetSpyなどのツールを使うことで第三者から比較的簡単に内容を覗くことができてしまう。そのためユーザーのIDやパスワード、購入する商品などの生の情報を直接cookieで保存して通信してしまうと、情報漏洩などのセキュリティ上大きな問題がある。また、cookieには記憶できる情報量に制限がある。そこでセッションと呼ばれる仕組みで安全に多くの情報を保持することができる。
セッションとは一連の処理の流れのことで、例えば以下のような処理のこと。
1. ログイン（ログインIDとパスワードの情報）
2. メニューから選択（メニューの情報）
3. 注文内容確認
4. ログアウト

そこで、これらの情報をwebサーバー上で管理、識別するために、上記の一連の処理にセッションIDという一意なIDを発行してやり取りする。
最終的にwebサーバとwebクライアントの間ではcookieを使ってセッションIDのみをやり取りすれば生の情報ではなく、情報をもたないセッションIDでやり取りが行われる。
しかし、これではセッションIDを第三者に盗まれて、なりすましが発生してしまう。これを防ぐには通信路をSSLによって暗号化することでセッションIDを第三者に盗み見られることを防げる。

## SSL/SSH
SSHとは、別のコンピュータ（サーバー）を遠隔操作するためのツールであり、同じようなツールに「Telnet」というものもある。SSHとTelnetの違いは、SSHは、通信データが暗号化され、Telnetは暗号化されない。
SSLとは、インターネット上の通信、やり取りしている情報を暗号化する仕組みのこと。
【JavaScript】日付は `YYYY/MM/DD hh:mm:ss.iii` の形式で欲しい！のに無いから自作した（のに、、よく調べたらあった

# 日付は `YYYY/MM/DD hh:mm:ss.iii` の形式で欲しい！のに無いから自作した（のに、、よく調べたらあった

日付のフォーマットは `YYYY/MM/DD hh:mm:ss.iii` 形式で欲しい！！そう、日本人なので。

ってか、日付フォーマット、多すぎ。そのまえに世界中でバラバラなの、なんとかして。

さらに最近は「ミリ秒」もあたりまえにほしい！

# コード（最初の版。追記あり〼）

```JS
//-------------------------------------------------------
// 現在の日時を文字列で返す
const  get_formated_time = (
    _fmt = 'YYYY/MM/DD hh:mm:ss.iii',
    _dt  = new Date(),
) => [
        [ 'YYYY', _dt.getFullYear()  ],
        [ 'MM',   _dt.getMonth() + 1 ], // なぜ Java と同じ仕様にしたのか？小一時間問いたい
        [ 'DD',   _dt.getDate()      ],
        [ 'hh',   _dt.getHours()     ],
        [ 'mm',   _dt.getMinutes()   ],
        [ 'ss',   _dt.getSeconds()   ],
        [ 'iii',  _dt.getMilliseconds() ],
    ].reduce(
        (s,a) => s.replace( a[0], `${a[1]}`.padStart(a[0].length,'0') ),
        _fmt
    )

// 使い方

const put = s => document.body.innerText += s + '\n'
// const put = s => console.log( s )

put( get_formated_time() ) // -> 2022/04/10 14:56:21.238

put( get_formated_time( 'MM/DD/YYYY' ) ) // -> 04/10/2022

put( get_formated_time( 'hh-mm-ss' ) ) // -> 14-56-45

put( get_formated_time( 'YYYY/MM/DD hh:mm:ss', new Date( '2000/1/1 12:34:56' ) ) )  // -> 2000/01/01 12:34:56

```

# 実行例（Codepen)

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="popKeeY" data-user="yamazaki3104" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/popKeeY">
  JavaScript で YYYY/MM/DD hh:mm:ss.iii 日付フォーマット</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# コードの解説

使用している関数の解説は、こちら（手抜き
ってか、必要ないでしょ。

## new Date 日付クラス

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date

## reduce() 配列の要素を順番に実行

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

## replace() 文字列置換

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace

## padStart() ~~ゼロサプレス~~ パディング(ゼロで埋める)

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/padStart


# 追記： よく調べたら、ありました。毎度お騒がせしております。

追記：上の関数　get_formated_time()　を使わなくても、、、、↓Intl.DateTimeFormat()で行けました

```JS

const yyyymmdd = new Intl.DateTimeFormat(
  undefined,
  {
    year:   'numeric',
    month:  '2-digit',
    day:    '2-digit',
    hour:   '2-digit',
    minute: '2-digit',
    second: '2-digit',
    fractionalSecondDigits: 3,
  }
)

console.log( yyyymmdd.format( new Date() ) )
```

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat


それでは引き続き、プログラミングライフをお楽しみください。
【メモ】UIViewの拡大、回転、移動する方法

swiftの勉強メモとして記録します。
※目新しい情報などはないと思います。

CGAffineTransform　で画像を回転、移動、反転させることができる
2Dグラフィックの描画に使われる、アフィン変換を表します。

UIViewに存在するtransformプロバティを用いて、viewに対して変更を行う。

# 使い方
回転
CGAffineTransform(rotationAngle: CGFloat(angle))

拡大・縮小
CGAffineTransform(scaleX: A, y:B)
(AまたはBを負の値にすると反転される)

移動
CGAffineTransform(tranlationX:C, y:D)

```
transScale = CGAffineTransform(scaleX:2, y:2)
imageView.transform = transScale
```
ユーザーに気づかれずにEmoCheckを実行して結果を収集する

# やりたいこと

JPCERTからEmoCheckというEmotet感染チェックツールが無償で提供されているのはご承知のとおりです。

[JPCERT/CC EmoCheck](https://github.com/JPCERTCC/EmoCheck)

基本的には感染が疑われるときに実行するものですが、社内のPCを毎日チェックし、チェック結果は一か所に集約して感染PCを検知したくなりました。

ただ、単純にBATファイルから実行するとDOS窓が表示されてユーザーを驚かせてしまいます。事前に周知しても毎回DOS窓が表示されるのはやはり煩わしい。

つまり要件は以下のとおり。

* UIを表示させずにEmoCheckを実行
* 実行結果のログは一か所に集約
* ログから感染PCを特定

大前提としてチェック対象のPCは社内ネットワークにあり、EmoCheckを自動配布、自動実行する環境はあるものとします。

## UIを表示させずに実行

BATファイルからEmoCheckを実行すると```/quiet``` ```-quiet```オプションをつけてもDOS窓は表示されてしまいます。

そこで追加のインストールが不要なVBScriptでDOS窓を抑止します。以下の例ではEmoCheckが```C:\temp\```に配布してあると仮定します。結果ログは後で扱いやすいようにJSONにします。

```Visual Basic:C:\temp\LaunchEmoCheck.vbs
Set objShell = CreateObject("WScript.Shell")
Call objShell.Run("c:\temp\emocheck_v2.1.1_x64.exe /quiet /json /output c:\temp", 0, True)
```

自動実行するのはEmoCheck本体ではなくこのLaunchEmoCheck.vbsになります。

## 実行結果のログは一か所に集約

上記のコードでは実行結果ログを```c:\temp\```に書き出していますが、これを一か所に集約します。

対象PCは社内ネットワークにある前提のため、適当な社内サーバーに共有フォルダを作成し、ユーザーに書き込み権限を与えておきます。

仮に```SERVER01```に```EmoCheckResults```という共有フォルダを作成したとして、上のVBScriptでEmoCheckの出力先を以下のように変更します。

```Visual Basic:C:\temp\LaunchEmoCheck.vbs
Set objShell = CreateObject("WScript.Shell")
Call objShell.Run("c:\temp\emocheck_v2.1.1_x64.exe /quiet /json /output \\SERVER01\EmoCheckResults", 0, True)
```

EmoCheckの仕様上、結果ログファイル名は```[computer name]_yyyymmddhhmmss_emocheck```となり事実上ファイル名の重複は起こりません。

## ログから感染PCを特定

共有フォルダ```\\SERVER01\EmoCheckResults```に全PCの実行結果ログが集まりますので、サーバー側で定期的にバッチ処理を自動実行するなどして感染したPCを探します。

追加インストールが不要という点にこだわってPowerShellを使うと以下のようになります。あくまで一例です。

```PowerShell
$logFullName = $PSCommandPath -replace ".ps1", ".log"
foreach ($item in (Get-ChildItem -Path "\\SERVER01\EmoCheckResults\")) {
    $json = ConvertFrom-Json -InputObject (Get-Content -Path $item.FullName -Raw)
    if ($json.is_infected -eq "yes") {
        $item.Name | Out-File -FilePath $logFullName -Append
    }
    Remove-Item -Path $item.FullName -Force
}
```

共有フォルダに書き出された実行結果ログを1つずつJSON形式として読み込み、```is_infected```が```yes```ならログファイルにファイル名を追記、チェック済み実行結果ログファイルは削除するという処理です。

さらに言えば、このPowerShellスクリプトにシステム管理者あてのメール送信処理を追加して、サーバーでタスクスケジューラーに登録して実行するなどになるでしょう。

# まとめ

以上、「何でも屋さん」社内情シスならではの地味なお仕事でした。
Dockerコンテナを一般ユーザーで操作する

# はじめに
コンテナを作成した時、**デフォルトのユーザーはrootユーザー**になっています。
そのため、コンテナ内で作成したファイルは権限がroot権限になってしまい、コンテナの外での編集に支障をきたしてしまいます。そのため、下記の流れでユーザーの設定を行います。

`１．.envに環境変数を記載`
`２．docker-compose.ymlのargsにて、Dockerfileに渡す環境変数を記載`
`３．Dockerfileにてグループとユーザーを追加＆使用者を一般ユーザーに変更`

# docker-compose.yml
```env:.env
UID=1000
GID=1000
USERNAME=user_name
```
```yml:docker-compose.yml
version: "3"
services:
  app:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
      args:
        # Dockerfileに環境変数を渡す
        - UID=${UID}
        - GID=${GID}
        - USERNAME=${USERNAME}
```


# Dockerfile
```dockerfile:Dockerfile
# イメージを指定
FROM php

# 中略

# docker-compose.ymlで設定した環境変数を導入
ARG UID
ARG GID
ARG USERNAME

# グループ・ユーザーを追加
RUN groupadd -g ${GID} ${USERNAME} \
  && useradd -u ${UID} -g ${GID} -s /bin/bash -m ${USERNAME}

# コンテナを操作するユーザーをルートから一般ユーザーに変更
USER ${UID}
```
Apple SiliconのMacでCarthageがビルドできない時の対応方法

# なんの記事
- M1MaxでXcode13.2.1を使用しCarthageをビルドしたところ、できなかったのでその原因と解決方法をメモする。


#　エラー内容
```text
Building universal frameworks with common architectures is not possible. The device and simulator slices for "Apollo" both build for: arm64
Rebuild with --use-xcframeworks to create an xcframework bundle instead.
make: *** [build-carts] Error 1
```


# 対応方法
- Carthageのバージョンを確認し、0.37.0以降であることを確認する。
```terminal
carthage version
```
- Carthageフォルダ内のファイルを削除し、以下のコマンドで、xcframeworksでCarthageをビルドする。
```terminal
carthage bootstrap --platform iOS --use-xcframeworks 
```

# 原因
- Xcode 12でシュミレーター用にarm64アーキテクチャが追加されるようになり、Carthageでビルドができなくなった。
- Carthage公式でワークアラウンドが提供されましたが、Apple SiliconのMacでは利用できない制限があった。
- 0.37.0からXCFrameworkでビルドできるようになった。
- XCFrameworkでビルドすることでXcode 12でCarthageが使えるようになる。
Scalaの勉強はじめました 6 〜関数型プログラミング編 関数について〜

## はじめに
N予備校で「Scala応用」コースを受講しています。
今回から関数型プログラミングについてです。

## 関数型プログラミング
:::note
外部の状態を変化させない関数だけでプログラミングを行うこと
:::

外部の状態を変化させることを、**副作用**という。

### 副作用のある関数
変数を変更する
オブジェクトが持っているフィールドの値を書き換える
例外やエラーを発生させる etc.

### 参照透過性
値と式が交換できるような関数
```scala
def square(n: Int) = n * n
```
同じ値を入れたら必ず同じ結果になることが保証されたもの、かな。
正直テキストよりもこっちの方がまだわかりやすい。

https://gimo.jp/glossary/details/referential_transparency.html

## 関数
```scala
val add = new Function2[Int, Int, Int] {
  def apply(x: Int, y: Int): Int = x + y
}
```

`Function0`〜`Function22`まではインスタンス化して表現できるらしい。
`apply`メソッドを実装することで、`x.apply(y)`が `x(y)`で書くことができる。

### シンタックスシュガー
```scala
val add = (x: Int, y: Int) => x + y
```
要は無名関数のこと。

### カリー化
名前を見るたびに「日本印度化計画」が流れます。

```scala
val addCurried = (x: Int) => ((y: Int) => x + y)
```

メソッドチェーンのような感じで書ける。
呼び出しは、
```scala
addCurried(100)(200)
```

## 再起関数の注意点
```scala
def series(n: Int): Int = {
    if (n == 0) {
      0
    } else {
      series(n - 1) + n
    }
  }
```

`series(10000)`などで実行すると、
`StackOverflowError`が発生してしまう可能性がある。

### 末尾再帰最適化
:::note
再帰関数の呼び出しが必ず関数の末尾に来るような記述としておくことで 内部的にループ処理に書き換えてくれる
:::

`@tailrec`アノテーションを利用すると、最適化されていない時はコンパイルエラーになる。
```scala
@tailrec
def series(n: Int): Int =
```

## まとめ
段々難しくなってきてますが、こうやってまとめると頭の中も整理されていく気がします。ここからしばらく関数型プログラミングが続きます。
ubuntu20.04にCUDA11.6とcuDNN8.4を導入する(2022年4月6日時点での最新バージョン)

# やること
- CUDAとcuDNNを機械学習用gpuサーバ(ubuntu20.04)に導入する
- 全部ssh接続で完結させる（サーバに直接ディスプレイとか入力機器繋げるの面倒だと思うので）
- バージョン相性の悪い機械学習ライブラリを使いたい時はDockerで何とかすることにして、とりあえずそれぞれ最新版を導入する（Dockerについてはここでは扱わない）

:::note
バージョンは以下の通り(2022.4.6時点での最新版)
- CUDA: v11.6
- cuDNN: v8.4
:::

# CUDA
[公式サイト](https://developer.nvidia.com/accelerated-computing-toolkit)からダウンロードする。

https://developer.nvidia.com/accelerated-computing-toolkit

CUDA ToolkitのDOWNLOADボタンを押すと下記ページが出てくるので、手順にしたがってダウンロードする。
（もし過去バージョンが欲しければ、下の方にあるArchive of Previous CUDA Releasesってとこを見れば良い）

https://developer.nvidia.com/cuda-downloads

今回の場合は下図のようにOSなどを選択していけば、下部にインストールコマンドがずらっと出てくる。
導入したいサーバで直接、ないしはsshでサーバに入って、これらのコマンドを入力してあげれば良い。

```
$ ssh ユーザ名@IPアドレス
```

![Pasted image 20220406225819.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534823/120c858b-4e2c-e808-540e-3531ddfc94ca.png)

次にパスを通す。
ホームディレクトリにある`~/.bashrc`というファイルを、viコマンドとか使って編集する。（編集できれば何でも良い）
```
$ sudo vi ~/.bashrc
```

`~/.bashrc`の末尾に、以下の内容を追記する。

```.bashrc
# cuda setup
export CUDA_HOME="/usr/local/cuda-11.6"
export PATH="$CUDA_HOME/bin:$PATH"
export LD_LIBRARY_PATH="$CUDA_HOME/lib64:$LD_LIBRARY_PATH"
export CPATH="$CUDA_HOME/include:$CPATH"
```
変更を保存したら再起動(reboot　コマンド)
```
$ reboot
```
これらのコマンドが機能していれば問題ないと思います↓
```
$ nvidia-smi
$ nvcc -V
```

最後に要らんやつ消して終わり。
```
$ sudo rm cuda-repo-ubuntu2004-11-6-local_11.6.2-510.47.03-1_amd64.deb
```


# cuDNN
まずは公式のダウンロードページへ

https://developer.nvidia.com/cudnn

Download cuDNN　ボタンを押したら、NVIDIA Developer Program Membership Requiredとか出てきて、ログインかアカウント登録を迫られる。
アカウントを持っていなければサクッと登録して、ダウンロードページに進む。

![Pasted image 20220407000512.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534823/044b9274-283c-5b56-f2ed-1ade579bb43f.png)

今回のサーバに合わせて、`Local Installer for Ubuntu20.04 x86_64[Deb]`を選択。
直接サーバでダウンロードしている場合は問題ないが、sshしている場合は手元のパソコンからサーバにこのファイルを送らないといけない。
今回は`scp`コマンドで、サーバのホームディレクトリにダウンロードしたファイルを送る。
```
$ scp [オプション] コピー元パス 保存先パス
```
なので、
```
$ scp cudnn-local-repo-ubuntu2004-8.4.0.27_1.0-1_amd64.deb ユーザ名@サーバのIPアドレス:/home/ユーザ名
```
でいけるはず。

:::note
`ユーザ名@サーバのIPアドレス`のところはssh接続するときに使ってるものと同じ。
`:/home/ユーザ名`のところは`:~`でもいけるかも(要はホームディレクトリを指定しているだけなので)
:::

サーバにインストーラファイルが用意できたら、さっきのダウンロードページの上の方に書いてあった[Installation Guide](https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html)の通りに作業する。

↓今回の該当箇所

https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html#installlinux-deb

:::note warn
>2.3.2. Debian Local Installation
Download the Debian local repository installation package. Before issuing the following commands, you'll need to replace X.Y and 8.x.x.x with your specific CUDA and cuDNN versions.

って書いてある通り、`X.Y`と`x.x.x.x`はダウンロードしたいバージョンに合わせて数字を代入する必要がある。
今回の例だと

- `X.Y` → cudaのバージョンなので`11.6`
- `x.x.x.x` → cuDNNのバージョンなので`8.4.0.27`(さっきダウンロードしたインストーラファイルの名前を真似する)

これらに置き換えて、リンク先のコマンドを入力していけばOK。
:::

※[Installation Guide](https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html)に書いてあった[テスト](https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html#verify)がうまくいくことも確認済。

最後に要らんやつ消して終わり。
```
$ sudo rm cudnn-local-repo-ubuntu2004-8.4.0.27_1.0-1_amd64.deb
```

お疲れ様でした。
【スプレッドシート】隣のセルより大きかったら色を染める（条件付き書式・GAS）

## 概要

スプレッドシートで隣のセルと比較して大きければ色付けする方法を記載します。
私は企業の毎年の利益などを比較するために使っています。

○イメージ（前の年より利益が上がっていればセルの色を染める）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/499aa6c0-dd43-27cc-1f01-311c5e13fa01.png)

##まずは手動で設定

①設定したい範囲を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/bdece866-2f01-ea01-fbfb-d6ce8b1e7abd.png)

②「表示形式」⇨「条件付き書式」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/e3de4a02-96fc-c1aa-d903-a751f45a954d.png)

③右端に表示される条件付書式ルールで「書式ルール」を「カスタム書式」
「=R3<S3」と入力。色の指定などをする
※カスタム書式に入れる式は一つだけでOK。私は1番左上のセルを設定しました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/633008/1d22e1f1-fa49-0ac8-4232-b52acc0704ab.png)


## GASで実行する場合
先ほどの処理をGASでやる場合は以下のようにする
※マクロで記録した後に余分なコードを削除しました
変数などを使用して適用する範囲などを変えれば汎用性が持てる


```
const spreadsheet = SpreadsheetApp.openById("スプレッドシートのID");
const sheet = spreadsheet.getSheetByName("シート名");

function test(){
  var conditionalFormatRules = sheet.getConditionalFormatRules();
  conditionalFormatRules.splice(conditionalFormatRules.length - 1, 1, SpreadsheetApp.newConditionalFormatRule()
  .setRanges([sheet.getRange('S3:U4')])
  .whenFormulaSatisfied('=R3<S3')
  .setBackground('#B7E1CD')
  .build());
  sheet.setConditionalFormatRules(conditionalFormatRules);
}

```

## 追記
初めに条件付書式を初期化したい場合はこのようにする

```
var conditionalFormatRules = industrySheet.getConditionalFormatRules();
//条件付書式の状態を配列で取得して、配列の長さ分削除（要素の削除）
  conditionalFormatRules.splice(0, conditionalFormatRules.length);
```
ローリングリリース とは

## 勉強前イメージ

回しながら・・・？

## 調査

### ローリングリリース とは

段階的に更新されていくようなリリース方法になります。
例えば1,2,3のパッケージが必要なアプリケーションがあったとすると、1,2,3をアップデートしてメジャーバージョンアップみたいにするのではなく
先週1をアップデート、今週2をアップデート、来週3をアップデート というように段階的に更新されていきます。
ArchLinuxやCentOSStreamなどがこのようなリリース方法になります。

### ローリングリリースの特徴

- 脆弱性などのアップデートが早い

リリース頻度が多いので脆弱性や障害が出た際の修正も早くなります。

- リリースの速度が早いので追従が大変

常に新しいものができればリリースされるので、更新頻度が高く定期的に確認を行い
アプリケーションが追従できるかの確認が必要です。

## 勉強後イメージ

メジャーバージョンアップとかマイナーバージョンとかでもなく
もっと早い頻度でのリリースってことか。

## 参考

- [Linuxディストリビューション選びの基礎知識](https://event.ospn.jp/slides/OSC2021-OnlineSpring/fujitsu_computer_technologies.pdf)
- [8年の2020つのベストローリングリリース](https://www.linuxadictos.com/ja/8-mejores-distribuciones-rolling-release-2020.html)
トランザクション実行時のメモリ領域はどうなっているか

## トランザクションとは
>「商品を渡して、代金を受け取る」のように「ここからここまでワンセット」な処理単位のこと

引用元：[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/word142.html)

## この記事で説明したいこと
SQL Serverによるトランザクション処理の実行時、どのようにしてコミット処理やロールバック処理が動作しているかのイメージを伝えたい。

## トランザクション実行時のメモリ領域はどうなっているか
トランザクション実行時には、実際の処理を行うのに必要なメモリが確保されます。
また、それと同じだけの大きさのトランザクションのための領域も同時に確保されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918417/729ce738-1198-2e06-b86d-8231abf4e000.png)

確保された後、実際の処理が行われていきます。
実際の処理が行われつつ、メモリ内のトランザクションログ領域にも実行内容が記録されていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918417/3711ea84-d747-4f43-6099-0ebd82c87afd.png)

エラーが発生した場合には、トランザクションログ領域の内容に従って処理がロールバックされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918417/6621d200-b9b8-6ab2-6c22-0858ac9af8b5.png)

## トランザクション終了後の挙動
トランザクションが終了されたタイミングで、トランザクションログ領域は解放されます。
※解放とは、確保していたメモリ領域を他のことに使える状態にすること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1918417/cf04b91b-63b9-29ee-0ca4-37b1a83be9fe.png)

ちなみに、上図の状態ではHDDなどのディスクへはデータの反映はされておらず、**ダーティページ**と呼ばれる状態になっています。
※ダーティページについては物理アーキテクチャの内容でかつ長くなりそうなので今回は割愛

## まとめ
トランザクション実行時にSQLServerどのようにメモリを利用して処理内容を管理しているかが伝われば嬉しいです。
Node.js のパッケージをバージョンアップして公開

# 種類
```sh
$ npm version patch # v0.0.0 -> v0.0.1

$ npm version minor # v0.0.0 -> v0.1.0

$ npm version major # v0.0.0 -> v1.0.0
```

# 公開
```sh
$ npm version patch
v0.0.1

$ git tag # gitにtagが反映されていることを確認
v0.0.0
v0.0.1 # 反映されてます

$ git push origin tags/v0.0.1 # gitにtagをpush

$ npm publish # npmに公開
```