OmniAICreator/Qiita-1.07M huggingface dataset:
Angular/@Input()と@Output()について

# @Input()と@Output()について
ようやくやんわりAngularに慣れてきたような気がしている。
雰囲気で理解してる箇所も少なくはないが、ルールや定石がしっかりしている印象なので、要所要所を押さえていけば案外理解しやすいのかもしれない。
@Inputと@Outputが割とややこしかったので記しておく。
コンポーネント内に存在する別コンポーネント、いわゆる親コンポーネントと子コンポーネント間で任意の値やイベントの発火などをさせるために定義するものである。

@Input
    親コンポーネントから子コンポーネントへ
    string,number等の型や、interface、あるいは配列などで子コンポーネントに渡すことができる。

    @Input() condition: string;
    @Input() project: Project;
    @Input() types: Type[];

@Output
    子コンポーネントから親コンポーネントへ
    EventEmitterという型を使う。emit() メソッドと subscribe() メソッドを使用してコンポーネント間でデータを共有するのに役立つモジュールとのこと。
    <>の中には親に渡す値の型を引数に設定できる。string,number等の型や、interface、あるいは配列などでもいける。

    @Output() click = new EventEmitter();
    @Output() condition = new EventEmitter<Condition>();


親コンポーネント内に「hoge-child」という別コンポーネントが存在している。親子関係である。
[]内のものは子コンポーネント側に渡すもの、すなわち@Inputで設定されているものであり、()内のものは子コンポーネントから親コンポーネントに渡されてきたもの、すなわち@Outputで設定されたものである。
[fromParent]、[fromParent__2]にはともに文字列を渡している。
hoge-child.component.ts側で型をstringに設定しているためである。
(fromChild)と(fromChild__2)はhoge-childからイベントが渡されてきたら関数を実行するようになっている。
hogeってみんな使うけど何なんだろう。


```hoge-parent.comonent.html
    <div>
        <hoge-child
            [fromParent]="'Mohamed Avdur'!" //親コンポーネントから子コンポーネントへ
            [fromParent__2]="'stand'" //親コンポーネントから子コンポーネントへ
            (fromChild)="avdurNotDead()" //子コンポーネントから親コンポーネントへ
            (fromChild__2)="magiciansRed($event)" //子コンポーネントから親コンポーネントへ
        >
        </hoge-child>
        {{ result }}
    </div>
```


```hoge-parent.comonent.ts
    result: string;

    avdurNotDead() {
        return (this.result = 'Yes I am!');
    }

    magiciansRed(event: string) {
        return (this.result = event);
    }
```

子コンポーネントでは上記のごとく@Inputにはそれぞれstringを設定し、@OutputのfromChildには引数なしのEventEmitter、fromChild__2にはstringを引数にしたEventEmitterを設定している。

```hoge-child.component.ts
    @Component({
        selector: 'hoge-child',
        templateUrl: './hoge-child.component.html',
        styleUrls: ['./hoge-child.component.scss'],
    })

    @Input()
    fromParent: string; //親コンポーネントから子コンポーネントへ
    @Input()
    fromParent__2: string; //親コンポーネントから子コンポーネントへ
    @Output()
    fromChild = new EventEmitter(); //子コンポーネントから親コンポーネントへ
    @Output()
    fromChild__2 = new EventEmitter<string>(); //子コンポーネントから親コンポーネントへ
```

子コンポーネント内では、@Inputの値の文字列のボタンが表示され、クリックすると@Outputにemit()する。
fromChild__2はEventEmitterの引数がstringなので、emit()の引数に文字列を入れてある。
ボタンをクリックすると、それぞれ親コンポーネント内で設定された関数が実行される。
引数を設定してあるfromChild__2にemit()した文字列は親コンポーネント内に$eventとして渡され、関数の引数等に使用できる。

```hoge-child.component.html
    <div>
        <button (click)="fromChild.emit()">{{ fromParent }}</button>
        <button (click)="fromChild__2.emit('Cross Fire Hurricane!')">{{ fromParent__2 }}</button>
    </div>
```

![スクリーンショット 2022-03-14 20.46.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/823323/3eb1f04d-0fba-ef94-cbc4-fd10831a8d57.png)
![スクリーンショット 2022-03-14 20.47.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/823323/ad2512c7-c40b-0318-414c-fdaa7a9163cd.png)



チュートリアルで学ぶような内容かもしれないし実際チュートリアルみたいなもので学んだ気もするが、理解するのに時間がかかってしまった。
理解してしまえばとてもシンプルなので、隙あらばInputしたりOutputしていきたいと思う。
Sourcetreeのパスワード初期化(mac)

以下の対応で必要になったのでまとめ

https://qiita.com/xy2/items/d28371dd94ea9b0336fc

# 解消方法
Keychainにパスワードが保存されているらしい

**「その他」 > 「キーチェーンアクセス」** で `キーチェーンアクセス.app`を実行

**sourcetree** を検索 → 検索対象を削除

※なぜか自分の環境だと **macのメニューバー 「編集」 > 「削除」** でしか削除できませんでした…
[Wordpress] 固定ページを作成せずに静的ページを設置する

# 静的ページの多い Wordpressサイト

先日、下記のような環境での作業を依頼されました。

クライアントから提供された環境は AWS EC2 で Wordpress がインストールされており、FTP で入れるのは `wp-content` フォルダ以下のみというものです。

この案件では静的ページが多数ありました。
例えば「物語」という静的ページを作るなら、**普通は固定ページに「物語」を作り、スラッグに `story` と設定します。**

## いちいち固定ページを作りたくない

しかしローカル、ステージング、プロダクションと３箇所に固定ページを作るのが面倒になりました。

そうだ！パスで判断して `get_template_part()` で表示すればいいんじゃね？

```php:index.php
global $wp_query;

if (is_page('story')){
  // 固定ページ「story」
  get_template_part('story/index');

} else if ($wp_query->query['pagename'] === 'onair'){
  // 静的ページ「onair」
  header(' ', true, 200);
  get_template_part('onair/index');

// 〜略〜

} else if (is_singular()) {
  // ブログ記事
  get_template_part('template/news/single');

} else{
  // それ以外
  get_template_part('template/news/archive');
}
```

## 解説

このサイトはアニメ作品のサイトなので「物語」「放送情報」「最新情報」などがあります。

そして筆者はテンプレート階層ファイル（`page-xxxx.php` や `archive-xxx.php` など）でゴチャゴチャするのが嫌いなので `index.php` でルーティングをしたいタイプです。

### 固定ページを使うパターン

各話あらすじは `story` という固定ページを作って、宣伝担当さんが更新できるようにしました。

```php:index.php
if (is_page('story')){
  // 固定ページ「story」
  header(' ', true, 200);
  get_template_part('story/index');
```

### 普通の記事（ニュース）のパターン

途中を飛ばして先に普通の記事について。
`archive.php` とか `single.php` をテーマのルートに置きたくないのでここでルーティングしています。

```php:index.php
} else if (is_singular()) {
  // ブログ記事
  get_template_part('template/news/single');

} else{
  // それ以外
  get_template_part('template/news/archive');
}
```

### 静的ファイルを使うパターン

この記事の本題、静的ファイルパターンです。

放送情報 `onair` は更新頻度が少ないので静的ページです。
固定ページは作成していません。

```php:index.php
} else if ($wp_query->query['pagename'] === 'onair'){
  // 静的ページ「onair」
  header(' ', true, 200);
  get_template_part('onair/index');
```

テーマフォルダに `onair/index.php` を作って更新します。

`https://****.***/onair` にアクセスすると `$wp_query->query['pagename']` には `onair` が入りますので、それを利用して分岐しています。

しかしコンテンツは表示されますが、固定ページを作っていないので `404 Not Found` が返されてしまいます。
対策として `header(' ', true, 200);` で正常値を返します。

### 分岐のパターン

下層フォルダへの対応も簡単です。
`https://****.***/special/comment` というURLなら下記のように書きます。

```php:index.php
} else if ($wp_query->query['pagename'] === 'special/comment'){
  header(' ', true, 200);
  get_template_part('special/comment/index');
```

おまけでカスタム投稿タイプ `goods` と、カスタムタクソノミー `type` に対応するパターンです。

```php:index.php
} else if (is_post_type_archive('goods') || is_tax('type')) {
  // カスタム投稿タイプ「goods」のアーカイブ
  get_template_part('template/goods/archive');

} else if (is_singular('goods')) {
  // カスタム投稿タイプ「goods」のシングル
  get_template_part('template/goods/single');
```

# おわり

「静的ページをたくさん作るけどルーティングのためだけに固定ページを作りたくねえ！」
という方はお役立てください。
Bitbucket Cloud recently stopped supporting account passwords for Git authentication を解消したはなし

Bitbucketからpullしようとした際に、エラーが発生したので解消方法のまとめ

# エラー内容
```
fatal: Authentication failed for 'https://bitbucket.org/xxx/xxx.git/'
remote: Bitbucket Cloud recently stopped supporting account passwords for Git authentication.
remote: See our community post for more details: https://atlassian.community/t5/x/x/ba-p/1948231
remote: App passwords are recommended for most use cases and can be created in your Personal settings:
remote: https://bitbucket.org/account/settings/app-passwords/
```

エラー内容通りに、
https://atlassian.community/t5/x/x/ba-p/1948231 にアクセスしてみる

# https://atlassian.community/t5/x/x/ba-p/1948231
要約すると、
セキュリティの関係で2022年3月1日以降はアカウントパスワードが使用できなくなっているらしい

# 対応
**左下のアイコン > SETTING Personal settings > アプリパスワード**
`アプリパスワードの作成`ボタンをクリック
![スクリーンショット 2022-03-14 20.21.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/209017/97fe8234-e4bb-09cd-2bba-8a0f5247266a.png)

**Label・権限**を設定して`作成`ボタンをクリック

Gitのパスワードをもとめられた場合には表示されたパスワードを入力
JavaScriptの配列

# 配列とは
***配列とは情報をしまっておくためのタンスのようなイメージ***です。

# 配列を作る方法
配列を作る方法は下のやり方です。

```js
const array = new.Array();
const array = [];
```
⚫︎補足
arrayは配列です。

# 配列の書き方
配列の書き方をみていきます。

```js
const scores = [100, 90, 70]; //数字を入れる
const sportts = ['野球', 'テニス', '柔道'];　//文字を入れる
const my_weapon = ['Lightsaber', 2, 'Raygun', 3];　//文字と数字を組み合わせる
```
あとはconsole.logで出力できます。

次にデータを取る方法です。

```js
const scores = [100, 90, 70];
console.log(scores[0]);

//100と出力
```

0が１番目から始まるルールがあります。

次にデータを取る方法です。

```js
const scores = [100, 90, 70];
scores.push(60); //pushがデータの追加
console.log(scores);
//[100, 90, 70,60];が出力
```

次にデータの更新方法です。

```js
const scores = [100, 90, 70];
scores[2] = 80;　//更新方法
console.log(scores);

// [100, 90, 80]で出力
```
こんな感じでできます。

次にデータの削除方法です。削除メソッドはないみたいです。
代わりに***splice***を使うみたいです。
***配列の要素を操作するメソッドで削除みたいな形式ができる***みたいです。

下の資料に詳細があります。
https://techacademy.jp/magazine/37922#sec1

```js
const scores = [100, 90, 70];
scores.splice(2);
console.log(scores);
//100,90が出力
```
色々組み合わせてできるみたいです。


# スプレッド演算子
これは```...〜```みたいな形で配列の文字列展開できるみたいです。


⚫︎最大値　最小値
これもスプレッド演算子で出せます。maxとminは最大値と最小値です。

```js
const scores = [100, 70, 90];
console.log(Math.max(...scores));
//100  最大値

const scores = [100, 70, 90];
console.log(Math.min(...scores));
//　70 最小値
```


⚫︎配列の結合
スプレッド演算子で配列を結合できます。

```js
const scoreA = [10, 30, 40];
const scoreB = [100, 400, 500];

const numberC = [...scoreA, ...scoreB]; //スプレッド演算子
console.log(numberC);

//[10, 30, 40, 100, 400, 500]で出力
```
const numberC = [...scoreA, ...scoreB];に注目してもらえればわかるのですが
この形で結合することができます。

⚫︎オブジェクトのやり方
オブジェクトの使い方は下の資料に記載があります。今回は配列の記事なのでオブジェクトは割愛します。

https://qiita.com/akisx/items/682a4283c13fe336c547


# いろいろな配列のメソッド
配列はいろいろなメソッドがありカンファレンスやドキュメントを確認して調べながらできます。
やりたいことを言葉にできれば調べることができたりします。

⚫︎配列の中身の確認
```includes```




⚫︎配列公式ドキュメント
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array













⚫︎参考資料
https://qiita.com/takeshisakuma/items/b23b1a748098f30e2ff2
https://blog.codecamp.jp/javascript-array-use
https://qiita.com/akisx/items/682a4283c13fe336c547
【Laravel】リレーション先のテーブルでソートする

この記事は移行しました！[最新の内容はこちら](https://naoqoo2.github.io/blog/Laravel-%E3%83%AA%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%85%88%E3%81%AE%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%A7%E3%82%BD%E3%83%BC%E3%83%88%E3%81%99%E3%82%8B/)をご覧ください😀


## リレーション先のレコード数でソートしたい

`withCount('リレーション名')`で取得して`リレーション名_count`を指定する。

```php:例）コメントの多い順
Post：：withCount('comments')
->orderBy('comments_count', 'desc')
```

## リレーション先のカラムでソートしたい

`withCount()` のような良い感じの関数がなく、joinしてあげる必要あり。

```php:例）古参ユーザーが投稿した順
Post::select(['posts.*', 'users.created_at'])
->join('users', 'users.id', '=', 'posts.user_id')
->orderBy('users.created_at')
```

※selectは必要なければ指定不要

テーブル名はモデル内に隠蔽しておきたい場合は `Post::make()->getTable()` で取得できる。[※参考](https://qiita.com/youstr/items/7849e9335f9cc9b213ed)

```php:例）古参ユーザーが投稿した順（テーブル名ベタ書きは嫌）
Post::join(
    User::make()->getTable(),
    User::make()->getTable().'.id', '=', Post::make()->getTable().'.user_id'
)
->orderBy(User::make()->getTable().'.created_at')
```

うーん、、
`withColumn('user', 'created_at')` のような関数あればいいのにな。

## 中間テーブルのカラムでソートしたい

`withPivot` を使う。


```php: とある投稿のいいねしたユーザー一覧（いいねした順）
class Post extends Model
{
    public function likeUsers()
    {
        // エイリアス指定しないとpivot_created_atになるので、わかりやすい名前をつけるのおすすめ
        return $this->belongsToMany('User', 'post_user_like')->withPivot('created_at as like_at');
    }
}

$post->likeUsers()->orderBy('like_at');
```
Woocommerceの個別プロダクトページで商品画像が表示されない時の応急対処法

ワードプレスでオリジナルテーマのECサイトを作る際にwoocommerceプラグインを適用したのですが、商品の個別ページで商品画像が表示されない不具合を発見しました。

日本語での解決法が見つからなかったため、英語でググったところ応急的な対処法がありましたので取り急ぎ共有いたします。

以下のコードをcssファイルに追加してください。

```
.woocommerce div.product div.images.woocommerce-product-gallery {
    opacity: 1!important; 
}
```


もし、この方法でも表示されない方がいましたらお知らせください。
なお、Woocommerce対応テーマである「Storefront」では上記コードがなくても問題なく表示されます。
Emacsのorg-mode

# 見た目の設定
Emacsを新しく入れたら，挙動が新しくなったのか.orgファイルをEmacsで開くと文章が展開された状態になっていた．
前までは全ては展開されず，見出しだけ展開されていたような気がする．

設定の仕方をググると下記サイトにデフォルトの展開設定だけではなく，
見出しのインデント方法の設定も書いてあったのでそのまま使う．

https://www.5ing-myway.com/org-mode-setting1/


`init.el`に書く

``` lisp
;;; org-mode
(setq org-startup-indented t)    ;; 見出しをインデント
(setq org-indent-mode-turns-on-hiding-stars nil)  ;; 見出しをインデントした時にアスタリスクが減るのを防ぐ
(setq org-indent-indentation-per-level 4)  ;; インデントの幅を設定
(setq org-startup-folded 'content)  ;; 見出しの初期状態（見出しだけ表示）
```

自動でインデントしてくれるのはめちゃくちゃ便利．


2022/03/25 追記
speed-commands を有効にした
``` lisp
(setq org-use-speed-commands t)
```
Kotlin KoansでKotlin入門　第９回：Data classes

# はじめに
公式の問題集[「Kotlin Koans」](https://play.kotlinlang.org/koans/overview)を解きながらKotlinを学習します。

過去記事はこちら
- Introduction
  - [第０回：Kotlin Koansについて](https://qiita.com/kosuke1/items/41d192af63485bfc8cb8)
  - [第１回：Simple Functions](https://qiita.com/kosuke1/items/5862a3ece96082a62e67)
  - [第２回：Named arguments](https://qiita.com/kosuke1/items/2af11262852ee41b5da7)
  - [第３回：Default arguments](https://qiita.com/kosuke1/items/16cb8ac780df58dc8054)
  - [第４回：Triple-quoted strings](https://qiita.com/kosuke1/items/52cfeed2c49b0252d40e)
  - [第５回：String templates](https://qiita.com/kosuke1/items/0221bbbc5bc70847be6f)
  - [第６回：Nullable types](https://qiita.com/kosuke1/items/aa96e422c5313b6961bc)
  - [第７回：Nothing type](https://qiita.com/kosuke1/items/1ca0e48820d58c9dfe16)
  - [第８回：Lambdas](https://qiita.com/kosuke1/items/8de74f9491e003127f53)

# 問題
[Data classes](https://play.kotlinlang.org/koans/Classes/Data%20classes/Task.kt)
[クラス](https://kotlinlang.org/docs/classes.html?_ga=2.137863797.47448449.1647255356-1976109019.1644486873)、[プロパティ](https://kotlinlang.org/docs/properties.html)、[データクラス](https://kotlinlang.org/docs/data-classes.html)について学んだ後、以下のJavaコードをKotlinに書き換えてください。
```Java
public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}
```
その後、出来上がったクラスに```data``` modifierを追加してください。
コンパイラはこのクラスに対して、いくつかの有用なメソッドを生成します: ```equals```/```hashCode```, ```toString```


修正前のコード
```Kotlin
class Person

fun getPeople(): List<Person> {
    return listOf(Person("Alice", 29), Person("Bob", 31))
}

fun comparePeople(): Boolean {
    val p1 = Person("Alice", 29)
    val p2 = Person("Alice", 29)
    return p1 == p2  // should be true
}
```


# 問題のポイント
データを保持することを主目的としたクラスを作成する場合、Kotlinでは、これらをデータクラスを使用します。
データクラスでは、いくつかの標準的な機能やユーティリティ関数が、データから機械的に導出されるます。


# 解答例
データクラスを定義するには```data class```とし、クラス名の後にコンストラクタを定義します。
```Kotlin
data class Person(val name: String, val age: Int)

fun getPeople(): List<Person> {
    return listOf(Person("Alice", 29), Person("Bob", 31))
}

fun comparePeople(): Boolean {
    val p1 = Person("Alice", 29)
    val p2 = Person("Alice", 29)
    return p1 == p2  // should be true
}
```
輪読会メモ：リーダブルコード（第4~6章）

前回記事：[輪読会メモ：リーダブルコード（第1~3章）](https://qiita.com/takumi_links/items/34e98d7dbbe0532a69d1)の続きになります。
今回は第4章～第6章まで。

## 第4章：美しさ
> **4.1 なぜ美しさが大切なのか？**
　**見た目が美しいコードのほうが使いやすいのは明らかだ。考えてみれば、プログラミングの時間のほとんどはコードを読む時間なのだッ！**
（「リーダブルコード」p.43~44より）
  - 今のプロジェクトではフォーマッタ等が導入できておらず一目でみても分からないコードが散見している・・・
    - **インデント**（スペース or タブ、何文字分開けるか等）に対して無頓着なメンバーもいるが、ここは早急に考えを改めてもらい、改善していかないといけない。（負の遺産が増え続ける）

> **4.2 一貫性のある簡潔な改行位置**  
（「リーダブルコード」p.44より）
  - 改行するときは、`(`を書いてから改行する、改行したらスペース4個あける 等の統一したルールは必要そう
  - PHPでもJavaでも（ほかの言語でも）一般的にフォーマッタは出回っているので、プロジェクトでフォーマットについて明確に決めないと、**個々人での好みが反映されたコードが乱立してしまう**。。

> **4.6 宣言をブロックにまとめる**  
  **4.7 コードを「段落」に分割する**  
（「リーダブルコード」p.50~52より）
- 処理を **「ブロック」単位** , **「段落単位」** に分けて記述するのはとても分かりやすいと感じる。すぐにでも実践したい内容
- 適切に**空行**を使い、処理ブロックごとに論理的な段落分けをするのはとても処理が追いやすいので、今後のレビュー観点にも取り入れたい

## 第5章：コメントすべきことを知る
> **コメントの目的は、書き手の意図を読み手に知らせることである。**  
  **5.1 コメントするべきでは「ない」こと**  
  **コードからすぐにわかることをコメントに書かない。**  
（「リーダブルコード」p.56~60より）
  - コメントするべきではないことを考えてみた
    - `//コンストラクタ` のような、言語仕様がわかっていれば何をやっているかわかる部分
    - `//インスタンス化`：仕様等ではない、開発する上で最低限必要な前提知識は無駄に書かない
- コメントするべき内容
  - 文字列で特定のフォーマットの入力を期待しているもの
  - 日付のデリミタや時分秒まで含むかどうか、変数からは読み取れない
  - 正規表現はコメントあった方が良さそう（どんな形式を想定しているか）

```php
/**
 * 日付からフォーマットした日付を返す
 * @param string $date 例：2021-10-10
 * @return string $formatted_date 例：2021年10月10日（月）
 */
function formatDate(string $date){}
```

> **ひどい名前はコメントをつけずに名前を変える**  
（「リーダブルコード」p.59より）
- 既存コードを読む中で、実処理の内容と全くかけ離れた関数名をつけている箇所等あるが、名前づけは大事。名前をつけるときはしっかり意図を持ってつける。

> **定数にコメントをつける**  
（「リーダブルコード」p.62より）
- 定数を定義するときは、何らかの意図がある（コード値だったり、色々なところで参照される値だと推測できる）ケースが多いので、なるべくコメントをつけて補足する。

> **5.3 読み手の立場になって考える**  
  **質問されそうなことを想像する**  
  **「全体像」のコメント・要約コメント**  
（「リーダブルコード」p.63~68より）
- 処理の初めにコメントで「全体像」を書いてあると、どんな処理かをあらかじめ想定できるので読みやすい
```php
function updateStatus(int $customerId, int $status) {
    // パラメータで渡されたstatusで該当顧客情報を更新する
    ・・・
    // IDの有効値チェック
    ・・・
    // 顧客情報存在チェック
    ・・・
    // ステータス有効チェック
    ・・・
    // 顧客情報更新
    ・・・
}
```

## 第6章：コメントは正確で簡潔に
> **6.1 コメントを簡潔にしておく**  
  **6.4 関数の動作を正確に記述する**  
（「リーダブルコード」p.72~74より）
- コメントを書いたものの、実コードとコメントの内容が乖離していては余計にわかりずらくなってしまう
- **正しいコメント**（該当処理を正確に説明したコメント）を、簡潔に書くことを意識する

## 第4~6章 まとめ
4~6章は「**読みやすい・分かりやすい**」コードを書くことを意識しよう、というメッセージが多く込められているように感じました。

自分だけ理解できるだけではもちろんダメで、**他人が読んでも分かりやすいコードを書くために、コメントを書いたり・インデントに気を付けよう！** というのを自戒しました。

正直、今の会社ではエンジニア全員が「**読みやすい・分かりやすいコードを書く**」ことを意識できておらず、かなり「オレオレ」なコードやインデントもめちゃくちゃなコードが散見されます・・・。

輪読会を通して、少しでもチームメンバーの考えが変わり、プログラムの品質がより良いものになることを本当に期待しています・・・（啓蒙活動頑張ろう・・・）

次の記事では、第7~10章のメモを書いていこうと思います。
【Automation Anywhere】ファイルを移動する　- はじめてのAA

# 今日はこれを覚えよう！

ここではAutomation360でファイルを移動する流れを押さえましょう。
現時点では「ファイルを移動する」アクションは提供されていないため、「ファイル:コピー」と「ファイル:削除」のアクションを組み合わせて実現します。

# 作り方

[Botの作成画面を起動](https://qiita.com/IQ_Bocchi/items/27a23969bcb4917824ec)し、以下の手順でBotを作成します。

---
「アクションを検索」の入力欄をクリックし、「ファイル」と入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/8e89815a-e727-55d2-d632-c2ddad6ffca4.png)

---
絞り込まれたアクションの中から、「ファイル」パッケージの「コピー」アクションを開始と終了の間にドラッグします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/969a576b-2768-abb1-6676-6991fd8fa7df.png)

続けて、「ファイル」パッケージの「削除」アクションを先ほど配置した「コピー」アクションの後ろにドラッグします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/99615f33-3ce4-b7e6-a7bd-bc67da2c3de2.png)

### ファイルのコピー
対象ファイルを移動先のフォルダーにコピーする設定をします。

「ファイル:コピー」アクションを選択し、画面右側の「元のファイル」欄にコピーするファイルを絶対パスで入力します。
また、「送り先ファイル/フォルダー」欄に移動先のフォルダ名を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/8c23a7b9-66aa-80da-229b-af84bdac2d83.png)

### 元ファイルの削除
次に、コピー元ファイルを削除する設定をします。

「ファイル:削除」アクションを選択し、画面右側の「ファイル」欄に削除するコピー元のファイルを絶対パスで入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/11324199-b3b5-d5ab-5f20-e57acba475d6.png)

---
「保存」をし、「実行」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/2223d3b5-b7c7-5b2d-56e4-cad03727aa7f.png)

---
Botの正常終了を知らせる「キラキラ」が表示されるので、「閉じる」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/25d676e5-eff2-71b8-53c8-fe83c00b20a0.png)

---
すると、コピー元のファイルがなくなり、指定した移動先のフォルダー配下に移動対象のファイルがコピーされています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/fcbb4f8e-38eb-4258-68bd-3bd407a33620.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517299/4140d9e9-f8e8-fa31-a054-203ce279a1f4.png)

# この演習で学んだこと
この演習では、Botでファイルを移動する方法を学びました。

ポイントとしては、下記になります。

- ファイルの移動は「ファイルのコピー」⇒「ファイルの削除」を組み合わせて行う（「ファイルの移動」自体のアクションは現時点では存在しない）
- ファイルおよびフォルダーの指定は絶対パスで指定
- コピー元のファイル名指定ではワイルドカードの使用も可能
- ファイル作成/更新日付やファイルサイズを条件にコピー／削除対象の選定も可能
　※ 前回の「ファイルのコピー」の記事もぜひご参照ください
　   https://qiita.com/tanakan1101/items/54a20324ad77e1731cb9

「ファイルのコピー」や「ファイルの削除」の際には、上記の通り「ファイル：コピー/削除」のアクションでファイル日付やファイルサイズを条件に対象を絞ることも可能ですし、今回は詳細には触れませんが「ループ」アクションや「If」アクションを組み合わせて、フォルダ内のファイルを一つづつチェックしながら、ファイル名に含まれる文字列やファイル日付などの条件に該当するファイルを個々に移動する方法もあります。

非常にシンプルなアクションですが、古くなったファイルの整理やログファイル退避など、実践的な処理を行うさまざまなケースで活用する機会があるかと思います。どんどん活用してみましょう！

# もっと知りたい！　学びたい！

この記事を読んで、「Automation 360 の使い方をもっと知りたい！」と思った方は、以下のシリーズをチェックしてみてください。

Automation360の基礎知識や使い方を、わかりやすくまとめたシリーズで、この記事もシリーズの１トピックとなっています。

https://qiita.com/IQ_Bocchi/items/8d28f12256037b5f9058

Automation Anywhere を使い始めたばかりの方はもちろん、これから使ってみようと思っている方や、ずっと使っているけど改めて基本を学びたい方などは、ぜひチェックしてみてください！
Ruby Goldに合格したので、そのおぼえ書き

Ruby技術者認定試験の Ruby Association Certified Ruby Programmer Gold version 2.1
(通称 Ruby Gold)

https://www.ruby.or.jp/ja/certification/examination/

に合格しましたのでそのメモです。
受験時期は2022/1です。


## 感想
- 学び直しの良い機会となった
- メタプログラミングという魔術に出会えた
- 周りの強いエンジニアに一歩近づけた
- 試験は96/100で意外と点数取れた

## 勉強方法
以下の方法で勉強しました。
1. 合格教本の問題を解く
1. CTCテクノロジーの問題を解く
1. 体験記系の記事を読む

要点としては、**体験記系の記事を読む**作業です。
確認すると実感できると思いますが、重箱の隅をつつくのような問題も出題されていることがわかります。
体験記系の記事を通して微妙に理解していなかった内容を確認する時間にすると良いと思います。

以下、私が参考にした記事です。
ググるとたくさんヒットしますがこの3つで十分網羅できると思います。感謝です。
- [武田哲也さんのRuby技術者認定試験受験記](https://togetter.com/li/769555)
- [1ヶ月後「Ruby Association Certified Ruby Programmer Gold version 2.1」に合格する方法](https://qiita.com/sogu/items/5ff2bf8702e14daf1804)
- [Ruby技術者認定試験-Goldを受験したお話](https://media.growth-and.com/ruby%E6%8A%80%E8%A1%93%E8%80%85%E8%AA%8D%E5%AE%9A%E8%A9%A6%E9%A8%93-gold/)

## メタプログラミングを読むべきか
合格のために必須ではないけど助けにはなる、という感想です。
合格という成果のみ欲しい人は読まなくても合格は可能だと思います。
私の場合は興味がある内容だった&いづれ読みたいと思っていたので、この機会に読みました。



## 勉強時間の目安
計測していないですが、おそらく20~25hくらい？だと思います。
Ruby Silverから連続で受験するともっと減らせると思います。

---
おぼえ書きは以上になります。
資格はDisられがちですが状況によってはアリだと思っています。
自信がつくし体系的に学び直す機会が得られるなどのメリットもあるので、使い方次第ですね。

以上ですー！
【Next.js】管理画面を作りながらNext.jsを学ぶ(レンダリング)

# まえがき

[前記事](https://qiita.com/crml1206/items/27102fed3228f0ffc325)でNext.jsの基本的な使い方を学んだ。
本記事では、Next.jsでCSR/SSR/SSGを使い分けるために必要な知識をまとめる。

Next.jsでは３つのレンダリング方法(CSR/SSR/SSG)が提供されている。※厳密にはISRもある
公式はパフォーマンス的に**SSGを推奨している**。

CSR/SSR/SSGの良いところ/悪いところは、下記の記事で自分でOUTPUTしてみた。

https://qiita.com/crml1206/items/24bf29bc36566f4cc68d

# CSR
・useEffect関数 ... クライアント側で、マウント時に実行されるもの
・useEffect関数は、Server-sideでは実行されない。

https://codewithhugo.com/react-useeffect-ssr/

```typescript
import type { NextPage } from "next";
import axios from "axios";
import { useEffect, useState } from "react";
import { AccountTable } from "../components/account/AccountTable";
import { Box } from "@chakra-ui/react";

const Account: NextPage = () => {
  const [accounts, setAccounts] = useState([]);

  // クライアント側でレンダリングする際に実行
  useEffect(() => {
    axios.get("/data/accounts.json").then((res) => {
      setAccounts(res.data);
    });
  });

  return (
    <div>
      <Box m="10px">アカウント管理画面</Box>
      <AccountTable accounts={accounts} />
    </div>
  );
};

export default Account;
```

# SSR
・getServerSideProps関数 ... サーバ側でレンダリング時に実行されるもの
・HTMLを生成するために必要な動的データの取得(APIコール)は、この関数内で実行する。
・ユーザ起因の動的データ取得処理は別で書けばOK。

```typescript
export async function getServerSideProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}
```

# SSRは基本的に使わない方が良さそう
下記の記事でSSRを使うべきか/使わないべきかについて説明してくれている。
あとで自分用に見返すためにまとめ部分だけ引用させていただく。

> ・基本的にSSRをするとコードが複雑になるので、避けられるなら避けるべき。
> ・SSRが必要なのはSEOを意識するWebページだけ。
> ・SEOが不要なページであれば、認証ありなAPIコールは全てブラウザ上で行えば良い。
> ・不用意な混入を防ぐために、getInitialPropsをやめてgetServerSidePropsを使おう。

https://qiita.com/ryokkkke/items/1bd858a5d6f261a9342a

# SSG
・useStaticProps関数　... ビルド時に実行されるもの
・propsとして渡されるデータは、**ビルド時にJSONファイルとして生成される**。
・HTTPリクエスト時にJSONファイルが同梱される。

```typescript
import type { NextPage, GetStaticProps } from "next";

// propsとして受け取る型を定義
type Props = {
  accounts: AccountDto[];
};

const Account: NextPage<Props> = (props) => {
　//------
}
// ★ pagePropsとしてのデータは「out/_next/data/hogehoge配下にJSONファイルとして保存される」
export const getStaticProps: GetStaticProps<Props> = async () => {
  // getStaticPropsでaxios使うと怒られた。
  // const accounts = (await axios.get("/data/accounts.json")).data;
  const accounts = [
    {
      id: "act_0000001",
      name: "Anthony",
      age: 26,
      gender: "男",
    },
  ];
  return {
    props: { accounts }, // will be passed to the page component as props
  };
};
```
ブロック暗号とストリーム暗号

## 勉強前イメージ

どっちもわからんし、違いはもちろんわからん

## 調査

### ブロック暗号 とは

共通鍵暗号の一種でブロックと呼ばれる固定長のデータ単位で暗号化を行います。
平文のデータをある特定の長さに区切ってその単位で暗号化するアルゴリズムになり、暗号文の長さは平文と同じになります。
ブロック内でデータの位置の入れ替えなどが行われるので、復号するためにはブロック全体のデータが必要です。

ブロック暗号には以下のようにいくつかのモードがあります。

- ECBモード

Electronic Codebook Mode の略で、
前のブロックの結果を利用しないで、どのブロックにも同じ暗号化処理を行う方式です。
一番単純で平文と暗号鍵のみ用いて暗号文を作成します。
このことから解読されやすく実用上はあまり使わないような良いとされています。

- CBCモード

Cipher Block Chaining Mode の略で、
直前のブロックの暗号文の各ビットのXOR演算したデータと平文に対して暗号化を行う方式です。
よく使用される暗号方式です。
最初のブロックには直前のブロックがないためダミーデータが用意されます。
安全性は高いが並列化できず時間がかかったり、伝搬エラーがその後のブロックにも影響が生じるなどあります。

### ストリーム暗号 とは

共通鍵暗号の一種で、データを1ビットまたは1バイト単位で暗号化を行います。
SSLや無線LANなどのネットワークを暗号化するために使われています。
データを1ビットまたは1バイト単位で暗号化できることから、復号に要する時間が短いのが特徴です。
ブロック暗号は一定のデータを纏めて復号することから一定量満たないといけないですが、ストリーム暗号は受信したものからすぐに復号可能です。

ストリーム暗号にもいくつかの方式があります。

- 外部同期式

送信者と受信者が同期した状態でデータのやり取りを行う方式で、
第三者から途中でデータの削除などが行われた際に、
同期にエラーが生じるのですぐに検知、他のビットへ誤りの影響が及ばないのが特徴です。

- 自己同期式

外部同期式と比べて非同期式とも呼ばれますが、同期がずれた際に自動的に修復できる方式です。
しかし、弱点としては1ビットの誤りが他のビットに伝搬してしまうということがあります。

## 勉強後イメージ

ブロックごとに暗号化するのがブロック暗号。
すぐに(1ビット1バイト)暗号化するのがストリーム暗号。
早く復号化したいときはストリーム暗号。

## 参考

- [ブロック暗号とは？特徴やストリーム暗号との違いを解説！](https://it-trend.jp/encryption/article/64-0066)
- [ストリーム暗号とは？仕組みや安全性について詳しく解説！](https://it-trend.jp/encryption/article/64-0060)
MIPSのSIMD

古くはi386のmmxやamd64のsseやarmのneonのようにmipsにもase dspという命令があります。ase dspに最初のレビジョンとレビジョン2があります。またこれより後にリリースされたMSA(MIPS SIMD Architecture)というのあるようです。DSPは64BitでMSAは128Bitでまったく別物です。

ase dspは2005年くらいに24KEでサポートされました。

https://pc.watch.impress.co.jp/docs/2005/0524/spf05.htm

これらはConfig3レジスタでサポートの確認ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4fd73072-9dc1-9a7a-ed6e-7468679cbd29.png)

10ビットが最初のレビジョンで11ビットがレビジョン2になります。

RalinkのRT3050は24KEでDSPPが1でサポートがありました。Atherosの24Kはサポートがありません。AtherosもMediatek(Ralink)も74KはDSPP,DSP2Pの両方サポートがあります。

|Vendor|4K|24K|74K|
|:--|:--|:--|:--|
|Atheros|×|×|DSPP,DSP2P|
|Ralink|×|DSPP|DSPP,DSP2P|

ちなみにFPUはすべてのチップで未搭載のようです。

コードの書き方は

Effective DSP Programming using MIPS® DSP Application Specific Extensions

が参考になりそうです。

実際のコードはqeumにテストコードがありました。

またcairoなどで使われているpixmanにもDSP2Pの最適化コードがあります。

またセルビアの大学の方が"Graphic Library Optimization for MIPS Architecture"という論文でlibpngの最適化コードの事を書かれています。

これを確認していて気がついたのですが、CPUの情報が含まれてるdmesgとそうでないものがあります。確認してみたところ、おそらく13-CURRENTの頃に下記の修正が入り、dmesgに含まれるようになったものの、12-STABLEにはMFCされてないようです。MFCってのはCURRENTから過去のSTABLEに反映する対応なんですが、14-CURRENTの現在sys/mipsは消されてしまったので、MFCができません。


https://reviews.freebsd.org/D24936

勝手に自分のブランチ(ZRouter:freebsd-src:zrouter_yamori813)にMFCしました。

gccのオプションは-mdspと-mdspr2になります。

FreeBSDのコマンドのビルドにmdspをつけても有効にならないようです。

```
Assembler messages:
Warning: mips3 ISA does not support DSP ASE
```

marchをmips32にするとワーニングがでなくなりますが、リンクでエラーになります。

```
sin.o: linking mips:isa32 module with previous mips:4000 modules
```

ZRouterの設定を修正してmdspオプションが使えるようにしました。

RISCアーキテクチャってのは、コンパイラーの最適化でパフォーマンスが出せるように、インストラクションを簡素にするってアプローチですが、SIMDは人力でアセンブラを書き最適化するという手法により高速化しています。

本来MIPSアーキテクチャとSIMDは対極にあると思うのですが、綺麗ごとばかりも言ってられないってことなのかもしれません。

なぜこれを調べたかというとmpg123にMIPSのSIMDコードがなかったので、どうなってるのか知りたかったためです。74Kくらいのパフォーマンスがあればとくに問題なくネットラジオの再生はできていますが、せっかくなのでffmpegのコードをぱちってくるのが良いような気がします。

また、FreeBSDのsoundドライバーはどうも24Kでは処理ができないぽいので、SIMDが使えればとおもいました。RalinkはDPSが使えますがAtherosは使えないので、微妙です。

MIPS社からFive Methods of Utilizing the MIPS® DSP ASEというドキュメントが出ています。これに5つのDSPサポートの方法が書いてあります。そのなかにあるMIPS DSP Libraryというのがあるのですが、~~どこにも見当たりません。fdk-aacで使っているのですが、コンパイルできません。~~ PIC32のレポジトリにありました。ZRouterのportsもどきにはライブラリコードを入れてビルドするようにしてあります。

* アセンブラで書く
* Cのインラインで書く
* gccのビルドイン関数を使う
* MIPS社のライブラリを使う
* 固定小数点を使う

などのようです。

fdk-aacではビルドイン関数も使っていて、-mdspオプションでビルドする必要がありました。
Swift で Link Header をパースする

# はじめに
今回、追加読み込みが可能な API の「次に読み込むものがあるか」をネイティブアプリ側に伝える手段として Link Header を利用しました。その際に必要になるパース処理の一例をご紹介します。
フォーマットなどは以下を参考にしてみてください。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Link

# Get Link Header
```swift
let response: HTTPURLResponse
let linkHeader = response.allHeaderFields["Link"] as? String
```

ヘッダ情報は HTTPURLResponse から取得可能です。ここでは以下の3点に注意した実装を行う必要があります。
- Link Header が含まれていない場合もある
- リンクは複数である可能性がある
- URL が Foundation.URL に準拠している保証はない

# Let's parse
```html
<url>; rel="rel", <url>; rel="rel"
```

先程取得した文字列には上記のようなフォーマットで値が格納されています。これをパースするのが今回の本題です。
さっそく以下の手順でパースしていきます。
1. `<url>; rel="rel"` を1セットとしてグループ化
1. グループ毎にパターンマッチング
1. マッチング位置を元に url, rel を文字列で抽出

## 1. グループ化
```swift
// ["<url>; rel=\"rel\"", "<url>; rel=\"rel\""]
let links = linkHeader.components(separatedBy: ",").map {
    $0.trimmingCharacters(in: .whitespaces)
}
```

グループの切れ目がカンマなので components を利用して分割します。これだけでも良いですが、カンマ後の半角スペースが余分に含まれてしまうので trimmingCharacters を利用して削除しています。

## 2. パターンマッチング
```swift
links.map { link in
    guard let regex = try? NSRegularExpression(pattern: "<(.*)>; rel=\"(.*)\"") else {
        return nil
    }
    ...
}
```

文字列抽出の方法はいくつかあると思いますが、今回は NSRegularExpression で正規表現を用いた抽出を行ってみます。
正規表現の書き方に関しては割愛しますが、取得したい2箇所が `()` で囲まれていることを意識すると、理解できるかと思います。

### 追記：2022/03/15
今回は url と rel のみが存在する場合のみで正規表現をご紹介しています。しかし、Link Header はそんなに単純なものではなく、title などの属性も使われる場合があります。

```swift
NSRegularExpression(pattern: "<(.*?)>(?:[^\"]|\"([^\"]*\")*;\\s*rel=\"(.*?)\"")
```
また、属性が2つ以上の場合、`<url>; title=""; rel=""`と `<url>; rel=""; title=""`の2パターンが考えられます。
どちらとも `; rel=""` であることに着目すると上記のように書き換えられます。
さらに別の属性も取得することを考えると…

## 3. 文字列で抽出
```swift
links.map { link in
    ...
    let matches = regex.matches(in: link, range: NSRange(location: .zero, length: link.count))
    guard let firstMatche = matches.first,
          firstMatche.numberOfRanges >= 2
    else {
        return nil
    }
}
```

matches 関数を利用して文字列からパターンにマッチする箇所を抽出します。
今回は map 関数内でパターンマッチングを行うため、`matches.first` として1つしか取れないことを前提とした処理としています。そして、取得したい箇所は2箇所なので安全のために `firstMatche.numberOfRanges >= 2` と制御を入れています。

カンマで分けずに文字列をそのままパターンマッチングさせれば、このような制御処理は不要なのですが、正規表現をシンプルに書きたかったのでこの方法を採用しました。

```swift
enum Relation: String {
    case next
    case none
}

links.map { link in
    ...
    let string: (Int) -> String = { at in
        NSString(string: link).substring(with: firstMatche.range(at: at))
    }
    let url = string(1)
    let rel = Relation(rawValue: string(2)) ?? .none
}
```

最後に仕上げです。
抽出したい箇所の Range をもとに実際の文字列を取得します。

# さいごに
いかがだったでしょうか。
フレームワークに頼らずに文字列をパースすると聞くと難しいイメージがありますが、Link Header に関してはかなりシンプルにパースできたと思います。

最後まで読んでいただき、ありがとうございます。
OpenCVでレシート画像を切り抜き （射影変換）その２

# 目的
- レシートと背景が写った写真からレシートをくりぬきたい
- OpenCVの理解
- なんか画像処理っぽいことしたい

# 前回のあらすじ
https://qiita.com/kazzzu/items/d9684319d2d0b64d6f31

写真の中からレシート部分を認識。線で囲う、まで行った。
今回は射影変換をやってみたいと思いました。


# 環境
- Windows11 Home
- VSCode
- Python3.9
- pip
 opencv-python 4.5.5.62

# 本編
射影変換をやってみたいと思いました。
参考：

https://qiita.com/mix_dvd/items/5674f26af467098842f0

## 輪郭抽出から
前回の輪郭抽出の結果はこんな感じ

![20220303_084409.jpg3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245578/f8561a42-492e-73d9-0a72-2a546747de0a.jpeg)

## 射影変換
これを射影変換します。

```    dst = []

    pts1 = np.float32(areas[0])
    pts2 = np.float32([[600,300],[600,0],[0,0],[0,300]])

    M = cv2.getPerspectiveTransform(pts1,pts2)
    dst = cv2.warpPerspective(img,M,(600,300))
    save_image(filename+"4", dst)

```

なんか90度回転してしまいました。

![20220303_084409.jpg4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245578/9cd1aa0b-27b1-e991-49f2-3d36d33c684d.jpeg)

頂点はどのように出てくるのだろうと思い　printしてみました。

```
print(areas[0])
```

輪郭抽出の頂点ですがどうやら
　右上→左上→左下→右下
となっているようです。
多分一筆書きで方向は順不同？

で、設定した射影側の頂点は
　右下→左下→左上→右上
なのでヘンテコになるのはそりゃそうですね。

```
[[[1947  348]]

 [[ 856  360]]

 [[ 853 3849]]

 [[1961 3790]]]

```

## 改善点
これを踏まえて以下の改善を行う。

- 輪郭抽出の頂点をソートし頂点の固定化
　レシート画像なので縦位置で縦長レシートと仮定する。
- 縦横の比率をもとのレシートになるだけ合わせる。

ちょっと冗長なプログラムになってしまいましたが何とかなりました。

```
    # 重心を求める
    cx=cy=0
    for i in areas[0]:
        cx += i[0][0]
        cy += i[0][1]
    cx /=len(areas[0])
    cy /=len(areas[0])

    # 切り取り画像サイズを求める
    h=w=0
    for i in areas[0]:
        if i[0][0]>cx :
            w +=i[0][0]
        else:
            w -=i[0][0]
        #右側
        if i[0][1]>cy:
            #右下
            h += i[0][1]
        else:
            #右上
            h -= i[0][1]

    # 点の順番を求める　tmp
    tmp = []
    for i in areas[0]:
        if i[0][0]>cx :
            #右側
            if i[0][1]>cy:
                #右下
                tmp.append([w,h])
            else:
                #右上
                tmp.append([w,0])
        else:
            #左側
            if i[0][1]>cy:
                #左下
                tmp.append([0,h])
            else:
                #左上
                tmp.append([0,0])
    # 射影変換
    dst = []
    pts1 = np.float32(areas[0])
    pts2 = np.float32([tmp])

    M = cv2.getPerspectiveTransform(pts1,pts2)
    dst = cv2.warpPerspective(img,M,(w,h))
    save_image(filename+"4", dst)
```

## 改良―射影変換の結果

これが
![20220303_084409.jpg3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245578/66f5d221-abe4-926b-d0b2-86a649c47384.jpeg)

こういう風に
![20220303_084409.jpg4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245578/7d2ead32-57f3-49db-0545-383844dc62b1.jpeg)

これも
![20170104_090657.jpg3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245578/1b4738bd-94da-4976-7614-2a35b872d8e0.jpeg)
こうなりました
![20170104_090657.jpg4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245578/b99dfd5b-68e3-9d0d-3692-21ce463c3478.jpeg)
AWS EC2 AmazonLinux2 yarnコマンドを実行できるようにする

# 概要

- EC2のAmazonLinux2インスタンスにてyarnコマンドを実行できるようにする方法をまとめる。

# 前提

- 下記の記事を参考に当該のAmazonLinux2インスタンスにてnpmコマンドが実行できる状態になっていること。
    - [AWS EC2 nvmを用いてNode.jsをインストールしてnpmコマンドを実行できるようにする](https://qiita.com/miriwo/items/2accf74a33e71d0a0d61)

# 方法

1. EC2インスタンスにssh接続を行い、下記コマンドを実行してyarnをインストールする。

    ```terminal
    $ npm install --global yarn
    ```

1. インストール後に下記コマンドを実行してyarnコマンドが実行できる事を確認する。（command not foundがでなければOK）

    ```terminal
    $ yarn --version
    ```
Cypressのcontainsで完全一致を使う

# 方法１

```typescript
cy.contains(/^文字列$/);
```
Cypressは正規表現をサポートしている

# 方法2
```typescript
const str = '文字列';
cy.contains(new RegExp(`^${str}$`, 'g'));
```
変数で検索したい場合はこうする


# 参考
https://stackoverflow.com/questions/56443963/click-an-exact-match-text-in-cypress
【Git】ローカルブランチを強制的にリモートブランチの状態へ変更するコマンド

競合解消時に何がなんだか分からなくなり、全てを無かったことにしたくなった時に使った。

:::note warn
警告
pushしていない変更がある場合、その変更は消えます
:::

```
git reset --hard origin/ブランチ名
```

例えば「ローカルのdevelopブランチをリモートのdevelopブランチの状態にする」
```
git reset --hard origin/develop
```
ApacheとNginx【個人的なお勉強アウトプット】

どちらもHTML文書ファイルなどの多くのリクエストを処理してブラウザで見れるようにするもの。
Apacheの方が先に出来てLinuxOS等でプリインストールさてれいたから主流だった。
しかし、Apacheにも不得意なところがあった。
Apacheは.htaccessを使用してディレクトリ単位でサーバーの設定を変えれる。
これは特にサーバーのプロバイダーにとって夢の状態。
しかし、.htaccessを読み込むために各ディレクトリを見に行く処理に結構時間がかかってるみたい。
また、マルチプロセスで1リクエストに対して1プロセスで処理を行い、同時接続のリクエストが増えれば増えるほどプロセスが増加し、サーバーのメモリを消費してしまい、メモリ使用に限界を迎えてサーバーがパンクする問題があった。
そのような問題を解決するために生まれたNginx。
Nginxはシングルスレッドのプロセスでたくさんのリクエストを並列で処理できる。
かつ、リバースプロキシとロードバランサを使うことができるので、他のサーバーとも協力して負荷分散できる仕組み。
ただ、動的処理が苦手。
なので、動的な処理はリバースプロキシでアプリケーションサーバーとしてApacheを使用する構成もあるみたい。
静的ファイルの表示だけだったらNginxの方が早い。
適材適所で使い分けたり、組み合わせて使うのが良さそう。

# 参考記事
https://www.sbbit.jp/article/cont1/65256
https://kinsta.com/jp/blog/nginx-vs-apache/
https://wa3.i-3-i.info/word1755.html
lambdaでセキュリティグループのインバウンドルールを変更する

AWSに構築したシステムのセキュリティ設計として、セキュリティグループでインバウンド制限をすることは珍しくないと思います。システムの利用者が増えた・減った場合、セキュリティグループを更新する必要があり、通常はAWSコンソールで変更すれば良いですが、諸事情により非エンジニアがAWSコンソールを使わずに変更できるようにする必要があったので、その方法をメモしておきます。

# はじめに
設定する人がエンジニアではない想定だったので、WEBでセキュリティグループのインバウンドを追加・削除できるようにしました。全体のアーキテクチャは下記のような感じなのですが、この記事ではlambdaにフォーカスしています。

![provDiagram.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989777/4c9dff3d-0b12-3990-03e8-3c8ee5cfe207.jpeg)

# lambdaでセキュリティグループの追加削除する
lambdaでboto3を使ってセキュリティグループへのIPアドレス追加、削除をします。
今回はpython 3.8を使っています。
セキュリティグループにアクセスできるように、lambdaのロールを追加しておく必要があります。AmazonEC2FullAccessがあればOKです。

## セキュリティグループの設定を取得する
まずは、対象のセキュリティグループの設定を取得します。
boto3やjsonなど必要なモジュールはimportしている前提です。
セキュリティグループは、セキュリティグループIDで指定します。
```py:sg_prov.py
    ec2 = boto3.client('ec2')
    sec_g = 'sg-xxxxxxxxxxxxxxxxx'
        
    res = ec2.describe_security_groups(
        GroupIds=[sec_g]
        )
```

戻り値で、登録しようとしているIPアドレスが含まれているか（すでに登録ずみか）のチェックができます。
```py:sg_prov.py
    json_res = json.dumps(res)
    if add_ip in json_res :
        #登録済みの場合の処理
```

## セキュリティグループにIPアドレスを追加する
追加する場合は、セキュリティグループ、ポート、IPアドレス、Descriptionを指定して登録します。
```py:sg_prov.py
        add_res = ec2.authorize_security_group_ingress(
            GroupId=sec_g,
            DryRun=False,
            IpPermissions=[
                {
                    'IpProtocol': 'tcp',
                    'FromPort': 443,
                    'ToPort': 443,
                    'IpRanges': [
                        {
                            'CidrIp': add_ip,
                            'Description': desc
                        },
                    ]
                }
            ]
        )
```

## セキュリティグループからIPアドレスを削除する
削除する場合は、セキュリティグループ、削除対象のポート、IPアドレスを指定します。
```py:sg_prov.py
        del_res = ec2.revoke_security_group_ingress(
            GroupId=sec_g,
            IpPermissions=[
                {
                    'IpProtocol': 'tcp',
                    'FromPort': 443,
                    'ToPort': 443,
                    'IpRanges': [
                        {
                            'CidrIp': add_ip,
                        },
                    ]
                }
            ]
        )
```

# まとめ
AWSコンソールで、追加・削除ができていることが確認できれば完了です。
SQL サブクエリの基礎の基礎のメモ

# 概要

- お恥ずかしながらSQLのサブクエリをしっかりと理解できていなかったので基礎だけまずまとめてみる。

# 前提

- MySQL8系を用いて説明する

# 準備

- 下記のSQLをすべて実行して検証用のDB、テーブル、データを作成する。
- DBの作成

    ```sql
    create database test;
    ```

- テーブルの作成

    ```sql
    use test;
    create table users (
        id int(11) auto_increment,
        last_name varchar(255),
        first_name varchar(255),
        age int(11),
        PRIMARY KEY (id)
    );
    ```

- データのインサート

    ```sql
    insert into users
    values(
        1,
        'Yamada',
        'Ichirou',
        20
    ),
    (
        2,
        'Yamada',
        'Jirou',
        19
    ),
    (
        3,
        'Yamada',
        'Saburou',
        15
    ),
    (
        4,
        'Yamada',
        'Shirou',
        13
    ),
    (
        5,
        'Satou',
        'Ichirou',
        22
    ),
    (
        6,
        'Satou',
        'Jirou',
        20
    ),
    (
        7,
        'Satou',
        'Saburou',
        19
    ),
    (
        8,
        'Satou',
        'Shirou',
        17
    );
    ```

# 基礎サブクエリを体験してみる

- サブクエリとはSQLの実行結果を用いてSQLを実行できるものらしい。
- とあるselect句の結果を元にselect句を実行するとかができる。
- 「準備」のSQLをすべて実行した後に下記のSQLを実行すると言わずもがなテーブルのすべてのレコードが出力される。

    ```sql
    select * from users;
    ```

- last_nameが「Yamada」のレコードだけを絞り込んで出力したい場合、下記のSQLを実行する。

    ```sql
    select * from users where last_name = 'Yamada';
    +----+-----------+------------+------+
    | id | last_name | first_name | age  |
    +----+-----------+------------+------+
    |  1 | Yamada    | Ichirou    |   20 |
    |  2 | Yamada    | Jirou      |   19 |
    |  3 | Yamada    | Saburou    |   15 |
    |  4 | Yamada    | Shirou     |   13 |
    +----+-----------+------------+------+
    ```

- 一つ前の`last_nameが「Yamada」のレコードだけを絞り込んで出力したい場合`をあえてサブクエリを使って記載してみる。

    ```sql
    select * from (select * from users where last_name = 'Yamada') as users;
    +----+-----------+------------+------+
    | id | last_name | first_name | age  |
    +----+-----------+------------+------+
    |  1 | Yamada    | Ichirou    |   20 |
    |  2 | Yamada    | Jirou      |   19 |
    |  3 | Yamada    | Saburou    |   15 |
    |  4 | Yamada    | Shirou     |   13 |
    +----+-----------+------------+------+
    ```

- 上記の2個のSQLは同じ情報が出力されている。（本来このレベルの処理ならあえてサブクエリを使う必要はない。）
- サブクエリの処理についてまとめる。
    - 全体

        ```sql
        select * from (select * from users where last_name = 'Yamada') as hoge;
        ```

    - 処理の流れ
        1. `(select * from users where last_name = 'Yamada')`の処理が実行される。
        1. 上記処理の結果を`as hoge`にて「hoge」という名前をつける。
        1. `select * from hoge`を実行する。（hogeには最初に実行されたselect句の実行結果が格納されている）

# 参考文献

- [https://wa3.i-3-i.info/word17573.html](https://wa3.i-3-i.info/word17573.html)
【AWS】EC2内にDockerをインストールする一番簡単な方法！

# はじめに
皆さんがEC2内にDockerをインストールしたことがありますでしょうか？
もちろん公式[dockerのドキュメント](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/)では、Dockerインストールする方法は紹介されており、スクリプトを実行すれば、手軽にインストールことができます。
実はAWSはもっと簡単な方法が提供されていることは皆さんご存知でしょうか？

# 結論
AWS側では非常に簡単なインストール方法が提供されており、
それはSystems Managerが提供しているRun Commandを利用することです！

Run Commandで``AWS-ConfigureDocker``を一発実行すれば、
EC2内にDockerをインストールすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/b9f30a2d-d167-ff5c-f15e-6cb5c39284bf.png)
この機能はめちゃくちゃ便利で、非常にお勧めします！！

# 手順
１．Systems Managerを利用する前提は、EC2にSSM用ロールを付与することです。
以下のように、``AmazonEC2RoleforSSM``ロールをEC2に付与します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/6fa86a92-5d01-6726-cf2d-e243f211064a.png)

２．EC2上にSystems Manager Agentをインストールします。
公式サイトに準じて、Systems Manager Agentをインストールしてください。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-manual-agent-install.html

３．Systems ManagerのRun Commandで、``AWS-ConfigureDocker``を選択してから実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/7e33fa55-dea6-f13c-7256-cbb38fa019a4.png)
ターゲットに、対象のEC2を選択し他の上、実行してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/9427ceb9-1024-29f7-834e-d112eafce570.png)

４．しばらく時間が経つと、実行成功が確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/af1fe6dd-683c-cc96-f579-22ae6377cd7d.png)

５．EC2内に確認したところ、Dockerが無事にインストールされたことを確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/850ed23b-27dc-b1db-82fd-401f8c23614c.png)

# 注意点
EC2はUbuntuの場合は、現時点ではまだサポートされていない模様です。
実際UbuntuのEC2に、上記のRunCommandを実行したら、下記のようなエラーが出力されていました。
いつかUbuntuもサポートされたら嬉しいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/865613/346b7198-4a29-2b9a-3422-ce3332bd00bb.png)
PHP Interface

# オブジェクト インターフェイス
**メソッドの実装を定義せず**に、クラスが実装する必要があるメソッドを指定する。

通常のクラスと同様に定義できるが`class`ではなく`interface`を用いる。

```php
interface HogeRepository
{
  public function create(): Hoge;
  public function delete(int $id): bool;
}
```

# 役割
- 同じインターフェイスを実装していることで、開発者が交換可能な異なるクラスを作成できる。
  実装が異なっていても、**インターフェイスを使うコードに変更を加えることなく、実装を交換**することができる。
- メソッドがインターフェイスを満たす引数を受け付け、操作できるようにする。
  **中身が何をするのかや、どう実装されているかを気にする必要がない**。

# implements（実装）
インターフェイスを実装するクラスに宣言する。

```php
class HogeProvider implements HogeRepository
{
  public function create(): Hoge
  {
    // 作成処理
    return new Hoge();
  }

  public function delete(int $id): bool
  {
    // 削除処理
    return true;
  }
}
```

# 参考
[PHP オブジェクトインスタンス](https://www.php.net/manual/ja/language.oop5.interfaces.php)
【備忘録】xampp環境でlaravelインストール直後に行ういろいろ(プロジェクト作成～確認）

## xamppへlaravelインストール後のメモ
xampp環境で起動方法とかいろいろ忘れちゃいそうなのでメモ

▼laravelインストール後
----
 c:\xampp 配下で以下を実行し、プロジェクトを作成する

     laravel new プロジェクト名
※今回はlaravel new shiftappを作成。（シフト管理ページ）


 作成したプロジェクトのディレクトリへ移動する
----
(ベースサンプル→C:\xampp\htdocs\laravel_sample)
今回は↓

    C:\xampp\shiftapp

その後、以下コマンド実行後、http://127.0.0.1:8000 へアクセスする。
----
    php artisan serve

確認→http://127.0.0.1:8000




----
#### ・初期設定ファイルメモ
いろいろ日本にする設定

app.phpを変更
`'timezone' => 'UTC',`
↓
`'timezone' => 'Asia/Tokyo',`

`'locale' => 'en',`
↓
 `'locale' => 'ja',`

`'fallback_locale' => 'en',`
↓
`'fallback_locale' => 'ja',`

`'faker_locale' => 'en_US',`
↓
`'faker_locale' => 'ja_JP',`

ファイル変更後、キャッシュクリア

    php artisan config:clear
【3分で終わる】とにかく簡単にphpのフォーマッターを導入する（PHP-CS-Fixer）

## PHP-CS-Fixer

https://github.com/FriendsOfPHP/PHP-CS-Fixer

PSR-1、PSR-2などで定義されているPHPコーディング規約に整形してくれるツールです。


## 一番簡単な方法

ひとまずインストールします。
```shell
$ composer require --dev friendsofphp/php-cs-fixer
```

composer.jsonのscriptsに下記を記載します。
（ルールはお好みで）
```json
{
    "scripts": {
        "fixer": [
            "vendor/bin/php-cs-fixer fix src --rules=@Symfony,@PhpCsFixer,@PHP80Migration,declare_strict_types --allow-risky=yes"
        ],
}
```

実行すると整形されます。
```shell
$ composer fixer
> vendor/bin/php-cs-fixer fix src --rules=@Symfony,@PhpCsFixer,@PHP80Migration,declare_strict_types --allow-risky=yes
Loaded config default.
Using cache file ".php-cs-fixer.cache".

Fixed all files in 0.056 seconds, 12.000 MB memory used
```
個人プロダクト以外や、除外するファイルが多いとちゃんと定義ファイルを書いたほうが良さそう。

```shell 
$ echo /.php-cs-fixer.cache >> ./.gitignore
```
PHP-CS-Fixerは実行するとキャッシュファイルを生成するのでignoreするのをお忘れなく

## フォーマットのルールについて
[ルールの数](https://mlocati.github.io/php-cs-fixer-configurator/#version:3.7)はかなり多く、細かく設定するとかなり時間がかかりそう。

`@Symfony` `@PhpCsFixer`などのメジャーなルールを設定すれば、PSRの規則通りになるので時間かけずにチャチャッと実行するのが良さそうだと思いました。

## 既存プロダクトに導入する際の注意点
全てのコードをフォーマットするととんでもないバグを生み出してしまったりするので、注意しましょう。
導入する際はフォーマット前とフォーマット後でASTの変更がないことを検証すると、挙動に変更がないことを証明できます。
（参考) [20 万行超のコードベースをテストせずにリファクタリングリリースした話](https://tech-blog.monotaro.com/entry/2018/09/26/142451)
GitでSubmoduleを含むリポジトリをCloneできないときの対処方法

先日友人と共同作業をするために、友人のGitリポジトリをCloneする機会がありました。

このリポジトリにはSubmoduleが含まれていたので、

``` bash
$ git clone --recursive リポジトリ.git
```

の形でcloneしようとしたのですが、見事にエラーになりました。

``` bash
Submodule 'サブモジュール名' (git@github.com:サブモジュールの場所.git) registered for path 'サブモジュール名'
Cloning into 'ローカルのパス'...
Host key verification failed.
fatal: Could not read from remote repository.
```

と言われてしまいました。

ちなみに、GitHub DesktopでCloneした場合は以下のようなメッセージが出ます。

``` Clone failed.txt
Authentication failed. Some common reasons include:

- You are not logged in to your account: see File > Options.
- You may need to log out and log back in to refresh your token.
- You do not have permission to access this repository.
- The repository is archived on GitHub. Check the repository settings to confirm you are still permitted to push commits.
- If you use SSH authentication, check that your key is added to the ssh-agent and associated with your account.
- If you use SSH authentication, ensure the host key verification passes for your repository hosting service.
- If you used username / password authentication, you might need to use a Personal Access Token instead of your account password. Check the documentation of your repository hosting service.
```

## 環境・状況

- 対象はGitHubのPublicリポジトリ
- submoduleもPublic
- リポジトリを作成した側は特に問題なく使えている


## 原因：sshでcloneしようとして認証ができない

SubmoduleのCloneができない理由の全てがコレ、ではないですが、私の場合はcloneの方法がsshになっていたことが原因でした。



## 解決方法

sshでなくhttpsでcloneするように変更します。

そのためには

1. 一度submoduleの中身以外をclone
1. 設定を一部書き換え
1. submodule部分を含めてclone

という流れで行います。


### cloneする

すでに上に書いたような`git clone --recursive ~~~`が済んでいるようであれば、submoduleの中身以外はcloneされた状態にあっているので、済です。

まだの場合はcloneしてください。

### 設定を書き換える

`.git`があるディレクトリ、.gitignore`を同じ階層に、`.gitmodules`というファイルを作成します。

中に以下情報を書き込みます。

``` .gitmodules
[submodule "marpstyle"]
	path = marpstyle
	url = https://github.com/cunhapaulo/marpstyle.git
```

ここではmarpstyleの例を出していますが、pathにはsubmoduleが入ったディレクトリへのパスを、urlはsubmoduleのclone先を記載します。

もし既に`.gitmodules`が存在していた場合、urlで指定しているものが`git@github~`のように記載されていないか確認してみてください。sshで接続する指定になっている可能性があります。

### submoduleを含めてclone

以下を実行

``` bash
$ git submodule update --init --recursive
```

## 参考

- [[Git]サブモジュールを含んだリポジトリをクローンする | CodeLab](https://codelab.website/git-submodule-clone/)
- [GitのSubmoduleのプロトコルをsshからhttpsに変更する方法(またはその逆)](https://rcmdnk.com/blog/2016/12/28/computer-git/)
- [git submoduleでhttpsとsshを使い分ける（仮） - Qiita](https://qiita.com/aokomoriuta/items/598ba477f4d96a6f0395)
ブラックボックステストについて

# ブラックボックステストとは ?
主にホワイトボックステストを用いた単体テストが終わると、続いて、ソフトウェアの内部構造を意識しない「ブラックボックステスト」を行います。ブラックボックステストは主に機能テストとシステムテストにおいて実施します。

## 各テスト工程での作業内容
各テスト工程には、それぞれ「テスト計画」、「テスト設計」、「テストケース作成」、「テスト実施」、「テスト報告」というフェーズがあります。

- テスト計画
テスト工程の目的と範囲を明確にし、どのようなアプローチテストするのかを検討する。テストに必要な設備や環境、人員といったリソースの調達やスケジュールなども定める。


|テストフェーズ|説明|備考
| :------------- | :------------: | -------------: 
|テスト計画| テスト工程の目的と範囲を明確にし、どのようなアプローチでテストするのかを検討する。テストに必要な設備や環境、人員といったリソースの調達やスケジュールなども定める              |
|テスト設計| そのテスト工程で実施すべきテストの種類や目的、テスト対象機能、使用するテスト技法、テストの入力・出力に何を使用するかな土を定める。また、テスト実施に必要な機材や合否判定基準などをより具体的に定める。 |      
|テストケース作成| 　テスト開始前の状態や、期待結果(テスト実施時の条件や操作手順に従ってテスト対象を動作させた結果どうなるか)や、判定欄（テスト対象の動作結果を記録する欄）などを記入するドキュメントを作成する |       
|テスト実施 | テストケースを見ながら実際にソフトウェアを動作させてテストを行い、その結果をテストケースの判定欄に○×などで記載する。期待結果と異なるテストケースがあった場合は判定欄に×印を記入した上で、不具合報告書を作成する。不具合報告書には、期待結果と異なった現象の説明や、その現象がどのような場合(操作、入力値、条件など)に発生するのかを記載する |
|テスト報告| テスト結果を要約して報告する。テストの合否基準を満たしているかを、各種データ（実施項目数、テスト消化率、実施工数など）や不具合データ（検出不具合件数、重大度別の不具合件数など）を元に評価する。また、リリース後に懸念されるリスクや磁気プロジェクトでの推奨事項などを提案する。 |

## テスト設計の流れ
テスト計画・テスト設計の具体的な作業内容を見ていきます。テスト計画ではテスト工程単位、テスト設計ではテスト観点（テストの種類）単位で書く内容を検討します。

1. テストの目的の確認
1. 機能一覧の作成
1. テスト観点の抽出
1. テスト観点の機能への割り当て
1. テスト技法の検討と適用
    1. リソースの見積もり
    1. スケジュールの作成
    1. 体制、役割 
    1. 設備、環境、場所 

最初に、テスト全体計画書を見てテストの目的(重点的に確認する品質特性など)を確認します。

## まとめ
ブラックボックステストはホワイトボックステストを用いた単体テストが終了し、ソフトウェアの内部構造を意識しないことをブラックボックステストという。
Laravelサービスプロバイダ

# 概要
初期起動処理。
サービスコンテナの結合や、イベントリスナ、フィルタ、ルートなどを登録することを一般的に指す。

Laravelの場合、プロバイダクラスは`config/app.php`内の`providers`配列に設定する。

# 記述
- 全てのサービスプロバイダは`ServiceProvider`クラスを拡張する
- `register`と`boot`メソッドを持つ
- `register`メソッドの中では**サービスコンテナへの登録**だけを行わなければならない
- `make:provider`コマンドにより、新しいプロバイダが作成できる

```
php artisan make:provider HogeServiceProvider
```

## registerメソッド
**サービスコンテナ**に何かを結合することだけを行う。
Laravelにおけるサービスコンテナとは、クラスの依存関係を管理し、依存注入を実行するツール。

サービスプロバイダ内では`$this->app`を介しコンテナにアクセスできる。

```php
use App\Services\Hoge\Connection;

class HogeServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('hoge'));
        });
    }
}
```

上記はサービスコンテナ内の`Hoge/Connection`の実装を定義している。
`singleton`メソッドは、クラスをコンテナにバインドするが、これは**1回のみ依存解決される**結合である。
シングルトン結合が依存解決されたらコンテナに対する後続の呼び出しで、
同じオブジェクトインスタンスが返される。

## bootメソッド

**ビューコンポーサ**をサービスプロバイダで登録する場合`boot`メソッドを使用する。
ビューコンポーザとは、ビューをレンダリングする時に呼び出すメソッド。

このメソッドは**他の全サービスプロバイダが登録し終えてから**呼び出される。

```php
public function boot()
{
    View::composer('view', function () {
        //
    });
}
```

# 参考
[Laravelドキュメント - サービスプロバイダ](https://readouble.com/laravel/8.x/ja/providers.html)