OmniAICreator/Qiita-1.07M huggingface dataset:
testcafe-blink-diffにて、画像を自動で比較するまでの、道のり。

#はじめに
testcafe-blink-diffにて、画像を自動で比較するまでの、道のり。
testcafe-blink-diffというものを使いました。


#最終更新日
2022年01月04日

#環境の情報
OS
Ubuntu20.04

#注意
最新の状態を確認して下さい。

#公式はこちら
https://testcafe.io/
https://www.npmjs.com/package/testcafe-blink-diff/v/0.3.1

#参考さま
https://github.com/tacoss/testcafe-blink-diff
https://qiita.com/naka_kyon/items/c3acbf3954d3db555476
https://qiita.com/at-946/items/fa1c089c153d83f48a03
https://testcafe.io/documentation/402702/reference/test-api/testcontroller/expect
https://testcafe.io/documentation/402639/reference/command-line-interface#takeonfails

#状況
https://qiita.com/berukokoko/items/c8a6c0b89eb1629dacbe
の続きとなります。

下記のように実行して、base.pngのスクショは撮れましたでしょうか。

```
npx testcafe chrome test.js --take-snapshot base
```
↓

撮れたら、同じように、actualに変えてやってみましょう。

```
npx testcafe chrome test.js --take-snapshot actual
```

↓

同じようにactualも撮れたのを確認できましたでしょうか。
![Screenshot from 2022-01-04 21-27-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/5a4cc0d1-8c3d-296f-65f8-2e6a6cde3934.png)

↓

actualの画像を、ちょこっと編集して変えましょう。
ちょっと位置をずらしてみます。
（ホントはテストと本番とかで比較したりするけど、
環境作ることが出来なかったので、試しに、何か細工してみて下さい。）
![Screenshot from 2022-01-04 21-27-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/8f4cd3aa-2fed-3648-b111-dcbf5637c2b5.png)

↓

このように実行してみます。

```
npx testcafe-blink-diff screenshots/Snapshots --open --threshold
```

↓

out.pngというファイルが出来ています。

```
/test/screenshots/Snapshots/check_something_here
 ls
actual.png  base.png  out.png  thumbnails
```

↓

見てみます。
じゃーん！差分が分かります！比較できました！
![Screenshot from 2022-01-04 21-43-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/6067be12-daa4-50fe-c58d-2e66d627908a.png)

![out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/37cbac5e-8bea-7c4d-7107-b84938017e2b.png)
Docker環境でPHP7→PHP8へバージョンアップ

#はじめに
PHP7.3のセキュリティサポートが2021年12月6日に終了しPHP8.1　にバージョンアップしたので備忘録としまとめます。


##インストール手順(詰まった箇所も含む)
```
$ php -v
PHP 7.3.20 (cli) (built: Jul 22 2020 10:03:35) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.20, Copyright (c) 1998-2018 Zend Technologies
    with Xdebug v3.0.4, Copyright (c) 2002-2021, by Derick Rethans
```

現在のバージョンはPHP7.3です。
バージョンはdockerfileで管理してるので修正します。

```docker:Dockerfile
FROM php:8.1.1-apache //ここでバージョン指定。

RUN apt-get update \
    && apt-get -y install --no-install-recommends vim wget lsb-release libicu-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev libzip-dev zlib1g-dev unzip \
    && docker-php-ext-install pdo_mysql mysqli intl zip \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd
RUN ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load
RUN ln -s /etc/apache2/mods-available/vhost_alias.load /etc/apache2/mods-enabled

以下略、、
```

###コンパイル時にエラーが発生しました。

```
configure: error: unrecognized options: --with-freetype-dir, --with-jpeg-dir
```
--with-freetype-dir, --with-jpeg-dirを推奨していないようなので、各々の-dirを削除します。
--with-freetypeと--with-jpegに修正します。


```docker:Dockerfile
FROM php:8.1.1-apache //ここでバージョン指定。

RUN apt-get update \
    && apt-get -y install --no-install-recommends vim wget lsb-release libicu-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev libzip-dev zlib1g-dev unzip \
    && docker-php-ext-install pdo_mysql mysqli intl zip \
    && docker-php-ext-configure gd --with-freetype=/usr/include/ --with-jpeg=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd
RUN ln -s /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load
RUN ln -s /etc/apache2/mods-available/vhost_alias.load /etc/apache2/mods-enabled

以下略、、
```

再度、dockerコンパイルします。

```
$ php -v
Failed loading /usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so:  /usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so: cannot open shared object file: No such file or directory
PHP 8.1.1 (cli) (built: Dec 21 2021 19:41:31) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.1, Copyright (c) Zend Technologies
```
PHP8.1.1のインストールは完了しましたが、xdebugが動作していないです。

php.iniの修正を修正します。

```php.ini
[xdebug]
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20180731/xdebug.so //ここを20210902へ変更します。
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20210902/xdebug.so
xdebug.client_host = host.docker.internal
```

再度、コンパイルします。

```
$ php -v
PHP 8.1.1 (cli) (built: Dec 21 2021 19:41:31) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.1, Copyright (c) Zend Technologies
    with Xdebug v3.1.2, Copyright (c) 2002-2021, by Derick Rethans
```
無事にバージョンアップが完了しました。
PHPで名前空間が使われていない古いライブラリを使うときにハマった話

# クラスがインポートできない


現在phpでは基本的にクラスはオートロードするだろう。
しかし以前はrequire_onceなどを使ってディレクトリで読み込んだりしていたことがあった。もちろん名前空間、それを利用するuse文も使っていなかった。

```
require_once();
```


##結論

名前空間が使われていないライブラリのクラスの最初の文字に
\ (バックスラッシュ)をつけるだけだ。
どうやらこれでグローバルなクラス？を使えるらしい。
もちろん古いライブラリの使いたいクラスを
require文で読み込んでいることが条件だ。




 ```
new somethingClassNameDayo();
 ```
こうでおじゃ

 ```
new \somethingClassNameDayo() 
 ```
testcafe-blink-diffにて、画像のスクショを撮るまでの道のり。


#はじめに
testcafe-blink-diffにて、画像のスクショを撮るまでの道のり。
比較を行うために、testcafe-blink-diffというものを使いました。


# 最終更新日
2022年01月04日

# 環境の情報
OS
Ubuntu20.04


# 注意
最新の状態を確認して下さい。

# 公式はこちら
https://testcafe.io/
https://www.npmjs.com/package/testcafe-blink-diff/v/0.3.1

#参考さま
https://github.com/tacoss/testcafe-blink-diff
https://qiita.com/naka_kyon/items/c3acbf3954d3db555476
https://qiita.com/at-946/items/fa1c089c153d83f48a03
https://testcafe.io/documentation/402702/reference/test-api/testcontroller/expect
https://testcafe.io/documentation/402639/reference/command-line-interface#takeonfails



#状況

```
とりあえずフォルダとか作って、そこへ移動します。
試しに、testフォルダに作ります。
cd test/
```

↓

インストールしよう。
（npmなかったら持ってきてね）

```
$ npm i testcafe-blink-diff --save-dev
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN eslint-loader@4.0.2 requires a peer of webpack@^4.0.0 || ^5.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN testcafe-blink-diff@0.4.11 requires a peer of testcafe@^1.9.4 but none is installed. You must install peer dependencies yourself.

+ testcafe-blink-diff@0.4.11
updated 1 package and audited 244 packages in 8.667s

22 packages are looking for funding
  run `npm fund` for details

found 4 vulnerabilities (1 low, 1 moderate, 2 high)
  run `npm audit fix` to fix them, or `npm audit` for details
```
↓

```
なにかjsファイルを作ります。
ここでは、test.jsとかにしておきます。
test$ ls
test.js
```

↓

こんな感じで書いてみます。

```test.js
import { takeSnapshot } from "testcafe-blink-diff";

fixture("Snapshots").page("https://www.google.com/");

test("check something here", async (t) => {
	await takeSnapshot(t);
});
```


↓

コマンドを立ち上げ、こんな感じで実行してみます。

```
npx testcafe chrome test.js --take-snapshot base
```
↓

こんな感じになれば大丈夫。

```
 Running tests in:
 - Chrome 96.0.4664.45 / Linux 0.0

 Snapshots
 ✓ check something here (screenshots:
 test/screenshots/Snapshots/check_something_here/base.png)
```

↓

ここに保存されています。

![Screenshot from 2022-01-04 21-09-17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/61a46414-5827-5e9f-4f81-d48350ed5e50.png)

じゃーん！
撮れていれば問題ありません。
![base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148394/f2032635-f41f-c828-8935-dfb35b2563e3.png)

続く。
【MUI】@mui/material/stylesでhoverを書く【styled-component】

<h2>@mui/material/stylesでhoverを書く</h2>
若干はまったのでメモ。

@mui/material/stylesでhoverやtransitionsを書こうとしたときにコンパイルエラーで弾かれまくったので、ここに書き方を記していきます。

<h2>実装方法</h2>

```react
import * as React from 'react';
import { styled } from '@mui/material/styles';
import SendIcon from '@mui/icons-material/Send';
import LoadingButton from '@mui/lab/LoadingButton';
import { styled } from '@mui/material/styles';

const CustomButton = styled(LoadingButton)({
  backgroundColor: 'red',
  "&:hover": {
    backgroundColor: 'blue',
  },
});

export function Button = () => {

  return (
    <div>
      <CustomButton
        size="large"
        variant="contained"
        color="primary"
        onClick={handleClick}
        loading={loading}
        loadingPosition="end"
        endIcon={<SendIcon />}
        className={classes.button}
      >
        {btnLabel}
      </CustomButton>
    </div>
  )
}

```

ホバー前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/1d179951-749f-74c8-c769-b1e94f8f65b0.png)

ホバーなう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927880/674b1701-86b4-d26d-24d6-549ecbd92253.png)


<h2>参考</h2>

https://mui.com/styles/basics/#styled-components-api

https://developer.mozilla.org/ja/docs/Web/CSS/transition
history.backを使わないで戻るボタンを作成する

##はじめに
history.backを使用して「戻る」ボタンを実装していたが、firefoxでセッションエラーになってしまうため別の方法で戻るボタンを実装したい。

##解決策
リファラ情報を取得して実装する

```
var ref = document.referrer;
```

ブラウザの閲覧履歴を取得：history.back
直前に閲覧していたページを取得：document.referrer
とのこと

##実装
```javascript:戻るボタン
<a href="##" onClick="go_back();"><b>戻る</b></a>
```

```javascript:処理
    function go_back(){
        var ref_tmp = document.referrer; 

        DF = document.form1;
        DF.action = ref;
        DF.submit();
    }
```
gitbash で vue-cli する際にカーソルキーが効かなくなった場合の対処法（メモ）

# 概要

GitBash で `vue create xxxx` を実行した際にカーソル上下で選択肢を選ばないといけないのだが、縦棒カーソルが上下に実際に文章に関係なく動いてしまい、選択肢を選ぶことができない。

# 対処法

```bash
echo 'alias vue="winpty vue.cmd"' >> ~/.bashrc
```

を実行して、GitBash 再起動。
すると初回のみ `.bash_profile` が無いとかで赤文字の警告でますが、自動修復されるので次からは出ない。
これで直る。


# 参考

https://stackoverflow.com/questions/51297079/vue-cli-arrow-key-not-working-while-creating-new-project-on-git-bash-windows
Go の気になったコミット (2021 年 12 月)

[golang/go](https://github.com/golang/go) の master ブランチに行われたコミットから個人的に気になったものをリストにしたものです。

前回作成したリストはこちら。

https://qiita.com/sg0hsmt/items/c3c3523e4f0fe6b69320

軽く説明を追加していますが勘違いや誤りがあるかもしれません。

## Topic

https://go.dev/blog/go1.18beta1

- Go 1.18 Beta 1 がリリースされました。 :rocket:

## Commits

### 2021-12-02

https://github.com/golang/go/commit/08ecdf7c2e9e9ecc4e2d7c6d9438faeed2338140

弱いメモリ一貫性モデル (メモリ参照命令が任意に並び変えられる) のアーキテクチャで実行した場合に GC が nil アクセスする不具合が修正されています。
関連 Issue を見ると以前から CI で発生していたようです。 [^1] [^2] [^3]

[^1]: https://github.com/golang/go/issues/43824
[^2]: https://github.com/golang/go/issues/48845
[^3]: https://github.com/golang/go/issues/49686

### 2021-12-09

https://github.com/golang/go/commit/f5b5939c28ecb8b8c0897584fed78589c27348f6

Go コンパイラ自体が Go で実装されていることは有名です。
この変更は開発環境のブートストラップに使う Go を Go 1.4 から Go 1.17 に変更するための準備です。 [^4]

[^4]: https://github.com/golang/go/issues/44505

当初は Go 1.18 で切り替えたかったようですが今回は Go 1.17 がインストールされていればそれを使用し、なければ Go 1.4 を使用するようになっています。

Go 1.17 に変更することで Go 1.4 がサポートしていない環境での開発が可能になるほか、ブートストラップコードで新しい言語機能を使えるようになります。

https://github.com/golang/go/commit/ac7e950d385b871ca28e1ac723d6ad97ebe3a4d7

https://github.com/golang/go/commit/6b609110fdfab4a496c246889f1e67fd7cba61df

型チェック時の依存関係グラフ計算が改善されています。
大きなパッケージでは影響が出てきそうです。 [^5]

[^5]: https://github.com/golang/go/issues/49856

https://github.com/golang/go/commit/7b7efd7a7c952f8b372c861c94acd159ee371acb

Go 1.18 は Go 1.17 よりビルドが約 15% 遅くなっているという記載がリリースノートに追加されています。
ジェネリクスサポートによるオーバーヘッドが速度低下の主原因で Go 1.19 で改善する予定とのことです。 [^6]
ジェネリクスを使用しておらずビルド速度が問題になる場合は `-G=0` オプションで回避できるようです。

[^6]: https://github.com/golang/go/issues/49569

### 2021-12-14

https://github.com/golang/go/commit/2580d0e08d5e9f979b943758d3c49877fb2324cb

Go のソースに含まれている `interface{}` がすべて `any` に書き換えられました。
Go 1.18 の `any` は `interface{}` にエイリアスとして定義されているため既存コードへの影響はありません。 [^7]

ただし、 `gofmt -w -r 'interface{} -> any' src` で書き換えたためコメントが修正されていないという指摘がされているようです。 [^8]

[^7]: https://qiita.com/sg0hsmt/items/06449d7ec8382b68d457
[^8]: https://github.com/golang/go/issues/49884#issuecomment-994117356

### 2021-12-15

https://github.com/golang/go/commit/becaeea1199b875bc24800fa88f2f4fea119bf78

Go 1.18 の API リストが作成されました。 :tada:
ここまでのコミットが Go 1.18 Beta 1 に含まれているようです。

## 雑感

Go 1.18 リリースが近づいてきたこともあり不具合修正とドキュメント修正が中心になっています。

また、 Go チームは 2021 年 12 月 17 日～ 2022 年 1 月 4 日にかけて「静かな週」に入っていたためそれほど動きがなかったようです。

https://github.com/golang/go/issues/50241
【gulp V4系】sassを自動でコンパイルするgulpfile.jsを書く

# はじめに

数年前、以下の記事を投稿した。

https://qiita.com/shimisunet/items/d8827b20cd5aeab2f9d2

現在、「gulp」はV4系がリリースされている。また、「gulpfile.js」で「gulp.task()」の記述が非推奨になっており、この記事はかなり古い情報と化していた……。
今回も何番煎じかわからないが、「gulp」のV4系でsass(scss) を自動コンパイルできるようにした。

# 環境
以下は、参考まで。

* OS：Windows 10
* Node.js：v14.15.0

# インストール
コマンドプロンプトにて、「npm」コマンドでインストールする。
予め「npm init」を実行し、「package.json」を作成しておく。

始めに、「gulp」をグローバルインストールする。

```
npm install -g gulp
```

次に、「package.json」のあるフォルダで「gulp」をローカルインストールする。
また、今回は、V4系の「gulp」をインストールするので、バージョンを指定し、ローカルインストールする。

```
npm install --save-dev gulp@4.0.2
```
「gulp-sass」と「sass」も併せてローカルインストールする。

```
npm install --save-dev gulp-sass sass
```

# gulpfile.js

「gulpfile.js」を作成する。
sass(scss) ファイルの格納場所や、コンパイルで生成されたcss ファイルの出力先などの設定を記述する。

```gulpfile.js
// 本体とプラグインの呼び出し
const { src, dest, watch } = require('gulp');
const sass = require('gulp-sass')(require('sass'));

// 監視ファイルと出力先フォルダ
const srcPath = 'sass/**/*.scss';
const distPath = 'css';

// コンパイル処理
const compileSass = () => {
    return src(srcPath)                            // 監視ファイル
        .pipe(sass({ outputStyle: 'compressed' })  // 出力形式はcompressed
            .on("error", sass.logError)            // sassのコンパイルエラー表示
        )
        .pipe(dest(distPath))                      // 出力先フォルダ
}

// sassの常時監視、変更があったら変換する
const watchSass = () => {
    watch(srcPath, compileSass);
}

// タスクの実行
exports.default = watchSass;
```
コンパイルタスクと常時監視タスクはメソッドにし、「exports.default」でタスクを実行する。

# gulp の実行
コマンドプロンプトで「package.json」があるフォルダへ移動。
「gulp」で実行する。
実行後、sass(scss) ファイルの監視が始まり、sass(scss) ファイルに何かしらの変更があるとコンパイルする。

```
D:\Myproject>gulp
[18:42:13] Using gulpfile D:\Myproject\gulpfile.js
[18:42:13] Starting 'default'...
[19:13:08] Starting 'compileSassFile'...
[19:13:09] Finished 'compileSassFile' after 1.55 s
[19:13:16] Starting 'compileSassFile'...
[19:13:16] Finished 'compileSassFile' after 162 ms
```

# 参考URL

ありがとうございました。

https://note.com/kei_01011/n/n34220e142583

https://zenn.dev/serina_yam/articles/197a15562949f9
➁PythonAnywhereの無料アカウントでGoogle Newsをスクレイピング

クラウド上のサーバーでPythonのコードを実行できるPythonAnywhereでアカウントを作ったので、
手始めにYahoo! Japanのtopicsをスクレイピングしたかったのですが、403 Forbiddenエラーになります。これは、無料アカウントではPythonAnywhereからアクセスできるサイトが限られているためです。

Google.co.jpはアクセスできたので、Google Newsからヘッドラインをスクレイピングすることにしました。
https://news.google.co.jp 

![スクリーンショット 2022-01-04 203150.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/823476/f5e41357-f060-af97-99a7-be21390160b2.png)

コードはこちらのサイトにのっているYahoo!のトピックスをスクレイピングするものをGoogle News用に変更しました。

【Webスクレイピング入門】ヤフーニュース の見出しとURLを取得する方法
https://rurukblog.com/post/python-webscraping-ynews/

```python
import requests
from bs4 import BeautifulSoup
import re

# Googlニュースのトップページ情報を取得する
URL = "https://news.google.com/topstories?hl=ja&gl=JP&ceid=JP:ja"
rest = requests.get(URL)

# BeautifulSoupにGoogleニュースのページ内容を読み込ませる
soup = BeautifulSoup(rest.text, "html.parser")

# Googleニュースの見出しとURLの情報を取得して出力する
data_list = soup.find_all('h3')
for data in data_list:
    print(data.text)
```

これをメモ帳か何かで"googleNewsTopics.py"などの名前で保存して、ファイルをアップロードします。この画面でUpload a fileのボタンを押して、ファイルを選択します。
![スクリーンショット 2022-01-04 203859.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/823476/fe143162-7b3e-f152-7ce6-23fc75a40b01.png)

そして、bash consoleから実行するだけです。
![スクリーンショット 2022-01-04 204136.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/823476/57757b79-096e-8f1a-5f28-32d14d3b3b0d.png)

Google Newsのheadlineの抜き出すタグh3はFirefoxのWeb開発ツールでh3のタグを探しました。
（ここらへんは他でも紹介されていると思うので、割愛します）

----

参考にしたページなど：

初心者向け Pythonanywhereを使ってみよう
https://qiita.com/tonytani37/items/60c7185b7cc235f45daf

次はこのスクレイピングした結果を、前回の記事
[Python] 初心者向け　簡単　pythonAnywhereの無料アカウントからメールを送る
https://qiita.com/Kent-747/items/fa92c51d81cd4f50eadc
と組み合わせ、メールにて送ってみようと思います！


----
PythonAnywhereで無料アカウントからアクセスできるサイトのドメインはこちらのwhite listにのっています。
https://www.pythonanywhere.com/whitelist/

あまりjpのついたサイトはないですね。。

たしか月５ドルほどで、制限なしになるので、もう少し慣れてきたら有料アカウントも検討したいと思います！
ゆるいスクラムからはじめてみる(Sprint 0)

## これはなんですか
スクラムを推奨しないスクラムマスターのゆるいスクラムをやってみたらどうかの実・・トライです。
連載企画です。**現在進行系でやってるなんてそんなことないよ？**
失踪したらクビになったか失敗したと思ってください。

## お前誰
戦うスクラムマスターです。クラスはルーラー。

## なんでそげなこと考えるの？
いきなり謎な仕組みを押し付けられる方の身になってみたらわかるんじゃないかな・・
あと、形骸化しがちな各種セレモニーが**くそかったるい**ので、スクラムのエッセンスだけ抽出、再構成してプロジェクト運営の骨子に据えてみようと思いました。

また、フルタイムではない人がほとんどのリモートワークでは時間を合わせるということがなかなかしんどくて、デイリーやったりするのがしんどいです。
例外はあると思いますが、一見集まらなければならなそうなことも、個別でやるか、チャットかインスタントな個別/グループ通話でなんとかなるんじゃないかとも思っています。

## ほう、そなたの意見を申してみ？
スクラムセレモニーを改変します。

1. デイリーミーティング→言いたいことがある人がいて必要なら開催を提唱する
2. グルーミング→やります
3. 計画会議→やります、PO説明と質疑応答→やります、SBL分解→やります、時間みつもり→やるけどざっくり
4. カンバン→使います
5. 振り返り→雑談モードでゆったりとやります　紙に書いたりはしません 無理そうなら個別に振り返り的な雑談をふっかけます。
6. POレビュー→POが希望すればやります。少なくとも 2 sprintには１回やったほうがよいでしょう。

抜けたエッセンスを補完するため、下記のルールをプロジェクトに足します
1. 個別通話、あるいはグループ通話で決めたことは必ずチャットに@ hereつけて貼る
1. １日なにやったかざっくりと書く、例：メールテンプレートの作成、ER図（ユーザ周り更新）、昼飯は○○さんと相談して各自ラーメン食べにいきそのレビューを公開することにした
1. (私向け)いきなりスクラムの専門用語を使わない、(Sprint, backlog, Velocity, など、必ず注釈をつけるか、専門用語を注釈にする）
1. スクラムライクだけど、厳密なスクラムやりたいかどうかはあなたたち次第。最初は推奨しない理由を説明する。
1. デイリーやるやらないに関わらず情報の共有、発信に熱心になる

## 懸念点
リモートワークなので何していいかわからない人、特に新人さんのフォローのためそういう人が入ってきたら個別でもしくは全体デイリーを毎日やるようにする。

レッツトライ！！
自分用GoでAPIを作る前に作るHttpClientラッパー

Go で API を作るときは実際にサーバを起動して HTTP で叩くテストを作りたいので HTTP で叩くのを簡単にする自分用ツール。認証を回避できない環境で Swagger とか POSTMAN を手作業でAuth通して叩くのは面倒なので Go Test 上で認証して叩くことができる。おまけでレスポンスの Unmarshalもできる。[GitHubはここ](https://github.com/turanukimaru/knocker)。
いつでもAPIが叩けると精神衛生上良いし、フロントからエラー報告が来た時もすぐ検証ができる。
GitHub にアクセスできない仕事場が稀に良く有るので貼り付けさせてください。

使い方

```Go

// ここまで省略。 Server を起動しておいてから以下を実行するテストコードを書く。
// サーバー接続情報を作る
	k := Knocker{"127.0.0.1", 8080, ""}
// シンプルな Get ただし認証が通らない。b は res.Body の文字列
	t.Run("Required authorization token not found", func(t *testing.T) {
		res, b, err := k.Knock(http.MethodGet, "/private", nil, nil)
		if err != nil {
			panic(err)
		}
		assert.Equal(t, 401, res.StatusCode)
		assert.Equal(t, b, "Required authorization token not found\n")
	})
// 認証を通してから Get
	t.Run("Auth and OK", func(t *testing.T) {
		res, _, err := k.Auth(http.MethodGet, "/auth", nil)
		if err != nil {
			panic(err)
		}
// レスポンスの中身が検証しやすいように Unmarshal する機能が入っている。
		v := &PrivateResponse{}
		res, _, err = k.Knock(http.MethodGet, "/private", nil, v)
		if err != nil {
			panic(err)
		}
		assert.Equal(t, 200, res.StatusCode)
		assert.Equal(t, v.Tag, "Go")
	})
// 略

// Private api　サーバ側でレスポンスを作っているコード
var private = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	reply:= PrivateResponse{
		Title: "jwt token が無いとアクセスできないはず",
		Tag:   "Go",
	}
	json.NewEncoder(w).Encode(reply)
})

// Private Response サーバ側のレスポンス構造体。テストからそのまま参照して使う。
type PrivateResponse struct {
	Title string
	Tag   string
}


```

実コード。

```Go

// Knocker is http client wrapper that Keep connection strings and Bearer token.
type Knocker struct {
	Host  string
	Port  int
	Token string
}

// Knock send request with Bearer token and unmarshal response json.
func (k *Knocker) Knock(method string, path string, param io.Reader, v interface{}) (response *http.Response, body string, err error) {
	url := fmt.Sprintf("http://%s:%d%s", k.Host, k.Port, path)
	request, err := http.NewRequest(method, url, param)
	if err != nil {
		return nil, "", err
	}
	if k.Token != "" {
		request.Header.Add("Authorization", "Bearer "+k.Token)
	}
	res, err := http.DefaultClient.Do(request)
	if err != nil {
		return nil, "", err
	}
	defer func() {
		err := res.Body.Close()
		if err != nil {
			panic(err)
		}
	}()
	resBody, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, "", err
	}

	if v != nil {
		if err := json.Unmarshal(resBody, v); err != nil {
			return nil, "", err
		}
	}

	return res, string(resBody), nil
}

// Auth send request and keep response string in Token.
func (k *Knocker) Auth(method string, path string, param io.Reader) (response *http.Response, body string, err error) {
	response, body, err = k.Knock(method, path, param, nil)
	k.Token = body
	return
}

```

あ。パラメータPOSTするテスト書き忘れた…明日で良いか。
wslからgoogle-chromeでchromeを起動したい

wsl上のUbuntuからWindows上のChromeを起動したいケースってあるよね。

ガチLinuxのUbuntuではchromeには`google-chrome`という起動スクリプトが作られる。chromeの起動くらいは、ガチUbuntuとwsl Ubuntuと同じソースで動かしたい。

ということでWSL上にもWindows側のChromeを起動するスクリプトを作ってあげれば同じように起動できる。

```
$ /usr/local/bin# cat google-chrome
#!/bin/bash
exec "/mnt/c/Program Files/Google/Chrome/Application/chrome.exe" "$@"
```

パスの通ったところ(ここでは`/usr/local/bin`）に、シェルスクリプトを作る。

`$@`を使ってシェルスクリプトに渡された引数はすべて本体のchromeに渡してる。

あとは、ファイルに実行権限をつけてあげればOK。
vimを使わないviで一括コメントアウト

### vimで用いられる一括コメントアウトの方法
1. 「Ctrl+v」 で矩形選択にします
2. コメントアウトしたい行を選択（j , k or キーボードの上下キー選択）
3. 「Shift+i」 （iの大文字）で挿入モードにします
4. コメントアウトの文字を入力します
5. 「Esc」を入力すればコメントアウトされます

上記の方法が使えなかったので下記を代わりに実行
### vimの方法を使わない一括コメントアウトの方法
1. [v]でビジュアルモードに移行
2. 一括挿入したい範囲をカーソルキーで選択
3. [:s]と入力、続けて一括挿入したいのが//の場合[/^/\/\//]と入力(#の時は[/^/#/]と入力)
4. returnキーで一括挿入完了

コメントアウト記号が//の時はエスケープが必要なのでバックスラッシュ（\）が入っています。

### 参考
https://yuuturn0422.hatenablog.jp/entry/2015/01/31/233533
MySQL5.6を5.7にバージョンアップしてみた

## はじめに
RDSではMySQL5.6のサポートを2022/2/1で終了します。
https://aws.amazon.com/jp/blogs/news/amazon-rds-for-mysql-5-6-extending/

サポート終了後はMySQL5.6のサーバーを新しく作成することができなくなります
そのため障害が発生した場合、ポイントインタイムリカバリーでの障害復旧ができないことになるのでバージョンアップはお早めに。。。

ということで今回はRDSのMySQL5.6をMySQL5.7にバージョンアップする手順をまとめました


## バージョンアップ手順の概要
1. スナップショット取得
1. バージョンアップ処理
1. 動作確認


## スナップショット取得
バージョンアップの影響で不具合が発生した場合、復旧できるようスナップショットを作成します。

1. RDS > スナップショット > スナップショットの取得 を実行
1. DBインスタンス: `hoge-production`, スナップショット名:`hoge-production-5-6`

## バージョンアップ処理
1. RDS > データベース > anavi-production から右上の「変更」ボタンを押す
1. 以下の二箇所変更する
    * DB エンジンバージョン: `5.7.34`
    * DB パラメータグループ: `defalut-5-7`（5.7用のパラメータグループを作成していない方は新しく作成しましょう）
1. 「DB インスタンスを変更」を押して変更を反映。
1. RDS > データベース > hoge-production > ログとイベント  を見て、バージョンアップの完了を確認する

## 動作確認

ブラウザからアプリケーションの動作確認を行いましょう

何かしら不具合があって修正できなければ次の`バージョンを5.6に戻す手順`へ

## バージョンを5.6に戻す手順(※不具合発生した場合のみ実施)
■ 概要
既存のRDSをダウングレードはできないのでスナップショット(`hoge-production-5-6`)からMySQL5.6のRDSを作成する

■ 手順
RDSのDB識別子がホスト名に使用されるので、競合しないよう不具合の発生したRDSの名称を変更する。

1. RDS > データベース > hoge-production から右上の「変更」ボタンを押す
1. `DB インスタンス識別子`を`hoge-production-5-7`に変更する
1. 「DB インスタンスを変更」を押して変更を反映
1. 名前が変更されたことを確認する
1. 既存RDSの名称変更ができたらスナップショットからRDSを作成する
1. `RDS > スナップショット > hoge-production-5-6 > アクション> スナップショットを復元` を選択
1. DBインスタンス識別子を`hoge-production`にする(※ 別の名称にするとホスト名も変更されて別のサーバーから接続できなくなるので注意)
1. 他の設定は既存のRDS(`hoge-production-5-7`)と同様にする。
1. 設定内容を確認して「DBインスタンスを復元」ボタンを押す
1. 作成されたら動作確認する
昔使ったAWSから謎の請求が止まらない人へ

数年前に、UdemyとかProgateで講座を受けて、AWS(AWS Cloud9とか)を使っている人で、なぜか解除できない請求が来ている方に向けてお送りします。

恥ずかしながら、放置して月200円程度払い続けていたので。。。。

## むかし無料で使えた「アジアパシフィック (シンガポール)」リージョンを、そのままにしておくと、請求が来ます。

今は日本リージョンでないと最小限の利用でも無料じゃないみたいです。
一旦AWSのリージョンをアジアパシフィック (シンガポール)リージョンに変えて、諸々の利用を止めると、請求が止まる可能性があります。ぜひお試しください。
【Rails】ページ毎にタイトルを変更する方法

## content_forを使ってタイトル名を変えていく
``content_for``というヘルパーを使って
**「　ページ名 | 固定タイトル　」**
と出力するやり方を見ていく。

**手順**
①``app/helpers/application_helper``にヘルパーメソッドを記入
②``views/layouts/application``にメソッドを記入
③viewにそれぞれのタイトルを入れていく

## ①``app/helpers/application_helper``にヘルパーメソッドを記入

```app/helpers/application_helper.rb
module ApplicationHelper
    def page_title(page_titlle = '')
        base_title = 'SAMPLE BOARD APP'
        
        page_title.empty? ? base_title : page_title + ' | ' + base_title
    end
end
```

``page_title.empty? ? base_title : page_title + ' | ' + base_title``
この一文は見慣れないが、条件演算子(三項演算子)を使った書き方となっている。
この一文をif分に書き換えると下記のようになる。

```
if page_title.empty?
  base_title
else
  page_title + " | " + base_title
end
```

## ②``views/layouts./application``にメソッドを記入

```views/layouts/application.html.erb
<html>
#省略
  <head>
    <title><%= page_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
  </head>
#省略
```
``<title>``タグの中に、先ほど定義した``page_title``を記入することで、他のページにも柔軟に対応できるようになる。

## ③viewにタイトルを入れていく
``ja.yml``にタイトルの翻訳を済ましている状態かどうか確認する。
例えば、ログインページのタイトルを入れたい時には、``user_sessions.htmlファイル``の**先頭に**タイトルを設定。

```user_sessions.html.rb
<% content_for(:title, t('.title')) %>
```

また投稿毎のタイトルを表示させたい場合は以下のようになる。

```post.html.rb
<% content_for(:title, @post.title) %>
```

## 参考記事
[[Rails] content_forでレイアウトの内容をviewから柔軟に変更する
](https://a-records.info/change-layout-content-by-content_for/)
CocoaPodsとSPMとCarthageを比較してみる

##はじめに
今回はライブラリ管理ツールについてのそれぞれの特徴について調べたのでまとめてみようと思います。

##今回比較すること

まずはCocoapodsとCarthageから比較してみましょう。
実際に特徴とメリデメを踏まえて紹介していこうと思います。
これらはこの後登場するSMP(Swift Package Manager)に比べると比較的古参のパッケージマネージャーです。

###両者の特徴

**CocoaPods**
・歴史が古い（Objective-c時代からある）ため、対応しているライブラリが圧倒的に多い
・Podfileからライブラリ情報取得し、Podsプロジェクトと呼ばれる集約プロジェクトからframeworkを作成する
・Xcodeの仕様に依存する

**Carthage**
・ライブラリ提供者の個人の活動に依存する
・ライブラリ側はXcodeプロジェクトが必要
・事前にframeworkを作成
・.xcworkspaceや.xcodeprojに手を加えない


##両者のメリット・デメリット

###CocoaPods
**メリット**
・対応ライブラリが豊富
・なんと言っても導入、設定が簡単
・依存関係を対象にリンクしビルド全プロセスを自動化できる
・環境構築が早い（導入コストが低い）
・定義元へのジャンプが複数提示されて探しやすい　←これは知らなかった！

**デメリット**
・podfileはRubyで書かれているので多少知識が必要
・xcodeの内部仕様を利用しているため、パージョンアップ時に噛み合わなくなることがある　←これが一番大きい！
・ある程度ビルドに時間がかかる

###Carthage
**メリット**
・ビルド時間が早い
（一度frameworkを作成すればそれ以降はframework側でコンパイルが走ることがないため）
・xcode内部仕様の変更に影響を受けない
・libのビルドや更新が簡単になる
・CI/CDサービスとの連携が比較的簡単にできる

**デメリット**
・環境構築に実装するステップが多い
・対応ライブラリは多いがCocoaPodsに比べると少ない
・定義元へのジャンプ候補が出ないためリーディングがしにくい　←これは知らなかった！

##SPM
apple純正のライブラリ管理ツールです。
比較的最近登場したので、CocoaPodsやCarthageに比べると新しい。

###メリット
・xcodeをインストールすれば使える（環境構築が早い）
・apple純正
・依存関係を簡単に把握することができる
・Linuxで動作する
・依存関係を自動的に管理してくれる

###デメリット
・新しいため対応ライブラリが少ない
・特定のフォルダ構造に従う場合がある
・現在iOS、watchOS、tvOSなどの全てのプラットフォームをサポートしている訳ではない

##今回のまとめ
これからはSPMの時代になっていくと思います。
なんと言っても**apple純正**がキラーワードです。
色々な企業の勉強会に参加させていただいていますが、SPMに移行するという議題で話されていることろもたくさんあるくらいです。

##参考記事
今回の記事は主にこちらを参考にさせていただきました。

https://www.codementor.io/blog/swift-package-manager-5f85eqvygj

https://www.swift.org/package-manager/

https://zenn.dev/kueharx/articles/40d66aad9afd5c

https://blog.mothule.com/ios/ios-carthage-vs-cocoapods
brewコマンド実行時に表示されるPATH/brew: line xx: hogehoge: command not found の解決

macユーザーがお世話になっているであろうbrewコマンドで起きていた、害はないが目障りだった問題を解決していく。

# 発生していた問題
安価で高性能と評判のM1macを使い始めて早半年、こまめに更新しないと気がすまない私は、毎度のごとくiTerm2(terminal)を開き

```zsh:zsh
brew update
brew upgrade
```
を実行した。すると・・・

```zsh:zsh
/opt/homebrew/bin/brew: line 27: readlink: command not found
/opt/homebrew/bin/brew: line 28: dirname: command not found
```
また君か
## hogehoge: command not found
私の環境では`readlink`と`dirname`がcommand not foundと表示されているが、似た問題が発生している方は、もしかしたら異なる単語が乗っているかもしれない。
brewコマンドを叩くたびに毎度毎度出てくるこれらの文は、何か問題を起こすわけではないものの、視覚的に非常に鬱陶しい存在であった。問題が起きないというのも、それはそれで怖い。
しかし、毎度毎度出てくるこの文を削除しようとggってはみたものの、出てくる事例は『homebrewそのものが見つからないの？そんなときはPATHを通しましょうね☆』というものばかりであった。ちゃうねん。
シェルスクリプトに慣れていない私にとって、ｚｓｈではなくbashについての記事ばかりだったのも解決へのモチベ低下の原因だった。

原因となる場所すらいまいちわからず、「homebrewそのものに問題があるのか」「.zshrcで変なものが混じっているのか」「iTerm2の設定で何かやらかしたのか」など悶々していたが、まとまった時間の取れる正月に無事解決できたので、忘れないようにメモしていく。

# 解決策
結論から言うと、.zshrcファイルの記述内容に問題があった。

```zsh:解決前の.zshrc
alias brew="PATH=/opt/homebrew/bin:/opt/homebrew/sbin brew"
```
```zsh:解決後の.zshrc
alias brew="PATH=/opt/homebrew/bin:/opt/homebrew/sbin:$PATH brew"
```

お気づきいただけただろうか？
aliasでbrewの呼び出し宣言時に、読み込むPATHの中に`$PATH`がないのがいけなかったらしい。ここ以前では`$PATH`の宣言をしていないのに・・・
根本の原因は不明だが、ひとまずここで`$PATH`を再帰的に?読み込むことで、どこかにあった`readlink`と`dirname`を見つけてくれたのだろう。

## ここに至るまでの過程
### brewファイルの中身
まず原因がどこにあるのかを特定しないといけない。
そこではじめに、`command not found`の出力に関わっているであろうhomebrewの中身を見ることにした。
[githubにて公開されている内容](https://github.com/Homebrew/brew/blob/master/bin/brew)と比較したものの、ローカルで使用しているものとの差異は見られず、brewに問題がないことがわかった。
また、27,8行目あたりをわからないなりに読んでみたものの、27,8行目で呼び出されている`readlinlk`と`dirname`はそれ以前で宣言されていないこともわかった。
### .zshrcの中身
brewファイル内で`readlink`と`dirname`が宣言されていないのであれば、どこか別のファイルから呼び出されているはずである（私がどこかで削除していなければ。もっともhomeディレクトリより下なんて怖くてあまり触らないが）。
そこで.zshrcで定義しているaliasやPATHがまずいのかもしれないと考え、.zshrcの中身を探してみることにした。
しかし怪しそうなところは見つからない。
仕方がないのでバックアップを取り、内容を徐々に削除してbrewコマンドを打つことを繰り返したものの、それでも.zshrcの中身が空になっただけであった。

### 判明
バックアップから復帰し、とりあえずPATH関係が怪しそうだと見ていったが、それでもわからない。alias定義部分でのPATHで、他のPATH変数で追加されている`:$PATH`がくっついていないので、何となく足してみたら解決した。



この記事はcorne cherry v3で書きました。
Dartで順列組み合わせ

## 背景
つい最近、結構昔にコーディングした内容を、備忘録的に[こんな記事](https://qiita.com/kamekame85/items/8ec7350a263f99d8441d)としてQiitaに載せたのですが、何かの巡り合わせでしょうか・・・？
なぜか今度はDartで順列（上記事では組み合わせのみ記載）を書くことになったので、またしても備忘録として置いておきます。

## 出来上がり
### 順列

``` permutation.dart
List<List<int>> permutation(List<int> list, int n) {
  return n == 1 
  ? list.map((el) => [el]).toList()
  : list.asMap().entries.expand((entry){
  	return permutation(list.sublist(0, entry.key) + list.sublist(entry.key + 1), n - 1)
    	.map((el) => [entry.value] + el).toList();
  }).toList();
}

print(permutation([1,2,3],2));

// expexted : [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]]
```

### 組み合わせ

``` combination.dart
List<List<int>> combination(List<int> list, int n) {
  return n == 1 
  ? list.map((el) => [el]).toList()
  : list.asMap().entries.expand((entry){
  	return combination(list.sublist(entry.key + 1), n - 1)
    	.map((el) => [entry.value] + el).toList();
  }).toList();
}

print(combination([1,2,3],2));

// expexted : [[1,2],[1,3],[2,3]]
```

## 考え方

以前書いたjavascriptと全く同じです。大した内容ではありませんが、気になる方は以下を参照ください。

[JavaScriptで関数型っぽく順列組み合わせを書いてみた](https://qiita.com/kamekame85/items/8ec7350a263f99d8441d)
DataWeaveで全角カナを半角に変換

#DataWeaveで全角カナ文字列を、半角カナに変換する

提案なのか、お客様プロジェクト向けなのか分かりませんが、同僚が全角から半角への変換について社内で質問してましたので、DataWeaveの勉強がてら考えてみました。
私が確認できた方法は２つ。

##方法１： Javaのクラスを利用する
Anypoint Studioでは、Javaのクラスを作成し、DataWeaveからそのクラスのStaticメソッドを呼び出すことが可能となっており、その仕組みを利用した方法です。

まず、下記のようなクラスを、src/main/javaに作成します。

```
import com.ibm.icu.text.Transliterator;
public class hankaku {
	public static String ztoh(String str) {
		Transliterator transliterator = Transliterator.getInstance("Fullwidth-Halfwidth");
		String result = transliterator.transliterate(str);
		return result;
	}
}
```

そして、DataWeaveからはこのように`import java!クラス`で呼び出します。

```
%dw 2.0
import java!hankaku
output applidation/dw
---
hankaku::ztoh("アイウエオ")
```
実行結果はこんな感じ。（Anypoint StudioのTransform Message）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/71c0509d-8524-d26a-7591-3e1aad8afe6d.png)

##方法２： 文字コードで変換する
もう一つは、全角ア～ンから、半角ｱ～ﾝへの変更とはなりますが、文字コードを利用する方法を試してみました。
全角ア～ンは、Unicodeで12450から12531で、一つ飛ばし。
半角ｱ～ﾝは、65393から65437となります。
下記のコードでは、対象の文字列の長さ分の配列を作り、全角カナの範囲であれば半角カナの文字コードを計算して文字を当てはめてます。
最後に、JoinByでくっつけて完成。
これであれば、DataWeaveのみの実装になっています。

```
%dw 2.0
import dw:core:Strings
output application/dw
var str = "アイウエオあいうえお"
var arr = 0 to sizeOf(str) -1
var dat = do {
  arr map (item,index) -> {
    char:  if(12450 <= Strings::charCodeAt(str, item) and Strings::charCodeAt(str, item) < 12531) Strings::fromCharCode((Strings::charCodeAt(str, item) - 12450)/2+65393)
    else Strings::fromCharCode(Strings::charCodeAt(str, item))
  }
}
---
 dat.char joinBy ""
```

下記は、[DataWeave Playground](https://developer.mulesoft.com/learn/dataweave/ )で試した結果です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615564/13f2aa04-bc12-3548-a1d3-cab13796f023.png)
【Flutter】地図ライブラリの比較

# 概要
地図を使用したアプリを開発するにあたり、地図ライブラリの選定を行いました。
いくつか選択肢があったので、簡単に調べた内容を残しておきます。

結論を先に書くと、用途によるけど「google_maps_flutter」か「flutter_map」 の2択で、
対応デバイスや、料金、実装済みの機能を考慮して決めることになりそうです。

今回自分の場合、地図のオフライン表示が必要だったため、「flutter_map」を採用することにしました。
（google_maps_flutterでは未実装だったため。）

# 候補
ざっと調べたところ「google_maps_flutter」「flutter_map」「mapbox_gl」の３つがメジャーな様子。

## google_maps_flutter
https://pub.dev/packages/google_maps_flutter

- 概要
    - Flutter公式によるGoogleMapライブラリ
    - ピン設定や、現在位置表示 など、基本的な機能は充分揃っていそう
    - 新しい機能も順次追加されていっているっぽい
- メリット
    - Flutter公式 によるリリース
        - 色々安心
            - サポート、セキュリティ面 など
    - 資料の多さ
        - Flutter公式だけあって、ドキュメント豊富
- デメリット
    - 有料(になる可能性がある)
        - ある程度は無料で使えるが一定数以上のアクセスがある場合は従量課金
    - オフライン表示に非対応っぽい

## flutter_map
https://pub.dev/packages/flutter_map

- 概要
    - JSの地図ライブラリ[Leaflet] のdart実装版
    - 表示地図は[OpenStreetMap] と呼ばれるオープンソースの地図
- メリット
    - プラグインに対応しており、痒い所に手が届きそう
    - 無料(?)
- デメリット
    - google_maps_flutter に比べるとドキュメントが少ない
        - 特に日本語のドキュメント
        - とはいえ、サンプルが充実してるのもあり、普通に使う分には困らなさそう

## mapbox_gl
https://pub.dev/packages/mapbox_gl

- 概要
    - like数多かったので一応見てみたもの
    - API利用に会員登録が必須
    - 環境問題かもしれないけど、自分の手元だとサンプルが動かないものが多かった
- メリット
    - オフラインマップに対応
- デメリット
    - 有料(になる可能性がある)
        - ある程度は無料で使えるが一定数以上のアクセスがある場合は従量課金
    - 情報が少ない
    - Android/iOS 間での差異が多いらしい(未確認)
        - iOS のみ未対応機能の存在など
  
# まとめ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188220/c5b4ad45-4192-1a05-db82-f13fee2122c6.png)

今回はオフライン表示が必要なため、自分は flutter_map を採用することになりました。
特に理由がない限りは、google_maps_flutter 使うのがいいのかな。と個人的には思います。
資料の多さはダントツですし、FLutter公式チームリリースの安心感もありますし。
`git ls-remote`でブランチの存在も確認したい

`git ls-remote`では、リモートブランチを取得するコマンドであり、
これを使うとそもそもリモートブランチが存在する事を確認できる。

> [3.5 Git のブランチ機能 - リモートブランチ](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81)
> [githubのURLが本当に存在するかシェルスクリプトから確認する](https://qiita.com/seigot/items/7eb7627b9ba835aedbb0)

```bash:例
$ REPOSITORY_URL="https://github.com/xxx/xxx"
$ git ls-remote ${REPOSITORY_URL}
XXXXXXXXXXXXXXXXXXXXXXXXX	HEAD
XXXXXXXXXXXXXXXXXXXXXXXXX	refs/heads/master
XXXXXXXXXXXXXXXXXXXXXXXXX	refs/tags/1.4e
YYYYYYYYYYYYYYYYYYYYYYYYY	refs/tags/v1.3
ZZZZZZZZZZZZZZZZZZZZZZZZZ	refs/tags/v1.3b
```

ブランチ一覧から、確認したいブランチが存在するかを完全一致で確認すればよい。

```bash:例
$ REPOSITORY_URL="https://github.com/xxx/xxx"
$ TARGET_BRANCH="v1.3"
$ git ls-remote ${REPOSITORY_URL} | cut -f 2 | cut -d/ -f 3 | grep --line-regexp "${TARGET_BRANCH}"
v1.3
$ echo $?
0
# `echo $?`の結果、TARGET_BRANCHが存在していれば0(正常終了)
# 存在していなければ1となる。
```


何か他にもっといい方法があれば教えてほしい、、です。

#参考
[3.5 Git のブランチ機能 - リモートブランチ](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E6%A9%9F%E8%83%BD-%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81)
[githubのURLが本当に存在するかシェルスクリプトから確認する](https://qiita.com/seigot/items/7eb7627b9ba835aedbb0)
[Linux：grepコマンドで完全一致する行を表示する方法](https://motamemo.com/linux/linux-tips/grep-match-whole-lines/)
[py2rb] assertAlmostEqual

# はじめに
移植やってます。
# assertAlmostEqual (Python)
https://docs.python.org/ja/3.7/library/unittest.html#unittest.TestCase.assertAlmostEqual

概要が完成しましたので、テストを開始しています。

assertAlmostEqual
> assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)
first と second が近似的に等しい (等しくない) ことをテストします。これは、places (デフォルト7) で指定した小数位で丸めた差分をゼロと比較することで行われます

~~えっ、等しい場合はどうするのだろう。~~

**[追記]**


|メソッド|確認事項|
|:--:|:--:|
|assertAlmostEqual(a, b)|round(a-b, 7) == 0|

# assert (Ruby)
```ruby
assert a.round(7) == b.round(7)

assert a != b && a.round(7) == b.round(7)
```
~~丸めた数値のみの比較ですと`assertions`
`a != b`をいれると`failures`になるけど、前者にしましょう。~~

**[追記]**
前者が正しいです。ニホンゴムズカシイネ。
むしろ、確認事項にそって書けば

```ruby
assert (a - b).round(7).zero?
```
# メモ
+ Python の assertAlmostEqual を学習した
+ 百里を行く者は九十里を半ばとす
Amazon Aurora for PostgreSQLでpg_hint_planを有効化する

# 環境
- Amazon Aurora for PostgreSQL 13.4

> 多分、AuroraではないRDSでも手順は同じだと思います。

# psqlでの操作
(1) pg_hint_planが有効化されているか確認します。

```bash
postgres=> select * from pg_extension;
  oid  |      extname       | extowner | extnamespace | extrelocatable | extversion | extconfig | extcondition 
-------+--------------------+----------+--------------+----------------+------------+-----------+--------------
 14346 | plpgsql            |       10 |           11 | f              | 1.0        |           | 
 78506 | pg_stat_statements |       10 |         2200 | t              | 1.8        |           | 
(2 rows)
```

pg_hint_planが有効化されていないことが分かります。

(2) pg_hint_planを有効化します。

```bash
postgres=> CREATE EXTENSION pg_hint_plan;
CREATE EXTENSION
```

(3) pg_hint_planが有効化されているか再確認します。

```bash
postgres=> select * from pg_extension;
  oid  |      extname       | extowner | extnamespace | extrelocatable | extversion |   extconfig   | extcondition 
-------+--------------------+----------+--------------+----------------+------------+---------------+--------------
 14346 | plpgsql            |       10 |           11 | f              | 1.0        |               | 
 78506 | pg_stat_statements |       10 |         2200 | t              | 1.8        |               | 
 86217 | pg_hint_plan       |       10 |        86216 | f              | 1.3.7      | {86220,86218} | {"",""}
(3 rows)
```

pg_hint_planが有効化されていることが分かります。

# パラメータグループの作成
(1) AWSマネジメントコンソールで[RDS]-[パラメータグループ]

(2) [パラメータグループの作成]をクリック
![スクリーンショット 2022-01-04 16.58.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/8681a462-e632-ef82-2260-ef79c949e1c2.png)

(3) [パラメータグループファミリー]で[aurora-postgresql13]を選択、[タイプ]で[DB Parameter Group]を選択、[グループ名]と[説明]は適当に入力して[作成]をクリック
![スクリーンショット 2022-01-04 16.37.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/c21e7084-642e-8645-3745-b3ca46c0f96e.png)

(4) パラメータグループの一覧から、先ほど作成したパラメータグループをクリック

(5) [パラメータの編集]をクリック

(6) 各パラメータを次のように設定→[変更の保存]をクリック

| 名前 | 値 |
|------|----|
| pg_hint_plan.debug_print | on |
| pg_hint_plan.enable_hint | 1 |
| pg_hint_plan.enable_hint_table | 1 |
| pg_hint_plan.message_level | debug5 |
| pg_hint_plan.parse_messages | debug5 |
| shared_preload_libraries | pg_stat_statements,pg_hint_plan |

> `pg_stat_statements,pg_hint_plan` の部分は、カンマの前後に空白をあけるとエラーになります。

(7) データベース一覧から対象のデータベースを選択→[変更]をクリック

> [リージョン別クラスター]ではなく[ライターインスタンス]・[リーダーインスタンス]を選択する

(8) [追加設定]-[DBパラメータグループ]に作成したパラメータグループを指定→[続行]をクリック
![スクリーンショット 2022-01-04 17.01.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/40aaeb77-c7f4-8ff4-d72e-d27babe4aac5.png)

(9) [変更のスケジューリング]で[すぐに適用]を選択→[DBインスタンスを変更]をクリック

(10) 選択したインスタンスのステータスが[変更中]になる→[利用可能]になったらOK

# パラメータグループの作成
前項の(1)〜(10)をもう一度行う。ただし、下記の点は変更する。

(2) [タイプ]で[DB Cluster Parameter Group]を選択する。[グループ名]・[説明]も適当に変更する。

(7) [リージョン別クラスター]を選択して[変更]

(8) 先ほど作成したクラスター用のパラメータグループを指定する。

# 参考にした記事
[PostgreSQLの拡張機能の有効化(オンプレ/AWS RDS](https://atsuizo.hatenadiary.jp/entry/2019/03/08/181902)
【備忘録】AWS Amplifyやってみた

#背景
仕事でAWSを触らなくなってしばらく経ったため、AWSでサーバーレスWebアプリ作成してみます。

#AWS Amplify(アンプリファイ)とは
拡張可能なフルスタックウェブおよびモバイルアプリケーションをより高速に構築します。開始も簡単、スケールも簡単。
(公式URL:https://aws.amazon.com/jp/amplify/)

とはいえよくわからん...

##結論
CodeCommitやGitHubにあるコードをデプロイまで実行して公開してくれる。
(circleUIみたいなもの？)

#やり方
下記サイト見たらできました。先達の方々ありがとうございます。

サーバーレスのウェブアプリケーションを構築１ AWS Amplify を使った静的ウェブホスティング
https://dev.classmethod.jp/articles/lim-serverless-app-1-amplify/

筆者が作ったサイト
https://master.d3001cga5i9ibc.amplifyapp.com/

#終わりに
GitHubじゃなくて、CodeCommitでもソース管理できるのか...
コマンドはこのまま同じにしてくれぇ
StoryBookでTailwindCSSを有効にする方法

# Story Book + Tailwind CSS

### 問題：普通にインストールしてもTailwindCSSが有効にならない

### 解決方法
#### ポストCSSのインストール
```shell:
yarn add -D @storybook/addon-postcss
```

#### 強制的なバージョン合わせ

```shell:
 npx sb init --builder webpack5 --force
```

#### ~こんなの方法もあるかも~
[~他のやり方~](https://storybook.js.org/addons/@storybook/addon-postcss)


#### 設定の追加-1

```js:.storybook/preview.js
import "../src/index.css"
export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}
```


#### 設定の追加-2

```js:.storybook/main.js
const path = require('path')
module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/preset-create-react-app",
    "storybook-zeplin",
    "storybook-addon-designs",
  ],
  "framework": "@storybook/react",
  "core": {
    "builder": "webpack5"
  },
  webpackFinal: async (config) => {
    config.module.rules.push({
      test: /\.css$/,
      use: [
        {
          loader: "postcss-loader",
          options: {
            // HERE: OPTIONS
            postcssOptions: {
              plugins: [require("tailwindcss"), require("autoprefixer")],
            },
          },
        },
      ],
      include: path.resolve(__dirname, "../"),
    });
    return config
  },
}
```
# おまけ Story Book + figmaとzeplin
#### figmaとzeplinのプラグイン追加
[Figmaプラグイン](https://help.figma.com/hc/en-us/articles/360045003494-Storybook-and-Figma)
[Zeplinプラグイン](https://storybook.js.org/addons/storybook-zeplin)

```shell:
yarn add -D storybook-addon-designs
yarn add -D storybook-zeplin
```

#### （例コンポーネントにfigmaとzeplinを追加

```js:.storybook/some.stories.jsx

import React from 'react';
import { Button } from './Button';

export default {
  title: 'Example/Button',
  component: Button,
  // More on argTypes: https://storybook.js.org/docs/react/api/argtypes
  argTypes: {
    backgroundColor: { control: 'color' },
  },
};

const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});

Primary.args = {
  label: 'This is a button',
};

Primary.parameters = {
  design: {
    type: 'figma',
    url: 'https://www.figma.com/file/1qYOl59kVzgYnXWJQ6O2vS/Untitled?node-id=102%3A4'
  },
  zeplinLink: "zpl://components?pid=61d363112967ca1219584135&coid=61d363128530641107dd2df9"
}

```

#### Zeplinのプレビュー@StoryBook
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/9cb13eb8-7ba5-f7aa-67a2-91b5df700753.png)

#### Figmaのプレビュー@StoryBook
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24726/f4baf658-9c35-0a57-5cf6-3f87a64a7329.png)

#### 参考
[Stackoverflow](https://stackoverflow.com/questions/65495912/storybook-tailwind-how-should-i-add-tailwind-to-storybook)
[Qiita](https://qiita.com/mizozobu/items/9e86b86df79f9988c7b3)
[Laravel]バリデーションexistsの挙動

## 前提

- Windows home 10
- Laravel 8.x
- PHP 8.1

## 背景

- Laravelでバリデーションを作っていた時の話。

- Validatorクラスを使って以下のように書いていた。

```php
$validator = Validator::make($request->all(), [
            'product_id' => ['required', 'exists:products,id', 'integer', 'digits_between:1,9'],
        ]);

        if ($validator->fails()) {
            return redirect()->route('...')
                ->withErrors(['error' => '不正な操作です。']);
        }
```

- バリデーションルールとして初めて`exists`を使用した
    - 指定したリクエスト値がDB内にあるか否かをチェックしてくれるので、結構便利

https://readouble.com/laravel/8.x/ja/validation.html#rule-exists

## 問題点

- ただ、上記の`exists`の使い方は問題があった。それは

**他のバリデーションルールを通す前にDBにアクセスしてしまっている点**

が問題だった

- これにより、**SQLインジェクションを引き起こしかねない**プログラムを書いたことになる

 

具体的にどんな問題があるかというと、

- まず前提として`exists`はDBにアクセスするため、**クエリを発行**する
- そして、上記のコードだとバリデーションルールが

`'required'` → `'exists:...'` → `'integer'` → `'digits_between:1,9'`

の順番に適用される

- 今回でいうと、`exists`でDBアクセスする際には`product_id`は`integer`であり、`'digits_between:1,9'`でなければいけない
- しかし、今のままでは**配列でも、文字列でもDBアクセスできてしまう状態になっている**のが一番の問題点

## 対策

- 正しくは以下のように`exists`をルールの最後に記述しなくてはいけなかった

```php
$validator = Validator::make($request->all(), [
            'product_id' => ['required', 'integer', 'digits_between:1,9''required', 'integer', 'digits_between:1,9', 'exists:products,id'],
        ]);
```

- これにより、リクエスト内にある`’product_id’`は

`'required'` → `'integer'` → `'digits_between:1,9'`

を通ったのちに`exists`でクエリを発行するので、セキュリティ上安全なクエリが発行され、問題なく`exists`が使えるようになります。

## 所見

- 「`exists`を使うとDBの値の有無チェックをする」＝「SQLを発行している」
ということに気づけば、当初の記述はしなかったですがバリデーションとクエリ発行のつながりは基本ないことが多いので、気づけませんでした。。。

- 自分がよく実感するのですが、フレームワークを使用しているとクエリへの意識の薄れは痛感しています。。。

- 今回の過ちにより、クエリへの意識が再認識できた点では非常にいい機会になりました！
オンプレミスIdPからのAWS環境へのアクセスについて

#はじめに
オンプレミスとの連携によるAWS環境へのアクセス認証について、改めて整理した。

#出てくるワードたち

- SAML(Security Asserrion Markup Language):
SSO(シングルサインオン)を実現する仕組みの1つ。OASISによって作成された異なるドメイン間でユーザ認証を行うための認証情報の規格
- SP(Service Provider): サービスの提供側、SAMLの認証情報を利用する
- IdP(Identify Provider): 認証情報を提供するシステムのこと(Active DirectoryやG Suiteなど)
- SAML Assertion: IdPとSPでやりとりするユーザの認証情報のこと
- SSO:１組のIDとパスワードで認証を行い、複数のサービスにログインできる仕組みのこと

#アクセス認証パターン1
〜AWSマネージメントコンソールへのアクセス
![snap_AWS_SSO.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234299/372d112e-bc51-24b5-ee9c-613e8937d61b.png)

①IdPで認証を行う
②ユーザを識別するSAMLアサーションを返す
③SAMLアサーションをSSOエンドポイントにPOSTする。
④AWS STSのAssumeRoleWithSAML APIを呼び出し、一時認証情報を取得する。一時認証情報を利用して、AWS マネジメントコンソールのサインイン URLを発行する。
⑤エンドポイントからAWS マネジメントコンソールのサインイン URLがブラウザに返される。
⑥一時認証情報でAWS マネジメントコンソールへアクセス

#アクセス認証パターン2
〜AWS APIエンドポイントへのアクセス
パターン1のようにブラウザからのアクセスではなく、アプリケーションがAWSのAPIへアクセスする場合の構成

![snap_AWS_SSO2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234299/25987bde-60d9-0bbd-637f-29e327555f07.png)

①IdPで認証を行う
②ユーザを識別するSAMLアサーションを返す
③SAMLアサーションをPOSTする。
④AWS STSのAssumeRoleWithSAML APIを呼び出し、一時認証情報を取得する。
⑤一時認証情報でAPIへアクセス

# SAMLとOpenIDの違い
なぜ、SSOにSAMIL認証を使うのか?
SSOにはSAMLの他にOpenIDがあり、両者を比較してみる。
(OpenIDの説明については、本資料では省略)

|  | SAML | OpenID |
|:-----------|------------:|------------:|
| 認証結果の伝送方法       | アサーション        | IDトークン         |
| データ形式     | XML      | JSON       |
| 事前登録や事前の情報交換の要否         | 必要(SPとIdPの間で事前に公開鍵を交換が必要)          | 不要           |
| ログイン情報を提供するサービスの選定       | ユーザーの同意なしで連携       |    連携する/しないはユーザ自身が判断    |
| 連携するかどうか    |   ユーザに同意確認しない   | ユーザ自身で選択可能      |
| 最適な用途    | Enterprise     | Consumer      |
#参考

[やさしい言葉で理解するSAML認証のまとめ](https://qiita.com/pasta_kun/items/4a57bd3b71ac8bf5d736)
[SAML認証を使用したシングルサインオンを設定する](https://jp.cybozu.help/general/ja/admin/list_saml/saml_settings.html)
[py2rb] 引数の省略

# はじめに
移植やってます。
# 引数の省略 (Python)
```python
def func1(str1, num1=(1, 2), num2=0):
    print(num1[1] + num2)

func1('test', num2=5)

# 7
```
別段変わった様子はなし。
# 引数の省略 (Ruby)
```ruby
def func1(str1, num1=[1, 2], num2=0)
  puts(num1[1] + num2)
end

func1('test', num2=5)

# 0
```
うぅ、これに手間取りました。

この時の`num1`と`num2`には、それぞれ`[1, 0]`と`0`が入っています。
よって`0`が返ってくるのは当然ですね。
しかし`5`はどこにいった？
# キーワード引数 (Ruby)
```ruby
def func1(str1, num1: [1, 2], num2: 0)
  print(num1[1] + num2)
end

func1('test', num2: 5)
```
キーワード引数は~~`Ruby 2.7`~~`Ruby 2.0`辺りから入ったらしいです。
皆さんも利用しましょう。

https://qiita.com/fursich/items/20b35d564e62fa0530b5
# メモ
+ Python の 引数の省略 を学習した
+ 道のりは遠そう
【Rails】rails sができなくなった時の対処

##背景
``rails s``実行中にエラーが起き、``control＋C``で終了出来なかったため、``control＋Z``で強制終了し、再度起動すると

```ターミナル.
=> Booting Puma
=> Rails 5.2.3 application starting in development 
=> Run `rails server -h` for more startup options
A server is already running. Check /Users/ユーザー名/projects/test/tmp/pids/server.pid
Exiting
```

と上記のようなものが出た。
``/Users/ユーザー名/projects/test/tmp/pids/server.pid``はサーバー起動する際に使用しているID。本来であればサーバーを終了したら、このIDも削除されるはずだが、今回のような強制終了により、IDが残ってしまうことがある。

##解決策
本来は自動で削除されるであろうこのIDを手動で消してあげれば、解決する。

**手順**
①server.pidの削除
②処理の終了

###①server.pidの削除

```ターミナル.
rm -f Users/ユーザー名/projects/test/tmp/pids/server.pid
```

###②処理の終了
まずは処理の一覧を表示させる。

```
lsof -i:3000
```
上記のコマンド実行結果

```
COMMAND     PID      USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
Google    45385 ユーザー名   43u  IPv6 0x839bb4867fea3c69      0t0  TCP localhost:64733->localhost:hbci (ESTABLISHED)
Google    45385 ユーザー名   47u  IPv6 0x839bb48685588da9      0t0  TCP localhost:64734->localhost:hbci (ESTABLISHED)
ruby      67430 ユーザー名   21u  IPv4 0x839bb4869b17f329      0t0  TCP localhost:hbci (LISTEN)
ruby      67430 ユーザー名   22u  IPv6 0x839bb4868abc95e9      0t0  TCP localhost:hbci (LISTEN)
ruby      67430 ユーザー名   40u  IPv6 0x839bb4867fea5ee9      0t0  TCP localhost:hbci->localhost:64437 (CLOSE_WAIT)
ruby      67430 ユーザー名   44u  IPv6 0x839bb4868abc9029      0t0  TCP localhost:hbci->localhost:64196 (CLOSE_WAIT)
ruby      67430 ユーザー名   45u  IPv6 0x839bb4867fea7029      0t0  TCP localhost:hbci->localhost:64733 (ESTABLISHED)
ruby      67430 ユーザー名   46u  IPv6 0x839bb4868558aa69      0t0  TCP localhost:hbci->localhost:64734 (ESTABLISHED)
```

「COMMAND」に「ruby」と記載のある行のPIDをコピーして(この場合だと67430)を削除すると処理の終了ができる。

```
kill -9 消したい番号

上記の例だと
kill -9 67430
となる
```

##参考記事
[rails sをしたらtmp/pids/server.pidというエラーが出る件について](https://qiita.com/sakuraniumarete/items/ac07d9d56c876601748c)
AWS MFAを使用した多要素認証（２段階認証）の設定手順

## 内容

MFAを使用した多要素認証（２段階認証）の設定手順。
[IAMユーザーの作成方法](https://qiita.com/tarian/items/324e986db159f34d7ead)

## 手順

- IAMの管理画面 ⇒ 左ペイン『ユーザー』 ⇒ MFAを割り当てるユーザーをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/d67f5692-668c-99a3-242a-040da1d790fb.png)

- 『認証情報』タブ ⇒ 『MFAデバイスの割り当て：管理』
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/3c27fde1-51ba-6a92-a4fa-4af90a416d8d.png)

- 『仮想MFAデバイス』 ⇒ 続行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/c84bd961-f9a0-755b-027d-4f3fd0a852b4.png)

- QRコードを読み取り、出てくるMFAコードを２つ入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692472/4b18834f-2c64-7c13-9799-0f428ef379cb.png)

これで次回のログインから２段階認証が求められる。