OmniAICreator/Qiita-1.07M huggingface dataset:
【Rails6.0】突然CSSが読み込まれなくなった、、【怪奇現象？】

現在個人開発でRailsアプリを作っているのですが、正常に動いていたRailsアプリのCSSが突然読み込まれなくなり(画像ファイルも）無駄に時間を食ってしまいました。
結局はっきりとした原因はわかりませんが、解決するまでの過程をここに書いていこうと思います。

**開発環境**

- windows10 Pro
- Rails: 6.0.3.2
- ruby: 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
- Docker for windows
- MySQL 5.7
- nginx:1.15.8


##エラーが発生した経緯
rspecのシステムスペックでテストを書いて実行、失敗を10回ほど繰り返してlocalhost（root_path)にアクセスしたら
CSSが反映されなくなっていた。
そのときのConsoleのエラー内容↓

```
Failed to load resource: the server responded with a status of 500 (Internal Server Error) 
```

このエラー自体はよく見るやつで、タイトル通りCSSファイルが読み込まれていないというものでした。

##解決手順（？）
この解決策が正しいのか正直微妙ですが、治るまでの経緯をここに書かせて頂きます。
結論から言いますと、nignx.confの内容を適当に書き換えて、dockerコンテナをビルドし直して起動しなおしてエラーを起こしてもう一度ビルドし直してコンテナ起動したら治ったという感じです。**普通に再ビルドしただけでは治りませんでした。**これのせいで時間がかかりましたね、、たまたまエラー起こせたんで治せましたが、、
これだとわかる人にしかわからないでの以下で詳しく説明します。

#1．nginx.confの内容を書き換える
私の開発環境ではなるべく本番環境に近づけるためにWEBサーバーとしてnginxコンテナを起動させています。
そのnginx.confはその設定ファイルです↓

```conf

# プロキシ先の指定
# Nginxが受け取ったリクエストをバックエンドのpumaに送信
upstream webapp {
  # ソケット通信したいのでpuma.sockを指定
  server unix:///webapp/tmp/sockets/puma.sock;
}

server {
  listen 80;
  # ドメインもしくはIPを指定
  server_name webapp ;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  # ドキュメントルートの指定
  root /webapp/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @webapp;
  keepalive_timeout 5;

  # リバースプロキシ関連の設定
  location @webapp {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://webapp;
  }
}
```

この設定ファイルのproxy_passを適当に書き換えてわざとエラーをおこします。（場所はどこでもいいかも）

##2.dockerを再ビルドして起動する。

```
$ docker-compose down
$ docker-compose up -d --build
```
-dオプションはバックグランドで実行してくれます。
--buildオプションをつけるとビルドから起動まで一気にやってくれます。

そうすると、

```
$ docker-compose ps
    Name                  Command               State           Ports
----------------------------------------------------------------------------
webapp_app_1   bundle exec puma -C config ...   Up
webapp_db_1    docker-entrypoint.sh mysqld      Up       3306/tcp, 33060/tcp
webapp_web_1   /bin/sh -c /usr/sbin/nginx ...   Exit 1
```

エラーが起きて webapp_web_1コンテナがExitするはずです。（コンテナ名は、docker-compose.ymlの設定で変わるので各自置き換えてください。）

##3.書き換えたnginx.confを元に戻して再ビルド
ここで適当に書き換えてわざとエラーを起こしたnginx.confのファイルを元に戻します。
そして2を再び実行します。
そしたらなぜか反映されるようになりました！嬉しい！！

##最後まで読んでいただきありがとうございます！
正直今回の方法がどういうロジックで治ったのか？そもそも正しいのか？というのはわかりません。もし、わかるかたがいましたらコメントいただけると幸いです。

とりあえず、これをやったら治ったというのは事実です。production環境でプリコンパイル時にCSS読み込みがうまくいかないとかならまだわかるんですが、今回は突然のエラーだったので治すのに時間がかかってしまいました。同じエラーに遭遇している方に、こちらが役に立てばうれしいです！
RubyとGem

####Gem（ジェム）

Rubyを用いた開発において使用できるツール（ライブラリ）。
ただしGemは他のGemの機能を使って成り立っているものが多く、単体では使用できないことが多い。

####bundler

そこで出番はこの**「bundler」**
欲しいGemに関連する必要Gemをまとめてインストールしてくれます。超便利。
ちなみにbundlerもGemの一つだったりする。

####Gemfile.lock

bundlerでbundle installしたときに、自動生成される情報が記録されているファイル。１つのGemのためにどのGemをどのバーションで合わせてインストールしたか確認できる。
勉強日誌20日目

今日と月曜日は出社なので時間がない・・・。
ほんとに次につながるスキルが手に入らないから早く実力証明できるものを手に入れなければ！

時間は自分で作るものだ


このトピック一番苦手
明日ももう1回やろ
来週の土曜日1回受けにいく予定です
でもコロナ怖い

正答率　64％ （74）

lsof
システムのリソースを使用しているプロセスの情報を表示

lsof -i:25
ポート25を使っているプロセスを表示

chage -l user
ユーザ　user　のパスワードの有効期限に関する情報

nmap
指定してるホストの開いているポートを一覧表示

正答率　56%(72)

/etc/xinetd.conf
スーパーサーバxinetdの設定ファイル

user=user
xinetd.confでユーザをuserに指定する

log_type
ログの出力先

/etc/xinted.d
xinetdでそれぞれのサービスごとの設定ファイルを置くディレクトリ

/etc/init.d
initにより各種サービスのディレクトリ

wait=no
xinetd.confのマルチスレッド

正答率　67% (52)

gpg -o pubkey --export user@aaa.com

ssh -p 1111 server

ssh
インターネット上のサーバにログインし、管理、設定する際のプロトコル

gpg -e -r メール　ファイル

~/.gnupg
GnuPGに関連するファイルの置かれるディレクトリ

/etc/ssh/sshd_config
sshdの設定ファイル

/etc/ssh/ssh_config
SSHのクライアントファイル
GAS（Google Apps Script）で定期的に値を記録するプログラムを作ってみた

#1．はじめに

Googleスプレッドシートで、あるサイトのある特定の値をXPathで抽出しておき、その値をGAS（Google Apps Script）で、定期的（１時間置きに）にGoogleスプレッドシートの別シートに記録していくというプログラムを作ってみます。

※サンプルとして、あるAm〇zonギフト券販売サイトの値を監視するプログラムを書いてますが、アクセスが集中するなどご迷惑をお掛けると良くないので、どこのサイトかという事まではここでは書かないことにしておきます。

#2．GoogleスプレッドシートでWEBページの特定の値を表示

・スプレッドシートの「A1」セルに対象のWEBページのURLを記載
・4行目以降に、そのWEBページの中で特定の値がセル上に書かれるようにする。
　－「=IMPORTXML(URLのセルを指定, XPath) 」で取得

![FireShot Capture 137 - Amazonギフト券履歴 - Google スプレッドシート - docs.google.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/517958b7-f8ec-93bf-a603-239c227b9ea8.png)

#3．GASでGoogleスプレッドシートを読んで、別シートに記録する

・Googleスプレッドシートには、記録用の別シート「履歴」を作っておくこと
・GoogleスプレッドシートのURLから、ID部分を記録しておくこと

なお、ID部分というのは、GoogleスプレッドシートのURLの↓の部分になります。
https://docs.google.com/spreadsheets/d/[ID部分]/edit#gid=337972102

```Javascript:code.gs
//取得するスプレッドシートを指定。スプレッドシートのURLのID部分を指定する。
var ssFile = SpreadsheetApp.openById("**GoogleスプレッドシートのIDを指定**");
//値を取得する対象のシートを指定
var baseSheet = ssFile.getSheetByName("取得シート"); 
//記録するシートを指定
var saveSheet = ssFile.getSheetByName("履歴");

//定期的に実行させる関数
function MainFrame() {
  //「取得シート」の4行目1列目から、1行分3列分のセル（つまり4行目の3セル分を取得）
  var array = baseSheet.getRange(4,1,1,3).getValues()[0];
  //今の日時を取得して指定したフォーマットに変換
  var date = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm');
  array.unshift(date);
  
  //最終行に配列データを追加で記録する
  saveSheet.appendRow(array);
}
```

#4．定期的に記録

「[『GAS（Google Apps Script）でHelloWorldしてみた（①バッチプログラム編）』の5章](https://qiita.com/jun_higuche/items/540d1a0b32293607d860#5%E5%AE%9A%E6%9C%9F%E7%9A%84%E3%81%AB%E5%8B%95%E3%81%8B%E3%81%99%E3%81%9F%E3%82%81%E3%81%AE%E8%A8%AD%E5%AE%9A)」で書いたような感じで、トリガーで「MainFrame」関数を１時間に１回動作するように設定します。

履歴が溜まってくると、こんな感じになります。
![FireShot Capture 140 - Amazonギフト券履歴 - Google スプレッドシート - docs.google.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448092/820422e2-3124-5f07-ffb1-158e5160de41.png)
※↑のグラフはGoogleスプレッドシートの機能で表示させてるだけです。

#5.ところが、一箇所思い通りに行かない点が（※後から追記しました）
運用初めてからしばらく後でわかった事なのですが、「IMPORTXML」関数は、２時間に１回しか更新されない模様Σ(ﾟдﾟlll)ｶﾞｰﾝ

どうしようかと考えた挙句、↓のようなコードで、毎回、「IMPORTXML」関数を削除してから、再度「IMPORTXML」関数を書き込むことで、そのときに新しく取得してくれることがわかりました。とりあえず、これでいいやっと。

```Javascript:
  // 強制的に更新させるための処理
  baseSheet.deleteRows(4,1);
  baseSheet.getRange(4,1).setValue("=IMPORTXML(A1,\"//span[@class='fl bl']/text()\")");
  baseSheet.getRange(4,2).setValue("=IMPORTXML(A1,\"//span[@class='fl og']/text()\")");
  baseSheet.getRange(4,3).setValue("=IMPORTXML(A1,\"//span[@class='fl gr']/text()\")");

```

#6．まとめ
おわかりいただけるように、こんな短いプログラムを書くだけで、便利なツールが出来てしまうのです。GASって超便利ですね！！
実は、個人的にAm〇zonギフト券の値段がいつ頃が安くなり易いのかを分析するために、履歴を見たかったのですが、無かったので、作ってしまったという次第なのです。。
VSCodeでDocker管理

Dockerで開発環境を管理してVSCodeでコーディングしたい
その為に調べた一連の流れとVSCode上でDockerの操作を記述しました。

#### 環境:
Windows 10 Home: 2004
VSCode: 1.49.2
Docker: 19.03.12


## Remote Developmentインストール
VSCodeを立ち上げて拡張機能で**Remote Development**を検索してインストール

## 実行環境の作成
Remote Developmentを用いた開発でのファイル構造はこんな感じです。

```
プロジェクト
├ .devcontainer
　├ devcontainer.json
　└ Dockerfile
└ 内容
```

プロジェクト直下にある**.devcontainer**フォルダ内にある
**devcontainer.json**と**Dockerfile**にコンテナに関する設定を記述する感じです。
例ではPythonの環境を[ここを参考](https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0)に書いておきます。

```
DockerPython
├.devcontainer
  ├ devcontainer.json
  └ Dockerfile
├ requirements.txt
└ test.py
```
```ruby:Dockerfile
#-------------------------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
#-------------------------------------------------------------------------------------------------------------

FROM python:3
```
```ruby:devcontainer.json
{
    "name": "Python 3",
    "context": "..",
    "dockerFile": "Dockerfile",

    "settings": { 
        "terminal.integrated.shell.linux": "/bin/bash",
        "python.pythonPath": "/usr/local/bin/python",
        "python.linting.enabled": true,
        "python.linting.pylintEnabled": true,
        "python.linting.pylintPath": "/usr/local/bin/pylint"
    },

    "appPort": [ 9000 ],

    "postCreateCommand": "pip install -r requirements.txt",

    "extensions": ["ms-python.python"]
}
```
```ruby:equirements.txt
scikit-learn
```
```test.py
print("haloworld")
```


## コンテナの作成・起動
左下にある**[><]**をクリック、その後**Remote-Containers: Open Folder in Container…**を選択、そして
**先ほど説明したプロジェクト(例ではDockerPython)**を選択でコンテナが立ち上がります。(少し時間がかかります)
無事立ち上がりプロジェクトが表示されるされたら、試しにターミナルで**python test.py**と**pip freeze**を実行してみましょう。

```
/workspaces/DockerPython# python test.py
haloworld
```

```
/workspaces/DockerPython# pip freeze
joblib==0.16.0
numpy==1.19.2
scikit-learn==0.23.2
scipy==1.5.2
threadpoolctl==2.1.0
```

以上の通りになればちゃんと出来ています。

## コンテナから抜ける
再び左下にある**[><]**をクリック、その後**リモート接続を終了する**を選択
するとコンテナから抜けることが出来ます。またコンテナも停止する。

## コンテナに再び入る
Remote Developmentをインストール際に出来たバーの**リモートエクスプローラー**をクリック
その後出てきたリスト内から先ほどのプロジェクトをクリックその後出てきたファイル端の**Open Contaner**を
クリック、そうすればコンテナが再起動して再び入ることが出来ます。

## コンテナの削除
コンテナから抜けた後**リモートエクスプローラー**をクリック
消したいプロジェクトを右クリックで出てくるメニューで**RemoveContaner**をクリック
するとコンテナは削除される

## Docker拡張機能
VSCodeの拡張機能として**Docker**があります。
実行環境を作る上ではRemote Developmentで十分ですが
Dockerは**レスポンスが良くイメージも表示してくれる**のでコンテナの管理の為に
一緒に入れとくのも良いと思います。


# 感想
Remote Developmentを使えばVSCodeでDocker環境での開発ができる上
コマンドを打たずにDockerの操作出来ていい感じでした。



# 参考
https://qiita.com/Yuki_Oshima/items/d3b52c553387685460b0

https://paiza.hatenablog.com/entry/2019/07/08/VSCode%E3%81%A8Docker%E3%81%A7%E7%B0%A1%E5%8D%98%E3%81%AB%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89%EF%BC%86%E5%85%B1%E6%9C%89%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95
[Laravel] 特定のマイグレーションだけをマイグレート、ロールバックしたい！！！

#初めに
入社してから与えられた課題で、特定のマイグレーション以外をロールバックして、修正、特定のマイグレーション以外を再び実行するという操作をしたくなったのですが、なかなか情報が見つからず、たくさんのサイトを見て得た情報と最終的に見つけた自己流の解決策を紹介します。
#マイグレーションは連続的なものであるという前提
いざというときにLaravelがデータを安全にロールバックできるようにするための仕組みがマイグレーションというものらしいです。
だから、マイグレーションはそれらが作成された順にひとつずつ実行しています。

この前提から特定のマイグレーションだけを実行することは邪道なのではという疑念を抱きつつ、解決策へ、、、

#解決策
###特定のマイグレーションだけをマイグレートする
`php artisan migrate:refresh`を応用して使います。

##### マイグレーションを指定したファイルから１つだけマイグレートする
```
php artisan migrate:refresh  --step=1 --path=/database/migrations/ファイル名
```
step=○の数字を変えることで、マイグレートするファイルの数を変更できます。
###特定のマイグレーションだけをロールバックする
コメントアウトを使います。

```
public function up()
    {
        Schema::create('flights', function (Blueprint $table) {
            #$table->increments('id');
            #$table->string('name');
            #$table->string('airline');
            #$table->timestamps();
        });
    }
    public function down()
    {
        #Schema::drop('flights');
    }
```
ロールバックしたくないファイルを上記のようにコメントアウトし、ロールバックすると、このファイルが無視されます。
クラスとモデル

##クラスとは
- rubyの概念
- 複数のデータと処理（メソッド）をまとめて入れた箱（オブジェクト指向）。設計図のようなもの。

##モデルとは
- railsの概念 ~~Ruby~~
- クラスには違いないが、必ずモデルに対応したテーブル（データベース）を持つ
- 例えばPostモデルにはpostsテーブル（テーブルには複数のデータが入るため名前は複数形になる）　=> 逆にモデル名は必ず単数形で命名すること。
MVVM Show View パターン3 Prism の Dialog Service

## 参考コード （Prism 7）
https://stackoverflow.com/a/61555337/9924249
https://github.com/HakamFostok/prism-boilerplate

通常のWindowの表示なのかDialogに限定した表示なのか、よくわからなかったのですが、新しいWindowの表示にも利用するようです。
ここでは、stackoverflowに書かれている回答をもとに考えてみます。
### View

```C#
    <StackPanel>
        <Label Content="{Binding Title}"></Label>
        <Button Content="Open Window" Command="{Binding OpenWindowCommand}"></Button>
    </StackPanel>
```

OpenWindowCommandを実行しウインドウを開くことを期待できますが、どのウインドウを開くのかは分かりません。Viewは、他のViewを知らない、と言えるはずです。

### ViewModel

```C#
        private void OpenWindowCommandExecuted()
        {
            _dialogService.ShowWindowTest(CloseWindowEventHandler);
        }

        private void CloseWindowEventHandler(IDialogResult dialogResult)
        {
        }
```

ViewModelは、ボタンを押されたら、ShowWindowTestを実行します。メソッド名からみると、WindowTestViewをShowすることが期待されていますが、本当にそのウインドウを開くのかは分かりません。そのため、ViewModelは、WindowTestViewを知らない、と考えれば良いでしょうか？
メソッド名が、単に、ShowWindow、だったらと考えてみると、WindowTestViewを知らないことがはっきりします。
また、ウインドウが閉じられた後の処理（CloseWindowEventHandler）ができます。

### Model

```C#
    public static class DialogServiceExtensions
    {
        public static void ShowWindowTest(this IDialogService dialogService, Action<IDialogResult> action)
        {
            dialogService.ShowDialog(nameof(WindowTestView), new DialogParameters(), action);
        }
    }
```

WindowTestViewの名前を知っているのはModelです。public staticなので（IDialogService経由？）、どこからでも呼び出すことができますが、この例では、ViewModelから呼び出されています。

Prism 7のこの例では、Modelが確定したウインドウの名前を知って表示していることになると思います。

### _dialogService

```C#
        protected BaseViewModel()
        {
            _dialogService = ServiceLocator.Current.GetInstance<IDialogService>();
        }
```

ちなみに、このViewModelで使われている_dialogServiceは、BaseViewModelにあります。


##Prism公式ドキュメントでは
https://prismlibrary.com/docs/wpf/dialog-service.html

### Using the Dialog Service
では、VMに次のコードを書いているようです。

```C#
    _dialogService.ShowDialog("NotificationDialog", new DialogParameters($"message={message}"), r =>
```

VMで、"NotificationDialog"というウインドウ名を指定しています。

### Simplify your Application Dialog APIs
もっと簡単に利用できるように、DialogServiceExtensionsで、Showする方法が書かれています。

```C#
public static class DialogServiceExtensions
{
    public static void ShowNotification(this IDialogService dialogService, string message, Action<IDialogResult> callBack)
    {
        dialogService.ShowDialog("NotificationDialog", new DialogParameters($"message={message}"), callBack, "notificationWindow");
    }
}
```
この場合、ここで"NotificationDialog"のウインドウ名を指定しています。

## まとめ
Prismでは、Dialog ServiceにViewの表示処理を、VMから渡してしまうようです。
また、VMでViewの名前をパラメータとして指定していても、MVVMとしてはOKというPrismの考えと思われます。名前の文字列なので、参照はしていない、という理屈なのでしょうか。

## 記事予定

* パターン1　[Viewのコードビハインド](https://qiita.com/hiro_t/items/967146f2ccb79318397c)
* パターン2　[Commandパラメータ](https://qiita.com/hiro_t/items/b177c40e03d22ef24068)
* パターン3　Prism の Dialog Service（この記事）
* パターン4　引数を渡す（予定）
Laravel6のAPIをデバッグ時にAccess-Control-Allow-Originでハマった

# cors対策はfruitcake/laravel-cors
```
composer require fruitcake/laravel-cors
```
既にパッケージはインストール済みで、設定もしてあること前提。
普通にAPIを叩くだけなら、正常に動く。

で、APIの修正やら新規作成する時にデバッグしたい箇所をdump & exitしようとする。
あれ。。。デベロッパーツールのコンソールに見たことあるエラーが表示される。。。

```
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```

# Access-Control-Allow-Originがhearder情報に無い
ここでしばらくハマった。。。
なんで他のAPIは普通に動くのに、デバッグしてるAPIや新規作成途中のAPIだけがCORSのエラーを履くのか。。。
hearder情報を確認するとAccess-Control-Allow-Originが確かにhearder情報に無い。。。

どうやら、
APIの処理→fruitcake/laravel-cors→responceらしく、途中で処理を止めちゃってたのが原因だった。

でも、どうしてもdump & exitでデバッグしたい！と色々やってみた。

# bootstrap/app.php
今回の案件では、bootstrapを使える様にしていたので、bootstrap配下のapp.phpの頭に以下コードを埋め込んでみた。

```
header('Access-Control-Allow-Origin: *');
```

ちゃんとデベロッパーツールのNetwork>Previewで見れた！！！

# 最後に
bootstrap/app.phpに追加したコードは忘れずに削除する。
削除を忘れると、headerにAccess-Control-Allow-Originが2つ存在するので、それはそれでエラーになる。

あんまり利用する場面は少ないと思いますが、CORSのエラーでハマってる方はお試しください。
でも、CORS対策でbootstrap/app.phpにheader('Access-Control-Allow-Origin: *');を書くのは厳禁です！（当たり前ですが。。。）
ちょっとしたデバッグ時に、config.phpとかを修正しなくてもdumpさせるチョイ技でした。
c# 画像をバイナリーデータとしてDBに保存する

DBに画像をバイナリーデータで保存する必要があったためのメモです。
なんだかんだ初ですのでちょっと沼りました。
ただの技術メモなのでご了承下さい。

使用DBはPostgreです。

それでは早速
下記が画像をDBに突っ込む過程です。

```
Bitmap bmp = new Bitmap(@"C:¥sample.jpg");
MemoryStream ms = new MemoryStream();
bmp.Save(ms,ImageFormat.jpeg);
byte[] binaryData = ms.ToArray();
NpgsqlCommand cmd = new NpgsqlCommand();
cmd.Connection = 環境にあった設定
cmd.CommandText = ("INSERT INTO TableName (Column) VALUES (:binaryData)");
NpgsqlParameter param = cmd.Parameter,Add("binaryData",NpgsqlDbType.Bytea);
param.Value = binaryData;
cmd.ExecuteNonQuery();
```


``Bitmap bmp = new Bitmap(@"C:¥sample.jpg");``
Bitmapの引数に画像の場所を指定します。

``MemoryStream ms = new MemoryStream();``
メモリを使って読み取りなどできるやつです。

``bmp.Save(ms,ImageFormat.jpeg);``

>Save(Stream, ImageFormat)	
>このイメージを、指定した形式で指定したストリームに保存します。

らしいですね。
バイナリーデータに変換します。

``byte[] binaryData = ms.ToArray();``
バイナリーデータを取り出します。

``cmd.CommandText = ("INSERT INTO TableName (Column) VALUES (:binaryData)");``
``NpgsqlParameter param = cmd.Parameter,Add("binaryData",NpgsqlDbType.Bytea);``
``param.Value = binaryData;``

こちらについてはルールっぽい？
sql実行するための準備ですね。
https://www.postgresql.jp/document/9.4/html/datatype-binary.html
絶賛学習中です。

``cmd.ExecuteNonQuery();``
sql実行。

続いて、バイナリーデータから画像表示です。

```
MemoryStream ms = new MemoryStream(binaryData);
Bitmap bm = new Bitmap(ms);
PictureBox.image = bm;
```

``MemoryStream ms = new MemoryStream(binaryData);``
先ほどのバイナリーデータをMemoryStreamで読んであげます。

``Bitmap bm = new Bitmap(ms);``
ビットマップに変換してあげます。

``PictureBox.image = bm;``
これで画像が表示できます。
【作ってみた】js不使用。CSSだけでマウスホバーで動く自動ドア作った。

# どうも7noteです。電車に乗っていてふと突然、「そうだ自動ドア作ろう」って思ったので作ってみた。

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/coding/autodoor/
Gitを使っていて起きる様々な『取り消したい！！』

# ●Gitを使っていて起きる様々な『取り消したい！！』
Gitを使っていると、時々、「今のコミット取り消したい！」みたいなことが起きたので、メモがてらまとめておきます。
今後他の方法なども書き加えて行けたらとも思っています！

## ①ファイルへの変更をターミナルから取り消す(※git add前)
※ファイルに色々変更を加えたけど、まっさらな状態に戻したい！という時に使う

```:ターミナル
~$ git checkout -- <ファイル名>
~$ git checkout -- <ディレクトリ名>
```

```:ターミナル
#全ての変更の取り消し
~$ git checkout -- .
```


## ②ステージに追加した変更を元に戻したいとき(※git add後/git commit前)
うっかりgit addしたけど戻したい時

```:ターミナル
~$ git reset HEAD <ファイル名>
~$ git reset HEAD <ディレクトリ名>
```

```:ターミナル
#全ての変更を取り消す(指定した変更をステージから取り消すだけなので、ワークツリーのファイルには影響はない)
~$ git reset HEAD .
```

【裏側で起きている動作の説明】
ワークツリーからgit addでステージに加えられた変更を、
ローカルリポジトリに現在ある最新の(直前の)コミットから情報を持ってきて上書きしている。
つまり、HEADというのがその上書きするために用いられる、リポジトリの最新のコミットの内容を示していて、
それを使ってreset(上書き)するよ！ということ

※git addによる変更を取り消しただけなので、ファイルには書き直したい?内容は残ったままになる。

## ③直前のコミットをやり直す(git commit後/git push前)
※リモートリポジトリにpushしたコミットはやり直してはだめ！！！
複数人で開発をしていた場合、他の人のリポジトリの状態とリモートリポジトリの内容が異なり取り込めないと言ったことが発生するため

```:ターミナル
~$git commit --amend
```

今のステージの状態を元に直前のコミットをやり直す（git addでやり直したい内容をステージに追加 → git commit --amendで直前のものを修正）

## おまけ
今回の取り消し作業とは関係ないのですが、Git GitHub用語に関してイラスト付きでイメージしやすい説明をされてるサイトがあったので、Git初めてでよくわからないよーという方は見てみてください。
[【イラストで覚える】初心者のためのGitとGitHub用語集](https://zukulog098r.com/git/)
創薬化学AI : 非加算性を有したデータの機械学習モデルに対する影響

## なにこれ
英国王立化学会(RSC)が主催するシンポジウムのポスターに興味深い記事があったので読んでみた主に自分向けの記録。

https://www.rsc.org/events/detail/42785/3rd-rsc-bmcs-rsc-cicag-artificial-intelligence-in-chemistry

以下、こちらのポスターを翻訳しています。図を貼るのがめんどいので、これを見ながら読んでけさい。

https://twitter.com/NittingerEva/status/1306911769986764802

英語力がガバいので変な翻訳しているかも。時間をかけて見直していきます。

## 忙しい人のための超要約
構造活性相関の前提になっている原則を無視するような官能基の組み合わせとかアッセイ結果が実はけっこうあるっぽいのでモデル作ったり予測するときには気をつけようね:relaxed:

## Abstract
「線形性」と「加算性」は量的構造活性相関(QSAR)モデリングにおいて基礎となる仮定(前提)である。Free-WilsonやMatched molecular pairs(MMP)といった手法は、置換基の線形性および加算性を前提としている。こうした前提ゆえに、未知の化合物に対する予測は信頼できるものとなりうるのである。

しかしながら、それぞれ単一で変更を加えた場合に想定よりもはるかに高い/低い活性をもたらす2つの官能基の組み合わせのような「SARにおける非加算性」はたびたび観測され、未知の化合物に対するSARを予測する際に問題となりうる。

ということで、我々は ChEMBLE25をベースとしたスケールの大きな生理活性データと、アストラゼネカの社内アッセイデータにおける非加算性の発生事情を分析した。結果、社内データ内の二次アッセイデータと、公共データ内の三次アッセイデータの両方において重大な非加算性が見受けられた。加えて、アストラゼネカのデータベースに含まれる全化合物の9%およびChEMBLに含まれる全化合物の5%は、重要な構造活性相関の特徴か、基本的な測定誤差を暗示するような有意な非加算性シフト？を示している。

最後に、非加算性が機械学習アルゴリズムやそれらの予測結果にどれほど影響を及ぼすかを示す。

## Introduction
構造活性相関の基礎となる基本原則：類似性、線形性、そして加算性

* 類似性：類似する化合物は類似した生理活性を示しやすい（という原則）
* 線形性：化学者たちがR基の最適化を繰り返している最中に見込まれるもの。この戦略は「ベストなR1基は、分子内の他のR基から独立して最も良好である」ものと想定している。線形性は、異なる置換基による影響はおそらくプラスされ増えていく＝加算性が成り立つだろう、ことをほのめかす
* 類似性と加算性の原則は、例えばFree-Wilson分析や2D/3D QSARあるいはMMP分析などのCADD(Computer aided drug design)における数々の確立された領域の基礎となっている

## Methods and Data Prepatation
* 非加算性(Non-additivity, NA)は化学的二重変異体サイクルにより定義される:すなわち、2つの同一な変換と関連している4つの分子において、以下の式で表される。
  * Non-additivity = ΔΔpAct = (ΔpAct2 - ΔpAct1) - (ΔpAct4 - ΔpAct3)
* NA分析はオープンソースのコードを用いて行われた。
* 生物学的データの実験的不確かさ(Experimental uncertainty)はin silicoの予測モデル性能に直で影響を及ぼす
  * pAct(exp) = pAct(true) + ε
  * 実験的不確かさを考慮し、公共データについては0.5、社内データについては0.3を閾値としてNA判定する？
* データキュレーションは以下の通りに実施。

## Results

### 非加算性分析
* ほとんどの非加算性は実験的不確かさということでで説明できる。
* 23.9% / 9.1%の試験データ、9.3% / 5.1%の化合物は明らかな非加算性が見受けられた
  * 社内データ / 公共データ

### 機械学習に対する非加算性の影響
* 明らかな非加算性を示すデータに対しては正確な予測ができない。
* 非加算性を示すデータを含んだ学習を行うとモデル性能は向上しない。

## Conclusion
* 公共データにも社内データにも、相応の数の非加算性をもつ化合物が見つけられた。これらは日頃のモデリングにおいて常に考慮される必要がある。
* ChEMBLE データは(社内データに比べて)NAが少なかった。理由としては、cpds/testの少なさか、実験的不確かさのカットオフの違いなのでは？
  * (CPDS ってなんだ...？)
* 非加算性を有したデータは機械学習において正しく予測することは難しい。そのため、非加算性分析は機械学習モデルをトレーニングする際に定期的に考慮されるべきである(それが現状グッドプラクティスとして推奨されていなかったとしても)。

## おわりに
2Dフィンガープリントみたいに平面的で局所的な構造しか捉えられない特徴量だけで活性予測するとか無茶くね？そんな単純な問題じゃないよね？...とモヤモヤしてたので、今回のポスターはそんなモヤモヤに対する1つの答えになったのかなと感じました。ChEMBL使って自分で検証もできそうなので、時間があれば試してみたい。
ターミナルからマスターにマージする方法

ターミナル操作によって、ファイルの追加、マージまでを一通りするコマンドについて書いていきます。

まず初めに、ファイルへ移動コマンドcd(チェンジディレクトリ)を押してcd~と移動したいところへ移動します。

目的のファイルへ移動後、VSCで都度変更を行う中で、commit、pushが必要になります。

まず、git add .とターミナルに入力します。これで変更した内容を上げます。

次に、git add commit -m"コミットしたい内容の名前"と入力します。これでリモートリポジトリに変更内容が上がります。

ここまでで、まだリポジトリを作成していない場合は、git remote add origin Newリポジトリのurlと入力します。これでリポジトリを登録します。

最後に、ターミナルでgit push origin masterを入力します。これで、マスターに上がります。:relaxed::sunny:
tmuxの用語集

# tmuxとは？

リモートマシンにsshなどで接続した時に役に立つツール。
tmuxの機能は画面分割したりや複数タブを開いたり、セッションを保持したりするツール。
ローカルマシン単体で開発を行うエンジニアはほとんど恩恵を受けることはできません。

## tmux用語集

### Prefix

これは、ショートカットキーを入力する前に入力する必要があるキーの組み合わせです。

tmuxのデフォルトのプレフィックスはctrl + bです。
ショートカットがcの場合、<ctrl + b> + cと入力する必要があります。

### Session

tmuxが管理する最大のユニット。
「アタッチ/デタッチ」する対象です。
セッションからデタッチしても、セッションは引き続きバックグラウンドで実行されます。

### デタッチ

コンソールから切り離すことをデタッチといいます。デタッチされたセッションはバックグラウンドで生き続けます。

デタッチはprefix dでできます。

### アタッチ

デタッチしたセッションを再度繋ぎ直すことをアタッチと言います。
直前のセッションは以下のようにアタッチ出来ます。

```
# 直前のセッションを繋ぎ直す
tmux a

# セッション名を指定してアタッチもできる
tmux a -t セッション名
```

### Window

これは、セッションに存在するのと同じタブです。
1つのセッションで複数のウィンドウを持つことができます。
セッション内でウィンドウを作成して切り替えることができ、タブを移動すると画面全体を切り替えることができます。

### Pane

ウィンドウに存在する画面単位です。
ウィンドウには複数のペインを配置できます。
画面全体を縦に2つに分割すると、2つのペインが作成されます。

## Sessionの基本

### sessionを始める

```
tmux
```

## 設定を適応する

```
tmux source ~/.tmux.conf
```

## 参考文献

[Install tmux on OSX and Basics Commands for Beginners | by Jeongwhan Choi | Medium](https://medium.com/@jeongwhanchoi/install-tmux-on-osx-and-basics-commands-for-beginners-be22520fd95e)

[ターミナル（黒い画面）を分割して使う tmux 超入門 - ばうあーろぐ](https://girigiribauer.com/tech/20200427/)


[ターミナルマルチプレクサ tmux をカスタマイズする - Qiita](https://qiita.com/b4b4r07/items/01359e8a3066d1c37edc)

[tmuxで快適なターミナル生活を送ろう - Qiita](https://qiita.com/zwirky/items/adbf22abad7d7822456b)

[【tmux】設定ファイル(.tmux.conf)を編集し、即時反映・適用させる方法 - Qiita](https://qiita.com/chatrate/items/ce09f2aaaba9869f2f7a)

[ドヤァッ！！コマンド一発で複数画面表示！【tmuxinator】でターミナルを華麗に操作しよう | 株式会社LIG](https://liginc.co.jp/313035)

[tmuxを必要最低限で入門して使う - Qiita](https://qiita.com/nl0_blu/items/9d207a70ccc8467f7bab)
docker build --help 日本語訳

``docker build --help`` 実行時に表示されるドキュメントの日本語訳。

# 使用法:

```
docker build [OPTIONS] PATH | URL | -
```

[Dockerfile](https://qiita.com/JhonnyBravo/items/c743a20c539c1aaaa2a9) からイメージをビルドする

# オプション: 

* --add-host list
  カスタムのホストから IP へのマッピングを追加します( ``host:ip`` )
* --build-arg list
  ビルド時変数を設定する
* --cache-from string
  キャッシュソースとして使用するイメージ
* --cgroup-parent string
  コンテナーのオプションの親 cgroup
* --compress
  gzip を使用してビルドコンテキストを圧縮する
* --cpu-period int
  CPU CFS(Completely Fair Scheduler)期間を制限する
* --cpu-quota int
  CPU CFS(Completely Fair Scheduler)の割り当てを制限する
* -c, -cpu-shares int
  CPU シェア(相対ウェイト)
* --cpuset-cpus string
  実行を許可する CPU(0-3, 0, 1)
* --cpuset-mems string
  実行を許可する MEM(0-3, 0, 1)
* --disable-content-trust
  イメージ検証をスキップ(デフォルトは true)
* -f, -file string
  [Dockerfile](https://qiita.com/JhonnyBravo/items/c743a20c539c1aaaa2a9) の名前(デフォルトは ``PATH/Dockerfile`` )
* --force-rm
  常に中間コンテナを削除する
* --iidfile string
  イメージ ID をファイルに書き込みます
* --isolation string
  コンテナ隔離技術
* --label list
  イメージのメタデータを設定する
* -m, --memory bytes
  メモリ制限
* --memory-swap bytes
  スワップ制限はメモリ + スワップに等しい: ``-1`` は無制限のスワップを有効にします
* --network string
  ビルド中に RUN 命令のネットワークモードを設定します(デフォルトは ``default`` )。
* --no-cache
  イメージのビルド時にキャッシュを使用しない
* -o, -output stringArray
  出力先(形式: ``type=local,dest=path`` )
* --platform string
  サーバーがマルチプラットフォーム対応の場合はプラットフォームを設定する
* --progress string
  進行状況出力のタイプを設定します
  コンテナの出力を表示する場合は ``plain`` を指定してください(デフォルトは ``auto`` )
  * auto
  * plain
  * tty
* --pull
  常にイメージの新しいバージョンのプルを試行します
* -q, --quiet
  ビルド出力を抑制し、成功したらイメージ ID を表示する
* --rm
  ビルドが成功した後、中間コンテナを削除します(デフォルトは true)
* --secret stringArray
  ビルド時に公開する秘密ファイル(BuildKit が有効な場合のみ): ``id=mysecret,src=/local/secret``
* --security-opt string
  セキュリティオプション
* --shm-size bytes
  ``/dev/shm`` のサイズ
* --squash
  新しく構築されたレイヤーを単一の新しいレイヤーにまとめる
* --ssh stringArray
  ビルド時に公開する SSH エージェントソケットまたはキー(BuildKit が有効な場合のみ)(形式: ``default|<id>[=<socket>|<key>[,<key>]]`` )
* --stream
  ストリームはサーバーに接続してビルドコンテキストを交信します
* -t, -tag list
  名前を指定する。 ``name:tag`` の形式で指定する。
* --target string
  ビルドするターゲットビルドステージを設定します。
* --ulimit ulimit
  Ulimit オプション(デフォルト ``[]`` )
Boost.Qiのqi::ruleについて少し調べた(1)

qi::ruleというものがあるが、これも初心者には分かりにくい。

英語で見てみる。。。
https://theboostcpplibraries.com/boost.spirit-rules

boost::spirit::ascii::digit can be both a parser and a rule. Typically, rules refer to more complicated expressions like qi::int_ % ','.

つまり、整数, 整数, というcsv的な表現はかさばるので、qi::ruleを使って名前をつけてしまうと吉ということではないだろうか。

プログラムを見てみる。。。

3,4,5といった文字列のコンマを、セミコロンに変換したいとする。

     1#include <boost/spirit/include/qi.hpp>
     2#include <string>
     3#include <vector>
     4#include <iterator>
     5#include <algorithm>
     6#include <iostream>
     7
     8using namespace boost::spirit;
     9
    10int main()
    11{
    12  std::string s;
    13  std::getline(std::cin, s);
    14  auto it = s.begin();
    15  qi::rule<std::string::iterator, std::vector<int>(),
    16           ascii::space_type> values = qi::int_ % ',';
    17  std::vector<int> integer_vector;
    18  if (qi::phrase_parse(it, s.end(), values, ascii::space, integer_vector))
    19    {
    20      std::cout << "parse OK" << std::endl;
    21      std::ostream_iterator<int> out{std::cout, ";"};
    22      std::copy(integer_vector.begin(), integer_vector.end(), out);
    23    }
    24  else
    25    std::cout << "parse fail" << std::endl;

https://github.com/RuoAndo/qiita/blob/master/qi4.cpp

+```c++
    15  qi::rule<std::string::iterator, std::vector<int>(),
    16           ascii::space_type> values = qi::int_ % ',';
+```

であるが、これは、qi::int_ % ','というパース規約にvaluesをいう名前を付けている。
このvaluesというruleを、18行目で使っている。

+```c++
    18  if (qi::phrase_parse(it, s.end(), values, ascii::space, integer_vector))
+```

実行してみる。。。

<pre>
$ ./a.out 
2,3,4
parse OK
2;3;4;
$ ./a.out 
string
parse fail
</pre>
JAZUG(Japan Azure User Group)10周年記念！イラスト風のじゃずにゃんを作ってみた。（ライティングを反映しないマテリアルを持ったglTF）

今回は、Blenderのメモです。立体的なじゃずにゃんもいいけど、2Dイラスト的なじゃずにゃんもいいなと思い、ライティングを反映しないマテリアルを用意して、glTF（glb）としてエクスポートしてみました。

以下URLに書かれているKHR_materials_unlitで設定します。

https://docs.blender.org/manual/ja/dev/addons/import_export/scene_gltf2.html#exported-materials

# ライティングを反映しないマテリアルを設定

方法はドキュメントに書かれている通り、下図の右側にあるマテリアルの設定から、サーフェスをBackgroundに設定するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/3e953f7e-6328-973a-e79a-ec1d24d9e36c.png)

設定した後に、glTFにエクスポートしてみます。

# Power Point で確認

エクスポートしたglTF（glbファイル）をPower Pointにドラッグアンドドロップして確認してみます。手前のじゃずにゃんが今回作成したglTFになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/7d563db6-1644-4d90-78f9-edbcc58efca6.png)

# さいごに

イラストが動いている感じになりました。こっちもいいですね。今回作成したglTF(glb)は以下になりますので、Japan Azure User GroupのLTやセッションでご利用ください。

https://github.com/KentaroAOKI/jaznyan/raw/master/jaznyan_unlit.glb
[CSS] flex align-itemsの混合の方法

CSSで要素の縦並びを中央揃えにしたり上揃えにしたりしたくなる時ありますよね？

単に中央揃えにしたかったら親要素を次の通りにすればいいだけです。

```css
.parent {
  display: flex;
  align-items: center;
}
```

でも、ある子要素だけ中央揃えでなくベースラインにしたい場合はどうすればいいでしょうか？

調べたところ、どうやらalign-selfをその子要素に設定すればいいようでした。

```css
.parent {
  display: flex;
  align-items: center;
}

.top {
  align-self: baseline;
}
```

コードの全体はCodePenに上げました。
https://codepen.io/kter/pen/jOqJEGO
Android でFIS_AUTH_ERRORエラー  Firebaseプッシュ通知が届かない

#はじめに
![3864.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/cb31ee9c-3e35-9b7f-1086-8a6b97aca33f.jpeg)

運営しているアプリを機種変更してから初めて起動すると突如、このようなエラーに見舞われた。。。。

#環境
Ionic 5 + Angular で開発したのネイティブアプリ
[Ionic プッシュ通知を送るテスト（Capacitor）](https://qiita.com/kokogento/items/c3390f16895a76dbde70#androidの設定)
:point_up:この記事と全く同じやり方でプッシュ通知を実装しました。

#解決までにやったこと
※結論から言うと、解決はしてません。。。

##Google Cloud PlatformでAPIの制限を追加
![スクリーンショット 2020-09-25 19.45.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/5cb59e37-3603-199e-1384-53a65da547f7.jpeg)


ずっと、「キーを制限しない」になっていたが、追加してみた。

>The FIS_AUTH_ERROR means Authentication for Firebase installation sdk has failed. 

https://stackoverflow.com/questions/60698622/java-io-ioexception-fis-auth-error-in-android-firebase

と言うことらしいので。

##Firebase SDK を追加する
[こちら](https://firebase.google.com/docs/cloud-messaging/android/client#add_firebase_sdks_to_your_app)を参考に、`app/build.gradle`に以下を追加

```gradle
dependencies {
    // 省略
    implementation 'com.google.firebase:firebase-messaging:20.1.2'
    implementation 'com.google.firebase:firebase-analytics:17.5.0'
}
```

しかしながら、[Using Push Notifications with Firebase in an Ionic + Angular App](https://capacitorjs.com/docs/guides/push-notifications-firebase#download-and-use-the-google-services-json-file)のドキュメントでは、以下のような記述がある。

>We don't need to add any dependencies to our project because Capacitor projects automatically include a version of firebase-messaging in it's build.gradle file.

何もdependenciesに追加する必要はない、と言っているが、、、とりあえず追加してみよう。

ゾウさんボタンでアプリを同期
![スクリーンショット 2020-09-25 20.20.58.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/bda4e25e-0554-671d-c35c-9bdb47fc9805.jpeg)




##google-services.jsonを新しく入れ替える
`Firebaseコンソール画面からプロジェクトを選択＞設定＞マイアプリ`の項目から新しくgoogle-services.jsonをダウンロード。

そして置き換える。




#エラーは消えたが、プッシュ通知を目視することはできなかった！！！:pensive:

```console
2020-09-25 19:35:13.665 15955-15955/com.hCalendar.app I/Capacitor/Console: File: http://localhost/common.js - Line 371 - Msg: プッシュ通知を受け取ったよ: {"id":"0:1601030113498713%b2260e4cb2260e4c","data":{},"title":"寒くなりましたね。。","body":"人肌を重ねてあったまりましょう"}
2020-09-25 19:35:13.811 15955-16488/com.hCalendar.app D/FA: Connected to remote service
2020-09-25 19:35:48.363 15955-15955/com.hCalendar.app I/Ads: Use RequestConfiguration.Builder().setTestDeviceIds(Arrays.asList("01C5204CC8216A22615E0A6DF7BDDD97") to get test ads on this device.
2020-09-25 19:35:48.393 15955-16288/com.hCalendar.app W/m.hCalendar.ap: Accessing hidden method Lsun/misc/Unsafe;->getObject(Ljava/lang/Object;J)Ljava/lang/Object; (greylist, linking, allowed)
2020-09-25 19:35:48.393 15955-16288/com.hCalendar.app W/m.
```

結局エラーは消えたが、プッシュ通知は確認できなかった。。。（コンソール上のログでは確認できてるので、一応届いてはいる？？？:thinking:）

うーん。。。どうすればいいんだろう？？
どなたか情報提供お願いします:sweat_smile:



#参考
https://stackoverflow.com/questions/60698622/java-io-ioexception-fis-auth-error-in-android-firebase
直接アドレス指定、間接アドレス指定、指標(インデックス)アドレス指定、基底(ベース)アドレス指定、相対アドレス指定、即値アドレス指定

応用情報技術者平成28年秋期 午前9

間接アドレス指定方式のアドレス部で指定するものはどれか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/6702e774-8d13-5ffb-b86c-bcdbacca34f4.png)


１、コンピューターの命令は、
命令部とアドレス部(オペランド)から構成されています。
※命令の種類によってはアドレス部がないものもあります

２、アドレス部
アドレス部では命令の処理対象となるデータのメモリ上の位置を指定しますが、この指定方法には次に挙げる6種類があります。

・直接アドレス指定
　アドレス部の値をそのまま有効アドレスとする。

・間接アドレス指定
　アドレス部の値で主記憶上のアドレスを指定し、そのアドレスに格納されている値を有効アドレスとする。

・指標(インデックス)アドレス指定
　アドレス部の値にインデックスレジスタの値を加えたものを有効アドレスとする。

・基底(ベース)アドレス指定
　アドレス部の値にベースレジスタの値を加えたものを有効アドレスとする。

・相対アドレス指定
　アドレス部の値にプログラムカウンタの値を加えたものを有効アドレスとする。

・即値アドレス指定
　アドレス部の値を有効アドレスではなく、そのまま演算対象データとする。


３、
・処理対象データが格納されている記憶場所のアドレス
⇒直接アドレス指定方式の説明です。

・処理対象データが格納されている記憶場所のアドレスが格納されている記憶場所のアドレス
⇒間接アドレス方式の説明です。

・処理対象データが格納されている記憶場所のアドレスとアドレス計算の基準点との差分
⇒基底(ベース)アドレス指定方式の説明です。

・処理対象データ自体
⇒即値アドレス指定方式の説明です。


参照：
https://www.ap-siken.com/kakomon/28_aki/q9.html
`gcloud functions deploy`で、"Failed to find attribute [project]."とエラーになった

```bash
$ gcloud functions deploy hello_http --runtime python38 --trigger-http --allow-unauthenticated

ERROR: (gcloud.functions.deploy) Error parsing [name].
The [function] resource is not properly specified.
Failed to find attribute [project]. The attribute can be set in the following ways: 
- provide the argument [--project] on the command line
- set the property [core/project]
```

上記のようなエラーが出た。

どうもプロジェクトを指定していないのが原因のようだ。

`gcloud auth login`で認証をしたあと、

```bash
gcloud config set project <PROJECT_ID>
```

で作成済みのプロジェクトのプロジェクトIDを指定してあげればOK。
[暗号通貨自動売買] TVExtBotスタートガイド6(Telegram通知ボット設定編)

TVExtBot for 暗号通貨(以下、TVExtBot)のTelegram通知ボット設定について説明します。
前回の記事をまだ見ていない方はこちらをどうぞ
 :point_right: [TVExtBotスタートガイド1(設定編)](https://qiita.com/tvextbot/items/5cc7e8028879b706b5e7)
 :point_right: [TVExtBotスタートガイド2(Pineスクリプト編)](https://qiita.com/tvextbot/items/969510a1940cedce8d44)
 :point_right: [TVExtBotスタートガイド3(注文メッセージ作成及び設定編)](https://qiita.com/tvextbot/items/07c82d50f880bdc4c818)
 :point_right: [TVExtBotスタートガイド4(決済&認証キー登録編)](https://qiita.com/tvextbot/items/101f3124f0add013329c)
 :point_right: [TVExtBotスタートガイド5(Webhook設定編)](https://qiita.com/tvextbot/items/f0602dc3639cab072d9c)

<font color="green">🎁**Bybit 取引手数料15%割引&特典**
Bybit取引所の**アフィリエイトリンク**を使ってアカウントを新規登録していただくと、**取引手数料15%割引**と**最大90ドルの登録特典**がいただけます。
 :point_right: [アフィリエイトリンク](https://www.bybit.com/en-US?affiliate_id=5246&group_id=0&group_type=1)
 :point_right: [登録特典ページ](https://www.bybit.com/ja-JP/prize_page/)
</font>

# 設定方法
Telegramのユーザー名を登録すると売買情報およびエラーメッセージをリアルタイムで受け取ることができます。

① TVExtBot設定画面の基本設定を選択し、@TTVExtBotリンクをクリックしてTelegram通知ボットを登録します。
![스크린샷 2020-09-25 22.03.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/78b4bca5-40d6-4191-53a0-ffd008f8b20d.png)
<font color="red">※スマートフォンにTelegram通知ボットを登録する場合は下記のリンクをクリックしてください。</font>
 :point_right: [Telegram通知ボットサービス](https://t.me/TTVExtBot) 
② Telgramアプリの設定よりプロフィールを開き、ユーザー名をコピーします。(<font color="red">@は除く</font>)
![스크린샷 2020-09-25 22.08.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/7923a4dc-26f8-6b11-a6b6-adf62df6d90f.png)
③ TVExtBot設定画面の基本設定へ戻り、ユーザー名に「bkson55」を入力し適用ボタンをクリックします。
![스크린샷 2020-09-25 22.14.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/ceb9baad-d39d-fdfa-08c5-9ca49567057d.png)
④ 下記のように売買情報およびエラーメッセージをリアルタイムで受け取ることができます。
![스크린샷 2020-09-26 22.59.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/7631ec0b-a31f-73a2-9aba-e502c666b3e3.png)
# トラブルシューティング
Telegramの通知がこない場合は下記の手順を実施してください。
① TVExtBot設定画面の基本設定に登録したユーザー名を削除します。
![스크린샷 2020-09-26 23.07.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/32e15a58-db0a-741d-6770-061adff82920.png)
② Telegramのチャットを削除します。
![스크린샷 2020-09-26 23.10.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/1a0f1cfd-0c2c-a773-da11-0544da223e14.png)
③ TVExtBot設定画面の基本設定にあるリンクをクリックし、Telegramのチャットを再登録します。
![스크린샷 2020-09-26 23.15.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/5c1eafbe-4389-5acd-f39e-714a7cd145a1.png)
④ TVExtBot設定画面の基本設定にユーザー名を再登録します。
![스크린샷 2020-09-26 23.17.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/a0b3fabe-2430-7741-6343-a1e905930d5e.png)
WebSocketによって実現できること

応用情報技術者平成28年秋期 午前7

WebSocketによって実現できるのはどれか。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/a0fcac80-a7e6-70c0-cd48-57661b59cdae.png)

１、WebSocketは、
Webアプリケーションにおいてクライアント(Webブラウザ)とWebサーバの間で効率的な双方向通信を実現するプロトコルです。

・Webにおける標準プロトコルであるHTTPは
「クライアントのリクエストに対してサーバがレスポンスする」という1組の通信が基本手順になっていて、サーバが自発的にクライアントに対してデータを送れるようにはなっていません。

HTTP：
クライアント⇒リクエスト⇒サーバ⇒レスポンス

・HTTPの問題点：※自動的に最新情報を更新する必要システムがその問題あり。
HTTPの仕組み(例えば自動的に最新情報に更新されるシステム)を実現するためにはAjaxのようにクライアントから定期的にリクエストを送らせ、サーバ側で適宜返答を行う仕組みが必要でした。しかし短い間隔で定期的に行われる情報取得の度にTCPコネクションが確立され、HTTPでのやり取りが発生するためパフォーマンス的には決して良い方法ではありませんでした。

クライアント⇒リクエスト⇒サーバ⇒レスポンス
　(定期的に) 
※短間隔で上記の流れを定期的に行われるので、効率が悪いです。

・WebSocket
WebSocketを使用したデータ通信では、まずHTTPの手順に則り、クライアントとサーバで1組のHTTP通信を交してWebSocket用の通信路を確立します。その後はHTTPの手順に縛られず、1つのTCPコネクション上でデータのやり取りが行えるようになっています。この仕組みによりオーバヘッドが少なくなり、リアルタイム性が必要とされるシステムを効率的に実現できるようになります。

WebSocket用の通信路を確立してから、１つのTCPコンネクション上でデータのやり取りを行える。
リアルタイム性が必要なシステムが実現できる。

参照：
https://www.ap-siken.com/kakomon/28_aki/q7.html
【セミナー】オンライン会議に役立つファシリテーション

登壇者：園部牧場株式会社代表取締役　園部浩司

表題：明日から使えるファシリテーション


「会議をうまく進めるのに必要なもの＝＝ファシリテーション」
脱線する、結論が出ない、目的不明確etc...を解決


◆フレイムワーク、ロジカルシンキングの本を読む


1.仕事とは＜問題解決すること＞
　- 力
　- 作業系
　- 問題解決　→人しかできない
2.
　- 企画力：現状と理想のギャップの絵を描く
　- プレゼン力：説明力
　- マネジメント力：課題の切り出し、役割分担
　- 土台
    - ファシリテーション：意見を引き出し、まとめる
    - ロジカルシンキング：色々な情報整理、発信の方法を持つ

3.ファシリテーションとは
・他対他のコミュニケーション
・会議を円滑に進めること：進行しつつ活発な意見のでる場づくりをする
・意見を受け入れる：賛同するとは違う。「そういう論点もありますね」などと返答


◆ファシリテータの役割
・ファシリテータは進行役、メンバーは発言役ということを意識
・意見の偏りをなるべく避ける
・質問は答えやすくする
  - 一言ずつ何週か聞く(一回くらいならパスOKとか)
  - 解決策を求めるのでなく気になるところありますかのように
  - 質問は明確に投げかける→いろんな質問の投げかけ方を考える)
・ファシリテータの役割　→ 会議をデザインする！
  - 問題解決に向けて、情報収集（意見収集）、整理(可視化)し、決断の場所に会議という場を利用する
・問題解決ステップ
  1.現場把握
  2.理想を描く
  3.問題
  4.原因の洗い出し→主原因の特定
  5.解決策の洗い出し→特定
  6.活動計画の策定
  7.実行


◆概要
　1.事前準備
　　　・アジェンダ作成：項目書き出しでなく、時間設定をつけた会議プログラムを作る
　2.
   1.時間管理
　　　・意識づけ
   2.合意形成
     ・決定方法：リーダなどに一任
　　　・粒度：担当者が困らない程度の方向性に
　　　- 意志決定マトリクス
　　　- ペイオフマトリクス

4.会議の種類を考える
　- 報告、連絡：情報共有が目的。議論いらない。
　- 進捗会議：情報共有、上司が部下を教育する目的。
　- 問題解決：問題特定、原因の洗い出し、解決策の検討決定、活動計画まで落とし込むのが目的

5.いい会議とは
・時間厳守
・アウトプットの質（解決仕方）
・参加者の納得度：意見をたくさん聞き、反映することにより満たされる
*納得度の測り方→一人ひとりにコメントをもらう。内容よりもトーンをチェック。必要あれば会議後にフォロー


◆オンライン会議
＜話のリズムが悪い＞
＜反応がとらえにくい＞
→カメラをつける！視覚の要素は大きいから。。







打ち合わせを開く意味＝＝色々な目線での意見を集めるために打ち合わせを開く
[暗号通貨自動売買] TVExtBotスタートガイド5(Webhook設定編)

TVExtBot for 暗号通貨(以下、TVExtBot)のWebhook機能の設定する方法について説明します。
前回の記事をまだ見ていない方はこちらをどうぞ
 :point_right: [TVExtBotスタートガイド1(設定編)](https://qiita.com/tvextbot/items/5cc7e8028879b706b5e7)
 :point_right: [TVExtBotスタートガイド2(Pineスクリプト編)](https://qiita.com/tvextbot/items/969510a1940cedce8d44)
 :point_right: [TVExtBotスタートガイド3(注文メッセージ作成及び設定編)](https://qiita.com/tvextbot/items/07c82d50f880bdc4c818)
 :point_right: [TVExtBotスタートガイド4(決済&認証キー登録編)](https://qiita.com/tvextbot/items/101f3124f0add013329c)

Webhook機能を使用すると、TradingViewアラートのWebhookとTVExtBotサーバーが連動して自動売買を行うので、パソコンを起動しておく必要がありません。
<font color="red">**※Webhook設定は不要です。**</font>
<font color="red">**※Webhook機能はPREMIUMバージョン使用者のみ設定できます。(設定)**</font>

<font color="green">🎁**Bybit 取引手数料15%割引&特典**
Bybit取引所の**アフィリエイトリンク**を使ってアカウントを新規登録していただくと、**取引手数料15%割引**と**最大90ドルの登録特典**がいただけます。
 :point_right: [アフィリエイトリンク](https://www.bybit.com/en-US?affiliate_id=5246&group_id=0&group_type=1)
 :point_right: [登録特典ページ](https://www.bybit.com/ja-JP/prize_page/)
</font>

# Webhook設定方法
先に認証キー登録を行なってから、下記の設定を進めて下さい。
:point_right: [TVExtBot 決済&認証キー登録ガイド](https://qiita.com/tvextbot/items/101f3124f0add013329c)

① TVExtBot設定画面から基本設定をクリックします。
![스크린샷 2020-09-25 20.34.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/86f55966-8e40-c616-68a5-f05f6fdd5da4.png)
② Webhookモードを選択し、適用ボタンをクリックします。
![스크린샷 2020-09-25 20.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/99a2611d-141e-7ce1-2886-65d8e3054240.png)
③ メッセージ作成画面を開く、Webhook用のURLアドレスが表示されます。
![Webhook URLアドレス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/feb4c053-53c1-09ac-bc71-b97a7df92c43.png)
④ メッセージ作成画面でメッセージ作成を行います。
<font color="red">**※作成方法はアラムモード(既存方式)で作成した注文メッセージと異なるので、Webhookモードに変更したら再度注文メッセージを作成してください。**</font>
![注文メッセージ作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/84c5b8fd-a6e4-bcb0-e9e0-9379b3a6b9f0.png)
⑤ TradingView画面のアラート設定画面で注文メッセージとWebhookアドレスをコピーして貼り付けてください。
![스크린샷 2020-09-25 20.46.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402678/2e08f9e7-ff5b-6c5b-7be0-25e088a8bb02.png)

以上、ほかの設定は既存方式と同様ですので、省略します。
[PlayCanvas]入力イベントの取得

# 概要
キーボードやマウス、スマホのタッチ操作などのイベントを処理する機能。

# 実装例
## マウス
``` javascript:mouse.js
var Mouse = pc.createScript('mouse');

Mouse.prototype.initialize = function() {
    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.mouseDown, this);
};

Mouse.prototype.mouseDown = function(event) {
    console.log("X: " + event.x.toString() + "Y: " + event.y.toString());
};

Mouse.prototype.update = function(dt) {
    // ホールドはupdateで取れる
    if( this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT) ){
        console.log("Pressing Left Mouse Button.")
    }
};
```
**initialize**で**this.app.mouse**に実行したい処理とイベントのキーを渡す事で実装する。
もしくは、**wasPressed**を**update**で呼び出して押されたかをチェックする事で実装もできる。(離した瞬間は**wasReleased**)

マウスボタンを押し続けている(ホールド)間に処理を実行したい場合は**isPressed**で状態を取れる。

| Event | 内容 |
|:--|:--|
| pc.EVENT_MOUSEDOWN | 押された時 |
| pc.EVENT_MOUSEUP | 離した時 |
| pc.EVENT_MOUSEMOVE | 移動した時 |
| pc.EVENT_MOUSEWHEEL | ホイールを動かした時 |


## キーボード
``` javascript:keyboard.js
var Keyboard = pc.createScript('keyboard');

Keyboard.prototype.initialize = function() {
    this.app.keyboard.on(pc.EVENT_KEYDOWN, this.onKeyDown, this);
};

Keyboard.prototype.onKeyDown = function(event) {
    // event.keyにキーコードが入っている
    if( event.key === pc.KEY_A ){
        console.log( "Press A" );
    }
};
```
**initialize**で**this.app.keyboard**に実行したい処理とイベントのキーを渡す事で実装する。
マウス同様、**isPressed**や**wasPressed**があるので、ホールドの検知や**update**での記述が可能。

| Event | 内容 |
|:--|:--|
| pc.EVENT_KEYDOWN | 押された時 |
| pc.EVENT_KEYUP | 離した時 |

## タッチ(スマホなど)
``` javascript:touch.js
var Touch = pc.createScript('touch');

Touch.prototype.initialize = function() {
    this.app.touch.on(pc.EVENT_TOUCHSTART, this.touchStart, this);
};

Touch.prototype.touchStart = function(event) {
    // event.touchesに画面に触れた場所の配列が入ってくる
    if( event.touches.length > 0 ){
        console.log("X: " + event.touches[0].x.toString() + "Y: " + event.touches[0].y.toString());
    }
};
```

**initialize**で**this.app.touch**に実行したい処理とイベントのキーを渡す事で実装する。
タッチイベントはマウスとキーボードと違い、**update**内で検知を行う関数はない。

| Event | 内容 |
|:--|:--|
| pc.EVENT_TOUCHSTART | 触れた時 |
| pc.EVENT_TOUCHEND | 離した時 |
| pc.EVENT_TOUCHMOVE | スワイプされた時 |
| pc.EVENT_TOUCHCANCEL | 何かしらの理由で、タッチをキャンセルされた時 |
ワンタイムパスワードをサーバー側とクライアント側で作るサンプル

## ワンタイムパスワードのロジックを作ってみた

2020/09/25 現在では何かと銀行がクラックされまくっているが、いずれもワンタイムパスワードのような認証が入ってない。もちろんワンタイムパスワードも「そのワンタイムの間に」盗まれればアウトなんだけど、常時通信内容を奪うのは盗む方も大変だ。

ただ、ワンタイムパスワードの仕組みが、Google Authenticator などの外部の仕組みに依存するのは、別の意味でリスク（急に仕様が変わるなど）。

なので、自前でどこまでできるかを検証。

## どのようにして動く？

以下の要素を組み合わせて、ダイジェスト（sha256）を生成し、ダイジェストから数値6桁を取り出してます。

- ユーザ毎に違う秘密鍵（クライアントとサーバーで同じ秘密鍵を持ちます）
- タイムスタンプ（今回のサンプルでは60秒で割った整数部を使います）
- ソルト（サーバー側で保持する長い文字列）

## サンプルソース

### 端末側

```onetime.js

async function digestMessage(message) {
  const encoder = new TextEncoder();
  const data = encoder.encode(message);
  const hash = crypto.subtle.digest('SHA-256', data);
  return hash;
}

function buf2hex(buffer) { // buffer is an ArrayBuffer
  return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
}

async function onetimePass(secret_key){
  const ts_min = parseInt( Date.now() / 60000 ).toString();
  const buffer = await digestMessage(secret_key + '_and_sault' + ts_min);
  const hexString = '0x' + await buf2hex(buffer) ;
  const digitString = BigInt(hexString).toString(10);
  return digitString.slice(-6);
}
```

```onetime.html
<html>
<script type="text/javascript" src="./onetime.js"></script>
<body>
<script>
(async () => {
document.write(await onetimePass('secret_key'));
})();
</script>
</body>
</html>
```

### サーバー側

```onetime.rb
require 'digest/sha1'

def onetime_pass(secret_key, next_min = false)
  # タイムスタンプを秒から分に丸める
  ts_min = Time.now.to_i / 60
  ts_min += 1 if next_min # 次の分までカバーしたい場合（チェックを受ける側）
  text = "#{secret_key}_and_sault"
  Digest::SHA256.hexdigest("#{text}#{ts_min}").to_i(16).to_s[-6, 6]
end

# ちょうど一分をまたがることを想定して、一分後のパスワードも取得できるようにしてる
puts onetime_pass('secret_key')
puts onetime_pass('secret_key', true)
```

## 実行結果

フロント側とサーバー側で同じ6桁ができてることがわかる。
（サーバー側のニ行目は、1分後のパスワード）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53489/db56a84a-e94c-9261-f658-ca85368c1bb2.png)


## 心残り部分

- 久しぶりにJS書いたら何実行してもPromiseばかり帰ってくる。試行錯誤で, async, await を書きまくったけど、あんまり自身がない。
- RFCにもちゃんとワンタイムパスワードのロジックはあるらしいが読まずに「きっとこういうことだろう」で済ませてる
- 端末側はJSで書いちゃったけど、肝心の「秘密鍵を渡す方法」がこの記事では触れられてない。QRコードで渡すのが良さそうだけど、QRコードを読んで端末側のローカストレージに秘密鍵を保存するというプログラムの方がよほど上記のソースよりも長くなりそう。そういうことまで考えると、 Google Authenticator　を使い、 Google Authenticator のサーバー側のライブラリを使っちゃうので解決か。
- sha256でダイジェストを作ったけど、10進数にして最後の6桁を取り出してる時点で、衝突確率は増える。
iOS 14 Safariではホスト名にアンダースコア（_）が含まれるWebページへのHTTPSアクセスが失敗する【一部未検証箇所あり】

# TL;DR

ホスト名にアンダースコア `_` は使わないこと。
下記の条件下で問題が起きる。

- HTTPSページにSafariでアクセスする
- iOS 14
- ホスト名にアンダースコアが含まれる

下記は未検証

- 証明書がワイルドカード証明書のときに起こったが、それ以外の証明書でも起こるのか？

DO NOT use any underscore `_` in HTTPS hostname, or you will encounter a SSL certificate error while accessing HTTPS web page in Safari on iOS 14 or later version.

# 発見の経緯

## 起こった不具合

iOS 14にアップデートしたところ弊社（onecareer.jp）サイト内の某LPのコンテンツが表示されなくなった。

## 対象ページについて

Headless CMSを使ってコンテンツ入稿し、ajaxでCMSからコンテンツ取得してjQueryでページにコンテンツを埋め込んでいた。

## トラブルシュート

### 初動
iOS 14のSafariでしか起こっていないので、iPhoneをMacにつないでSafariの開発者モードを起動。
失敗しているHTTPリクエストを調査。
SSLエラーによりコンテンツ取得していないことが判明。

### 調査
iOS 14に関する証明書絡みのネタを洗った。
[2020年9月1日以降に発行した証明書は1年ちょっと以内の有効期限じゃないといけなくなる変更が発表](https://support.apple.com/en-us/HT211025)されているが、今回の証明書はそのNGパターンに該当しない。
けれども、証明書検証ロジックに変更があったのは確かっぽい。

Headless CMSのサイト側も怪しいので、ajaxから叩くエンドポイント以外でも再現するページがないか、iOS Safariでアクセスしてみる。
一部の管理側ページも同様のエラーが起こることを確認。
エラーが発生する条件を帰納的に調べたところ、アンダースコア `_` がホスト名に含まれるサイトで同様の不具合が発生することが分かった。

## 考察

そもそも、RFC的にはホスト名にアンダースコアは含めることができない。
だが、今回利用していたHeadless CMSは、CMSのワークスペースを生成するときにアンダースコアを含むワークスペース名を指定することができた。
また、そのCMSはワークスペース名をそのままサブドメイン部に用いたサイトを生成し、その中でコンテンツ管理をする仕様になっていた。

これまでのバージョンのiOS Safariは、RFCの定義に反し暗黙のうちにアンダースコアを含むホスト名の証明書検証をパスしてきた模様。
一方、直近のiOS Safariでの証明書検証ロジックが変更され、アンダースコア周りの処理条件も暗黙のうちに厳格化されたと考えられる。

# まとめ

Webの世界はたくさんRFC非準拠な実装が溢れているが、自分だけはRFCを守ろう。
それが自分の身と、自分の周りの大切な人を守ることに繋がる。
読書会「プログラマが知るべき97のこと」 #5

# 1．今回の読んだ記事
No.14　[コードレビュー](https://xn--97-273ae6a4irb6e2hsoiozc2g4b8082p.com/%E3%82%A8%E3%83%83%E3%82%BB%E3%82%A4/%E3%82%B3%E3%83%BC%E3%83%89%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC/)　
著者: Mattias Karlsson

# 2．記事の概要
**コードレビューはコードの誤りを指摘するだけでなく、チーム全員に同じ知識を共有させること**

+ 友好的な態度で参加する
+ 単に誤りを探すだけでなく個人のコードについて学び、理解することを心掛ける
+ 新人でも違う着眼点からの気づきができる
+ できるだけ砕けた雰囲気でレビューを楽しいものにする


# 3．この記事を選んだ理由・感想
**理由**
コードレビューを実施する際の着眼点について、「間違いを指摘するだけではない」ということを本記事で学んだので共有したかった。
また、チーム全員に同じ知識を共有させることも重要だと感じたから。

**感想**
これまで、自分の間違いを指摘してもらう以外にも、他人のコードから学ぶ・情報を共有するといった観点でレビューできていなかった。
自分のチーム以外の人のソースコードから学んでみたいと思った。
（早速、コロナ対応サイトのOSSなどを眺めてみたとのこと）

# 4．議論
**このエッセイで書かれているようなソースコードレビューをするのは今の業務だと難しいかも**

   - 本文より：曜日を決めて毎週実施する・レビュー時間を2時間かける
     - このやり方で実施するには、現在の業務とはフローが違いすぎる
     - エッセイのやり方は、勉強会のようなスタイルは合うかもしれない


**普段実施しているソースコードレビューの「観点」は何ですか？**

- 見やすいコードかどうかをチェックする
    - 変数、メソッド名などの命名
    - 無駄な処理がないか、代替で利用できるライブラリがないかも提案する
- 処理が停止するところに着目して、おかしな値が入ることがないのかを見る（例えばNULLが入る可能性など）
- 設計書通りに作られているか

	
**他のチームの皆さんは、どのようなやり方でレビューを実施していますか？**

- 基本は全員参加で実施
    - チームメンバーが全員同じ知識にしたいので、全員参加としている
    - 対面実施のときは、レビューされる人がすべての説明を行う
        - 担当機能に対する理解度を確認したいから
    - 対面でやるのは情報共有としてはよいが、参加しているだけで理解した気になってしまう可能性もあるので注意している
    

**レビューの雰囲気については筆者の言う通りだと思う**

- あまり熱心にやりすぎなくてもいい
    - コードレビューの中でバグの発見は難しいため、隅々まで見るほど熱心にならなくてよい気がする
    - 簡単なものなら回覧でもよいかもしれない
- 嫌な気分で会議をやりたくない
    - ソースコードレビューだけではなくて、会議の雰囲気は大事！

# まとめ
**「砕けた雰囲気でレビューを楽しいものにする」** という点。
本会議の雰囲気はどうだろうか、あらためて考えた。
批判や指摘などは無いので悪いものではないと思うが、若手などは意見が言いにくくなってはいないか。
懇親も兼ねているので、誰でも言いたいことを言えるようにしたいと思う。
次回に続く。
インスタンスメソッドとクラスメソッドの使い分け

# インスタンスメソッドとクラスメソッドの使い分け
今回は、インスタンスメソッドとクラスメソッドの使い分け方について書いてみます。

# インスタンスメソッド
#### インスタンスごとで挙動を制御したい場合に使用します
* インスタンスを生成しないと呼び出すことができない
* インスタンス名.メソッド名で呼び出すことができる
* 第一引数には`self`を用いる

# クラスメソッド
#### クラス全体で共通の挙動を制御する際に使用します
* インスタンス化しなくてもメソッドを呼び出せる
* クラス名.メソッド名で呼び出すことが可能
* メソッドの一番上に`@classmethod`と付けることで定義する
* クラスメソッドの第一引数は`cls`を用いる

# 学校を例にしたインスタンスメソッドとクラスメソッドの使い分け
```python:学校
class Class:
    # 学校全体の入学者数
    all_students_count = 0

    def __init__(self, teacher_name, grade, group):
        self.teachername = teacher_name
        self.grade = grade
        self.group = group
        self.roster=[]

    def enter(self, name):
        # インスタンスメソッド
        self.roster.append(name)
        Class.all_students_count +=1

    @classmethod
    def reset_students_count(cls, reset):
        # クラスメソッド
        cls.all_students_count = reset

# インスタンスメソッドで2年3組の入学者を記録
cl_23 = Class("山中", 2, 3)
cl_23.enter("平沢")
cl_23.enter("秋山")
cl_23.enter("田井中")
cl_23.enter("琴吹")
cl_23.enter("真鍋")

print("2年3組の入学者名簿" , cl_23.roster)
print(cl_23.all_students_count)
#出力: 2年3組の入学者名簿 ['平沢', '秋山', '田井中', '琴吹', '真鍋'], 5

# インスタンスメソッドで1年1組の入学者を記録
cl_11 = Class("豊田", 1, 1)
cl_11.enter("金子")
cl_11.enter("佐藤")
cl_11.enter("清水")

print("1年1組の入学者名簿" , cl_11.roster)
print(cl_11.all_students_count)
#出力: 1年1組の入学者名簿 ['金子', '佐藤', '清水'], 8

# クラスメソッドで全ての入学者数をリセット
Class.reset_students_count(0)
print(cl_11.all_students_count)
#出力:0