OmniAICreator/Qiita-1.07M huggingface dataset:
【Vue.js】router-linkのactive-class・exactの使い方

## はじめに
仕事で使う事になったので1からVue.jsについて学んだ。
ちゃんと覚えておかないとまずそうな事を備忘録として1つ1つ残しておく。

## router-linkのactive-class属性とexact属性
### router-linkとは
vue-routerを使う際に、URLで画面の内容を切り替える時に使うタグでSPAを構築する上では必須の機能。

### router-linkのactive-class属性
`active-class`属性を使うと、router-linkの`to`属性で指定しているURLパスに合致している時に、`active-class`で定義しているclass属性を要素に付与する事ができる。
実際に、以下の動画のようにリンクがアクティブな時（URLパスに合致する時）にclass属性が付与されている事が分かる。
![ezgif.com-gif-maker (26).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/275028e2-e076-02d0-1a42-1df76de01dc9.gif)
動画のソースコードは以下。

```vue:App.vue
<template>
  <div>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container-fluid">
        <!-- 省略 -->
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav">
            <li class="nav-item">
              <router-link
                class="nav-link"
                to="/"
                active-class="link--active"
                >Home
              </router-link>
            </li>
            <li class="nav-item">
              <router-link
                class="nav-link"
                to="/users"
                active-class="link--active"
                >Users
              </router-link>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    <main class="container-sm">
      <router-view></router-view>
    </main>
  </div>
</template>

<style scoped>
.link--active {
  font-size: 20px;
}
</style>
```

ただ、上記では**User**を選択している時に、**Home**も同じく`active-class`に指定しているクラスが要素に付与されてしまっている事が分かる。
これは、URLパスに合致というのが**それを含む**という意味であり、今回で言えば`/users`はHomeのrouter-linkである`/`を含んでいるので、Homeの要素のようにも`link--active`が付与されてしまっている。
これを完全に一致している時、つまり、URLパスが`/`の時だけ、`/users`の時だけ、という厳密に判定させるには`exact`属性を使う。

### exact属性
`exact`属性を`router-link`に付与すると以下のようになり、URLパスに厳密に(完全に)一致している時のみ`active-class`で定義しているクラスが要素に付与されるようにできる。
![ezgif.com-gif-maker (27).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/3a4ae140-b40c-939d-963b-f9d6e63134ee.gif)
動画のソースコードは以下。

```vue:App.vue
<template>
  <div>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
      <div class="container-fluid">
        <!-- 省略 -->
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav">
            <li class="nav-item">
              <router-link
                class="nav-link"
                to="/"
                exact
                active-class="link--active"
                >Home
              </router-link>
            </li>
            <li class="nav-item">
              <router-link
                class="nav-link"
                to="/users"
                exact
                active-class="link--active"
                >Users
              </router-link>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    <main class="container-sm">
      <router-view></router-view>
    </main>
  </div>
</template>

<style scoped>
.link--active {
  font-size: 20px;
}
</style>
```

## Vue.jsの勉強メモ一覧記事へのリンク
Vue.jsについて勉強した際に書いた勉強メモ記事のリンクを集約した記事。

- https://qiita.com/yuta-katayama-23/items/dabefb59d16a83f1a1d4
学習記録(LPIC101)

６月３０日（水）
☆本日の目標☆
LPIC101合格に向けての学習を進める。

☆達成できたか☆
未達だが、少し前進！

☆未達成の場合、原因☆
今日はLPIC１０１に向けて、Linuxの学習を動画で進めました。
しかし、根本的な部分が理解できていないため、捗らない…
明日からは基礎の基礎の部分から理解していくべく、より初心者向けの書籍で学習していきます。

☆感想☆
今日は、AWS上に、EC2を立て(?)、Amazon Linuxが使える環境を整えることができました！
私のMacbookではVirtualBoxの中でLinuxが使えず、
思ったように実践することができていなかったため、少し前進です！

明日は、問題演習の解説を読んである程度理解できるレベルに少しでも早く到達することを目標に、Linuxの基礎の学習を進めていきます！



☆本日の気づき☆
シェル変数を学習している際、ある発見をして驚きました。
(中々理解ができず躓いているのですが、
変数とは、その時々によって変えられる、データを格納する入れ物の名前です。)

例えば、
INFILE="infile.txt"
といったように、
変数="名"
と値を代入しておくとき、
私は初め、
INFILE = "infile.txt"
といった具合で、いつものようにスペースをとって記述していました。
すると、そのようなコマンドが見つかりませんといった旨で返ってきます。
私は、前述のようにきちんとLinux環境でできていなかったので、そういうものかと思ってしまっていました。

しかし、
INFILE="infile.txt"
といったように、変数と=、""まで全てスペースを開けずに記述し実行すると…
なんと正常に代入ができました。
常識なのかもしれませんが、お恥ずかしながら初心者の私には今日一番の発見でした…!

結論、
※変数と="はくっつける！！
Node.jsのLinter, Formatter比較 2021

#はじめに
Node.jsでアプリ開発をするにあたり、2021年現在で使用するのが良さそうなLinter, Formatterについて調査しました。
2021/5/29時点での情報です。

# Linter, Formatter比較表
調査したLinter, Formatterは以下の４つです。
概要については、[こちらの記事](https://www.codegrid.net/articles/2018-eslint-1/)を参考にさせていただきました。
推奨は、調査結果から使うのが良さそうかどうか私が判断した項目です。

|項目名              |概要|npmダウンロード数|推奨|URL|
|:------------------|:------------------|:------------------|:------------------|:------------------|
|ESLint|・現在最も使用されている<br>・すべてのルールについて適用するかどうかを決められる<br>・自分のプロジェクトに合わせたルールを作れる|14,979,235|◎|https://eslint.org/|
|JSLint|・ESLint普及前に使われていた<br>・コーディング制約が厳しすぎた|20,003|×|https://www.jslint.com/|
|JSHint|・JSLintをフォークして作られた<br>・デフォルトのコーディング制約が緩くなり、設定ファイルベースでコーディング制約の調整が可能となった|405,339|×|https://jshint.com/|
|prettier|・コードフォーマッターに特化している<br>・ESLintなどと機能がかぶるが、より可読性の高いコード整形を行える|12,123,554|◎|https://prettier.io/|

# Linter, Formatterダウンロード数比較グラフ
参考サイト
https://www.npmtrends.com/eslint-vs-jshint-vs-jslint-vs-prettier

![linter_npmtrends.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/539406/93b59982-dff4-59de-ad73-04115f98e735.png)

# 結論
ESLintとprettierを、必要に応じて併用するなどして使うのが良さそうです。
【Rails】axiosでResponceHeaderに任意の値を取得できるように設定する【devise-token-auth】

<h2>概要</h2>
ReactとRailsAPIを使ったアプリで、devise-token-authをaxiosでアクセスしたときに取得できるheader情報を取得する方法について書きます。

devise-token-authでSignOutしたときに、SignInしたときの'access-token', 'uid','client'が必要になります。

しかし、CORSを使う場合defaultのままだと、上記値が取得できません。

なので、ResponceHeaderに'access-token', 'uid','client'の値が乗っかるように設定していきます。

<h2>実装方法</h2>
CORSに以下のコードを追加します。

```ruby:
expose: ['access-token', 'uid','client'],
```

実際に入れてみたのが以下

```ruby:CORS.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3001'

    resource '*',
      headers: :any,
      expose: ['access-token', 'uid','client'],
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      credentials: true
  end
end
```

<h2>参考</h2>

https://note.kiriukun.com/entry/20200303-axios-response-header-could-not-get

https://stackoverflow.com/questions/37897523/axios-get-access-to-response-header-fields

https://qiita.com/cyperaceae/items/a6e5ec7f0cdf89365e8c

https://qiita.com/tomokazu0112/items/5fdd6a51a84c520c45b5
301と302redirectの違い

現在学習中のApacheについて、少しでも記憶に残るように備忘録を作ります。

＃はじめに

開発環境

MAMP 


#Redirect

```
Redirect /apache/redirect-test https://google.com
```

上記のコードを、/apache/redirect-testの間のどこかの位置に作成した .htaccessファイルに書いておくと

URLに/apache/redirect-testと書くことによってgoogleのトップの検索画面に移動できます。

```
Redirect /apache/redirect-test /apache/
```

とすると、外部アクセスにはなりませんが、ローカルの/apacheのページに移動します。
Rewriteとは違い、必ずURLも変化します。

一般的に書くと

```
Redirect "パス(ここのパスを入力すると、右のアクセス先に移動する)" "アクセス先"

(ただし、このコードが、入力したパスの最中の.htaccessファイルに書かれてないとだめ)
```

みたいな感じですかね、、、

#301と302の違い

```
Redirect 302 /apache/redirect-test https://google.com
```
や、

```
Redirect 30１ /apache/redirect-test https://google.com
```
というふうに、リダイレクトの種類をURLの前に付け加えることができます。

・302 → 一度redirectで送信したものに関しても、アクセス先を変更するとちゃんと変更が反映される

・301　
→ 一度301redirectで送信したものに関しては、アクセス先がdisk cacheというブラウザキャッシュに保存される。その後、いくらアクセス先を変更しても、アクセス先は常にdisk cacheに保存された最初のアクセス先になる。よってサーバーのアクセス先の変更は反映されない。

#まとめ

Apache、自分にとっては史上最高に難しいです。
NTTドコモのIPv6シングルスタック化についての調査メモ

NTTドコモが2020年春からIPv6シングルスタック化を行うという発表があり、それにむけた対応を調べたのでそれのメモです。社内用に作った文章を少し整理したものです。
[プレスリリース（PDF）](https://www.nttdocomo.co.jp/binary/pdf/info/news_release/topics_210629_00.pdf)

# 確認用フローチャート
![Untitled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19807/f6018f35-8161-ce12-a9c1-67c8f0e29f28.jpeg)

## A: サービスがすでにIPv6化されている場合
サービスがすでにIPv6対応しているなら気にすることはありません。現在ドコモ回線はIPv4/IPv6デュアルスタック構成になっているので、これまで通りIPv6経由でのアクセスとなります。

## B: サービスはIPv6対応していないが、IPアドレスを直接使わずAレコードによるアクセスを行っている
これが最も一般的なタイプかと思います。アプリ内に埋め込まれたAPIエンドポイントがapi.example.comのように、Aレコード（ELBやCDNならCNAMEのことも）で指定されているケースです。この場合はネットワーク内のDNS64サーバでAレコードがIPv4-IPv6変換アドレスを返すAAAAレコードに変換され、NAT64経由で利用可能です。

## C: IPv4アドレスで直接アクセスしているが、Android 4.3以上あるいはWindows Vista以上である
一見動かないように見えますが、Pref64::/n Discoveryという機能によって、端末内部でIPv6アドレスに変換されます。このため接続できると思われます。

## D: IPv4アドレスで直接アクセスしていて、なおかつPref64::/n Discovery未対応端末である
この場合は、IPv6シングルスタック化すると通信できなくなります。AppleのOSは未対応のようです（未確認）。ただしiOSアプリ審査を行う環境はIPv6シングルスタック構成なので、アプリの場合はそもそも審査に通りません。ブラウザから利用する場合は影響を受ける可能性があります。

# 何が起きるのか
## 接続先をAレコードのみで指定している場合
ドコモのDNSサーバでIPv4-IPv6変換アドレス（擬似的なIPv6アドレス）に変換されるため、**現状通り利用できます。**

## 接続先をIPv4アドレスのみで指定している場合
擬似的なIPv6アドレスへ変換されないため、**通信できなくなりますが、実装によっては接続できることがあります。（実装依存なので動作検証時にはご注意ください）**
クライアントによっては、Pref64::/n Discoveryによりクライアント内でDNS64相当の処理を行います。この場合は利用可能です。

## 接続先をAAAAレコードで指定しているorIPv6アドレスで指定している場合
**現状通り利用できます**

# 変更点の概要
- 2022年春からNTTドコモ（ahamo含む、MVNO除く）の回線は端末にIPv6アドレスのみが設定されるようになる予定です。
- これにより、端末がIPv4ネットワークとは直接通信できなくなります。
- IPv4サーバと通信するときはドコモネットワーク内のNAT64/DNS64で変換されるため、端末から見ると擬似的にIPv6サーバとして扱われます。
- この仕様はiOSアプリの審査が行われるネットワークと同じなので、iOSアプリであればおそらく引き続き利用可能と思われます。
- 一方で、ウェブブラウザで利用するサービスかつ、クライアントからIPアドレスで直接通信している環境では動作しない可能性があります。

# 使われている技術要素
## NAT64
IPv6しか割り当てられていない端末がIPv4サーバと通信するための仕組み。ネットワークのGatewayでIPv6アドレスからIPv4アドレスにNATされるのでこう呼びます。

## DNS64
AレコードしかないレコードをAAAAレコードに変換する仕組みです。[RFC8215](https://www.rfc-editor.org/info/rfc8215)で規定されており、64:ff9b::からはじまるIPv6アドレスの中にIPv4アドレスが埋め込まれた形式です。たとえば192.0.2.100なら、64:ff9b::c000:264(64:ff9b::192.0.2.100)というアドレスになります。

このIPv6アドレスの向き先がNAT64のゲートウェイとなっており、ここでIPv4アドレスに変換されてIPv4サーバと通信します。

## Pref64::/n Discovery
DNS64を検知して、クライアント内で合成アドレスを生成する仕組みです。[RFC7050](https://datatracker.ietf.org/doc/html/rfc7050)で規定されています。具体的にはipv4only.arpaのAAAAレコードを解決し、レスポンスが64:ff9b::c000:aa(64:ff9b::192.0.0.170), 64:ff9b::c000:ab(64:ff9b::192.0.0.171)だった場合、NAT64ネットワーク内にいると判定します。名前の通り、このFQDNにはAレコードしか登録されておらず、192.0.0.170, 192.0.0.170が返ってきます。もし利用するDNSリゾルバーがDNS64サーバだった場合は、ないはずのAAAAレコードが返ってきます。
この場合NAT64環境下にあると判定され、IPv4アドレスでの通信を行う場合自動的にIPv4-IPv6変換アドレスに変換されます。

# 解決方法
## IPアドレス直接指定をやめる
IPアドレスを直接指定して通信しているところをAレコードを割り当てるようにすれば、DNS64/NAT64で変換され引き続き利用できるはずです。

## サーバにIPv6アドレスを割り当てる
これはそのままですね 。ただし、サーバ事業者がIPv6に対応していなかったり、アプリケーションがIPv6に対応していない場合は大きな労力がかかります。


# 参考
こちらの記事がわかりやすいです。
https://www.geekpage.jp/blog/?id=2017-2-23-1
prepareメソッドでセキュリティ強化

##SQLでの危険なコード

```input.html
  <form action="input_do.php" method="post">
    <textarea name = "memo" cols="50" rows='10' placeholder="自由にメモを残して"></textarea></br>
    <button type='submit'>登録する</button>
  </form>
```
```input_do1.php
  try{
    $db = new PDO('mysql:dbname=〜);
    
    $db->exec('INSERT INTO memos SET memo="' . $_POST['memo'] . '", created_at=NOW()');
  } ~
```
例えば、上記のinput.htmlのform内から入力した内容をデータベースに保存する場合がある。
上記例だと、**input_do.php**内のSQLである**$_POST['memo']**を、そのまま記述してしまうと書き換えられる危険性がある。

##pepare関数で対策

```input_do2.php
  <?php
  try{
    $db = new PDO('mysql:dbname=〜);

    $statement = $db->prepare('INSERT INTO memos SET memo=?, created_at=NOW()');
    $statement -> execute(array($_POST['memo']));

  } ~
  ?>
```
まず、**$statement**という変数を作り、$dbオブジェクトに**prepareメソッド**を使用する。prepareメソッド内にSQL文を挿入して、memo=**$_POST['memo']**をmemo=**?**とする。
この**?** にindex.htmlのformから入力した値が入る。
また、危険な方は**$db ->exec**　となっていたが、**$statment->execute**となっている。
executeメソッド内には実際に何が入るかという値を指定している。この中に**memo=?**の入力値が入る。

##まとめ
いまいち細かい理屈はわからなかったが、
###SQLが固定されいている時
**$db ->exec**　を使う

###QLがユーザー次第で変わる時

**$db->prepare**を変数に入れる。
prepareの中身の変動するSQLに **= ?** とする。
**$変数名->execute**を使う
Next.js11にhuskyを導入する


![photo-1574273443477-87bf272e5100.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166484/f54a52e8-9236-ecf2-8fb0-699ffcef1d14.jpeg)

## huskyってなに?

huskyとは、Gitのコミットやプッシュなどの特定のアクションが起こった時、任意の処理を実行する仕組みのことです。

## huskyをなぜ使うの？

huskyは、Gitのコミットコマンドの実行を検知して、コミットが実際に行われる前にLintによるコードチェックやテストを走らせ、コードに誤りが無いか確認することができます。

もしこの段階でテストが失敗したりコードに誤りがあった場合、コードはコミットされません。

このようにhuskyを導入しておくと、コミット前に必要なチェックが自動で実行されるため、コードの品質を一定に保つことができるようになります。

## 導入手順

### 1.huskyとlint-stagedパッケージのインストール

`husky`は、`lint-staged`と組み合わせて使います。
下記コマンドを実行し、パッケージをインストールします。

```shell
npm install --save-dev husky lint-staged
```

### 2.lint-stagedの設定

次に`package.json`にステージングファイルに対して、対象ファイルと実行するコマンドを追加します。

```json:package.json
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": "eslint --fix",
    "*": "prettier --write"
  }
```

### 3.huskyの設定 その１ -> prepare 

下記のコマンドを実行します。

```shell
npx husky install
```

次に`package.json`に`prepare`キーを追加します。
`prepare`は、`npm install`で全てのインストールが終了した後に実行されるコマンドです。

```json:package.json
  "scripts": {
    "prepare": "husky install"
  }
```

### 4.huskyの設定 その２ -> コミット前の実行コマンドを登録

下記のコマンドを実行すると`.husky/pre-commit`ファイルが作成されます。

```shell
npx husky add .husky/pre-commit "npx lint-staged"
```

作成された`.husky/pre-commit`ファイルに、コミット前に実行したいコマンドを追記します。

```shell:.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged

// もしtestを実行したい場合は、以下のように追記します。
test
```

### 5.動作確認

最後にGitのコミットコマンドを実行し、`husky`が動作するか確認します。

```shell
$ git commit -m "comment"
✔ Preparing...
✔ Running tasks...
✔ Applying modifications...
✔ Cleaning up...
[main xxxxxxx] feat: *******
 2 files changed, 9 insertions(+), 13 deletions(-)
```

以上で`husky`の導入設定は完了となります。
お疲れさまでした。

## 導入後、コミット時に発生したエラーと対処

### it's not set as executable

#### 問題の状況

```shell
$ git commit -m "first commit."
// ...
hint: The '.husky/pre-commit' hook was ignored because it's not set as executable.
hint: You can disable this warning with `git config advice.ignoredHook false`.
```

#### 原因と対処

`.husky/pre-commit`ファイルに実行権限がありません。
下記のコマンドを実行し、`.husky/pre-commit`に実行権限を与えます。

```shell
chmod 755 .husky/pre-commit
```

### ENOENTエラー

#### 問題の状況

```shell
$ git commit -m "feat: 機能追加"
✔ Preparing...
⚠ Running tasks...
  ✔ Running tasks for *.{js,jsx,ts,tsx}
  ❯ Running tasks for *
    ✖ prettier --write [ENOENT]
↓ Skipped because of errors from tasks. [SKIPPED]
✔ Reverting to original state because of errors...
✔ Cleaning up...

✖ prettier --write failed without output (ENOENT).
```

`ENOENT`とは、`Error No ENTry`の略でファイルやディレクトリが存在しないの意味。

#### 原因と対処

確認したところ、まさかの`prettier`そのものがインストールされていませんでした。
下記のコマンドで`prettier`をインストールして、エラーは解消されました。

```shell
npm install --save-dev prettier
```

## 参考

- https://typicode.github.io/husky
- https://github.com/okonet/lint-staged
- https://unsplash.com/photos/3UFqqOhGBuE
- https://fwywd.com/tech/husky-setup
- https://zenn.dev/kurao/articles/456f44a6f43d89
rails /config ディレクトリ　設定まとめ

# 1. 概要

- railsのいろんな設定について調てみようと思った
- railsの`/config`ディレクトリ以下を調べた内容をまとめる

### 参考資料：[設定ファイルについて](https://railsdoc.com/config)

# 2. /configディレクトリ以下の構成と意味

/config
├ /application.rb	すべての環境で共通の設定
├ /environments	環境ごとの設定ファイルを格納
│ ├ /development.rb	開発環境固有
│ ├ /test.rb		テスト環境固有
│ └ /production.rb	本番環境固有
├ /initializers	初期化処理やそれに関する設定情報
│ ├ /infiections.rb	単数形・複数形のルールを規定
│ ├ /mime_types.rb	アプリで使用するファイルタイプ
│ ├ /secret_token.rb	クッキーを署名とするためのトークン情報
│ └ /session_store.rb	セッションを保存するための設定ファイル
├ /locales		国際化対応のためのリソースファイルを格納するディレクトリ
└ /database.yml	データベースの設定


以下それぞれのファイルの詳細を記載

## 2.1. application.rb

タイムゾーンの設定や、デフォルトで使用する言語、アプリ起動時に読み込むディレクトリなどを指定

尚、以降で示すソースは以下の内容の間で設定することを前提とする

``` ruby:application.rb
module App
  class Application < Rails::Application
    ...
    #実際の設定がある場所
    ...
  end
end
```

### 2.1.1. アプリケーションで使用するタイムゾーン

アプリケーションの中で使用するタイムゾーンを設定
日本に合わせる場合は以下の設定を行う

```ruby:application.rb
config.time_zone = 'Tokyo'
```

参考：[タイムゾーンの設定](https://railsdoc.com/page/config_time_zone)

### 2.1.2. データベースの読み書きに使用するタイムゾーン

データベースの読み書きに使用するタイムゾーンがあるので設定
日本に合わせる場合は以下の設定を行う
デフォルトはutf(協定世界時)[^1]

```ruby:application.rb
config.active_record.default_timezone = :local
```
### 2.1.3. 日本語化ファイルの読み込み設定

エラーメッセージやメールタイトルを他の言語に翻訳する設定
`i18n`というRailsのモジュールを使用して設定する

```ruby:application.rb
config.i18n.default_locale = :ja #デフォルトは:en
```
### 2.1.4. 自動読込パスの設定

Railsでは、Linuxの`$PATH`のような自動読込パス`$LOAD_PATH`を設定できる
これはRails6から組み込まれた`Zeitweik`(ツァイトベルク)というオートロードシステムで実現される
`Zeitweik`を有効にするには以下を設定

```ruby:application.rb
config.load_defaults 6.0 #Zeitweilモード有効
config.add_autoload_paths_to_load_path = false #Zeitweilモード有効の時falseが推奨
```

参考：[application.rbの初期設定](https://blog.cloud-acct.com/posts/u-rails-applicationrb-settings/)

## 2.2. /environments

環境固有の設定をする際にここに`環境名.rb`というファイルを作成する
環境固有の設定については省略

参考：[railsでproduction起動の備忘録](https://intellectual-curiosity.tokyo/2018/09/26/rails%e3%81%a7production%e8%b5%b7%e5%8b%95%e3%81%ae%e5%82%99%e5%bf%98%e9%8c%b2/)　production環境の設定
参考２：[development? production? 開発環境ごとに処理を切り分けたい時](https://kemarii.com/blog/rails/rails-env-branch/)　環境を追加するときの方法。尚、環境ごとの設定の具体例についてはない模様

## 2.3. /database.yml

データベースの環境ごと(development,test,production)の設定を行える
YAML形式で記述する
以下`MySQL`での設定例
`YAML`形式の記法は別途解説

```yml:database.yml

common: &common #共通項をcommonとしてまとめる
  adapter: mysql2
  encoding: utf8
  reconnect: false
  pool: 5

development:
  <<: *common
  database: mysql_development
  username: root
  password:
  host: localhost

test:
  <<: *common
  database: mysql_test
  username: root
  password:
  host: localhost

production:
  <<: *common
  database: mysql_production
  username: root
  password:
  host: localhost
```

参考：[MySQL用のデータベース設定ファイル](https://www.javadrive.jp/rails/model/index2.html)
参考２：[YAML/共通部分の切り出し](https://nju33.com/notes/yaml/articles/%E5%85%B1%E9%80%9A%E9%83%A8%E5%88%86%E3%81%AE%E5%88%87%E3%82%8A%E5%87%BA%E3%81%97#%E5%85%B1%E9%80%9A%E9%83%A8%E5%88%86%E3%81%AE%E5%88%87%E3%82%8A%E5%87%BA%E3%81%97)


[^1]: 国際原子時 (TAI) に由来する原子時系の時刻で、UT1世界時に同調するべく調整された基準時刻 参考：[Wikipedia/協定世界時](https://ja.wikipedia.org/wiki/%E5%8D%94%E5%AE%9A%E4%B8%96%E7%95%8C%E6%99%82)
dotenv-railsを使用したRails環境変数管理

# 1. 概要

- railsでは環境変数等をどのように管理しているのか気になった
- 設定方法について調べた内容をまとめる

### 参考資料：[dotenv-railsを使って環境変数を管理しよう](https://pikawaka.com/rails/dotenv-rails)

# 2. 環境変数とは

以下を参照すること

https://qiita.com/Islanders-Treasure0969/items/c911c2bce63affb91fe2

# 3. dotenv-railsとは

環境変数を管理する事が出来るgem
プロジェクトルートに`.env`を作成してこの中に設定を記載することで、自動で読み込んで環境変数として使用できる

# 4. 導入の流れ

## 4.1. `.Gemfile`に追加

```　.Gemfile
gem 'dotenv-rails'
```

## 4.2. インストール

```
$ budle install
```

## 4.3. `.env`ファイルの作成

プロジェクトルートで作成すること
また、環境ごとに設定を分けたい場合は`.env`の命名ルールで分けるようになっている
定義していある`.env`ファイルは環境に応じて読み取られ、同じ環境変数は優先順位が高いほうが優先される
※`.env.local.<環境名>`という指定もできるようだが使用用途が分からなかったので除外

|ファイル名  |環境  |優先順位  |
|---|---|---|
|.env|全環境|低  |
|.env.development|開発環境|中  |
|.env.test|テスト環境|中  |
|.env.production|本番環境|中  |

```
$ touch .env #全環境共通の環境変数を定義するファイル
```

## 4.4. 環境変数の設定

作成した`.env`ファイルに環境変数を設定する
作成した環境変数は`ENV`に自動で設定される

```　.env
SAMPLEKEY=samplevalue	
```

## 4.5. 呼び出す

プログラムから以下のように呼び出せる
また、以下はirbを使用したコンソールでの呼び出し

```
> ENV['SAMPLEKEY']
=> "samplevalue"
```

# 5. 環境変数作成ファイルのボイラープレートを作る

`.env.boiler`などのファイルを作成し、.envで必要な設定をおいておくことで
新規にアサインされた開発者がボイラープレートを使用して`.env`ファイルを作成できる
**プロジェクトで設定する必要のある開発環境が一目でわかる**ので有用

※ボイラープレートの環境変数に設定する値はダミーデータとすること

## 5.1. 導入の流れ

### 5.1.1. `.env.boiler`を作成する

### 5.1.2. Git管理するためにPushする

### 5.1.3. 新規開発者がプロジェクトをローカルにcloneする

### 5.1.4. cloneしてきたプロジェクトの`.env.boiler`ファイルをコピーして新しくファイルを作成する

```
$ cp .env.boiler .env
```

### 5.1.5. 環境変数を自分の設定に合わせる

### 5.1.6. Git管理から外すように`.gitignore`で設定する

# 6. 具体的な用途

データベースのユーザー名やパスワードを環境変数として設定する

- database.ymlを編集する必要がなくなる
- `.emv`関連のファイルだけローカルで管理すれば`datbase.yml`はバージョン管理に挙げることができるようになる

```yml:database.yml(一部抜粋)
default: &default
  #defaultの設定は省略

development:
  <<: *default
  database: dotenv_development
  username: <%= ENV['DB_USERNAME'] %> # 開発環境の環境変数を参照
  password: <%= ENV['DB_PASSWORD'] %> # 開発環境の環境変数を参照
```

```　.env.development
DB_USERNAME = 'sample_user'
DB_PASSWORD = 'password'
```
# まとめ

`Rails 5.2`以降は`EncryptedCredentials`とかいう暗号化する機能が追加されたらしいがとりあえずこれで環境変数の管理をやってみる
Dockerで noneイメージを一括で削除する

Dockerでイメージが&lt;none&gt;になったimageの削除方法です。

```console:console
>docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
<none>        <none>    95567986227a   5 hours ago    1.36GB
app           latest    59195fa62f44   5 hours ago    1.36GB
alpine/git    latest    b8f176fa3f0d   5 weeks ago    25.1MB
hello-world   latest    d1165f221234   3 months ago   13.3kB
```

下記のコマンドで削除可能です。
ver 1.25以上で使用可能です。


[公式ドキュメント](https://docs.docker.com/engine/reference/commandline/image_prune/)

```console:console
docker image prune [OPTIONS]
```
会社の中にAIの仲間を作るための覚え書き

2021年6月30時点の覚え書きです。

##G検定公式テキスト第2版刊行記念イベントの動画
6月10日に公開されたのでこれを紹介して仲間になってもらう。SNS拡散推奨されているので安心して伝えられる。
https://www.youtube.com/watch?v=IYyDgQPo5Dg

https://www.youtube.com/watch?v=IYyDgQPo5Dg

##Deep Learning for DX NEWS 会員になる

Deep Learning for DX NEWS ニュース会員になってもらう。
https://www.jdla.org/join-dxnews/

https://www.jdla.org/join-dxnews/

そうすると
2021年4月9日の「第5回AI・人工知能EXPO【春】」での松尾豊（東大）教授の基調講演「DX時代のAI(ディープラーニング)活用最前線」が観れるようになる。
それから「DX導入ガイドブック」も貰える。
このガイドブックはアンドリュー・ウ（Andrew Ng）先生の「AI Transformation Playbook」をベースにしてまとめてあるのでとてもいい。
（参考）
https://qiita.com/sugulu_Ogawa_ISID/items/831b85384b79091f1ee3

##AI For Everyone を一緒に受講

https://www.coursera.org/learn/ai-for-everyone-ja
を一緒に学ぶ。アンドリュー・ウ先生から直接話を聞ける（日本語訳付きで）のがとても嬉しい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/ca76f8a4-a678-116b-3f34-faa401910184.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/4c2d4533-a66e-fc59-f094-386fed0ec28a.png)

##AI論文を一緒に学ぶ


https://www.youtube.com/c/nnabla/videos

##社内でKaggle仲間を作る
Kaggleで勝つ、とか競い合う、というよりもまずはTitanicデータに取組むなど社内でディスカッションできる仲間になってもらう

Pythonで動かして学ぶ！Kaggleデータ分析入門
https://www.shoeisha.co.jp/book/detail/9784798165233

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/bfd7556f-5be7-ff9b-d71a-7d4cf919e4f3.png)


PythonではじめるKaggleスタートブック
https://www.kspub.co.jp/book/detail/5190067.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/3a53b268-fba9-3841-b5d6-c4aa3a971111.png)

Kaggleで勝つデータ分析の技術
https://gihyo.jp/book/2019/978-4-297-10843-4

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/27a26aa8-b399-1c85-92b5-b75b6a203e69.png)

##文学好きがいたら青空文庫の作品分析をやってみる
作者別、年代別などいろんな切り口で解析をしてみて披露しあう。

##音楽好きがいたら好きなアーティストの歌詞分析をやってみる
これもいいかも
cssで使われる「#」「>」「$」の意味について

CSSの復習も兼ねてタイトルにも記載した通りですが、今日使った「#」「>」「$」についての意味についてメモとして残していこうと思います。

そもそもセレクターとは何かというとcssでスタイルを適用させたい時にどこに適用させたいかを指定してあげる必要があります。
その指定するときにセレクターを使用します

#「#」
指定したID属性の要素にスタイルを適用させることができるIDセレクターです。
HTMLタグで設定したID名を指定します

#「>」
指定した親要素の子要素を指定することができます。

```ruby
name>a{適用させたいスタイルの内容}

```
この場合はname要素の子要素であるa要素にスタイルが適用される。

#「$」
こちらは要素を指定するのではなく属性を指定する時に要するセレクターです。
【AdMob】Constraint items must each be a view or layout guide

#詰まった点
GoogleAdMobでバナー広告を設置する際に** Constraint items must each be a view or layout guide**というアラートが出た

```swift
    bannerView = GADBannerView(adSize: kGADAdSizeBanner)
    bannerView.adUnitID = "ca-app-pub-HIDDEN/HIDDEN"
    bannerView.rootViewController = self
    bannerView.delegate = self
    bannerView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(bannerView)
    view.addConstraints(
        [NSLayoutConstraint(item: bannerView,
                            attribute: .bottom,
                            relatedBy: .equal,
                            toItem: view.safeAreaLayoutGuide.bottomAnchor, // アラート箇所
                            attribute: .top,
                            multiplier: 1,
                            constant: 0),
         NSLayoutConstraint(item: bannerView,
                            attribute: .centerX,
                            relatedBy: .equal,
                            toItem: view,
                            attribute: .centerX,
                            multiplier: 1,
                            constant: 0)
        ])
    bannerView.load(GADRequest())
```

#解決策
画面下部に設置していようとしていたため**bottomAnchor**を指定していたが、**safeAreaLayoutGuide**だけでいい模様

```
toItem: view.safeAreaLayoutGuide,
```
pyenv インストール& python バージョン管理

## Python3で開発するためpythonのバージョンを変更したい時に、pythonのバージョン管理ツールpyenvを使うと便利です

環境: Mac OSX
## pyenvのインストール

```
$ brew install pyenv
```

```qiita:(実行後の出力)
Updating Homebrew...
==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
  https://github.com/Homebrew/brew#donations
==> Auto-updated Homebrew!
.
.
.
==> Installing pyenv
==> Pouring pyenv--2.0.2.arm64_big_sur.bottle.tar.gz
🍺  /opt/homebrew/Cellar/pyenv/2.0.2: 762 files, 2.6MB
```


## インストールしたいPythonのバージョンをリストの中から確認

```
$ pyenv install --list
```

```qiita:(実行後の出力)
Available versions:
  2.1.3
  2.2.3
..
  3.9.4
  3.9.5
  3.10.0b3
  3.10-dev
  3.11-dev
..
  stackless-3.5.4
  stackless-3.7.5
```


## Pythonのバージョンを指定してインストール

```
$ pyenv install 3.9.5
```
```qiita:(実行後の出力)
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.9.5.tar.xz...
-> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz
Installing Python-3.9.5...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.9.5 to /Users/takuma/.pyenv/versions/3.9.5
```

## インストール後に読み込み設定

```qiita:terminal
$ echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile
$ eval "$(pyenv init --path)"
```

これでバージョンを確認するとインストールしたバージョンに変わっているはずです。

```
$ python -V
3.9.5
```


<参考サイト>
[pyenvにより、pythonのバージョンを変更する](https://qiita.com/Kohey222/items/19eb9b3cbcec9b176625)
[pyenvでpython環境構築](https://qiita.com/shoicchi/items/a4e140b1dc6944277e23)
[Simple Python Version Management: pyenv](https://github.com/pyenv/pyenv/blob/master/README.md#uninstalling-python-versions)
動画からフレーム単位で連番ファイルを抽出してフレーム数と時間を付ける（cap.get(cv2.CAP_PROP_FRAME_COUNT)が、ファイルの実際のフレーム数と違う値を返す時の、雑な対応付き）

###はじめに
動画からフレーム単位で連番ファイルを抽出するPythonプログラムを作った。

https://note.nkmk.me/python-opencv-video-to-still-image/
Python, OpenCVで動画ファイルからフレームを切り出して保存

を参考にした。と言うか、上記サイトにある、フレーム毎に出力するのと、時間を表記するのを合わせただけ。
細かい追加としては、時間を秒だけでなく、時間_分_秒表記にしたのと、全フレームでなく、指定した単位で飛ばして出力するようにした。

ただ、いくつかの動画で実行してみると、正しい時間が表示されないものがあり、調べて見ると、cap.get(cv2.CAP_PROP_FRAME_COUNT)で得られるフレーム数と、実際の動画のフレーム数が異なっているのが原因だった。
実際に数えてみる、という雑な手法で、解決したものを、後半に掲示する。


#動画からフレーム単位で連番ファイルを抽出してフレーム数と時間を付けるスクリプト
```python
import cv2
import os

def save_all_frames(video_path, dir_path, basename, step_num, ext='jpg'):
    cap = cv2.VideoCapture(video_path)

    if not cap.isOpened():
        return

    os.makedirs(dir_path, exist_ok=True)
    base_path = os.path.join(dir_path, basename)

    digit = len(str(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))))

    fps = cap.get(cv2.CAP_PROP_FPS)
    fps_inv = 1 / fps

    n = 0

    while True:
        ret, frame = cap.read()
        #read()メソッドで動画を１フレームずつ読み込む。retにはbool値が入る。動画の最後まで来るとwhile処理が終了
        if ret:
            if n % step_num ==0:
                cv2.imwrite('{}_{}frm_{:02.0f}h_{:02.0f}min_{:02.0f}sec.{}'.format(base_path, str(n).zfill(digit), (n * fps_inv) // 3600, ((n * fps_inv) // 60) %60, (n * fps_inv) % 60, ext), frame)
            n += 1
        else:
            return

save_all_frames('data/temp/sample_video.mp4', 'data/temp/result', 'sample_video_img', 10)
#引数は、元の動画の場所、出力画像の保存フォルダ、出力画像の頭に付ける文字列、フレームを飛ばす数（全フレーム出力なら1を設定)
```

#cap.get(cv2.CAP_PROP_FRAME_COUNT)で得られるフレーム数と、実際の動画のフレーム数が異なっている場合に、定義したreal_frame_num_count関数で、実際のフレーム数を数えて、それを使って、ファイル名に時間を表記するプログラム
```python
import cv2
import os

def save_all_frames(video_path, dir_path, basename, step_num, ext='jpg'):
    cap = cv2.VideoCapture(video_path)

    if not cap.isOpened():
        return

    real_frame_num = real_frame_num_count(video_path)
    
    os.makedirs(dir_path, exist_ok=True)
    base_path = os.path.join(dir_path, basename)

    digit = len(str(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))))

    total_sec = cap.get(cv2.CAP_PROP_FRAME_COUNT) / cap.get(cv2.CAP_PROP_FPS)
    fps_inv = total_sec / real_frame_num

    n = 0

    while True:
        ret, frame = cap.read()
        #read()メソッドで動画を１フレームずつ読み込む。retにはbool値が入る。動画の最後まで来るとwhile処理が終了
        if ret:
            if n % step_num ==0:
                cv2.imwrite('{}_{}frm_{:02.0f}h_{:02.0f}min_{:02.0f}sec.{}'.format(base_path, str(n).zfill(digit), (n * fps_inv) // 3600, ((n * fps_inv) // 60) %60, (n * fps_inv) % 60, ext), frame)
            n += 1
        else:
            return

def real_frame_num_count(video_path):
    real_frame_num = 0

    cap = cv2.VideoCapture(video_path)

    if not cap.isOpened():
        return

    while True:
        ret, frame = cap.read()
        if ret:
            real_frame_num += 1
        else:
            return real_frame_num


save_all_frames('data/temp/sample_video.mp4', 'data/temp/result', 'sample_video_img', 10)
#引数は、元の動画の場所、出力画像の保存フォルダ、出力画像の頭に付ける文字列、フレームを飛ばす数（全フレーム出力なら1を設定)
```

real_frame_num_count関数の実行だけで、結構な時間が掛かってしまい、実行してもすぐにはファイルは作成されていかないのが問題。
Mac で 突然 Git に personal access token を求められた時の対処

２段階認証とか設定してないし

特に設定の変更もしていないけど

git pull の時とかに突然エラーが出た時の対処

Mac の 設定で ちょっとハマったので、次の犠牲者のためにメモ

エラー内容

```
Password authentication is temporarily disabled as part of a brownout. Please use a personal access token instead.
```

# ハマった内容
「パスワードの代わりにトークン使いなさい」 って言われるけど
トークンゲットした後、どこに入力するん？
pull したりした時にパスワード求められるらしいんだけど、求めてこないよ？

# 原因
MACのキーチェーンを削除していないので、パスワードを再度聞かれなかったのが詰まった原因だった

# 解決
アプリケーション >> ユーティリティ >> キーチェーンアクセス で、github.com を削除
これで、もう一回PUSHしたりする時に、パスワード聞かれる様になるので、そこで先程生成したトークンを入力すればOK



# 終わりに
確かに、マックの初期設定で キーチェーンをONにした覚えあるわ...
Twitter gemの使い方

#はじめに
twitter apiをRailsを使って実装する際に、twitter gem を使用しようと思い、twitter gemについて調べたことをまとめました。

#使用前の注意点
・twitter gem はruby 2.7までしか使えない。
・twitter gem を使う前にTwitter Devへ申請し、アプリを作成し各種KeyやTokenを取得する必要がある
（参考：[Twitter APIを利用するには](https://qiita.com/taishi0202/items/092c267c0c6dc68347c5))
・OAuth認証が完了していないと使えないメソッドやリクエストがある。
(OAuth認証についてはまだ未解決）
・環境変数を使うので、`gem dotenv-rails`はインストールしている前提である。

#Twitter gemの使い方
###1. インストール
まず、`Gemfile`に

```ruby:Gemfile
gem `twitter`
```
を追加し、ターミナルで

```terminal:
gem install twitter
```
を実行し、インストールをします。

###2. gemを使う前の環境構築
冒頭の注意書きにも書いたように、Twitter APIに必要な各種keyとTokenがないと

```
Bad Authentication data
```
というエラーが出てしまいます。そこで、各種KeyとTokenを利用できるように
application_controllerに定義して、それぞれのcontrollerにbefore_acttionで認証していきましょう。
早速、application_controller.rb以下を記入。

```ruby:application_controller
  @client = Twitter::REST::Client.new do |config|
      config.consumer_key        = ENV['CONSUMER_KEY']
      config.consumer_secret     = ENV['CONSUMER_SECRET']
      config.access_token        = ENV['ACCESS_TOKEN']
      config.access_token_secret = ENV['ACCESS_TOKEN_SECRET']
    end
```

各KeyやTokenはTwitter Devを申請し、アプリを作成した時に取得したものを`.env`に入力。
(.envファイルがない場合はターミナルで`touch .env`を実行し、ファイルを生成しましょう。）
これが出来れば、準備完了です！

###3. twitter gem で使えるメソッドを確認しよう。
次にrails consoleでtwitter gemのメソッド一覧を確認していきましょう。
`bundle exec rails c`を実行後
console内で

```ruby:console
client = Twitter::REST::Client.new
```
を実行し、clientを定義します。
（別にclientでなくてもなんでも大丈夫です。とりあえず、Twitterモジュールに関連した変数を定義できればOK）
次に

```ruby:console
client.methods
```
を実行するとズラーっと使用できるmethodsが出てきます。
このメソッドを用いて、直近のツイートの情報を取ってきたり、あるユーザーの情報やDM、リストなど様々な値を取ってくることができます。
それぞれのメソッドについては以下のサイトにまとめてあったので、参考にしてください。
[Ruby Twitter gemの簡易リファレンス](https://gist.github.com/yhara/3087849)
これ見ると、Twitterの機能全部が作れそうな気がします・・・w

#まとめ
簡易ではありますが、Twitter gemの使い方とメソッドの調べ方をまとめました。
ただ、今回、OAuth1.0aやOAuth2.0 Bearer Tokenを使った場合のgemの使い方には触れていないので、表面的なものとなります。

＃参考サイト
[The Twitter Ruby Gem](https://www.rubydoc.info/gems/twitter)
[参考コード](https://github.com/sferik/twitter)
[Ruby Twitter gemの簡易リファレンス](https://gist.github.com/yhara/3087849)
Cloudfrontの後ろにいるRailsでブラウザのソースIPを安全に取る

この記事は
===

* 便利なgem見つけたのでメモです

やりたかったこと
===

* Cloudfrontの後ろにRailsが配置されている状況で、Railsのrequest.remote_ipでブラウザのIPアドレスをセキュアに取りたかったです

方法
===

* とりあえず下記のgem入れておけばOK
* [cloudfront-rails](https://github.com/dinks/cloudfront-rails)

仕組み
===

* そもそもソースIP取得のためにX-FORWARDED-FORの仕組みを利用する場合、偽装対策の一環として、中間機器を「信頼されたIP」とみなして、判定時にX-FORWARDED-FORリストから除去する必要があります
* そのためにRailsでは```ActionDispatch::Railtie.config.action_dispatch.trusted_proxies```という設定値があり、ここにリバースプロキシのIPを入れるという機構があります
  * ここに入れておくと、X-FORWARDED-FORのIPリストから該当IPを除去してくれるという仕組みになっています
* 上記のgemは、[ここで公開されているAWSのIPリスト](https://ip-ranges.amazonaws.com/ip-ranges.json)を自動的にダウンロードして、上記のRailsの設定に入れ込んでくれるというものでした

終わりに
===

* Rails最近ディスられやすいけど、こういうのがgem一発なのほんとやめられないよね

参考
===

* https://www.m3tech.blog/entry/x-forwarded-for
mysqlの 物理バックアップ・論理バックアップ の違い

## 勉強前イメージ

ディレクトリごとバックアップか、dumpしてバックアップかってイメージ

## 調査

### 物理バックアップとは

物理的なサーバ内のディレクトリとrawファイルバックアップ。
早急にリカバリする際に適しています。

- メリット

バックアップのサイズが小さい
バックアップ・リストアの際に、データの変換(SQLファイルへの変換)が少ない(ない)ので速度が早い

- デメリット

バージョン間で互換性が取れない場合がある

![1# 物理バックアップ・論理バックアップ の違い - diagrams.net - Google Chrome 2021-06-30 19.28.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/faf00cf6-7b92-0daa-2ab6-9067453a12b8.png)


### 論理バックアップとは

データベースからデータをSQLファイルにしてバックアップをする。
mysqldumpで実施できる。
違うアーキテクトのDBにリストアする際に適しています。

- メリット

他のバージョンや、違うRDSMSにリストアができる。

- デメリット

バックアップのサイズが大きくなる
SQLファイルへの変換があるので、バックアップ・リストアの時間がかかる

![2# 物理バックアップ・論理バックアップ の違い - diagrams.net - Google Chrome 2021-06-30 19.28.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/dc8968c9-23d1-949e-0c02-27ca631c93d9.png)

## 勉強後イメージ

イメージほぼ合ってた。
確かにディレクトリごとのバックアップを行うと、違うバージョンとかへのリストアは難しいかもしれない

## 参考

- [MySQLバックアップの基本](https://www.slideshare.net/yoyamasaki/mysql-15289428)
- [7.1 バックアップとリカバリの種類](https://dev.mysql.com/doc/refman/5.6/ja/backup-types.html)
Git logからChangeLogを自動生成する方法を考えたら、その考え自体が不適切だったという話

Gitでコード管理してる自作ソフトをDebianパッケージにしたいとき、標準的な構成を自動生成できないかと考えました。標準的な構成とは何か、ですが、/usr/share/doc/(パッケージ名)の下にNEWS, ChangeLog, copyrightがあるくらいでしょうか（色々見た限りでは決まりは無いようで、単なる慣習だろうと思います）。copyrightは自分で用意してやるほかありませんが、ChangeLogはgit logコマンドで適当に作れそうだな、と思ったのが事の始まりです。

実際、そのような趣旨の記事やQ&Aページは沢山見つかります。下記はそのほんの一部。

https://pypi.org/project/gitchangelog/#changelog

https://stackoverflow.com/questions/3523534/what-are-some-good-ways-to-manage-a-changelog-using-git

https://portaltan.hatenablog.com/entry/2015/09/29/133203

https://uwabami.hatenablog.com/entries/2010/06/25

https://qiita.com/ryokbys/items/4271efa8e06caa3ddbe1

ところがDebianパッケージのChangeLogを調べると、多くは次の書式を採用しています。

```
パッケージ名 (バージョン番号) stable/unstable/それに類する単語; urgency=low/medium/high
  * 更新内容の説明
 -- 作業者名 <メールアドレス>  曜日, 日 月 年 時刻 +GMT
```
前述の記事たちに、このような書式に整形する内容はありませんでした。

Gitでコード管理しているなら、

 - パッケージ名=リポジトリ名 … basename \`pwd\` すればOK
 - 更新内容の説明 … git logのコミットメッセージそのまま
 - 作業者名 … git config --listからuser.nameを取ってくればOK
 - メールアドレス … 同じくuser.emailを取ってくればOK
 - 日時 … 上のページたちにあるようにgit logに--prettyだの--decorateだのつければなんとかなる

んですが、バージョン番号やstable/unstable、urgencyなどはGitで管理してません。

残念でした、おしまい、とするのは何だかなので、背景をもう少し調べてみました。そもそもChangeLogとはどういうものなのか。

https://keepachangelog.com/en/1.0.0/

https://blog.yux3.net/entry/2017/05/04/035811

上記のページは大変参考になります。これらによれば、

 - git commitはコードの差分を端的に言語化するもので、説明的であってはならない
 - ChangeLogは開発者間のコミュニケーションの拠り所とするものなので、説明的でなければならない

のがそれぞれの趣旨である、と。相容れません。

もう一つ、ChangeLogでは

```
 - Mention whether you follow Semantic Versioning.
```
とされていて、気持ちとしてはSemantic Versioningに従うことを推奨されている雰囲気があります。
Semantic Versioningについては↓をご参照下さい。

https://semver.org/

一方、Gitの哲学では（完全に理解しているわけではありませんが、恐らく）コード管理するのに明示的なバージョン番号は不要、という考え方があります。これも相容れません。

ですから正しいやり方は、Git logからChangeLogを作るのではなくChangeLogを先に書き、それに基づいてGit操作する、具体的には、

 - ChangeLogに非説明的な見出しを付けて、それを抽出してコミットメッセージにする
 - Semantic Versioningに基づいてバージョン番号を自分で付け、それをコミットのタグにする
 - stable/unstableはブランチを分ける
 - urgencyはSemantic Versioningと整合するように自分で決める（Gitに明示的情報として残すのは諦める）

ということになろうかと思います。こちらはある程度自動化できそうです。

異論・反論・反証を歓迎します。調べが足りない部分もあろうと思いますので。
M1チップ搭載macbookでのDockerを用いたMYSQLの接続方法（Rails）

## M1チップ搭載macbookでのDockerを用いたMYSQLの接続方法（Rails）

データベース周りの環境構築時につまずいた部分なので、自分なりのエラー解決方法を記載します。

<dl>
  <dt>Ruby ver</dt>
  <dd>Ruby 2.7.2</dd>
  <dt>Rails ver</dt>
  <dd>5.2.6</dd>
  <dt>Docker Engine ver</dt>
  <dd>Docker Engine v20.10.6</dd>
  <dt>MySql ver</dt>
  <dd>5.7.34</dd>

</dl>

## docker-compose.ymlの編集 ##

```docker-compose.yml
version: '3.2'

services:
  database:
    restart: always
    image: mysql:latest
    ports:
      - 3306:3306
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - mysql-datavolume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root

volumes:
  mysql-datavolume:
    driver: local
```
上記のファイルで`docker-compose build`し、`docker-compose up -d`するとエラーコードが出ることがあります。

```
Pulling database (mysql:latest)...
latest: Pulling from library/mysql
ERROR: no matching manifest for linux/arm64/v8 in the manifest list entries
```
上記エラーコードが出た場合は、まずローカルにインストールされているmysqlのバージョンを確認してください。
確認後に、`database.yml`内の`image: mysql:latest`を`image: mysql:ローカルにインストールされているmysqlのver`に指定してください。
その後、ローカルにインストールされているmysqlLのverをdockerにpullします。

```
docker pull --platform linux/amd64 mysql:(ローカルにインストールしているmysqlのバージョン）
```

この後、`docker-compose up -d`するとエラーすることなく、dockerが立ち上がります。
あとは、`database.yml`内で設定したパスワードの`root`を使用すれば、mysqlに接続できます。
[Flutter] TextFormFieldでメールアドレスのバリデーションを行う

[email_validator](https://pub.dev/packages/email_validator)を使います。

## pubspec.yamlにemail_validatorを追加する
```pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2

  # 追加
  email_validator: ^2.0.1
```

## 保存ボタンをクリックして、入力値が不正ならエラーメッセージを表示する

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365643/03e46bfa-9e9c-1791-23b7-a5e051402ddf.png" width=400 />



以下、全体の実装です。

```dart
import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Email Validation Sample',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<FormState> _key = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Email Validation Sample'),
        actions: [
          IconButton(
            icon: Icon(Icons.save),
            onPressed: () {
              if (!_key.currentState!.validate()) return;
              _key.currentState!.save();
            },
          )
        ],
      ),
      body: Padding(
        padding: EdgeInsets.all(10.0),
        child: Center(
          child: Form(
            key: _key,
            child: TextFormField(
              decoration: InputDecoration(
                labelText: 'Email',
              ),
              validator: (value) {
                if ((value == null) || !EmailValidator.validate(value)) {
                  return 'Emailが不正です';
                }
              },
              onSaved: (value) => null,
            ),
          ),
        ),
      ),
    );
  }
}
```
GitHubからpullすると認証エラーが出るようになった。

## 発生した問題
ローカル環境のコマンドライン（bash）からいつものようにGitHubプライベートリポジトリに対して`git pull`を行ったところ、以下の認証エラーが突然出るようになった。

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

どうやらこれまでのようなパスワード認証から二段階認証やパーソナルアクセストークンとやらを使った認証を利用しないとコマンドラインからGitHubリポジトリにアクセスできなくなる模様。

後掲の参考サイトに記載のあるように、確かにGitHubより忠告のメールが来てた気がする。。

## 選択した解決策
GitHubよりパーソナルトークンを発行し、ローカルからの認証にパーソナルトークンを利用するように設定する。

### パーソナルトークンの発行
以下の公式ドキュメントのとおりに発行。
https://docs.github.com/ja/enterprise-server@2.21/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token

今回はbashから認証したいので、トークンに付与するスコープは`repo`のみを選択。

### パーソナルトークンをgitの認証情報として保存
発行したパーソナルトークンを`password`に設定。
`git config --global --add user.password '発行したパーソナルトークン文字列'`

パーソナルトークンをキャッシュさせる。
`git config credential.helper store`

以上で`git pull`などのコマンドが実行できるようになる。

### 参考にさせていただいた記事
https://qiita.com/kanta_yamaoka/items/1a59892028b9c422df22
https://qiita.com/Kamo123/items/c92b03278b6302c641e3
void型ランキング

Void型について調べたときに参考になった記事

##第1位
https://qiita.com/keitean/items/a967712581f539934ab0

##第2位
https://qiita.com/tadsan/items/154070f1ee4c7fe4ae47

##第3位
https://qiita.com/t_t238/items/30c28817b980258885ff

##その他
https://qiita.com/mizcii/items/38aa405122542771a23f
https://qiita.com/tamy0612/items/bfc4b034d94b7fee1b82

いつもわかりやすい記事ありがとうございます。
"gcloud iam service-accounts keys create" を実行すると "FAILED_PRECONDITION: Precondition check failed." が発生

## 概要

`gcloud`コマンドでサービスアカウントのキーを生成しようとしたところ、`FAILED_PRECONDITION: Precondition check failed.`というエラーが発生した。
具体的な原因を示してくれず不親切だが、結果的に発行可能なキーの上限に達していたのが原因だった。

## 実行したコマンド

```bash
# サービスアカウントのEmailアドレス
GCP_SA_EMAIL=sa-name@project-id.iam.gserviceaccount.com
# サービスアカウントの認証情報を保存するファイル
GCP_SA_KEY_FILE=key-file.json
# サービスアカウントのキーを生成
gcloud iam service-accounts keys create $GCP_SA_KEY_FILE \
  --iam-account=$GCP_SA_EMAIL
```

## 発生したエラー

```
ERROR: (gcloud.iam.service-accounts.keys.create) FAILED_PRECONDITION: Precondition check failed.
```


## 原因

サービスアカウントに対して発行可能なキーの上限`10個`に到達している。

以下の通り、[公式ドキュメント](https://cloud.google.com/iam/docs/creating-managing-service-account-keys?hl=ja#creating_service_account_keys)にも記載がある。

> サービス アカウントには最大 10 個のキーを設定できます。


## 対処方法

クラウドコンソールにログインして、 

* `IAM と管理` > `サービス アカウント` > (対象のサービスアカウントを開く) > `キー`

にアクセスして、不要なキーを削除して9個以下にする。
システム開発で使われる用語難しいい！

・CRUD図
データに対してどの機能で新規登録（create）,参照（read）,更新（update）,削除（delete）するかをマトリスク形式（表みたいなやつ）で定義した図。
頭文字を取ってCRUD図という。

・ER図
データのまとまりであるエンティティ（entity）とデータ同士の関連性（relationship）を表した図。
頭文字を取ってER図という。

・アジャイル
ソフトウェア開発の手法。
代表的なアジャイルの例が以下3点。
1.スクラムといったイテレーションごとに開発の進行に問題がないか、制作物は正しい動きをしているのかを精査しながら開発を行う手法。

2.XP（エクストリーム・プログラミング）
初期の計画よりも技術面を重視したプログラマー中心の柔軟性を重視する手法。

3.ユーザー機能駆動開発（FDD）
実際に動作する機能を開発するには、ユーザー側のビジネスの見える化を行うために、実際に動作するソフトウェアを適切な間隔で繰り返す手法。

・ステークホルダー
会社や団体など直接的あるいは間接的に利害関係のある人たちの意味。EX)発注側の経営者、業務担当者、運用担当者など菅発するシステムに関係するメンバー

・デプロイ
Webシステムを構成するプログラムのソースコードをすyエージング環境やプロダクション環境に配備して実際に動作するようにすること。

・ステージング環境
Webシステムの動作検証を目的に、プロダクション環境を模して作られる環境のこと。実際に近い条件でテストを行えるので、プログラムの挙動だけでなく負荷の検証などもできる。

・プロダクション環境
実際に公開されるWebシステムが動作する環境（本番環境）のこと。プログラムが動作するWebアプリケーション、データベース、ファイルストレージ、キャッシュなどの要素で構成される。

・ドメイン
システム開発では、システム対象における業務領域のこと。
具体的には、「商品」「数量」「金額」「配送日」「配送先」「請求先」という小さな「部品」やそれらをまとめた「注文」などがドメインになる。

・ベンダー
ソフトウェアやシステム、サービス、製品を販売する企業のこと。ベンダー企業自体がシステム開発する場合もあれば、他社が開発した製品やサービスの販売・導入支援をする場合もある。

・ミドルウェア
業務処理を行うアプリケーションとOSの中間nに入るソフトウェアのこと。アプリケーションを補助する汎用的な機能を集めたものが多い。EX）データベース管理システム（DBMS）


学習すればするほど、難しい単語出てきて処理が追いつかなくなるから、定期的にアウトプットを心がける。
ReactでMaterialUIのmakeStylesで:before、:afterが表示されない

## はじめに
ReactでMaterialUIのmakeStylesを使用した際に、:beforeと:afterが表示されずに時間を使ったので、メモとして残して置きます。

## 問題のコード
```
const useStyles = makeStyles(() => ({
  link: {
    '&::before': {
      background: `url(http://~~~~~) no-repeat`,
      content: ''
    }
  }
}))
```
上記のコードで問題なくbackgroudに指定した画像がlinkのところで表示されるかと思っていましたが、このコードでは何も表示されません。

##　解決した方法
```
const useStyles = makeStyles(() => ({
  link: {
    '&::before': {
      background: `url(http://~~~~~) no-repeat`,
      content: '""'
    }
  }
}))
```
上記のコードでは、contentに'""'を指定しました。
JSの中でCSSを書いているので、contentに''だけではJSの空文字として扱われ、CSSに変換した時`content: ""`の状態にはならず表示されませんでした。


## 終わりに
他にもCSSinJSならではハマりどころなどありそうだなと思いました。ハマったら随時メモしていきます。

## 参考
https://github.com/mui-org/material-ui/issues/14153
【リファクタリング】コードのにおい(code smell)とは

## どんな記事
- 新人エンジニアのサクッとアウトプット記事
- 具体的な内容(コード)というよりは"ざっくり"理解するのが目的

## リファクタリングとは
* 既存のコードをふるまい(動き)を変えずに内部の設計をかえること
* 設計コストを小さくでき、保守や拡張の際の工数を減らせる。
* ”まとめたり””分けたり”することで分かり易い設計(コード)にするのが目的

## コードのにおい
リファクタリングする際に直すべきコードを感覚で見つける必要がある。
その”感覚”を”センス・経験”のようなもので片づけず、兆候を一覧化したものが「コードのにおい」

代表例(ほんの一部)

|  アクセス修飾子  |  アクセスできる範囲  |  アクセスできる範囲  |
| ---- | ---- | ---- |
|  重複したコード  | 同じようなコードが複数個所に存在  |  メソッド・クラスの抽出  |
|  長すぎるメソッド  |  メソッドが長くなりすぎている。  |  メソッドの抽出、条件の分解  |
|  巨大なクラス  |  大きすぎるクラス。責務が多すぎる  | クラスの抽出、サブクラスの抽出、インターフェース  |

### どこを見ればわかる？
著書『リファクタリング』に記述されている

https://www.amazon.co.jp/dp/B01IGW5MG0/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1
Windows10(20H1)で MS Office 2019 を利用しようとするとライセンス認証されていてもエラーが出る

#状況
Windows10（20H1）に更新した環境にMS-Office2019をインストールして Word や Excel などを起動すると「この製品のライセンスを確認できませんでした。コントロールパネルを使ってOfficeを修復してください」というダイアログが表示される。
そのダイアログをOKを押すと正常に利用できるし問題なくライセンス認証されていることも確認できる。
セキュリティソフトを何か入れているわけでもなく Defender で運用している。
表示されるメッセージに従ってコントロールから修復をかけても何も変わらない。


#参考になったサイト
- [WindowsUpdate\(20H1\)後Officeで「この製品のライセンスを確認できませんでした。コントロールパネルを使ってOfficeを修復して下さい」 \- ITよろづや](https://ityorozuya.hatenablog.com/entry/2020/07/07/042312)
- [Windows Update\(20H1\)後に「この製品のライセンスを確認できませんでした」](https://social.technet.microsoft.com/Forums/ja-JP/2a84f58e-e7ad-4141-a0fe-1c721749ab9d/windows?forum=Office2016ITProJP)

#解決方法
レジストリエディタで __\HKEY_USERS\S-1-5-20__ というキーのアクセス許可に __NETWORK SERVICE__ というグループに対して__フルコントロールのアクセス権__を付与したところ、ダイアログが表示されなくなった。

正しい対処方法なのかは不明だが、いずれ Microsoft の Update か新しいバージョンの Office で改善されると期待したい。
【docker + vsftpd】複数ネットワークから連続でアップロードを行うと失敗する

dockerとかよく分からなくて、他社が構築したサーバだったのでダダハマリしたorz

##事象
複数ネットワークから連続でアップロードを行うと失敗する。
再現性はあるけど絶対起こるわけでもない。

##原因
・dockerはフォアグラウンドのプロセスのみを維持し、それ以外はexitしてリソースを解放する
・vsftpdは転送作業が正常に終了するとバックグラウンドになる
→ configで「background=NO」としても駄目だった
・vsftpdのコンテナに「restart: always」が設定されていたので、exitした後、新しいプロセスでvsftpdは再起動される
→ この再起動中にアップロードが失敗する

##解決方法
dockerがexitしないようにコンテナに別のフォアグラウンドプロセスを常駐させる。

##参考
https://github.com/delfer/docker-alpine-ftp-server/issues/15
PythonでIDPASS入力してMySQL側でログインさせるにはどうしたらいいですか

SQLテーブル内容
employer_tbl
　・employer_id (int(10)PrimaryKey)
　・employer_name (varchar(50))
　・password (varchar(50))

ーーーーーーーーーーーーーーーーーーーーーーー

～～～～省略1（※最後のほうに追記）

while True:
    try:
        print("名前と社員番号・パスワードを入力してください")
        employer_name = input("氏名：")
        employer_id = int(input("社員番号："))
        employer_pass = input("パスワード：")
        password = " (\'"+ employer_pass + "\')"
        
        cursor.execute("select employer_name from employer_tbl where employer_id ="+ str(employer_id) + " and password = "+ password + ";")
        name = cursor.fetchall()

        if name == []:
            login = False
        else:
            login = True

～～～省略2

ここまでで一応IDとパスワードをPython側から入力してMySQL側で一致すればTrue、一致しなければFalseを返してくれるようにはなっています。
ただ初心者でかなり汚いかなと思っているのですが、いかがでしょうか
２か月後現場で初めて働くのですがもっといい方法などあれば教えてください、それとも動けばある程度汚いコードでも大丈夫って感じなのでしょうか

非常にわかりづらい文章・コードで大変恐縮ですが回答いただけるかたいましたらどんな意見でもいいのでいただきたいです。。




※省略した部分追記いたします。
データベース部分は追加しないとですがコピペで動くと思います。（TrueとFalseで処理変更するとかはまだ出来ていないので変な処理になってますが気にしないでください）

省略1部分ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
import mysql.connector

config = {
    "host":"localhost",
    "port":"3306",
    "user":"root",
    "password":"",
    "database":"reservation_system"
    }

class NumError(Exception):
    pass

dbconnector = mysql.connector.connect(**config)

if dbconnector.is_connected():
    print("DBへの接続完了")
else:
    print("DBへの接続失敗")
    exit(1)

cursor = dbconnector.cursor(buffered= True)


cursor.execute("select venue_name from venue_name;")
venue_list = cursor.fetchall()


print("健康診断予約フォーム\n会場番号：会場名")
for num,name in enumerate(venue_list):
    print(num,"：",name)

省略２部分ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
        venue_num = int(input("希望の会場を指定の番号で入力してください："))
        if 0<= venue_num <= 4:
            cursor.execute(f"update employer_tbl set venue_id = {venue_num} where employer_id = {employer_id};")
            print("☆予約完了☆　　＝＞",str(venue_list[venue_num]))
            dbconnector.commit()
            break
        else:
            raise NumError()
    except ValueError:
        print("数字で入力してください")
    except NumError:
        print("指定の数字で入力してください")
新しいLinuxの教科書C4

##はじめに
Linuxはカーネルやシステムの動作設定含め、全てがファイルとして表現されている。
このためLinuxでは、ファイルを整理する入れ物である**ディレクトリ**が用意されている。

##Linuxのディレクトリ構造
・`パス`
各ディレクトリを/で区切り「/user/bin/perl」のように、あるファイルへの道筋を示すもの。

・`カレントディレクトリ`
現在位置しているディレクトリのこと。
**pwdコマンド**で確認することができる。

○`/`
ルートディレクトリ。
Linuxはこれを頂点とした階層構造になっている。

○`/bin`
ユーザーが利用するコマンドの実行ファイルを置くためのもの。
Linuxの動作に最低限必要な重要なコマンドを格納している。

○`/dev`
デバイスファイルを格納しているもの。
デバイスファイルとはディスクやキーボードなどのハードウェアを、ファイルとして扱えるように用意されたもの。

○`/etc`
設定ファイルを置くためのもの。
Linux自体やアプリケーションの設定には用意された設定ファイルを使用するため、それらが格納される。

○`/home`
ユーザー毎に割り当てられる、ホームディレクトリが配置されるもの。

○`/sbin`
/binと似ていて、実行ファイルを置くためのもの。
こちらは管理者ユーザー向けのコマンドが格納されている。

○`/tmp`
一時的なファイル(テンポラリファイル)を置くためのもの。
作業途中の結果などを保存する際にここに作成される。

○`/user`
各種アプリケーションと、それに付随するファイルを置くためのもの。

○`/var`
変化する(variable)データを置くためのもの。
アプリケーションを動作する上で作成されたデータやログ、電子メールなどが格納される。

##絶対パスと相対パス
・`絶対パス`
ルートディレクトリを起点としてパスを示すこと。

・`相対パス`
カレントディレクトリを起点としてパスを示すこと。

○`「.」`はカレントディレクトリを示す。

```
cd ./file-1　　　　#同義
cd /home/hile-1　 #同義
```

○`「..」`は親ディレクトリを示す。

```
cd ..　　　#一つ上のディレクトリへ
cd ../..　#二つ上のディレクトリへ
```

##ディレクトリの移動
カレントディレクトリを移動するには、**cdコマンド**を使う。
後ろに指定したディレクトリ**(コマンドライン引数)**に移動する。

```
cd -p /user/local
#オプション　#コマンドライン引数　
```

○引数を付けずにcdコマンドを実行すると、ホームディレクトリへ移動する。

○`チルダ展開`
~(チルダ)はホームディレクトリへのパスに置き換えられる。
これを利用すると、ホームディレクトリ配下へのディレクトリの移動が楽にできる。

```
cd ~/report　
#home/kogetsu/report
```

##lsコマンド
**lsコマンド**はファイルやディレクトリを一覧表示するもの。

○**パス名展開**
ファイル名の一部を指定し、複数のファイルを指定する機能。
・`「*」`
任意の文字列で指定。拡張子で指定するときにも使用する。

```
% ls ba*
base64 basename bash
```
・`「?」`
任意の一文字だけ指定。ba??なら「baではじまり4文字のもの」を指定する。

```
% ls ba??
bash
```

○**オプション指定**

・`-lオプション`
ファイル属性などの詳細情報を表示する。

```
 % ls -l
drwx------@  3 kogetsu  staff    96  6 12 16:02 Applications
```

・`-aオプション`
隠しファイルを含め、全てのファイルを表示する。

```
 % ls -a
.			.DS_Store		.docker			.vscode			.zshrc			Documents		Movies			Public
..			.Trash			.gem			.zsh_history		Applications		Downloads		Music			VirtualBox VMs
```

・`-Fオプション`
後ろにファイルの種類を表す記号を表示する。

「/」ディレクトリ
「*」実行可能ファイル
「@」シンボリックファイル

```
% ls -F
bin@ dev/ home/ lib64@
```