OmniAICreator/Qiita-1.07M huggingface dataset:
Laravelの開発環境構築

##環境
Mac Catalina10.15

##Homebrewをインストールする
[Homebrew](https://brew.sh/index_ja)はソフトウェアの導入を単純化するパッケージ管理システムのひとつです:blush:

以下コマンドを実行

```sh
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

インストールできたか確認

```sh
$ brew -v
```

##PHPをインストールする
以下のコマンドでphp7.4をインストールする

```sh
$ brew install php@7.4
```
インストールできたか確認

```sh
$ php -v
```

##Composerをインストールする
Composerとは、PHP向けのパッケージ管理システムです:blush:

Homebrewでインストールする

```sh
$ brew install composer
```

インストールできたか確認

```sh
$ composer -V
```

##Laravelのインストール
Composerを用いてLaravelをインストールします:blush:
方法は2通りあります。

####方法1

```sh
#Laravelインストール＆プロジェクト作成
$ composer create-project laravel/laravel --prefer-dist プロジェクト名
```

####方法2

```sh
#Laravelインストール
$ composer global require "laravel/installer"
#プロジェクト作成
$ laravel new プロジェクト名
```

##laravelのバージョン確認
```sh
$ php artisan -V
```

##デバッガーのインストール
```sh
$ composer require barryvdh/laravel-debugbar
```
AWS CLI で ECS コンテナを単発起動する

# 前提条件

- ECS Cluster
- Task Definition
- VPC
- Subnet
- Security Group

上記のリソースが作成済みであること。

# 実行するコマンド

以下の箇所は適宜代入したり書き換えたり。

- subnet-000000000000
- sg-000000000000
- CLUSTER_NAME
- TASK_DEFINITION_NAME  

```bash
aws ecs run-task \
	--launch-type FARGATE \
	--network-configuration "awsvpcConfiguration={subnets=['subnet-000000000000','subnet-000000000000'],securityGroups=['sg-000000000000'],assignPublicIp='DISABLED'}" \
	--cluster ${CLUSTER_NAME} \
	--task-definition ${TASK_DEFINITION_NAME}
```

# 使いどころ

private な RDS のマイグレーションを単発でささっと呼び出すのに使ったりする用。

# 気になるところ

CFn では、 `!Sub`, `!ImportValue` を使って変数部分を書くことができるが、 cli では使えなさそう(?)
CFn を書くことになっても良いので、何か方法をご存知の方がいらっしゃれば教えていただきたいですm(_ _)m
bashでEC2のインスタンスを設定する

#プロローグ
AWSのインスタンス起動時にbashによる設定が可能です。
インスタンス起動時に、apacheをインストールしたり、ホスト名を併せて変更したりできます。

#手順
EC2の画面から「インスタンスの作成」を押下します。
<img width="650" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/ece8df8b-c489-71da-f11a-82b19f9c0d45.png">

AMIの「選択」ボタンを押下します。
<img width="649" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/dd68ec8d-14f7-dcc3-dc20-51000e01998e.png">

インスタンスタイプを選び、「次のステップ：インスタンスの詳細の設定」を押下します。
<img width="632" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/57f72fad-0399-a52a-a3e7-08e487156f42.png">

下部にある高度な詳細のユーザデータの項目にbashの内容を記入します。
自分はudemyの講座をやっているので、下記を入力しました。
<img width="632" alt="4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/75549b4a-8e56-cf8b-1331-ce46fe8c7b96.png">

```bash:test
#!/bin/bash
# サーバーの設定変更
sed -i 's/^HOSTNAME=[a-zA-Z0-9\.\-]*$/HOSTNAME=udemy-bash/g' /etc/sysconfig/network
hostname 'udemy-bash'
cp /usr/share/zoneinfo/Japan /etc/localtime
sed -i 's|^ZONE=[a-zA-Z0-9\.\-\"]*$|ZONE="Asia/Tokyo"|g' /etc/sysconfig/clock
echo "LANG=ja_JP.UTF-8" > /etc/sysconfig/i18n
# アパッチのインストール
sudo yum update -y
sudo yum install httpd -y 
sudo chkconfig httpd on
====
```

ストレージです。
デフォルトにしています。「次のステップ：タグの追加」を押下します。
<img width="659" alt="5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/bf34c39b-bbc0-0353-a949-f9b2002913c2.png">

タグです。
デフォルトにしています。「次のステップ：セキュリティグループの設定」を押下します。
<img width="642" alt="6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/bc912be2-c1cf-49b0-e3fa-bf8a2368469c.png">

セキュリティグループの設定です。
デフォルトにしています。「確認と作成」を押下します。
<img width="659" alt="7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/2e02051d-00f1-ead8-09b5-79b57c6363c7.png">

内容に問題がなければ「起動」を押下します。
<img width="667" alt="8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/c0b9de56-8119-ca79-8512-4db712fbf5b6.png">

これでEC2に作ったインスタンスが起動できたので、SSHで接続します。
自身はWindows環境なのでTeratermを利用します。
接続先IPアドレスは動的なアドレスを画面から確認して指定しています。
<img width="404" alt="9.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/aab1b3b0-efb3-6051-ad38-51713c58eeeb.png">

<img width="404" alt="10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/8eb5d406-64ef-3aec-b767-75df8a9e2a68.png">

bashの設定でApacheをインストールしているので、導入されているか確認してみます。

```bash
yum list installed | grep httpd
```
apacheが導入されていることが確認できました。
また、ホスト名も変更していましたが、ホスト名も変わっていることが確認できました。
（黒塗りになってしまっていますが。。）
<img width="494" alt="11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/15e8a60c-2796-2d83-bec7-440cfc65ff9f.png">
【VMware ESXi】仮想スイッチのポートセキュリティポリシーとは？

# はじめに

今回は、ESXiホスト構築時の仮想スイッチのポートセキュリティポリシーについて知識をアウトプットしていきます。

僕にはデータセンターに赴いてvSphereを構築をしていた経験があります。
当時、仕事にやりがいを見出せなかった影響からこちらの設定をよく忘れておりました。

また、最近ではOS設定周りを担当することが多く、HyperVisor自体を構築する機会が少なくなりました。
そのため、忘れないように備忘録として残しておきたいと思います。

# 仮想スイッチ設定の中にある「セキュリティ設定」とは？

下記画像の赤枠部分の設定内容になります。

![1_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/ea587a4c-5519-4069-7f8e-d6a673414ceb.jpeg)



- **無差別モード**
- **MACアドレス変更**
- **偽装転送**

こちらの3つの設定になります。


デフォルトの設定は画像の通りでこのようになります。

- 無差別モード  
**→拒否**  
- MACアドレス変更  
**→承諾**  
- 偽装転送  
**→承諾**  


では、こちらのそれぞれの設定について解説していきたいと思います。

## 無差別モード

無差別モードとは、「自分宛ではないデータパケットも全て処理するかしないか」という設定です。
**別名、「プロミスキャスモード」**

「承諾」と「拒否」の設定の意味はこちらになります。

- **「承諾」** 
仮想スイッチ上に流れる全てのトラフィックを仮想マシンが受信

- **「拒否]**
自分宛のトラフィックのみ受信

デフォルト設定では**「拒否」**になります。

仮想マシンが全てのトラフィックを受信できる場合、見られてはいけない情報を見られてしまう可能性がありますからね(笑)

仮想マシンでのトラフィックのモニタリング等、仮想スイッチ上のトラフィックを受信する必要がある要件の場合は「承諾」に設定するようです。

## MACアドレス変更

MACアドレス変更とは、「仮想マシンのMACアドレスを、仮想NICに割り当てられているMACアドレスと異なる値に設定するかどうか」という設定です。

「承諾」と「拒否」の設定の意味はこちらになります。

- **承諾**
仮想マシンの構成ファイル(.vmxファイル)にて定義したMACアドレス以外に、仮想マシンにて作成したMACアドレス宛のフレームも受信できる。

- **拒否**
仮想マシンの構成ファイル(.vmxファイル)にて定義したMACアドレスにのみフレームを受信することができる。

デフォルト設定は**「承諾」**です。

承諾にするメリットは、「iSCSI SAN」や「Microsoft Network Load Balancer」を起動させたいような時に便利であることだそうです。

「拒否」にした場合は、ハッカーからのMACアドレスの変更を防ぐことができます。

僕が構築作業をした際には「承諾」に設定にするパターンが多かったです。


## 偽装転送

偽装転送は、「MACアドレスのなりすましに対して保護するかしないか」という設定です。

「承諾」と「拒否」の設定の意味はこちらになります。

- **承諾**
仮想マシンの構成ファイル(.vmxファイル)にて定義したMACアドレス以外に、仮想マシンにて作成したMACアドレスを送信元とするフレームの送信が可能。

- **拒否**
仮想マシンの構成ファイル(.vmxファイル)にて定義したMACアドレスのみを送信元としたフレーム送信が可能。

デフォルト設定は**「承諾」**です。

「MACアドレス変更」が受信設定で、「偽装転送」は送信設定になります。

フレームの送信元(出どころ)を誤魔化すか誤魔化さないかの設定になります。

こちらも構築作業では「承諾」以外に設定したことがないです。

※設定理由についての記事がインターネット上に少ないと感じます。


## 参考記事

**VMware vSwitchの安全なセキュリティ設定について**
https://www.climb.co.jp/blog_vmware/vmware-5114

**徹底攻略VCP6.5-DCV教科書 VMware vSphere 6.5対応 徹底攻略シリーズ**
https://ebookjapan.yahoo.co.jp/books/438715/




# 最後に

本記事は調べながら書きました。

思ったこととしては、インターネット上に情報が少ないということです。

「無差別モード」は設定のメリットがわかりやすいのですが、「MACアドレス変更」や「偽装転送」については少しわかりづらいなと感じました。

VMware製品については、まだまだ勉強不足なところがあります。

これからも勉強していく中で気になった点等をアウトプットしていきたいと思います。


**↓こちらもチェック頂けると嬉しいです！**

**僕のブログ**
https://satton-infra.com/

**Twitter**
https://twitter.com/satton6987

**note**
https://note.com/satton56874

**YouTube**
https://www.youtube.com/channel/UCYaSYnagyhKzdOXK_RsiKiA
PDF処理関係(分割など)

#PDFの分割方法(25ページずつ分割する例)
・pgnにページ数が格納される
・pdfWriter.addPage(reader.getPage(j))でページを足していく


```python
import PyPDF2
import os
os.chdir(hogehoge)

pdf_name = "hogehoge"
reader = PyPDF2.PdfFileReader(pdf_name)
pgn = reader.getNumPages()

for i in range(0, pgn, 25):
    pdfWriter = PyPDF2.PdfFileWriter()
    for j  in range(i, i+25):
        
        if j >= pgn:
            break
        pdfWriter.addPage(reader.getPage(j))
    pdfWriter.write(open(hogehoge.pdf".format(i), "wb"))
```
pandasで地味に使う書き方

#データフレームの並び替え

```python
#デフォルトは昇順
newdf = df.sort_values(["column1","column2"])

#降順にするにはascending = Falseをつける
newdf = df.sort_values(["column1","column2"], ascending = [True, False])
```

#欠損値の処理
```python
#欠損値を0で埋めるケース
newdf = df.fillna(0)

#欠損値の列毎の集計方法
df.isnull().sum()

#欠損値の行だけ抽出
df[df.isnull() == True]
```
Herokuを用いたRailsアプリのデプロイ

## Herokuのアカウントを作る
まずは以下のページからHerokuのアカウントを作りましょう。
https://signup.heroku.com/login
すると、登録したメールアドレス宛にHerokuから認証用のメールが送信されるので、リンクをクリックしてリンク先でパスワードの設定を行います。
![スクリーンショット 2020-05-13 20.24.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/eb05f9d2-7e84-95b8-99ab-3fc1b24ec5af.png)
これで登録は完了です。

## アプリの設定を変更する
アプリ側の設定をHerokuに合わせて変更します。

・Gemの追加
HerokuではPostgreSQLというデータベースを使うため、pgというgemをインストールする必要があります。
本番環境だけにインストールできればいいので、group :production do ~ endの間に記載します。

```
group :production do
  gem 'pg'
end
```

.database.ymlの修正
上述のようにHerokuではPostgreSQLを使用しているので、database.ymlも本番環境(production)の記述を変更します。

```
production:
  <<: *default
  adapter: postgresql
  encoding: unicode
  pool: 5
```

## GitHubに反映
設定ファイルの修正が完了したため、GitHubのマスターブランチに反映しましょう。
![スクリーンショット 2020-05-13 20.59.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/7c33bfd6-bceb-2a1e-ee4a-bc22b861c4a3.png)

## Herokuを自分のPCにインストール
以下のURLからHerokuをインストールしましょう。
私はMacを使っているのでHomebrewを使ってインストールします。
https://devcenter.heroku.com/articles/heroku-cli
<img width="400" alt="0" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/41cf319f-3dc1-71e7-577b-105751682e58.png">

・インストールコマンド実行

```
% brew tap heroku/brew && brew install heroku
```

・インストール完了後、herokuのバージョンを確認することで、herokuがインストールされているか確認。
ここでherokuコマンドが見つからないというエラーメッセージが出るので、パスを通してあげます。

```
 % heroku -v
zsh: command not found: heroku
```

## パスを通す
~/.zshrcにherokuコマンドのパスを追記します。

```
vim ~/.zshrc
```

~/.zshrcに以下を追記

```
export PATH=$PATH:/usr/local/Cellar/heroku/7.39.5/libexec/bin
```
sourceコマンドでzshrcの内容を反映する。

```
% source ~/.zshrc
```

これでherokuコマンドが実行できるようになります。

```
% heroku -v
heroku/7.41.1 darwin-x64 node-v12.16.2
```

・あまりお勧めしないやり方
以下のようにechoコマンドで.zshrcにパスを追記することもできますが、>>ではなく>で.zshrcの内容を全て上書きしてしまう可能性があるため、個人的にはvimで編集することをお勧めします。

```
echo 'export PATH=$PATH:/usr/local/Cellar/heroku/7.39.5/libexec/bin' >> ~/.zshrc
```

## PCからherokuにログインする
loginコマンドを実行するとブラウザが起動しHerokuのログイン画面に飛びます。
ログインを実行後、ターミナルに戻って作業を再開します。

```
% heroku login
heroku: Press any key to open up the browser to login or q to exit: 
```
![スクリーンショット 2020-05-13 22.07.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/429077/e2b70ffe-7756-7adb-4730-1b813c25d1e8.png)

ターミナルからの操作でHerokuのアプリを作ります。
ここで作ったアプリにGithubからコードを反映することでデプロイできるようになります。（アプリ名がURLになるので、名前は一意となるものにしてください)

```
% heroku create アプリ名
```

## デプロイ
以下のコマンドでデプロイしましょう。

```
% cd アプリを格納しているディレクトリ
```

```
% git push heroku master
```
おそらくこんな感じのエラーが出ます。

```
% git push heroku master
fatal: 'heroku' does not appear to be a git repository
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

.git/configを修正することでエラーを回避できます。

```
% vim .git/config
```

以下を追記することで"heroku"がどこのURLを指すのか指定します。
アプリ名は上述の「heroku create アプリ名」で作成したアプリを記述してください。

```
[remote "heroku"]
  url = https://git.heroku.com/アプリ名.git
  fetch = +refs/heads/*:refs/remotes/heroku/*
```

それでは再度デプロイ。

```
% git push heroku master
```

デプロイ完了後はマイグレーションを行います。

```
% heroku run rails db:migrate
```

ここまで正常終了すればHerokuにアプリが上がっているはず！
ターミナルで「heroku open」を入力するか、https://アプリ名.herokuapp.com/にアクセスして確認しましょう！
便利だなと思ったCSSテクニック【初心者向け】

# あくまでも初心者向け
あくまでも初心者目線となります。（なのでテクニックって言うほどじゃないかも...）
私と同じことで悩むことがなくなったり、新たな発見に繋がると嬉しいと思ってこの記事を書いています。



## 親要素の設定を引き継ぐ
```
a {
  color: inherit;
}
```
`inherit`キーワードは親要素の設定を引継ぎます。

例えば、

```
// HTML
<p>詳細は<a href="#">こちら</a></p>

// CSS
p {
  color: #fff;
}

p a {
  color: #fff;
}
```
a要素も文字色を変更したい場合は、２回同じ指定をする必要があります。

しかし、

```
// HTML
<p>詳細は<a href="#">こちら</a></p>

// CSS
p {
    color: #fff;
}

p a {
    color: inherit;
}
```

上記の記述を使えば、文字色が変更になっても修正箇所はひとつで済みます。

......

## 擬似要素にも同じ色を使う

```
.nav-btn {
    /* 省略 */
    width: 30px;
    height: 30px;
    cursor: pointer;
    color: #333;
}

.nav-btn::before,
.nav-btn::after {
    /* 省略 */
    color: currentColor;
}
```
これはハンバーガーメニューの実装で見た例。

`currentColor`を使って色を揃えています。
こちらも、色の変更があっても修正が一箇所で済みますね。

......

## 随時更新予定
私も勉強中なので、引き出し全然ありません。すみません...。
今後もっと増やしていきたいと思っています。

もし「こんな便利なテクニックあるよ！」という場合は
コメントにてお待ちしています。

実際に試してみた後に、記事に追記していきたいと思います。
SQL学習1日目

Qiitaへの初投稿です:santa_tone2:

今日は**SQL**について学んだので簡単にまとめます:smirk:

「SQL」とは簡単にうとデータベースを扱うための言語です。データベースとは、テキストや数値などのデータを保存するためのツールです。データベースは、エクセルのような表でデータを管理しています。表のことを「テーブル」、縦の列のことを「カラム」、横の列のことを「レコード」と呼びます。データベースからデータを取得するためには、「データを取得してください」といったようにデータベースに送る命令（クエリ）が必要です。SQLはこのクエリを書くための言語です。

### ○クエリ一覧
　・select→「select カラム名」とすることで、特定のカラムのデータを取得することができます。

※複数のカラムからデータを取得したい場合は「,」で区切って取得することができます。（例：select name, age;）
※全てのカラムを取得したい場合は「select*」とすることで全てのカラムのデータを取得するとこができます。

　・from→「from　テーブル名」とすることで、どのテーブルのカラムなのかを指定します。

　・where→「where カラム名　＝　？」と書くことによって、カラム名が？であるレコードのデータを取得することができます。

　・比較演算子→「>, <, <=, >=」を用いることによって、「カラム名」が〜以上や〜未満といったレコードを取得することができます。

　・like演算子→where カラム名 like '%〇〇%'とすることによって〇〇を含むデータを全て取得できる。また、'〇〇%'とすると〇〇で始まる文字列、'%〇〇'とすると〇〇でおわる文字列を取得することができます。

　・NOT演算子→「where not 条件」とすると条件を満たさないデータを取得します。

　・is null / is not null→nullとは、何も保存されてないということ。「where カラム名　is null」で指定したカラムがNULLであるデータを取得することができます。「where カラム名　is not null」で指定したカラムがNULLではないデータを取得することができます。

　・AND演算子→「where 条件１ and 条件２」とすることで、条件１と条件２を共に満たすデータを検索することができます。

　・OR演算子→「where 条件１ or 条件２」とすることで、条件１または条件２のどちらかを満たすデータを検索することができます。

　・order by→「order by　並べ替えたいカラム名　並べ方」とすることでデータを並び替えることができます。並べ方に関しては、昇順にしたい場合は「ASC」、降順にしたい場合は「DESC」を使うことによって並び替えることができます。

　・limit→「limit データの件数」とすることで、検索結果の上から指定されたデータの件数だけ取得することができます。



長くなってしまいましたが、今日の学習の振り返りは以上です。
このように今日学習したことを簡単にまとめて自分の復習がてらアウトプットしていきます。
最後まで読んでくださってありがとうございました:poop:
【Unity】Terrainのtree重すぎ問題をGPU Instancingで解決する

<img width="480" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/0368e0ea-efa5-9b24-a2e3-3fb28cf49450.png">

---


##やりたいこと
- terrainで木を大量に配置したのですが、せっかくLODを設定した低ポリの木でも、バッチ数がとても多くなってしまいました
- これを減らしたいです

##やったこと
- terrainのGUP Instancingという機能を使います
- 木のもととなっているオブジェクトについているマテリアルの「GPU Instancing」にチェックを入れます
- そんなチェックないよ！という場合は、それがあるものにシェーダを変えます

参考までに、僕のマテリアルのbefore afterを載せておきます

before
<img width="480" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/1e25118d-180b-e3ca-76a1-f04f8ffa4d28.png">

after
<img width="480" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/77e46bdf-f780-c9f7-8dc7-b98a4140dfee.png">

「bark wh」というマテリアルのシェーダをMobile Diffuseにし、Enable GPU Instancingにチェックを入れました

さらに、
- terrainの設定から、Draw GPU Instancedにチェックを入れ、Bake Light Probes for Treeはチェックを外しておきます↓

<img width="480" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/2bcdff36-5db9-5673-feac-dc83fe634226.png">


そうすると...before afterでこんなに変わっちゃいます！
ポリゴン数が微妙に変わってるというツッコミはなしだよ♡(スクショの前後で別の作業したので、なんか関係ないものが消えたんだと思います)

before
<img width="720" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/883eb61d-a8f0-92de-dc86-f0da9abfde07.png">

after
<img width="720" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/e46ba3f6-89b5-8d28-b832-5b0ace26040a.png">

##追記1(20200514): うまくいかないときは　dynamic batchingできていないかも
以上と同じ手順でやってもうまくいかない、減るは減るけど劇的に減らない、
という場合はdynamic batchingが設定できていない可能性があります。

Edit > Project Settings > Player > Other Settingsのなかから
Dynamic Batchingがオンになっているか確認してください(ここにたどり着くのに数時間溶かしました)
<img width="480" alt="スクリーンショット 2020-01-02 0.21.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/348026/852b92ee-df03-b385-93ff-172b270fa73f.png">

##参考
[【Unity】Terrainの負荷やらDrawCallやらを下げるポイント](http://tsubakit1.hateblo.jp/entry/2018/02/02/184332#Instancing%E3%82%92%E6%9C%89%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B)
Let's EncryptでSSL化したNginxサーバは、証明書更新後にreloadを忘れると古い証明書を使い続けてしまう

# この記事について
掲題の通り。
そんなの当たり前だろ、と言われてしまいそうですが、実際先日やらかしてしまったので…。
メモ兼戒めとして記事にします…。

# 事の発端
2020年2月半ばごろ、個人でとあるWebアプリケーションの運用を開始した。
フロントエンドがNginx + vue.js、バックエンドがPython(Flask) + uWSGIという構成。
NginxはSSL化しており、SSL証明書はLet's Encryptで発行したもの。

証明書の更新は自動化しようと思い、crontabに以下を登録した。

```crontab
# 毎月20日の1:20にSSL証明書を強制的に更新する
20 1 20 * * /usr/local/bin/certbot-auto renew --force-renewal
```

# 事象発生
2020年5月1日、上記のWebアプリケーションに接続しようとすると証明書エラーが出た。
これを受けて調査を開始する。

- エラーとなっている証明書の内容を確認
    - 4/30で期限切れとなっていた。初回発行時の証明書のままと気づき、証明書更新が行われていないことを疑う
- crontabに設定した証明書更新ジョブが動いているか確認
    - 動いており、証明書は7月中に期限が切れるものに更新されていた。更新はできているがNginxに反映されてないと気付くも、reloadのし忘れにはまだ気づかず
- NginxのSSL化手順に関するサイトを検索し始める
    - [Nginxのroloadをしないと証明書が反映されないと書いているページ](https://nekonenene.hatenablog.com/entry/2017/10/14/043001)を発見。ここでようやく原因に気づいた

# 対応
急いで以下のコマンドを投入してリロード実施。
実施後、証明書が更新後のものに切り替わっており、証明書エラーが解消されていることを確認。

```
service nginx reload
```

エラーが解消されたことが確認できたので、crontabを以下の通り修正。
これで今後、同事象は再現しなくなると思われる。

```crontab
# 毎月20日の1:20にSSL証明書を強制的に更新した上で、Nginxのリロード実施
20 1 20 * * /usr/local/bin/certbot-auto renew --force-renewal && service nginx reload
```

# おわりに
考えてみればreloadしないと証明書が更新されないのは当たり前なのですが、なかなか気づけず、恥ずかしい限りです。
今後は同じミスはしないよう、気を付けます…。
【Kaggle】頻繁に使うデータ可視化方法

#1.目的

Kaggleを始めとしてデータ分析を行う際、
**ほぼ毎回使うにも拘らず書き方を忘れて、都度検索しているコードがある**。

毎回「これを使いたい」というコードは割と定例化されているので、蓄積しておくことが目的です。

#2.使用データ
広く知られている、kaggleのタイタニックをテーマにします。

https://www.kaggle.com/c/titanic

#3.目的別コード

##(1)その前に・・
必要なもののインポートとデータ読み込みをします。

```python
#インポート（不要なものも一部あり）
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
matplotlib.style.use('ggplot')
%matplotlib inline

#データ読み込み
df_train =  pd.read_csv("C:train.csv")
df_test = pd.read_csv("C:test.csv")

```

##(2)特定の条件の情報を見たい

###(ⅰ)単一条件の場合

例えば、まずはFareをヒストグラム化します。

```python
sns.distplot(df_train["Fare"])
```

<img width="350" alt="キャプチャ1.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465870/ee6684fa-391b-f97d-1e41-b9dc85a03b5d.png">

すると、大半が低いところに固まっているにも関わらず、ほんの一部、
500を超えている人たちがいますね。

この人たちの他の説明変数の情報も見たい場合、下記のようにします。
この、[]と()の使い方を毎回忘れてしまうのです・・・。

```python
df_train_Fare = df_train[(df_train["Fare"] > 500)]
df_train_Fare
```
するとこのように、Fareが500以上の人が表示（この場合は3人）されるので、
何か他の変数に特徴がないか？等を分析することができます。

<img width="650" alt="キャプチャ2.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465870/fd5d80e8-8611-1488-e748-c0ba1a781799.png">

ちなみに条件が数値（先ほどの例で言うと500以上）ではなくカテゴリ（文字列）の場合はこのようにします。

```python
#例えば、男性だけのデータをdf_train_Sexに格納
df_train_Sex = df_train[(df_train["Sex"] == "male")]

#男性だけのFareのヒストグラムを描画
sns.distplot(df_train_Sex["Fare"])
```

<img width="350" alt="キャプチャ3.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465870/f59a964e-e8e6-f1cb-9d84-d8cfe35d5cd6.png">

###(ⅱ)複数条件の場合
先ほどの例で、例えばFareが500以上かつ男性のデータを参照したいとします。
（データ分析上、需要があるかは別として）

その場合、下記のように複数条件をつなぎます。
私はこの書き方を頻繁に忘れてしまいます。

```python
df_train_male_Fare = df_train[(df_train["Fare"] > 500) & (df_train["Sex"] == "male")]
df_train_male_Fare
```

するとこのように、Fareが500以上の男性のデータが抽出されます！
<img width="600" alt="キャプチャ4.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465870/79fe69cb-8463-5bf3-6bb0-ee4153370c76.png">

上記は「かつ（&）」で結びましたが、「または（or）」で結びたい場合は「&」を「|」で結んでください。

##(3)groupbyしたい
例えばPclass毎のAgeの平均を見たいとします。
そういったときはgroupbyをするのがいいですが、このやり方もよく
忘れてしまいます。

```python
groupby = df_train["Age"].groupby(df_train["Pclass"]).mean()

#データフレーム化
groupby = pd.DataFrame(groupby)

groupby
```

Pclassごとの平均年齢を出すことができました！
<img width="150" alt="キャプチャ5.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465870/38c43cf1-a217-db44-fe61-51d330728062.png">

#4.結び
よく使うコードを控えておくのも煩雑だし、かといって都度調べるのも非効率と感じる場面が多いと思います。

今回のコードは割と細かい調査をする時に使う場面が多いと思うので、
少しでもお役に立てますと幸いです。
WordPressでjQueryが動かない

##WordPressでjQueryが動かない
WordPressでjQueryを使おうとした時「$ is not a function」とコンソールエラーが出て動かなかったので調べてみた。

##悪さしている奴が見つかった
wordpressの中で使っているjquery.jsの「jQuery.noConflict();」という記述が問題だった。
APIの説明通り、他ライブラリとのコンフリクトを避けるために使われているそう。ふーん・・。
http://semooh.jp/jquery/api/core/jQuery.noConflict/_/

というわけで、以下の通り記述を直したら動いた！！
$('.hoge').val();
↓
jQuery('.hoge').val();

続き頑張るぞー(^O^)／
Laravel Sanctumお試し

## プロジェクトの作成とSanctumの導入
```zsh
$ laravel new hello-sanctum
$ cd hello-sanctum
```
- Sanctumのインストール

```zsh
$ composer require laravel/sanctum
```

- configファイルとmigrationファイルの作成

```zsh
$ php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
```

- .env内のDBパラメータを任意の値に設定

```text:.env
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=
```

- migrationの実行

```zsh
$ php artisan migrate
```

- ダミーユーザーを作成

```zsh
$ php artisan tinker
>>> factory(App\User::class)->create()
=> App\User {#3054
     name: "Dr. Gerry Jast",
     email: "mschroeder@example.com",
     email_verified_at: "2020-05-13 11:00:44",
     updated_at: "2020-05-13 11:00:44",
     created_at: "2020-05-13 11:00:44",
     id: 1,
   }
```

## Userモデルにトークン認証用の設定を追記

```php:app/User.php
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
```

## 認証用のコントローラの作成

```zsh
$ php artisan make:controller AuthController
```

```php:app/Http/Controllers/AuthController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        if (!Auth::attempt(request(['email', 'password']))) {
            return response()->json([
                'message' => 'Unauthorized'
            ], 401);
        }
        $accessToken = Auth::user()->createToken('authToken')->plainTextToken;
        return response()->json([
            'access_token' => $accessToken,
        ]);
    }
}
```

## 認証用ルートの作成

```php:routes/api.php
// ログイン
Route::post('/login', 'AuthController@login');

// ユーザー情報の取得
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});
```

## お試し
- ビルトインサーバーを起動

```
$ php artisan serve
```

- ログインしてトークンを発行（Postman）

```yml:PostmanのHeaders
Content-Type:application/json
X-Requested-With:XMLHttpRequest
```

```yml:PostmanのBody（form-data）
email:mschroeder@example.com #ダミーユーザーを作成したときのemail
password:password
```
![スクリーンショット 2020-05-13 21.15.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2469/8245b158-a423-eb83-4db4-3cc2758c8189.png)

- 認証つきのURLにアクセス（Postman）

```yml:PostmanのHeaders
Content-Type:application/json
X-Requested-With:XMLHttpRequest
Authorization:Bearer access_token #ログインのリクエストで返却されたaccess_token
```
![スクリーンショット 2020-05-13 21.22.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2469/cda622c9-2d92-8f14-de7a-d19837306c1d.png)

## その他

```php:config/sanctum.php
'expiration' => 1, // これを設定すると有効期限（分）をつけれる
```
【ExcelVBA】ハイパーリンクの不具合？ ～Why VBA People ～

--------------------------------

# はじめに

この記事ではExcel VBA で起きたあんなエラーや
こんな不具合、ポイントについて書いています。

# 動作環境
Windows10 Pro 64bit
Excel2016 32bit
Excel2019 64bit

O365なし

# 問題発生
障害や問題はある日突然起きる。

表題にもあるとおりExcel VBAで
ハイパーリンクを取得するマクロを
動かしていた時の話

100個のハイパーリンクが一つの
ハイパーリンクを削除しただけで消える
という問題が発生

ざっくり何が問題かと言えば
> **目に見えるハイパーリンクの数**と
> **実際のハイパーリンクの数**が違う

ということ

# なんでこんなことが...

どうやらExcel先生はハイパーリンクの入ったセルを
複数選択でコピーして別のセルに貼り付けると
貼付先が複数セルでも
一つのハイパーリンクがセルに貼り付けられるそうだ。

**要するに**
**セルの数だけハイパーリンクを貼り付けない**
という仕様

# ちょっと検証してみよう ～ 検証手順 ～

1. マクロ有効ブックを新規作成
2. 適当なセルにリンクの入りそうなURLを入力
3. URLの入ったセルをコピー
4. 複数行にセルをコピー
5. ハイパーリンクを調べるをマクロ実行

マクロは以下のコードを使用した

``` VB
Sub Sample2()

  Dim i As Long, msg As String

  '1回目 ハイパーリンクの数：2
  msg = "ハイパーリンクの数:" &  ActiveSheet.Hyperlinks.Count & vbCrLf
  MsgBox msg

  For i = 1 To ActiveSheet.Hyperlinks.Count
    msg = msg & ActiveSheet.Hyperlinks(i).Range.Address & vbCrLf
  Next i
  Range("A1").Hyperlinks(1).Delete

  '2回目 ハイパーリンクの数：1
  msg = "ハイパーリンクの数:" &  ActiveSheet.Hyperlinks.Count & vbCrLf
  For i = 1 To ActiveSheet.Hyperlinks.Count
    msg = msg & ActiveSheet.Hyperlinks(i).Range.Address & vbCrLf
  Next i

  MsgBox msg
  Range("B2").Hyperlinks(1).Delete
  msg = "ハイパーリンクの数:" &  ActiveSheet.Hyperlinks.Count & vbCrLf
  For i = 1 To ActiveSheet.Hyperlinks.Count
    msg = msg & ActiveSheet.Hyperlinks(i).Range.Address & vbCrLf
  Next i

  '3回目 ハイパーリンクの数：3 ?
  MsgBox msg

End Sub

```

# トレース
簡単なプロシージャの動きを順に追っていこう

>前提：
>セルA1にリンクを入力
>コピーしてB2からB5までペースト

1回目 このときのCountプロパティは
ハイパーリンクの数を2と返します。
１つはRange("A1")、もう一つはRange("B2:B5")

2回目 このときのCountプロパティは
ハイパーリンクの数を1と返します。
Range("A1")のハイパーリンクは削除
Range("B2:B5")はハイパーリンクの数を
１としています。

**３つ貼り付けているように見えますが
実際には１つです。**

それでは
3回目 このときのCountプロパティはいくつを返すか

**答えは0です。**

Range("B2")のハイパーリンクを削除したので
Range("B3,B4,B5")が残るように見えますが

Range("B3,B4,B5")はRange("B2")を参照しているので
Range("B2")のハイパーリンクを削除すると
つながるRange("B3,B4,B5")の
ハイパーリンクも削除してしまうのです。

**厳密にいえばRange("B3,B4,B5")は**
**Range("B2")のハイパーリンクを共有している**

# 対策
- 選択コピペはしない
- リンクの編集は右クリックでやる
- リンクの数が多い場合はマクロでリンクを貼る
- そもそもExcelにリンクを貼らない

# まとめ

長々と書きましたが、いかがだったでしょうか。

それではまとめです。
**Excelのセルにハイパーリンクを入れるときは**
**コピー＆ペーストで貼り付けず**
**セルに直接、入力する形をとりましょう。**

# おわり
zshの見た目を良い感じにした

# はじめに
MacOS Catalinaから標準となった`zsh`ですが、デフォルトのテーマでは殆ど色がなく無機質な感じがしますよね。
<img width="573" alt="スクリーンショット 2020-05-13 20.21.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/90164762-d71f-e38b-ad95-a525eaa6bce1.png">
また、プロンプトにはユーザー名やPC名ではなく、作業ディレクトリのフルパスやGitブランチ名を表示させたいです。
そんな中で、見た目をお洒落にでき、かつフルパスやGitブランチ名を表示させることができる`Powerline`というライブラリを見つけました。

お洒落なソフトウェアエンジニアの皆さんは是非ターミナルの見た目もお洒落にしていきましょう(ちなみに私自身はお洒落には無頓着です...)。

# 前提
- 筆者の環境はMacOS 10.15.4です。
- コマンドラインで`git`を使用します。
- iTerm2を使用することもできますが、今回はTerminal.appで設定します。
- 本記事では、zshの設定フレームワークである[Prezto](https://github.com/sorin-ionescu/prezto)を用いて、zshに`Powerline`を適用していきます。

# 手順

1. Preztoのリポジトリをクローンします。

```:terminal
$ git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
```
2\. (あれば)既存の設定ファイルを`zsh_orig`ディレクトリに移動します。

```:terminal
$ mkdir zsh_orig && mv zshmv .zlogin .zlogout .zprofile .zshenv .zshrc zsh_orig
```
3\. Preztoの各種設定ファイルを作成します。

```:terminal
setopt EXTENDED_GLOB
for rcfile in "${ZDOTDIR:-$HOME}"/.zprezto/runcoms/^README.md(.N); do
  ln -s "$rcfile" "${ZDOTDIR:-$HOME}/.${rcfile:t}"
done
```

**注意**
手順2で`zsh_orig`に移動したファイルの設定値を使いたい場合は、ここで新たに作成された各ファイルに追記します。`.zshrc`はそのまま上書きしてしまっても良いですが、その際は以下を追記してください。

```vim:.zshrc
source "${ZDOTDIR:-$HOME}/.zprezto/init.zsh"
```

4\. Zshを再起動するとPreztoのテーマが適用されています。下記のコマンドでテーマをPowerlineに設定します。

```:terminal
$ prompt powerline
```

5\. この状態でプロンプトが文字化けしてしまっている場合は、Powerline Fontのインストールが必要です。
今回は`Ricty for Powerline`を使用することとします。
以下のコマンドでインストールできます。

```:terminal
$ brew tap sanemat/font
$ brew install ricty --with-powerline
$ cp -f /usr/local/Cellar/ricty/4.0.1/share/fonts/Ricty*.ttf ~/Library/Fonts/
# バージョン名の4.0.1は適宜変更
$ fc-cache -vf
```

6\. インストールが完了したら、
`ターミナル > 環境設定 > プロファイル > フォント`
から、フォントを
`Ricty Regular for Powerline`
に設定します。
<img width="429" alt="スクリーンショット 2020-05-13 21.12.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/41ef1d6e-1294-88e7-77b5-b162b0b006aa.png">

7\. Hello Powerline Shell! 
プロンプトに良い感じでフルパスやgitのブランチ名が表示されています。
<img width="577" alt="スクリーンショット 2020-05-13 21.03.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189802/45a29312-5076-90e3-7e93-136cd91219a0.png">

8\. テーマの永続化

この状態では再起動するとテーマが初期化してしまうので、
`~/.zprestorc`の`zstyle :prezto:module:prompt theme`
で始まる行を以下のように編集します.

```vim:~/.zpreztorc
zstyle ':prezto:module:prompt' theme 'powerline'
```
`source`コマンドで反映します。

```
$ source ~/.zpreztorc
```

# 参考

https://qiita.com/kinchiki/items/57e9391128d07819c321

https://qiita.com/park-jh/items/3c5b9b4aa5619a3631b3
Oracle Database 19cがRHEL/Oracle Linux 8でサーティファイされたよ

# 19cがRHEL/Oracle Linux 8でサーティファイ
Mike Dietrichのブログによると、RHEL/Oracle Linux 8でOracle Database 19cがサーティファイされたようだ。

* [Oracle Database 19c is certified on OL8 and RHEL8](https://mikedietrichde.com/2020/05/11/oracle-database-19c-is-certified-on-ol8-and-rhel8/)

詳しくはMikeのブログを見てほしいけれど、19.7以降のRU（Release Update）でサポート。

# サポート期間を長くするには
<font color="blue">Oracle Databaseを長く使うならばターミナルリリースのOracle Database 19c。
7系Linux OSのサポート期限は2024年までだから、いまから導入するなら8系を使いたい。</font>

**参考：Linuxのサポート期間**
いずれもアップデートが提供されるサポート期間は2024年6月（RHEL7）or7月（OL7）まで。6系が延長されたように、最終的にどうなるかわからないけど。

* [PDF: Lifetime Support Policy:Coverage for Oracle Linux and Oracle VM](https://www.oracle.com/a/ocom/docs/elsp-lifetime-069338.pdf)
* [RED HAT ENTERPRISE LINUX 7 の延長サポート（ELS）について](https://redhat.sios.jp/red-hat-enterprise-linux/rhel7_els/)

# こっそり出ていたOracle Linux 8向けUEK

Oracle Linux 8を使っている人は少ないと思うけれど、実は最近までOracle Linux 8向けUEK（Unbreakable Enterprise Kernel）はリリースされていなかった。5月6にアナウンスがあったばかり。

* [2020/05/06 Announcing the release of Oracle Linux 8 Update 2](https://blogs.oracle.com/linux/announcing-the-release-of-oracle-linux-8-update-2)

# 7系と8系の違い

8系で心配になるのは7系との違い。6と7では基本コマンドが大幅に変わって戸惑ったけれど、7と8では違いは少ない。

**「6系と7系の違い」>>「7系と8系の違い」**

実際のところメジャーアップデートなので違いはある。だけれど理解する必要があるのはApplication Streamという新しいリポジトリ管理方式かな。

詳しくは、このあたりをご覧あれ。

* [赤帽エンジニアブログ Red Hat Enterprise Linux 8 リリース!](https://rheb.hatenablog.com/entry/rhel8ga)
* [RHEL 8 の導入における検討事項](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html-single/considerations_in_adopting_rhel_8/index)
* [Red Hat Enterprise Linux 8についておさらいするよ。](https://tech-lab.sios.jp/archives/15045)
* [Red Hat Enterprise Linux 8 新機能をわかりやすく解説【RHEL8】](https://hackers-high.com/linux/rhel8-new-features/)
本番環境でローカルで指定していたフォントが使用できない時の対処法

アプリをRails で開発して1ヶ月経ち、デプロイして本番環境でどんなふうに動くのかを確かめている時に、フォントが適用されず半日くらい潰れてしまったので備忘録として書きます。

使用している技術はRuby,Rails, EC2, Nginx,Puma
WebサーバーにNginx　　アプリケーションサーバーにPuma

Capistranoを使ってデプロイしている。（まだ使い始めてから１日なので、理解が浅いが簡単にデプロイできて感動している）

```ターミナル
$ rails -v
Rails 5.2.3
```
```ターミナル
$ ruby -v
ruby 2.5.7
```

クロームのブラウザで検証を見ると、/assets/soft.ttfがnot foundと言っていた。 

フォントファイルが見つからないと

ターミナルでログを確認

```ターミナル
$ sudo tail -f /var/log/nginx/access.log
```

すると

```
"GET /assets/soft.ttf HTTP/1.1" 404 555
```
こちらも見つからないというログがあった。

ローカル環境ではapp/assets/fontsの中にsoft.ttfを入れていたのだが

本番環境だとassetsの下のjavascripts,images,stylesheetsしか読みに行ってくれないみたい（現時点ではこの認識）

なのでEC２上でcpコマンドでローカルのfontsディレクトリの中のfontファイルをEC2にコピーしてくれば良いと考え

ターミナルでEC2にログインして

```
$ ssh -i ~/.ssh/〜〜〜〜ここにはAWSの鍵とユーザー名とIPアドレス〜〜〜
```

自分のアプリにいき

```
$ cp app/assets/fonts/* public/assets
```

本番環境ではpublicの下にassetsになる

assets下にコピーして持ってきた。

それを確認

```
$ ls public/assets
```

```
soft-190a1a8da7a6e1b55869608ae297bbfa9f25f921ef63f86646eef087e47530eb.ttf
soft-190a1a8da7a6e1b55869608ae297bbfa9f25f921ef63f86646eef087e47530eb.ttf.gz
soft.ttf
```

コピーされている。

これでブラウザをリロードするとまだ見つからないとエラー


その原因はCapistranoを使ってデプロイしているので自分のアプリの直下にあるcurrrentにコピーしてこないといけなかった


ターミナルで自分のアプリ内で


```
$ sudo vi /etc/nginx/conf.d/アプリ名.conf
```

と入力すると

下の方に



```
 location ^~ /assets/ {
       　　　省略
         /、、、/.../.../アプリ名/current/public;
    }
```

assetsの下はアプリ名/current/publicになっている

Capistranoを使うとgithubに上がっているアプリを日付のついたフォルダにしまって、それにcurrentと名前をつけて常に最新版をデプロイするようにしてくれている？らしい。この辺りはまだ理解できていない

ターミナルで

```
$ ls -al
```

入力すると

 06:24 current -> /〇〇/〇〇/〇〇/releases/20200513062433

こんな感じのが見れる


```
$ ls -alt
```

すると

 06:24 20200513062433
 05:09 20200513050925
 01:44 20200513014420
12:48 20200512124820
12:42 20200512124154

デプロイした回数だけ出てきた

結局のところ
EC2で自分のアプリから

```
$ cd current
```


```
$ cp app/assets/fonts/* public/assets
```

このようにすることで問題が解決した。
掃き出し法(sympyで)Numerical Evaluation

(参考)[初投稿]質問・python 掃き出し法
https://qiita.com/snq7amf522dvzpjbwshb/items/5c267d8286857eda9a71
(参考)Numerical Evaluation
https://docs.sympy.org/latest/modules/evalf.html
(参考)sympy matrix element (fraction--> float)? how to
https://stackoverflow.com/questions/61752705/sympy-matrix-element-fraction-float-how-to
#pychramのsympyで
```
from sympy import *
print(Matrix([[3,1,1,2],[5,5,3,4],[2,0,6,2],[1,3,2,1]]).inv())
print(Matrix([[3,1,1,2],[5,5,3,4],[2,0,6,2],[1,3,2,1]]).inv().n(3))
# Matrix([[11/4, -7/4, -1/4, 2], [1/8, -1/8, -1/8, 1/2], [3/8, -3/8, 1/8, 1/2], [-31/8, 23/8, 3/8, -7/2]])
# Matrix([[2.75, -1.75, -0.250, 2.00], [0.125, -0.125, -0.125, 0.500], [0.375, -0.375, 0.125, 0.500], [-3.88, 2.88, 0.375, -3.50]])
```
#SympyOnlineで
https://live.sympy.org/
(入力)
Matrix([[3,1,1,2],[5,5,3,4],[2,0,6,2],[1,3,2,1]]).inv().n(3)
print(Matrix([[3,1,1,2],[5,5,3,4],[2,0,6,2],[1,3,2,1]]).inv().n(3))
(結果)
省略
Matrix([[2.75, -1.75, -0.250, 2.00], [0.125, -0.125, -0.125, 0.500], [0.375, -0.375, 0.125, 0.500], [-3.88, 2.88, 0.375, -3.50]])
vue/max-attributes-per-lineがprettierでうまくフォーマットされなかった

Vue.js を eslint とprettierを使って開発してたらフォーマットがうまくいかなかったので解決策と設定をメモ
エディタはvscode

## 問題
eslint-plugin-vueのルール[max-attributes-per-line](https://eslint.vuejs.org/rules/max-attributes-per-line.html)(１行あたり属性値の最大数を制限するルール）をprettierがうまくフォーマットしてくれなかった

## 解決
issueのコメントに対策があった
https://github.com/prettier/eslint-plugin-prettier/issues/94

https://github.com/prettier/eslint-plugin-prettier/issues/94#issuecomment-438781791

結局、属性値の最大数を増やして対応が良さそう
複数の属性値が許可されてしまうが、１行あたりの文字数の制限超えたらよしなに改行してくれるので酷くならないよねって感じ
根本的な解決ではないけど、それで良いやと思ったので設定を変える



## .eslintrc.json (落ち着いたやつ)
```json
{
  "env": {
    "browser": true,
    "es6": true,
    "node": true
  },
  "parser": "vue-eslint-parser",
  "parserOptions": {
    "parser": "babel-eslint",
    "ecmaVersion": 2020,
    "sourceType": "module"
  },
  "plugins": [
    "vue",
    "prettier"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:vue/recommended",
    "plugin:prettier/recommended",
    "prettier/vue"
  ],
  "rules": {
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true,
        "htmlWhitespaceSensitivity": "ignore"
      }
    ],
    "vue/max-attributes-per-line": [
      "error",
      {
        "singleline": 5,
        "multiline": {
          "max": 1,
          "allowFirstLine": false
        }
      }
    ]
  }
}
```

## その他
vscodeの拡張として入れてるprettierがフォーマットしてたり、veturがフォーマットしてた？のでvscodeの設定も少しいじった
（いじりすぎて迷子になったので後で見直す）
BigQuery Web UI のキーボードショートカットメモ

## 公式

公式ドキュメントはこちら。
https://cloud.google.com/bigquery/docs/bigquery-web-ui?hl=ja#keyboard_shortcuts

## ドキュメントされていないものも

こちらにいくつかまとまっています。

[[BigQuery]WebUI上のキーボードショートカット集 - Qiita](https://qiita.com/hidetoshi_n_cograph/items/6d2a300421cc62976f30)

## さらに見つけたもの

いくつか見つけました。

|キーの組み合わせ（Mac OS）|アクション|
|:--|:--|
|cmd + X（非選択状態で）|カーソル行をカット|
|cmd + C（非選択状態で）|カーソル行をコピー|
|cmd + D|カーソル行を削除|
|tab（選択状態で）|インデント|
|shift + tab（選択状態で）|逆インデント|

## 番外

~~option + クリックで矩形選択ができます！~~
いつのまにか、option + shift + クリックに変わっていました。（2023-03-09追記）


<img width="241" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15117/50ce3fab-d3d1-130a-3d70-109265804d92.png">
PythonのBeautifulSoupによるWebサイトのスクレイピング

# この記事について
以前Qiitaにも書いたが、[JavaでWebサイトのスクレイピングを行うコード](https://qiita.com/hiro0236/items/26414f5bee1999ff9199)を書いていたのだが
今読み返してみると、要件は満たしているもののコードの内容がきれいとは言い難く
見ていて恥ずかしくなってしまったので、Pythonで書き直すことにしたのでメモ。

Qiita内にも類似の記事は多数あるが、覚書ということで。

# BeautifulSoupについて
Javaによるスクレイピングを行う際には[jsoup](https://jsoup.org/)というライブラリを使用していたが
今回は**BeautifulSoup**を使用する。

BeautifulSoupはPythonのスクレイピング用のライブラリである。
CSSセレクタを用いてページ内の要素を抽出できるので、ページ内の欲しいデータだけを抽出するのに便利である。
公式：https://www.crummy.com/software/BeautifulSoup/bs4/doc/

Pythonのライブラリなので、導入はpipで行う。

```
pip install beautifulsoup4
```

# 使用例
以前書いた記事と同様に、以下のページから「お知らせ」の日付・タイトル・URLを抽出したい。

```
<body> 
 <div class="section"> 
  <div class="block"> 
   <dl>
    <dt>2019.08.04</dt> 
    <dd>
     <a href="http://www.example.com/notice/0003.html">お知らせ その3</a>
    </dd> 
    <dt>2019.08.03</dt> 
    <dd>
     <a href="http://www.example.com/notice/0002.html">お知らせ その2</a>
    </dd> 
    <dt>2019.08.02</dt> 
    <dd>
     <a href="http://www.example.com/notice/0001.html">お知らせ その1</a>
    </dd> 
   </dl>
  </div>
 </div>
</body>
```

以下のコードにてお知らせの抽出を行い、printする。

```python:scraping.py
# -*- coding: utf-8 -*-
import requests
import sys
from bs4 import BeautifulSoup
from datetime import datetime as d

def main():

    print("Scraping Program Start")

    # 指定のURLに対してGETリクエストを送信し、ページの内容を取得
    res=requests.get('http://www.example.com/news.html')

    # 取得したHTMLページをBeautifulSoupオブジェクトにパース
    soup = BeautifulSoup(res.text, "html.parser")

    # ページ内のblockクラスの要素を丸ごと抽出
    block = soup.find(class_="block")

    # blockクラス内のdt要素（日付）とdd要素を抽出
    dt = block.find_all("dt")
    dd = block.find_all("dd")

    if(len(dt) != len(dd)):
        print("ERROR! The number of DTs and DDs didn't match up.")
        print("Scraping Program Abend")
        sys.exit(1)

    newsList = []

    for i in range(len(dt)):
        try:
            date = dt[i].text
            title = dd[i].find("a")
            url = dd[i].find("a").attrs['href']

            print("Got a news. Date:" + date +", title:" + title.string + ", url:" + url)

        except:
            print("ERROR! Couldn't get a news.")
            pass

    print("Scraping Program End")

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

上記コードを実行した際の期待結果は以下。

```
Scraping Program Start
Got a news. Date:2019.08.04, title:お知らせ その3, url:http://www.example.com/notice/0003.html
Got a news. Date:2019.08.03, title:お知らせ その2, url:http://www.example.com/notice/0002.html
Got a news. Date:2019.08.04, title:お知らせ その1, url:http://www.example.com/notice/0001.html
Scraping Program End
```

# おわりに
前回JavaのSpring Bootで書いた時と比べて、Pythonだとコーディング量が圧倒的に少なく済むのがいいですね。
内容の間違い等あれば、ご指摘願います。
【Ruby on Rails】始業時間と終業時間を入力したときに、自動計算にて、時間の差分を表示したいです。

'''Ruby
class TasksController < ApplicationController
    
    def index
        @tasks = Task.all
    end
    

'''Ruby

<table border="1">
<tr>
    <th>Date</th>
    <th>Task</th>
    <th>Description</th>
    <th>Start</th>
    <th>Finish</th>
    <th>result</th>
    </tr>
<% @tasks. each do |task| %>
<div class="contents_task" >
<tr>
    <th><%= task.daily %></th>
    <th><%= task.name %></th>
    <th><%= task.description %></th>
    <th><%= l task.start %></th>
    <th><%= l task.finish %></th>
    <th><%= task.result %></th>
<th>
<div class="more_list">
    <li>
    <%= link_to "Edit","/tasks/#{task.id}/edit", method: :get %>
    </li>
    <li>
    <%= link_to "Delete","/tasks/#{task.id}", method: :delete %>
    </li>
</th>
</div>
</div>
</tr>
</div>
<% end %>
</table>


今は手打ちしているため、resultカラムに時間の差分を入力してDBに保存しています。
resultカラムにstartカラムとfinishカラムの差分を自動計算した値を格納するようにしたいです。

ご教授お願いいたします。
解いた問題①

#問題1
[A - Infinite Coins](https://atcoder.jp/contests/abc088/tasks/abc088_a)

```c++
#include <iostream>
#include <string>
using namespace std;
 
int main(){
  int N,A ;
  cin >> N >> A;
  if(N%500<=A) cout << "Yes" <<endl;
  else cout << "No" << endl;
}

```

#問題2
[A - Already 2018](https://atcoder.jp/contests/abc085/tasks/abc085_a)

```cpp

#include <iostream>
#include <string>
using namespace std;

int main(){
  string s;
  cin >> s;
  s[3] = '8';
  cout << s << endl;
}
```

#問題3
[B - i18n](https://atcoder.jp/contests/abc069/tasks/abc069_b)
std::to_string()で数値を文字列に変換できる。
string.length()で文字列の長さを取得できる。

```cpp

#include <iostream>
#include <string>
using namespace std;

int main(){
  string s;
  cin >> s;
  int length = s.length();
  string ans = s[0] + std::to_string(length-2) + s[length-1];
  cout << ans << endl;
}
```

#問題4
[B - Shift only](https://atcoder.jp/contests/abc081/tasks/abc081_b)

```cpp
#include <iostream>
#include <string>
using namespace std;

int main(){
  int N;
  int A[200];
  cin >> N;
  for(int i=0 ; i<N ; ++i) cin >> A[i];
  int res = 0;
  
  while(true){
    
    bool exist_odd =false;
    
    for(int i=0;i<N;++i){
      if(A[i]%2 != 0) exist_odd = true;
    }
    
    if(exist_odd) break;
    
    for(int i=0;i<N;++i) A[i] /= 2;
    
    ++res;
  }
  
  cout << res <<endl;
}

```

#問題5
[B - Maximum Difference](https://atcoder.jp/contests/abc102/tasks/abc102_b)

```cpp
include <iostream>
using namespace std;
 
int main(){
  int N;
  long long int A[201];
  long long int max=0;
  long long int min=1000000000;
  cin >> N;
  for(int i=0; i<N ;++i){
    cin >> A[i];
    if(A[i]>max) max=A[i];
    if(A[i]<min) min=A[i];
  }
  cout << max-min <<endl;
}

```

#問題6
[B - OddString](https://atcoder.jp/contests/abc072/tasks/abc072_b)

```cpp
#include<iostream>
#include<string>
using namespace std;

int main(){
  string s;
  cin >> s;
  string ans;
  for(int i=0;i<s.length();++i){
    if(i%2==0) ans+=s[i];
  }
  cout << ans << endl;
}
```

#問題7
[B - Coins](https://atcoder.jp/contests/abc087/tasks/abc087_b)

```cpp


```

あ
ファイルの内容を複数行ごとにまとめて1行にしたい

# はじめに
普段あまりLinuxコマンドを利用しないのですが、ワンライナーでテキストを複数行ごとにまとめて1行にできたのでメモ

# ユースケース

ファイルが何らかの事情によりこんな感じで複数行になってしまっているのを

```src.txt
header1,
header2,
header3,
dataA1,
dataA2,
dataA3,
dataB1,
dataB2,
dataB3,
```

こうしたい場合のTips

```dst.txt
header1,header2,header3,
dataA1,dataA2,dataA3,
dataB1,dataB2,dataB3,
```

# コマンド

```
cat src.txt | awk '{if(NR%3)ORS="";else ORS="\n";print}' > dst.txt
```

# 解説
catコマンドを利用しsrc.txtの内容を出力し、それをパイプを利用してawkの入力とする。
awkのコマンドにより3の倍数の時だけ改行文字を挿入し、それ以外の場合には改行文字を入れずに出力する。それをdst.txtに出力する。

# 補足
Windows環境で作成されたファイルの場合は改行コードに\rが入っているため、思い通りにいかない。
その場合は以下のようにtrで\rを削除した上で実行すればOK

```
tr -d \\r < src.txt | awk '{if(NR%3)ORS="";else ORS="\n";print}' > dst.txt
```
CentOS7でIPを固定した話（GUI）

社内で使うWebアプリケーションをCentOSに作り、IPアドレスを固定した話です。

# 1. 上司「固定IPもらってきますね」
すべてはこの一言からはじまった。

オレ「えーと…Linuxどころか、Windowsでもやったことないんだけど。。。」

とりあえず、固定IPを待つことに。

# 2. 上司「固定IPもらってきました！」
渡されたメモ用紙には、こう書かれていた。

```
IP: 172.16.**.**
サブネットマスク: 255.255.254.0
DNS: 172.16.*.* 
```

サブネットマスクとは？
とりあえずググって見る。

# 3. 参考になりそうなページを見つけた

こちらのページを参考にさせていただきました。
[CentOS 7～8 ネットワーク設定、及び IPv6 無効化](https://server.etutsplus.com/centos-7-network-configuration/)

1.コマンドラインで以下を実行

```bash

nmtui
```
2.GUIが立ち上がるので、IPv4を設定

サブネットマスクの使い方がわかりませんでしたが、どうやらIPアドレスの後ろに書くやつらしいです。
[サブネットマスク計算（IPv4)](https://note.cman.jp/network/subnetmask.cgi)

255.255.254.0 → 23 らしいので、IPは 172.16.**.**/23 に設定。

ゲートウェイは、IPの最後を1にしてみました。
172.16.**.1

DNSはもらったものをそのまま設定。

3.戻って、「接続をアクティベートする」を選んで実行

4.コマンドラインで以下を実行し、IPアドレスが変わったか確認

```bash

ip a
```
expoで他端末からmetro bundlerにアクセス

久し振りにネタが出来たので書きます。

### 趣旨
expoでスマホアプリを作る事になったのですが、
ある程度できて他の人に確認をして貰った時に
エラーが起きたのはいいけどエラー内容が全く分かりませんでした。
アプリはapkで渡していてブラックボックスでした。

という事でその人とも見える形でなんとかしたくて
二人ともアクセス可能なlinuxサーバを立ててそこで
metro bundlerを起動してwebで確認しよう、
っていうのが今回の趣旨です。

通常だとexpoの開発は自分のPCでexpo startして
動かしながら状態を確認しますが、
今回の場合はexpo開発者ではない人にも状況が
確認できるようにする必要がありました。
が、中々そういう事をしようとする人がいないらしく
ネットで調べても答えを見付けるのにひどく苦労しました。

### 結論
まず先に結論を書きます。

expo start
の前に
export EXPO_DEVTOOLS_LISTEN_ADDRESS=linux機のIP
とします。

デフォルト設定だと19002ポートは**ローカルホストからしかつながりません。**
ここがハマりポイントです。
つまり各自のPCではなく二人が同時にアクセスできるように共通のサーバで
起動した場合デフォルトではそのサーバ内からしか19002につながらないんです。

これはlsof -i:19002で状況の確認ができます。
デフォルトの起動方法だとlocalhost:19002 (LISTEN)と出てきます。
EXPO_DEVTOOLS_LISTEN_ADDRESSを設定するとlsofの結果が
*:19002 (LISTEN)に変わります。

ちなみにこの設定が分かったのはDOCKER経由でやろうとした人が
同じようにハマってdockerファイルにこう書けば解決するよ！
みたいな記事を見たからです。
その設定だとEXPO_DEVTOOLS_LISTEN_ADDRESSは実機のIPではなく
0.0.0.0を設定してました。
なので「linux機のIP」と書いていた部分はもしかしたら0.0.0.0で
いけるのかもしれません。

### 以下、試行錯誤
#### 1. enforce問題
最初にデフォルトの状態でexpo startして自分のPCからアクセスした時に
19001も19002も接続できませんでした。
これは色々調べた結果、CentOSだったのでenforceの問題っていうのが
調べたらわかりました。
（expoに限った問題じゃないのでexpo以外で調べて出てきました）

とりあえず解除して動かしてみたところ19001は接続できるようになりました。
が、19002が接続できません。

#### 2. websocket問題
19002に直接接続できないならnginxでリバプロ立てればいけるんじゃないか？
って事で試しました。
結果はダメでした。

リバプロ自体はちゃんと機能しています。
ただ、真黒な画面が表示されるだけでそこから進展がありません。
chromeの開発ツールで通信を眺めつつ調べているとどうもwebsocketを
使っているんじゃないか？ってとこに行きつきました。
という事でnginxでのwebsocket対応というのを調べてやってみましたが
やはり真黒な画面から進みませんでした。

これに関しては確証はなく推測になりますが
websocketだと入口だけリバプロが機能してるけど
websocket通信部分がnginx経由ではなく直結してしまってて
それでダメなんじゃないかな？って思いました。

もしかしたら最初に書いた結論と関係があるかもしれなくて
接続元がローカル以外を弾いてるけどwebsocketだと接続元が
自分のPCになってそれで弾かれるのかと。
でも、これを書いている時点で気付いたのですが仮にそうだとすると
nginxの設定で実はイケてたのかもしれません。
nginxの設定は「proxy_set_header Host $host;」としていました。
この$hostがサーバ自身にしていればもしかしたらリバプロで
イケていたのかもしれません。
が、結局nginxダメだこりゃってなってリバプロ方法を捨てました。

---
他にもはまってた気がするけど大きなところではこれくらいですね。
一番のハマり処はなんといっても**ローカルからしかつながらない！**ですね。
Ubuntu24で爆速でプリントサーバ立てて iPhone とか Chromebook でも印刷する

#人生でもうプリンタなんて設定する事も無かろう、
と思ってたのになぜか居なくなりませんよね。紙じゃないと死んじゃう人。

レガシーオブレガシーだなと思いつつ、
クソほど使いづらいWindowsサーバで疲弊してる同僚たちを救うために
最小の手間でプリントサーバを立ててみました。

以前、Ubuntu18で書いた記事なのですがありがたいことに定期的にLGTMを頂きますので、最新LTSで再検証しました。
ubuntu24がセットアップされた状態から、ざくざく行きます。

大本はこちらを参考にさせて頂きました。
https://www.linuxbabe.com/ubuntu/set-up-cups-print-server-ubuntu-bonjour-ipp-samba-airprint


# いつも最初にやること
```bash
sudo apt update
sudo apt upgrade
```

#先に avahi (mDNS) の設定をしておく。
```
# ネットワーク上のサーバやプリンタを勝手に見つけてくれる便利なデーモン。iOSやAndroidで自動的に出てくる
sudo apt install -y avahi-daemon
sudo systemctl start avahi-daemon
sudo systemctl enable avahi-daemon
sudo ufw allow 5353/udp
```

# CUPS 入れる
```bash
# CUPS 入れる
sudo apt install -y cups
# CUPS 起動する
sudo systemctl start cups
# CUPS 毎回起動するように設定
sudo systemctl enable cups
# CUPS 動いてるの確認
sudo systemctl status cups
```

# CUPS 設定弄る
```
# nano で CUPS設定ファイル修正 (nano の終了は ctrl-x)
sudo nano /etc/cups/cupsd.conf
```

/etc/cups/cupsd.confの中を４箇所変える：

1:

```
16行目辺り
# Only listen for connections from the local machine.
Listen localhost:631

Listen localhost:631 を
Port 631 に
```

2:

```
19行目 あたり
# Show shared printers on the local network.
Browsing Off

Browsing Off を
Browsing On に

# 2025 追記 Ubuntu24だと表記が変わってました
Browsing No を
Browsing Yes に

```

3, 4 :

```
29行目、
35行目あたり (２回・同内容) / Ubuntu24 だと4回くらい

<Location />
  Order allow,deny
</Location>

を、

<Location />
  Order allow,deny
  Allow @LOCAL
</Location>

に

他の部分もこんな感じで
# Restrict access to log files...
<Location /admin/log>
  AuthType Default
  Require user @SYSTEM
  Order allow,deny
  Allow @LOCAL
</Location>

```

これが出来たら「ctrl - x」でnanoを終了する。

CUPS再起動して、ファイヤウォール開く：

```
# CUPS 再起動
sudo systemctl restart cups

# ポート631をLANに開放
sudo ufw allow in from 192.168.0.0/24 to any port 631
# 192.168.0.0 はご自分の環境に合わせてください
```

http://サーバ名:631
をブラウザで開くと、cupsの設定画面が開くので、後は画面の指示にしたがって
プリンタを追加する


# ここでつまづいた
以下のグループにユーザを追加しておかないとフォビドゥンされてします。ubuntuだけみたい

```
# これちょっとハマりポイント。 
# WEBから "add printer"　した時に「forbidden」が出る。

sudo usermod -a -G lpadmin taiyodayo

# ubuntuだと、プリンタ管理用の特権グループが最初から作ってある。
# centosとかだとまた違う流儀みたい
```

# 色んなガイドに「Linuxマシンにプリンタドライバインストール」と書いてるが
必要無い。
プリンタ追加時に、webUIから直接PPDファイル上げたほうが早いと思う。
非公式だが、Mac用のドライバからPPD持ってくればだいたい動く(同じCUPS用なので)


# Macの方は、これ叩くと既にCUPSが稼働してる所が覗ける
```
cupsctl WebInterface=yes
```
これ叩いてから http://localhost:631

「既存プリンタの設定」が覗けるのでものすごく参考になります。
設定をコピペするだけで動くと思われます。
カタリナは cups 2.2.7、ubuntu18.04 では 2.2.9 がデフォルトでした。


# Ubuntu24でも検証したので追記だよ
ありがたいことに結構な方から今も見て頂けているようで最新LTSの ubuntu24 でも検証しました！

上記に一部表記が変わったくらいで、ほぼそのまま動きますね
CUPS は `2.4.7` に上がって、UIがダークモードに対応していました。笑

なんかもう、以前より更に進化したのかポチポチプリンタ選ぶだけで、勝手にドライバのインストールまで進んでくれて
もうほぼほぼ全自動で認識してくれましたね。

![Screenshot 2025-06-03 at 20.54.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255842/a4ff6fbd-d4e2-4718-83b8-94a952ad4321.png)

カンタン過ぎるやろ！良い時代ですねー

![IMG_6268.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255842/3905146b-1c10-44b1-b512-48ccc97b41b3.jpeg)
active_interaction での attributes の i18n 

```ruby
def create
  user = Users::Create.run(params.fetch(:user, {}))
  if user.valid?
    ...
  else
    render json: { message: user.errors.full_messages.to_sentence }, status: :unprocessable_entity
  end
end
```

`Users::Create` という `ActiveInteraction::Base` 継承したクラスを定義している場合、以下のように書くと attributes を翻訳できます。


```yml:config/locals/interactions/user.yml
ja:
  active_interaction:
    attributes:
      users/create: # Users::Create と合わせる
        email: メールアドレス
        password: パスワード
```
【git 初心者】cloneしてきたgithub repositoryに.gitmoduleが入っている場合の対処法

# 概要
- クローンしてきたレポジトリ内のPipfileから`pipenv install`を試みたがエラーになった．
- 指定したパスに実行コマンドがないとのこと
- .gitmoduleという見たことないファイルがあった
- 調べたらsubmoduleといって，レポジトリ内で別のgitレポジトリを使う場合に記述があるらしい
- .gitmoduleから，submoduleのパスの中身をクローンする必要があったのだがコマンドがあんまり載ってなかったからここにメモ

###.gitmoduleの中身の例

```config
[submodule "{path_to_rep}/{rep_name}"]
    path = {path_to_rep}/{rep_name}
    url = https://{rep_name}.git
```

`{rep_name}`: submoduleのレポジトリ名
`{path_to_rep}/{rep_name}`: submoduleのパス ここが最初にクローンしてきた状態では空のフォルダになっている

# 対処法

### submoduleをクローンする

```shell
git submodule init
git submodule update
```

`{path_to_rep}/{rep_name}`の中を確認すると，サブモジュールのレポジトリがクローンされていることがわかる．

ちなみに，メインのレポジトリの変更にはならないので，コミットの差分はありません．

# 感想
複数レポジトリつなげたの初めてだったので，すこし戸惑った．
こんなの当たり前だろ！っていじめないでください m(_ _)m
一部Android端末でeventからlayerXを取得できない

# 経緯
HTML5のcanvasを使用してブラウザから操作できるお絵かきツールを作成中、iOS端末のSafariでは取得できた座標情報（layerX,layerY）が**undefined**になってしまい、動作しないことを確認

以下のようなイベントリスナーでユーザのタッチイベントを取得していたが、iOS/SafariとAndroid/Chromeでは取得するイベント情報が異なっている

```canvas.js
canvas.addEventListener('touchmove', (e) => {
    drawing(e.layerX, e.layerY);
});
```
# 原因はChromeが参照するTouchイベントにlayerX、layerYの座標位置が存在しない
ChromeとiOSでは取得するイベントが以下のように異なっていた。

・Chrome：Touchイベント
・iOS：Mouseイベント

# 対策
以下のように参照するイベントをハンドリングすることでiOSおよびChromeの双方で座標情報を正しく取得することが可能

```canvas.js
canvas.addEventListener('touchmove', (e) => {
  if (e.layerX === undefined) {
    drawing(e.touches[0].pageX - canvas.offsetLeft, e.touches[0].pageY - canvas.offsetTop);
  } else{
    drawing(e.layerX, e.layerY);
  }
});
```

基本的に**e.touches[0]**でカレントのイベント情報を取得できるが、処理をしたいイベントを指定する場合には別途処理が必要。
Dockerでつまづいた点

#前提
Docker導入済み
Mac

#本題
dockerを本番環境で構築し、Laravelの.envファイルを作成する時にエラーが出たので備忘録として書きます。

```
ubuntu@ip-172-31-40-123:~$ sudo su 
root@ip-172-31-40-123:/home/ubuntu/book-store/laradock# docker-compose exec workspace bash
root@eee10544329b:/var/www# cp .env.example .env

#エラー発生!!

```

lsでリストの確認

```
root@ip-172-31-40-123:/home/ubuntu/book-store# ls
laradock  book-store
```

```laradock/.env
#変更前
APP_CODE_PATH_HOST=../laravel

#変更後
APP_CODE_PATH_HOST=../book-store
```

初歩的なミスでした。。。