OmniAICreator/Qiita-1.07M huggingface dataset:
Lambda からのREST_APIをAPI GatewayでマッピングテンプレートでHTML変換する

### Lambda関数
```python
import boto3
from boto3.dynamodb.conditions import Key, Attr

def main(nam):
#def lambda_handler(event, context):
    region = "us-east-2"
    dynamodb = boto3.resource('dynamodb')
    table    = dynamodb.Table('testUser')
    response = table.query(KeyConditionExpression=Key('name').eq(nam))
    sites = response["Items"]
    print(sites)
    return sites
```
### API Gateway
#### マッピングテンプレート
```python
#set($inputRoot = $input.path('$')) 
#foreach($elem in $inputRoot) 
<table border="1">
<tbody>
<tr>
<td>name</td>
<td>charge</td>
<td>email</td>
</tr>
<tr>
<td>"$elem.name"</td>
<td>"$elem.charge"</td>
<td>"$elem.email"</td>
</tr>
</tbody>
</table>
#end
```
簡単ログイン機能実装

自分用にまとめます。
新規登録なしでポートフォリオを見てもらえるように実装。
user、admin両方作成

# guest userの作成

```ruby:models/user.rb

  def self.guest
    # 以下の情報を持ったユーザーを探す、または作成する
    find_or_create_by!(email: 'test@example.com', name: 'guest') do |user|
      user.password = SecureRandom.urlsafe_base64
    end
  end
```

```ruby:registrations_controller.rb

  def check_guest
    # 以下のメールアドレスのユーザーが変更や削除を行おうとした時はマイページに飛ばす
    if resource.email == 'guest@example.com'
      redirect_to user_path(user), alert: 'ゲストユーザーの変更・削除はできません。'
    end
  end
```

```ruby:users_controller.rb
  # ユーザー情報の編集や削除はできないようにusers_controllerに追記
  before_action :check_guest, only: [:update, :destroy]
```

```ruby:sessions_controller.rb
  # ログイン処理
  def new_guest
    user = User.guest
    sign_in user
    redirect_to user_path(user), notice: 'ゲストユーザーとしてログインしました。'
  end
```

```ruby:config/routes.rb

  devise_for :users, controllers: {
    sessions:      'users/sessions',
    passwords:     'users/passwords',
    registrations: 'users/registrations'
  }

  devise_scope :user do
    post 'users/guest_sign_in', to: 'users/sessions#new_guest'
  end
```

```ruby:application.html.slim
  li.btn.btn-light.home-btn= link_to users_guest_sign_in_path, method: :post, class: 'list' do
    i.fas.fa-key
    |  user guest
```

※adminも全く同じような考え方で記述していけば実装可

完成！
オンプレミス環境とAzure環境で日本語文字列が同じ順番に並ばない時

<h1>【記載理由】</h1>
オンプレミス環境とAzure環境のSQLServerManagementStudioで扱うデータを
bcpコマンド(csvファイルを出力するコマンド)でデータを吐き出す際に
日本語文字列のカラム(項目)でデータが同じ順番に並ばず出力され、
データの一致が確認できない事例が私のタスクの中で起きました。
その解決策を共有したいと思います。

[●BCPコマンドの参考リンク](https://docs.microsoft.com/ja-jp/sql/tools/bcp-utility?view=sql-server-ver15)
参考：https://docs.microsoft.com/ja-jp/sql/tools/bcp-utility?view=sql-server-ver15

<h1>【問題点】</h1>
今回タスクとして使用した環境はオンプレミスとAzureの2環境。
環境構築を統一して行っていなかった為、以下のような差異があります。

SQLServerManagementStudioのデータベースのプロパティ

●照合順序
・オンプレミス環境の照合順序が「Japanese_CI_AS」
・Azure環境の照合順序が「SQL_Latin1_General_CP1_CI_AS」

と設定されていました。

現在のプロジェクトの状況から初期段階で設定した照合順序を変更するのは、
影響範囲等を考えたりする為、工数がかかると判断が下り、
照合順序の設定を変更することができませんでした。

<h1>照合順序の設定変更が不可能。では、どうしましょう？</h1>

そこで使用したのが、
「COLLATE Japanese_CI_AS」
公式としては
COLLATE [照合順序を設定するキーワード]

COLLATEの使用可能な箇所は
where句、SELECT句の列ごと等に指定することが可能です。

指定するとその指定したものに対しての照合順序がCOLLATEで
設定した順序になります。


[参考にリンク⇐クリックしてください](https://www.projectgroup.info/tips/SQLServer/MSSQL_00000005.html)



<h3>ご覧に頂きありがとうございました。
以上です。</h3>
DropBoxの同期対象から除外する

![image05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76058/283b5635-012a-5159-beb7-d8a516a32e9e.png)

DropBoxは指定したディレクトリ内のデータをクラウドで保管してくれる便利なサービスですが、保存しなくても良いファイルまで保存されると困る場面があります。

標準機能として「選択型同期」機能がありますが、これで指定した除外対象は、同期されませんが、「同期はしたくないけどローカルには保存したい」ということが出来ません。

そこで、下記の方法で動機対象から除外する方法を試みた。

## 公式

> Dropbox ファイルやフォルダを「無視」に設定する
> https://help.dropbox.com/ja-jp/files-folders/restore-delete/ignored-files

公式には　`［dropbox.com と同期しない］をクリックします。`　とありますが、Dropbox Plus [（これ）](https://www.sourcenext.com/product/dropbox/) にはこの項目がありませんでした。

![image01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76058/e746e842-7caa-9421-2785-c2f6d0199750.png)


なので、「コマンドラインでファイルやフォルダを「無視」に設定する」項目を元に、スクリプトファイルを作って設定することにしました。

## 除外の注意

この方法は、拡張ファイル属性を利用したもので、dropbox.com上にアップロードしないというルールを追加するだけでdropbox.comに何かをするものではないようです。

**設定したデバイスでのみ働く機能**のようなので、複数のデバイスで除外する場合は、そのすべてのデバイスで同じように設定が必要です。

## Mac

1. 下記スクリプトファイルを適当なファイル名（今回はファイル名の例としてdropbox_ignore.sh）を設定して保存。
2. 保存したら、次のようにchmodで実行権限をもたせる。`chmod 777 dropbox_ignore.sh`
3. 実行すると、設置したファイルと同じディレクトリにある、スクリプト内で指定した特定のファイル・ディレクトリがdropboxの同期から除外される。

### スクリプト

Mac版とLinux版で同じスクリプトに収めました。Linux版では、`attr`をインストールする（ `apt-get install -y attr` ）必要があるかもしれません。

```bash
#/bin/bash
if [ "$(uname)" == 'Darwin' ] || [ "$(expr substr $(uname -s) 1 5)" == 'Linux' ]; then
    cd "$(dirname "$0")"
fi
echo "${PWD}"
# ここに配列で除外する項目を設定する。
# この場合、node_modulesとignore_filesファイルもしくはフォルダが除外される。
ignore_name=("node_modules" "ignore_files")

for file in ${ignore_name[@]}
do
    if [ -e $file ];then
        if [ "$(uname)" == 'Darwin' ]; then
            # Mac
            xattr -w com.dropbox.ignored 1 "${PWD}/${file}"
            echo "--- ${PWD}/${file}  is dropbox ignores ---"
        elif [ "$(expr substr $(uname -s) 1 5)" == 'Linux' ]; then
            # Linux
            attr -s com.dropbox.ignored -V 1 "${PWD}/${file}"
            echo "--- ${PWD}/${file}  is dropbox ignores ---"
        fi
    fi
done
exit 0
```

## Windows

Mac版と基本的には同じ手順だが、こちらはPowerShellで実行させる必要があります。

PowerShell内で実行させるか、実行ファイルとして実行させる場合は`.ps1`ファイルとして保存して実行させます。ただし、**デフォルトではファイルでの実行はポリシーで禁止されているので、実行できるように設定する必要があります。**

> https://techinfoofmicrosofttech.osscons.jp/index.php?PowerShellのPS1ファイルの作成と実行

### スクリプト

```powershell
# ここに配列で除外する項目を設定する。
# この場合、node_modulesとignore_filesファイルもしくはフォルダが除外される。
$files = @('node_modules','ignore_files');

for($i = 0; $i -lt $files.Count; $i++){
    $path = "$Pwd" + '\' + $files[$i];
    if (Test-Path "$path")
    {
        Write-Host "--- $path  is dropbox ignores ---";
        Set-Content -Path "$path"  -Stream com.dropbox.ignored -Value 1;
    }
} 
```

## 実行結果

実行すると、次のようにアイコンが「 - 」のバッチになります。

![image02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76058/24f7870d-72c3-7a0c-8bdc-53e995e61333.png)

## 再び同期する方法

対象のファイル・ディレクトリを右クリックして`dropbox.comに同期する`を指定すると、再び同期が始まります。

![image03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76058/0d281ef1-5b86-8ec1-760a-400ad1acb620.png)

![image04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76058/64cf76b7-ccac-edbf-38f7-9aed56bdb6f8.png)
CentOS7でのチーミング設定

# CentOS7でのチーミング設定

チーミング：複数のNICを1つのNICとしてまとめて扱う技術。チーミングされたNICの一部が欠落してもほかのNICで通信を補うことができたり、通信速度の低下を防ぐことができる。

参考記事：https://qiita.com/yunano/items/34c6b805759b7560352f

## teamdコマンドのインストール
CentOS7ではteamdコマンドはプリインストール済みだが、ない場合はインストールする。

```.bash
# yum install -y teamd
```

## チーミングされたNICを作成する。
複数のNICを束ねる仮想的なインタフェースteam0を作成する。
`runner`は`roundrobin`を用いる。
`roundrobin`ではまとめられたNICで分散しながらデータを送信するので、負荷分散が見込める。
[ネットワークチーミングデーモンおよび「ランナー」について](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/networking_guide/sec-understanding_the_network_teaming_daemon_and_the_runners)

```.bash
# nmcli connection add type team con-name team0 ifname team0 config '{"runner": {"name": "roundrobin"}}'
```

## チーミングされたNICのIPを振る。
teamによって作成される仮想的なNICのIPアドレスを192.168.0.200/24、ゲートウェイを192.168.0.1に設定する

```.bash
# nmcli connection modify team0 ipv4.method manual ipv4.addresses 192.168.0.200/24 ipv4.gateway 192.168.0.1
```

## チームの奴隷にしてやろう。
チーミング対象のNICをteam0のスレーブとして割り当てる。

```.bash
# nmcli connection add type team-slave ifname [NIC名] master team0
```

## 最終チェック
チーミング対象のNICに物理的LAN接続をしたら、ネットワークの再起動を行う。

```.bash
# systemctl restart network
```

nmtuiコマンドでチーミング対象のNICを自動接続OFFに変更し、team0のスレーブを自動接続ONに変更する。

この設定時にDNSサーバが消えているとサーバからドメインでの外部アクセスができなくなるので注意。

設定が完了したらネットワークを再起動して、反映させる。

```.bash
# systemctl restart network
```

お疲れ様でした。
MySQL⑨　複数テーブルの扱い

postsテーブル（親）

| id | title | body |
|:-:|:-:|:-:|
|  1 |  AAA | aaa  |
|  2 |  BBB | bbb  |
|  3 |  CCC | ccc  |

commentsテーブル（子）

| id | post_id | body |
|:-:|:-:|:-:|
|  1 |  1 | ABC  |
|  2 |  1 | DEF  |
|  3 |  3 | GHI  |
|  4 |  4 | JKL  | 


###共通データのみ取得　select 取得するカラム from 親テーブル join 子テーブル on 親のid = 子のカラム;

select * from posts join comments on posts.id = comments.post_id;

| id | title | body | id | post_id | body |
|:-:|:-:|:-:|:-:|:-:|:-:|
|  1 |  AAA | aaa  |  1 |  1 | ABC  |
|  1 |  AAA | aaa  |  2 |  1 | DEF  |
|  3 |  CCC | ccc  |  3 |  3 | GHI  |



###軸にしたテーブルを全て取得する

####親テーブルを軸にする　select 取得するカラム from 親テーブル left join 子テーブル on 親のid = 子のカラム;
select * from posts left join comments on posts.id = comments.post_id;

| id | title | body | id | post_id | body |
|:-:|:-:|:-:|:-:|:-:|:-:|
|  1 |  AAA | aaa  |  1 |  1 | ABC  |
|  1 |  AAA | aaa  |  2 |  1 | DEF  |
|  3 |  CCC | ccc  |  3 |  3 | GHI  |
|  2 |  BBB | bbb  |  NULL|  NULL | NULL  |



####子テーブルを軸にする　select 取得するカラム from 親テーブル right join 子テーブル on 親のid = 子のカラム;
select * from posts right join comments on posts.id = comments.post_id;

| id | title | body | id | post_id | body |
|:-:|:-:|:-:|:-:|:-:|:-:|
|  1 |  AAA | aaa  |  1 |  1 | ABC  |
|  1 |  AAA | aaa  |  2 |  1 | DEF  |
|  3 |  CCC | ccc  |  3 |  3 | GHI  |
|  NULL|  NULL | NULL  |  4 |  4 | JKL  | 



#外部キー制約
#####alter table 子テーブル add constraint 制約名 foreign key (制約をつけるカラム名) references 親テーブル (id);
alter table comments add constraint fk_comments foreign key (post_id) references posts (id);






#直前に挿入されたレコードの id を調べる

####postsテーブル（親）に新たにレコードを入れる
insert into posts (title, body) values ('new title', 'new body');

postsテーブル（親）

| id | title | body |
|:-:|:-:|:-:|
|  1 |  AAA | aaa  |
|  2 |  BBB | bbb  |
|  3 |  CCC | ccc  |
|  ４ |  new title | new body  |

####上で入れたレコードにコメントをつける　last_insert_id()
insert into comments (post_id, body) values (last_insert_id(), 'first comment for new post');

commentsテーブル（子）

| id | post_id | body |
|:-:|:-:|:-:|
|  1 |  1 | ABC  |
|  2 |  1 | DEF  |
|  3 |  3 | GHI  |
|  4 |  4 | JKL  | 
|  ５ |  4 | first comment for new post  | 





#トリガー
###あるテーブルでなんらかの変更が起きたときに、それをトリガーにして何らかの処理をする
posts テーブルにデータが挿入されたら他のテーブルにログが残るようにする
####トリガーを作る　create trigger トリガー名 処理するタイミング 変更 on 付けるテーブル 変更箇所 処理の内容;

create trigger posts_insert_trigger after insert on posts for each row insert into logs (msg) values ('post added!');


####トリガーの一覧表示
show triggers \G
####トリガーの削除
drop trigger posts_insert_trigger;






###トリガー内に複数の処理を入れる

delimiter 変更する区切り文字
create trigger トリガー名 タイミング 変更 on 付けるテーブル 変更箇所
　　begin
　　　　処理の内容;
　　　　処理の内容;
　　end;
変更された区切り文字
delimiter 変更する区切り文字



delimiter //　⬅️（区切り文字を変更する）
create trigger posts_update_trigger after update on posts for each row
　　begin　⬅️（処理をまとめる　ここから）
　　　　insert into logs (msg) values ('post updated!');
　　　　insert into logs (msg) values (concat(old.title, ' -> ', new.title));　⬅️（変更前のタイトル->変更後のタイトル）
　　end;　⬅️（処理をまとめる　ここまで）
// ⬅️（変更した区切り文字）
delimiter ;　⬅️（区切り文字を元に戻す）
Vue.jsの練習

自分用メモとして。

##結果

おなかすいた
{{ message }}


```vuejs

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.jsのサンプル</title>
</head>
<body>
    <div id="app">
        {{ message }}

    </div>

    <div id="app2">
        {{ message }}
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        // Vueというクラスを定義
        var app = new Vue({
            // el 対象となる要素を設定する
            // #app 指定するCSSと同じやり方
            el: "#app",
            // {{ message }}と紐づいている
            data: {
                message: "おなかすいた"
            }
        });
    </script>
</body>
</html>
```
データベース(DB)の初学者へおすすめリンク・サイト

<h1>データベース(DB)の初学者へおすすめリンク・サイト集</h1>

こんにちは。私がDB初学者だった際にこんなリンクの説明サイトがあれば
良いなと思っていました。

私と同じ境遇の方に参考になればと思い、リンクを共有させていただきます。


<h1>●「SQL Server 虎の巻」さん</h1>
【説明】
SQLServerにおける0からのスタートの方にお勧めです。
データベースとは何かから始まり、市販で売っている「DB初学者向け」本に
記載されている内容が網羅されています。
無料で知識が学べるので、とてもおすすめのサイトです。

＊SQLServerに絞ったタイトルに思えますが、他のデータベースでも参考になる
内容が記載されています。

●リンク
https://kaya-soft.com/sqlserver2008-toranomaki/beginner/outline/


<h1>●最後に</h1>
ご覧に頂きありがとうございます。
まだ記載内容も少ないですが、参考になるリンクがあれば追記していく形で情報を
共有して参ります。
Vue.jsについて

自分用にメモとして。

### Vue.jsについて
The Progressive JavaScript Framework

### Vue.jsの特徴
- ビューに特化
- 軽量
- Virtual DOM(仮想DOM)
- コンポーネントシステム
- 日本語ドキュメント
  
### DOMとは
- Document Object Model
- ドキュメントツリーを操作するAPI
- DOMを利用することでHTMLを自由に操作できる
- ブラウザはドキュメントツリーを作成後表示処理を行う

### 主なやつ
- Vueインスタンスを作成
- リアクティブ（js）
     dataで指定したオブジェクトはVueがプロシキする
- v-bind
    属性を反映する
- v-for
    配列の繰り返しを扱う（リストを表示するときに使ったりする）
- v-model
    入力を反映する
Pythonのクラスについて意外だったこと

# 驚いた点
以下のようなコードを想定します。

```python:sample.py
class Sample:

    sample_list = []

    def __init__(self, args1):
        self.name = args1

    def add_args(self, args2):
        self.sample_list.append(args2)
```

このコードを実行するとsample_listが**クラス変数**となるため、aとbの間でシェアされてしまいます。

```
>>> a = Sample('a')
>>> b = Sample('b')
>>> a.add_args('hoge')
>>> b.add_args('huga')
>>> a.sample_list
['hoge', 'huga']
```

このような動作が望ましい場合もあると思いますが、今回はインスタンス毎に独立した変数であってほしいため、以下のような方法でsample_listを**インスタンス変数**として宣言します。

# 解決方法
以下のようにインスタンス変数を用いてクラスを設計することで、この問題を防ぐことができます。

```python:sample.py
class Sample:

    def __init__(self, args1):
        self.name = args1
        self.sample_list = []

    def add_args(self, args2):
        self.sample_list.append(args2)
```

実行結果

```
>>> a = Sample('a')
>>> b = Sample('b')
>>> a.add_args('hoge')
>>> b.add_args('huga')
>>> a.sample_list
['hoge']
>>> b.sample_list
['huga']
```

## 参考
[クラス ― Python3.8.5 ドキュメント](https://docs.python.org/ja/3/tutorial/classes.html)
とても参考になるコメントありがとうございます！
実行時刻を記録してログを残したい。

# cronで定刻実行するスクリプトで実行時刻も記録したい

## { echo =====\`date\`=====; スクリプト; } >> ログファイル

以下解説
### { ●●●; ▲▲▲; }
括弧でとスペースで括られ、セミコロンで区切られたコマンドの出力を一つにまとめる

### echo =====\`date\`=====
現在時刻を「=」で囲んで表示。
例：=====2020年 8月 19日 水曜日 15:22:14 JST=====

### \>>
出力を追加していくリダイレクト


## ログの出力イメージ
```
=====2020年 8月 19日 水曜日 15:59:01 JST=====
(スクリプトの出力結果がここに入る)
```
i!i!←これは数式です

#問題
こんにちは，突然ですが問題です．

$$ｉ！\overline{ｉ！}=0.27$$を示せ

これはなぞなぞではありません
れっきとした数式です．特殊関数論を履修している方も一瞬数式とすら思わないかもしれません．
諸悪の根源はフォントです．$\TeX$文字で問題文を書き直すと次のようになります．

$$i!\overline{i!}=0.27$$を示せ

これなら，問題文が明確に理解できますね．
$\overline{\ }$を付けているのは，意味のある計算にするためです．
詐欺っぽいですがこらえてください．

要は，虚数の階乗の二乗を求めろということですね．

まだ問題文を解読できた段階です．
まず，虚数の階乗ってなんやねん！ってところです．
階乗って整数でしか計算ふつう計算しません．
整数では，
$$1,1,2,6,24,\cdots$$

と続く数列です．漸化式で書くと，

$$a_n=n a_{n-1}$$

となります．
階乗の概念をいきなり複素数まで拡張することは難しいので
実数にまで拡張します．

#ガンマ関数
入力が単一引数で整数であるメソッドを数列といいます．
入力が単一引数で実数であるメソッドを関数といいます．

定義域を実数まで拡張すると関数になります（そうでない場合もあるので注意）

数列の$a_j$と$a_{j+1}$を補完する滑らかな曲線を探します．
たまたま見つけたのがガンマ関数です．

ガンマ関数$\Gamma(x)$は階乗とよく似た性質を持っていることが知られています．
ガンマ関数$\Gamma(x)$は階乗の一般化といってもいいでしょう．

ガンマ関数$\Gamma(x)$の定義式をみても意味が分からないので
いくつかの性質をみてみましょう

1. 正の整数$n$に対して$\Gamma(n)=(n-1)!$
2. 正の実数$x$に対して$\Gamma(x+1)=x\Gamma(x)$
3. $\Gamma(1)=1$

これらをみれば，ガンマ関数が階乗の一般化であると納得できると思います．
２番目の事実は，階乗の漸化式といえます．
１番目は$n$が少しずれていることに気をつけましょう
３番目は初項を定めているだけです．
実はガンマ関数の入力が実数だけでなく，実部が正の複素数でもうまく計算できます．
これで$i!$を考えることができます．

ガンマ関数を少し踏み込んで勉強すると，相反公式に出会うでしょう
ガンマ関数の相反公式

$$\Gamma(x)\Gamma(1-x)=\frac{\pi}{\sin \pi x}$$

相反公式の公式証明は難しいのですが，留数定理を勉強した人は楽しく証明を読めると思います．

#問題の解答
多少天下り的な部分もありますがご了承ください．
まず，$z=ix$と置きます．
なぜ$x$をつっくけるかというと，一般の公式を作って，最後に代入すると計算がうまくいくからです．（オイラーの公式もそうでしょ）
$$|z!|^2=|\Gamma(z+1)\Gamma(z+1)|=|z||\Gamma(z)\Gamma(z+1)|.$$
ここで，
$$|\Gamma(z)\Gamma(z+1)|=\Gamma(z)\Gamma(1-z)$$
を使います．（この証明は簡単でつまらないものなので省きます）
下の式に当てはめると，
$$|z!|^2=z\Gamma(z)\Gamma(1-z)$$
また，相反公式から
$$|z!|^2=\cfrac{\pi z}{\sin \pi z}$$
$z=ix$を代入すると，
$$(ix)!\overline{(ix)!}=(ix)!^2=\cfrac{i\pi x}{\sin i\pi x}$$

となります．$\sin ix =i \sinh x$を使い，x=1を代入すると
$$i!\overline{i!}=(ix)!^2=\cfrac{\pi x}{\sinh \pi x}\mid_{x=1}$$
あとは計算機に任せば
$$\cfrac{\pi}{\sinh \pi}=0.27$$
となり，
$$i!\overline{i!}=0.27$$

示をすことができました．
ガンマ関数をテクニカルに使うと，
$$\int_0^1 x^x dx$$
なんかも計算できたりします．
vueファイル内でscssを使う（シンタックスハイライトも含め）

vueでWEBサイトを作っているとき、せっかくだからSCSSで書きたくなりました。

# vueテンプレート内でscssを使う
``` app.vue
<template>
~
</template>
<script>
~
</script>
<style lang="scss">

</style>
```
と、lang="scss"をつけてやる。
あと、sass-loaderとnode-sassをインストールしてやるだけでした。

```
npm install node-sass --save
npm install sass-loader --save
```

# Vimのシンタックスハイライトを設定
自分vimのposva/vim-vueプラグインを入れているのですが、デフォルトのCSSだとちゃんときくのに、lang設定をしたとたん、シンタックスハイライトがきかなくなってしまいました。
こちらを参考に直しました。
https://github.com/posva/vim-vue/issues/68

```
 vi ~/.vim/bundle/vim-vue/syntax/vue.vim
※プラグインが入っているディレクトリを探してください
```

``` vue.vim
let s:languages = [
      \ {'name': 'less',       'tag': 'style'},
      \ {'name': 'pug',        'tag': 'template', 'attr_pattern': s:attr('lang', '\%(pug\|jade\)')},
      \ {'name': 'slm',        'tag': 'template'},
      \ {'name': 'handlebars', 'tag': 'template'},
      \ {'name': 'haml',       'tag': 'template'},
      \ {'name': 'typescript', 'tag': 'script', 'attr_pattern': '\%(lang=\("\|''\)[^\1]*\(ts\|typescript\)[^\1]*\1\|ts\)'},
      \ {'name': 'coffee',     'tag': 'script'},
      \ {'name': 'stylus',     'tag': 'style'},
      \ {'name': 'sass',       'tag': 'style'},
      \ {'name': 'scss',       'tag': 'style'},
      \ ]
```
一番上の行にあるlessというのを、一番下に移動します。

``` vue.vim
let s:languages = [
      \ {'name': 'pug',        'tag': 'template', 'attr_pattern': s:attr('lang', '\%(pug\|jade\)')},
      \ {'name': 'slm',        'tag': 'template'},
      \ {'name': 'handlebars', 'tag': 'template'},
      \ {'name': 'haml',       'tag': 'template'},
      \ {'name': 'typescript', 'tag': 'script', 'attr_pattern': '\%(lang=\("\|''\)[^\1]*\(ts\|typescript\)[^\1]*\1\|ts\)'},
      \ {'name': 'coffee',     'tag': 'script'},
      \ {'name': 'stylus',     'tag': 'style'},
      \ {'name': 'sass',       'tag': 'style'},
      \ {'name': 'scss',       'tag': 'style'},
      \ {'name': 'less',       'tag': 'style'},
      \ ]
```
自分の場合はこれで直りました。
ただ、先ほど書いたページだと、逆にlessを一番上に持っていくことで直ったとも書いてあるので、どちらも試してみてください。

以上、vueファイル内でscssをシンタックスハイライトありで使う場合の設定でした。
Private onlyの環境からVeeam 10を利用してICOSにアクセスする方法

# 1. はじめに
VCS(VMware vCenter Sever) on IBM CloudのAdd-onサービスとしてVeeam 10をプロビジョニングすると、VMもしくはVSIでプロビジョニングされます。
これらのサーバーはPrivate only(Private IPしか持たない）ため、Internetにはアクセスできません。しかし、ICOS(IBM Cloud Object Storage)は、Public側だけでなくPrivate側にもEndpointを持っている（Private IPでアクセスできる）ので、Private側のEndpointに接続すればいいよね！って思ってたのですが、接続できません！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/1fb3467d-6436-94ba-4316-30398351a4b7.png)

- Backup Respositoryの追加<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/5aa24e92-393f-6525-40e7-c1d5b395b4d4.png)

- IBM Cloud Object Storageを選択<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/20204cc5-b4c2-1876-cdb2-473afb600397.png)
- 適当な名称を選択<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/b1cee00a-8b3c-7396-c95d-9e39ffa85b52.png)
- 下記画面でしばらく固まった後・・・・<br><img width="752" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/3de24041-a1c2-b4c2-2de1-81585e0ff445.png">
- 接続に失敗する<br><img width="753" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/63e6e6ae-1c6e-3a23-60db-eda7dbb1f89c.png">

ちゃんとTCPレベルで接続できることは確認済みです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/17f06406-dfda-c17e-6470-663a06a94b3f.png)


# 2. 結論

一般的にHTTPS通信をする場合は、証明書が適切な認証局から署名されているかどうかというチェックだけでなく、Certificate Revocation List (CRL)にアクセスして、証明書が失効していないかをチェックします。VeeamはこのCertificate Revocation Checkをデフォルトで厳密にチェックしようとするため、Internetに接続できない環境では失敗するようです。
このチェックを無効化するためのレジストリ変数があるのですが、従来はprivate fixでのみ利用可能となっていました。正式に利用するためにはVeeam10aが必要になります。

# 3. 対応方法
以下の2つのことを実施する必要があります。

## 3-1. Veeam10aの適用

https://www.veeam.com/kb3228
私の既存環境では、10.0.0.4461だったのですが、この2020/08/04に更新された最新のupdateを適用することにより10.0.1.4854になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/8e1f9893-4d30-c49e-943e-b0abd0240b13.png)


## 3-2. レジストリ変数の変更

レジストリ変数: `HKEY_LOCAL_MACHINE\SOFTWARE\Veeam\Veeam Backup and Replication\S3TLSRevocationCheck`を0に設定して、OSを再起動する。


```
#レジストリ変数の設定
C:\>reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Veeam\Veeam Backup and Replication" /t REG_DWORD /v S3TLSRevocationCheck /d 0
The operation completed successfully.

#設定の確認
C:\>reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Veeam\Veeam Backup and Replication" /v S3TLSRevocationCheck

HKEY_LOCAL_MACHINE\SOFTWARE\Veeam\Veeam Backup and Replication
    S3TLSRevocationCheck    REG_DWORD    0x0

```


# 4. 再テスト

- ここで再度テストしてみると・・・<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/29acc381-4f72-5c1c-3819-fef001644648.png)
- 次に進めた！<br>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/8995b64b-1851-d527-7d46-2205d5c77439.png)
Laravel6.0以降でjQueryを使用する方法

LaravelでjQueryを使用する時にどこから読み込むのが良いか調べました。

### laravel/uiをインストール

```
$ composer require laravel/ui
```

`laravel/ui`パッケージを追加するとbootstrap.jsでjqueryが読みこまれるようになる。

```bootstrap.js
/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

try {
    window.Popper = require('popper.js').default;
    window.$ = window.jQuery = require('jquery');

    require('bootstrap');
} catch (e) {}
```

`window.$ = window.jQuery = require('jquery');`で読み込まれる。
bladeテンプレートに`<script src="https://code.jquery.com/jquery-3.3.1.js"></script>`など書き込んで読み込ませる必要はありません。

### resorceディレクトリにjsファイルを作成

```resources/js/jquery.js
$(function () {
    $('#test_jquery').on('click', function() {
        alert("Hello, jQuery!");
    })
})
```

### LarvelMixでコンパイルして読み込む
`webpack.mix.js`に先ほど作成した`resources/js/jquery.js`をコンパイルするように書き込む。

```webpack.mix.js
mix.js([
    'resources/js/app.js',
    'resources/js/jquery.js'
    ], 'public/js')
    .sass('resources/sass/app.scss', 'public/css');
```

あとは`yarn dev`もしくは`npm run dev`で自動でコンパイルしてくれる。

```index.blade.php
<button id="test_jquery">ぽちっとな</button>
```

ボタンを作成して、クリックしてアラートが表示されたらOK。
![スクリーンショット 2020-08-19 15.40.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558877/8f0ebb37-4219-c8a4-ad1e-e341bd5a6440.png)

なるべくpublicディレクトリに置いて、直接読み込むようなことはしない。

### （おまけ）jquery-uiも追加してみる

jquery-uiをインストール

```
$ yarn add jquery-ui --dev
```

bootstrap.jsでjquery-uiを読み込む
今回は並び替えのsortable.jsを読み込んでみます。

```bootstrap.js
try {
    window.Popper = require('popper.js').default;
    window.$ = window.jQuery = require('jquery');
    require('jquery-ui/ui/widgets/sortable.js');
    require('bootstrap');
} catch (e) {}
```

jquery.jsに並び替えのコードを追加

```jquery.js
$(function() {
    $("#box").sortable({
        axis: "y",
        opacity: 0.5,
        update: function() {
            console.log('並び替えました');
        }
    });
});
```

これで動きました。
Proofreading APIで500文字以上の文章の異常検知を行う

#はじめに
Proofreading APIは文章の異常箇所を検知してくれるAPIになります．APIキーを発行し，httpsでリクエストに引数としてAPIキーと文章を渡すだけで簡単に使えます．しかし，引数として渡す文章が500文字以上の場合

```
{'status': 1500, 'message': 'server error'}
```
上記のようなリクエストがAPIから返されます．本記事の内容はProofreading APIで500文字以上の文章の以上検知をする手法についてになります．そのため，APIのわかりやすい使い方などは[参考サイト](https://sinyblog.com/django/proofreading/)を参照してください．

#参考サイト
・[文章の異常箇所を検知するLSTMを利用したAPIをDjangoで実装](https://sinyblog.com/django/proofreading/)

こちらのサイトでProofreading APIのわかりやすい使い方が紹介されています．本記事でも基本的な使い方はこちらを参考にしています．

#準備
[こちら](https://a3rt.recruit-tech.co.jp/product/proofreadingAPI/)のサイトから，APIキーの発行を行なってください．メールアドレスだけで簡単に発行できます．

また，今回は500文字以上のテキストデータを使用しますので，青空文庫が公開している[夏目漱石の「こころ」の上一](https://www.aozora.gr.jp/cards/000148/files/773_14560.html)を使用します．因みに1000文字弱でした．

#コーディング
Proofreading APIで500文字以上の文章の異常検知を行うコードを書いていきます．

```python
import urllib.request
import urllib.parse
import json
import requests

API = "https://api.a3rt.recruit-tech.co.jp/proofreading/v2/typo"
#発行したAPIキーを指定する
KEY = "" 

#ここに「こころ」の上一の文章を貼り付ける
TEXT = "私はその人を常に先生と呼んでいた。~~~~"


def proofreading_api(text):  #異常検知
    each_500_char_list=[]
    sentences=""
    for stc in text.split("。"):
        if len(sentence + stc) < 500:
            sentences = sentences + stc + "。"
        else:
            each_500_char_list.append(sentences)
            sentences = stc + "。"

    each_500_char_list.append(sentences)

    result=[]

    for text_500_char in each_500_char_list:
        values = {
        'apikey': KEY,
        'sentence':text_500_char,
        'sensitivity':"medium",
        }
        # パラメータをURLエンコードする
        params = urllib.parse.urlencode(values)
        # リクエスト用のURLを生成
        url = API + "?" + params

        #リクエストを投げて結果を取得
        r = requests.get(url)
        #一度辞書型に変換し，リスト化して追加していく
        data=json.loads(r.text)
        result.append(list(data.items()))

    return result

print(proofreading_api(TEXT))
```

やっていることとしては，500文字以上ある文章を句点で区切り文ごとにし，文頭から500文字を超える文を見つけたら，その一つ手前までの文を配列に格納しています．そうすることで500文字以内の文章が格納された配列を作り，配列の各要素を順番にAPIへ渡すことができます．APIの返した結果は一度辞書型に変換したあとで，リスト化します．

#最後に
Proofreading APIは，求人などで使われるようなテキストが推奨されているため，今回使用したような文学チックなテキストだと結構異常だと判断されます．あと，青空文庫サイトの文章をコピペするとルビまで取得してしまうので，ニュース記事とか他のデータで試すのも良いかもしれません．
手っ取り早くPostgreSQLのサンプルDBに接続確認してみる手順


Docker使って、こちらのサンプルDBをDockerのPostgreSQLに投入する手順です。

PostgreSQLそのものの機能というより、別サービスとの接続確認などで使います。

https://www.postgresqltutorial.com/postgresql-sample-database/

# 準備

```sh
# ディレクトリ作成 && 移動
mkdir pg-sample && cd pg-sample

# サンプルDBのダウンロード
wget https://sp.postgresqltutorial.com/wp-content/uploads/2019/05/dvdrental.zip && unzip dvdrental.zip
```


# コンテナ起動

```sh
PASSWORD=passw0rd
VERSION=12.4
docker run --rm -d --name sampledb \
  -p 5432:5432 \
  -e POSTGRES_PASSWORD=${PASSWORD} \
  -v $(pwd):/tmp/data \
  postgres:${VERSION}-alpine
```

# サンプルDBのデータ投入

```sh
docker exec sampledb psql -U postgres -c "create database dvdrental"
docker exec sampledb pg_restore -U postgres -d dvdrental /tmp/data/dvdrental.tar
```

# 使ってみる

`psql` で繋いでみる。

```sh
$ docker exec -it sampledb psql -U postgres
psql (12.4 (Debian 12.4-1.pgdg100+1))
Type "help" for help.

postgres=# \c dvdrental
You are now connected to database "dvdrental" as user "postgres".
dvdrental=# \d
                     List of relations
 Schema |            Name            |   Type   |  Owner
--------+----------------------------+----------+----------
 public | actor                      | table    | postgres
 public | actor_actor_id_seq         | sequence | postgres
 public | actor_info                 | view     | postgres
 public | address                    | table    | postgres
 public | address_address_id_seq     | sequence | postgres
 public | category                   | table    | postgres
```

5432ポートで繋ぐことも可能です。


```sh
$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                    NAMES
02857907c9a9        postgres:12.4-alpine   "docker-entrypoint.s…"   7 minutes ago       Up 7 minutes        0.0.0.0:5432->5432/tcp   sampledb
```

# 片付け

```sh
docker rm -f sampledb
```
FizzBuzz問題

FizzBuzz問題を解いてみました！
もっとすっきりかける気がしますがまた今度解いてみようと思います。

##FizzBuss問題
1以上100以下の整数を順に画面に出力します。

ただし、3の倍数の場合には”Fizz”、5の倍数の場合には”Buzz”、3かつ5の倍数の場合には”FizzBuzz”を、数字のかわりに画面に出力します。



```java


public class FizzBuzz {
    public static void main(String[] args) {
        for (int i = 1; i <= 100; i++) {  // forで1から100までの数でループ for (①初期化式; ②条件式; ④反復式)
            //反復式では繰り返し後に行いたい処理を書く(繰り返し時には必ずiが+1される)
            if (i % 3 == 0) {
                // 3の倍数かつ5の倍数のとき
                if (i % 5 == 0) {
                    System.out.println("FizzBuzz");
                    // 3の倍数のとき
                } else {
                    System.out.println("Fizz");
                }
            } else if (i % 5 == 0) {  // 5の倍数のとき
                System.out.println("Buzz");
                // どれにも該当しない場合
            } else {
                System.out.println(i);
            }
        }
    }
}

```
BigQueryでRedirectMissingLocation: Redirected but response is missing a location: headerのエラーが出た時の対処法

pyenvをinstallしているGCEにおいて
`bq load  xxxx`
のコマンドを叩いた時に以下のエラーが出た

```
RedirectMissingLocation: Redirected but response is missing a location: header
```

どうやら、特定のpythonのライブラリを使っていると出るらしい

[ここらへん](https://github.com/googleapis/google-api-python-client/issues/803)にissueがまとまっている


httplib2のversionを0.15.0にすればふせげるらしいので
`pip install -U httplib2==0.15.0`
したが、状況はかわらず。　

`bq` コマンドが使っているpythonのlibを変えないといけなかったが、pyenvを使っていたので
gcloudコマンドとbqコマンドのpythonをpyenvのパスに通す

```
# Use a python you have installed in a special location
export CLOUDSDK_PYTHON=/usr/local/my-custom-python-install/python
export CLOUDSDK_BQ_PYTHON=/usr/local/my-custom-python-install/python
```

参考
https://cloud.google.com/sdk/gcloud/reference/topic/startup?hl=ja

その上で、pyenvのpipのlibを見るように下記の設定を追加

```
export CLOUDSDK_PYTHON_SITEPACKAGES=1
```


これで `bq load` コマンドが動くようになった
PHP 退会機能

SessionにユーザーIDが入ってるので、そのユーザーIDをもとにDBに接続してdelete_flgを1にするだけ。
今回の場合は、user情報・退会するユーザーの登録商品・退会するユーザーのお気に入りを論理削除するので、
３つSQLが必要。
【初心者向け】初心者コーダーが陥りやすいHTML・CSSのトラップ4選

# どうも7noteです。HTML・CSS初心者は気をつけたい罠(トラップ)4選

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

https://naruweb.com/technique/trap/
運営中のサービスにペライチの独自サブドメインを設定する

# こんな状況でした

1. Google Domainsで取得したドメインで、すでにサービスを運営中。
2. ペライチで作成したランディングページを追加したい
3. 同じドメインで、ペライチと既存サービスを共存させられない(開発に時間がかかる)

解決策として、**サブドメインを作ってペライチはそちらに遷移させる**。

早速、設定していきたいと思います。

## ペライチサイド
### 1.ページ情報編集を開く

 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/9674eb2a-ed58-5491-914f-c9f7abb5719b.png)

### 2. カスタムURLに記載されているIPアドレスをメモ

13.112.187.226の部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/7bc7741e-fe74-c73d-9f36-b7301990af13.png)

## Google Domainsサイド
### 3.Google Domainsを開く

該当ドメインのDNS設定を開き、カスタムリソースレコードを編集。
例えば、`mysite.jp`というサイトを運営していて、`sub.mysite.jp`というサブドメインを追加する場合は以下で追加する。
1. 名前はサブドメイン
2. タイプはA
3. TTLは1H
4. データは2でメモしたIPアドレス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/83fe4f94-9027-3111-e04a-2832964454db.png)

## ペライチサイドに戻る
### 4.URLを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533120/e73fb6ea-8c4f-8de3-1733-5b8debb86cc8.png)

設定したらこれで完了!
Python初心者によるDjango超入門！その６　ログイン機能を実装してみた

# 本記事について
UdemyでDjangoについて学習した結果のアウトプットページです。
前の記事は<a href=https://qiita.com/sw1394/items/5d5af3356485c6980d92>こちら</a>です。

今回は、前回作成した日記アプリケーションにログイン機能を実装します。

# 成果物

### ログイン前のTOPページ（ナビバーに一覧とログインが表示されています。）
<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/5c43af6f-a9a5-4f84-88c2-ccd3015cf379.png">

### ログイン後のTOPページ（ナビバーに一覧と追加とログアウトが表示されています。）
<img width="700" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/d4dfcbed-9952-a880-b3d2-c588d412c1db.png">

### ログイン画面
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/87cfd455-0d0e-1500-b02c-dd1b1be845bd.png">


### ログアウト画面
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242659/f3cee9b6-3090-d1fb-497d-e7878b8dd2ce.png">

# settings.py
settings.pyにLOGIN_URLを追記します。
今回はadminサイトのログイン画面を流用するので、admin:loginとしましょう。
以下のコードをsettings.pyに追記します。

```settings.py
LOGIN_URL = 'admin:login'
```

# views.py
今回は、追加・更新・削除のページにはログインが必要になるよう制御をかけたいと思います。

まずviews.pyを編集します。
``LoginRequiredMixin``をimportしてください。
そしてログイン対象としたいクラスに、``LoginRequiredMixin``を継承してください。
たったこれだけでログイン機能の実装は完了です。あとはHTMLの編集です。
※``LoginRequiredMixin``はListViewなどのクラスよりも前に宣言してください。エラーになります。

```views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect, get_object_or_404
from .forms import DayCreateForm
from .models import Day
from django.views import generic
from django.urls import reverse_lazy

class IndexView(generic.ListView):
    model = Day
    paginate_by = 3

class DayCreateView(LoginRequiredMixin, generic.CreateView):
    model = Day
    form_class = DayCreateForm
    success_url = reverse_lazy('diary:index')

class DayUpdateView(LoginRequiredMixin, generic.UpdateView):
    # CreateViewとほぼ同じ内容だが、formだけでなくDayオブジェクトも渡している。
    model = Day
    form_class = DayCreateForm
    success_url = reverse_lazy('diary:index')

class DayDeleteView(LoginRequiredMixin, generic.DeleteView):
    model = Day
    success_url = reverse_lazy('diary:index')

class DayDetailView(generic.DetailView):
    model = Day
```

# base.htmlの編集
次はHTMLの編集です。

ログイン後にだけ見せたいものがある場合は、以下のif文で囲うと実現できます。
``{% if user.is_superuser %}ログイン後に見せたいもの{% endif %}``
※else文には、ログイン前に見せたいものを表示させます。

下記のように記述すると、追加とログアウトはログイン後に表示され、
ログインはログイン前に表示されます。

target="_blank"としておくと、ログイン・ログアウトが別タブで開きます。

```base.html
    <div class="container">
      <nav class="nav">
        <a class="nav-link active" href="{% url 'diary:index' %}">一覧</a>
        {% if user.is_superuser %}
        <a class="nav-link" href="{% url 'diary:add' %}">追加</a>
        <a class="nav-link" href="{% url 'admin:logout' %}" target="_blank">ログアウト</a>        
        {% else %}
        <a class="nav-link" href="{% url 'admin:login' %}" target="_blank">ログイン</a>        
        {% endif %}
      </nav>
      {% block content %}
      {% endblock %}
    </div>
```

# 動作確認
py manage.py runserverで動作確認してください。
更新・削除ボタンをクリックすると、ログイン画面に変移するかと思います。
e2eテストのTestCafeで APIをモックする方法


e2e（end to end）テストを実装できるフレームワークであるTestCafeにおいて、APIをモックする方法についてです。

コードは以下のようなケースを想定しています

* メールアドレスを入力して登録するあるページがあるとします。
* メールアドレスの重複チェックがAPI経由でなされるパターンで、テストにおいてはそのチェックが不要である場合、mockを差し込む
    * 私の環境では、テスト上で絶対に不要というわけではなかったのですが、APIからなぜか419 unknown statusが帰ってきてしまってエラーで落ちるので一旦mockにしました

```javascript

import { RequestMock, Selector } from 'testcafe'

// モックの動きを先に登録しておきます
const mock = RequestMock()
  .onRequestTo(/.*\/user\/registrable_email/)
  .respond({ can_register: true }, 200)

// テスト対象ページの設定などをするfixtureでrequestの時にhookとしてmockを差し込みます
fixture('登録ページ')
  .page(`http://localhost/simple_register`)
  .requestHooks(mock)

// 通常通りテストを書きます
test('登録して登録完了ページに遷移', async (t) => {
  await t
    .typeText(Selector('input[name="email"]'), 'test@example.com')
    .expect(t.eval(() => document.location.href))
    .match(/.*register_completed/, { timeout: 10000 })
})
```

expect の書き方については @zackey2 さんの[こちらの記事](https://qiita.com/zackey2/items/2f862982a3030e38afda)が参考になります。
AWS ECSでのPermissionエラー解決メモ

## 環境
- Laravel
- ECS
- ECR
- Docker

## エラー
laravel.logを開けない。

## 解決方法
ローカルでchmod実行。(下記コマンド)
docker build後、ECRにプッシュ。

```
chmod -R 777 [権限付与するディレクトリ]
```
Paizaのスキルチェック過去問「みんなでしりとり」を解いた話

がんばりました。
こちらは公開OKのやつです。
##書いたコード
```python:shiritori.py
# coding: utf-8

N,K,M = [int(i) for i in input().split()]
d_dict = {input() for i in range(K)}
m_list = [input() for i in range(M)]
n_list = [i+1 for i in range(N)]

n = 0
flg = 0

for i in range(len(m_list)):
    z = ""
    if m_list[i] in d_dict:
        d_dict.remove(m_list[i])
        if m_list[i][-1:] == "z":
            z = n_list[n]
            flg = 0
        elif flg == 1 and m_list[i-1][-1:] != m_list[i][:1]:
            z = n_list[n]
            flg = 0
        elif flg == 0:
            flg = 1
    else:
        z = n_list[n]
        flg = 0
    if flg == 1 or n == len(n_list)-1:
        if n >= len(n_list)-1:
            n = 0
        else:
            n += 1
        
    if z != "":
        n_list.remove(z)

print(len(n_list))
for i in n_list:
    print(i)
```
##解説的ななにか
コード汚くてすまない…
###最初の定義部分
最初の3行はInputされるやつをそれぞれ格納しているだけです。
`d_dict`で使ってもいい単語リストを格納(dictって書いてるけどこれ辞書型じゃなくね？)
`m_list`で発言されたものをリスト化
`n_list`で参加者の管理

`n = 0`は発言者の順番を管理するやつ
`flg = 0`は最初の人かどうかを管理するフラグ(0=最初の人、1=2番目以降の人)
###For文部分
for文は`m_list`を主軸にしました。
このとき、`for i in m_list:`としないのがポイント。
コレをやると、条件である

>最初の人以外の発言の頭文字は、直前の人の発言の最後の文字と一緒でなければならない。

の比較ができなかった。
####発言と単語リストの比較
`if m_list[i] in d_dict:`で、発言した単語が単語リストにあるかどうかを調べます。
ヒットすれば、単語リストから該当単語を`d_dict.remove(m_list[i])`で削除します。
こうすることで、二重発言のチェックとそもそもリストにない単語を同時に見ることができます。
ヒットしなければ、無条件で発言者を脱落させ、`flg`を`0`(最初の発言者)にします。
脱落者の処理については後述します。
####末尾にzが含まれていないか確認
`d_dict`に含まれていてもzで終わる単語はNG扱いとなっているので、含まれていれば脱落させます。
末尾だけみればいいので、`m_list[i][-1:] == "z"`の`[-1:]`部分で末尾だけスライスします。
コレは後述の末尾と先頭を比較する際にも使うテクです。
####一個前の末尾と今の先頭の文字を比較する
まず、`m_list[i-1][-1:] != m_list[i][:1]`部分の解説をします。
この部分は前の単語と今の単語の末尾と先頭を比較するものです。
前述した`for i in m_list:`としない理由がこれです。
単語を直接ぶちこむと比較できなくなってしまうため、`for i in range(len(m_list))`としたのです:smirk:
スライスについてはもっと良い解説をしている方がいるはずですので、そちらで。
このまま使用すると、間違えた次の人にも適用されてしまうため先頭じゃないフラグ`flg=1`の人のみを対象とするため、`flg==1`を追加して以下とします。
`flg == 1 and m_list[i-1][-1:] != m_list[i][:1]`
####次の人へ
一折見終わったら次の人へパスします。
パスするには単純に`n += 1`をすれば回せます。
が、ここで2つ問題が発生します。
1つ目が、最後まで回ったときどうするのか。
2つ目が、脱落者の部分をどうするのか。
それを一気に解決するのが次の部分です。

```python
if flg == 1 or n == len(n_list)-1:
    if n >= len(n_list)-1:
        n = 0
    else:
        n += 1
```

1つ目については
`n`が`len(n_list)-1`と同じになったら`0`にすることで解決します。
これ2個めのifいらないのでは…？
2つ目の部分については、
脱落させると順番がズレます。
次の人が今の`n`の位置に収まるので実は何もする必要がないです。
それ以外の場合`n += 1`します。

####脱落者の処理
脱落処理で`z`に脱落者番号を格納しておき、その都度処理します。

```python
if z != "":
    n_list.remove(z)
```
####出力
最後に出力して終わりです。

```python
print(len(n_list))
for i in n_list:
    print(i)
```

##最後に
重複の管理と参加者の管理がミソなのかなと思います。

もっとこうしたらいいよっていうのがあったら教えて下さい
PHPでログイン機能

# ログイン機能
1. POSTされてきた値を確認する
2. 変数に格納
3. バリデーション
4. エラーが無ければ例外処理を用いてDB接続
5. SQLを準備（Emailが同じもののpasswordとidを取得する）
6. プリペアドステートメントで値を入れる
7. クエリを投げる
8. ログイン有効期限をセットする（ログイン保持にチェックがあれば30日に延長）
9. ユーザーIDと最終ログイン日時を入れる
10. マイページへ遷移
pyfof を用いて FoF(friends-of-friends) アルゴリズムを試す方法

# FoF(friends of friends) アルゴリズムとは

アルゴリズムは超単純で，パラメータはたった一つで，それを敷居値 r とします．

1. 空間内にN点あったときに，その中のとある一点に着目します．その一点から残りのN-1点までの距離を計算して，r 以下のものは friend と判定します．
2. 次に，別の一点に着目して同じ計算をします．もし，先に決めたfriendと共通のものがあるなら，friend を追加します．もし，全く共通の要素がなければ，あたらしいfriendの族を生成します．
3. これを繰り返すだけです．

## pyfofのインストール

[pyfof](https://github.com/simongibbons/pyfof) は，フレンド-フレンドクラスタリング (Friends of Friends cluster finding) を python で高速で可能にしたライブラリです．単純に，friends-of-friends algorithm を実装したのではなくて，[R*-tree](https://en.wikipedia.org/wiki/R*_tree) という方法で高速化を可能にしたようです(詳細は把握してません)．

インストールは，

``` bash:
pip install pyfof
```

だけでOKでした(@ google colab, 2020.8.19)

## 実行例

``` python:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import pyfof

npts = 10000
ndim = 2
nptsperdim = int(npts/ndim)
data = np.vstack((np.random.normal(-1,0.2,(nptsperdim,ndim)),\
                  np.random.normal(1,0.2,(nptsperdim,ndim))))

groups = pyfof.friends_of_friends(data, 0.4)

colors = cm.rainbow(np.linspace(0, 1, len(groups)))
for g,c in zip(groups, colors):
    plt.scatter(data[g,0], data[g,1], color=c, s=3)

plt.show() 
```

とすると，

![スクリーンショット 2020-08-19 14.23.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/49c06945-956e-4305-2bcc-e690ad2b6fb6.png)

のように，綺麗に２つにクラス分けできます．


次に，もう一つのクラスを真ん中に入れてみるとどうでしょう？

``` python:
npts = 10000
ndim = 2
nptsperdim = int(npts/ndim)
data = np.vstack((np.random.normal(-1,0.2,(nptsperdim,ndim)),\
                  np.random.normal(1,0.2,(nptsperdim,ndim)),\
                  np.random.normal(0.,0.2,(nptsperdim,ndim))))

groups = pyfof.friends_of_friends(data, 0.4) # 0.4 だと大きすぎで，全部同じクラスに分類されてしまう．

colors = cm.rainbow(np.linspace(0, 1, len(groups)))
for g,c in zip(groups, colors):
    plt.scatter(data[g,0], data[g,1], color=c, s=3)

plt.show()
```

そうすると，全部同じ色，つまり，同じ一つのクラスになってしまいました．

![スクリーンショット 2020-08-19 14.25.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/65338c49-6c28-86f0-e7bd-d11b9075762b.png)


では，少し範囲を変えて，

``` python:
npts = 10000
ndim = 2
nptsperdim = int(npts/ndim)
# ガウシアンのシグマを小さくする．
data = np.vstack((np.random.normal(-1,0.1,(nptsperdim,ndim)),\
                  np.random.normal(1,0.1,(nptsperdim,ndim)),\
                  np.random.normal(0.,0.1,(nptsperdim,ndim))))

groups = pyfof.friends_of_friends(data, 0.2) # 0.2して少し基準を小さくする．かつ，上のシグマを小さくした．

colors = cm.rainbow(np.linspace(0, 1, len(groups)))
for g,c in zip(groups, colors):
    plt.scatter(data[g,0], data[g,1], color=c, s=3)

plt.show()
```

みると，

![スクリーンショット 2020-08-19 14.27.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179652/72ee14de-5d82-a62a-7ed3-6ac139a33544.png)

ちゃんと３つのクラスに分類されました．ガウシアンのシグマを小さくして，判定基準を 0.4 から 0.2 に小さくしたためです．

コードは [google colab](https://colab.research.google.com/drive/1ozMdhDpGd8uns2GIPloPtDZYWqM5KU5S?usp=sharing) でも閲覧可能です．
PHPでユーザー登録

# ユーザー登録の処理フロー
1. POST送信を確認する
2. POST送信されて来た値を変数に代入する
3. 各種バリデーションを行う
    4. Email重複チェックはDBに接続し、同じEmailが登録されていないか確認する
4. 例外処理を用いてDB接続する
5. SQLを用意する
6. プリペアドステートメントで値を入れる。現在時刻は`date('Y-m-d H:i:s')`として入れる
5. クエリがきちんと投げられていた場合、ログイン有効期限を1時間にし、最終ログイン日時を現在時刻に更新
6. SessionにユーザーIDや最終ログイン日時・ログイン有効期限を格納する
6. headerでマイページへ遷移
GitHub Actions local action の実行

## local action の実行

public action ではなく、リポジトリ内に定義したprivate なactionを実行する

ファイルは下記のような感じで配置

```text
.github/
├── actions
│   └── hello
│       ├── action.yml
│       └── index.js
└── workflows
    └── hello.yml
```

### action の定義と script


```yaml
# .github/actions/hello/action.yml
name: "Hello World"
runs:
  using: "node12"
  main: "index.js"
```

* node は node12 のみっぽい
* package.json は使えないぽい
    * node_modules/ 以下も登録する必要がある ?
    * https://www.kaizenprogrammer.com/entry/2019/10/15/071636#node_modules-%E3%81%AE%E7%AE%A1%E7%90%86

```js
// .github/actions/hello/index.js
console.log("Hello, World!");
```
### workflow の定義


```yaml
# .github/workflows/hello.yml
name: Hello
on: push

jobs:
  hello:
    runs-on: ubuntu-latest
    name: Hello
    steps:
      - name: Checkout
        uses: actions/checkout@master
      - name: run hello action
        uses: ./.github/actions/hello
```

* checkout がないとだめ
    * 下記のようなエラーが出る
    * Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/xxx/xxx/.github/actions/hello'. Did you forget to run actions/checkout before running your local action?
Vivado v2019.1 > Windows(ホストOS)とUbuntu(ゲストOS) > それぞれでのRun Implementationの処理時間 > ゲストOSでも遅くない

```txt:動作環境
ホストOS:
メモリ32GB, Core i7-6700K 4.0GHz
Windows 10 Pro v1909
Vivado v2019.1

ゲストOS:
メモリ8GB, プロセッサ2(x コア2)
Ubuntu 18.04 LTS
Vivado v2019.1
```

### 概要

- Vivado v2019.1にてSlideSWをLEDとつなげるBlock DesignのRun Implementationまでの時間を計測
- Windows, Ubuntuともに同じような処理時間だった


### 計測

- [PYNQ > PL > IP: concat > 一つの入力(Slide SW)を一つの出力(RGBLED_R)につなげる](https://qiita.com/7of9/items/147a8092b5b61f8ba31f)

1. リンクで作成したtclファイルをsourceで読み込む
2. Create HDL Wrapperをする
3. Run Implementationをして、処理が終わるまでの時間を計測する


### 結果

- 一回目
    - Windows (ホストOS): 3分07秒
    - Ubuntu (ゲストOS): 2分06秒
        - Launch runs on local host: Number of jobs = 4とした
- 二回目
    - Windows (ホストOS): 2分41秒
    - Ubuntu (ゲストOS): 2分07秒
        - Launch runs on local host: Number of jobs = 4とした

ゲストOSでも処理が遅くならない。むしろ、少し速いか。

ゲストOSにてプロセッサ数を増やして、jobs=6で処理してみたが、同じように2分07秒だった。


### jobs=1

ゲストOSの処理において、jobs=4とjobs=1の違いは気になった

- jobs=4: 2分7秒
- jobs=1: 2分7秒

並列化してない。
基本情報技術者試験　覚える事[随時更新]

すまんな、自分用やから適当やで。

##2の補数
先頭が1でnビットすべて0(2^n)から引いた値

- 2の補数の直したりするやつ
    - 正数から負数：反転して＋１する
    - 負数から正数：-1してから反転
    - 11111111が-1であるので　それに00000001がどうすれば反対になるかを考える　逆は順序も逆


##算術シフト
乗算：空いたところに0を入れる
除算：符号ビットと同じものを入れる


##相対誤差

$ \frac{絶対誤差}{真の値} $

なんかすげえ数式ちっさくなるけどどうにかならんのか


##XOR
2ビットの時両方が1、または両方が0の時に0　それ以外は1

##等差数列の一般項

$ a_n = a_1 + d(n-1) $

##等比数列の一般項

$ a_n = a_1 \times r^{n-1} $

##階差数列の一般項

n≧2のとき

$$ a_n = a_1 + \sum_{k=1}^{n-1}(b_k) $$

バブルソートのときのデータの個数と比較回数のやつ
☆データの個数と第n項のnは数が1つずれてるので、出てきた数式のnはn-1に変換する。
　第1項：データの個数n　＝　1：2
　第2項：データの個数n　＝　2：3
　第3項：データの個数n　＝　3：4
　第4項：データの個数n　＝　4：5
　第5項：データの個数n　＝　5：6
　※n個のデータの数の比較回数を見たいときは数列でいうと1つ前の項を見るってこと


##Σの公式

$$ \sum_{k=1}^{n}(a) = na $$
$$ \sum_{k=1}^{n}(k) = \frac{1}{2}n(n+1) $$
$$ \sum_{k=1}^{n}(k^2) = \frac{1}{6}n(n+1)(2n+1) $$
$$ \sum_{k=1}^{n}(k^3) = \bigl[ \frac{1}{2}n(n+1)\bigr]^2 $$
$$ \sum_{k=1}^{n}(ar^{k-1}) = \frac{a(1-r^{n})}{1-r} = \frac{a(r^n-1) }{r-1} $$
最後のやつはnけたの文字列の種類を調べる事ができる。

これ数式左寄せとかできへんのか、勘弁してくれ


##MIPS……Million Instruction Second
意味の通り1秒間あたりの命令数(単位がは100万)
百万秒あたりの命令数とかCPUのクロックとかの問題の時にでてくる。
分母を百万で考えるとか参考書がわけわからん事言ってたけど、これ覚えとけばいいと思った。

##数字・単位系

- $ 100万= 10^6 $
- $ K = 10^3  ≒ 2^{10} $
- $ M = 10^6  ≒ 2^{10} $
- $ G = 10^9  ≒ 2^{30} $
- $ T = 10^{12} ≒ 2^{40} $

- $ m = 10^{-3} $
- $ μ = 10^{-6} $
- $ n = 10^{-9} $
- $ p = 10^{-12} $
  ※nをよく忘れる

- $ 2^8 = 256 $
  だから255は2進数表記で全ビット１の8桁

- 240は2進数で"11110000"


##ド・モルガンの法則

1.
$ \overline{A・B} = \overline{A} + \overline{B} $

2.
$ \overline{A+B} = \overline{A}・\overline{B} $

×はかつと一緒、＋はまたはと一緒　冷静に考えればわかる

##LRU……Least Recently Used
参照されてから

##逆ポーランド記法

###逆ポーランド記法→中置記法
[文字,文字,演算子]の組み合わせになっているところを探して、1つ1つ処理する。
参考URL：https://www.fe-siken.com/kakomon/21_aki/q3.html

###中置記法→逆ポーランド記法
優先順位の高いところから任意の文字(kとかlとか)に変えていって、
最終的に戻す。
参考URL：https://spica.co.jp/it-school/cloud-notes-it/commentary/os-39/

##ロールバック・ロールフォワードの違い
ロールバック：戻すだけ
ロールフォワード：戻して計算して直前の状態に復帰させる

##射影：列を取り出す演算

##スタブとドライバ
- スタブ：下位モジュールの代わり
- ドライバ：上位モジュールの代わり
のぶを 「拡張」 #OAuth #PKCE #瑛人

夜中にいきなりさ　ログインできないのってLINE
コードはもう3年くらいいじってないのにどうしたの？
あの頃　OAuthはさ　なんでもできる気がしてた
2人でドラフト読んでは　たくさんサンプル作ったね

でも見てよ今の実装を
独自SchemaなCallbackを
eKYCしても　JWTに署名しても
別アプリに取られるんだ

別にPKCEを求めてないけど　Challenge送られると思い出す
君のYouTubeアプリのCallback Schemaのせいだよ

今更ログインしてさ　僕は何をつぶやいたらいい？
「流行りになったね」口先でしか言えないよ
どしたの　いきなりさ　リクエストまで署名しだして
そこじゃないそこじゃないんだよ　アプリが変わっただけだから

でも見てよ今の実装を
DeeplinkのCallbackを
Webに嘘ついてアプリ起動して
涙ひとつもでなくてさ

別にPKCEを求めてないけど　Challenge送られると思い出す
君のYouTubeアプリのCallback Schemaのせいだよ
別にGNAPをまた好きになることなんてありえないけど
君のYouTubeアプリのCallback Schemaが思い出させる

何もなくても　1.0aの頃に
戻りたいとかは思わないけど
拡張群を見ると思う

別にPKCEを求めてないけど　Challenge送られると思い出す
君のYouTubeアプリのCallback Schemaのせいだよ

別にGNAPをまた好きになるくらい君は素敵なAPI
でもまた同じことの繰り返しって
Editorブチ切れんだ

## References
* [香水 / 瑛人](https://youtu.be/9MjAJSoaoSo)
  * [香水／瑛人　MV再現 (covered by 瑛肩)](https://youtu.be/lDur3mBHXSI)
  * [香水 - 瑛人 / 藤森慎吾 Rap ver.【個人的な感情込みで歌ってみた】](https://youtu.be/FMFpEV1mQIo)
  * [その他のカバー達](https://www.youtube.com/results?search_query=香水+カバー)
  * [瑛人「香水」はなぜ異例のヒットとなったのか？　その成功が持つインパクトとは](https://news.yahoo.co.jp/byline/shibatomonori/20200629-00185128/)
* [PKCE](https://tools.ietf.org/html/rfc7636)
* [OAuth拡張群](https://tools.ietf.org/wg/oauth/)
* [いままで作ったサンプルアプリ群](https://github.com/nov?tab=repositories&q=sample)
* [のぶを「拡張」歌ってみた #OAuth #PKCE #瑛人 - YouTube](https://www.youtube.com/watch?v=oVLqs43pseo)
リファクタリング_メモ_20200819

#リファクタリング



**１．プログラム改善について**

　　プログラム開発はとても複雑な行為で、試行錯誤を行いながら進めます。
　　その方法はさまざまで、レビューを開いてどこを改善すべきか、このまま開発を進めてよいかなどを
　　お客さんに確認して進めたりします。

　　また、期限、締め切りが迫っているなどの理由で「好ましくないが手軽な書き方」をあえて
　　選択しなければいけないこともあるでしょう。
　　※期限を守ることを最大限努力してもダメな場合


　　ですから、**意識せずに放っておくと開発中のプログラムはどんどん複雑になってしまいます。**
　　後から見ると、自分でも「なんでこんなわかりにくいコードを書いたんだろう？」と思うことは、
　　熟練したエンジニアでも決して珍しくありません。
　　同じようなクラスをコピペで増やしていって後で修正が大変になる、などがその例ですね。

　　しかし複雑なコードになればなるほど修正も大変です。
　　複雑なプログラムほど最初は軽微なものでも、時間がたつとともにどんどん雪だるまのように
　　複雑さが増えて最後には手をつけられないようになります。
　　→そのためだけに凄腕のエンジニアを雇うとなれば企業も大変ですね。

　　そこで、時々コードを見直して改善をする**リファクタリング**という活動が推奨されています。

複雑なプログラムを・・・

　　＜放っておくと＞

　　・コードがぐちゃぐちゃでわけがわからなくなる
　　・作成者、設計者以外が見たときにわかりずらくなる
　　・処理設計から離れてしまい違うものになることもある


　　＜こまめに改善すると＞

　　・コードはいるもののみ残っているので見やすくなる
　　・他チームの人や作成者と設計者以外の人が見ても内容が入ってきやすい
　　・設計に即したものが完成する


**２．リファクタリングとは**

　　厳密には、リファクタリングとは「**外部から見た動作、仕様を変えずに内部構造を改善すること**」を
　　さします。

　　例えばtestクラスをリファクタリングする場合、testクラスを呼び出す別のクラスに大きな影響が及ぶような
　　修正(メソッドの動作内容が全く別のものになるような変更等)は行いません。

　　リファクタリングという言葉は特殊な書き方というよりは、活動のことを指しています。

　　リファクタリングという概念が生まれる前は、作成済みでいちど正常に動作したプログラムは
　　触らないほうが良いという考えが浸透していました。
　　なぜなら修正してバグが出た時に修正作業がプロジェクト全体に広がって収集がつかなくなる
　　可能性があるからです。

　　しかし、プログラム開発には仕様変更や要求が変わることは日常茶飯事であり、
　　そのためにリファクタリング活動が次第に広がっていきました。

**３．代表的なリファクタリング活動**

　　以下のようなものが代表的なリファクタリングです。

　　①**重複部分を１か所にまとめる**
　　コピペしたなどの理由で似たようなコード部分が複数の箇所に出てくる場合、
　　それを１つのメソッドにまとめて呼び出せるようにしたりします。

　　②**メソッドやクラスを分割する**
　　大きく複雑になりすぎたメソッドの一部を、別メソッドとして切り出します。
　　通常、privateメソッドとして切り出すことが多いでしょう。

　　③**外部ライブラリや新しいJavaのバージョンの文法を利用する**
　　たくさん行数を使って書いた処理も新しく登場した外部ライブラリや新しい文法を使うことで
　　シンプルになることがあります。
　　もちろんライブラリは使ってよいもののみ使用しましょう。



**４．リファクタリングの注意点・デメリット**

　　基本的に、リファクタリングはどんどん行ったほうが良い「良いこと」です。
　　しかし、リファクタリングを行うのも時間(=コスト)がかかります。
　　ですから、かかるコストを上回るメリットが得られそうにない場合は、
　　「保守性が低いコードであっても、あえてリファクタリングすべきでない」場合があります。

　　**注意点①　納期直前はリファクタリングのメリットが得られにくい**

　　期限が目の前まで迫っている状況でリファクタリングしても、そのあとすぐに製品が
　　完成してしまえば「修正が容易になる」というメリットを生かせません。
　　これは完璧にしてからリリースしたいと考えている筆者からするとあまりよくなさそうですが。
　　→やったほうが良いのでは・・

　　納期ギリギリだと要するにテストなど検証業務をきちんと行うほうが良いケースも多いということですね。
　　
　　**注意点②　むやみにやらない、やりすぎない**

　　テストと同様、リファクタリング活動もやろうと思えばきりがないような無限にできてしまう活動です。
　　それに、リファクタリング時点では完璧と思えるまで突き詰めて考えた設計も数か月後に見れば
　　最適でない可能性もあります。

　　時間は無限ではありませんので、コストや手間が無駄にならないよう、適度にリファクタリングを
　　行うのが大事ですね。
Macでバイナリファイルの内容比較

サイズが1バイトだけ異なる２つのバイナリファイルの違いを知りたかったので、以下を行いました。テキストファイルだったら単純にdiffとかvimdiffとかでできるんだけど、それに近いことをバイナリファイルで確認したいなと。

自分の環境はMacですが、Windowsでもほぼ同じことができそうです。と言うかWindowsならバイナリファイル同士の比較のソフトがありそうですね。

まず最初にcmpコマンドで二つのファイルを比較。これはdiffのバイナリバージョンで、何バイト目が異なっているのかを教えてくれます。

```bash

$ cmp yumin.z yumin2.z
yumin.z yumin2.z differ: char 5578418, line 21732
```
ふむふむ、5578418バイト目ね。これで異なっている位置が分かりました。
今度はバイナリエディタでこれらのファイルを開いてみましょう。

Hex Fiend
https://apps.apple.com/jp/app/hex-fiend/id1342896380
上記はMacのApp Storeですが、Windows用もググれば出てきます。これを自分のマシンにインストールします。

で、今度はバイナリファイルをHex Fiendで開きます。開いたら、メニューの
「Edit」→「Jump to Offset ⌘L」で出てくる窓に、上記の異なるバイト`5578418`を入力して「Move」あるいはエンターを押すと、画面はその箇所に移動します。
![HexDiff.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35345/e75d6d95-5cb2-59e9-0763-c281f29e73a9.png)
もう一つのファイルに対しても同じことを行い、メニューの「Window」から異なる方のファイルを指定したり、`⌘+F1`または`⌘+fn+F1`で画面を切り替えたりすると、値を比較できます。
![HexDiff2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35345/32f11d51-1e2f-ca9f-1848-1d8e3f862fea.png)
この時、２つのウィンドウのサイズや位置をぴったり合わせておくと、`⌘+F1`または`⌘+fn+F1`での比較が楽そうですね。

他にもMacで良さそうなツールがあったらぜひ教えてください。

これのおかげで、Gitが改行コードをLF（0A）からCRLF（0D0A）自動変換してるせいで、（今回は１バイトの）違いが生じてしまったのに気づけました。.gitattributesはちゃんと書かないとね！