OmniAICreator/Qiita-1.07M huggingface dataset:
Docker初心者がjsファイルをDocker hubにpushしてみた（M1 Mac使用）

DockerhubにjsファイルをpushしECSでログを表示させるまでの過程を説明します。

#1. 実行するフォルダ作成

```
cd desktop
mkdir js-docker
cd js-docker
npm init　（Enterの連打）
npm install
touch Dockerfile
```
作成したフォルダ『js-docker』を開いてjsファイルを作成してください。

```
js-docker
   　　|- index.js
   　　|- Dockerfile
   　　|-package.json
```

```erb:Dockerfile
FROM node:14.4.0-buster

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies (package.json and package-lock.json)
COPY package*.json ./
RUN npm install

# Bundle app source (server.js)
COPY . .

# Listen port
EXPOSE 8080

# Run Node.js
CMD [ "node", "index.js" ]

```
```erb:package.json
{
  "name": "hello",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "4.17.1"
  }
}
```
入力後 npm install

```erb:index.js
console.log("hello")
```
ひとまず「Hello」と表示させます

#2. Dockerにイメージを作成
本来はこちらでBuildするようですが。。。

```
docker build -t docker-js .
```

M1macを消していて、AWSのECSで使用する際にエラーが出たのでこちらでBuildしました。

```
docker build --platform amd64 -t docker-js .
```

これを実行するとデスクトップのDockerのimagesに表示されます。
確認してみましょう！

```
docker images
```
```
REPOSITORY           TAG       IMAGE ID       CREATED              SIZE
docker-js           latest    4b4fd40e9d9c   About a minute ago   861MB
```
追加されています！

```
docker run docker-js

=> hello
```
大丈夫そうです！

#3. Docker hubにpush
次にDocker hubにpushします。

```
docker tag 9374g689ss65 takeshi/docker-js:latest  
```

```
docker push takeshi/docker-js
```

Dockerhubにログインすると現在pushしたものが追加されています。

```
docker run takeshi/docker-js
```
これでうまく動きますと成功しています！

https://hub.docker.com/

#おまけ　M1 mac docker error: exec user process caused "exec format error"　の解決策

ECSでエラーが起こった際にこちらの記事で解決しました。

https://qiita.com/keita_ogawa/items/e115c46f1c8caf6fd34d

#おまけ　docker環境構築
初心者なのでDockerの環境構築から始めます。
Docker Desktopのダウンロード

https://amateur-engineer.com/docker-mac-m1/

#参考にしたもの

jsを動かせた記事

https://nodejs.org/ja/docs/guides/nodejs-docker-webapp/

その他

https://docs.docker.jp/v17.06/docker-for-mac/step_four.html

https://qiita.com/umi/items/d4b5a68263ad0444693b
aws s3コマンドのexcludeに関するメモ

パスの先頭を"/"にしてもバケットのルートからの意味にはならない。
バケットのルートから指定したい場合でも、"/"抜きでパスを開始しなければならない。
パスはcpコマンド（rsyncも同じかな？）のコピー元（src）からの相対で指定しなければならない。
PHP 関数定義

#関数定義

```PHP:エディター
/**
    整数xを受け取り、xの2乗を返す関数を作成。
**/
<?php

function square($x){
    return $x * $x;
}

//関数の呼び出し
echo square(2) . PHP_EOL;

//式
echo (square(4) + 10) . PHP_EOL;

// 2つの数を受け取り、引き算を行う関数
function subtract($x,$y){
    return $x - $y;
}

// 3
echo subtract(5,2) . PHP_EOL;

// -5
echo subtract(10,15) . PHP_EOL;

// 2つの数を受け取り、掛け算を行う関数
function multiply($x,$y) {
    return $x * $y;
}

// 10
echo multiply(5,2) . PHP_EOL;

// 150
echo multiply(10,15) . PHP_EOL;
```

#ステートメント
ステートメントとは、命令や宣言等の、実行されるコードのまとまりのことを指します。ステートメントの終了にはセミコロン；を使用。

#関数定義
```PHP:
<?php
// 縦、横、高さを受けとって、立体の体積を計算するboxVolumeという関数を作成してください
function boxVolume($l,$w,$h) {
    return $l * $w * $h;
}

// 関数の呼び出し＆コンソール出力
echo boxVolume(2,3,5) . PHP_EOL;
```
```php:
// 半径、高さを受け取って、円柱の体積を計算するcolumnという関数を定義
// 円周率は3で計算してください。
function column($r,$h) {
    //戻り値を設定してください。
    return 3 * $r * $r * $h;
}
// 半径2、高さ5を関数に入力して、コンソールに出力してみましょう。(60)
echo column(2,5) . PHP_EOL;
```

```php:
// 上底、下底、高さを受け取って、台形の面積を返す、trapezoidという関数を定義

function trapeozoid($a,$b,$h) {
    return ($a + $b) * $h * 0.5;
}
// 上底3、下底5、高さ6を関数に入力して、コンソールに出力してみましょう。(24)
echo trapeozoid(3,5,6) .PHP_EOL;
```
テンションが下がった時、やる気が出ない時にやること

生きているとどうしてもネガティブなイベント※ が発生して仕事に集中できない、やる気が出ないと感じるケースがあると思います。

※例:

- 社内でコミュニケーションがうまく行かなかった :upside_down_face:
- 自分の提案が通らず、ショックを受ける :dizzy_face:
- 生きがいのアニメが最終回を迎え、次週から見れない :sob:
- 健康診断で尿酸値が基準値を超えた :beers:

これって大体気づいたら解消しているんですが、もっと早く気持ちを切り替えたいので「自分がネガティブな感情をどうやって乗り越えてるのか？」を思い出しつつ整理してみました。

# 気分転換手法とその効果(感覚値)

### 場所を移動する、体を動かす
自席に座って黙々と作業すると気分の切り替えが上手くいかないので、コンビニに飲み物を買いにいったり、気分転換のため少し散歩するなどで気分転換を図る。

だが、自分の場合は何もしないと悪いイメージが浮かんできちゃうので、あまり効果がないと感じる。

### 起こった事象に対して、深堀りして考える
マインドマップなどでその事象に対しての自分なりの整理を行う。
整理、咀嚼することで落ち着けるかと思いきや、ネガティブ思考に入ってしまい悪いことばかり思い浮かんでくるので、すぐにやるのは駄目っぽい。
自身の気力が回復したタイミングで行うと良い。

### 手を動かす系の作業をやる
設計、スケジュールを引くとか考える系の作業をやらない。
ネガティブなイベントがどうしても気になってしまい、思考がまとまらないので効率が最悪。
あまり頭を使わないコーディング、テスト、雑務など手を動かす系の作業を行うことで、気を紛らわすようにしている。

そんなに効果がないけど、まだ働かなきゃいけない時間のときにやってる。


### 好きな音楽などを聞いてテンションを上げる
無理やり切り替える方法。
好きな音楽を爆音できいたりして、意識をそらすことに務める。

効果的な場合とそうじゃない場合がある。


### 人と会話(雑談)をする
弊社の場合はフルリモートワークだが作業はペアプロやモブプロをやることが多い。 また、デイリースクラム後に雑談が好きなメンバーがいるため、リモートワークにしては人との雑談頻度は高い状態といえる。 家で仕事をしてる人は家族と雑談したりコミュニケーションするだけでも違う。
少し乗り気じゃなくても、人と雑談することでかなり気が紛れると感じた。

**私の場合はかなり効果的だったので、おすすめ。**


### 仕事を切り上げる
集中できないときに無理やりやってもいいことは無いので、さっさと諦めて翌日頑張るのもアリ。


# まとめてみての感想、気付き
- 美味しいものを食べるとかは、自分にはあんまり効果的じゃない気がする。 ~~もしかして、食に興味が薄い？~~
- 私自身はしゃべるのが苦手だと思ってましたが、雑談が特効薬だということがわかりました :raised_hands:
- 筋トレや運動をするなど、もっとアクティブに体を動かすことを検討してもよさそう。
- クソ忙しい人はそんな悩みすら無いのかも知れない。自分が暇なだけかな？ :innocent:

# 終わりに

みなさんの場合、どのように気分転換していますか？
今回整理したことで、以前よりも気持ちを早く切り替えることができるようになった気がします :wink:
ぜひ皆さんもやってみてください！
【初学者奮闘録】訪問者数カウンターに関わる関数についての学習（PHP）

###はじめに
この記事は、独学開始から約３ヶ月の実務未経験者が作成したものです。
よって、スキルは非常に未熟なため、決してこの記事の内容を鵜呑みにされないように、ご注意ください。
（未熟な私が本記事の作成に至った背景については、本文の最後にお伝えします。）
また本記事は、PHP言語の基礎理解を目的としております。
よって、Webアプリ開発におけるルーティングなどについては考慮できておりませんので、ご容赦ください。

### 参考にしたサイト記事
本記事を作成するために参照したのは、PHP公式マニュアルです。
https://www.php.net/

###【訪問者カウンター】のコードレビュー
まず、今回レビューしていく完成コードは以下の通りです。

```
function set_count( $file_name = "counter.txt"){

//【ブロック①】
        if( file_exists($file_name) ){
            $count = (int)file_get_contents($file_name) + １;
            file_put_contents($file_name, $count);		
//【ブロック②】
        }else{
            $handle = fopen($file_name , 'w+');
            $count = 1;     
            fwrite($handle, $count);
            fclose($handle);
	}
	
	return $count;
    }
```
私が設定したブロック毎にレビューしていきます。

###【ブロック①】file_exists関数　・　file_get_contents関数　・　file_put_contents関数
```
//【ブロック①】
        if( file_exists($file_name) ){
            $count = (int)file_get_contents($file_name) + １;
            file_put_contents($file_name, $count);
}
```
まずfile_exists関数は、【ファイルまたはディレクトリが存在するかどうかを調べる関数】です。
今回の場合、file_exists関数の引数内にある$file_nameに代入されている　counter.txtというテキストファイルがディレクトリ内に存在しているかを確認しています。
＄file_name（＝counter.txt）がディレクトリ内に存在しなかった場合、後ほど解説するelse以下へ条件分岐します。

もし＄file_name（＝counter.txt）が存在した場合、file_get_contents関数が起動します。
file_get_contents関数は、【ファイルの内容を全て文字列に読み込む関数】です。
つまり、file_get_contents関数の第一引数にある＄file_nameに書き込まれている文字を読み込んでいます。
もしも、＄file_name（＝counter.txt）に『整数１』のみが記載されていた場合、file_get_contentsは『１』となります。
後書きで『＋１』とも記載さているため、１＋１の合計値である『２』が$countに代入されます。

次に、file_put_contents関数が起動します。
file_put_contents関数は、【データをファイルに書き込む】関数です。
file_put_contents関数の第一引数には、データの書き込み先のファイルが定義されます。
この場合は、＄file_name（＝counter.txt）です。
そして、第二引数には、書き込まれるデータを定義します。
この場合、＄countに代入されている『２』が書き込み先のファイルに上書きされます。
※余談ですが、以下のように記載すれば、データを上書きするのではなく、追記ができます。

```
file_put_contents($file_name, $count)FILE_APPEND
```

###【ブロック②】fopen関数　・　fwrite関数　・　fclose関数


```
//【ブロック②】
        else{
            $handle = fopen($file_name , 'w+');
            $count = 1;     
            fwrite($handle, $count);
            fclose($handle);
}
```
次に、else以下のコードについて、レビューしていきます。

まず、fopen関数です。
fopen関数の挙動は引数のmodeによって異なります。
詳しくは、以下のURLを確認ください。
https://www.php.net/manual/ja/function.fopen.php
今回の例でのfopen関数の挙動は、以下の通りです。
①＄file_name（＝counter.txt）がディレクトリ内に存在しないことを確認する。
②fopen関数の第二引数のmodeであるw+が発動し、新規ファイルが作成される。
modeについては以下の公式マニュアルを参照ください。
fopen関数により、新規ファイルが作成され、且つそれに書き込み可能な状態となります。
その状態のまま、$handleに代入されます。

次に、fwrite関数です。
fwrite関数の第二引数で定義されているデータ（$count）を、第一引数で定義されている『書き込み可能なファイル』に書き込まれます。

最後に、fclose関数によって、開かれた状態のファイルを閉じます。

###最後に
上記でもお伝えいたしましたが、私は独学開始から約３ヶ月の実務未経験者です。
そんな未熟な私が記事を投稿しようと決意した理由は、以下の通りです。
・初学者の記事が多いほどに、プログラミングの学習を検討している方の背中を押せると考えたから（私自身、学習を開始するまでに初学者の記事を読み漁っておりました）
・周りに同じ境遇の仲間がいない、孤独な初学者さんの競争心を掻き立てられるのではと考えたから（学習効率を上げるためにはライバルの存在は重要）
・あるいは「自分のレベルはこいつよりも上」と優越感を与えられるのではと考えたから（学習効率を上げるためには自信を持つことも重要）

プロのエンジニア同様、初学者にもそれなりの努めがあると、私は思います。
今後も、下手くそながらも【初学者ページ】を上げ続けて参ります。

ありがとうございました。
Play App Signingで登録されている署名のSHA1のハッシュ値を取得する方法

Play App Signingで登録されている署名のSHA1のハッシュ値を取得する方法がわからなかったので調べてみました。

まずは、Play Store ConsoleのPlay App Signingのページに記載されているSHA1のフィンガープリントをバイナリーエディタに貼り付けて、保存。ここではファイル名をsha1.binとします。
その後以下のコマンドで、base64.txtにハッシュ値を出力します。

```
openssl base64 -in sha1.bin -out base64.txt
```
以上です！
YOLOv5をJetson Nano2G(4G)で動かして、物体を検知するから応用まで　その1



YOLOv5とJetson Nano2Gを使って、物体検知(Object Detection)ができるように実装していきます
Jetson Nano4Gでも対応できるように進めていきます


###環境
・YOLOv5  https://github.com/ultralytics/yolov5
・Jetson Nano2G(4G)　SWAPファイル設定と冷却ファン必須
・JetPack 4.6 
・OpenCV 4.5.1
・PyTorch 1.9.0
・TorchVision 0.10.0

###更新履歴
2021年10月　初版

##このシリーズのゴール
Jetson Nano2G(4G) でUSBカメラを使って物体検知を動かします

ただ動いてヨシではなく、応用できるようにします

##1.準備
Jetson NanoにJetPackが導入されていること
冷却ファンが稼働すること(PWM制御の場合は注意)
###SWAPファイル作成
Jetson Nano2Gはインストール中にSWAPファイルを作成するか聞いてきます
その際SWAPを作成してください

Jetson Nano4Gのみインストール後SWAPを作成します

```
git clone https://github.com/JetsonHacksNano/installSwapfile
cd installSwapfile
./installSwapfile.sh
```


###JTOP
J-TOP GPUの使用率やOpenCVのビルド状況を確認できます


```
sudo apt install python-pip
sudo -H pip install jetson-stats
```



再起動

```
sudo reboot
```

JTOP起動

```
jtop
```


ここから次回以降でやっと
OpenCV　compiledCUDA: YES を目指します
![Screenshot from 2021-10-08 11-53-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2142883/6ac86867-dba1-52a5-4cdf-465d99fe72bf.png)
[YOLOv5をJetson Nano2G(4G)で動かして、物体を検知するから応用まで　その2]
(https://qiita.com/ShimoyamaAi/items/57a9f0b5c3996b651bce)
githubのプルリクエスト作成時に自動でビルドチェックと文法チェックをさせる

## これはなに？
プロジェクトでプルリク作成時に自動でビルドチェックとLintチェックをしてくれるように設定したので忘れないように記載しました

※作業は全てvscodeで行っています

## 作成物
https://github.com/mu-suke/nextjs-sample-app/tree/feature/actions_build_and_lint

## 導入手順

### 1. actionsを追加

プロジェクトのルートから`.github/workflows/****.yaml`を作成します
基本的に`.github/workflows/****.yaml`＋設定したトリガーでCIが動くようなイメージです


----- ちょっと雑談 -----
`.github/ISSUE_TEMPLATE`とかでissue作成時のテンプレート設定もできるなど色々カスタマイズできるのでここも試してみると良いかもです

----- 雑談終わり -----


### 2. ビルドの設定
1でyamlファイルを作成できたらまずはビルド時の設定を記載していきます

```yaml:test_and_build_check_at_pr.yaml
name: test_and_build_check_at_pr

on:
  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: "14.17.6"
      - name: Install Dependencies
        run: npm ci
      - name: check-build
        run: npm run build
```

actionsを自分も忘れないように記載しておくと、
`on: `でどのタイミングでこのActionsを実行するかを記載していて、今回はタイトルにも記載してある通りプルリク作成時になっています

`branches: `では更にどのブランチに向けた時にActionsを実行するかを記載しています
ここではmainブランチに向けた時になっていますが、`version*`と設定することでversion1.0, version1.1等のブランチに向けた際に実行してくれるようになります

もっと細かく設定できたりするのでドキュメントを読んでみると面白そうです

https://docs.github.com/ja/actions/learn-github-actions/events-that-trigger-workflows


### 3. reviewdogの設定
ビルドが通った後は自動で文法チェックをしてくれるreviewdogを記載します

reviewdogは可愛いワンちゃんが静的解析をしてルールに従っていない箇所を注意してくれるものです


https://github.com/reviewdog/reviewdog

```yaml:test_and_build_check_at_pr.yaml
name: test_and_build_check_at_pr

on:
  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: "14.17.6"
      - name: Install Dependencies
        run: npm ci
      - name: check-build
        run: npm run build

  reviewdog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: reviewdog/action-eslint@v1
        with:
          github_token: ${{ secrets.github_token }}
          reporter: github-pr-review
          eslint_flags: "pages/**/*.{ts,tsx}"
```


### 4. 実行してみる
プルリクを作成してみて以下のような結果が出ればActionsが正しく走っていることになります
![スクリーンショット 2021-10-08 17.35.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316760/86d6cc1a-101d-de12-fdf1-5bf4f1d23d5e.png)

こちらのリンクからスクショと同様のものが確認できると思うので参考にしてみてください

https://github.com/mu-suke/nextjs-sample-app/pull/1


## 終わりに
ビルドできる状態(レビューする品質になっているか)を自動でチェックしてくれるおかげで開発者の負担が少し減った印象です

プログラマーの3大美徳にもあるように労力を減らすことを常に意識するのは大事なので今後も「自動化できそうだ！」と思ったら積極的にやっていこうと思います

今回はvscodeで書きましたがgithub上でも記載できる(というか本来はそっちなのかも...)ので好きな方で試してみると良いのかなと思います

ではまた！
ABC189 C - Mandarin Orange に痺れた

https://atcoder.jp/contests/abc189/tasks/abc189_c

![abc189_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/3ca2869b-b55d-b0be-69f0-e63c95a8e2f7.png)
![abc189_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/6f58f7a5-98c0-6ca4-39cb-1358f6b43fe9.png)
![abc189_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/737344/70cd445b-1061-b9d8-f1f4-21801e382878.png)

わ、わからん。
解答 please

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

うーん、わかったのかな。
とりあえず、分かったつもりになって書いてみた。

```MandarinOrange.py
N = int(input())
A = list(map(int,input().split()))

def solv():
    ans = 0
    for l in range(N):
        ref = A[l]
        for r in range(l,N):
            ref = min(ref,A[r])
            ans = max(ans,ref*(r-l+1))
    print(ans)

solv()
```

Python では間に合わないので
PyPy にしないと通らないのでご注意ください。

****

あれから真っ新で再チャレンジ。
以下の記述で WA。

```abc189c_wa.py
def solv():
    N = int(input())
    A = list(map(int,input().split()))
    lis = []
    for i in range(N):
        ref = A[i]
        score = 0
        for j in range(i,N):
            if A[j] < ref:break
            score += ref
        lis.append(score)
    print(max(lis))
solv()
```

なぜダメなのだろうか。
random_01.txt をダウンロードして
WA/AC を比較してみた。
具体的には、最大合計値、左端、右端を printを使って表示してみる

**AC** 合計値 901408/ 左端 1429/右端 1445
**WA** 合計値 125322/ 左端 1429/右端 1431

ご覧のとおりスタート地点は同じだが右端で切れている位置が異なる。
なぜ？
AC/WA には記述に根本的な差がある。

AC : 左端から最小値を更新しながら探索するので、連続してカウントする数を伸ばしている
WA : 左端を最小値とし、最小値以上で連続してないとカウントを止めてしまう

冷静に考えて前者の AC の考え方じゃないと all case を満たした回答が出来ないのではなかろうか？

以上のようにイメージし直すと、
AC の記述に自力で辿り着き、見事 AC となった。
クリティカル・シンキングとは？とその考え方

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2138796/892dc16b-362f-fcc8-8dc8-3b57b73b77db.png)

グラフィックデザイナーが受講したビジネススクールで学んだことの振り返りと、その感想を兼ねて、今回はクリティカルシンキング。

## クリティカル・シンキングとは

クリティカル・シンキングは、僕がデザインを学んだときには無かった言葉ですが、師匠からさんざ詰めら続けるほど、デザインで必ず使う考え方です。物事を適切な方法で、適切なレベルまで考えることを言います。クリティカル・シンキングをしっかりと行えれば、直感的な問題解決ではなく、物事の本質を捉えた問題解決が行えるようになります。

直感的に結論を出してしまうと考えはそこで止まってしまいますが、じっくり考えることで様々な可能性が発見でき、それまで思いつかなかった「新たな発想」ができます。また、それまでとは違った視点で考えるということが出来るため、見落とされていたチャンスや問題への気付きがあります。これらのメリットを得る過程で、客観的、多角的に考えるという工程があるため、相手の言いたいこと、その前提を的確に理解することも可能です。

## クリティカル・シンキングの考え方
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2138796/be061d4a-85ea-e78d-1dae-6c728dbf97c1.png)

クリティカルシンキングでは、目的は何なのかを非常に意識します。問題のあちこちを突いて意味のない検討をしてしまわないよう、そもそも「何のために考えるのか」「今そのことについて考える意味はあるのか」について常に考え、そして問題の一部だけに着目して、他の問題を見落とさないよう「目的は実は違うじゃないか」などを考えていきます。

例えば、お客さまから会社のWebサイトのリニューアルしてほしいという依頼があった時、そもそもなぜリニューアルをしなければならないのか、ご依頼された理由を考えるようにします。例えば、経営者が変わって、経営理念に変更があったので、Webサイトのリニューアルをする場合、そこを見落として、見た目だけを今風に変更したとすると、的はずれな仕事をしてしまいます。何のため？目的は？ということを、しつこく考えて行きます。

![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2138796/b4381c2e-45c3-d4a3-bec1-45d132673d31.png)

また、自分と他の人の考える道筋が違うということも意識しておきます。僕もそうですが、人が何かを考える時、客観的にと思っていても個人の価値観を、多角的にと思っていても過去の経験からの教訓を、といったような、暗黙の前提を置いて物事を考えています。これを理解しておかないと、とても狭い世界や範囲で問題の答えを求めてしまいます。

例えば、ディレクターとスタッフが、A案、B案、C案、の3つの案を検討している打ち合わせがあったとき、ディレクターは効率重視のA案、スタッフは品質重視のB案を推している時、ディレクターはスケジュールや予算を、スタッフはクオリティややりがいを前提にしています。それぞれの暗黙の前提が違うので、お互いの主張に納得ができません。

![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2138796/7460140e-170d-4b8f-3d16-1d8b0b7aa16f.png)

そしていちばん重要なのは、考えて結論が出たとしても、そこで思考を止めずに「つまり？」と「なぜ？」を考え続けることが重要です。で、刻一刻と変化していくビジネスの世界では結論の出た問題の先にまた新たな問題が見えてくることもあります。客観的な思考を継続することで、物事の本質を捉えながら先へ進むことができるようになります。

例えば、デザイナーのミスが多い時、なぜ？と考えた結果、作業フローが守られていない、という答えが出たとしても、ここで止めずに更に、なぜ作業フローが守られない？と続けて考えると、赤字の文字が汚い、作業量がとても多い、といった答えまでたどり着けます。その先も、更に、そして更に、と考えることで、問題の本質に近づいていきます。

## まとめ：クリティカル・シンキングとは？
- 物事を適切な方法で、適切なレベルまで考える
- クリティカル・シンキングで可能になること
 - それまで思いつかなかった「新たな発想」ができる
 - 見落とされていたチャンスや問題への気付きがある
 - 相手の言いたいことや前提を的確に理解できる
- クリティカル・シンキングの考え方
 - 目的を常に意識する：何のために考えるのか、今そのことについて考える意味はあるのか、目的は実は違うじゃないか、など、目的を常に意識する
 - 考えの癖を理解する：人が何かを考える時、個人の価値観や過去の経験からの教訓など、考え方に癖が出るため、これを理解し、そして意識する
 - 本質まで考え続ける：考えて結論が出たとしても、そこで思考を止めずに更に、そして更に、と考えることで、問題の本質に近づいていくまで考える

次回はエレベーター問題を使った具体的なクリティカル・シンキングの流れを記事にします。

## 振り返り
僕がデザイナーになりたての時、デザインの師匠から「なぜデザインするか考えろ」「お客さまは素人、お前はプロ」「依頼されたこと以上のことをやれ」と口酸っぱく言われてきました。当時はクリティカル・シンキングという言葉は無かったのですが、この言葉たちはまさしく、クリティカル・シンキングだったんだなと考えさせられました。

デザインの依頼があった時、お客さまには何か目的がありますが、その目的はお客さまも分かってないことが多いものです。お客さまは素人だから。なので、プロの我々が、なぜデザインするのか、それはデザインで解決することなのか、なにを解決したいのか？を考え、プロとして、デザインで問題の本質を解決できるならやるし、解決できないなら他の方法を提案したりします。とても厳しい師匠でしたが、一人前のデザイナーになる基礎の基礎を根気よく教えてくれてありがたいなと思った次第です。肩でも揉みに行こうかな。
【Laravel】テーブルのカラム名を取得して、配列化するメソッド

テーブルのカラム名を取得して、配列化する方法
→**getColumnListing**を使う！


Schemaファサードを使用

```
use Illuminate\Support\Facades\Schema;
```

getColumnListingでテーブル名を指定してカラム名取得

```
getColumnListing('テーブル名');
```

---

Tinkerで実行して確認する場合は下記のように記述

```
Illuminate\Support\Facades\Schema::getColumnListing('テーブル名');
```
【凡ミス①】Formタグ外に登録ボタンを配置

#私の凡ミス集その①です。
Formタグ外に登録ボタンを配置した事が原因で、
登録ボタンが反応しなくなる。

##環境
* PHP7
* Laravel6
* Docker

##背景
* ユーザー登録画面と処理機能作成時の凡ミス
* 登録ボタンを押しても反応無し。エラーすら出ない。笑
* `RegisterController.php`を確認しても問題は見当たらない
* `Web.php`の記述は、`Auth::routes();`で認証系はバッチリ
* `register.blade.php`の記述を見ても、この時点では間違いが見当たらず
* 諦めて就寝...

##解決

翌朝`register.blade.php`を再確認したところ、
Formタグ外に登録ボタンを間違って配置していたおかげで、
入力データがPOSTされていない事を確認。

```PHP:register.blade.php
     </div>
    </form>
    <button class="btn btn-block" title="アカウント登録" type="submit">
      はじめる
    </button>
    <div>
        アカウントをお持ちの方は<a href="{{ route('login') }}">こちら</a>から
    </div>
   </div>
```
以下のように修正したら、上手くいった。

```PHP:register.blade.php
     </div>
　　　　　　　　　　<button class="btn btn-block" title="アカウント登録" type="submit">
      　はじめる
    　　　</button>
    </form>
    <div>
        アカウントをお持ちの方は<a href="{{ route('login') }}">こちら</a>から
    </div>
   </div>
```

##終わりに
Formタグの中でPOSTメソッドを定義して登録処理を実行しているので、
登録ボタンをタグ内に置かないと機能しないのは当たり前。

また、この事象はユーザー登録機能に関わらず、ログイン、パスワードリセット、投稿等、
あらゆるPOSTメソッドを使用する処理で起こりうる凡ミスです。


```PHP:register.blade.php
<form method="POST" action="{{ route('register') }}" class="p-3">
     @csrf

　　　　　・・・・省略・・・・

   <button class="btn btn-block" title="アカウント登録" type="submit">
        はじめる
   </button>
</form>
```

###以上、凡ミス集①でした
React ステートフック

#ステートフックとは
ステートのためのフック。
ステートとは、値をコンポーネント内で保持しその値を更新すると表示が更新できる。
ただし、クラスコンポーネントでしか使えない。
ステートフックは関数コンポーネントでもステート機能を使えるようにしたもの。

#ステートフックの作り方・呼び出し方
```react
export default function(){
  const [変数A,変数B] = useState(初期値);
  const 関数C = ()=>{
    変数B()          //変数Bの内容は変数Aを更新する処理
  }
  return(
       <div onClick={関数C}>
         {変数A}
       </div>
)
}

```

変数Aはステートの値。呼び出すときに使う。
変数Bはステートの値を変更する関数
呼び出すだけで、変更が必要ない場合は変数B、関数Cはいらない。
更新する場合は、イベント時に関数Cを呼び出すなどします。関数Cが実行されると、変数Bが実行され、変数Aの値が更新されます。
Unityジャンプのやり方

#2段ジャンプ

```C#:Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    private Rigidbody rb;
    public int Jumpflg;
    public float Jump = 300;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        Jumpflg = 0;  //ジャンプの初期化
    }
}
```
ここまではジャンプに必要なコードです。

次に

```C#:Player
public class Player : MonoBehaviour
{
    void Update()
    {
        if (Jumpflg <= 1)  //2段ジャンプ
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                rb.AddForce(Vector3.up * Jump);
                Jumpflg++;
            }
        }
    }
}
```
Jumpflgをpublicにしたことでインスペクター上でJumpflgの値が見れるようになりました。
Jumpflgが1以下だったらスペースキーを押せてAddForceで上向きに力をかけており、
一回スペースキーを押すごとにJumpflgが1ずつ上がっていきます。
これにより、1回ジャンプでJumpflgは0から1になります。1になったらif(Jumpflg <= 1)の
条件式が成立するのでもう一回スペースキーを押し、ジャンプすることが可能になります。
ちなみに、if(Jumpflg == 0)は1回のみジャンプが可能、if(Jumpflg <= 2)は3回ジャンプが可能になります。

しかし、上記の記述のみだと再生してから2回しかジャンプ出来ないと言うことになります。
ゲームの場合、地面に着地するごとに2回ジャンプしたいですよね。
そうするためには下記の記述が必要になります。
地面とPlayerにcolliderをつけて、colliderに触れたらJumpflgを0にするという記述が必要です。
ジャンプを2回するとJumpflgが2になり、上記のif (Jumpflg <= 1)の条件式は不成立になって
しまいます。
下記のような記述だと、地面に着地するとJumpflgが0になり、地面着地後、上記のif (Jumpflg <= 1)の条件式が成立するようになります。

```C#:Player
public class Player : MonoBehaviour
{
    void OnCollisionEnter(Collision collision)  //ジャンプ、地面に触れると
    {
        Jumpflg = 0;  //Jumpflgを0にする
    }
}
```

#まとめ
```C#:Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    private Rigidbody rb;
    public int Jumpflg;
    public float Jump = 300;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        Jumpflg = 0;  //ジャンプの初期化
    }

void Update()
    {
        if (Jumpflg <= 1)  //2段ジャンプ
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                rb.AddForce(Vector3.up * Jump);
                Jumpflg++;
            }
        }
    }

void OnCollisionEnter(Collision collision)  //ジャンプ、地面に触れると
    {
        Jumpflg = 0;  //Jumpflgを0にする
    }
}
```
こうやって記述すると2段ジャンプが出来るようになりました！！
PHP クラス名(インスタンス)からPHPファイルパスに辿り着く方法

クラス名(インスタンス)から実際のPHPファイルパスを探したいとき。

```php
public function run($nazoClass)
{
    $nazoClass->nazonazo();
}
```

`$nazoClass` ってどこに定義されてるの？を調べます。

## 環境

IDEのコードジャンプが効かないクソ環境を想定してます。
コードジャンプできればこんなことしなくていいのに...

## クラス名を調べる

```php
var_dump(get_class($nazoClass));
die;
```

## ファイルパスを調べる

```php
var_dump((new \ReflectionClass(get_class($nazoClass)))->getFileName());
die;
```

## 参考

- https://www.php.net/manual/ja/function.get-class.php
- https://www.php.net/manual/ja/class.reflectionclass.php
- https://stackoverflow.com/questions/3014254/how-to-get-the-path-of-a-derived-class-from-an-inherited-method
[Ralis] パンクズ機能

ポートフォリオにgretelを使ってパンくずリスト機能を実装した時のメモです。

# 完成イメージ
![パンくずリスト.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/9160669c-0905-909e-7b60-3d6968b2a4cb.gif)


# 実装
まずはGemをインストールします。

### gretel　導入
```ruby:Gemfile
gem 'gretel'
```
```terminal:ターミナル 
$ bundle install
```
インストールできたらgretelを導入していきます。

```terminal:ターミナル 
$ rails g gretel:install
```
`config`に`breadcrumbs.rb`が作成されていれば準備完了です。

### パンくずリストの書き方
作成された`config/breadcrumbs.rb`にパンクズリストを書いていきます。
書き方の基本は、

```ruby:
crumb "ページ名" do
  link "viewに表示される名前", "URLパス"
  parent :現在の1つ前のページ
end
```
という感じです。
これだけ見てもイマイチ分かりにくいので実装しながら覚えていきましょう！

### パンくずリスト実装
今回実装する部分は完成イメージのように、
TOPページ → イベント検索ページ → イベント詳細ページのような流れでパンくずリストを作成していきます。

- TOPページ

```ruby:config/breadcrumbs.rb
crumb :root do
  link 'TOP', root_path
end
```
- 検索ページ

```ruby:config/breadcrumbs.rb
crumb :event_search do
  link "イベントを探す", events_search_path
  parent :root
end
```
parentに最初に設定したrootを設定することでTOPページに戻れます。

- イベント詳細ページ

```ruby:config/breadcrumbs.rb
crumb :event_show do |event|
  link event.name, event_path(event)
  parent :event_search, event
end
```
詳細ページにはイベントのidを含める必要があるのでブロック変数を使って記述をします。
また、ブロック変数を使うことで`event.name`のようにしてイベント名でリンク名を設定することができます。

### Viewに反映
あとは設定したパンくずリストをviewに反映していきます。
設定したページ名で反映できます。

- 検索ページ部分

```ruby:
- breadcrumb :event_search
= breadcrumbs separator: " &rsaquo; "
```

- 詳細ページ部分

```ruby
- breadcrumb :event_show, @event
= breadcrumbs separator: " &rsaquo; "
```
ブロック変数で定義した部分にはインスタンス変数を渡す必要があるので忘れずに設定しましょう！


最後にスタイル調整をすれば完成です。
breadcrumbsというクラスがデフォルトで設定されているので、そこにスタイルを当てていきます。

```ruby
.breadcrumbs {
  margin-top: 15px;
  font-size: 15px;
  &.breadcrumbs a {
    color: red;
    &:hover {
      opacity: 0.5;
    }
  }
} 
```

これで完成！
RxSwift で独自のリトライ処理を実現

# はじめに
エラーが流れてきたときに指定回数、指定条件でリトライする処理は標準オペレータとして提供されており、 `retry` もしくは `retryWhen` を利用します。
今回はこのようなエラーが流れてきたときではなく、「nil だったとき」のような独自のリトライトリガーを実現する方法をご紹介します。

# 方針
1. flatMap で特定条件時に独自のエラーに変換する
2. flatMap の中で timer で遅延させて自身を再帰的に呼び出す

ザッとこの2パターンを思いつきました。
1に関しては、リトライ処理のためにエラーを新しく定義するのはどうなのかという点、2はリトライ回数を制御するためにグローバル変数を定義する必要がある点が個人的に感じた悩みポイントです。
実装環境に合わせた判断と工夫を追加で施していただければと思います。

# 1. エラーに変換してリトライ
```swift
enum CustomeError: Error {
    case nilData
}

private func fetch() -> Observable<Data> {
    API.fetch()
        .flatMap { res -> Observable<Data> in
            guard let data = res else {
                return .error(CustomeError.nilData)
            }
            return .just(data)
        }
        .retry(3) // 標準オペレータの利用
}
```

# 2. 再帰処理を利用してリトライ
```swift
private func fetch() -> Observable<Data> {
    API.fetch()
        .flatMap { res -> Observable<Data> in
            guard let data = res else {
                // 5 秒間隔でリトライ
                return Observable<Int>.timer(.seconds(5), scheduler: MainScheduler.instance)
                    .flatMap { [unowned self] _ in
                        // リトライ回数を制御する場合はここで判定
                        self.fetch() // 再帰
                    }
            }
            return .just(data)
        }
}
```

# おわりに
RxSwift の利用方法メモとして書いてみました。
ご指摘等ございましたら、コメント頂けますと幸いです。
VPCの豆知識

<h1>初めに</h1>
AWSに関する知識を身に着けるため
役に立つ用語や知識をに備忘録として残していく。

<h2>VPC豆知識</h2>

● VPCは大きな箱のような役割をしており、
　その中にルーター・サブネット・EC2などを格納できる。

● VPCのアドレスレンジは下記から選ぶことができる。

10.0.0.0～10.255.255.255
172.16.0.0～172.32.255.255
192.168.0.0～192.168.255.255

※ /16 ~ /28の範囲内で作成でないといけない。※

※ 例えば、10.0.0.0/15といった設定だとエラーが発生するので注意 ※

● IPアドレスには10進数と2進数での表記方法がある。
2進数は0と1であらわすことができ、10進数は普段私たちが使っている表記。

<h2>追記</h2>
間違った内容や記述があればコメントで教えてくださいね！

この記事が参考になればうれしいです。
webmockのgem使用時にhashdiffの警告ログが吐かれる

## 環境情報

- Ruby 2.6.1
- Rails 5.2.6

## 起きたこと

webmockのgemを使用しているRailsプロジェクトを `rails s` などで立ち上げた際、下記ログが吐き出される

```
The HashDiff constant used by this gem conflicts with another gem of a similar name.  As of version 1.0 the HashDiff constant will be completely removed and replaced by Hashdiff.  For more information see https://github.com/liufengyun/hashdiff/issues/45.
```

## 解決方法

ログの内容にもあるように、hashdiffを1.0.0以上に更新する
ただ、webmockの最新（3.14.0）でもhashdiffの最低バージョンは0.4.0になっていたため、Gemfileに追記する

```
gem "hashdiff", ">= 1.0.0"
```

その後、 `bundle update hashdiff` でgemを更新すれば解消されます
unitest/jinja2のそれぞれで呼び出される特殊メソッドについて

#目的

- unittestでは「プログラムが期待通りの構造でデータを返す」を確認する。
    - そのオブジェクトを識別できる文字列でOK
- 実際の利用場面（Jinja2）では指定した書式の文字列を渡す。
    - HTMLタグを使った複雑な文字列
    - この機能については別途テストケースを用意することで対応したい。

#結果

- unittest
    - テスト時は ``__eq__`` が利用される。
    - テストが失敗した時は ``__repr__`` の情報を見せる。
- jinja2
    - ``__str__`` が利用される。

#確認

サンプル

```python
#!/usr/bin/python
import unittest
from jinja2 import Template

class aclass(object):
    def __str__(self):
        return "__str__"
    def __repr__(self):
        return "__repr__"
    def __eq__(self, other):
        return "cccc" == other

a = aclass()

tpl_text = 'a = {{ value }}'
template = Template(tpl_text)

data = {'value': a}
disp_text = template.render(data)
print(disp_text)

test = (1, 2, a, 4)
rslt1 = (1, 2, 'bbbb', 4)
rslt2 = (1, 3, 'cccc', 4)
rslt3 = (1, 2, 'cccc', 4)

class testKanaText(unittest.TestCase):
    def test01_astext(self):
        self.assertEqual(test, rslt1)
    def test02_astext(self):
        self.assertEqual(test, rslt2)
    def test03_astext(self):
        self.assertEqual(test, rslt3)

unittest.main()
```

実行結果

```bash
$ ./zzz.py
a = __str__
FF.
======================================================================
FAIL: test01_astext (__main__.testKanaText)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./zzz.py", line 29, in test01_astext
    self.assertEqual(test, rslt1)
AssertionError: Tuples differ: (1, 2, __repr__, 4) != (1, 2, 'bbbb', 4)

First differing element 2:
__repr__
'bbbb'

- (1, 2, __repr__, 4)
+ (1, 2, 'bbbb', 4)

======================================================================
FAIL: test02_astext (__main__.testKanaText)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./zzz.py", line 31, in test02_astext
    self.assertEqual(test, rslt2)
AssertionError: Tuples differ: (1, 2, __repr__, 4) != (1, 3, 'cccc', 4)

First differing element 1:
2
3

- (1, 2, __repr__, 4)
+ (1, 3, 'cccc', 4)

----------------------------------------------------------------------
Ran 3 tests in 0.002s

FAILED (failures=2)
```

#以上
argocdにログイン出来なかった時の対処法

##背景
Kubernetesクラスターを作成し、その後argocdを導入したところ、ログインで手間取ってしまった。
備忘録としてログイン出来なかった場合の対処法を記す。

###問題
要約すると、ブラウザでログイン画面が開かれるところまでは上手くいき、初期パスワードでのログインが拒否られる問題。

###経緯
[Argo CDはじめました](https://blog.star-flare.com/2020/12/24/start-gitops-using-argo-cd/)に記載されている方法を参考にしつつ、導入を進めたところ、以下コマンドにてパスワードを確認しようとのこと。

```
# kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2
```
ここで表示されるPod名を指定してログイン画面で入力するも失敗！！！！


##間違った対処法
###その１: Pod名が間違っていないか確認
以下コマンドにてPod一覧を参照し、名前が間違っていないのか確認

```
# kubectl get pod -n argocd
```

結論から言うと、間違っていなかった。

###その2: パスワードをリセットする
パスワードをリセットするコマンドがあるとのことなので、それを実践

```
# kubectl patch secret argocd-secret  -p '{"data": {"admin.password": null, "admin.passwordMtime": null}}'
```
コマンド実行後確認すると別のエラーが発生していた。secretファイルを作成していない為、存在していないと言われてしまったのだ。

```
# kubectl patch secret argocd-secret  -p '{"data": {"admin.password": null, "admin.passwordMtime": null}}'
Error from server (NotFound): secrets "argocd-secret" not found
```
実行コマンドが間違っているので、再度調査。

##正しい対処法
###Secretに記載のパスワードを暗号化して出力する
[Getting Started](https://github.com/argoproj/argo-cd/blob/master/docs/getting_started.md)の中の`4.Login Using The CLI`の手順を参考に、CLIからのログインを試みる。secretファイルを一時的に作成して、表示されたパスワードからログインするというもの。

```
# kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
```

コマンド実行後表示されたパスワードをブラウザに入力し、ログインすることが出来た。

##結論
ログイン出来なかったらSecretファイルのパスワードを初期化して暗号化すること。

##参考資料
[公式Overview](https://argo-cd.readthedocs.io/en/stable/)
[argocd-server Username or Password not working on fresh install #998](https://github.com/argoproj/argo-cd/issues/998)
[FAQ](https://github.com/argoproj/argo-cd/blob/master/docs/faq.md#i-forgot-the-admin-password-how-do-i-reset-it)
[Getting Started](https://github.com/argoproj/argo-cd/blob/master/docs/getting_started.md)
GitHub

# GitHubとは
**GitHub**とは、ソフトウェア開発プロジェクトのためのソースコード管理サービスのこと。
ソースコードのバージョン管理や閲覧、バグ追跡機能、SNSの機能を備えている。

# 用語
GitHubを使うにあたって、知っておきたい専門用語や操作についてまとめる。

###■ リポジトリ
ファイルやディレクトリの状態を保存する場所。
**リポジトリ**は「**ローカルリポジトリ**」と「**リモートリポジトリ**」の2つがある。

**ローカルリポジトリ**：自分のPC内に記録されるリポジトリ。
**リモートリポジトリ**：サーバーなどネットワーク上にあるリポジトリ。

###■ コミットとプッシュとプル（commit/push/pull）
**コミット(commit)**：ファイルの追加や変更履歴をリポジトリに記録すること。
**プッシュ(push)**：ローカルリポジトリのファイルの追加や変更の履歴をリモートリポジトリに反映させること。
**プル(pull)**：リモートリポジトリのファイルの追加や変更をローカルリポジトリに反映させること。

###■ ブランチ（branch）
作業を分岐させて履歴の流れを記録していくもの。
分岐したブランチは他のブランチの影響を受けないので、1つのソフトウェアに対して複数のメンバーが同時にバグの修正や新たな機能追加を行うことができる。

###■ クローン（clone）
リモートリポジトリをコピーしてローカルリポジトリを作成すること。
クローンしたタイミングのリモートリポジトリと全く同じ環境をローカルに作成する。

###■ フォーク（fork）
他の人が書いたコードのリモートリポジトリを、自分のリモートリポジトリにコピーすること。



#GitHubの使い方
基本的なGitの作業は下記のような流れとなる。
1、リポジトリを作成（git init）
2、ファイルの作成、編集
3、gitのインデックスに追加(git add)
4、ローカルリポジトリにコミット(git commit)
5、プッシュしてリモートリポジトリに反映
同じテーブルのほかの行を使用したUPDATE【SQL Server】

同じテーブルの別のレコードの値を使用したUPDATEの書き方がわからず調べていました。
備忘録的に残していこうと思います。
何分未熟者ですので、ご指摘等いただければと思います。

UPDATE FROM をほとんど使ったことがなかったので、その練習も含めて

#やりたいこと
TableAの行a列1の値を、TableAの行b列1の値で更新する
以下参考にした記事です。(陳謝)
[https://qiita.com/sugarboooy/items/7c4947594d502dddcc01](URL)

#同じテーブルのほかの列の値を使用したUPDATE
こちらは比較的シンプル
UPDATE FROM を使い、同じテーブルをINNER JOINすればOK

正直UPDATE FROM の挙動を正しく理解できている気がしないのでその辺はおいおい


```sql:同テーブル別列の値
UPDATE a
SET
	 a.Column1		= b.Column2

FROM  TableA a
INNER JOIN  TableA　b
ON  
		a.Column3	= b.Column3
WHERE
		a.Column1　	= 'hogehoge'
```


#同じテーブルのほかの行の値を使用したUPDATE

今回の場合、以下のようなある値を2期間分保存するテーブルにおいて、
特定のタイミングで新しいほうの値を古いほうに移したい

|キー|a  |b  |c  |
|---|---|---|---|
|1|前期|c  |d  |
|2|当期|a  |b  |

###結合列を選択することでできました

```sql:同テーブル別行の値
UPDATE a
SET
	 a.Column1		= b.Column2

FROM  TableA a
INNER JOIN  TableA　b
ON  
    --ここで、UPDATEしたい行と、データ元となる行を結合する
        a.Column2   = '前期'
    AND b.Column2   = '当期'
WHERE
		a.Column1　	= 'hogehoge'
```
転職活動管理アプリを作ろう④（Laravel に鞍替え〜ログイン実装チュートリアル）

前回は [コチラ](https://qiita.com/soso555/items/89acdd45e88d0e0251f1)

# Laravel に変更します
- Java(Spring) ではなく PHP のスキルが必要になり、復習のため
- テーブル定義は前回のものから変更しません
    - が、user テーブルの変更は必須なので後で更新する
- 今回の記事ではチュートリアルに即したログイン画面の実装をしていきます
    - 記事の体裁は前回を踏襲

# その他も変更します
- DB は PostgreSQL にします
- Laravel の開発環境構築は [コチラ](https://qiita.com/soso555/items/616307285bee984ce60f) にて解説
    - docker-compose.yml 等は [github/sosobl/env-laravel](https://github.com/sosobl/env-laravel) にて

# ログインを実装してみよう
- [laravel-admin](https://laravel-admin.org/docs/en/) を使用します
    - 他のライブラリも検討しましたが、ドキュメントの多さとそこまで複雑なことをやる必要もないため、本ライブラリを選定しました
    - ログイン後のダッシュボード画面も付いてくるのが助かる

- 以下ドキュメントよりインストール実施

https://laravel-admin.org/docs/en/

- やったこと（コマンドログ）
    1. ```$ composer require encore/laravel-admin```
    2. ```$ php artisan vendor:publish --provider="Encore\Admin\AdminServiceProvider"```
    3. ```/config/app.php``` の timezone を ```Asia/Tokyo``` に、locale を ```ja``` に修正
    4. ```$ php artisan admin:install```
        - これをやると初期アカウントの作成等のシーディングをしてくれる

- つまった点
    - ```SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "sessions" does not exist LINE 1```
        - 解決策
            - 以下コマンドを実行し sessions テーブルを作成し、サーバー再起動
            - ```$ php artisan session:table```

- 動作確認
    1. ```http://localhost/admin/``` へアクセス
    2. id:admin / pass:admin でログイン
    3. こんな画面が表示される
        ![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1167986/d9a88db3-8a8b-674a-3ddd-fd3846541de5.png)



# ~~（備忘録）ログインを実装してみよう（JetStream）~~
- __※__ laravel-admin を使用した方が色々と捗るので、以下の記事は __備忘録として__ 残しておりますが以降は使用しません
    - 一般ユーザーのような階層を設ける場合は使うかも
- 以下チュートリアルを行う

https://readouble.com/laravel/8.x/ja/authentication.html

- 使用するライブラリは [Laravel Jetstream](https://jetstream.laravel.com/2.x/introduction.html) にしました
    - コマンド打ってインストールするだけで以下機能が追加されるため（簡単）
        - ログインフォーム
        - 認証
        - 新規ユーザー登録
        - パスワード問い合わせ
        - チーム管理（一応）
        - API サポート（一応）
    - インストール方法
        1. ```$ composer require laravel/jetstream```
            - Laravel Jetstream の有効化
        2. ```$ php artisan jetstream:install livewire --teams```
            - Laravel Jetstream のインストール（Livewire    ）
        3. ```$ npm install && npm run dev```
        4. ```$ php artisan migrate```
        5. ```$ php artisan vendor:publish --tag=jetstream-views```
        6. 日本語化
            - https://github.com/Laravel-Lang/lang/ から zip ダウンロード
            - zip を解凍し lacales/ja 内のファイルをプロジェクト内の resources/ja にコピー、ja.json を resources/ にコピー
                - config/app.php の locale を 'ja' に変更
    - インストール方法詳細は後ほど追記したい
        - 参考
            - [Laravel Docs](https://readouble.com/laravel/8.x/ja/authentication.html)
            - [Jetstream Docs](https://jetstream.laravel.com/2.x/installation.html)
個人開発で愛用しているNext.jsデプロイ手順 (~5分)

# 概要
個人開発をしようと思ったら、僕が最初にやることはNext.jsをAWSにホストすることです。
その際の手順を記載します。5分程度でインターネット公開することができます。

# 手順
## ① Create Next App

```sh
npx create-next-app@latest --ts <アプリ名>
```

## serverless.ymlファイルの作成

```sh
cd <アプリ名>
touch serverless.yml
open serverless.yml
```

serverless.ymlに以下の内容を記載します。

```yml
myNextApplication:
  component: "@sls-next/serverless-component"
```

## serverlessインストール

```
npm install -D serveless
```

## デプロイ
以下コマンドを実行してデプロイ (AWS CLIの設定ができていることが前提です)

```sh
serveless
```

# まとめ
以上の作業だけで、Next.jsをS3 + CloudFront構成でデプロイができます。
作業時間は５分程度でできるので自分はいつも最初にこれをやっています。
Arduinoでステッピングモーターを動かす


# ステッピングモーター
ステッピングモーターは一定の角度ずつ回転するモーターです。
[使用するステッピングモーター](https://akizukidenshi.com/catalog/g/gP-05372/)
入力定格電圧:12V, ステップ角：1.8度
[モータードライバA4988](https://www.amazon.co.jp/HiLetgo-5%E5%80%8B%E3%82%BB%E3%83%83%E3%83%88RepRap-%E3%82%B9%E3%83%86%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0%E3%83%A2%E3%83%BC%E3%82%BF%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-HR4988-3D%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF%E3%83%BC/dp/B010Q17CAI/ref=pd_lpo_1?pd_rd_i=B010Q17CAI&psc=1)

# 配線
ステッピングモーターをA4988に接続し、STEPを９番ピン、DIRを8番ピン、VDDを5V、GNDとGNDをつなぎます。

![スクリーンショット 2022-04-11 9.53.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577027/b33b3d4a-ae8b-f7dc-d007-96ff1382ee8d.png)


# プログラム
下記のプログラムをArduinoに書き込みましょう。

```Arduino
const int DIR  = 8;
const int STEP = 9;

void setup() {
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  digitalWrite(DIR, LOW);
  digitalWrite(STEP, LOW);
}

void loop() {

  for (int i=0; i <= 50; i++){
    clockwise(5000);
  }
  for (int i=0; i <= 50; i++){
    counter_clockwise(5000);
  }
}

void clockwise(int delaytime){
  digitalWrite(DIR, HIGH);//HIGHは時計回り

  digitalWrite(STEP, HIGH);
  delayMicroseconds(delaytime);
  digitalWrite(STEP, LOW);
  delayMicroseconds(delaytime);

}

void counter_clockwise(int delaytime){

  digitalWrite(DIR, LOW);//はLOWは反時計回り
  digitalWrite(STEP, HIGH);
  delayMicroseconds(delaytime);
  digitalWrite(STEP, LOW);
  delayMicroseconds(delaytime);
}
```
[flexbox]ブラウザのサイズやデバイスの違いを柔軟に表示する　固定　可変

flexboxでリキッドレイアウト（固定 + 可変）にする方法
・リキッドレイアウトとは可変カラムと固定カラムのこと。

ブラウザのサイズやデバイスの違いを柔軟に表示する概念
例) 「サイドメニューが、固定幅で、メインコンテンツが可変幅」など。


・flexboxのリキッドレイアウトが使えるケース
・レスポンシブデザインに最適
・固定、可変する要素があるとき
・フォームのラベルと入力要素が並ぶ時

cssfile

.wrapper {
display: flex;
}

.side {
width: 300px;
}
.main {
flex: 1;
}

htmlfile

<div class="wrapper">wrapper
<div class="side">side
<!-- 固定カラム -->
</div>
<div class="main">main
<!-- 可変カラム -->
</div>
</div>

１,
CSSでは、梱包要素のwrapperクラスに、display: flex; を適用することで
フレックスコンテナボックスにすることが目的。これで子要素は横並びになる

2,
sideクラスに width: 300px;の横幅を与えて固定値とする

3,
mainクラスにflex: 1;の指定で可変を実現する。
flexプロパティはflexのスタイルカスタマイズする省略プロパティ。
CSSショートハンドという。リキッドレイアウトを実現するに当たって厳密にプロパティを指定する必要性がない。

まとめ
・必要なHTML：梱包要素、固定カラム、可変カラム。
・必要なCSS：梱包要素 display: flex; 固定カラム width: ~~px; 可変カラム flex:
React Study(2) ～ React Hooks

# React Hooks
　昨日に引き続きReact学習中！昨日は勉強中に大きな地震があってなんかやめてしまった。。。
　めげずに今日もやっていきましょう。
## React Hooksとは
　React Hooksは割と最近Reactに追加された機能。って言っても、自分は初学者なので最初からあるものとして勉強します。

> フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。
> [React公式](https://ja.reactjs.org/docs/react-api.html#hooks "フック(hook)")

と、いうことで今まで面倒くさい実装してたのが楽になるよーっていう雑な解釈をします。
使いたい機能に対して「use～」を使うわけですね。

## useState
　state、つまり状態を管理するためのフックで、React使うなら基本中の基本とのこと。
　画面に表示される値とかを扱うのに利用するのでほぼ必須機能と考えてよさそう。使うためにはコンポーネントの頭でuseStateをimportし、使いたい状態を入れる変数と状態を変更させる関数のセットをconstで宣言するだけ。

```javascript:useState
import React, {useState} from "react";

const [ stateValue, setState ] = useState("defalutValue");
```

　こうやって宣言したstateValueを画面表示なんかに使ってあげると、そのあとsetStateで設定する値で更新してくれる。なるほど。これは便利。
　よくあるサンプルのカウンタの実装とかだと、+1ボタン、-1ボタン、リセットボタンみたいなのを作って、それぞれのonClickから呼び出されるイベントの中でsetStateに+1,-1,0の値を渡してあげる感じ。
　なお、今のstateValueの値、をsetStateの引数で受け取ることも出来るので、使いたい場合は値を受け取るアロー関数を記述する。

```javascript:setState
// 値を受け取らない
setState(NEW_VALUE);

// 値を受け取る（今の値+1を設定する）
setState((current_value) => current_value + 1);
```

## useEffect
　useEffectの公式説明は以下のような感じ。
> 副作用を有する可能性のある命令型のコードを受け付けます。
> 
> DOM の書き換え、データの購読、タイマー、ロギング、あるいはその他の副作用を、関数コンポーネントの本体（React のレンダーフェーズ）で書くことはできません。それを行うと UI にまつわるややこしいバグや非整合性を引き起こします。
> 
> 代わりに useEffect を使ってください。useEffect に渡された関数はレンダーの結果が画面に反映された後に動作します。副作用とは React の純粋に関数的な世界から命令型の世界への避難ハッチであると考えてください。
> 
> デフォルトでは副作用関数はレンダーが終了した後に毎回動作しますが、特定の値が変化した時のみ動作させるようにすることもできます。

　まぁ、ちょっと何言ってるのかわからない。日本語でおｋ。避難ハッチってなんだよ。
　わからない場合はとりあえず動かしてみましょう。考えるんじゃなくて感じるんだ！

```javascript:useEffect(1)
import React, { useEffect } from "react";

const TestComponent = () => {
  // コールバック関数を定義
  const callbackFunction = () => console.log("コールバックが実行された！");
  // useEffectでコールバック関数と、呼び出すタイミングをセット
  useEffect(callbackFunction,[]);
  return (
    <h1>test</h1>
  );
}

export default function App() {
  return <TestComponent />;
}
```

　コールバック関数を宣言して、それをuseEffect関数の第１引数へ。第２引数にはコールバックが呼ばれる契機になる変数なんかを入れた配列を渡します。今回は[]なので空配列。画面が初期レンダリングされたときに呼び出されます。
 雑なサンプルですが実行結果はこんな感じ。

![react-useEffect_1.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/833719/7d61470d-e9d9-cca0-1fab-06eb9aa7f5d4.jpeg)

　これだけのサンプルだとなんに使っていいかわからないですね。実際には、先のsetStateと組み合わせて特定のstateが変化したときにその値を表示したり、とかに利用します。

```javascript:useEffect(2)
const [ stateValue, setState ] = useState(INIT);
const callbackFunction = () => {
  document.title = `${count}`;
}
useEffect(callbackFunction,[count]);
```

　こうしてやると、countの値が変わるたびにブラウザタブに表示されるタイトルが変わる（意味は、ない。）。

### クリーンアップ関数
　より実用的に使おうとすると、コールバック関数の中でリソースをつかんだり、タイマーをセットしたり、などを行うことになる。
　そうするとちょっとした問題があって、例えばタイマーでポップアップウィンドウを開いたりする仕組みにすると、次にまたコンポーネントが再描画されるときに次のタイマーが新しく作られてしまい、どんどんイベントが重複していく問題にぶちあたる。これを解消するための仕組みがクリーンアップ関数。コールバック関数の中で定義してやることになる。

```javascript:useEffect(3)
const callbackFunction = () => {
  // 例えばタイマーセット
  const timer = setInterval(alert("!!!",1000));
  // クリーンアップ関数
  return () => {
    clearInterval(timer);
  }
}
```

　なんとなくわかったようなわからないような。
　useEffectに関してはすでに有益な記事がたくさんあるのでそちら参照したほうが良い（元も子もない）

 - [React Hooks の useEffect の正しい使い方](https://qiita.com/keiya01/items/fc5c725fed1ec53c24c5)

　まず、初学者が初見ですらすら使える類の機能じゃないが、React使う上では必須になってくるところなので今後経験積みながら覚えていくしかなさそう。
【Flutter】 全画面覆うようにローディングを表示する

appBarも含めて処理中にローディングを回したい時の方法。
備忘録として残します。
処理中にappBarが押せたりすると、思わぬ不具合に繋がります。
```showGeneralDialog```を使うと全画面覆うようにローディングが表示されるので安心です！

※追記
[routemaster](https://pub.dev/packages/routemaster)を使うようになってから、popしても消えなくなってしまいました！！
Navigator.of(context, rootNavigator: true).pop();を使うことで解決しました😭
※さらに追記
[routemaster](https://pub.dev/packages/routemaster)を使う際は、そもそもshowGeneralDialogを使わないで、背景を半透明にするなど、ダイアログっぽいWidgetをルートにpushすれば通常通りにpopすることができました😅


```dart
// 全画面プログレスダイアログを表示する関数
void showProgressDialog(context) {
  showGeneralDialog(
    context: context,
    barrierDismissible: false,
    transitionDuration: Duration.zero, // これを入れると遅延を入れなくて
    barrierColor: Colors.black.withOpacity(0.5),
    pageBuilder: (BuildContext context, Animation animation,
        Animation secondaryAnimation) {
      return Center(
        child: CircularProgressIndicator(),
      );
    },
  );
}

/// 省略 ///

TextButton(
  onPressed: () async {
    showProgressDialog(context);
    await Future<dynamic>.delayed(Duration(seconds: 2));// dialogをawaitできないので、遅延させて調整。。他の方法知っている方いらっしゃいましたら教えてください！！

    // await 何かの処理

    // 処理が完了したらローディングを消す
    if (isCompleted) Navigator.of(context).pop(); // これだと消えない。。
      Navigator.of(context, rootNavigator: true).pop();

  },
  child: Text('登録する'),
)
```

参考にさせていただいたページ
https://cbtdev.net/flutter-progress-indicator/

https://stackoverflow.com/questions/59990277/flutter-navigator-pop-only-when-an-alertdialog-is-shown

最近ぐるぐる回るのじゃなくて、長いのをよく見かける今日この頃
リニアタイプっていうのね。。LinearProgressIndicator()

でもリニアモータカーはmaglev(マグレブ)て言うらしいですよーー

間違いありましたらコメントいただけますと！！！(マグレブの方も)
Rspecでhave_receivedのテストにハマった~subjectはit内で必ず呼び出さなければいけない~

## はじめに
何回も同じ失敗を繰り返さないように自分を戒めるためのメモ書きです

## テストが通らない

### テストしたメソッド
```ruby:user.rb
def user_update
  ~何らかの処理~
  update(params: params)
end
```

### 記述したテスト
```ruby:user_spec.rb
let_it_be(:user) { create(:user) }

describe "#user_update" do
  subject{ user.user_update }
  
  before do
    allow(user).to receive(:update).whith(params: anything)
  end

  it { expect(user).to have_received(:update).with(params: anything).once }
end
```

### 実行結果
```ruby:実行結果
expected: 1 time with arguments: ({:params=>anything})
           received: 0 times
```

## 調査
メソッドの最初とupdateの直後にpryして調査したところ、updateは実行されており、allowかitに問題があるのではないかと踏んで、subject!にしたり、beforeをdescribeの上に記述したりしたが、同じエラーが出てしまった

### 動いたテスト
```ruby:user_spec.rb
let_it_be(:user) { create(:user) }

describe "#user_update" do
  subject{ user.user_update }
  
  before do
    allow(user).to receive(:update).whith(params: anything)
  end

  it do
   expect(subject).to eq(nil) #subjectを呼び出している
   expect(user).to have_received(:update).with(params: anything).once
  end
end
```

## 解説
subjectはit内で呼び出さなければ実行されず、今回のようにテストが通らない
is_expected.toは暗黙的にsubjectを呼び出しているので、subjectを別で呼び出す必要はないが、expect(user)はsubjectを呼び出していないので、別途呼び出す必要がある
もちろん、subjectを呼び出せばいいので、expect(subject)ではなく、subject単体で呼び出したほうが簡潔な記述かもしれない

```ruby:user_spec.rb
it do
   subject #subjectを呼び出している
   expect(user).to have_received(:update).with(params: anything).once
end
```

## まとめ
- subject { ◯◯ } は単に定義しているだけで、別途呼び出さないと実行されない
- is_expected.toは暗黙的にsubjectを呼んでいる
pyqt5を使って、ボタンを押すと、ダイアログを表示する

# コード
1. QtDesigner を使って、画面を作ります。
   - 画面① CountTimer.ui
   - 画面② Input.ui
1. PyUIC を使って、pyファイルに変更します。
1. main.pyで以下のコードを書きます。   

```python
# わかりやすいため、ボタンイベントのコードを略にします
import sys
import PyQt5
import CountTimer
import Input
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtCore import QTimer, QTime
from PyQt5.QtCore import *

# 画面1
class MyClass(QWidget, CountTimer.Ui_Dialog):

    # 初期化関数
    def __init__(self):
        super(MyClass, self).__init__() 
        self.init_ui()

    # 画面初期化
    def init_ui(self):
        self.setupUi(self)
        self.setWindowTitle("計測タイマー")

# 画面2
class NewClass(QWidget, Input.Ui_Dialog):
    def __init__(self):
        super(NewClass, self).__init__()
        self.setupUi(self)
        self.setWindowTitle("Input")

    def button_set_click(self):
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mc = MyClass()
    nc = NewClass()
    mc.button_set.clicked.connect(nc.button_set_click)
    mc.show()
    sys.exit(app.exec_())

```

# 実行結果  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/73df5dac-757b-3726-bdbd-abcecc6de2cd.png)

Set button を押すと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/a5f0be05-724c-79e2-2073-257da4dfd453.png)
Ubuntu20.04 Chrome, FirefoxのWindowが真っ白になる不具合

Nvidiaのプロプライエタリドライバを利用しているUbuntu端末でFirefox、およびGoogle Chromeを利用しており、
自分の場合はさらに３画面の構成も影響しているかもしれない。
同ブラウザを更新した際に、起動後、または新規ウィンドウを開いたときに発生するレンダリングの不具合、検索すると割と長い期間で存在する同様の現象の報告を目にする。
対応策としては設定にてGPU（ハードウェアアクセラレーション）を無効化する。とあるが、


イヤでしょｗ


今回はDriverを470 -> 465に戻すことで修復された。

お試しあれ。
belongs_toのバリデーションについて

以下のような中間テーブルを作成した。

```ruby:tagging.rb
class Tagging < ApplicationRecord
  belongs_to :post
  belongs_to :programming_language
end
```

```ruby:schema.rb
create_table "taggings", force: :cascade do |t|
    t.bigint "post_id"
    t.bigint "programming_language_id"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["post_id"], name: "index_taggings_on_post_id"
    t.index ["programming_language_id"], name: "index_taggings_on_programming_language_id"
end

add_foreign_key "taggings", "posts"
add_foreign_key "taggings", "programming_languages"
```

このテーブルに対するバリデーションテストを作成している時、現在何もバリデーションを実行するコードを書いていないのにバリデーションが発生したので原因を探った。

**`belongs_to`単体のデフォルト設定について**
今回の場合のように単体で用いた場合外部キーカラムに値を設定していなければバリデーションが実行される。

**`optional: true`**
このoptionを渡すことによって外部キーカラムに値が入っていなかったり関連先に存在しないidを設定してもバリデーションが発生しない。

**`required: false`**
`optional: true`と同様の機能を果たすオプションとして`required: false`が存在する。
これは、Rails5以前ではデフォルトで`required: false`になっていたもので当時は外部キーに対するバリデーションを行うためにこのオプションを`true`にしなければならなかった。
しかし、dhh曰くこの挙動はおかしいのでデフォルトで`true`にしようとなったが、デフォルトで`true`となるオプションはダメなんじゃないの？ということで`optional`という代替オプションが誕生したっぽい
これがその時の[issue]
(https://github.com/rails/rails/issues/18233#issuecomment-68256740)?
【Django】filter/get/excludeで複数の条件指定やQuerySetを結合する方法

## 単一の条件指定
通常このように指定していると思います。

```python:views.py
#QuerySetで返す
MyUser.objects.filter(name=query)

#ひとつだけ返す（確実にデータがある場合にのみgetは使う）
MyUser.objects.get(name=query)

#除外する
MyUser.objects.all().exclude(name=query)
```

## 複数の条件指定
### andの場合
複数の条件<b>全てを満たすものを取得</b>する場合`,`を使います。

```python:views.py
#名前にtaroを含む20歳のユーザーを取得
MyUser.objects.filter(name__icontains="taro", age="20")

#名前がtaroで20歳のユーザーを取得
MyUser.objects.get(name="taro", age="20")

#名前にtaroを含む20歳のユーザーを除外
MyUser.objects.all().exclude(name__icontains="taro", age="20")
```

### orの場合
条件を<b>一つでも満たすものを取得</b>する場合`Q objects`と`|`を使います。

```python:views.py
from django.db.models import Q

#名前にtaroを含むか、20歳以下のユーザーを取得
MyUser.objects.filter( Q(name__icontains="taro")|Q(age__lte="20") )

#名前にtaroを含むか、20歳以下のユーザーを除外
MyUser.objects.all().exclude( Q(name__icontains="taro")|Q(age__lte="20") )
```
上記の場合、taroを含む全てのユーザーと、20歳以下の全てのユーザーが取得できます。

### andとor両方使う場合
`Q objects`と`キーワード引数`を混在させる場合は、先に`Q objects`を書くこと。

```python:views.py
from django.db.models import Q

#Tokyo出身で、名前にtaroを含むか、20歳以下のユーザーを取得
MyUser.objects.filter(
    Q(birthplace="Tokyo"), Q(name__icontains="taro")|Q(age__lte="20"))

#キーワード引数を使う場合
MyUser.objects.filter(
    Q(name__icontains="taro")|Q(age__lte="20"), birthplace="Tokyo",)

#これだと無効になる
MyUser.objects.filter(
    birthplace="Tokyo", Q(name__icontains="taro")|Q(age__lte="20"))
```
::: note info
全てQ objectsにすれば順番は気にしないでOK！
:::

::: note warn
先にキーワード引数を書くと無効になるので注意！
:::

https://docs.djangoproject.com/en/3.2/topics/db/queries/#complex-lookups-with-q-objects

## 複数のQuerySetを結合する
複数のQuerySetを結合したい場合は`|`を使う。

```python:views.py
hoge1 = MyUser.objects.filter(hogehoge1)
hoge2 = MyUser.objects.filter(hogehoge2)

#hoge1と2のQuerySetを結合する
total_hoge = hoge1|hoge2

#QuerySetから本人を除外する
total_hoge = (hoge1|hoge2).exclude(id=request.user.id)

#重複を無くす（※注意）
total_hoge = (hoge1|hoge2).distinct()
```

重複について`shell`で確認したところ、`hoge1|hoge2`の時点で重複が無くります。

なので、<b>クエリが複数のテーブルにまたがっている場合など、何らかの理由で重複が発生した場合以外</b>は使わないでOK！

というのも・・

### distinctは注意

::: note warn
データベースの種類やorder.byの有無で機能しない場合があります。
:::

`PostgreSQL`とそれ以外で書き方が変わります。

詳しくは公式ページで確認してみてくださいまし！

https://docs.djangoproject.com/en/3.2/ref/models/querysets/#distinct

### 演算子で結合
この方法は重複等色々手間が発生するで、上記の`|`をオススメしますが一応紹介。

```python:views.py
hoge1 = MyUser.objects.filter(hogehoge1)
hoge2 = MyUser.objects.filter(hogehoge2)

#hoge1と2のリスト化して結合する
total_hoge = list(hoge1) + list(hoge2)

#.excludeは使えないので結合する前に除外しておく
hoge1 = MyUser.objects.filter(hogehoge1).exclude(id=request.user.id)
hoge2 = MyUser.objects.filter(hogehoge2).exclude(id=request.user.id)
#本人を除外した
total_hoge = list(hoge1) + list(hoge2)
```

いや、もう演算子を使うのは色々と不便なので却下ですね笑

ちょっと助長でしたがこんな感じです！