OmniAICreator/Qiita-1.07M huggingface dataset:
ESP32からMicropythonでHTTPリクエスト(POST)でデータを送信し，PHP(サーバ)で受け取る

# 環境
マイクロコントローラー：ESP32
ファームウェア：Micropython1.3

サーバ：Ubuntu18.04
ウェブサーバ：Apache2
PHP：PHP7.4


※ESP32にMicropythonが入っていないと実行できませんのでご注意ください．
※もしMicropythonの入れ方を知りたい人がいたらこちらを参照ください．　>>> [ESP32にmicropythonを入れる方法（uPyCraftを使います）](https://qiita.com/sirius1000/items/0d8aad6abae996051ff6)

# やりたいこと

![スクリーンショット 2020-12-11 13.54.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/459889/53392622-9375-cc5e-e3ee-eed5b5e0df8d.png)

例えば，**ESP32からセンサーのデータを取得した後，データをサーバに送りたい！**とか

今回は上の図のように，ESP32からファームウェアMicropythonで，サーバであるUbuntu18.04(Apache2)に対してHTTP POSTでデータ送信をします


# ESP32
MicropythonにはHTTPリクエストをするためのモジュールが備わっています．
それが**urequests**というモジュールです．

また今回はデータをJSON形式にして送信するので，そのための**ujson**モジュールも利用します．

**※なおurequestとujsonはPythonのモジュールであるrequestsとjsonと使い方はほぼ同じです**

以下ソースコードになります．

```py
import urequests
import ujson

#送信先のURLの指定
url = 'http://xxx.xxx.xxx.xxx/test.php'

#データをDICT型で宣言
data = {
             "value" : "23.4",
             "text" : "Hello World!"
             }

#jsonデータで送信するという事を明示的に宣言
header = {
        'Content-Type' : 'application/json'
         }

#HTTPリクエストをPOSTとして送信
res = urequests.post(
    url,
    data = ujson.dumps(data).encode("utf-8"),
    headers = header
)

#サーバ側からのレスポンスを受け取って表示(jsonのデコードも一緒にしている)
print (res.json())

#終了
res.close()
```

コードの意味はコメントアウトで書いてあるのでそちらを参照ください．


# サーバ

受け取り側のプログラムはPHPを使って書いていきます．

予め，ウェブサーバであるApache2の起動を行っておいてください．

もしPHPのインストールが済んでいない方は下記コマンドでインストールをお願いします．

```shell
sudo apt install php7.4 libapache2-mod-php7.4
```

```shell
$ sudo systemctl start apache2
$ systemctl status apache2
● apache2.service - The Apache HTTP Server
   Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
  Drop-In: /lib/systemd/system/apache2.service.d
           └─apache2-systemd.conf
   Active: active (running) since Wed 2020-12-09 08:01:07 UTC; 1 day 21h ago
  Process: 8442 ExecReload=/usr/sbin/apachectl graceful (code=exited, status=0/SUCCESS)
 Main PID: 1049 (apache2)
    Tasks: 7 (limit: 4915)
   CGroup: /system.slice/apache2.service
           ├─1049 /usr/sbin/apache2 -k start
           ├─4001 /usr/sbin/apache2 -k start
           ├─8446 /usr/sbin/apache2 -k start
           ├─8447 /usr/sbin/apache2 -k start
           ├─8448 /usr/sbin/apache2 -k start
           ├─8449 /usr/sbin/apache2 -k start
           └─8450 /usr/sbin/apache2 -k start
```


次にPHPファイルを書いていきます．
Apache2は**/var/www/html/**配下にファイルを置きます．

test.php

```php
<?php
//送られてきたPOSTデータを受け取って，JSONデータをデコードして$inに入れる．
$in = json_decode(stripslashes(file_get_contents('php://input')),true);

//送られてきたデータを取り出す
$value = $in["value"]; // = 23.4
$text = $in["text"];   // = Hello World!

//レスポンスを「Completed!」とし，それをJSONとして再度エンコード
//そして送信元(ESP32)へ返す．
echo json_encode("Completed!");
?>
```

コードの意味は同様にコメントアウト参照ください．


# 実行
ESP32にて実行をします．

```shell
>>> execfile("test.py")
["Completed!"]
```

実行をしてCompleted!という文字列が帰ってくれば成功です．


# おわり
今回はHTTP POSTを使ってESP32からサーバへデータを送信しました．
これを応用すれば受け取ったデータをデータベースに保存することも可能になります．
時間があればその記事も書くつもりです．
MDAnalysisがインストールできないときの対処

# 概要
MDAnalysisのcondaを使ったインストールで失敗したので、対処法を書いておきます。

## 状況
MDAnalysisのインストールを[チュートリアル](https://www.mdanalysis.org/MDAnalysisTutorial/installation.html#conda-installation)通りに進めていたが、

```
conda install --yes -n mdaenv MDAnalysis MDAnalysisTests
```

のところで、以下のエラーが出た。

```
Solving environment: failed

PackagesNotFoundError: The following packages are not available from current channels:

  - mdanalysis
  - mdanalysistests

Current channels:

  - https://repo.anaconda.com/pkgs/main/linux-64
  - https://repo.anaconda.com/pkgs/main/noarch
  - https://repo.anaconda.com/pkgs/free/linux-64
  - https://repo.anaconda.com/pkgs/free/noarch
  - https://repo.anaconda.com/pkgs/r/linux-64
  - https://repo.anaconda.com/pkgs/r/noarch
  - https://repo.anaconda.com/pkgs/pro/linux-64
  - https://repo.anaconda.com/pkgs/pro/noarch

To search for alternate channels that may provide the conda package you're
looking for, navigate to

    https://anaconda.org

and use the search bar at the top of the page.
```

## 対処法
リポジトリのチャンネルを指定する。`-c conda-forge`

```
conda install -c conda-forge --yes -n mdaenv MDAnalysis MDAn
alysisTests
```

これで、mdaenvにcondaをつかってMDAnalysisをインストールできた。

## 原因
[インストール](https://www.mdanalysis.org/MDAnalysisTutorial/installation.html#conda-installation)の最初にあるこのコマンドがうまく行っていなかったと考えられる。

```
conda config --add channels conda-forge
```
Viにおける「E325:ATTENTIONエラー」への対処


#E325:ATTENTIONエラー」
はじめに

viでファイルを開こうとすると

```
E325: ATTENTION
Found a swap file by the name "/var/tmp/******
          owned by: ************   dated: 木 12 10 22:52:04 2020
         file name: /private/etc/****
          modified: YES
         user name: *******   host name: ***
        process ID: *****
While opening file "/etc/*****"
      CANNOT BE FOUND
(1) Another program may be editing the same file.  If this is the case,
    be careful not to end up with two different instances of the same
    file when making changes.  Quit, or continue with caution.
(2) An edit session for this file crashed.
    If this is the case, use ":recover" or "vim -r /etc/******"
    to recover the changes (see ":help recovery").
    If you did this already, delete the swap file "/var/tmp/********"
    to avoid this message.

Swap file "/var/tmp/*******" already exists!
[O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort:
```

というエラーが出てきてしまう。

#原因
前回、編集中に閉じてしまい、多重編集をしようとしている状況であるため。

#対処
Dでデリートして、編集モードに入れるのでそこで:qで閉じる。

#最後に
かなり見づらい記事になっているため、おそらく自分の備忘録としてしか使われないだろう。
今後の記事は見やすさも意識して書く必要がある。
【秘密計算】最古のMulti-party Computationプロトコル「Yao's Garbled Circuit」とは

# はじめに

この記事では、最古のMulti-Party Computation（以下MPC）プロトコルである、「Yao's Garbled Circuit」の仕組みを紹介していきます。

# Yao's Garbled Circuit 概要

Yao's Garbled Circuit は1982年にAndrew Yao 氏が発表した、2者間での初めてのMPCプロトコルです。 2人の参加者が提供する秘密データ$x, y$ をお互いに知られることなく、関数$f(x, y)$ の実行結果を得ることができます。関数$f(x, y)$ は次節に説明するGarbled Boolean Circuit によって構成されます。また、その特徴をまとめると以下になります。

### 特徴

- ブール回路
- Semi-Honest Security
- 2 Party Computation

ブール回路とは、関数の構成に論理ゲートを用いる場合を指しています。また、Semi-Honest Security とは、参加者がプロトコルから逸脱しない場合においてセキュアであることを示しています。最後に、2 Party Computation とは、参加者が2人である場合のMPCであることを示しています。

# Garbled Boolean Gate

関数$f(x, y)$ を構成する論理ゲートは、2つの入力ビット$x, y$ を知られずに、計算結果$z$ を出力することを目指します。このような論理ゲートのことをGarbled Boolean Gate(GBG) と定義します。以後は論理ゲートとして以下のようなANDゲートを想定します。

![andGateWithTable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390000/49f1d629-e388-749b-c42d-8caac0681b5b.png)

$P_1$と$P_2$は参加者、$x, y$ はそれぞれの参加者が入力する1ビットの秘密情報、$z$ はAND ゲートの出力ビットを表しています。

# Garbled Computation Table

上記のGBGを実現するために、Garbled Computation Table(GCT)という表を導入します。Yao's Garbled Circuit では論理ゲートの計算を表によって実現することで、入力値$x, y$ を秘密にしたまま計算結果を出力します。以下にAND ゲートのGCTを示します。

![gctTable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390000/248421b4-dfb6-7729-0724-408fba7548af.png)

ここで、$Enc()$は添字の鍵によって暗号化する関数を示しています。また、$k$ は$x, y$ の値に対応する鍵であり、添字が$x, y$ のそれぞれの入力ビットの値に対応しています。つまり、$P_1$と$P_2$の入力ビットそれぞれに対応した鍵であることを示しています。この時GCTは、AND ゲートの出力結果である$z$ の値を、それぞれに対応する$x, y$ の鍵$k$ で暗号化したものを表しています。

ANDゲートの計算結果は、$x, y$ それぞれの対応する鍵を用いてGCTを復号することで得られます。例えば、$x = 0, y = 1$ に対応する鍵$k_{x=0}, k_{y=1}$ を獲得した場合は、$z = 0$ を復号することができます。以下にプロトコルの手順を示します。

## 手順

1. $P_1$ が全ての鍵$k$ を生成しAND ゲートに対応するGCTを作成する
2. $P_1$はGCTの行の並びをシャッフルする
3. $P_1$ は$P_2$ に作成したGCT を送信する
4. $P_1$ は$P_2$ に自身の入力ビットに対応した鍵$k_x$ を送信する（$P_2$ にはどちらのビットに対応した鍵であるかは分からない）
5. $P_1$ は$P_2$ にOblivious Transfer を用いて$k_{y=0}, k_{y=1}$ を送信する（Oblivious Transfer は後述する）
6. $P_2$ はGCT, $k_x, k_y$ を用いて計算結果$z$ を復号する
7. $P_2$ は$P_1$ に計算結果$z$ を送信する

ここで、Oblivious Transfer は受信者の受け取った値が送信者には分からない通信方法です。また、受信者は受け取った値しか知ることができません。したがって、$P_1$は$k_{y=0}, k_{y=1}$ のどちらを$P_2$ が受け取ったのかを知ることがなく、$P_2$ は受け取った鍵の値しか知ることはできません。また、GCTをシャッフルすることで、どの行がどの入力に対応しているのかを$P_2$は知ることができません(garbled は「シャッフルされた」という意味です)。結果的に、$P_2$ は$P_1$ から$k_x, k_y$ の2つの鍵を入手することができたため、GCTの適切な行を復号しz の値を得ることができました。

上記のプロトコルにより、$P_1, P_2$ の入力ビット$x, y$ の値が相手に知られることなく、AND ゲートの計算結果を得ることができました。さらに、GCTはAND ゲート以外の任意の論理ゲートに適用できるため、任意の関数$f(x, y)$ をブール回路を用いて実現することができます。

# まとめ

Yao’s Garbled Circuit は最古のMPCプロトコルであり、Semi-Honest Security 、2 Party Computation 、ブール回路という特徴を持っています。そして任意の関数$f(x, y)$ を$x, y$ を秘密にしたまま計算可能であり、Garbled Boolean Gate とGarbled Circuit Table を用いて参加者$P_1$ と$P_2$ の間でMPCを実現しています。

# 参考文献
https://acompany.tech/blog/technology-yaos-garbled-circuit/

#Happy Hacking :sunglasses: !
パッチの作成方法

# パッチの作成

```
$ diff -u 変更前のファイル 変更後のファイル > パッチファイル名
```

オプションの「-u」はパッチファイルを、unified diff形式で出力するという指定になります。

記載例を次に示します。

```
$ diff -u file_before.py file_after.py > file_patch.patch
```


# パッチ適用
```
$ patch -u 変更前のファイル < パッチファイル名
```

パッチファイルの作成時にオプションの「-u」をつけた場合、パッチ適用時にも「-u」オプションの指定が必要になります。
記載例を次に示します。

```
$ patch -u file_before.py < file_patch.patch
```
inetd/xinetd/systemdの違い

LinuCの勉強をしていて気になったので調べました。
# inetd/xinetd/systemdはスーパーデーモン
inetd/xinetd/systemdはスーパーデーモンと呼ばれるものです。
スーパーデーモンとは、待ち受けポートを一元管理して、要求が来た待ち受けポートに対応するデーモンを起動させる中継デーモンとのことです。
イメージは以下の図の通り。
![inetd_xinetd_systemd2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429125/3ea06bae-30dd-f6cc-bb71-293c3b20c3cb.png)
システムの負荷軽減以外にも、システム管理を一元化することによる管理負荷軽減や、
システムの冗長性・堅牢性向上のメリットもあるそうです。

また、Linuxのサービスは常駐型と接続要求のたびに起動するサービスがあるのですが、スーパーデーモンは主に後者の管理に使われるようです。
apacheなど頻繁に接続要求を受け付けるサービスは、リクエストごとのデーモン起動・終了が頻繁に発生し、かえって負荷が大きくなるので、スーパーデーモンを介さないスタンドアローンモードで使うことが推奨されているようです。
# inetd/xinetd/systemdの違い
### inetd
　デーモン起動を制御します。
　アクセス制御を行う「TCPWrapper」との組み合わせで利用されていました。
　※自分がLinuxをいじり始めた20年位前に使われていたような...
### xinetd
　単体でアクセス制御とデーモン起動を行います。
　inetdと比べ、セキュリティ面で改良が施されているそうです。
### systemd
　Linuxの起動処理やシステム管理を行う、システム管理デーモン、
　ライブラリおよびユーティリティ一式のことです。
　Linuxの起動からシステム管理まで幅広い機能を持っており、
　その中にxinetdの代替機能を含んでいます。

現在の主要ディストリビューションのほとんどはすでにsystemdを採用しているようですが、
LinuC102の勉強をしていると、inetdやxinetdの問題をちらほら見かけます。

参考
https://ja.wikipedia.org/wiki/Xinetd
https://ja.wikipedia.org/wiki/Systemd
http://equj65.net/tech/systemd-boot/
https://dev.classmethod.jp/articles/systemd-getting-started/
【Java】識別子( クラス・メソッド・変数など )の命名規則

# Javaにおいての識別子の命名規則

についてまとめました。

## 【要約】

識別子とはJavaにおいての「クラス」、「メソッド」、「変数」などのことで、それらの命名規則は以下です。

- 「public」などの予約語を識別子として使うことが出来ない
- 使える記号は「$」(ドルマーク)と「_」(アンダースコア)の2種類のみ
- 数字から初めてはいけない(2文字目以降は可)

これらを無視するとコンパイルエラーが起きる

## 【各命名規則】

### **【クラス名】**

クラス名の先頭は大文字で始めましょう。

もしクラス名の先頭を小文字にした場合は警告がでます。

### 【**メソッド名・変数名**】

- キャメルケースで書く。（例: myName, javaScript)
- 値と変数名が矛盾するような書き方をしてはならない。

大文字で始めるとコンストラクタやクラス名と区別がつきにくくなってしまうたメソッド名、変数名の先頭は小文字で始めましょう。

### 【**定数名**】

定数とはfinalがついた再代入不可の変数です。

一般的に全て**全て大文字で記述します。**

## 記述方法について

### **キャメルケース**

複数の単語を繋げて識別子とする場合の規則です。

キャメルケースには以下の2種類があります。

- 単語の先頭もじを大文字で表記する「アッパーキャメル」
- 後にくる単語の先頭を大文字にする「ローワーキャメルケース」

```java
// （例）アッパーキャメル
String CamelCase;

// （例）ローワーキャメル
String camelCase;
```

### **スネークケース**

複数の単語を繋げて識別子とする場合の規則です。

2つの単語を「_」(アンダースコア)で区切ります。

```java
// （例）スネークケース
String snake_case;
```

### ハンガリアン記法

変数名やクラス名などの識別子の先頭に型の接続語を入れる記法。

以下のように文字列（string）の場合だと先頭に「s」を入れ、int型なら「i」といった感じに記述する

```java
// （例）ハンガリアン記法
String sHungarian;
int iHungarian;
```

## 【まとめ】

Silverの試験対策としては、以下の2点を抑えておく。

- アンダースコアと$が識別子として使える
- 文字の先頭に数字をつけることは出来ない

予約後はJDKのドキュメントに51種類があるようですが、とりあえずは「クラス、変数名、メソッド名以外のstatic, や if, や, tryなどのこと」ぐらいの認識で抑えておく。

## 参考文献・記事

- [徹底攻略Java SE 11 Silver問題集[1Z0-815]対応](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Java-SE-11-Silver%E5%95%8F%E9%A1%8C%E9%9B%86-1Z0-815/dp/4295007625/ref=pd_lpo_14_img_0/356-5238196-1895250?_encoding=UTF8&pd_rd_i=4295007625&pd_rd_r=1c21865b-a9fe-43e8-ac01-46170e44abca&pd_rd_w=9El0Q&pd_rd_wg=hh5Hc&pf_rd_p=4b55d259-ebf0-4306-905a-7762d1b93740&pf_rd_r=72AVH18EM90CKG00CH5W&psc=1&refRID=72AVH18EM90CKG00CH5W)
- [予約語](https://www.javadrive.jp/start/const/index7.html)
ZOOM,meet,Skype,teamsにクールな映像イフェクトやリアルタイムCGを！

###ZOOM,meet,Skype,teamsにクールな映像イフェクトやリアルタイムCGを！
スマホのSNSアプリにえらく高度な画像処理やイフェクトが用意されているのに、ZOOM,meet,Skype,teamsなどは、ビジネス用と考えられているせいか、あまり面白い画像処理やイフェクトが使えません。
　そこで、これらのリモート会議システムにも色んなイフェクトが使えるように、またそのイフェクトを簡単に
増やせるようなアプリケーションを作ってみました。

![out000008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/af255a9a-645b-2f72-66dc-40824ef0ea8a.jpeg)

↓このコードはそのまま使えます。
https://www.shadertoy.com/view/ldsBz2
![out000078.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/895292f7-11d5-f44f-2eb2-4d18858ea2bf.jpeg)


　openframwworks + ofxshadertoy + Spout + その他アドオンで作り、shadertoyのコードがほぼそのまま
使えるので、shadertoy.comやGLSL sandboxなどの膨大なコードが参考になりますので、イフェクトをどんどん増やせます。たとえば、上の惑星の写真のコードをhttps://www.shadertoy.com/view/ldsBz2
からコピーして、
"data/shaders"フォルダ下の、001-009.fragのどれかにぺイストすると、その番号のキーを押すと、
惑星の動画が表示されます。（最初の一行に空のコメント行、//を追加してください。）

　一応Windows上で開発しましたが、openframeworksで開発したので、macにも移植できるはずです。
　オフライン時にshadertoyのシェーダ（特にマルチレイヤー）のシェイダーをデバッグしたり、
開発したりするのにも使えます。

###GIT
https://github.com/ultrahamlet/SjShare

　
　git上に実行プログラムとサンプルのシェイダー（主にshadertoy.comから）を置きました。**WebCamが接続されていないと起動しません。キーボードのキーの0－9にそれそれ、イフェクトがアサインされています。**スペースキーを押すと、表示している画像をフレーム毎に"data/export"に書き出します。書き出し中にスペースバーを押すと書き出しが止まります。キー1-9に対応する"data/shaders"の下に000.frag -- 009.fragの10個のシェイダーファイルがありますが、この中をshadertoy.comからコピーしたものぺイストし、最初のコメント行を以下の説明のように追加すれば、shadertoyのコードがスタンドアローンでPC上で動きます。
（MySettings.exeで表示ウィンドウの縦横サイズを選択できます。）
  

　このシェアバージョンでは顔のランドマークを検出する機能や、ZOOMなどの仮想カメラになる機能などを
外してありますが、どういうコンセプトかこのバージョンでご理解いただけると思います。
　ポイントはShaderToyのマルチシェイダーをシェイダーの最初の行に簡単に記述できるのがアイデアです。
openframeworksベースですので、shadertoy以外の機能も今後追加していく予定です。
  
  gitのreadme.mdに使い方の詳細を追加していく予定です。
　
###マルチパスシェイダーの記述
　たとえば、上のシェーダーフォルダ(data/shaders/)内の 004.fragは
https://www.shadertoy.com/view/wttSRM　
のコードですが、これはA,B二つとメインのイメージバッファのマルチパスレイヤーで、git内のデータの最初の行は、

　//:0ab,1bb,0b,0va,1v

　と、なっていますが、これは、
　
　0ab　は、bバッファの0チャンネルにaバッファのテキスチャーを送る
　1bb  は、bバッファの1チャンネルにbバッファの結果をもどす
　0b   は、イメージバッファの0チャンネルにbバッファの結果を送る
　0va  は、aバッファの１チャンネルにwebcamの画像を送る
　1v   は、イメージバッファの１チャンネルにwebcamの画像をインプット

　ということになります。
　":"の左のフィールドはマウス、サウンドなどのスイッチで、
//M:とすれば、シェイダー内でマウスの値が参照されていいればマウスコントロールがオンになります。
//S:はサウンドの入力がオンになり、サウンドでリアルタイムCGを制御できたりできます。
プロ版では//F:でwebcamに映る顔のface landmarksをディテクトして表示します。

やや複雑なマルチパス構造を持つ、"Sirenian Dawn"　https://www.shadertoy.com/view/XsyGWV
![out000010.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/02c929f0-b9a9-61f2-e5fd-707fbe064b34.jpeg)

は、メインのイメージバッファの他に、A, B, Cのレイヤーを持ちます。
ヘッダーは以下のようになります。

//M:0gMa,1rLa,0ab,1bb,0bc,1cc

ここで、
　
0gMa  ->  input middle size gray noise texture　to A buffer thru 0 channnel
1rLa  ->  input large size rgb noise texture to A buffer thru 1 channel
となり、Sjでは一般的にノイズファイルは以下のように記述します。

gL gray Large noise texture
gM gray Middle noise texture
gS gray Small  noise texture
g,[noize texture size]

rL rgb Large noise texture
rM rgb Middle noise texture
rS rgb Small  noise texture
r,[noize texture size]
R11.org

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83](<https://img.shields.io/badge/ruby-2.7.1p83-brightgreen>) 


# 第１１回

チャート式Rubyの第６回目(最終)


## classについて

hello\_method.rb

```ruby
def gets_name
  name = ARGV[0]
  if name == nil
    puts "What's your name?"
    name = gets.chomp
  end
  return name
end

def hello name
  puts "Hello, #{name}!!"
end

name = gets_name
hello name
```

以前作成したhello\_method.rbを拡張しclass化してみる。

```ruby
class Greeter
  def initialize
    @name = gets_name
    puts_hello
  end

  def puts_hello
    puts "Hello #{@name}."
  end

  def gets_name
    name = ARGV[0] || 'world'
    return name
  end
end

Greeter.new
```

上記のコードはname変数に入力があれば、Hello {name}

入力がなければHello Worldを出力する。「main loopを消せないか」というのがclassの発想だそうだ。


## 参考サイト

[チャート式ruby-Ⅵ](https://qiita.com/daddygongon/items/969ad5112878f6dab844)



------
 - **source** ~/grad_members_20f/members/skona/memo/R11.org
開発者コンソールの制限 : 30 日間の無料 Service Cloud トライアルについて

[Service Cloud トライアル](https://www.salesforce.com/form/signup/freetrial-service.jsp?d=70130000lxERAAY)ですが、開発者コンソールにクエリエディタがない。何で？


答えが分かりました。

[Query Editor tab missing](https://trailblazers.salesforce.com/answers?id=90630000000ZhorAAC)

Professional Editionではクエリエディタは使えないらしい。困ったなぁ。サクッとオブジェクトをチェックできない。

変な制限です。

+ [開発者コンソールでコードを実行しようとするとスクリプトエラーが発生する](https://help.salesforce.com/s/articleView?id=000335530&type=1)
リモートワークは自分ルールが大切だと思う話

在宅勤務制度が導入されリモートワークが開始されました。
リモートワークは自分で決めたルールを守ること大切と感じましたので
まとめてみようかと思います。

# ●家族にしっかり説明を行う
一緒に住む家族にはテレワーク(リモートワーク)でも働いていることは変わらないので、
仕事しながら話せる状態になるわけでは無いことを認識してもらいましょう。
仕事の効率が落ち逆に時間がかかってしまう事もあるでしょう。

# ●可能であれば書斎をしっかり設ける
仕事と私生活の切り分けをしっかり行う事で自分を守る事にもつながります。
その一環として書斎は仕事する場所と決めてることで境界線を設けることができるでしょう。

# ●会社で働いていたらを考える
会社で働いていたら世間話をする時もありますよね。
チャットでも構いませんので会社で働いていたときと同様にコミニケーションをとりましょう、
相手の状態や自分の状態を知らせることができます。

# ●会話より文字は伝わらないことを理解しましょう
今まで会話でしていた内容が文字になることが多くなります。
会話より文字は内容が伝わっていないことが多いので忖度や遠慮をしないで
しっかり確認を行いましょう。

# ●通話しましょう
相手が忙しいことはあなたが通話をお願いすることとは関係ありません。
今通話できますか?と聞き、無理ならば相手が断るだです。
この場合いつできるか調整しましょう。
(急に通話をかける行為はやめましょう。)

# ●まとめ
会社で働いていたら行われた行動はリモートワークでも行いましょう。
また、会社にいたらできないことをリモートワークで行うことはなるべく避けることをお勧めします。
Rails コールバック・フィルタ

現在筆者は書籍を参考にタスク管理アプリをつくっています。
今回はその中でもログイン機能の一部分を実装した手順を書いていこうと思います。
<h1>ログインしていなければタスク管理を利用できなくする</h1>


アプリのタスク管理機能を、ユーザーがログインしていなければ利用できないようにしていきます。
前提としてログイン、ログアウト機能の実装が終わっていることとします。


ユーザーがログインしていなければ利用できないようにするには、コントローラの<b>フィルタ(Filter)</b>という機能を使います。
<b>フィルタ</b>というのはアクションを処理する前後に、任意の処理を挟むことができる。
アクションの前処理として他の機能へのリダイレクトを実装すると、リダイレクトが行われ、アクションには到達しない。
そのため、特定の状況の時にだけアクションが利用できるように制限するという目的のために前処理の<b>フィルタ</b>が使用される。

フィルタはコールバックと似たような機能なので違いがわかる参考記事を貼っておきます
https://k-koh.hatenablog.com/entry/2020/02/10/222058

そもそもなんでコールバックとフィルタの機能って使うの？という方にはこちらの記事がおすすめです。(ここではコールバックの必要性のみ)
https://tech.kitchhike.com/entry/2018/06/30/232400

フィルタもモデルのコールバックと同様にフィルタとしてメソッドを登録して実際にそのメソッドを実装するというやり方で追加する。
今回は、login_requiredという名前のメソッドをアクションの前に呼ばれるフィルタとして登録することにする。
アクションの前に呼ばれるフィルタを登録するには、before_actionメソッドを使う。
before_actionにはonlyオプションなどで適用するアクションを指定することもできる。今回は指定せずに全てのアクションに対して有効にする。

なお、タスク管理をログインしていない時に利用させないだけであれば、login_requiredフィルタの追加はTasksControllerで行えば良い。
しかし、他の機能にもそのような制限を付けたいことも予想できるため、全機能に共通の処理を記述することに適したApplicationControllerに記述する。

ApplicationControllerを次のような形に編集していきます。

```ruby:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  helper_method :current_user
  before_action :login_required

  private
  
def current_user
    @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
  end

  def login_required
    redirect_to login_url unless current_user
  end
end

```

これで、アプリケーション内の全てのアクション処理前に、ユーザーがログイン済みかどうかのチェックが入り、
ログイン済みではなかった場合にはログイン画面を表示するようになりますが、これが正しく動作するためには１点だけ解決すべき問題がある。

今のままでは、ログイン画面を表示するためのアクションに対してもlogin_requiredフィルタが実行されてしまうため、
アプリケーションのどのURLをリクエストしても無限にredirectが行われてしまう。

これを避けるため、SessionControllerはログインしていなくても利用できるようにしていきたいと思います。
親クラスなどですでに定義済みのフィルタを通らないようにするには、skip_before_actionなどを利用する。

```ruby:app/controllers/sessions_contorller.rb
class SessionsController < ApplicationController
  skip_before_action :login_required
  def new
  end

  def create
    user = User.find_by(email: session_params[:email])

    if user&.authenticate(session_params[:password])
      session[:user_id] = user.id
      redirect_to root_url, notice: 'ログインしました。'
    else
      render :new
    end
  end

  def destroy
    reset_session
    redirect_to root_url, notice: 'ログアウトしました'
  end
  private

  def session_params
    params.require(:session).permit(:email, :password)
  end
end
```
これで、ログインしていないユーザーに利用制限をかける実装は完了です。

次回は、ログインしているユーザーのデータだけを扱えるようにしていきたいと思います。

参考書籍：現場で使える　Ruby on Rails5 速習実践ガイド
【JavaScript】2つの日付の差(日数)を求める方法

#プログラミング勉強日記
2020年12月11日
2つの日付から日数を出すときの方法をまとめる。

#Date型とgetTimeメソッドとは
　Date型はJavaScriptで日付や時刻を扱うためのクラスである。Date型を使うことで、プログラム上で現在時刻の取得や計算を行うことができる。

　getTimeメソッドは1970年1月1日0時0分0秒から現在まで何ミリ秒経過したか取得するメソッドである。

#2つの日付の差分を求める方法

1. 差分を求めたい日付を1970年1月1日0時0分0秒から何ミリ秒だったかを取得する
2. その1で求めた差を計算する
3. 取得できるのは日付のミリ秒であるのでこの値を1日をミリ秒に換算した値で割る

　1日分のミリ秒は`24時間×60分×60秒×1000ミリ秒(=86,400,000ミリ秒)`で割る。

#サンプルコード

```js
var date1 = new Date(2020, 1, 1);
var date2 = new Date(2020, 12, 11);
var termDay = (date2 - date1) / 86400000;
console.log(termDay);
```

#参考文献
[JavaScriptで2つの日付の差分を求める方法を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/31186)
[[JavaScript] ２つの日付の差を日数で求める](https://javascript.programmer-reference.com/js-date-term/)
ESLint 7.15.0

前 [v7.14.0](https://qiita.com/mysticatea/items/0470f0566b75b750847c) | 次 (2020/12/19 JST)

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">ESLint v7.15.0 has been released: <a href="https://t.co/vEhsNE838x">https://t.co/vEhsNE838x</a></p>&mdash; ESLint (@geteslint) <a href="https://twitter.com/geteslint/status/1335133962474237953?ref_src=twsrc%5Etfw">December 5, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ESLint `7.15.0` がリリースされました。小さな機能追加とバグ修正が行われました。

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

> 🏢 [日本語 Issue 管理リポジトリ](https://github.com/eslint/eslint-jp)
> 👫 [日本語サポート チャット](https://discord.com/channels/688543509199716507/718026066001788958) ([招待リンク](https://discord.gg/wfTnWvE))
> 🏢 [本家リポジトリ](https://github.com/eslint/eslint)
> 👫 [本家サポート チャット](https://discord.com/channels/688543509199716507) ([招待リンク](https://eslint.org/chat))

---

[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。

- [ESLint の GitHub Sponsors](https://github.com/sponsors/eslint)
- [私個人の GitHub Sponsors](https://github.com/sponsors/mysticatea)

---

# ✨ 本体への機能追加

特になし

# 💡 新しいルール

## [no-unsafe-optional-chaining](https://eslint.org/docs/rules/no-unsafe-optional-chaining)

🔖 [#13859](https://github.com/eslint/eslint/issues/13859)

`TypeError` が発生するような、誤った Optional Chaining 構文の使い方を警告します。

```js:例
/*eslint no-unsafe-optional-chaining: error */

//✘ BAD
(obj?.foo).bar;
(obj?.foo)();
(obj?.foo)`template`;
new (obj?.foo)();
class A extends obj?.foo {};
[...obj?.foo];
bar(...obj?.foo);
new Bar(...obj?.foo);
1 in obj?.foo;
var { a } = obj?.foo;
var [b] = obj?.foo;
foo instanceof obj?.prop
for (foo of obj?.prop);
[{ foo } = obj?.prop] = [];
(obj?.foo ?? obj?.bar)();
(foo || obj?.foo)();
```
» [Open Demo](https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgbm8tdW5zYWZlLW9wdGlvbmFsLWNoYWluaW5nOiBlcnJvciAqL1xuXG4vL+KcmCBCQURcbihvYmo/LmZvbykuYmFyO1xuKG9iaj8uZm9vKSgpO1xuKG9iaj8uZm9vKWB0ZW1wbGF0ZWA7XG5uZXcgKG9iaj8uZm9vKSgpO1xuY2xhc3MgQSBleHRlbmRzIG9iaj8uZm9vIHt9O1xuWy4uLm9iaj8uZm9vXTtcbmJhciguLi5vYmo/LmZvbyk7XG5uZXcgQmFyKC4uLm9iaj8uZm9vKTtcbjEgaW4gb2JqPy5mb287XG52YXIgeyBhIH0gPSBvYmo/LmZvbztcbnZhciBbYl0gPSBvYmo/LmZvbztcbmZvbyBpbnN0YW5jZW9mIG9iaj8ucHJvcFxuZm9yIChmb28gb2Ygb2JqPy5wcm9wKTtcblt7IGZvbyB9ID0gb2JqPy5wcm9wXSA9IFtdO1xuKG9iaj8uZm9vID8/IG9iaj8uYmFyKSgpO1xuKGZvbyB8fCBvYmo/LmZvbykoKTtcbiIsIm9wdGlvbnMiOnsicGFyc2VyT3B0aW9ucyI6eyJlY21hVmVyc2lvbiI6MTEsInNvdXJjZVR5cGUiOiJtb2R1bGUiLCJlY21hRmVhdHVyZXMiOnt9fSwicnVsZXMiOnt9LCJlbnYiOnt9fX0=)

# 🔧 オプションが追加されたルール

特になし
ESLint 7.14.0

前 [v7.13.0](https://qiita.com/mysticatea/items/a3bee56b028db223abaa) | 次 [v7.15.0](https://qiita.com/mysticatea/items/c817e9305de63235b272)

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">ESLint v7.14.0 has been released:<a href="https://t.co/HRANqRCPZW">https://t.co/HRANqRCPZW</a></p>&mdash; ESLint (@geteslint) <a href="https://twitter.com/geteslint/status/1329925629844852737?ref_src=twsrc%5Etfw">November 20, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ESLint `7.14.0` がリリースされました。小さな機能追加とバグ修正が行われました。

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

> 🏢 [日本語 Issue 管理リポジトリ](https://github.com/eslint/eslint-jp)
> 👫 [日本語サポート チャット](https://discord.com/channels/688543509199716507/718026066001788958) ([招待リンク](https://discord.gg/wfTnWvE))
> 🏢 [本家リポジトリ](https://github.com/eslint/eslint)
> 👫 [本家サポート チャット](https://discord.com/channels/688543509199716507) ([招待リンク](https://eslint.org/chat))

---

[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。

- [ESLint の GitHub Sponsors](https://github.com/sponsors/eslint)
- [私個人の GitHub Sponsors](https://github.com/sponsors/mysticatea)

---

# ✨ 本体への機能追加

特になし

# 💡 新しいルール

## [no-nonoctal-decimal-escape](https://eslint.org/docs/rules/no-nonoctal-decimal-escape)

🔖 [#13845](https://github.com/eslint/eslint/issues/13845)

JavaScript には 8 進数エスケープ シーケンスという互換性のために残されている非推奨の構文があり、[no-octal-escape](https://eslint.org/docs/rules/no-octal-escape) ルールで禁止できます。

同様に `"\8"` や `"\9"` のような「8 進数エスケープ シーケンス構文のように見えるけれど 8 進数ではない数値」も非厳格モードではエラーになりません。しかし ES2020 までこの構文は検討漏れで言語仕様に記載されていませんでした。

ES2021 で記載されるようになったので、このルールで禁止できるようになります。

```js:例
/*eslint no-nonoctal-decimal-escape: error */

//✘ BAD
const bad = "Don't use \8 and \9 escapes.";

//✔ GOOD
const good = "Don't use \\8 and \\9 escapes.";
```
» [Open Demo](https://eslint.org/demo#eyJ0ZXh0IjoiLyplc2xpbnQgbm8tbm9ub2N0YWwtZGVjaW1hbC1lc2NhcGU6IGVycm9yICovXG5cbi8v4pyYIEJBRFxuY29uc3QgYmFkID0gXCJEb24ndCB1c2UgXFw4IGFuZCBcXDkgZXNjYXBlcy5cIjtcblxuLy/inJQgR09PRFxuY29uc3QgZ29vZCA9IFwiRG9uJ3QgdXNlIFxcXFw4IGFuZCBcXFxcOSBlc2NhcGVzLlwiO1xuIiwib3B0aW9ucyI6eyJwYXJzZXJPcHRpb25zIjp7ImVjbWFWZXJzaW9uIjoxMSwic291cmNlVHlwZSI6Im1vZHVsZSIsImVjbWFGZWF0dXJlcyI6e319LCJydWxlcyI6e30sImVudiI6e319fQ==)

# 🔧 オプションが追加されたルール

特になし
ESLint 7.13.0

前 [v7.12.0](https://qiita.com/mysticatea/items/919b15bef14b9d6f553a) | 次 [v7.14.0](https://qiita.com/mysticatea/items/0470f0566b75b750847c)

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">ESLint v7.13.0 has been released:<a href="https://t.co/oBbUgm816d">https://t.co/oBbUgm816d</a></p>&mdash; ESLint (@geteslint) <a href="https://twitter.com/geteslint/status/1324906235955703808?ref_src=twsrc%5Etfw">November 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ESLint `7.13.0` がリリースされました。小さな機能追加とバグ修正が行われました。

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

> 🏢 [日本語 Issue 管理リポジトリ](https://github.com/eslint/eslint-jp)
> 👫 [日本語サポート チャット](https://discord.com/channels/688543509199716507/718026066001788958) ([招待リンク](https://discord.gg/wfTnWvE))
> 🏢 [本家リポジトリ](https://github.com/eslint/eslint)
> 👫 [本家サポート チャット](https://discord.com/channels/688543509199716507) ([招待リンク](https://eslint.org/chat))

---

[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。

- [ESLint の GitHub Sponsors](https://github.com/sponsors/eslint)
- [私個人の GitHub Sponsors](https://github.com/sponsors/mysticatea)

---

# ✨ 本体への機能追加

## `TIMING` 環境変数が `10` より大きい値や `all` をサポート

🔖 [#13812](https://github.com/eslint/eslint/pull/13812)

従来より、`TIMING=1` 環境変数が設定されている場合、ESLint は最も時間がかかったルール Top 10 を表示します。

```bash
$ TIMING=1 eslint lib
Rule                    | Time (ms) | Relative
:-----------------------|----------:|--------:
no-multi-spaces         |    52.472 |     6.1%
camelcase               |    48.684 |     5.7%
no-irregular-whitespace |    43.847 |     5.1%
valid-jsdoc             |    40.346 |     4.7%
handle-callback-err     |    39.153 |     4.6%
space-infix-ops         |    35.444 |     4.1%
no-undefined            |    25.693 |     3.0%
no-shadow               |    22.759 |     2.7%
no-empty-class          |    21.976 |     2.6%
semi                    |    19.359 |     2.3%
```

このバージョンから以下の値に特別な意味が持たせられました。

- `11` 以上の整数 ... 時間がかかった順に指定した数のルールを表示します。
- `all` ... すべてのルールを表示します。

# 💡 新しいルール

特になし

# 🔧 オプションが追加されたルール

特になし
ESLint 7.12.0

前 [v7.11.0](https://qiita.com/mysticatea/items/856e2605f82eb6bb3e01) | 次 [v7.13.0](https://qiita.com/mysticatea/items/a3bee56b028db223abaa)

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">ESLint v7.12.0 has been released: <a href="https://t.co/e9teRdRbEx">https://t.co/e9teRdRbEx</a></p>&mdash; ESLint (@geteslint) <a href="https://twitter.com/geteslint/status/1319806650363031552?ref_src=twsrc%5Etfw">October 24, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ESLint `7.12.0` がリリースされました。小さな機能追加とバグ修正が行われました。

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

> 🏢 [日本語 Issue 管理リポジトリ](https://github.com/eslint/eslint-jp)
> 👫 [日本語サポート チャット](https://discord.com/channels/688543509199716507/718026066001788958) ([招待リンク](https://discord.gg/wfTnWvE))
> 🏢 [本家リポジトリ](https://github.com/eslint/eslint)
> 👫 [本家サポート チャット](https://discord.com/channels/688543509199716507) ([招待リンク](https://eslint.org/chat))

---

[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。

- [ESLint の GitHub Sponsors](https://github.com/sponsors/eslint)
- [私個人の GitHub Sponsors](https://github.com/sponsors/mysticatea)

---

# ✨ 本体への機能追加

## 修正内容が空の Suggestions は表示されなくなりました

🔖 [#13772](https://github.com/eslint/eslint/pull/13772)

プラグイン開発者向け。

Suggestions の `fix` 関数が `null` や空配列を返した場合、その Suggestion は結果に含まれないようになりました。VSCode 等の UI が何もしない Suggestion を表示してユーザーを困惑させる事がなくなります。

# 💡 新しいルール

特になし

# 🔧 オプションが追加されたルール

特になし
google recruit

\![Mac OS X-10.15.7](<https://img.shields.io/badge/MacOSX-10.15.7-brightgreen>) \![ruby-2.7.1p83$](<https://img.shields.io/badge/ruby-2.c7.1p83-brightgreen>)


# 課題

授業の最終課題でgoogle recruit の課題が出たのでやってみた．

-   e(自然対数の底)の値で連続する10桁の数のうち，最初の素数を求めよ


# 作成したプログラム

```ruby
# coding: utf-8
require "prime"

def check_prime(num)
  return Prime.prime?(num)
end

def make_num
  e = "2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457\
13821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907\
632338298807531952510190"
  num = e.delete(".")
  i = 0
  loop{
    slice_num = num.slice(i..i+9).to_i
    puts slice_num
    if check_prime(slice_num) == true
      puts "素数です"
      break
    end
    i = i+1
  }
end

make_num
```


# 解説

素数判定する関数と10桁の整数を作成する関数を作成

素数判定にはprimeっていうモジュールがあったからインポートしてそれを使用．値を入力すると素数かどうかをtrue かfalseで返してくれる

あとはループして10桁ずつ変数に入れて判定するだけ

めっちゃ簡単やったけど，グーグルの試験の時にはprimeモジュールあったんかな？なかったら若干反則な気がするけどまあいいか


# 発展課題

    f(1)=7182818284
    f(2)=8182845904
    f(3)=8747135266
    f(4)=7427466391
    f(5)=__________

規則性見つけて当てはまる数字を入れるらしい


# 解説

問題に表示されている数字はすべて10桁でe(自然対数の底)に含まれる数字である。

さらに、各桁の合計が49になってる…

なので、e(自然対数の底)の値で連続する10桁の数のうち,各桁の和が49になる値を探す


# 作成したプログラム

```ruby
# coding: utf-8
def count_digits(num)
  num.to_s.length
end

def check_49(num)
  sum = 0
  for j in 1..10 do
    a = num % 10
    sum = sum + a
    num = num / 10
  end
  if sum ==49
    return 1
  end
end

def main
  sum = 0
    e = "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763\
2338298807531952510190"
    num = e.delete(".")
    len = count_digits(num)
    for i in 0..len-10 do
      slice_len = num.slice(i..i+9)
      slice_num = slice_len.to_i
      if check_49(slice_num)==1
	puts slice_len
      end
    end
end

main
```

実行結果は以下の通り

    7182818284
    8182845904
    8747135266
    7427466391
    5966290435
    2952605956

これより答えは5966290435

もうちょっときれいにコードを書きたいけど時間がないからこのくらいでいいか


# 参考にしたサイト

[class Prime（リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Prime.html)

[instance method Array#slice](https://docs.ruby-lang.org/ja/latest/method/Array/i/slice.html)



------
 - **source** ~/grad_members_20f/members/okamoto0910/article/google.org
Docker Desktop Mac 3.0.0 にアップデートしたら、起動しなくなった時の対応

> 2021/01/28追記
> コメントにて「3.1.0（51484）で解消」の報をいただき(ありがとうございます！)、恐る恐るアップグレードしたところ、大丈夫でした！！！
> ようやくこの記事は役割を終えることが出来たようです。ありがとうございました！ 

---

> 2020/12/15追記 
> 喜び勇んで 3.0 にアップデート→問題があって、本件を書いたわけですが、複数プロジェクトの開発を進めて行くと、どうも不安定です・・・
> なので、ver. 2.5 にダウングレードすることにしました・・・
> 奇しくもダウングレードの方法は [次の記事のダウングレード](https://qiita.com/shibomb/items/34fe78233a2bd0bf7338#1docker-desktop-%E3%82%92%E3%83%80%E3%82%A6%E3%83%B3%E3%82%B0%E3%83%AC%E3%83%BC%E3%83%89) に書いていたのですんなりできました ＼(^o^)／

---

#現象
Docker Desktop Mac 3.0.0 アプデが来たわよー！
ってアップデートしたら、コンテナが起動しなくなりました。


```
ERROR: for frontend  Cannot start service frontend: Mounts denied: approving /Users/***/src: file does not exist

ERROR: for frontend-admin  Cannot start service frontend-admin: Mounts denied: approving /Users/***/src: file does not exist

ERROR: for db  Cannot start service db: Mounts denied: approving /Users/***/mysql/conf.d: file does not exist

ERROR: for localstack  Cannot start service localstack: Mounts denied: approving /Users/***: file does not exist
```
って感じで、

```
Mounts denied: approving [ローカルディレクトリ]: file does not exist
```
となります。

#公式のIssue
公式のIssueを検索すると、こちらが。
https://github.com/docker/for-mac/issues/5115

#対応方法
Docker Desktop > 設定 > Experimental Features の
User gRPC FUSE for file sharing を **オフ** とのこと
![aassss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60052/f1fdd1f7-9c3d-841f-0dcb-47f437d243cc.png)

#だが、しかし
起動はできたのですが、mysqlが再起動を繰り返しています・・・
まだ問題がありそうです(汗
→ [原因と解決方法を書きました](https://qiita.com/shibomb/items/34fe78233a2bd0bf7338)
PythonでJSONを編集するならこれを見てくれ

この記事は [ちゅらデータアドベントカレンダーの11日目の記事](https://qiita.com/advent-calendar/2020/churadata) になります。

# TL;DR
- JSONを辞書型から作る
    - 一番楽なので皆さんはこちらを使いましょう。

```python
import json

json_dict = {
    "hoge": "hoge",
    "fuga": {"fuga": "piyo", "chura": data},
}

# dict → json
json_string = json.dumps(json_dict)

# json → dict
json_dict = json.loads(json_string)

```

- トリプルクォーテーション(三連引用符)で編集する
    - （多分文字列でjson作ろうって思ってしまったんだろうなぁ（私））

```python
import textwrap

json_text = f"""\
        {{
            "hoge": "hoge",
            "fuga": {{
                "fuga": "piyo", "chura": data
            }},
        }},
    """
geojson_text = textwrap.dedent(geojson_text)
```

- 文字列をつなげて編集する
    - できる限り↑2つのどちらかを使いましょう。可読性が高いです。

```python
json_text = "{'hoge': 'hoge', 'fuga': {'fuga': 'piyo', 'chura': " + data + "}}"
```

# 初めに

南の島でデータ分析している、いんてるです。

最近PythonでJSONを編集する機会があったのですが、JSONを編集する方法って必ずしも1つじゃないと思っていて、初心者から上級者まで幅広い書き方があると思うんですよ。アイディア次第では簡単な方法にたどりつかず回り道してしまうことだってあると思っています。そこで今回は3種類ほどJSONの書き方を示した上で、各書き方ごとのポイントを抑えて行こうかと思います。TL;DRに書いてありますが、この記事を読んだ皆さんはぜひ **辞書型** でJSONの中身を作って変換しましょうね！お兄さんとの約束ですよ！

## JSONを辞書型から編集する

```python
import json

json_dict = {
    "hoge": "hoge",
    "fuga": {"fuga": "piyo", "chura": data},
}

# dict → json
json_string = json.dumps(json_dict)

# json → dict
json_dict = json.loads(json_string)

```

これが1番良いです。何故良いのかというと、Pythonの持つ辞書型の書き方を踏襲しながら、標準ライブラリであるJSONを使ってJSON⇔Dictを変換しています。さらに書き方についてググるケースが少ない（おそらく調べてもjson.loadsとjson.dumps）くらいです。初心者にも優しいですね。

## トリプルクォーテーション（三連引用符） で編集する

```python
import textwrap

json_text = f"""\
        {{
            "hoge": "hoge",
            "fuga": {{
                "fuga": "piyo", "chura": data
            }},
        }},
    """
geojson_text = textwrap.dedent(geojson_text)
```

この書き方はおそらく頭の中で「JSON == Stringで編集だ！」みたいな脳になっているときにたどり着きそうですね。この書き方のポイントは3つあって

- fstring を使って変数の値をJSONテキストに入れている
- fstring を使っているので波括弧｛｝をテキストとして入れるために二重にしている（ **{{** とか **}}** とか）
- textwrap ライブラリでコード内にインデントしていても書き出す時や変数から読み出すときに共通のインデントを削除しています。

です。なのでStringでも可読性高く書くことができます。が、しかし調べなきゃいけないことが多くて、あんまりおすすめはできないです。意地でも遠回りして達成感を味わいたい方にはおすすめです。

## 文字列をつなげて編集する

```python
json_text = "{'hoge': 'hoge', 'fuga': {'fuga': 'piyo', 'chura': " + data + "}}"
```

できる限り避けたほうがよさそうな書き方ですが↑の例はちょっとわざと可読性低く書いてる感じがしますね。誰がこの記事書いたんでしょうか。

ポイントですが、

- トリプルクォーテーションの書き方同様にfstringが使えます。（↑の書き方だと文字列同士の足し算がなくなる形になります）
- シングル・ダブルクォーテーションを初めに使った方と逆で文字列内部のクォーテーションを記載することができます。

くらいでしょうか。どちらにしても改行のためにバックスラッシュ（\）入れたりするのは毎度面倒なので避けたいですね。短いJSON作るなら採用してもいいかなくらいです。それより辞書型から変換する方法をつｋ（テキストはここで終わっている）

# まとめ

JSONを辞書型から作る記事は山程あると思うのですが、テキストから作る記事はなかなかなくて、どうして書こうと思ったかというと、同じように「文字列からJSON作ってくしかねぇなぁ」というエンジニアの皆さんに、時間を無駄にしてほしくないと思って書きました。おそらく文字列から作ろうとする人たちはググるときのキーワードで「python json string」とか調べて「俺はjsonの中身の作り方が知りたいんじゃ！」ってなってると思います。僕は二度と文字列で作らないです。

もしPythonでJSONを編集する方法でもっと可読性高くてスマートに書けるとか、俺ならこう書いたほうが後々便利だぜとか、あればぜひコメントでご指導ご鞭撻いただければと思います。

明日、12日目は @amacbee さんが [ちゅらデータ設立において大事にしたこと](https://amacbee.hatenablog.com/entry/2020/12/12/013303) です。私はこの考え方が好きで入社したと言っても過言ではないので、よければ。


# 参考記事

- [Pythonのf文字列（フォーマット済み文字列リテラル）の使い方](https://note.nkmk.me/python-f-strings/)
- [textwrap --- テキストの折り返しと詰め込み](https://docs.python.org/ja/3/library/textwrap.html)
PHP7→PHP8で設定変更してもGDが使えないと思ったらApacheの再起動してなかった

#PHP7→PHP8で設定変更してもGDが使えないと思ったらApacheの再起動してなかった

###使用環境
* XAMPP 8.0
* PHP 8.0
* windows 10

##背景
先日、悲しいことにMySQLが起動しなくなり試行錯誤したものの、XAMPPの再インストールに至りました。そこで、せっかくなので最新のPHP8をインストールしてみたところ見事に詰まりました。
PHP7→PHP8へと変更したところ、**imagecreatefromgif**とか**imagecreatefrompng**とか**imagecreatefromjpeg**あたりのGD系の関数が使用できなくなっておりました。


##調べに調べたところ、どうやらGD利用するときの設定が変わったらしい

>Windows では、php_gd2.dll の名前が、php_gd.dll に変更されました。[PHP公式マニュアル](https://www.php.net/manual/ja/migration80.incompatible.php)

ということで```C:\xampp\php```フォルダ内の```php.ini```ファイルを開き、GDの設定を変更する。

GDで検索をかけて、```extension=gd2```となっていたため```extension=gd```に変更。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615830/65b904aa-1545-60d4-cc29-c89067fe3395.png)


**この後、重要なのがApacheの再起動！**
XAMPPターミナルでApacheを再起動したらエラーは出なくなりました。
※この再起動をせずに何時間も悩みに悩みました笑
codeigniter3 で絵文字が使えない

・mysqlの文字コードをutf8mb4にする

・application/config/database.php

'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',

↓

'char_set' => 'utf8mb4',
'dbcollat' => 'utf8mb4_general_ci',
【水曜日のダウンタウン】所持金5連続UP企画で適当に声をかけるとどうなるか、シミュレーションで検証してみた

# 所持金5連続UP、適当に声をかけるだけでも何とかなる説

皆さん、水曜日のダウンタウンという番組は観ていますか？

今週の放送では「街行く人の所持金、5人連続UPできるまで帰れません」と企画が行われ、
その名の通り、街の人に声をかけて財布の中を見せてもらい、
所持金が5人連続でUPするまで帰れないという内容でした。

番組内では声をかけるにあたって様々な駆け引きがあり、
「バンドマンの多い街は所持金が低いだろう」「お年寄りの多い街では所持金が低いだろう」といった憶測をもとに
芸人さんが通行人に声をかけていました。

ここで一つ疑問が湧いてきます。
**変に駆け引きをせずに、手当り次第速攻で声かけていったら
案外早く終わったんじゃないでしょうか。**
~~森田ぐずぐずするなと誰もが思っていたはず。~~

ということで、今回はpythonを使って「街行く人の財布の中を見せてもらうシミュレーション」を作成し、
駆け引きなしで適当に声をかけた場合にかかる平均時間を調べていきたいと思います。

# シミュレーションの実装

まずは必要なライブラリのimportから

```python
import numpy as np
from random import random
from random import randint
```

次に所持金を返してくれる関数を作成します。
作成するにあたって以下の記事を参考にしました。

[おとなの財布の中身はいくら？〇円以下が50％超 | 東証マネ部！](https://money-bu-jpx.com/news/article024679/)

また所持金の端数はランダム, 所持金の最大金額は10万円と想定しています。

```python
def show_money():
    rand = random()
    if rand < 0.076:
        money = randint(0,1000)
    elif rand < 0.328:
        money = 1000 + randint(1,4000)
    elif rand < 0.578:
        money = 5000 + randint(1,5000)
    elif rand < 0.803:
        money = 10000 + randint(1,10000)
    elif rand < 0.915:
        money = 20000 + randint(1,10000)
    else:
        money = 30000 + randint(1,70000)
    return money
```

最後に、所持金5連続UPの試行を100万回仮想的に挑戦し、
成功する確率や成功までに声をかけた平均人数を算出していきます。

```python
# 所持金連続UPにトライする回数
n = 1000000

# n回の試行中、所持金5連続UPに成功した回数
count_success = 0

# 5連続UPに成功するまでに、所持金を聞いた回数
count_before_success = 0

# count_before_success を成功した試行毎に格納したリスト
count_before_success_list = []

for i in range(0,n):
    
    # 一回前に聞いた所持金(スタートは-1円から)
    pre_money = -1    
    
    for j in range(0,5):
        count_before_success +=1
        money = show_money()
        if money <= pre_money: break
        pre_money = money
    else:
        count_success +=1
        count_before_success_list.append(count_before_success)
        count_before_success = 0
        
        
print(f"成功確率：{count_success/n*100:.2f}%")
print(f"成功までに声をかけた平均人数:{np.average(count_before_success_list):.2f}")

# 成功確率：0.84%
# 成功までに声をかけた平均人数:322.16
```
# 結果の考察

シミュレーションの結果、成功までに声をかけた平均人数は322人となりました。
一人に声をかける平均時間を、インタビューや移動時間を含めて3分とすれば、
**適当に声をかけると、成功までに平均16.1時間かかる**ということになりそうです。

やはり今回の企画は適当に声をかけるだけでは早く終わるのは難しく、
外見から所持金を推測することが重要となる企画のようでした。
~~だから森田がなかなか所持金を聞けないのも仕方がなかったと言えそうです。~~
【Python】ファイルをオンメモリで生成してFTPで転送する

FTP(SFTP)による高頻度なファイル転送を実装する機会があったので、
備忘録も兼ねてまとめました。

## PythonでのFTP

PythonにはFTP周りのインタフェースを提供するライブラリ`ftplib`があり、
これを用いることでFTPサーバとの通信プログラムを簡単に実装することができます。

ローカルファイルを転送する場合はこんな感じ:

``` python:ftptransfer.py
from ftplib import FTP

def main():
    # 接続
    ftp = FTP("example.com", "username", passwd = "password")

    # FTP.storlinesにファイルオブジェクトを渡す
    with open("test.txt", "rb") as f:
        ftp.storlines("STOR ./test.txt", f)

    # 切断
    ftp.quit()

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

しかし、この方法ではプログラム実行中に出力されたメモリ上のデータを転送することができません。
いちいちファイルに出力するのは冗長ですし、何より**ストレージへの負荷がすごそう**です。

## オンメモリでファイルオブジェクトを作る

そこで、`StringIO`および`BytesIO`を用いてストリームを生成し、ftplibに渡す方法を考えます。

> 引用: Pythonドキュメント 「[io --- ストリームを扱うコアツール](https://docs.python.org/ja/3/library/io.html#in-memory-streams)」

> インメモリー ストリーム  
> str や bytes-like オブジェクト を、読み書き可能なファイルのように扱うことができます。 StringIO は文字列に対して、テキストモードで開かれたファイルのように使うことができます。 BytesIO はバイナリーモードで開いたファイルのように扱うことができます。この2つのクラスは、読み書き可能で、ランダムアクセス可能です。  

`storlines`はバイナリモードで開いたファイルのオブジェクトを渡す必要があるので、今回は`io.BytesIO`を使用します。

```python:BytesIOTest.py
import io

def main():
    # io.BytesIOオブジェクトを生成
    bytesIO = io.BytesIO(bytes("Hello, World!!", encoding="utf-8"))
    print(type(bytesIO))

    # ファイルオブジェクトのように操作する
    with bytesIO as b:
        print(b.readlines())

if __name__ == "__main__":
    main()

# 実行結果
# <class '_io.BytesIO'>
# [b'Hello, World!!']
```

`BytesIO`オブジェクトが生成され、with文で読むと`bytes`が返ってきます。

## ftplibに渡して転送する

では、この`BytesIO`オブジェクトを`storlines`に渡してみます。

```python:sendOnMemoryFile.py
import io
from ftplib import FTP

def main():
    # io.BytesIOでファイルっぽいものを作り、
    bytesIO = io.BytesIO(bytes("Hello, World!!", encoding="utf-8"))
    print(type(bytesIO))

    # FTP.storlinesに渡して転送する
    ftp = FTP("example.com", "username", passwd = "password")
    ftp.storlines("STOR ./test.txt", bytesIO)

    ftp.quit()

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

実行後、サーバをのぞくと…

```
[username@example.com ~]$ cat test.txt 
Hello, World!!
```

記述した文字列が書き込まれたファイル`test.txt`が作成されていることがわかります。

## まとめ

ここまで読んでいただきありがとうございました。

まとめで言うのもアレですが、こんな面倒なことをするより**HTTPSを使うべき**だと思います。
FTPは**F**ile **T**ransfer **P**rotocolなので。

ではまた!
CakePHP2→4の移行作業で意識している点

この記事は[Lancers（ランサーズ） Advent Calendar 2020](https://qiita.com/advent-calendar/2020/lancers) 11日目のエントリーです。

## はじめに

ランサーズ株式会社に21卒入社予定でインターンをしている川原です。
現在、Lancersの管理画面のバージョンアップ作業を行っています。
CakePHP2.8→4のバージョンアップのための書き換えを行っているのですが、実際にソースコードを書き換えていく際に意識している(していこうと思う)点について書きます。
[こちらの記事でCakePHP2→4バージョンアップについて紹介されています。](https://engineer.blog.lancers.jp/2020/03/cakephp2to4/)


## 移行
### 旧実装にひきずられないようにする
コピペして終了、とならないのが移行作業です。実際にどのような手順を踏むかは以下です。

#### 旧実装の仕様把握

バージョンアップ作業において、最初に認識するべきことは旧実装の仕様です。仕様を把握しないとそもそも書くことができません。
そのため、CakePHP2で書かれているORMがどのようなクエリを発行しているのかを直接みる必要があります。

MySQLの場合、以下のように設定して

```
SET GLOBAL general_log = 'ON';
```

MySQLを起動すると実行されるクエリのログの流れを見られるようになります。

```
tail -f /var/mysql/mysql.log
```


#### 具体的な記法、文法等の差について

CakePHP2→3で大幅な変更があり、3→4の差はそれほどでもないようです。
CakePHP2では使用されていて、4では非推奨とされているライブラリ、関数等があります。


#### リファクタリング

旧実装のコードは数年単位で前に書かれたものだったりします。故に当時の開発環境によって現在の開発環境ではCIが通さないようなコードも存在しています。開発環境が整備されたことにより既存の変数、関数等の責務を考え直すきっかけになります。

例えば

```php
return ($this->Users->someMethod() || $this->someMethod() || $this->Hoge->someMethod() || $this->Fuga->someMethod()) ? true : false;
```

上記のようなコードが旧実装の中に存在していましたが、同じような書き方だとPHPMDにより複雑性の指摘がされるということがあり以下のように修正する感じです。

```php
if ($this->Users->someMethod()) {
  return true
};
if ($this->someMethod()) {
  return true
};
if ($this->Hoges->Method()) {
  return true
};
if ($this->Fuga->someMethod()) {
  return true
};
return false;
```

旧管理画面の仕様もそのまま流用するだけではなく、UIや機能の修正も行います。

## 所感

全体として、コードの差分しかないなという感じです。基本的にコードの流用などはほとんどなく、だいたい一からの作り直しという形です。
そのため、移行作業は多くの知識が要求されることから、個人的に良い学習のきっかけにもなっていると思っています。
[docker][AWS] docker コンテナの起動/停止を繰り返すと EC2 間でネットワークが繋がらなくなる


docker コンテナの起動/停止を繰り返していると、EC2 へ接続できなくなる現象でハマったので覚え書き。


## 現象

elasticsearch と連動するアプリケーションを docker コンテナで動かしている環境で、コンテナの起動/停止をしているとあるタイミングで EC2 への接続が切れてしまう現象が発生しました。

- docker-compose でコンテナ起動/停止
- 一定の確率で発生する
- EC2 への ssh 接続がつながらなくなる
- EC2 再起動しても復旧しない
- EC2 再起動中に ping をかけておくと、起動直後に一瞬疎通するが、その後ダンマリになる

アプリケーションの実行環境は以下のような構成。
アプリ用の VPC へピア接続された保守用 VPC 内の踏台 EC2 からアクセスしています。


![fig-docker-network-conflict-env.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558772/13e3c79f-93b1-1a3a-8a5d-e46f20ee28a7.png)


## 解析

EC2 起動直後、しばらくしてからネットワークがつながらなくなるため、EC2 起動時にコンテナを自動起動していた(restart=always) のを廃止してみたが、現象変わらず。
なので、アプリケーション自体の線は除外しました。

問題発生時の EC2 の状態が確認できないと何も分からないため、Elastic IP を割り当てて接続したところ、無事 ssh 接続成功。
ということは、踏台 EC2 からの接続のみの問題となりそうです。

問題のサーバに入れたので、いろいろ状態の情報を収集してみます。

```
# ネットワークインターフェースの状態
$ ifconfig
$ ip route

# ブリッジの状態
$ brctl show

# iptables の状態
$ sudo iptables -L
$ sudo iptables -L -t nat

# docker network の状態
$ docker network ls
$ docker network inspect xxxxxx_default

# docker コンテナの状態
$ docker ps
$ docker inspect xxxxxx
```


## 原因

上記のコマンドによる取得結果を、正常時と問題発生時で比較していると、コンテナの起動/停止の繰り返しで、docker-compose が作るネットワークのアドレスが一つずつ変わっていくのが分かりました。
それで、あるアドレスが設定された場合に問題が発生しているようです。

`172.31.0.0/16`

原因は、アクセス元である保守用 VPC のアドレスと、docker network でブリッジに設定したアドレスがかぶってしまったときに、ルーティングがおかしくなってしまうというものでした。

docker network は内部で iptables を書き換えるので(★)、この影響を受けていたことになります。

```
$ sudo iptables -L -t nat
    :
Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  ip-172-31-0-0.ap-northeast-1.compute.internal/16  anywhere ★
MASQUERADE  all  --  ip-172-17-0-0.ap-northeast-1.compute.internal/16  anywhere
```

docker のネットワークは、デフォルトでは `172.18.0.0/16` から順番に `172.19.0.0/16`、`172.20.0.0/16`、と採番するようで、これがたまたまアクセス元の VPC とかぶってました。アクセス元の VPC は AWS のデフォルト VPC だったので、デフォルト設定で動かしていると案外遭遇してしまうかも。

docker network のアドレス設定については、以下のサイトが参考になりました。

Dockerはネットワークを31個しか作れない
https://ashphy.hateblo.jp/entry/2020/05/23/223354

デフォルトで以下のアドレスがプールされていて、順番に利用されるようです。

- "172.17.0.0/16"
- "172.18.0.0/16"
- "172.19.0.0/16"
- "172.20.0.0/16"
- "172.21.0.0/16"
- "172.22.0.0/16"
- "172.23.0.0/16"
- "172.24.0.0/16"
- "172.25.0.0/16"
- "172.26.0.0/16"
- "172.27.0.0/16"
- "172.28.0.0/16"
- "172.29.0.0/16"
- "172.30.0.0/16"
- "172.31.0.0/16"
- "192.168.0.0/20"
- "192.168.16.0/20"
- "192.168.32.0/20"
- "192.168.48.0/20"
- "192.168.80.0/20"
- "192.168.96.0/20"
- "192.168.112.0/20"
- "192.168.128.0/20"
- "192.168.144.0/20"
- "192.168.160.0/20"
- "192.168.176.0/20"
- "192.168.192.0/20"
- "192.168.208.0/20"
- "192.168.224.0/20"
- "192.168.240.0/20"

※結構、大きな帯域使ってますね。。


## 対処

docker network で利用するアドレスプールを指定できるようなので、これをアクセス元 VPC にかぶらないように設定しました。

```/etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "10"
  },
  "live-restore": true,
  "default-address-pools": [
    { "base":"192.168.0.0/16", "size":24 }  ★
  ],
  "max-concurrent-downloads": 10
}
```

分かってしまえば単純な問題ですが、これはなかなか気づきにくいなと思います。
最初にアプリケーションの原因を考えていたので、だいぶ遠回りしました。。
(docker ネットワークの勉強になったのでヨシとします)


// EOF
Rails ログイン機能


<h2>ログイン情報の取得を簡単にする</h2>

ユーザーがログインしていればsession[:user_id]にユーザーのIDが格納された状態となるのでログイン後はセッションが
生きている限り、下記のコードでユーザーを簡単に取得することができる。

```ruby:

User.find_by(id: session[:user_id])
```

このようなログインしているユーザーを取得する処理は、頻繁に必要になるので、
コントローラやビューから簡単に呼ぶのが定石になっている。
簡単な実現方法としては、ApplicationControllerにcurrent_userというような名前のメソッドを定義することで
全てのコントローラから利用できるようにします。
さらにhelper_methodを指定することで、全てのビューから使えるようにする。


```ruby:app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  helper_method :current_user

  private

  def current_user
    @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
  end
end

```

これでログインに成功すればsession[:user_id]にユーザーのidが入り、current_userでUserオブジェクトを取得できる
状態になりました。

このままでは、ログインしていなくてもどの機能も利用できてしまうので、ログインする必要性に乏しい状態。

各種機能を、ログインしている時にだけ使えるようにする必要がある。

ただし、その前にログアウトから実装する。理由は一旦ログインに成功すると、ログインしていない状態を作り出すことが難しく、開発上不便だから。


<h2>ログアウト機能を実装する</h2>
ログアウト機能とは、アプリケーションの状態を、ログインしている状態からログインしていない状態に変えること。
したがって、このアプリの場合は、session[:user_id]にnilが入っている状態にすれば良いということになる。

セッションからuser_idの情報だけをピンポイントで消すには以下のようにすればできる。

```
session.delete(:user_id)
```

ただし、user_idだけでなく、ユーザーに紐づくその他の情報をセッションに入れるようにしている場合には、ログアウト時にセッション内の情報を
全て削除するようにします。

```
reset_session
```
それでは、このようなログアウト処理を実行するdestroyアクションを、SessionsControllerに追加していきます。
まず、ログアウトのためのルーティングを定義していく。

```ruby:config/rotes.rb
delete '/logout', to: 'session#destroy'
```

次にアクションを追加

```ruby:app/controllers/sessions_controller.rb
  def destroy
    reset_session
    redirect_to root_url, notice: 'ログアウトしました'
  end
```

これでアクションの準備ができた。最後にアプリケーション内に「ログアウト」のリンクを追加してみる。

```ruby:app/views/layouts/application.html.slim
doctype html
html
  head
    title
      | Taskleaf
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
  body
    .app-title.navbar.navbar-expand-md.navbar-light.bg-light
      .navbar-brand Taskleaf

      ul.navbar-nav.ml-auto
        - if current_user
          li.nav-item= link_to 'タスク一覧', tasks_path, class: 'nav-link'
          li.nav-item= link_to 'ユーザー一覧', admin_users_path, class: 'nav-link'          
          li.nav-item= link_to 'ログアウト', logout_path, method: :delete, class: 'nav-link'
        - else
          li.nav-item= link_to 'ログイン', login_path, class: 'nav-link'
    .containar
      - if flash.notice.present?
        .alert.alert-success= flash.notice
    = yield
```

ここではさっき定義したcurrent_userメソッドを利用して、ログインしている時はログアウトのリンクを表示している。
また、以前に追加したユーザー管理機能へのリンクも表示している。
一方、ログインしていない時はログイン画面へのリンクを表示します。

これでログインとログアウトを行うことができるようになったがあまり仕上がっているとは言えない。
認証機能を追加する場合は「ログインしていなければ一定の機能を使えなくする」「ログインしているユーザーが自分のデータしか見られなくする」
と、いった制限も付け加えたいところです。

次回でやっていきたいと思います。

参考書籍：　現場で使える Ruby on Rails5 速習実践ガイド