OmniAICreator/Qiita-1.07M huggingface dataset:
演算子のオーバーロード，比較関数について「個人的なメモ」

## 構造体, 演算子のオーバーロード（比較）

```c++
struct Edge{
    int a, b, cost;
    bool operator<(const Edge& other) {
        return cost < other.cost;
    }
};

int main(){
    vector<Edge> v={{1,2, 3}, {2, 3, 1}, {1, 1, 0}};
    sort(v.begin(), v.end());
    for(auto e : v){
        cout << e.cost << "\n";
    }   
    return 0;
}
```
**出力結果**
構造体のメンバ変数costの昇順にソートされる．ソートの際に比較関数を用いれば同じことが出来るが，setに入れる時にはこのやり方が楽．

```
0
1
3
```
### 比較関数
演算子オーバーロードを使わずに構造体のメンバ変数costの昇順にソートする方法として，比較関数を用いる方法がある．出力結果は上の例と同じ．

```c++
struct Edge{
    int a, b, cost;
};

bool compare(Edge a, Edge b){
    return a.cost<b.cost;
}

int main(){
    vector<Edge> v={{1,2, 3}, {2, 3, 1}, {1, 1, 0}};
    sort(v.begin(), v.end(), compare);
    for(auto e : v){
        cout << e.cost << "\n";
    }
    return 0;
}
```
ストリーミング とは

## 勉強前イメージ

ダウンロードから読み込むんじゃなくて
ダウンロードしてきたデータをそのまま読み込むイメージ

## 調査

### ストリーミング

streaming と書き、ネットに接続された状態で
データ等をダウンロードしながら、再生・表示を行う方式。
動画等であれば、ダウンロードしてから再生ではなく ダウンロードしながら再生する方法になります。

### ストリーミングのメリデメ

メリデメは以下になります。
基本的にはストリーミングは高速で安定した場所で適していると思われます。

- メリット
	- 生放送のようなタイムラグのないものの配信可能
	- 端末に保存する手間と時間が短縮できる
	- 保存されないことで著作権侵害の問題の可能性を少なくした
	- 端末のデータ容量の圧縮がされない
- デメリット
	- 高速な通信回線ではないと再生に時間がかかったり、途中で途切れることがある
	- 端末に保存されないため、再生中は常にデータ通信が発生する

### ストリーミング と ダウンロード の違い

- ストリーミング
	- 再生しながらダウンロードする
	- 保存されない
- ダウンロード
	- ダウンロードしてから再生
	- 端末に保存

ストリーミングのイメージとしては、常に流れているテレビで
ダウンロードのイメージはCDを読み込んでから再生するラジカセのようなイメージになります。

## 勉強後イメージ

こうかなー？って思ってたことがそのまま結構当たってた
wifiある環境じゃないとストリーミングきついよね。

## 参考

- [ストリーミングとは？| 動画ストリーミングの仕組み](https://www.cloudflare.com/ja-jp/learning/video/what-is-streaming/)
- [ストリーミング](https://www.weblio.jp/content/%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0)
freenomで取りたいドメインが軒並み利用不可になる

全部取れねぇじゃねぇか！となった方へ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/bcd5476d-937e-8a21-42b8-46747240fa8c.png)

調べると、`.tk`までつけろというのもあるが、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/b80b5e99-0511-7e5a-5d89-cd3c320618f2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/62c7a3af-6a12-cd31-ee95-064a08a7d4da.png)

いやカートに入ってねぇじゃんか！ となる方へ。
こんにちは。
___

## 何がいけないか。

原因は正直わかりません。が、試した感じ、ドメイン検索/ドメイン選択のページの時点でサインインされていないと全部利用不可になりそうです。

「いや、ちゃんと最初にサインインしてるんだが。」と言われそうですが、実際に以下の流れでドメイン検索をかけるとドメイン選択の時点ではサインインされていないかのようになります。

freenomにアクセスし、ヘッダ部の`Sign in`からログイン。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/7de6cc0b-3ac4-4eca-c0ca-4928d27a5d2b.png)

ログインすると、`Hello ***`と出てきて、検索バーどこ行ったんだとなる。
この時に、右上の言語選択から`日本語`を選ぶと、言語を日本語に変えることもでき、ついでに検索バーも出てくるので押してたんですが、これをするとこの先でドメイン取得できなくなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/53c99550-275e-8980-3237-90d52b81fd67.png)

↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/ad8e6f0e-e7bc-7b1b-83c5-4a32dd2b8b37.png)

検索バーが出てきていい感じそうだが右上を見ると`サインイン`となっている。このまま突っ切ろうとすると上記のように全ドメイン取得不可orカート0現象に至ります。

## どうしたらいいのか。

日本語化は諦めましょう。ドメインを取るまでなので我慢して英語で行きます。
ヘッダの`Services` > `Register a New Domain`を選択すると検索バーが現れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/479ffe82-807b-3797-f9fd-71182fd2ea9c.png)

検索実行するとちょっとレスポンスが遅いですが次の画面に遷移します。
すると、日本語verとは違い、右上にサインインされている表示のままになる。
この状況だと、欲しいドメインを選択でき、`Checkout`するとちゃんと選択できているとわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/28e02693-86ee-861b-d19e-dc8f17619caf.png)

↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406130/c4b3c820-0c09-c6f9-e52a-4816ff0986b3.png)

Mission Complete!
あとは`Continue`してドメイン取得したらOK。
DNSについて

# はじめに
改めてWebの様々なことについて、復習を兼ねて理解を深めるため自分なりにまとめる。
ここでは主にDNSについてまとめる。

# DNSとは？
Domain Name Systemの略。
IPアドレスとドメイン名を紐づけているシステム。
まずは先にIPアドレスと、ドメイン名について簡単におさらいする。

## IPアドレス
IPアドレス（Internet Protocol Address）は、ネットワーク機器を識別するための番号。識別するため、もちろん重複してはいけない。

IPアドレスには、IPv4やIPv6といった通信する際のプロトコル（規約）がある。
(Internet Protocol version4/Internet Protocol version6)
これらには様々な違いがある。例えば、ビット数の違いがある。

IPv4では、32ビット。IPv6では128ビット。
IPV4では、
`11000000.10101000.00000001.00000011`という32ビット(2進数32桁)で表されていてこれを8ビットずつ区切り10進数、`192.168.1.3`という風に表記している。
2の32乗で約43億通り表現できる。

IPv6では、128ビット(2進数128桁)を16ビットごとに区切り、16進数で表記している。
2の128乗は、約43億×43億×43億×43億通り(ざっくり)表現できる。

上記のようにビット数が異なるため、IPv6のほうがより多くのIPアドレスを割り当てることが出来る。

IPv4が普及していく中で、42.9億とかなり多く表現できるように思われるが、実際世界中の機器に重複しないように割り当てる必要があることから、IPv4によるIPアドレスの枯渇問題が起こっている。

こうした背景からもより多く表現できるIPv6が登場した。
ただ、IPv4とIPv6に互換性がないことからも、IPv6へすぐに移行されることもなくどちらも使用されている。



### 参考
[IPv4とIPv6の違い8つとは？IPv4 over IPv6についても解説](https://www.fenet.jp/infla/column/network/ipv4%E3%81%A8ipv6%E3%81%AE%E9%81%95%E3%81%848%E3%81%A4%E3%81%A8%E3%81%AF%EF%BC%9Fipv4-over-ipv6%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%82%82%E8%A7%A3%E8%AA%AC/)

[IPアドレス枯渇問題](https://kotobank.jp/word/IP%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E6%9E%AF%E6%B8%87%E5%95%8F%E9%A1%8C-189185)


キタミ式イラストIT塾 基本情報技術者 平成31/01年

## ドメイン名
ドメイン名とは、インターネット上のネットワークを特定するための文字列。
サイト（サーバー）ごとにIPアドレスが振られていますが、IPアドレスを覚えるのは人間には難しい。
そこで、我々人間にも覚えやすいようIPアドレスを特定するための文字列がドメイン名。
IPアドレスを特定するため、ドメイン名も重複しない。

では、IPアドレスとドメイン名はどのようにして紐づいているのかというと、***DNS***がこれらを管理している。

## DNS
DNSによって、IPアドレスとドメイン名が紐づいていて、ドメイン名からIPアドレス（またはIPアドレスからドメイン名）へ変換することを***「名前解決」***という。

名前解決のざっくりとした流れは以下の通り。
１．クライアントからのリクエスト
２．DNSサーバーがIPアドレスをレスポンス
３．そのIPアドレスにアクセス

ただ、膨大な量のIPアドレスをDNSサーバーのみで管理するのは厳しい。
そこで、ドメイン名を「.(ドット)」で区切ってそれぞれの階層ごとに分散させて管理している。


この区切られた階層の一番上のものを***「ルートサーバー」***という。
そこから順に下位のサーバーに問い合わせをしていき、必要な情報を取得する。

ただ、毎回このルートサーバーに問い合わせをしてしまうと処理が集中してしまうため、***「キャッシュサーバー」***と呼ばれる、DNSサーバーへ問い合わせ（名前解決）専用のサーバを用意し、このサーバーを経由して名前解決が行われている。

このキャッシュサーバーは、一度問い合わせをして得た情報を一定期間保持することで無駄な問合せを減らしている。
一定期間が経過したら、また必要になった際は問い合わせを行う。


### 参考
ドメイン名とドメインネームシステム（DNS）　※図もありわかりやすかった

https://www.idcf.jp/rentalserver/user-support/knowledge/domain/dns.html
DBのストレージエンジンとは？

## 勉強前イメージ

ストレージエンジン？
わからん・・・

## 調査

### ストレージエンジンとは？

DBでのエンジンのことで、DBに対してデータをinsertしたりselectしたりするプログラムの部分で、
いくつかの構成要素によって成り立っています。
SQLを受け取って結果を返す → エンジン部分
データベースエンジンを結びつける → クライアントモジュール 等
様々なツールから成り立っており、DBのメインの部分になります。

### 動作について

クライアントからのSQLを受け取ると以下が走ります

1. SQLの解釈 → パース
2. どのようにしてデータを処理するか → プランナやオプティマイザ
3. 実データへのアクセス → ストレージエンジンの部分

特に3番目がストレージエンジンの動作の部分で
実データへアクセスしてSQL文を返す役割をしています。

### ストレージエンジンの種類

MySQLであれば以下のようなものが代表的です

- InnoDB : 行ロックとトランザクションのサポート
- Memory : メモリ上にテーブルを配置
- Merge : 複数のMyISAMテーブルを統合

試しにmysql8でストレージエンジンを確認してみたら以下のように出力されました。
InnoDBがデフォルトになっていました

```
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
```

### ストレージエンジンは指定できる

ストレージエンジンはテーブル単位で指定ができて、
create table時に `ENGINE` を使用して、使用したいストレージエンジンを指定できます。
alter tableでストレージエンジンの変更もできます。

## 勉強後イメージ

実データへアクセスする際にどうやってアクセスするのか、みたいなのでストレージエンジンがあるらしい
例えば↑の他にもCSVっていうストレージエンジンがあるらしくて、それはデータにCSVを使用できるから。
SQL文は一緒でもどうやってデータを取ってくるのかの箇所を指定できるってことかな。

## 参考

- [徹底比較!! MySQLエンジン](https://thinkit.co.jp/free/article/0608/1/1/)
- [ストレージエンジン (strage engine)](https://wa3.i-3-i.info/word11571.html)
【図解で理解】インタフェースとDIについて

<h2>はじめに</h2>
インタフェースとDIってなくても実装できるのに何で必要なの？と思ったのでこの記事にまとめました。

言語の学習の際につまずく要因として「何その考え？」ということが多いと思いますが、これを理解しておくのとしないのでは現場での活躍度が遥かに変わってくると思います。

図を用いて解説します。

<h2>インタフェースとは？</h2>
メソッドの具体的な処理は記載せずに「変数」「メソッドの型」を明記したもの。

要約すると、
他のクラスで使用する変数とメソッドが明記されたファイル。

インタフェースのメリットと使い方は<a herf="https://qiita.com/jin007/items/b4dc391a2e83eb999669">こちら</a>で詳しく記載しています。


<h2>DIとは？</h2>
DIとは、<b>外部の環境などに依存する部分(データへのアクセスなど)を切り離し、 ソフトウェアの外部から提供できるようにする</b>という考え方です。
(引用：Webアプリケーション開発教材 <a herf="http://si.comp.ae.keio.ac.jp/web_app_dev_material/app/di_container/">DIコンテナ</a>)

クラス間との<b>疎結合※</b>ができることによって保守性が上がります。

※疎結合とは、クラス同士の結びつきが弱く独立性のある状態のことを指します。逆にクラス同士の結びつきが強いものを<b>蜜結合</b>といいます。

<h4>▼図で理解を深める</h4>

![密結合.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/87b8ab71-c23c-5fba-bcf9-1a49a6c17265.jpeg)

改修、拡張しやすいように3層に分けているにも関わらず自身のクラス内でnewしてインスタンスを生成しているのでお互い強い依存関係になっている。

---
一方、疎結合は

①同様に各層毎にクラスが存在する。
　この時はまだお互いのクラスに依存性はない。
![疎結合1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/0b979161-daf7-67f2-c344-3ef36938942e.jpeg)

②蜜結合にしないためにインタフェースを各層のクラス間に定義する。（インタフェースを作成し「変数、メソッドの型」を作成する）
　このインタフェースを実装する形でビジネスロジック層の[Serviceクラス]、データアクセス層の[ServiceOdaクラス]をを実装していく。
![疎結合2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/6671e8f2-0272-c3a2-9c6b-e2aba72b12e4.jpeg)

③値を受け取るにはインタフェース型の変数を用意しておく。
　インタフェースの実装クラスである[Serviceクラス]のオブジェクトを[Controlクラス]に<b>外から渡してあげる</b>。（ServiceOdaクラスも同様）
　こうすることで、<b>自分のクラス内に他のクラスを指定して記載する必要がない！</b>ということになります。
![疎結合3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/eb1b79f8-86b9-e12e-09b9-bf21223446bb.jpeg)

④外から渡すために別のクラスを用意し、そのクラス内でnewして渡してあげることで依存性が解消されます。
![疎結合4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/491501/8c6d2967-257e-5b5a-604d-913350d5017e.jpeg)

このように外からオブジェクトを渡すことを「<b>DI※</b>」と言います。
DIの仕組みを使うことで直接newすることなくインスタンスを生成することができ依存性が解消されます。

※DI：Dependeny Injection（依存性の注入）と言い、分かりやすく言い換えると「<b>オブジェクトを外から渡す</b>」ということになります。

<h2>DIについて理解するまでもう一歩！</h2>
④の時のようにクラスを用意してDI化することも可能だが、一般的には「<b>DIコンテナ</b>」というものがフレームワークから提供されているのでそちらを使います。

DIコンテナの中で今回だと、[Service][ServiceDao]のオブジェクトを作成して渡してあげることができます。


<h2>まとめ</h2>
DIを使うと今まで依存関係があったクラス間を切り離すことができ、保守性が向上し、依存性が解消される。

<a herf="https://www.youtube.com/watch?v=SmiyWwP9Q1E">この解説動画</a>おすすめでした。
（注：職場のPCで閲覧されている方はお気を付けください！YouTubeに遷移します。）
【JavaScript】ナップザック問題


https://qiita.com/drken/items/a5e6fe22863b7992efdb

前回の続き．ナップザック問題をJavaScriptで実装してみたメモ．

```JavaScript:knapsack.js
const generate2DArray = (height, width) => {
    return [...Array(height)].map(() => Array(width).fill(0));
}

const knapsack = (items, weightLimit) => {
    const listHeight = items.length;
    let dp = generate2DArray(listHeight + 1, weightLimit + 1); // 0行目・0列目を含む二次元配列を生成

    for (let col = 0; col < listHeight; col++) {
        for (let row = 0; row < weightLimit + 1; row++) {
            if (row >= items[col][0]) {
                dp[col + 1][row] = Math.max(dp[col][row], dp[col][row - items[col][0]] + items[col][1]);
            } else {
                dp[col + 1][row] = dp[col][row];
            }
        }
    }

    return dp[listHeight][weightLimit];
}

const items = [
    [2, 3],
    [1, 2],
    [3, 6],
    [2, 1],
    [1, 3],
    [5, 85]
]; // weight, value

console.log(knapsack(items, 9)); // 94
```
Rubyのバージョンアップとrails new時のエラー対処方法

先日、Rubyのバージョンアップして、新しいバージョンでRailsアプリを作成しようとしたら、エラーが発生しました。
その時のRubyのバージョンアップ実施方法とエラーの原因、対処方法について備忘録としてまとめました。

###環境
MacOS 11.5.2
Ruby 2.6.6（バージョンアップ前）　→　3.0.2（バージョンアップ後）
Rails 6.1.4

###バージョンの確認
バージョンをあげる前に、現在のrubyのバージョンを確認する。

```
$ ruby -v
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin19]
$ rbenv version
2.6.6 (set by /Users/username/.rbenv/version)
```

###homebrewのバージョンアップとrbenvの導入
homebrewのアップデートとrbenvをインストールを実施します。
rbenvは、Rubyのバージョン管理ツールで、複数のrubyを管理、切り替えできます。

```
# homebrewを最新版にアップデートする 
$ brew update

# rbenvのインストールと最新版へのアップグレード
$ brew install rbenv ruby-build
$ brew upgrade rbenv
```

###
ここから、Rubyをインストールしていきます。
まず、インストールできるRubyのバージョンを確認します。
確認後、インストールしたいバージョンを指定して、インストールします。
インストール完了したら、インストールできているか確認し、バージョンを切り替えます。

```
# インストール可能なrubyのバージョンを確認する
$ rbenv install -l

# バージョンを指定してrubyをインストールする
$ rbenv install 3.0.2

# インストールが完了したら、バージョンを確認する
$ rbenv versions
  system
* 2.6.6 (set by /Users/username/.rbenv/version)
  3.0.2

# Rubyのバージョンを切り替える
$ rbenv global 3.0.2

# 再度バージョンを確認する
$ rbenv versions    
  system
  2.6.6
* 3.0.2 (set by /Users/username/.rbenv/version)

$ ruby -v
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin20]
$ rbenv version
3.0.2 (set by /Users/username/.rbenv/version)

```

バージョンの切り替えは以上になります。

バージョンアップ後、railで新しいアプリを作成しようとすると、エラーが発生しました。

```
$ rails _6.1.4_ new appname
rbenv: rails: command not found

The `rails' command exists in these Ruby versions:
  2.6.6
```

どうやら、新しくインストールした`ruby:3.0.2`にはrailsがインストールされていないことが原因のようです。


```
# rbenv(3.0.2)の中身を確認する
$ cd ~/.rbenv/versions/3.0.2/bin
$ ls
bundle          erb             irb             rake            rdoc            ruby
bundler         gem             racc            rbs             ri              typeprof

#railsが含まれていないことが確認できた
```

原因を確認できたので、railsをインストールしていく。
Railsチュートリアルの方法に沿ってインストールする。

```
$ cd
$ echo "gem: --no-document" >> ~/.gemrc
$ gem install rails -v 6.1.4
Fetching rack-2.2.3.gem
 ・
 ・
 ・
37 gems installed
```

インストール完了後、再び`rails _6.1.4_ new appname`を実施すると、実行できました。

以上です。
git rebase -i でコミットをまとめているだけ(のつもり)なのにコンフリクトに遭遇した

知ってる人からしたら当たり前の挙動なのかもしれないですが、初めて遭遇したので。

## 起きたこと

いつものように`git rebase -i main`みたいにブランチの元となるコミットから伸びたコミットをまとめようとしていたら、コンフリクトが発生しました。
もともとmainから伸ばしたブランチで`git rebase -i main`ではコンフリクトの発生はないと思っていたので混乱しました。

## 原因

コミットをまとめようとしていたブランチで過去に`merge`でコンフリクト解消を行なっていたのが原因でした。
一度`merge`でコンフリクト解消していても`rebase`で再度コミットをまとめようとすると同じコンフリクト解消をやる必要があるみたいです。私はrebase派なため、mergeでのコンフリクト解消はやらないようにしていたのでこれまで遭遇することがなかったのだと思います。

ちなみに、上記のmergeでのコンフリクト解消は他の方がやっていた作業です。チーム内ルールでmergeでもrebaseでもOKだったのでmergeで実施していたみたいですね。



## 状況説明

その時のgit graphを簡易的に再現したのが↓のような感じです。
コミットハッシュのところは便宜上名前をつけてます。

```zsh
*   commit merge-commit1 (HEAD -> feature/base)
|\  Merge: base-commit1 dev-commit2
| | 
| |
| * commit dev-commit2 (dev-branch-1)
| | 
| |
| * commit dev-commit1
| | 
| |
* | commit base-commit1
|/  
|
* commit 775e09 (main)

```

上記の状態になるまでの作業順で言うと以下のような感じです。

1. `feature/base`を`main`から作成
1. そこから`dev-branch-1`を作成し、dev-commit1、2を作成
1. `dev-branch-1`のコミットが`feature/base`にマージされる前に`feature/base`でbase-commit1が作成される
1. `feature/base`ブランチで`git merge dev-branch-1`してコンフリクトを解消しつつ`feature/base`に取り込み

この後、冒頭の通り`feature/base`で`git rebase -i main`するとコンフリクトが起きます。内容は4と全く同じなので同じ作業を再度行う必要があるということになります。


## 結論

rebaseする予定のあるブランチへのマージはrebaseでコンフリクト解消を行ってからやること


で、いいのかな？？
ほんとに再度コンフリクト解消する必要あるのか疑問なのですが、詳しい人いたら教えてください...
【Django】パスワードのハッシュ化

settings.py の `PASSWORD_HASHERS` 変数を追加する

Djangoで使えるhasherは以下のURLを参照。
https://docs.djangoproject.com/ja/3.1/topics/auth/passwords/#included-hashers

そこからいくつか選んで以下のようにsettings.pyに追加する。今回はBcrypt, Argon2, PBKDF2にした例です。

```python
PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
]
```
Keyboardを出した状態でNavigator.Popすると一瞬Render Flex Overflowする問題【Flutter】


###状況
FormなどでKeyboardが表示されている状態でNavigotor.Popすると一瞬Render Flex Overflowしてしまう
before Screen < Pop < now Screen

###原因
before ScreenのchildがColumnだからだそうな...

###解決策
before ScreenのchildをListViewにする

###最後に
さっぱりわからず沼にハマりました、前の画面に原因があるとは...
原因もふわっとしかわかっていないので、再現性があるかも怪しい...
なんでこうなるのか分かる方がいれば教えていただきたいです m(_ _)m

###参考にしたリンク
https://stackoverflow.com/questions/57146086/executing-navigator-pop-when-key-pad-is-visible-results-in-render-flex-error
pythonの中にshellコマンドを実行できるやつ(subprocess)

今回はpythonの中にshellコマンドを実行できるライブラリと、それのよく使うやり方。またそれを使ってできる技など、丁寧に紹介します。

<h1>subprocess</h1>
それはsubprocessというライブラリです。一般的に下のようにインポートします

```php
# ライブラリのインポート
import subprocess as sp
sp.call("ここにshellのコマンド",shell=True)
```

<h1>実行例</h1>
```php
// 今のsubprocessディレクトリにはtestフォルダとsub.pyが入っている
subprocess % ls
#     sub.py	  test/

//sub.pyの中身
subprocess % cat sub.py
#　　import subprocess as sp
#　　sp.call("midir test2",shell=True)

// sub.py 実行
subprocess % python sub.py

// 確認
subprocess % ls
#   sub.py	test/	test2/

## test2フォルダが作られている
```

<h1>subprocessの応用</h1>
google　corabやpipyに登録するpythonファイルなど、ローカルpcと繋げない時に用いる。 また、データだけ撮ってきて、最後にそのファイルを消したい時も使える。

この気象省の2020年の気象データをsubprocessからダウンロード
http://www.data.jma.go.jp/obd/stats/etrn/index.php


```php
subprocess % cat sub2.py 
import subprocess as sp
sp.call("wget http://www.data.jma.go.jp/obd/stats/etrn/index.php?prec_no=&block_no=&year=2020",shell=True)

// python実行 wgetが実行された
subprocess % python sub2.py
#--2021-11-13 13:05:47--  http://www.data.jma.go.jp/obd/stats/etrn/index.php?prec_no=
#www.data.jma.go.jp (www.data.jma.go.jp) をDNSに問いあわせています... 104.71.166.219
#www.data.jma.go.jp (www.data.jma.go.jp)|104.71.166.219|:80 に接続しています... 接続しました。
#HTTP による接続要求を送信しました、応答を待っています... 200 OK
#長さ: 23860 (23K) [text/html]
#`index.php?prec_no=' に保存中

#index.php?prec_no=  100%[===================>]  23.30K   123KB/s 時間 0.2s     

#2021-11-13 13:05:49 (123 KB/s) - `index.php?prec_no=' へ保存完了 [23860/23860]

```

ファイル削除

```php
// 確認
subprocess % ls
#  index.php?prec_no=	sub2.py			test/
#  sub.py			sub3.py			test2/

subprocess % cat sub3.py
import subprocess as sp
sp.call("rm index.php?prec_no=",shell=True)

// 
subprocess % python sub3.py
subprocess % ls
#  sub2.py         test/
#  sub.py          sub3.py         test2/
```
 
<h1>まとめ</h1>

subprocessを用いればpythonファイル一つでデータをダウンロードし、データを整形し、結果を出力してデータを削除するところまでを行える
tar.gzファイルからの目的のファイルだけ抽出する

大量のファイルを含む書庫ファイルtar.gzから特定のファイルを抜き出したい時、ファイルを全て一度に展開するとファイル数も多く時間もかかりディスクの容量も圧迫することがある。
そこで、tar.gzファイルからの特定のファイルだけ抜き出す方法を紹介する。

###**■tar.gzファイルの確認**###
```
# ls
test.tar.gz
```

###**■抜き出したいファイルの存在確認**###
```
# tar tf test.tar.gz |grep TestFile

TestFile001.log
```
※目的のファイルが確認できた。

###**■ファイルの抜き出し**###
```
# tar zxf test.tar.gz TestFile001.log
```

###**■抜き出したファイルの確認**###

```
# ls

TestFile001.log  test.tar.gz
```

ファイルが抽出された。
以上になります。
PHPSTORMを職場の開発サーバと同期させる手順

既に沢山の記事はあるけどやり方がばらけていたのでまとめました。

## PHPSTORMで接続先のサーバーを設定

1.ファイル→設定、ではなく、トップメニューのツールをクリックする
2.デプロイ→構成を選ぶ。この時はまだサーバーは一つも用意されていない
3.左ペインの＋ボタンをクリック、接続方法は職場に合わせる。ここではSFTPを選ぶ
4.サーバー命名を要求されるので適当な名前を付ける
5.SSH構成を聞かれるのでここでは…ボタンをクリックしてホスト名、ユーザー名、パスワードを入れて接続テストをクリックし、問題なければ適用をクリックして、OKボタンをクリックしてデプロイ画面に戻る
6.デプロイ画面の左ペインに先ほど設定したサーバー名があるのでこれを「右クリック」で「デフォルトとして使用」を選択。
**これをやらないと同期や、ローカルで変更したファイルの開発サーバへの自動アップロードが行われないので注意。**
7.ファイル→設定→デプロイを選ぶ。そうすると既に設定したサーバが選ばれているのでマッピングを選び、ローカルパスを自分の作業したいローカルフォルダに設定した後、デプロイパスを選び、開発サーバのルートパスを選ぶ、ここでは**/home/fu3nori/laravel_thread_bbs**とした。
8.ファイル→設定→デプロイ→オプションを選び、**変更されたファイルのデフォルトサーバへの自動アップロード**を常時に設定し、適用ボタンを押す
9.メイン画面の左ペインにあるプロジェクトフォルダをクリックし、ツール→デプロイ→ダウンロードを選択

これで職場の開発サーバのコードがローカル開発環境にダウンロードされます。
Linux テキスト処理（行単位の取得と削除）

# 行単位の取得と削除

## 先頭の N 行を取得/削除する

```bash
# 先頭の N 行を取得する (N=3)
$ seq 10 | head -n 3
$ seq 10 | sed -n '1,3p'
$ seq 10 | awk 'NR <= 3'
```

```bash
# 先頭の N 行を削除する (N=3)
$ seq 10 | tail -n +4
$ seq 10 | sed '1,3d'
$ seq 10 | awk 'NR >= 3'
```

## 末尾の N 行を取得/削除する

```bash
# 末尾の N 行を取得する (N=3)
$ seq 10 | tail -n 3
```

```bash
# 末尾の N 行を削除する (N=3)
$ seq 10 | head -n -3
```

## N-M 行を取得/削除する

```bash
# N-M 行を取得する (N=4, M=6)
$ seq 10 | tail -n +4 | head -n 3
$ seq 10 | sed -n '4,6p'
$ seq 10 | awk '4 <= NR && NR <= 6'
```

```bash
# N-M 行を削除する (N=4, M=6)
$ seq 10 | sed '4,6d'
$ seq 10 | awk 'NR < 4 || 6 < NR' 
```

## 先頭の N 行と末尾の M 行を取得/削除する

```bash
# 先頭の N 行と末尾の M 行を取得する (N=3, M=2)
$ seq 10 | nl -s: | tee -p >(head -n 3) >(tail -n 2) > /dev/null | sort -un | cut -d: -f2-
$ seq 10 | nl -s: | pee 'head -n 3' 'tail -n 2' | sort -un | cut -d: -f2-
```

関連: [ファイルの先頭 N 行と末尾 M 行を取り出すワンライナー](https://qiita.com/suzuki-kei/items/c136b27dd0db6b812124)

```bash
# 先頭の N 行と末尾の M 行を削除する (N=3, M=2)
$ seq 10 | tail -n +4 | head -n -2
```

## 正規表現にマッチする行を取得/削除する

```bash
# 末尾が '3' である行を取得する
$ seq 20 | grep '3$'
$ seq 20 | sed -n '/3$/p'
$ seq 20 | awk '/3$/'
```

```bash
# 末尾が '3' である行を削除する
$ seq 20 | grep -v '3$'
$ seq 20 | sed '/3$/d'
$ seq 20 | awk '!/3$/'
```

## 行番号と正規表現で指定する範囲を取得/削除する

```bash
# 3 行目から /06/ にマッチする行までを取得する
$ seq -w 10 | sed -n '3,/06/p'

# /03/ にマッチする行から 7 行目までを取得する
$ seq -w 10 | sed -n '/03/,7p'

# /03/ にマッチする行から /06/ にマッチする行までを取得する
$ seq -w 10 | sed -n '/03/,/06/p'
```

```bash
# 3 行目から /06/ にマッチする行までを削除する
$ seq -w 10 | sed '3,/06/d'

# /03/ にマッチする行から 7 行目までを削除する
$ seq -w 10 | sed '/03/,7d'

# /03/ にマッチする行から /06/ にマッチする行までを削除する
$ seq -w 10 | sed '/03/,/06/d'
```

## 偶数行/奇数行を取得する

```bash
# 偶数行を取得する
$ seq 10 | sed -n '0~2p'
$ seq 10 | awk 'NR % 2 == 0'
```

```bash
# 奇数行を取得する
$ seq 10 | sed -n '1~2p'
$ seq 10 | awk 'NR % 2 == 1'
```

## N 行おきに取得/削除する

```bash
# 3 行おきに取得する
$ seq 10 | sed -n '1~3p'
$ seq 10 | awk 'NR % 3 == 1'
```

```bash
# 3 行おきに削除する
$ seq 10 | sed '1~3d'
$ seq 10 | awk 'NR % 3 != 1'
```
GitHub ActionsでWorkFlowやJobを連鎖させる方法

## はじめに

この記事は、GitHub Actionsでjobやworkflow同士を連鎖させる方法を記録、共有するためのものです。

### 想定する環境

この記事は、2021/11/12時点でのGitHubを前提に書かれています。GitHubが更新されると、記事の内容をそのまま適用できないことがあります。ご注意ください。

### 想定する読者

- gitを使ったことがある
- GitHubのアカウントを持っている
- GitHub Actionsを使ったことがある

この記事ではgitの使い方やGitHubの導入方法などは取り扱いません。ご承知ください。

## GitHub Actionsとは

[GitHub Actions](https://github.co.jp/features/actions)とは、GitHubが提供するCI/CD環境です。リポジトリへのPushやPull requestの作成、Issueへのコメントなどさまざまなイベントを引き金としてコンテナーが立ち上がり、指定された命令を処理します。

利用ケースとして

- Pull requestが作成されたら、テストを実行し合否を判定する
- デフォルトブランチが更新されたら、APIドキュメントを生成しGitHub Pagesで公開する
- Issueが作成されたら、内容にしたがって特定のラベルをつける
- 一定期間Issueに活動がなかったら、IssueをCloseする

などがあります。

### ワークフロー

GitHub Actionsのアクションは、以下のような粒度で管理されています。([公式ドキュメント](https://docs.github.com/ja/actions/learn-github-actions/understanding-github-actions#))

##### ステップ

アクションの最小単位です。シェルコマンド1行に相当します。

##### ジョブ
複数のステップで構成された処理です。ジョブ同士は並列処理されます。

##### ワークフロー
複数のジョブで構成され、イベントを引き金として実行される処理の塊です。1つのワークフローは1つのYAMLファイルに記述されます。


ワークフローファイルは`.github/workflows`というディレクトリに保存され、このファイル自体もgitでバージョン管理されます。

### ワークフローファイルの肥大化

複雑なワークフローを構成すると、ワークフローファイルが肥大化して管理が難しくなっていきます。そのためジョブを分割したり、相互に関連しないジョブを別々のワークフローに切り分けなければいけません。

## 処理の連鎖

GitHub Actionsには、ワークフローやジョブの分割のための連鎖機能があります。この連鎖機能を使えば「テストが成功し、デフォルトブランチにマージされたら、APIドキュメントを更新してGitHub Pagesで公開し、npmでパッケージを公開する」といった複雑な処理を管理しやすくなります。

GitHub Actionsでは、依存ジョブとworkflow_runトリガーの2種類の連鎖機能が提供されています。

### ジョブの連鎖 : 依存ジョブ

GitHub Actionsのジョブはデフォルトでは並列で実行されます。[依存ジョブ](https://docs.github.com/ja/actions/learn-github-actions/managing-complex-workflows#creating-dependent-jobs)にneedsフィールドを設定すると、指定した他ジョブの完了を待ちます。

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: ./build_server.sh
  test:
    needs: build
    ^^^^^^^^^^^^ ここが依存ジョブの設定
    runs-on: ubuntu-latest
    steps:
      - run: ./test_server.sh
```

上記の例ではbuildジョブが成功したら、testジョブが実行されます。buildジョブが失敗したらtestジョブは実行されずに中断されます。

依存ジョブは並列実行されないため、ワークフロー全体の処理時間は長くなります。後続の処理が中断される利点と、処理時間が長くなる欠点を比べて設定してください。

### ワークフローの連鎖 : workflow_runトリガー

[workflow_runトリガー](https://docs.github.com/ja/actions/learn-github-actions/events-that-trigger-workflows#workflow_run)を使うと、前ワークフローの完了を引き金に次のワークフローが開始されます。

```yaml
on:
  workflow_run:
    workflows: ["Run Tests"]
    branches: [main]
    types:
      - completed
```

上記の例では`Run Tests`という名前のワークフローが、mainブランチで完了したときに処理が始まります。

なお、workflow_runトリガー単体では、前ワークフローの処理が成功したか失敗したかをチェックできません。前ワークフローが成功したか否かを確認するには[コンテキスト](https://docs.github.com/ja/actions/learn-github-actions/contexts#context-availability)`github.event.workflow_run`を確認します。このコンテキストには前ワークフローの情報が格納されています。

```yaml
on:
  workflow_run:
    workflows: ["Build"]
    types: [completed]

jobs:
  on-success:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      ...
```

たとえば`github.event.workflow_run.conclusion`には前ワークフローの成否が格納されています。

処理を分割することで、再利用しやすく可読性の高いワークフローを作れます。お手元の環境で複雑すぎるワークフローがある場合、ぜひ分割を検討してみてください。
以上、ありがとうございました。
AmplifyのSlack通知プラグインが便利すぎた件

[AWS Amplify Advent Calendar 2021](https://qiita.com/advent-calendar/2021/amplify)の16日目の記事です。

Amplifyで開発しているときビルドが終わったらすぐに動作確認したいことがあります。
Amplifyの通知はメールがありますが、あまりメーラーを見てなくてしばらく気づかなかたり、
Slack通知を自前で用意するのも面倒です。

Amplifyでビルドの開始と終了を通知していくれるプラグインが便利だったので紹介

https://github.com/fossamagna/amplify-category-console-notification

Amplifyのプラグインとして提供されているのでインストールも簡単です。

インストール方法(Amplify CLIインストール済み状態）

```
# NPMパッケージをインストール
npm install -g amplify-category-console-notification
# プラグインを有効化
amplify plugin scan
# プラグイン追加
$ amplify console-notification add
Using service: AmplifyConsoleNotification, provided by: awscloudformation
? Input function name in order to send message to Slack. Sender ← ファンクション名をを指定
? Input Web hook URL of Slack.
https://hooks.slack.com/services/T000/B000/XXXX　← SlackのWebフックURLを指定
Successfully added resource Sender locally
```
ビルドの開始と終了時にSlack通知が来るので便利です。
<img width="400" alt="スクリーンショット" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20217/92c5d810-4c67-2236-2547-b5e205f40eb6.png">

追伸
AmplifyのAdmin UIがAmplify Studioになり、Figma連携されるようになったので、
いつか記事を書こうと思います。

https://aws.amazon.com/jp/blogs/news/aws-amplify-studio-figma-to-fullstack-react-app-with-minimal-programming/

https://docs.amplify.aws/console/tutorial/buildui/
tarコマンドを使ったファイルコピー

ファイルサーバの刷新などでデータ移行が発生して、膨大な数のディレクトリやファイルをコピーする機会がある。その時、cpコマンドやrsyncコマンドで使用してうまくコピーできないことがある。
ここで、このtarコマンドを使用したディレクトリおよびファイルコピーの手法が
過去に難を乗り切ったことが少なくとも数回はあったため、お役に立てればと思い紹介したい。

###**■ディレクトリ構成**###
**旧サーバー**	: /data1     ※元データがあるところ  
**新サーバー**	: /stroge1　 ※移行先

###**■ファイルの確認(元データ)**###

コマンド操作はrootで新サーバから実行する。
新サーバから旧サーバの/data1には事前にNFSなどでマウントしておく。

***※ログイン認証情報は新旧のサーバで同一ものをしていると仮定。***
***※NFSなどでマウント時に、新サーバのrootでアクセスが出来るようにしておく。***

####(1) ディレクトリの移動 
元データのあるディレクトリdata1に移動する。

```
# cd /data1 		
```

####(2) ファイルの確認
treeコマンドでファイル・ディレクトリ構造を確認する。

```
# tree -F 

.
├── subdir/
│   └── test03.txt
├── test01.txt
└── test02.txt
```

lsコマンドでファイルの所有権アクセス権を確認する。

```
# ls -l

drwxr-xr-x 2 root      root      4096 11月 13 02:52 subdir
-rw-r--r-- 1 ishimatsu ishimatsu    7 11月 13 02:50 test01.txt
-rw-r--r-- 1 ishimatsu ishimatsu    7 11月 13 02:51 test02.txt


# ls -l subdir/

-rw-r--r-- 1 ishimatsu ishimatsu 7 11月 13 02:52 test03.txt
```


###**■ファイルコピーの実行**###
```
# tar cvf - . |(cd /storage1;tar xvf -) 

./
./subdir/
./subdir/test03.txt
./test01.txt
./test02.txt
./
./subdir/
./subdir/test03.txt
./test01.txt
./test02.txt
```
コピーが完了。

###**■ファイルの確認(移行先)**
####(1) ディレクトリの移動 
移行したデータのあるディレクトリstorage1に移動。

```
# cd /storage1
```

####(2) ファイルの確認
treeコマンドでファイル・ディレクトリ構造を確認する。

```
# tree -F
.
├── subdir/
│   └── test03.txt
├── test01.txt
└── test02.txt
```

lsコマンドでファイルの所有権アクセス権を確認する。

```
#  ls -l

drwxr-xr-x 2 root      root      4096 11月 13 02:52 subdir
-rw-r--r-- 1 ishimatsu ishimatsu    7 11月 13 02:50 test01.txt
-rw-r--r-- 1 ishimatsu ishimatsu    7 11月 13 02:51 test02.txt

ls -l subdir/
-rw-r--r-- 1 ishimatsu ishimatsu 7 11月 13 02:52 test03.txt
```

ファイルが移行されていることが確認できた。
以上になります。
[A Tour of Go] Exercise: Mapsの自分の解答

```go
package main

import (
	"golang.org/x/tour/wc"
)

func WordCount(s string) map[string]int {
	words := make(map[string]int)
	var wordstorage string
	for i:=0; i < len(s); i++ {
		if s[i:i+1] == " " {
			words[wordstorage] += 1
			wordstorage = ""
		} else {
			wordstorage += s[i:i+1]
		}
	}
	words[wordstorage] += 1
	return words
}

func main() {
	wc.Test(WordCount)
}
```
セラピストからエンジニアになってみて

約1年ほど前にセラピストからエンジニアに転職した経験談を本日は書いていきたいと思います！

## 前職の内容

美容専門学校を卒業し、卒業後、美容師として都内で働いていました。
美容師として働いていた期間は1年ほどで、そこからセラピストに転職しました。

セラピストといっても施術の内容は美容師免許がないとできないものなので、新卒から一貫して美容系の仕事をしていた感じです。
主ヘッドスパやファイシャルエステの施術をメインに担当していました！

セラピストは3年半ほど行っていたので、美容師と合わせて約4年半の社会人経験をへて、エンジニア転職を決意しました！

異業種からエンジニアになってみて、実際にどうなのか？
働き方は変わったのか？生活は変わったのか？？
そんな気になる内容を今回は書いていこうと思います！！！


## エンジニアになろうと思ったきっかけ

なぜエンジニアになろと思ったかと言うと、正直言うとコロナウイルスの影響が大きいです。
コロナにより店は休業し、給料ダウン。

当時、世田谷区に一人暮らししていた自分としてはかなり生活的に苦しくなった記憶が残っています。

そこから時間も場所にもとらわれず、自分のスキルのつく仕事がしたいと思いはじめました！
偶然にもセラピストをしている時に、出張で都内のIT企業に行く機会が多かった為、真っ先にエンジニアという職業が思いつきました(この辺りまでは軽い気持ちです)

実際に自分なりに調べてみると、"エンジニアは給料が高い", "リモートワークができる", "私服でおしゃれなオフィスで働ける"など心を踊らせる記事がたくさん出てきたのを覚えています笑
当時は、エンジニア系のインフルエンサーも全盛期の頃だった為、このような情報がかなり多かったのだと思います笑


まー実際はそんなに甘くないことはわかっていましたが、今までロクに勉強してきたこともなかったので、コロナで時間もあるし、ここでしっかり勉強すれば何か変われるかも、、、、と自分にも期待を込めて勉強を始めることにしました。


## エンジニア転職までにやったこと

結果から言うと現在は都内にある10数名規模の自社開発企業でエンジニアとして働いています。

勉強開始から内定までの期間: 半年
働きながらですが平日4時間、休日10時間はやっていたと思います。

#### 勉強内容

- progate
- Railsチュートリアル 
- プログラミングスクールでの学習(ポテパンキャンプ)
- その他スクールからおすすめされた書籍(5冊くらい)
- ポートフォリオ作成
- 面接練習(10時間くらい)

書類審査はかなり落ちましたが、面接までいった企業は全て内定をもらい、確か5社くらいは内定もらった記憶があります。
そこから現在の企業に決めて働いています！

ちなみに現在の職場の技術スタックはこんな感じです。
未経験からにしては中々の経験をつめていると思っています！

フロントエンド: Nuxt.js, Next.js(主にNuxt.jsがメインです), TypeScript
バックエンド: Node.js(TypeScript), express
インフラ: AWS
CICD: Docker, circleCI
その他: slack, backlog, swagger


## エンジニアとして働いてみて

正直言うと最高です。
現在の働き方は

- 週４リモートワーク
- フルフレックス
- 服装自由
- おしゃれなオフィス

って感じで正直想像していたエンジニアの世界通りです。
給料に関しても転職時は前職と同じくらいか少し少ない感じでしたが、1年たった今、入社時より給料は月10万円ほど上がり、生活にもかなりゆとりが出ています。
当時、世田谷区に住んでいましたが、今後も出社は週1日程度なので、少し郊外に引っ越して家賃も安く広い家にも引っ越しができました♪

仕事では主に新規開発案件のフロントエンドを担当させてもらっており、自分のスキルの無さと戦う日々です笑
個人的な感想だと入社当時より、1年ほどたった今の方が、タスクの難易度が高いので、全然しんどいです笑
毎日勉強しています笑

そして、10数名規模の会社なので、やることは盛り沢山で、メインはフロントエンド開発ですが、他にもワイヤーフレーム作成、デザインディレクション、場合によってはデザイン作成、外注先のディレクション、明細処理等、えっ？何屋さん？？ってくらい色々やってます笑

日々やることは多く大変ですが、達成感もすごく、日々楽しくやれています！

転職する前までは、平日は仕事で割り切って休日楽しむ！！
みたいな生活だったのですが、
現在は毎日仕事！！毎日遊び！！みたいな感覚になりました笑

なので転職前から比べると充実感は半端なく向上しました。


## 今後どんなエンジニアを目指したいか

現在フロント周りに特化していて、正直かなり楽しいので、フロントエンドのキャリアを伸ばしていきたいなと思っています。
ただ働いていて思うのが、バックエンドの知識もないとお話にならないので、ある程度フルスタックに触れるが、フロントエンドが得意領域でメイン！
くらいの立ち位置になりたいと思っています。

将来的には英語も勉強して、オフショアとのブリッジに立ってみたい！！みたいなことも考えていたりします。

無理せず楽しく、エンジニアライフを今後も楽しんでいきたいと思っています。

## 最後に

読み返していると、エンジニア最高！転職楽チン！！みたいに見えますが、これは本当のことですが一部の頑張った人に与えられる特権だと思っています。
正直、自分も勉強に関しては当時周りで勉強していた誰よりもやっていた自身があります。

軽い気持ちでエンジニアを目指すと、想像と違い痛い目をみることもあると思いますが、
人生崖っぷち、一発逆転したい、自由を手に入れたい、そしてやり切る自信がある人は是非エンジニアを目指すのをお勧めします！！！！！(注意: やり切れないと詰む可能性もあります)
【JavaScript】最大和問題を動的計画法で解く


https://qiita.com/drken/items/a5e6fe22863b7992efdb

こちらの記事を参考に最大和問題を勉強していくなかで，JavaScriptでコードを再現してみたメモ．

```JavaScript:
const main = (numList) => {
    const length = numList.length
    let dp = [...Array(length + 10)].map((_) => 0);

    for (let i = 0; i < length; i++) {
        dp[i + 1] = Math.max(dp[i], dp[i] + numList[i]);
    }

    return dp[length];
}

console.log(main([7, -6, -9])) // 7
```
2進数と10進数

## はじめに：なぜ書くか
- 現在少しでもIT知識を身に着けて業務理解を深めるためにITパスポートの学習をしている
- 業務で学んだテクノロジー関連はこのアカウントに書いていたのでついでにITパスポートで学んだこともここに書こうと思った
- 思いついた要素からどんどん書いているので順番とかぐちゃぐちゃだがご了承

## 2進数とは
- 「0」と「1」の組み合わせで表現される数字のこと
- コンピューターの世界ではこれが標準
- それぞれの桁の数字が「2」になると繰り上がる

## 2進数から10進数への求め方
### 値が「1」の桁だけ「桁の値×重み」を計算し、それを合計する
- 「重み」：2進数のn桁目の重み = 2のn-1乗
	- 例：2進数4桁目の重み = 2の4-1乗、つまり2の3乗になる
- 例：10.011を10進数で表現する
	- (2の1乗) + (2の0乗) + (2の0乗) + (2の-2乗) + (2の-3乗)
	- = (2) + (0) + (0) + (2×4/1) + (2×8/1)
	- = 2 + 0.5 + 0.125
	- = 2.375

## 10進数から2進数への求め方
### 10進数の数値を2で割って余りを求め、その答えを更に2で割って余りを求める計算を繰り返し、最後に余りを後ろから並べる
- 例：18を2進数で表現する
	- 18 ÷ 2 = 9余り0
	- 9 ÷ 2 = 4余り1
	- 4 ÷ 2 = 2余り0
	- 2 ÷ 2 = 1余り0
	- 1 ÷ 2 = 0余り1
	- 余りを後ろから並べると「10010」になる


## まとめ：これが分かるとどんな役に立つ？
- コンピューターの内部動作を理解することに役立つ
- ちなみに、これを知っていると片手で31まで、両手で1023まで数えることが出来るらしい…
- そういえばスマブラの櫻井さんもそんなことをやっていたような…
	- [6分くらいから](https://www.youtube.com/watch?v=xAssd5p6LZM)
【バグ速報】Flutter Web で Riverpod が動かない時の回避策

Flutterアプリ開発者の間で人気の **Riverpod** というパッケージが **1.0.0** になって喜んでいたら
Debugモードで Chorme で実行した時に、この状態から進まなくなりました。

![stuck.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/982650/efdcac6b-5add-c35a-bcf3-9ad326eb9be7.png)

Riverpodの開発者によれば、これは Dart のバグであって、パッケージ側の不具合ではないらしいです。

まさに今 issue が進んでいます。そのため、すぐに修正が入ると思いますが、それまでの間の回避策を共有しておきます。
https://github.com/dart-lang/sdk/issues/47645

# 一時的な回避策

- **pubspec.yaml** で指定するパッケージのバージョンを開発版にします
- **flutter_riverpod** , **riverpod** の両方ともを ```1.0.0-dev.10``` にしてください

```pubspec.yaml
dependencies:
  flutter_riverpod: 1.0.0-dev.10
  riverpod: 1.0.0-dev.10
```

本質的な原因を知りたければ 1.0.0を使った時に、詳細なログを確認できるモードで実行するとエラー内容が見えるらしいですが、私には難しくてよくわかりませんでした。
素直に解決を待ちたいと思います。
Node.jsで学ぶビットコイン・ブロックチェーン

# この資料について

KOF2021の資料になります

https://www.k-of.jp/2021/session/node-js_bitcoin_blockchain/

# 自己紹介

小渕 周(こぶち しゅう)

システムエンジニア、暗号資産事業者向けウォレットベンダーを経て、現在、暗号資産交換業者のブロックチェーンエンジニア。

Twitter:
https://twitter.com/shu_kob

Facebook:
https://www.facebook.com/shu.kobuchi

# コミュニティの紹介

ビットコインをはじめとする暗号通貨（暗号資産・仮想通貨）、ブロックチェーンの技術勉強会

月1〜2回、平日の19:30〜オンライン勉強会を開催中！

お気軽にご参加ください

https://cryptocurrency.connpass.com/

# 参考資料

# ビットコインとは

過去のKOF・OSCで発表した資料をご覧ください

## 初心者のためのビットコイン送金体験

### 動画

https://youtu.be/84wUlXe_f8A

### 資料

https://speakerdeck.com/shukob/burotukutienchu-xin-zhe-falsetamefalsebitutokoinsong-jin-ti-yan

## ビットコイン・ブロックチェーン入門(OSC)

### 動画

https://youtu.be/K0TZcw8yLvw

### 資料

https://speakerdeck.com/shukob/bitutokoinburotukutienru-men-a942d199-a1e6-41dc-873c-7649376f120b

# 今回使う資料

https://qiita.com/shu-kob/items/380e26eaee025edd6fcb
【React】そのReact.memoはちゃんと機能していますか？

#はじめに
React.memo、useCallback、useMemoを利用したコンポーネント、関数、値のメモ化は、実装コストが少ない分「とりあえず記述しとけ！」みたいなノリで書きがちな初心者(自分)が多そうな気がします。

しかし、意味のないメモ化はただの負債でしかないので、ちゃんと理解した上で記述できるよう、おさえておきたい内容を初心者向けに記事にしました。

React.memo、useCallback、useMemoってなんや！？って方は、以前書いた記事を参考にしていただければと思います。

https://qiita.com/suzuki0430/items/445ac1b38fa7ef383864

https://qiita.com/suzuki0430/items/8c242222c7903aa2a52d

#JavaScriptのデータ型
まずおさえておきたいのは、JavaScriptのデータ型についてです。

JavaScriptのデータ型は基本型と参照型に分類されます。

- 基本型：number, string, boolean, synbol, null/undefined
- 参照型：array, object, function

これらは値を変数に格納する方法が異なります。
基本型の変数には値そのものが直接格納されますが、**参照型の変数には値を格納しているメモリ上のアドレス(ポインタ、参照値)が格納されます**。

#Reactのレンダリング
"Add a Boxer"で`React.memo`でメモ化した`Boxer`コンポーネントを追加するケースを考えます。
![スクリーンショット 2021-11-13 12.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/95b39995-1c6e-549c-d614-8df6d3e88d9d.png)

```jsx:App.jsx
const Boxer = React.memo(({ name, punch }) => {
  console.log(`rendering ${name}`);
  return <p onClick={() => punch(name)}>{name}</p>;
});

const App = () => {
  const [boxers, setBoxers] = useState(['Ippo', 'Sendo', 'Mashiba']);

  const punch = (name) => console.log(`${name} has punched`);

  return (
    <>
      {boxers.map((name, i) => (
        <Boxer key={i} name={name} punch={punch} />
      ))}

      <button onClick={() => setBoxers([...boxers, prompt('Name a boxer')])}>
        Add a Boxer
      </button>
    </>
  );
};
```
コードを一見すると、`Boxer`を追加したとき、既存コンポーネントのPropsである`name`と`punch`に変化はなさそうです。
メモ化が成功して、既存コンポーネントの再レンダリングは起こらないようにみえます。

しかし、実はこれ、**再レンダリングが起こります**。
![スクリーンショット 2021-11-13 11.58.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/60544bf9-52eb-ea07-5cbc-157b1a47fd91.png)

この理由を考えるときに、前項の「JavaScriptのデータ型」を理解している必要があります。

`Boxer`のPropsである`punch`には関数が設定されています。

**関数のデータ型は参照型であり、描画のたびに異なるインスタンスが生成されます(格納されるメモリのアドレスが変わります)。**
**結果、`punch`の値が変化したとみなされて、`Boxer`コンポーネントが再描画されることになるというわけです。**

それでは、関数`punch`の値が変化したとみなされないようにはどうすればいいのか...
ここで使用するのが`useCallback`です。

`punch()`を`useCallback`でメモ化してみます。

```js
const punch = useCallback((name) => console.log(`${name} has punched`), []);
```

再度`Boxer`を追加してみると、今度は既存コンポーネントの再レンダリングが行われなくなりました。
![スクリーンショット 2021-11-13 12.08.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569054/70d23f08-ae9e-3865-7b8a-7185a5913540.png)

#まとめ
**`React.memo`を使うときは、ラップするコンポーネントのPropsのデータ型に気をつけて、関数のような参照型が含まれる場合は必ず`useCallback`で合わせてメモ化しましょう！**

#参考資料

JavaScript本格入門　山田祥寛　著

オブジェクト指向でなぜつくるのか　平澤章　著

Reactハンズオンラーニング　Alex Banks, Eve Porcello　著
[WIP] 公式ドキュメントから引用したGit用語集

# 公式ドキュメントから引用したGit用語集
- **git push -u origin HEAD**
    - **origin**
        -  "origin — that is the default name Git gives to the server you cloned from"
        -  [意訳] originとは、クローン元であるサーバーのことを指します。
        -  [で結局?] **originとは、クローン元であるサーバーのこと**
        -  [参考: Showing Your Remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)
    -  **HEAD**
        -  "HEAD is the pointer to the current branch reference, which is in turn a pointer to the last commit made on that branch. "
        -  [意訳] HEADとは現在のブランチ上で行われるコミットのうち、最新のコミットのこと。
        -  [で結局?] **HEADとは、現在のブランチ上で行われるコミットのうち、最新のコミットのこと。**
        -  [参考: The HEAD](https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified)
    -  **-u**
        -  "If you already have a local branch and want to set it to a remote branch you just pulled down, or want to change the upstream branch you’re tracking, you can use the -u or --set-upstream-to option to git branch to explicitly set it at any time."
        -  [意訳] ローカルブランチをリモートに反映したい時、あるいは追跡している上流ブランチを変更したい時や明示的に上流ブランチを指定したいときはいつでも、-uや--set-upstreamオプションを使用することができる。
        -  [で結局?] **-uとは、上流ブランチを指定するオプションのこと。**
        -  [参考: Tracking Branches](https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches)
    -  **upstream-branch(上流ブランチ)**
        -  "Checking out a local branch from a remote-tracking branch automatically creates what is called a “tracking branch” (and the branch it tracks is called an “upstream branch”). "
        -  [意訳] リモート追跡ブランチからローカルブランチへチェックアウトするとき、自動的に追跡ブランチが生成される。この追跡ブランチが追跡するブランチを上流ブランチという。
        -  [で結局?] **追跡ブランチが追跡するブランチ**
        -  [参考: Tracking Branches](https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches)
    -  **Remote-tracking branches(リモート追跡ブランチ)**
        -  "Remote-tracking branches are references to the state of remote branches. They’re local references that you can’t move; Git moves them for you whenever you do any network communication, to make sure they accurately represent the state of the remote repository."
        -  [意訳] リモート追跡ブランチはリモートブランチへの参照であり、リモートのブランチではなくローカルにおけるブランチのことで、このブランチはリモートブランチを参照しています。Gitはどんな通信環境にあろうともローカルにおけるリモート追跡ブランチをリモートブランチに合わせることができます。
        -  [で結局?] リモート追跡ブランチとは、リモートブランチを追跡するローカルのブランチのこと。
    -  **push**
        -  "Updates remote refs using local refs, while sending objects necessary to complete the given refs."
        -  [意訳] ローカル参照を使ってリモート参照を更新する。そのためにリモート参照をローカル参照に合わせるために必要なオブジェクトを送信する。
        -  [で結局?] **pushとは、ローカルの変更をリモートに反映させる命令のこと。**
        -  [参考: DESCRIPTION](https://git-scm.com/docs/git-push#_description)
    -  **git push -u origin HEAD**
        -  **クローン元のサーバーに対して、現在のローカルブランチと同名の上流ブランチを設定して、現在のブランチ上で行われるコミットのうち最新のコミットを、上流ブランチに反映させる命令のこと**

- **git pull --prune**
    - **--prune**
    - "Before fetching, remove any remote-tracking references that no longer exist on the remote. "
    - [意訳] リモートリポジトリの情報を取ってくる前に、既に存在していないリモートリポジトリ内のブランチに対応するリモート追跡ブランチを削除する。
    - [で結局?] リモートで削除されたリモート追跡ブランチを削除する。
    - [参考: --prune](https://git-scm.com/docs/git-pull#Documentation/git-pull.txt---prune)
2021年年末現場で使えそうな知識メモ

- soucetreeではコミットメッセージで検索がかけれるみたいなので、タスク番号から過去の履歴を特定できる説はある→[参考サイト](https://pasomaki.com/sourcetree-search-commit/)

## MyBatisの書き方

[参考サイト1かなりわかりやすい]
(https://qiita.com/5zm/items/e1faac61a1d00998fb1f#mybatis%E3%81%A8%E3%81%AF)
[参考サイト1の続き]
(https://qiita.com/5zm/items/0864d6641c65f976d415)
[動的SQLを使う場合はこれもつかえる]
(https://mybatis.org/mybatis-3/ja/dynamic-sql.html)

- Mapperファイルとインターフェースを紐付けるのはnamespace属性でできるみたい
- @MapperScanアノテーションでパッケージスキャンできるみたいだが、そもそもパッケージスキャンがよくわかんない
- id属性にインターフェースのメソッド名を指定すること
- メソッドの引数が１つの場合のみ、引数のデータ型を特定するため、parameterType属性に引数のデータ型を指定すること
- メソッドの引数が複数（２つ以上）の場合、parameterType属性は指定しないこと
- 検索（select）のSQLの場合、戻り値のデータ型を特定するため、resultType属性に戻り値のデータ型を指定すること※登録（CREATE）、更新（UPDATE）、削除（DELETE）の場合、resultType属性は指定しないこと
- 登録（CREATE）、更新（UPDATE）、削除（DELETE）のSQLの場合、インターフェースのメソッドの戻り値は「なし」、「真偽」、「更新件数」のいずれかになっていること、逆をいえばどれかを選べる
- 戻り値の指定方法で、resultType属性とresultMap属性は同時に利用しないこと、基本的にはresultType属性で実現できないときはresultMap属性を利用する
- Mapperファイル内で引数のJavaのデータを参照する場合、バインド変数#{...}を利用すること
- テーブル名やカラム名などPreparedStatementでは設定できない箇所にJavaのデータを設定する等、バインド変数#{...}では対応できない場合に限り、置換変数${...}を利用すること
- メソッドの引数が複数（２つ以上）の場合、@Paramアノテーションを引数に付与すること
- メソッドの引数が一つの場合、@Paramアノテーションを付与しないこと
- マッピングするクラスには空のコンストラクタが存在すること
- >、<はエスケープ処理をすること、<![CDATA[...]]>を利用する。
.ideaのgit管理について Android Studio

Android Studioでプロジェクトを開始するときに.ideaファイル内のgit管理についていつも迷うのメモします。

### 結論
[こちら](https://takemikami.com/2018/08/29/GitIntelliJ-IDEA.html)によると以下3個をgit管理しておけば良いみたいです。

- `build.gradle`
- `.idea/gradle.xml`
- `.idea/misc.xml`

### 自分の場合

しかし自分の環境では`misc.xml`にはユーザー固有のファイルパスが記述されていました。とりあえずユーザー固有のファイルパスの部分を`$PROJECT_DIR$`に変更しておけば良いと思います。

上記以外も基本的にユーザー固有ファイルパスの部分を適宜`$PROJECT_DIR$`に直してさえいればgit管理して問題ないかと思います。

### .idea内のファイルについて

記事を各過程で各ファイルがどのような役割なのか簡単に分かったことをまとめたいと思います。(適宜更新していくかと思います。)

- `workspace.xml`
    - [こちら](https://www.jetbrains.com/help/idea/2017.1/about-projects.html)によるとこのファイルだけはgit管理するべきではありません。固有の情報が含まれるみたいです。

- `misc.xml`
  - git管理するべき
  - プロジェクトで使用するJavaSDKのバージョン情報
  - ユーザ固有のファイルパスで生成される場合ある。その場合は適宜`$PROJECT_DIR$`に置き換える。

- `deploymentTargetDropDown.xml`
  - AVD関連の情報があります。
  - web上でこのファイルについての説明を見つけられていない。
  - ユーザー固有の情報があったためひとまず.gitignoreに入れました。



### 設定(GUI)をプロジェクトの設定ファイルに反映させる。
1. 「Settings」->「Editor」->「Code Style」
2. SchemeをDefaultからProjectに変更する。
PHP引数を使って処理の内容を変えて見ましょう！

#PHP引数
<br>
仮引数と実引数を使って関数の処理の内容を変えていきます！

以下のコードがあったとします。
<br>

```php:index.php
<?php
function show () {
  echo '・・・・・・・・' . PHP_EOL;
  echo '・・・・・・・・' . PHP_EOL;
  echo '・・・・・・・・' . PHP_EOL;
}


show ();           
echo 'おにぎり食べたい！' . PHP_EOL;
echo 'ケーキ食べたい！' . PHP_EOL;
show ();        
echo 'ハンバーガー食べたい！' . PHP_EOL;
echo 'チョコレート食べたい！' . PHP_EOL;
show (); 
```
<br>
ターミナルに以下を入力すると...
<br>

```
~$ php index.php
```
<br>
このように出力されます...
<br>

```
~ $ php main.php
・・・・・・・・
・・・・・・・・
・・・・・・・・
おにぎり食べたい！
ケーキ食べたい！
・・・・・・・・
・・・・・・・・
・・・・・・・・
ハンバーガー食べたい！
チョコレート食べたい！
・・・・・・・・
・・・・・・・・
・・・・・・・・
~ $ 
```

<br>
では、show ( ) 関数に仮引数と実引数を入れていきます！
<br>

```php:index.php
<?php
function show ($message) {    //$messageという仮引数
  echo '・・・・・・・・' . PHP_EOL;
  echo '・・・・ ' . $message . ' ・・・・' . PHP_EOL;
  echo '・・・・・・・・' . PHP_EOL;
}


show ('良いね');           //実引数
echo 'おにぎり食べたい！' . PHP_EOL;
echo 'ケーキ食べたい！' . PHP_EOL;
show ('美味しそう');        //実引数
echo 'ハンバーガー食べたい！' . PHP_EOL;
echo 'チョコレート食べたい！' . PHP_EOL;
show ('最高');            //実引数
```
<br>
もう一度ターミナルで以下を実行します！
<br>

```
~$ php index.php
```
<br>
関数に渡した引数が呼び出されました！
<br>

```
~ $ php main.php
・・・・・・・・
・・・・ 良いね ・・・・
・・・・・・・・
おにぎり食べたい！
ケーキ食べたい！
・・・・・・・・
・・・・ 美味しそう ・・・・
・・・・・・・・
ハンバーガー食べたい！
チョコレート食べたい！
・・・・・・・・
・・・・ 最高 ・・・・
・・・・・・・・
~ $ 
```
<br>
次は、関数に引数を渡さなかった場合

デフォルト値が表示されるように設定していきます。
<br>

```php:index.php
<?php
function show ($message = 'グッド！') {  //デフォルト値をグッド！と指定しておきます
  echo '・・・・・・・・' . PHP_EOL;
  echo '・・・・ ' . $message . ' ・・・・' . PHP_EOL;
  echo '・・・・・・・・' . PHP_EOL;
}


show ('良いね');           
echo 'おにぎり食べたい！' . PHP_EOL;
echo 'ケーキ食べたい！' . PHP_EOL;
show ('美味しそう');        
echo 'ハンバーガー食べたい！' . PHP_EOL;
echo 'チョコレート食べたい！' . PHP_EOL;
show ();            //引数を渡さない場合デフォルト値が表示される
```

<br>
同じように以下ターミナルを実行します！
<br>

```
~$ php index.php
```

<br>
関数に引数を指定しなかった場合、

デフォルト値が表示されました！
<br>

```
~ $ php main.php
・・・・・・・・
・・・・ 良いね ・・・・
・・・・・・・・
おにぎり食べたい！
ケーキ食べたい！
・・・・・・・・
・・・・ 美味しそう ・・・・
・・・・・・・・
ハンバーガー食べたい！
チョコレート食べたい！
・・・・・・・・
・・・・ グッド！ ・・・・
・・・・・・・・
~ $ 
```
npm installでパッケージのダウンロードが始まらない

#起こった事象
githubで管理されてるnode.jsで開発されたソースをcloneして、とりあえず動かすために

```
$ npm install
```
を実行したが、一向にインストールが進まなかった。ログを見る限りパッケージのDL自体できてなさそう

##環境
- Ubuntu 20.02 (AWS EC2インスタンス)
- nvmでnode.jsのバージョンを管理

#原因
npmの設定を確認したところ、user-configのregistryの値が謎のIPアドレスになっていた。

```
$ npm config list
; userconfig /home/xxx/.npmrc
registry = "xxx.xx.xxx.xxx"
```

いつどこで書き換えてしまったのかは不明...

#解決策
以下のコマンドでregistryを標準のアドレスに設定し直して解決

```
$ npm config set registry https://registry.npmjs.org/
```

.npmrcファイルの中身を空にしてnpm installを再実行でも解決する

##備考
proxyの問題で、registryをhttps→httpに変更することで解決することもあるそうです
https://qiita.com/aoi_snow/items/45d6ef03d509fc103ba7
【Go言語】interface定義内に別のinterfaceを埋め込む

# net/httpライブラリで気になる記述を見つけた
[net/http]()のGETを使ってレスポンス本体の内容を操作する、といったコードを書いていた時、
ふとResponse.Bodyの型を見てみるとio.ReadCloser interfaceが指定されていた。

```response.go
type Response struct {
    /// ~~~ 省略 ~~~

    Body io.ReadCloser

    /// ~~~ 省略 ~~~
}
```

こいつのinterface定義を見てみるとこのように定義されていた。

```io.go
// 定義①
type ReadCloser interface {
    Reader
    Closer
}
```

こんな感じのinterface定義は見るけど、上記のような定義はあまり見たことがなかったのでちょっと調べてみた。

```io.go
type Writer interface {
    Write(p []byte) (n int, err error)
}
```

# interfaceの埋め込みという記述らしい
先述の別interfaceを含むinterface内に出てきた`Reader`interfaceと`Closer`interfaceはそれぞれ下記のような定義だが、

```io.go
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Closer interface {
    Close() error
}
```

これらを両方の実装を要求するinterfaceを定義する際に定義①のような記述ができる。
これをinterfaceの埋め込みといい、下記の記述と同等の定義となる。

```io.go
type ReadCloser interface {
    Read(p []byte) (n int, err error)
    Close() error
}
```

# どんな場面で活用できるか
`Reader`interfaceと`Closer`interfaceのような一つしか関数の実装要求をしないinterfaceならば、そのまま新しいinterface内に要求関数を記述してもいいように思えるが、簡潔な記述とメンテナンス性を考えるなら埋め込みを使ったほうがいい。

例えば、そもそも`Reader`interfaceと`Closer`interfaceが実装要求する関数がそれぞれ複数個あると、それを全部新しいinterfaceに記述するのは冗長だし、仮に初期実装時に実装要求する関数が少なくても後々増えたときにいちいち`ReadCloser`interfaceに定義を追加するのは面倒くさい。

なので、埋め込みを使うことで簡潔でメンテのしやすいコードを書くことができる。

```go
type Reader interface {
    MethodA() error
    MethodB() error
    MethodC() error
    MethodD() error
    MethodE() error
    MethodF() error
}

type Closer interface {
    MethodG() error
    MethodH() error
    MethodI() error
    MethodJ() error
    MethodK() error
    MethodL() error
}

// ReaderもCloserも実装要求するようかけるが、冗長すぎる...
type ReadCloser interface {
    MethodA() error
    MethodB() error
    MethodC() error
    MethodD() error
    MethodE() error
    MethodF() error
    MethodG() error
    MethodH() error
    MethodI() error
    MethodJ() error
    MethodK() error
    MethodL() error
}
```
windowsでiverilog その118

#概要　

windowsでiverilogやってみた。
練習問題やってみた。

#練習問題

8bitのgpioを実装せよ。

#サンプルコード

```

module gpio #(parameter ADDR = 0, parameter WIDTH = 8) (input [5:0] addr, inout [7:0] data, input write, input read, inout [WIDTH - 1:0] gpio);
	reg [WIDTH - 1:0] DDR;
	reg [WIDTH - 1:0] PORT;
	reg [7:0] out;
	wire [WIDTH - 1:0] PIN;
	assign data = read ? out : 8'bZ;
	assign PIN = gpio;
	genvar i;
	for (i = 0; i < WIDTH; i = i + 1)
	begin
		assign gpio[i] = DDR[i] ? PORT[i] : 1'bZ;
	end
	initial
	begin
		DDR <= {WIDTH{1'b0}};
		PORT <= {WIDTH{1'b0}};
	end
	always @(*)
	begin
		if (write)
		begin
			if (addr == (ADDR + 1))
				DDR <= data[WIDTH - 1:0];
			if (addr == (ADDR + 2))
				PORT <= data[WIDTH - 1:0];
		end
		if (read)
		begin
			if (addr == ADDR)
				out <= {{8 - WIDTH{1'b0}}, PIN};
			if (addr == (ADDR + 1))
				out <= {{8 - WIDTH{1'b0}}, DDR};
			if (addr == (ADDR + 2))
				out <= {{8 - WIDTH{1'b0}}, PORT};
		end
	end
endmodule

module test;
	reg [5:0] addr = 0;
	reg [7:0] dreg = 0;
	reg [7:0] greg = 0;
	reg read = 0;
	reg write = 0;
	wire [7:0] data,
		pin;
	assign data = write ? dreg : 8'bZ;
	assign pin = read ? greg : 8'bZ;
	gpio u(.addr(addr), .data(data), .write(write), .read(read), .gpio(pin));
	initial
	begin
		$display("addr data write read gpio");
		$monitor("  %h   %h    %h   %h   %h", addr, data, write, read, pin);
	end
	initial
	begin
		#10
			write <= 1;
			addr <= 1;
			dreg <= 8'hff;
		#10
			write <= 0;
		#10
			write <= 1;
			addr <= 2;
			dreg <= 8'h55;
		#10
			write <= 0;
		#10
			write <= 1;
			addr <= 2;
			dreg <= 8'h88;
		#10
			write <= 0;
		#10
			write <= 1;
			addr <= 1;
			dreg <= 8'h00;
		#10
			write <= 0;
		#10
			read <= 1;
			addr <= 0;
			greg <= 8'h55;
		#10
			read <= 0;
		#100
			$finish;
	end
endmodule





```

#結果


```
addr data write read gpio
  00   zz    0   0   zz
  01   ff    1   0   00
  01   zz    0   0   00
  02   55    1   0   55
  02   zz    0   0   55
  02   88    1   0   88
  02   zz    0   0   88
  01   00    1   0   zz
  01   zz    0   0   zz
  00   55    0   1   55
  00   zz    0   0   zz

```

以上。