OmniAICreator/Qiita-1.07M huggingface dataset:
Laravel Excel を用いてCSV出力する手順

Laravel Excelに関しての情報があまり多くないので、備忘録としてアウトプット。
手順は、
1.パッケージのインストール
2.Excel.phpの生成
3.サービスプロバイダーの登録
4.エクスポートクラスの生成
となる。

#1.パッケージのインストール
composerを用いて、LaravelExcel3.1をインストールする。
必要なバージョン、PHP拡張モジュールは以下の通り。
・PHP　7.0以上
・Laravel　5.5以上
・PhpSpreadsheet　1.6以上
・php_zip、php_xml、php_gd2、php_iconv、php_simplexml、php_xmlreader、php_zlib 

 


ルートディレクトリで以下のコマンドを実行する。

```
$ composer require maatwebsite/excel
```
インストール完了後、composer.lockを確認する。

```
"name": "maatwebsite/excel",
"version": "3.1.20",
```
ちゃんとインストールされている。

#2.Excel.phpの生成
ディレクトリ直下で以下のコマンドを実行する。

```
$ php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"

・・・
Copied File [/vendor/maatwebsite/excel/config/excel.php] To [/config/excel.php]
```
config直下にexcel.phpが生成される。

#3.サービスプロバイダとファサードの登録
サービスプロバイダーにLaravel Excelを登録していく。
config/app.phpのprovidersに追記

```php

'providers' => [

  /*
  * Package Service Providers...
  */
  Maatwebsite\Excel\ExcelServiceProvider::class,

 ]
```
続いてファサードに登録する。
config/app.phpのaliasesに追記

```php

'aliases' => [
  
  'Excel' => Maatwebsite\Excel\Facades\Excel::class,

]
```

#4.エクスポートクラスを生成
エクスポートクラスを生成する。
以下のSampleの部分には、出力したいデータを持つモデル名を適宜記述する。

```
$ php artisan make:export SamplesExport --model=App\\Sample
```
app直下にExportsディレクトリ、Exports直下にSampleExport.phpが生成される。

#実際に出力してみる
コントローラーにexportメソッドを追加する。

```php

public function export()
{
  return Excel::download(new SamplesExport, 'samples.csv');
}
```

ルーティングを追加する。

```php

Route::get('export','SampleController@export');
```

設定したURLにアクセスすることで、出力されるはずです。

またこちらを参考に出力する表をビューで形成することもできます。
https://docs.laravel-excel.com/3.1/exports/from-view.html
[Microsoft] 番外. C#ソースコードとRazorの分離 - Angularチュートリアル Tour of Heroes を Blazor で再実装する

# C#ソースコードとRazorの分離

今までRazorファイル中に`@code {}`としてC#プログラムを書いていました。

```razor:Page/Dashboard.razor
@page "/dashboard"
@using BlazorTourOfHeroes.Model
@using BlazorTourOfHeroes.Service
@inject IHeroService HeroService

<h3>Top Heroes</h3>
<div class="grid grid-pad">
    @foreach (var hero in heroes)
    {
      <NavLink href="@("detail/" + hero.Id)" class="col-1-4">
        <div class="module hero">
        <h4>@hero.Name</h4>
        </div>
      </NavLink>
    }
</div>

@code {
    private IEnumerable<Hero> heroes;

    protected override async Task OnInitializedAsync()
    {
        await GetHeroesAsync();
    }

    private async Task GetHeroesAsync()
    {
        heroes = (await HeroService.GetHeroes()).Take(5);
    }
}
```

このままでも問題ありませんが、長くなると見にくくなりますので、C#プログラムを別ファイルに分離します。

# 部分クラスとして別ファイルに分離する

C#プログラムを`partial class`として別ファイルにします。

## ファイル名を決定する

ファイル名はコンポーネントにあわせて`コンポーネント名.razor.cs`にします。


## クラス名を決定する

クラス名はコンポーネントと同一にします。

```cs:Pages/Dashboard.razor.cs
public partial class Dashboard
{
}
```

## 名前空間を決定する

クラスの名前空間は以下のルールによって決まります。

* Razorファイルに`@namespace`がある場合はその名前
* プロジェクトのルート名前空間 + razorファイルが存在するフォルダ名

```cs:Pages/Dashboard.razor.cs
namespace BlazorTourOfHeroes.Pages
{
    public partial class Dashboard
    {
    }
}
```

## 依存するクラスを注入する

コンポーネントの場合はプロパティインジェクションになります。[^1]

```cs:Pages/Dashboard.razor.cs
[Inject]
private IHeroService HeroService { get; set; }
```

[^1]: コンポーネントではない場合はコンストラクタインジェクションになります。


## コードを移動する

Razorファイルにある`@code {}`の中身を新しく作成したC#ファイルに移動します。
必要な`using`句を追加します。

```cs:Pages/Dashboard.razor.cs
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BlazorTourOfHeroes.Model;
using BlazorTourOfHeroes.Service;
using Microsoft.AspNetCore.Components;

namespace BlazorTourOfHeroes.Pages
{
    public partial class Dashboard
    {
        [Inject]
        private IHeroService HeroService { get; set; }
        private IEnumerable<Hero> heroes;

        protected override async Task OnInitializedAsync()
        {
            await GetHeroesAsync();
        }

        private async Task GetHeroesAsync()
        {
            heroes = (await HeroService.GetHeroes()).Take(5);
        }
    }
}
```

## razorファイルを整理する

Razorファイルから不要になった`@using`や`@inject`を削除します。

```razor:Pages/Dashboard.razor
@page "/dashboard"

<h3>Top Heroes</h3>
<div class="grid grid-pad">
    @foreach (var hero in heroes)
    {
      <NavLink href="@("detail/" + hero.Id)" class="col-1-4">
        <div class="module hero">
        <h4>@hero.Name</h4>
        </div>
      </NavLink>
    }
</div>
```
【Swift】オプショナル型とnilの基本

###はじめに
---
今回はSwiftを書いていくうえでとても重要な、オプショナル型の基本について解説します。

###オプショナル型とnilとは
---
Swiftでは扱うべき値が存在しないことを表すために、nilという特別な値が存在しています。変数や定数、関数の返り値、式の評価結果や、通常の値だけでなく未設定やエラーなどの状態を表すことがある場合、その値をnilで表現します。
例えば整数の場合、変数や式の型はInt型ですが、通常はInt型の値を持ち、特殊な場合にnilを値として持つことがある変数や式は、Int?型で扱います。これをオプショナルInt型と呼びます。次の例を見てください。

```swift:
var a : Int = 0
var b : Int? = 10
b = nil //代入可能
a = nil //エラー
``` 

このように、int型は整数以外の値を保持できませんが、オプショナルint型は整数以外に値nilを保持することができます。

なおオプショナル型は、データ型のイニシャライザの返り値にも使われます。ここではInt型イニシャライザの、文字列を引数とするイニシャライザの例を以下に示します。

```swift:
let olympic = "2020"
var year : Int? = Int(olympic) //2020が返される
var city : Int? = Int("Tokyo") //整数として評価できないので、nilが返される
```

このように引数の文字列を整数として評価した値を返しますが、整数として評価できなかった場合はnilを返すため、このイニシャライザの返り値を受け取る変数の型はInt?である必要があります。

###オプショナル型の値を開示する
---
オプショナルInt型(Int?型)の値は整数かnilですが、型がInt型ではないので、そのままInt型に代入することも、Int型として式の中で演算することもできません。そのためにオプショナル型からデータを取り出す、すなわちInt?型からInt型を取り出す必要があります。このことを、ここでは開示と呼ぶこととします。開示のためにはオプショナル型に対して「!」という記号を使います。具体的な例を以下に示します。

```swift:
let year : Int? = Int("2020")
let next : Int = year! + 4   //開示指定(!)が必要
```

この例ではyearの後ろに!がないとコンパイル時にエラーとなります。では、オプショナル型の変数の値がnilだった場合はどうなるのでしょうか。

```swift:
let year : Int? = Int("令和20年") //yearの値はnil
let next : Int = year! + 4  //実行時エラーになる
```
この場合にはInt型の値を取り出すことができないので、コンパイルはできますが実行時にエラーになります。また、開示さえすれば復合代入演算子を使うこともできます。

###条件判定
---
オプショナル型は開示しようとしても、nilが格納されているとエラーが発生してしまいます。そこで、開示前にどんな値が格納されているのか確認する方法として、比較の演算子「==」や「!=」を利用することができます。この際に開示は必要ありません。以下に例を示します。

```swift:
var nagano : Int? = Int("1998")
if nagano != nil {                //真(ここでは開示指定は使わない)
    print("Nagano: \(nagano!)")   //ここで開示指定が必要
}
if nagano == 2020 {               //偽(ここでは開示指定は使わない)
    print(2020)
}
```

変数または定数をnilと比較したとき、nilなのかどうかが調べられます。値と比較すると、nilではなく、かつその値かどうかが調べられます。

###終わりに
---
今回はSwiftを書く上で非常に重要な、オプショナル型の基本について解説しました。オプショナル型についてはまだまだ大切な使い方があるので、また今度オプショナル型に関した記事を書こうと思います。オプショナル型はすごく大切な知識なので、ぜひ身に着けてください。
高専キャリアとマイクロソフトがコラボしたクラウドAI開発講座進捗報告[5]

# クラウドAI開発講座進捗報告- 5週目

[これ](https://qiita.com/teruto725/items/222b011a8dd63bf76158)の続き


作りたいものに向けてひたすらコーディング。


## やったこと
### 1. Teamsへのアップロード
前回の中間発表でとりあえずteamsにアップロードできるかどうかは試したほうがいいといわれていたのでやってみた。
[ちょまど](https://qiita.com/chomado/items/23c66a975e21265d99ae)さんの記事を参考にした。
うまくいかない、、、なんで？？？
いろいろ試してダメそうだったので、一からbot appをAzure上で作ってやってみるとうまくいった。
なのでアップしたbotはただのechobot。下に写真。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/573723/f3fde646-8e32-bea6-58cb-149bfc3f06e4.png)

### 2. ひたすらコーディング
なので特に報告できることはなし。
クラスはほとんど洗い出したので、あとは細かい部分を書いていく必要がある。
割合的には20%くらい。


## 感想
　1. Teamsへのアップロードで面倒な工程はすべて終わったはずなので、あとはコーディングを進めるだけ。
　頭使いながらコードを書いてる時間が一番楽しい。
　
  
## 来週の予定
ひたすらコーディング、ある程度かけてきたらコード解説記事を書きたい。
クリエイティブ・コモンズの条件早見表(2020年8月版)

# クリエイティブ・コモンズ(CC:Creative Commons)とは

>作品を公開する作者が「この条件を守れば私の作品を自由に使って構いません。」という意思表示をするためのツールです。([本家](https://creativecommons.jp/licenses/)より)

特にSEO対策を気にしている場合など、ブログ執筆時にアイキャッチ画像の指定は必須の作業です。
Flickrなどでは[検索画面](https://www.flickr.com/search/)でライセンスの条件指定（商用で改変可など）もできますが、久しぶりだとマークの意味を確認するために毎回本家やWikiを巡ってしまいます。意外とシンプルな解説サイトが直ぐに出てこなかったので復習と将来の自分用を兼ねてまとめました。2020年8月の内容です。

# クリエイティブ・コモンズの利用条件早見表

上にあるほど自由度が高いマークです。

| コモンズ証／表記 | 商用可 | 改変可 | 商用利用の条件 | 解説 |
|:----------:|:-----:|:------:|:-------------:|:-----|
|![pd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/cdfff6a2-5e7b-1c35-7751-e9580d37f88a.png)<br />PDM|〇|〇|なし|既にパブリックドメインになっている作品に標示するツールである。(※1)|
| ![cc0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/b4c0ee84-7ca2-5da2-ea7f-e40c4a25bae5.png)<br />CC0 |〇|〇|なし|権利者が自分の作品を能動的にパブリックドメインに置くツールである。(※1)|
|![cc-by.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/985a7379-3b1a-0f9e-3383-b41c0f92c5ca.png)<br />CC-BY (表示) |〇|〇|クレジット表示 |原作者のクレジット（氏名、作品タイトルなど）を表示することを主な条件とし、改変はもちろん、営利目的での二次利用も許可される最も自由度の高いCCライセンス。(※2)|
|![cc-by-sa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/ee4ae057-ad49-cc17-5eb5-56745108d824.png)<br />CC-BY-SA (表示—継承) |〇|〇|クレジット表示／ライセンス継承|原作者のクレジット（氏名、作品タイトルなど）を表示し、改変した場合には元の作品と同じCCライセンス（このライセンス）で公開することを主な条件に、営利目的での二次利用も許可されるCCライセンス。(※2)|
|![cc-by-nd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/30df8b0b-a158-8bb0-259c-fa4438871666.png)<br />CC-BY-ND (表示—改変禁止) |〇|×|クレジット表示／改変禁止|原作者のクレジット（氏名、作品タイトルなど）を表示し、かつ元の作品を改変しないことを主な条件に、営利目的での利用（転載、コピー、共有）が行えるCCライセンス。(※2)|
|![cc-by-nc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/365e15d8-0618-84ad-4f65-3cff9b22c555.png)<br />CC-BY-NC (表示—非営利) |×|〇|商用不可|原作者のクレジット（氏名、作品タイトルなど）を表示し、かつ非営利目的であることを主な条件に、改変したり再配布したりすることができるCCライセンス。(※2)|
|![cc-by-nc-sa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/735b20e8-57c5-f990-ad05-904ca9cc32a9.png)<br />CC-BY-NC-SA (表示—非営利—継承) |×|〇|商用不可|原作者のクレジット（氏名、作品タイトルなど）を表示し、かつ非営利目的に限り、また改変を行った際には元の作品と同じ組み合わせのCCライセンスで公開することを主な条件に、改変したり再配布したりすることができるCCライセンス。(※2)|
|![cc-by-nc-nd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51434/89964f00-3a35-6d5e-9678-b1edd67e41a4.png)<br />CC-BY-NC-ND (表示—非営利—改変禁止) |×|×|商用不可|原作者のクレジット（氏名、作品タイトルなど）を表示し、かつ非営利目的であり、そして元の作品を改変しないことを主な条件に、作品を自由に再配布できるCCライセンス。(※2)|

(※1)PDに関する解説は「[Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AA%E3%82%A8%E3%82%A4%E3%83%86%E3%82%A3%E3%83%96%E3%83%BB%E3%82%B3%E3%83%A2%E3%83%B3%E3%82%BA%E3%83%BB%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9)」のコピペです。
(※2)CCに関する解説は「[公式](https://creativecommons.jp/licenses/)」のコピペです。

# 参考

[クリエイティブ・コモンズ・ジャパン](https://creativecommons.jp/)
[Wikipedia: クリエイティブ・コモンズ](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AA%E3%82%A8%E3%82%A4%E3%83%86%E3%82%A3%E3%83%96%E3%83%BB%E3%82%B3%E3%83%A2%E3%83%B3%E3%82%BA)
RancherOSのインストールからSSH公開鍵認証でログインするまで in VirtualBox

覚え書きに
#### 環境
- VirtuaBox 6.0.20
- [RancherOS 1.5.6](https://github.com/rancher/os/releases/tag/v1.5.6)（ゲスト）
- Windows 8.1（ホスト）
- Cmder (ホストでのコンソールエミュレータ)

# RancherOSのインストール
## VMの作成
VirtualBoxでLinuxのVMを作成．
メモリ：2MB
ストレージ：10GB前後

RancherOSの[GitHub](https://github.com/rancher/os)から落としてきた`rancheros.iso`を設定からVMの光学ドライブ欄にセット．
ネットワーク設定はホストオンリー．

## 起動（ゲスト）

起動したらとりあえずパスワードを変えておく．（なくても良いかも）


```
$ sudo passwd rancher
```


## 設定ファイル作成（ゲスト）
設定ファイルを作る．
本記事ではホームディレクトリ直下(~/)に作っている．

```
$ vi cloud-config.yml
```

``` cloud-config.yml
#cloud-config
hostname: rancher
```

## インストール（ゲスト）
まずパーティションを確認．

```
$ sudo fdisk -l
```
---
インストールを実行．
（仮想環境でないならフォーマットが必要かもしれない）
本記事では`/dev/sda`にインストールする．`PASSWORD`の部分は任意のパスフレーズに変更．

```
$ sudo ros install -c cloud-config.yml -d /dev/sda -a "rancher.password=PASSWORD"
```
確認のダイアログを確認して`y`
再起動を促されるが，拒否してシャットダウンする．

その後，設定から`rancheros.iso`の割り当てを除去してから起動．

# SSH作業
## 鍵の作成（ホスト）
鍵のペアを作る．
形式はRSA，長さは4096bit.

```
$ ssh-keygen -t rsa -b 4096
```

~/.sshディレクトリに（windowsなら/User/(username)/.ssh）
id_rsa（秘密鍵）, id_rsa.pub（公開鍵）が生成されている．

## 鍵の転送（ホスト）
先ほど鍵が生成されたディレクトリに移動し，**公開鍵**をゲストOSに転送．
今回はsftpを使用．
例ではゲストOSのIPアドレスは`10.0.0.1`とする

```
$ cd /User/(username)/.ssh/
$ sftp rancher@10.0.0.1
rancher@10.0.0.1's password:
Connected to rancher@10.0.0.1.
sftp> put id_rsa.pub
Uploading id_rsa.pub to /home/rancher/id_rsa.pub
id_rsa.pub                                                    100%  743   175
sftp> quit

```

## 鍵の登録（ゲスト）
先ほどの操作でゲスト側に公開鍵が転送できているため，それを登録する．

```
$ cd ~
$ mkdir .ssh
$ touch .ssh/authorized_keys
$ chmod 700 .ssh
$ chmod 600 .ssh/authorized_keys
$ cat id_rsa.pub >> .ssh/authorized_keys
```
## 確認（ホスト）
ここまでうまくいっているならパスフレーズなしでログイン可能

```
$ ssh rancher@10.0.0.1
```




### あとがき
詰みたくなかったのでパスワード認証をオフにする設定はこの記事では取り扱っていません．
この方面に詳しいわけではないため，現在推奨されていない方法を使ったり，そもそもやり方が間違えている可能性があります．お詳しい方，訂正のコメントを頂けると幸いです．

#### 参考文献
https://pdwslmr.netlify.app/posts/on-premise/rancheros-install/
https://qiita.com/kazokmr/items/754169cfa996b24fcbf5
フレームワークについて考えてみた

先日、フレームワークを使うメリット、デメリットについて質問された際に、うまく言語化できなかったので、今回はフレームワークについてまとめてみました。

## フレームワークとは
Webアプリケーションを作成する際に用いられる枠組みのこと。フレームワークでアプリケーションの雛形を作成し、必要なファイルをカスタマイズしていくとWebアプリケーションが作成できる。

- フレームワークの種類（一例）
 - Ruby → Ruby on Rails（ルビーオンレイルズ）、Sinatra（シナトラ）
 - PHP  → Laravel（ララベル）、CakePHP（ケイクピーエイチピー）
 - Java → Spring Framework（スプリングフレームワーク）、Java EE（ジャバイーイー）

## フレームワークを使うメリット
- 速く作れる 
 - 必要なファイルやデータの流れを既に一つのセットとして用意してくれているフレームワークを用いることで、比較的容易に素早く、Webアプリケーションを開発することができます。
- コードの書き方を統一させることができる
 - これは、プログラミングに限った話ではないですが、どんな仕事をするにも、個々人のやり方があると思います。個人のやり方があることは良いことですが、チームで仕事をする際はやり方を統一させた方が効率が良いこともあります。フレームワークを使えばコードの書き方が統一されるため、個々人による違いを大幅に減らせます。また機能追加や改修もし易くなり、バグが発生するリスクを減らすことにもつながるので、運用管理の工数やコストを減らすことにも効果があります。

## フレームワークを使うデメリット
- 学習コストがかかる
 - フレームワークはとても便利なのですが、フレームワーク特有のコードが書けなければいけません。つまり、プログラミング言語の書き方だけでなく、フレームワーク特有の書き方についても勉強が必要となってきます。特に使用人口が少ないフレームワークは、情報も少ないので覚えるのに時間・労力がかかってしまいます。
- 仕組みを理解していなくてもコードを書けてしまう
 - 先ほども書きましたが、 必要なファイルやデータの流れを既に一つのセットとして用意してくれているので、コードを書く量は少なくなるのですが、その反面`仕組みを理解していなくても作れてしまうのです。`プログラミングの技術を上げたいのなら、フレームワークを使わない場合の書き方についても学んでおくと良いと思います。

## まとめ
エンジニアとして働く上で、フレームワークは開発経験があり言語の知識がある方はいいですが、初学者の方はまず言語の知識を身に付けることを優先した方が良いと思ったのと、恐らく`なんとなく動いた`で進めてしまうと、後々応用が効かなくなってしまうので、使用する場合は熟知してから使用した方が良いと思いました。
Featherフォーマットを使ってPython・R・Julia間で簡単にデータをやり取りする

Python、R、Juliaそれぞれの強みがあるので組み合わせて使いたい場面がしばしばあるかと思います。コードを直接呼び出す機能もありますが、データ解析の場面ではそこまで密に結合させなくても別々のスクリプトで違うステップを担当すれば十分なことも多いでしょう。たとえばPythonでデータのスクレイピングをして、Juliaでマルチスレッドに解析を回し、Rで統計解析や可視化を行うといったケースは想像しやすいかと思います。

### Why Feather?
そんなとき、Pythonでpickleで保存するともちろん他のプログラミング言語にデータを持っていくことができない、いっぽうでCSVでの保存は遅かったり読み込み時にパースし直すのが面倒、など微妙にやりづらさを覚えることがあります。今回はそんなワークフロー構築での悩みを解決してくれる [Featherフォーマット](https://blog.rstudio.com/2016/03/29/feather/) とその使い方を簡単に紹介します。Featherはデータ保存用の軽量なフォーマットで、シンプルなAPIで使え、プログラミング言語間での行き来が自由で、かつ読み書きが高速なことを特徴とします。

[こちらの比較記事](https://towardsdatascience.com/the-best-format-to-save-pandas-data-414dca023e0d) によるとFeatherは速度、メモリ消費の両面で優れたパフォーマンスを示すようです。実際の性能はどのようなデータを格納するかによって異なるでしょうが、ともかく簡単に使えるので試してみる価値は十分にあるのではないでしょうか。

### 注意
**Featherフォーマットは行ラベルに対応していません。そのためpandasで行ラベルを与えている場合はあらかじめ `df.reset_index()` してやる必要があります。** Rはぜんぜん行ラベルは使わない気がしますし、 [推奨できないという話もあります](https://www.perfectlyrandom.org/2015/06/16/never-trust-the-row-names-of-a-dataframe-in-R/) 。

### Feather形式読み書きのコード
#### Python
```python.py
import pandas as pd
import feather

# read
df = feather.read_dataframe("foobar.feather")

# write
feather.write_dataframe(df, "foobar.feather")
```

#### R
```r.r
library(feather)

# read
df <- read_feather("foobar.feather")

# write
write_feather(df, "foobar.feather")
```

#### Julia
```julia.jl
using DataFrames
using Feather

# read
df = Feather.read("foobar.feather")

# write
Feather.write("foobar.feather", df)
```

これだけです。いずれの言語でも型やヘッダなど気にすることなく読み書きができるためCSVより楽だと思います。

追記：最近 [Feather V2](https://ursalabs.org/blog/2020-feather-v2/) がリリースされました。まだJuliaでの対応パッケージが出揃っていないのでここでは扱いません。本記事の内容はFeather V1を対象としたものとなります。
プログラミングの勉強方法として写経は非効率？


# はじめに

プログラミングの学習の進め方として写経があります。写経での学習方法に対しては、かなり非効率だという批判がありますが私としてはそうでは無いのではと思っており写経での学習もしています。

この投稿では写経での学習のポイントを私なりにまとめてみました。

# 写経学習のポイント

## 【大前提】バランスが大事。写経だけしても当然NG。アプリケーションを作ることを目標にしよう。

世の中何事も中庸が大切です。

エンジニアリングは世に役立つものを作ることが本質なので、まずは作りたいアプリケーションを作り出してしまい、つまずいた部分を逐次調べながら学ぶことも非常に重要だと思います。

しかし、体系的に学ぶこと(良質な書籍のコードの写経は体系的に学ぶための良い方法の1つだと思っています)も重要です。

単純な例で、Pythonにて1から9までの奇数のみを持つリストを作りたいとき、予備知識の無い初心者が1つずつ調べながら書くと以下のようなコードになるかもしれません。

```python
>>> l = []
>>> for i in range(10):
...   if i % 2 == 1:
...     l.append(i)
>>> l
[1, 3, 5, 7, 9]
```

しかしrangeの仕様と内包表記を学習していれば下記のように1行で済むことを、逐次なやり方では知らずに進めてしまうことにもなり得ます。

```python
>>> l = [i for i in range(1, 10, 2)]
>>> l
[1, 3, 5, 7, 9]
```

## 学習済みの箇所はコピペしよう

既に自分が十分に理解している箇所に関しては積極的にコピペして当然問題無いと思います。学ぶことが目的なので学びにならない箇所をモクモクと書いてしまうのは時間の無駄でしょう。

## 脳死ではやらない

コードを写経するときは意味を頭で反芻しながらやりましょう。

例えば下記のコード(Rust)では、「`chunks`という変数を宣言。0から`N_THREADS`の整数をmap。mapのクロージャの中身は`series_range`から...」のように意味を考えながらやってみましょう。

```rust
let chunks = (0..N_THREADS).map(|ii| series_range.clone().skip(ii).step_by(N_THREADS)); |
```

## "実験"もしながら理解を深めよう

上記のように考えながら進めると、写経対象のコードに対して疑問が浮かぶときがあります。

*このXXの箇所をYYに置き換えたらどうなるんだろう？*

などと思ったらやってみましょう。

以下の例では、私は写経対象コードにある`move`予約語を消すとどうなるか気になったので試してみて、その結果をコメント欄に書いて保存しました。

```rust
    .map(|vv| std::thread::spawn(move || {
    // .map(|vv| std::thread::spawn(|| { // moveを消すとコンパイルエラーになる。READMEに詳細を記載した。
```

## 得た知識をコードのコメントとして残そう

上記のように自分なりに新しく理解したことはコメントとして書いてみると良いと思っています。

```rust
    // ①
    // (①の説明) series_rangeをN_THREADS個に分割する。it.skip(ii)はitの先頭からii個をスキップする。
    // これにより、series_range.clone().skip(0), series_range.clone().skip(1), series_range.clone().skip(2) の3つができる
    // it.step_by(N_THREADS)はitからN_THREADS個ごとに取り出す。
    // https://doc.rust-lang.org/std/iter/trait.Iterator.html
    // の公式ドキュメントで詳細を参照できる。
    // 結果、chunks = [[0,3,6,...], [1,4,7,...], [2,5,8,...]]; が得られる。
    // ただし、mapは遅延処理なので、この段階では評価されない。
    // このmap内のクロージャは②の最後にあるcollectが呼ばれた際に、②にある他のmapとあわせて評価される。
    // series_rangeはcloneする。cloneをしないと、map内のクロージャにあるseries_rangeに所有権が移動し、
    // ii:1のときの後続で失敗してしまう。
    let chunks = (0..N_THREADS)
        .map(|ii| series_range.clone().skip(ii).step_by(N_THREADS));
```

## 写経したコードは自分の引き出しとしてすぐに取り出せるようにしておこう

私は写経したコードは自分のGitHubレポジトリにあげています。そうすると、キーワードに対して検索ができますし、プライベートでも職場でもすぐに参照することができます。
アニメみたいに「この作戦 (プロジェクト)の成功率は○○%です」と言いたいなら

erfという関数の存在を知ったのでメモ。
言ってみたい方はExcelなどで計算してみましょう。

# 用意するデータ
* 残りのリソース量(R)
    * 例：↓ほど細かい
        * スプリント数
        * 人スプリント
        * 人日
        * 人時
* 未消化のタスク量(T)
    * 例：↓ほど細かい
        * タスク数の総和
        * タスクの相対見積もりの総和(ストーリーポイントなど)
        * タスクの見積もりの総和(人日,人時など)
* 過去実績における"タスク量 / リソース量単位"の平均(M)と分散(V)
    * 例：↓ほど細かい
        * スプリント（あるいは週別、月別などの期間）別に集計
        * タスク別に集計(各タスクに消費したリソース量を記録しておく必要あり)

# 計算
* 残りのリソース量で消化可能なタスク量の期待値(μ)
    * M * R
* 残りのリソース量で消化可能なタスク量の標準偏差(σ)
    * √( V x R )
* T = μ - xσ の x
    * (μ - T) / σ
* 残りのリソース量で消化可能なタスク量が μ - xσ 以上である確率 = リソースが足りる確率 = 成功率
    * 0.5 + erf( x / √2 ) / 2
         * μ 以上である確率は 50%(=0.5)
         * μ ± xσ の範囲内である確率は erf( x / √2 )
         * μ ~ μ - xσ の範囲内である確率は erf( x / √2 ) / 2

# 参考
* [68–95–99.7則 - Wikipedia](https://ja.wikipedia.org/wiki/68%E2%80%9395%E2%80%9399.7%E5%89%87)
dockerの超超基本からまとめる #1 ~仮想環境とDocker~

#はじめに
この記事は私がいつまで経ってもDockerの仕組みやメリットが一切理解できないのでまとめていく記事になります。方針としては、厳密性を犠牲にして、ひとまず自分なりにコンテナを作って動かせることを目標とします。
何か間違いや誤解があった場合は優しく指摘していただけると幸いです。

#仮想環境とは
よくDockerとの比較で出される仮想環境。
ただ、正直この二つの違いよくわからない……
ということで、まずは仮想環境とはなんぞや、というところから始めましょう

##仮想環境
少しGoogleで`仮想環境`で調べてみると山のように検索結果が出てきます。
これらを要約すると

- 様々なライブラリが散らからない
- 同じライブラリの複数のバージョンを使い分けることができる
- 最悪全部消してやり直しても他のプロジェクトに影響を与えない

という感じです。


<img width="404" alt="仮想環境" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629803/4f363591-adf5-d6c8-25a4-7880387315c8.png">
([こちらの記事](https://qiita.com/ozaki_physics/items/985188feb92570e5b82d#%E4%BB%AE%E6%83%B3%E7%92%B0%E5%A2%83%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)から画像をお借りしました)

上の図からわかるように、様々なライブラリをrootの環境に用意しておいてあげて、その中から使いたいライブラリだけを選んで仮想環境を構築することができているのがわかります。

例えば仮想環境１のPythonを3.7にアップデートしたいけど仮想環境３のPythonはアップデートしたくない！という要望も簡単に叶いますし、仮想環境３を全部消して作り直しても、他の仮想環境には影響を与えません。

##Dockerの仕組み
じゃあ一体Dockerはその辺の仮想環境と何が違うねん、という話です。

勉強して気づいたのは**Dockerは仮想環境の一種だ**、ということです
<img width="404" alt="仮想環境" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629803/746e7bd7-5316-ae35-7a2a-f987f1494629.png">

上の図から言えることは、Dockerは仮想OSを立てるのではなく、HostOSの上にDockerがあって、その中でコンテナがそれぞれ独立に動いているということです。
~~だからなんだってんだ~~

##DockerのContainerとImage
Dockerの用語はわからないことが多いけど、コンテナとイメージの違いがよくわからないです。

- コンテナ
イメージをたくさん入れて動くようにしたもの。
コンテナごとに独立していて、一つのコンテナが一つのアプリケーションを動かす。

- イメージ
pythonとかPytorchとかNumpyとかそれぞれのライブラリをコンテナに入れるためのもの。
基本的にDockerのどっかに落ちているので落として使う。

ひとまずこの理解で進めていきます。

#わからないところ
ひとまず厳密なところは置いておいて、この理解で困ることがあったり指摘があったらまた戻ってくることにします。

- コンテナの中に複数のアプリケーション(php,jsなど)を入れることは不可能？

次回はpythonをDocker上で動かしてみる。
PythonでNumPy配列「ndarray」をliltに変換する【tolist()】

Pythonでcsvから値を抽出して、for文で回そうと思ったら抽出したデータが**ndarray**という、カンマ（,）がないバージョンの配列になっていたので苦戦。 => 解決したのでメモ

**抽出先のcsv**

```sample.csv
sample_name,sample_colomn
aaaaaaaaaaa,bbbbbbbbbbbbb
ccccccccccc,ddddddddddddd
```

**抽出するためのロジック**

```py3:sample.py

import pandas as pd
import numpy as np

sample_data = pd.read_csv('sample.csv',index_col='sample_colomn')
sample_colomn = sample_data.index.values
print(sample_colomn)

# ['bbbbbbbbbbbbb' 'ddddddddddddd']
```

`['bbbbbbbbbbbbb' 'ddddddddddddd']`をfor文で回そうとしたら`TypeError: only integer scalar arrays can be converted to a scalar index`と怒られました。

## 対策

**tolist()**を使用して、カンマ（,）がないバージョンの配列を、普通の配列（list）に変換する

```py3:sample.py

import pandas as pd
import numpy as np

sample_data = pd.read_csv('sample.csv',index_col='sample_colomn')
sample_colomn = sample_data.index.values
print(sample_colomn.tolist())

# ['bbbbbbbbbbbbb', 'ddddddddddddd']
```

以上です！

参考
https://note.nkmk.me/python-numpy-list/
コールバック関数

引数に関数を渡す。
Javaから始めた自分としては考えられない。

````js
var callBackTest1 = (callback) => {
    console.log("1");
    callback();
};

var callBackTest2 = () => {
  console.log("2");
}

// 呼び出し
callBackTest1(callBackTest2);
// "1"
// "2"

````

上記を無名関数に置き換えることもできる。

````js
callBackTest1(function() {
    console.log("2");
});    

````

引数がある関数を呼ぶ場合

````js

var callBackTest1 = (callback, name) => {
    console.log("1");
    callback(name);
};

var callBackTest2 = (name) => {
  console.log(name);
}

callBackTest1(callBackTest2, "hoge");
// 1
// "hoge"

````
Linuxでアップデートしたら中華フォントになった件について（修正方法）

# 与太話
　巷では中国本土で使われる漢字（簡体字）の字形が表示される現象を「中華フォント現象」と呼ぶらしい．最も簡体字を利用する中国語利用者にとっては「なんのこっちゃ」というこの現象名なのだが，この表示現象をひと括りの単語として認識するまで時間がかかってしまった．そして，この現象を「問題」として認識するのはおそらく日本語利用者しかいないだろう．

　先日，久々にOSのアップデートをしようと`sudo dnf update`（筆者はFedoraを利用．Ubuntuでいう`sudo apt-get update`と同義）をかけて再起動したところ，ログイン画面から中華フォント現象が起きていた．もちろんOSの設定言語は「日本語」であるにもかかわらず！

　これはめんどくさいことに多くの時間を費やすなと思いながら，早速改善策を調べる．

# 解決策

- `/etc/fonts`以下の設定（`etc`はOSの設定ファイルが格納されているディレクトリ）：
  - コマンド`ls /etc/fonts/`を実行したところ，`conf.d`ディレクトリと`fonts.conf`の設定ファイルがある．一度，`fonts.conf`を開いてみると，X Window開発者のKeith Packard氏のコメントが書かれてあった．

```text
<!--
        DO NOT EDIT THIS FILE.
        IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED.
        LOCAL CHANGES BELONG IN 'local.conf'.

        The intent of this standard configuration file is to be adequate for
        most environments.  If you have a reasonably normal environment and
        have found problems with this configuration, they are probably
        things that others will also want fixed.  Please submit any
        problems to the fontconfig bugzilla system located at fontconfig.org

        Note that the normal 'make install' procedure for fontconfig is to
        replace any existing fonts.conf file with the new version.  Place
        any local customizations in local.conf which this file references.

        Keith Packard
-->
```

 つまり，ここに直接書き込んではだめということがわかる．その代わりにlocal.confに設定を書き込めと．でも，`local.conf`は`ls`で見当たらなかったので，`/etc/fonts/`下で作成した．

```
# vi /etc/fonts/local.conf
```

フォントファミリー "serif", "sans-serif", "monospace" それぞれ，Noto * フォントファミリを読み込ませるように以下のように記述した．記述方法は[fontconfigのユーザードキュメント](https://www.freedesktop.org/software/fontconfig/fontconfig-user.html)を参考にする．

```xml:local.conf
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
    <alias>
        <family>serif</family>
        <prefer>
            <family>Noto Serif</family>
        </prefer>
    </alias>
    <alias>
        <family>sans-serif</family>
        <prefer>
            <family>Noto Sans</family>
            <family>Noto Sans CJK JP</family>
        </prefer>
    </alias>
    <alias>
        <family>monospace</family>
        <prefer>
            <family>Noto Sans Mono CJK JP</family>
        </prefer>
    </alias>
</fontconfig>

```

これで再起動したところ，無事中華フォント現象から脱却できていた．

## 追記（2024/09/17）

- 再起動を必要とせず，`sudo fc-cache -fv`でフォント設定の反映は可能であることを確認
- さらに，Ubuntuの設定言語を英語にしたときに生じる中華フォント現象も同様の対応によって解消されることを確認した
間違えたブランチで作業し始めてしまった時の対処法｢git stash｣。又、git stashやcheckoutができなくなった時の対処法。

間違えたブランチで作業し始めてしまった時の対処法｢$git stash｣。
又、git stashやcheckoutができなくなった時の対処法。

#本記事の狙い
gitで躓いたことを自分用に記録してゆきます。


#問題
間違えて統合ブランチで作業を始めちゃった。。。

ブランチを切り替えようと
`$git stash`すると
```app/views/layouts/application.html.erb: needs merge```
と言われstashできなかった。


#解決方法
###git stashで一時保存する。
以下で$git stashとはなんぞやを説明しています。
知っている方は下記<strong>手順</strong>まで。

`$git stash`　
を実行することでステージングされている･いないデータを
別の場所でそれぞれ一時保管しておける。

<strong>ただし、以下は stash されない。</strong>
･まだステージングされていない作業コピー内の新しいファイル
･無視されたファイル(gitignoreに記述されたファイル)

▼参考:作業コピーの位置づけ(スライド15p)
https://www.slideshare.net/yoshinoriyamanouchi12/git-79086120

stash後にcheckoutやその他git操作が行える。
checkoutして本来居たかったブランチに移り
`$git stash pop`
でstash から変更が削除され、現在のにブランチに再適用される。

又
`$git stash apply`
を使用してその変更を stash に維持することも可能。

※stash は作業しているローカルの Git リポジトリにのみ適用される。
プッシュ時にサーバーには転送されない。

▼参考:stashについて
https://www.atlassian.com/ja/git/tutorials/saving-changes/git-stash
▼参考:リモート追跡ブランチについて
https://qiita.com/uasi/items/69368c17c79e99aaddbf



#手順
`$git status`　
で問題を特定します。

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   (コンフリクトが起きているファイル)

=>エディターでコンフリクト箇所を修正し、保存。

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	(変更されているがステージング($git add (ファイル名))されていないファイル)

=>コンフリクト修正したファイルもろともステージング


この状態で

```
$git stash
$git checkout (行きたいファイル)
```


#git stashの使い方

###$git stash　
一時的に作業した内容を保存。

###$git checkout (branch名)
お望みのブランチ(branch名)へ移動。

###$git stash pop
stash前の状態に戻す。

```
$git stash
$git checkout
$git pop
```
を行うとcheckout前の状態をcheckout後のブランチへ反映させるため、
コンフリクトが起きます。

またコンフリクトを解消し、ステージング($git add (ファイル名))すれば
checkout、もしくはstash等操作ができる状態になります。

###$git stash apply
お望みのブランチ(branch名)にstashした内容を反映。


因みに…
###$git stash list
stash 中の内容が見れる。

```
$ git stash list --date=local
```
とすることで作成日時を表示できる。

###$git stash apply stash@{2}
で望んだstashのみ反映させられる。
▼参考
https://gist.github.com/koudaiii/526707492ebc5915596e
https://ccbaxy.xyz/blog/2020/03/20/ruby33/
dockerのrestart→exec→exitではexitedしない話

dockerを勉強し始めて、exitしたのにexitedにならなくハマったお話。

##開始前のコンテナの状態
`$docker ps -a`でコンテナの状況を確認。

```
$docker ps -a 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
b45e56cec3c6        ubuntu              "bash"              7 hours ago         Exited (137) 17 minutes ago                       silly_hoover
c71eae7ff038        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                            elegant_swanson
6374f67a1248        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                            epic_varahamihira
```

今回はCONTAINER ID：`b45e56cec3c6`を起動する。

##コンテナ起動
`$docker restart b45e56cec3c6`で起動してみる。

```
$docker ps -a               
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS               NAMES
b45e56cec3c6        ubuntu              "bash"              7 hours ago         Up 1 second                                  silly_hoover
c71eae7ff038        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                       elegant_swanson
6374f67a1248        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                       epic_varahamihira
```

起動した。

## ubuntuの中へ
`$docker exec -it b45e56cec3c6 bash`でbash実行。

```
$docker exec -it b45e56cec3c6 bash  
root@b45e56cec3c6:/# 
```

入った。

##コンテナを抜ける
`$exit`でコンテナを抜けホストに戻る。

```
root@b45e56cec3c6:/# exit
exit
```

戻ってきたので、コンテナのステータスを確認。

##ステータス
`$docker ps -a`で確認

```
$docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS               NAMES
b45e56cec3c6        ubuntu              "bash"              7 hours ago         Up 4 minutes                                 silly_hoover
c71eae7ff038        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                       elegant_swanson
6374f67a1248        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                       epic_varahamihira
```

exitedになっていない。。。

##アタッチしてみる
`$docker attach b45e56cec3c6`

```
docker attach b45e56cec3c6
root@b45e56cec3c6:/# 
```

入れた。

##再度exit
`$exit`を再度実行。

```
$exit
exit

```

##再度ステータスを確認
`$docker ps -a`を再度実行。

```
$docker ps -a                     
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
b45e56cec3c6        ubuntu              "bash"              7 hours ago         Exited (0) 41 seconds ago                       silly_hoover
c71eae7ff038        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                          elegant_swanson
6374f67a1248        hello-world         "/hello"            7 hours ago         Exited (0) 7 hours ago                          epic_varahamihira
```

無事exitedになってる！
Route53でドメインを登録した際にNginxのページが表示されてしまう時の対処

# 経緯
・Railsのアプリケーションは既にAWSへデプロイ済み
・せっかくならIPアドレスのままではなく、独自ドメインで表示したい！

# 行ったこと
1.お名前.comでドメインを購入。
2.Route53でホストゾーンを作成し、ネームサーバーをお名前.comからRoute53へ変更。
3.レコードセットを作成し、ドメインに紐づくIPアドレスを登録

# 起こった問題
AWSのコンソール、レジストラ側の設定が全て完了して、いざ取得したドメインで自分のサイトが開ける。と思ったが、Nginxのページが出てしまいアプリケーションへアクセス出来ない。
<img width="663" alt="スクリーンショット 2020-08-02 18.22.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652806/cc6948f4-6d41-d0f9-d974-125f8f7a02af.png">


# 対処
・Nginxの設定で新しいドメインのURLを明記する

EC2へログインして、

```
[ec2-user@ip-xxxx ~]$ sudo vim /etc/nginx/conf.d/rails.conf
```
```:rails.conf
upstream app_server {
  server unix:/var/www/<アプリケーション名>/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  # ここのElasticIPとなっている箇所を、
  server_name xxx.xxx.xx.xx; 
  # 取得したURLへ変更する
  server_name <取得したドメインのアドレス>; 


  client_max_body_size 2g;

  root /var/www/<アプリケーション名>/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}
```
最後にNginxを起動させて設定ファイルの変更を読み込ませる

```
[ec2-user@ip-xxxx ~]$ sudo systemctl start nginx
[ec2-user@ip-xxxx ~]$ sudo systemctl reload nginx
```
あとは、Capistranoを走らせるついでにUnicornを再起動したら、無事に自分のアプリケーションが開けました！
【Next.js】 getInitialPropsの備忘

## getInitialProps
↓公式
https://nextjs.org/docs/api-reference/data-fetching/getInitialProps

これはssrのときに使うって感じで書かれているんだけど、フロントのspa遷移時にも動くから注意。
というか、そっちのほうが使いやすかったりする。

```tsx
const Test = ({ kkkkk }) => {
return <div>{kkkkk}</div>
}

Test.getInitialProps = () => {
  console.log('ooooooooooo')
  return {
    kkkkk: 'pppppp'
  }
}

export default Test;
```
spa遷移のときとserverで処理を分けたいときには、window.browserを使えばいい。

```tsx
const Test = ({ kkkkk }) => {
return <div>{kkkkk}</div>
}

Test.getInitialProps = () => {
　if (window.browser) {
    console.log('window is not undefined')
    return 'bbbbb'
  }
  console.log('ooooooooooo')
  return {
    kkkkk: 'pppppp'
  }
}

export default Test;
```

## getServerSideProps
↓公式
https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering

これ関数名的にserverSideのときに渡すpropsを生成っぽい感じなんだけど、実際は違う。

この関数を定義したページは、Linkで遷移させたとしても、必ずサーバーを経由するようになる。

この関数名はやめてほしいです。。！

なので、reduxのstoreの参照とかができないので、そこらへんの使い勝手が若干悪い気がしている。

## まとめ
getInitialPropsは単純なSPA遷移ができて、storeを使えるので使っていきたい。

getServerSidePropsが推奨されているけど、必ずサーバー経由になっちゃってstore使えないのはちょっとやだねー。

なんか認識間違ってたら指摘してほしいーですー。
DevOps事始め

はじめまして、LinkedInでは書けない長文をこちらで書いていこうと思います。
## Aglie開発との出会いと崩壊
15年以上も前、米国でプロジェクト管理ソフトの開発をした際、チームリーダが当時Aglie開発に関してはかなり有名な人で、完全なAglie手法に沿って開発を行っていました。
- 少人数のアーキテクトによる完全な管理
- アーキテクトによる中長期のスケジュール管理と短期スケジュールのタスク化
- ホワイトボートに貼られた作業タスク
- 同じ人が重ならないように考慮されたペアプログラミング管理
- GUIモック専門のデザイナー
- アーキテクトとは明確に分けられ、ただコーディングするだけのプログラマ
- CIを活用した自動テスト
開発現場と言うより、作業効率向上を目的に管理された工場といった感じでした。

日本で当時はやっていた、なんちゃってアジャイルとは全く違い、プログラマはいつでも替えが効き、稼働状況に合わせて人数を増減できるようになっていました。
また、プログラマは問題を発見しても修正する権限は与えられず、アーキテクトへの報告のみを行う仕組みでした。
給料に関しても替えの効かないアーキテクトといつでも変更できるプログラマとは明確に違い、文字通り桁が違いました。

この方法はとても理にかなっていて、プログラマの質に左右されること無く、スケジュールを淡々とこなしていくことができました。
ただし、 **初期リリースまでの話** です。

この仕組の崩壊は早かったです。
Webサービスではなくプロダクトであったため、まだマシではありましたが、
- 新機能の開発
- 対応データベースやOSの追加
- バグフィックス
- パフォーマンス改善
- 顧客からの要望
と言った予め中長期計画の立てられない、タスクを起こしても急なバクフィックスで担当者がいない等の問題を引き起こし始めました。
最終的には、バグフィックスやパフォーマンス改善、スケジュールに載らない突発的な対応を行うチームと、新機能開発、対応OS追加等のスケジュール管理できるチームの2つに分けて対応することになりました。

当時かなりの混乱をきたしましたが、後から考えてみれば、DevOpsに近いことを試行錯誤してやり始めていたんだなと思うようになりました。

なんとか立て直し、やっていけるとなった所で、決定的な崩壊を起こします。
当時GoogleとAppleによる人材引き抜き合戦が加熱していました。
そして引き抜きの際、とんでもない権利が与えられていました。
**好きなメンバーを一緒につれてきて良い**
これによって、最も重要であるアーキテクトが大量にいなくなりました。
私も一応誘われましたが、当時は日本に居たかったので断りました(多分首を切られるのも最初でしょうし)

こうしてあっけなく開発は崩壊し、この後はアジャイル開発ではなく、グダグダなウォーターフォールと成り果てました…

## DevOpsとの出会い
その後、転職した私は独自でアジャイル開発、プロジェクト管理、CIなどを進めるため、社内向けに色々なツールを作りました。
しかしこれらはあくまで開発のためで、その後の運用とバージョンアップが考慮されていませんでした。
会社の業務も完全な縦割りで、開発と運用は別れ、リリースではたいてい喧嘩になりました。

なにか良い方法はないかなと模索していたところ、SRE(Site Reliability Enginieering)と言うキーワードに行き着き、DevOpsにたどり着きました。

これはいけると確信し、色々調査を進めましたが、数十人の会社ならともかく2000-3000人の会社で完全縦割り、そこで作業をするエンジニアも自分のテリトリを勝手に決めそれ以外はやらないと言う世界には全く相容れないものでした。
DevOpsそのものはWeb上にも本にも色々書かれているので省きますが、一番の要素は **各部門のコミュニケーション** にあると思っています。
これができない状態でツールを入れたり、推進部門を作ったりしても無意味です。

縦割りの構造が変わらないのは上層部にとってそれが一番管理しやすいからです。
そして、働く人達も自分のやるべき事がはっきりしているため働きやすく感じます。
この構造を変えるのはほぼ不可能ですので、私は逆のアプローチを検討し始めました。

それは **縦割り業務用DevOps** です。

今後順番に書いていきたいと思いますが、縦割りには縦割りの利点があります。
これを崩さずに開発と運用とリリースを上手く循環させる方法を考えていますが、まずは現状(開発と運用)の可視化だと思います。
自分たちのやり方がサービスにどんな悪影響を与えているのか分かれば対応は変わります。
ますはここを目指してやっていきます。
Rubyでクラスの継承を書く

<h3>親クラスで定義したメソッドを他の新規クラスで継承して使用する方法を書いていきます。</h3>


書き方は以下の通りです。

<h4>class 子クラス名 < 親クラス名</h4>
<h4>end</h4>


まずは、親クラスの例をみてみましょう。

class Mos
  def eat
    puts "食べる"
  end

  def drink
    puts "飲む"
  end

  def take_out
    puts "持ち帰り"
  end
end


次に継承した子クラスの例をみてみましょう。

class Mcdo < Mos  # クラスの継承
  def smile
    puts "笑顔無料"
  end
end




親クラスのメソッドは、<strong>継承した他のクラスでも使用</strong>できます。

| メソッド名 | Mos(親クラス) | Mcdo(子クラス) |
|:--|:--|:--|:--|
| eat | ◯ | ◯ | 
| drink| ◯ | ◯ |
| take_out | ◯ | ◯ |
| smile | × | ◯ |

上記の図をみてみると、親クラスのメソッドに記述したeat、drink、take_outを
子クラスに継承できていることがわかります。しかし、子クラスMcdoのメソッドであるsmileは親クラスのMos
には継承されていません。


つまり
class 子クラス名 < 親クラス名
end
のように記述することで親クラスのメソッドを他のクラスで継承させながら、新たなメソッドを
付け加えることができます。
【Unity：Debug】端末に繋いでデバッグする

Unity2020で端末に繋いでVSでデバッグする方法

検証：Unity2020.1

ビルドするときに画像の箇所にチェックを入れる
AndroidもiOSも同じ
![debugger_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/aaba1017-1084-91e8-32e2-5bce39375b5e.png)

あとはVSでPCで行うときみたいにアタッチするだけなんだけど
アタッチリストに端末が表示されない時があるので画像の「デバッグ > Unityデバッガーのアタッチ」で開くダイアログから繋いでる端末を選択
![debugger_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216261/5d5ce20c-1ce6-d44c-e93d-fa5d355307af.png)

これでブレーク張れるようになるのでデバッグが捗ります
【Flutter】BottomNavigationBarのitemが最大３つしか表示されない

#はじめに
画面の下部にナビゲーションメニューを置くのに`BottomNavigationBar`を使用した際、`BottomNavigationBarItem `が最大３つまでしか表示がされない問題に遭遇したので、解決方法を紹介したいと思います。

#解決方法
### BottomNavigationBarのtypeを設定する
```dart
BottomNavigationBar(
  // 3つ以上表示する場合はこの設定が必要となる
  type: BottomNavigationBarType.fixed,
)
```

typeを`BottomNavigationBarType.fixed`に設定する必要があったみたいです。
この設定が抜けていると`BottomNavigationBarItem`を3つより多く設定していても、最大3つまでしか表示されなくなってしまいます。
ITサービスマネジメントの改善ー午後

応用情報技術者令和元年秋期 午後問10

ファイル：2019r01a_ap_pm_qs.pdf　午後問10

メモです。

１、チームリーダが窓口となってサービス部に対応する目的は何か？
オペレータが繁忙していることを避けてシステムログ取得作業を遂行できるの目的
→
繁忙状況を踏まえて、適切なオペレータに作業を実施させるため

２、aに入れる適切な英語の字句を３字で答えよ
KPIとは、Key Performance Indicatorの略で、日本語に訳すと「重要業績評価指標」という意味になります。KPIとは目標を達成する上で、その達成度合いを計測・監視するための定量的な指標のこと。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/4a4e4167-ca2c-cd12-60ab-22cca7a7551e.png)


３、表１中の項番の改善内容について、インシデント発生の連絡遅延以外に、改善できる問題点は何か？品質の観点で、答えよ。
自動的に判断できないインシデントを集中に対応できる
→
オペレータによるインシデント発生の見落とし

４、S主任をサービス部から運用部に異動させた、S主任に期待している役割は何か？
改善活動の実施を徹底させたい
→
運用部に自主的な改善活動を根付かせる役割

本当は、自主的な。。。とは、私は見えませんね。。。

参照
KPI
https://www.kaonavi.jp/dictionary/kpi/#:~:text=KPI%E3%81%A8%E3%81%AF%E3%80%81Key%20Performance,%E7%9A%84%E3%81%AA%E6%8C%87%E6%A8%99%E3%81%AE%E3%81%93%E3%81%A8%E3%80%82
$ps $curl $top $grep $tail $findコマンドのメモ

- とあるきっかけで調べることになったのでちょいメモ。


# psコマンド

- ps (自分自身で実行したプロセスを表示する)
- ps -a (他のユーザが実行しているプロセスも表示する)
- ps -f (プロセスの親子関係が分かるように表示する. PPID = parent process id)

```
$ ps -f
  UID   PID  PPID   C STIME   TTY           TIME CMD
  501 12529 12524   0  9:46PM ttys001    0:00.26 /bin/bash -l
  501   441   440   0 Thu01PM ttys004    0:00.07 -bash
  501   456   450   0 Thu01PM ttys007    0:00.08 -bash
```

- ps -x (デーモンが実行したプロセスも表示する)

# curlコマンド

様々なプロトコルを用いてファイルを送受信するコマンドラインツール

- curl https://www.google.com/index.html (ダウンロードしたファイルを標準出力)
- curl -o output.html https://www.google.com/index.html
- curl -O https://www.google.com/index.html
  - = curl -o https://www.google.com/index.html https://www.google.com/index.html

HTTPS メソッドと対応するオプション(-X でメソッド指定。なかったら GET)

- GET: `curl https://example.com/get`
- POST(BODY を key-value): `curl -X POST https://example.com/post ーd 'key1:value1' -d 'key2:value2'`
- POST(BODY を json): `curl -X POST -H "Content-Type: application/json" -d '{"key1":"value1", "key2":"value2"}'`
  - json ファイルを使って body を指定する場合は`-d @input_file.json`を使う
- PUT/PATCH/DELETE: `-X PUT`や`-X PATCH`や`-X DELETE`を使う、あとは`-X POST`と同様。

その他調べていて学んだこと

- [DELETE に body を付ける事は GET 同様、仕様上禁止されていないのですが、 POST, PUT は content-length を付けることが必須なのに対して、 GET, DELETE は任意となっております。この仕様上、 content-length がリクエストパラメータに付与されていないことになると、多くのサーバでは GET/DELETE の際にどこまで body として読んだら良いのかわからないことがあります。このため、多くの web サーバでは GET/DELETE で body を付けることに対応していないことが多いです。](https://teratail.com/questions/68972)

# top コマンド

- 「top」は現在実行中のプロセスを CPU 利用率が高い順に表示する。表示はリアルタイムで更新されていき、「q」を入力すると終了する。

# tailコマンド
- `tail ファイル名`(指定ファイルの最後の最後10行を表示)
- `-c 5`で最後5文字、`-n 5`で最後5行を表示、といった形で指定できる。
- `-f`でファイルの更新をリアルタイム追跡できる


# grep コマンド

ファイルの中の特定の文字列を正規表現を使って検索し表示するコマンド。

- `grep 検索文字列 ファイル名 -n` (ファイル内で検索文字列を含む行を行番号付きで標準出力)
- `grep 検索文字列 ディレクトリ名/* -n` (ディレクトリ内の全てのファイルについて、同上)

その他のオプション

- -i (大文字小文字を区別しない)

# findコマンド

- `find ディレクトリ名 -name ファイル名の正規表現` (ディレクトリ内で与えられたファイル名を持つものを標準出力)


# sedコマンド

- `sed s/置換前の文字列/置換後の文字列/ ファイル名` (指定されたファイルに出現した指定文字列を置換して標準出力)
- `sed -i “_backup” “s/置換前の文字列/置換後の文字列/” ファイル名`(指定されたファイルを置換して上書きし、尚且つ`ファイル名_backup`というバックアップファイルを作る

## findとsedを組み合わせて特定のファイルの中を置換処理
- `find test -name '*.txt' | xargs sed -i 'backup' 's/a/v/'`
ストロングパラメータとは何か？なぜ使うのか、どんな時にどのように使うのか？(Ruby)

**注意**
プログラミング初学者の記事のため、間違いがある可能性があります。
もし気づいたことやわかりにくい部分があれば、ご指摘いただけると非常に嬉しいです。

# この記事を読むとわかること
ストロングパラメータとは何か、なぜ使うのか、どんな時にどのように記述して使うのか。

目次
1.[ストロングパラメータとは？](#a1)
 1-1.[なぜ使う必要があるの？](#a1-1)
 1-2.[どんな時に使う？](#a1-2)
2.[ストロングパラメータを記述してみる](#a2)
 2-1.[基本構文](#a2-1)
 2-2.[requireメソッド](#a2-2)
 2-3.[permitメソッド](#a2-3)
[まとめ](#sum)

## 1.ストロングパラメータとは? <a id=a1></a>
formなどで送信されるパラメータを指定し、取得できる値を制限したもの。
データ送信によるセキュリティを高めるための仕組み。
具体的にはフォームから送られる情報を制限し、意図しないデータを受け取らないようにすることでセキュリティを高めています。
なぜセキュリティが高まるのかについては1-1にて合わせて記述します。
### 1-1. なぜ使う必要があるの?<a id=a1-1></a>
意図しないデータが誰でも遅れるような状態になってしまうから。

**意図しないデータが送られると困ることあるの？**
例えば、名前とメールアドレスをフォームに入力してデータベースに登録する。
という操作を行った時に、名前とメールアドレス以外にもいろいろなデータを送信されています。
管理者権限を識別する値などもこのフォームから送信されているため、どんなユーザーでも管理者権限を持てるようになってしまいます。
そのため、ストロングパラメータで送信する値を制限する必要があります。

**管理者権限とは**
管理者＝アプリのメンテナンス係
権限＝許可をもっているか否か

つまりストロングパラメータで送信するパラメータを制限しておかないと、あらゆる人が管理者権限を持つ（自由にいじれちゃう）ことができるようになります。
その結果、誰でもアプリを管理することができるという事態が起こりえるということです。
こういった状況を回避するためにストロングパラメータで受信できるパラメータを制限しておく必要があります。

### 1-2. どんな時に使う？<a id=a1-2></a>
実際にどんな場合にストロングパラメータを設定しておく必要があるか。
・投稿フォームのようなフォームからデータを送る時
・データの登録を行う時
・もともとあるデータの更新を行う時
パラメータ自体がHTTPメソッドのGET,POSTが行われる時に送信されるので、上記のような場合になります。
## 2. ストロングパラメータを記述してみる<a id=a2></a>
### 2-1. 基本構文<a id=2-1></a>
コントローラーのprivate以下に記述する。
メソッド名は一般的に```[モデル名_params]```とするようです。
今回は```[tweet_params]```としました。

```
private
def tweet_params
  params.require(:tweet).permit(:image, :text)
end
```

Tweetモデルのimageカラムとtextカラムの値をストロングパラメータとする。
### 2-2. requireメソッド<a id=a2-2></a>
requireメソッドはparams内の特定のキーを引数として指定することで、そのキーに紐づく値を抽出することができます。
今回はrequireに引数として指定されているtweetがキーとなります。

**キーはどこの値をとる？**
viewファイル上でform_withメソッドを使用した場合、
1行目にmodelとして指定されている@tweetがrequireで指定するキーになります。


```
    <%= form_with(model: @tweet, local: true) do |form| %>
　　　 <%= form.text_field :name, placeholder: "Nickname" %> 
      <%= form.text_field :image, placeholder: "Image Url" %>
      <%= form.text_area :text, placeholder: "text" %>
      <%= form.submit "SEND" %>
    <% end %>
```

どうして@が外れるかはわからないので、ご存じの方いましたらコメントをお願いします。

### 2-3. permitメソッド<a id=a2-3></a>
permitメソッドは許可された値を指定し、その値のみを取得できるようにするメソッドです。
permitメソッドの引数に、登録を許可するカラム名をすべて指定する必要があります。
ここに記述のないパラメータについてはデータが取得されません。

```
  params.require(:tweet).permit(:image, :text)
```
Tweetモデルに存在するimageとtextカラムのみ取得が許可されている状態です。
```form_with``` メソッドの中に:nameのカラムがありますが、ここでは指定されていないため:nameの値は取得されないということになります。

##まとめ<a id=sum></a>
ストロングパラメータは送信するデータのセキュリティを高めるために使われる仕組み。
ストロングパラメータを指定しないと、意図しないデータが取得、送信されてしまう。
そのため送信フォームなどにおいては指定する必要がある。

基本構文

```
params.require(:モデル名).permit(:カラム名1, :カラム名2)
```
**モデル名は小文字スタート**

以上のように指定したカラムのデータがストロングパラメータとなり、取得できる値となる。
ここで指定しない値については取得が行われない。
[rails]画像の投稿方法

#画像投稿方法
画像の投稿方法はこんな感じの手順です。

・refileをgemfileに追加
・image_idカラムを追加
・attachmentメソッドを追加する
・Strong Parametersにimage_idを追加する
・viewファイルにf.attachment_fieldを埋め込む

###1.refileをgemfileに追加
refileの役割
・画像を簡単に組み込むことができる。
・サムネイルを生成できる。
・ファイルのアップロード先を設定できる。

refile-mini-magickは画像をサイズを変更するためのgemです。

```
# 画像投稿用gem
gem "refile", require: "refile/rails", github: 'manfe/refile'
# 画像加工用（サイズ調整など）gem
gem "refile-mini_magick"
```

bundle installは忘れずに。

```
$ bundle install
```

###2.image_idカラムを追加
Userテーブルにimage_idカラムを追加します。

```
$ rails g migration AddImageIdToUsers image_id:string
```

これも忘れてはいけません。
$ rails db:migrateでデータベースに反映。

```
$ rails db:migrate
```

###3.attachmentメソッドを追加する
Refileを使うには、attachmentメソッドをモデルに追加する必要があります。
attachmentメソッドとは、refileが指定のカラムにアクセスするために必要です。
これによりDBに存在する画像を取得したりアップロードが可能となります。
カラム名はimage_idですが、ここでは_idは不要です。

```app/models/user.rb
class User < ApplicationRecord
  attachment :image
end
```

###4.Strong Parametersにimage_idを追加する


```
class UserController < ApplicationController
  #省略

  private
  def list_params
    params.require(:user).permit(:name, :email, :image)
　end
end
```

###5.viewファイルにf.attachment_fieldを埋め込む
次に画像を投稿するページに以下の通り、記述します。

```
<%= f.attachment_field :image %>
```
AutoMLのライブラリに関する私的メモ

# はじめに

AutoMLのオープンソースソフトウェア（OSS）をいくつか調べて見ましたが、何がどういう特徴があったか一度整理して見たいと思い、簡単に表にまとめてみます。
対象としては、構造化データを対象にしたAutoMLツールで、DeepLearning特化のライブラリを除いています。また、論文などで主に取り上げられているツールを対象にしています。

表の内容は、論文やドキュメントベースの机上調査の場合もあれば、実際に触って見て知った内容も混合しています（レベル感などもテキトーです）ので、ご了承ください。あくまで個人的なメモ程度です。

~~2020年8月2日時点の情報をもとにしています。~~
常に最新情報に保つというわけではないですが、気が付いたときに更新します。

2021年3月3日に更新しました。

# まとめの表

| OSS | 開発元 | URL | 特徴など| メモ | 自分の投稿 |
|:---|:-----|:---|:---|:---|:---|
|Auto-sklearn | Freiburg-Hannover.orgなど | https://www.automl.org/automl/auto-sklearn/ <br> https://papers.nips.cc/paper/5872-efficient-and-robust-automated-machine-learning.pdf| - Pythonで使用可能 <br> - アルゴリズムはsklearnで使用できるもの | 2020年7月8日にAuto-sklearn2.0の論文が公開 |https://qiita.com/dyamaguc/items/b7b8e8b0c952a53c31ab|
|H2O | H2O.ai社 | http://docs.h2o.ai/h2o/latest-stable/h2o-docs/automl.html | - GUIとAPIによる操作が可能 <br> - 表の結合、欠損値保管、ターゲットエンコーディングなども可能 <br> - アルゴリズムはDeepLearningやXGBoostも含む（LightGBMはない）| 2021年3月3日時点でversion 3.32.0.4が最新。 | https://qiita.com/dyamaguc/items/84868e2e4e656e61a7c2 |
|TPOT |  Computational Genetics Lab at the University of Pennsylvaniaなど | https://github.com/EpistasisLab/tpot <br> https://arxiv.org/abs/1603.06212 | - コマンドラインとpythonで使用可能 <br> - 前処理でPCAなども実行 <br> - scikit-learnで使えるようなアルゴリズム+XGBoost+NN| 2021年3月3日時点でv0.11.7が最新 | - |
|AutoGluon | Amazonなど | https://autogluon.mxnet.io/ <br> https://arxiv.org/pdf/2003.06505.pdf | - Pythonで使用可能 <br> - 表形式データだけでなく、画像やテキストの分類などもできる <br> - アルゴリズムはsklearnで使えるようなアルゴリズム+LightGBM+NNという感じ | 2021年3月3日時点でv0.1.0が最新 <br> v0.1.0でAPIがリファクタリングされた。XGBoostをサポート。多ラベル予測など新機能が追加。 |https://qiita.com/dyamaguc/items/dded739f35e59a6491c8 <br> https://qiita.com/dyamaguc/items/19c977bf1536df9d0f99 |
|PyCaret| (調査中) | https://pycaret.org/ <br> https://github.com/pycaret/pycaret | (調査中) | 2021年3月3日時点でversion 2.3.0が最新 | - |
|Auto-WEKA | University of British Columbiaなど | http://www.cs.ubc.ca/labs/beta/Projects/autoweka/ <br> https://github.com/automl/autoweka| (調査中) |2017年4月で開発が止まっている | - |
|Hyperopt-sklearn | (調査中) | https://github.com/hyperopt/hyperopt-sklearn | (調査中) | 2021年3月3日時点でv0.0.3が最新（開発自体はほとんど止まっている） | - |
WSLでyarnをインストールしようとしたらgpgのエラーが発生した

# TL;DR

WSLでyarnをインストールしようとしたら、gpgに関連したエラーが2つ出ました。
原因や原理はわかりませんが、それぞれネットの情報を参考にしたら解決できました。

## エラーその1： `gpg: can't connect to the agent: IPC connect call failed`

gpgをinstallし直して解決しました。

```bash
apt remove gpg
apt install gnupg1
```

## エラーその2： `apt-key gpg no valid OpenPGP data found`

apt-keyをいったんファイルにして追加することで解決しました。

```bash
curl -O -fsSL https://download.docker.com/linux/debian/gpg
sudo apt-key add gpg
```

# 環境

Windows10
WSL Ubuntu20.04
nvmを使ってnodeをインストール済

# 詳しく

[Webサイト高速化のための 静的サイトジェネレーター活用入門](https://ebisu.com/gatsbyjs-book/)という本のために、
WSL上に環境を構築しているときに発生しました。

[書籍に付属していた開発環境用の資料](https://github.com/ebisucom/gatsbyjs-book)と最新のyarnのインストールが若干違ったので、[yarnの公式ページ](https://classic.yarnpkg.com/en/docs/install#debian-stable)の内容を参考に実施しました。

## エラーその1

公式サイトに従って、WSLで以下のコマンドを実行すると

```bash
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
```

エラーその1が発生

```shell-session
gpg: can't connect to the agent: IPC connect call failed
```

> gpg、別名は「Gnu Privacy Guard」「GPG」「GnuPG」である。
>
> これは、公開鍵でファイルの署名を検証したり、公開鍵と秘密鍵のペアでメール> の暗号化・復号化を行ったり署名を添付したりするツールである。

もしくは

> 通常，Linux環境では自分が意図した作成者が作ったソフトであるか、
> 使うインストーラーが本物である事を検証（身元が正しいかどうか）してからインストールします．
> このとき，ソフトウェアの検証に使用される仕組みの一つがgpgです．

とのこと。
解決方法は以下のようにインストールし直す。

```bash
sudo apt remove gpg
sudo apt install gnupg1
```

## エラーその2

gpgをインストールし直したので、再びyarnのインストールを実行

```bash
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
```

しかし、エラーその2が発生

```shell-session
gpg: no valid OpenPGP data found.
```

apt-keyをいったんファイルにして追加することで解決。

```bash
curl -O -fsSL https://download.docker.com/linux/debian/gpg
sudo apt-key add gpg
```

以下のように出力されたので、良さそう。

```shell-session
OK
```

> apt-key は、apt が パッケージを認証するのに使用するキーの一覧を管理するのに使用します。このキーで認証されたパッケージは、信頼するに足ると見なせるでしょう。

さきほどインストールし直したgpgには公開鍵が含まれていないので、公開鍵を取得してそれを使ってインストールしようとしているパッケージ（この場合はyarn）を認証しようとしているらしい？


## yarnのインストール

三度目の正直

```bash
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
```

以下の出力が返ってきたので、問題なさそう。

```shell-session
deb https://dl.yarnpkg.com/debian/ stable main
```

あとは公式サイト通りに実行

```bash
sudo apt update && sudo apt install yarn
```

```bash
sudo apt update && sudo apt install --no-install-recommends yarn
```

インストールの確認！うまくいきました。

```bash
yarn -v
```

```shell-session
1.22.4
```

# 参考

- [WSLでdockerをinstallするときにハマった話 - Qiita](https://qiita.com/obukoh/items/416c4cb1b88261bf3357)
- [apt-key gpg no valid OpenPGP data found - Yanor.net](https://yanor.net/wiki/?Linux/%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8/Debian/apt-key%20gpg%20no%20valid%20OpenPGP%20data%20found)
- [GPGについて学んだことを整理してみる - Qiita](https://qiita.com/y518gaku/items/435838097c700bbe6d1b)
- [Ubuntu Manpage](http://manpages.ubuntu.com/manpages/trusty/ja/man8/apt-key.8.html)