OmniAICreator/Qiita-1.07M huggingface dataset:
SeleniumとHeadless ChromeでページをPDFに保存する

[以前の投稿](https://qiita.com/mochi_yu2/items/d1a2c91776eba93c25e5)で利用した[Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)を活用して、Seleniumで表示したページをPDFに保存します。

```python:cdp-pdf.py
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
import base64

def save_to_pdf(driver, file_path):
    parameters = {
        "printBackground": True, # 背景画像を印刷
        "paperWidth": 8.27, # A4用紙の横 210mmをインチで指定
        "paperHeight": 11.69, # A4用紙の縦 297mmをインチで指定
        # "displayHeaderFooter": True, # 印刷時のヘッダー、フッターを表示
    }
    # Chrome Devtools Protocolコマンドを実行し、取得できるBase64形式のPDFデータをデコードしてファイルに保存
    pdf_base64 = driver.execute_cdp_cmd("Page.printToPDF", parameters)
    pdf = base64.b64decode(pdf_base64["data"])
    with open(file_path, 'bw') as f:
        f.write(pdf)

options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-gpu')

# Webdriver ManagerでChromeDriverを取得
driver = webdriver.Chrome(
    executable_path=ChromeDriverManager().install(),
    options=options
)

driver.get('https://qiita.com/')
save_to_pdf(driver, 'qiita.pdf')

driver.close()
driver.quit()
```

- [Page.printToPDF](https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF)というメソッドでPDFを出力します。
- Headlessでなく普通にブラウザを立ち上げる状態(非Headless)で試すと、`{"code":-32000,"message":"PrintToPDF is not implemented"}`というエラーになりました。
  - [Puppeteer](https://pptr.dev/#?product=Puppeteer&version=v9.1.1&show=api-pagepdfoptions)（Chrome DevTools Protocolを介してHeadless Chromeを操作するNode.jsライブラリ）のドキュメントの情報によると、現在、PDFの生成はHeadless Chromeのみのサポートのようです。
  - Headlessでない状態でのPDF作成は、以下の記事の内容で実現できそうです。  
    　[PythonのSeleniumでログインありのwebページをPDF保存する - Qiita -] (https://qiita.com/kuro227/items/838b9bab231902e280d4)
- 長さを指定する際の単位はインチ（1 in = 25.4 mm）のようです。A4サイズ(210mm X 297mm)となるように指定しましたが、生成されたPDFの情報を見るとぴったりにはならずに微妙に違っていました。
- `headerTemplate`、`footerTemplate`というパラメータでヘッダ・フッターのデザインを変えることができます。こちらはVSCodeでmarkdown → PDF変換を行う[markdown-pdf](https://github.com/yzane/vscode-markdown-pdf)という拡張機能に関する情報が役立つかもしれません。
  - 参考: [VSCode markdown-pdf でヘッダーやフッターをいい感じに設定する](https://mseeeen.msen.jp/vscode-markdown-pdf-v1-header-footer-settings/) 


# 参考
- [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)
- [PuppeteerのちょっとしたTipsいろいろ](https://yurufuwa-tech.hatenablog.com/entry/2019/02/05/235444)
1から1000までのフィボナッチ数列を排出するプログラム[ruby] pop / shift / delete_atメソッド

コーディングテストで学びの多かった問題に出会えたので、この記事を通して復習を行いたいと思います。

## 問題

```
1から1000までのフィボナッチ数列を出力するアルゴリズムを作成する。
フィボナッチ数列とは、最初の二つの数字が1で、三つ目以降がすべて直前の二つの数字の和になっている数列。
例) 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…
```

## 回答 (初期)

```ruby
answers = [1, 1]
while answers.last < 1000 do
  answer = answers.reverse[0] + answers.reverse[1]
  answers.push(answer)
end
puts answers
```

## 解答 （復習後)

```ruby
answers = [1, 1]
while answers.last < 1000 do
  answers.push(answers[-1] + answers[-2])
end
answers.pop
puts answers
```

## 学び

以下にリファクタリング際に学んだメソッドをまとめます。
その際に、配列として`array = [1, 10, 100, 1000, 10000]`を具体例として扱う

### 配列の要素のマイナス指定

```ruby
array[-1] #=> 10000
array[-2] #=> 1000
```

### popメソッド

```ruby
array.pop #=> 10000
array #=> [1, 10, 100, 1000]
# または
array.pop(2) #=> 1000, 10000
array #=> [1, 10, 100]
```

指定した数字分要素を後ろから削除する。ただ`popメソッド`の返り値はあくまで、削除した要素。

### shiftメソッド

```ruby
array.shift #=> 1
array #=> [10, 100, 1000, 1000]
# または
array.shift(2) #=> 1, 10
array #=> [100, 1000, 1000]
```

指定した数字分要素を先頭から削除する。ただ`shiftメソッド`の返り値はあくまで、削除した要素。

### delete_at (数字) メソッド

```ruby
array.delete_at(2) #=> 100
array #=> [1, 10, 1000, 1000]
```

指定したインデックスの要素を削除する。ただ`delete_atメソッド`の返り値はあくまで、削除した要素。


今回の記事は以上です！！
最後まで目を通していただきありがとうございました！！
Python初心者の備忘録

#Jupyter-notebookの拡張機能を導入する
「Nbextensions」をする。「Hinterland」がいいらしいので使えるようにした。TABキーを使わなくても予測変換が使用できる。

#Jupyter labにkiteを導入する
kiteはAIで必要なコードを補正してくれる。https://teratail.com/questions/320701 を参考にしたらうまくいった

#Pythonを勉強していてわかったこと(Jupyter-notebook利用)

・関数単独で使うことができる。変数に代入しなくても良かった（a =　hello()を入れなくていい）

```Python
def hello():
    return "hello"

print(hello())
```

・リストの並び替えでsort()は破壊、sorted()は非破壊

```python
list1 = [1,3,2]
print(sorted(list1))#一時的に保存している
print(list1)#なのでlist1はそのまま
print(list1.sort())#list1を変更してしまう
print(list1)#list1の並び順が変わってしまった。
```

・イテラブルとは「要素を順番に取り出せること」
ディジタル技術者試験 【2級 情報部門】 解説

ディジタル技術者試験の試験勉強に当たり自分が疑問に思った問題の解説をざっくりと理解できるように記載します。
※マイナーな試験なのか、あまり参考になる記事が存在してなかったので、
　強引な解説があるかもですが、あくまで参考程度にご覧ください。
※問題については、公式HPで詳しく見てください。

__第６１回 2級情報部門__

__(1)-(イ)：回路の特性を特殊加法標準形で表したときに最小港として含まれないものはどれか。__
まず、「特殊加法標準形ってなんぞ？」となったので、調べてみましたがヒットせず、、
しかし、似た言葉で主加法標準形と言うものがありました。(多分同じ考え方で行けるだろうと判断。)
その__主加法標準形__とは・・・？
→主加法標準形：最小項(どれか1つの組み合わせに対してZが１になる関数で、A・B・Cを1つずつ含む論理積)の論理和である。

例えば、下図の様な真理値表があった場合、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1165599/c5bf1229-8ee4-63be-2207-c44f30867bb5.png)
Zが1になる最小項のパターンは、
「A=0 B=1 C=1」
「A=1 B=0 C=1」
「A=1 B=1 C=0」
「A=1 B=1 C=1」
↑の４パターンになる。

主加法標準形ではこの最小項の論理和を求めるので、
答えは、__‾A・B・C＋A・‾B・C＋A・B・‾C＋A・B・C__
となります。
実際に回答を確認したところ、上記の考えて正解が導き出せました。
なので、「特殊加法標準形＝主加法標準形」の考え方で問題ないと思ってます。

※ルールか知りませんが、0は‾Aで表し、1はAで表すらしいです。
　‾はバー(否定)を表してます。
Amplifyクラスのコンストラクタが見つからない

# 現象
以下のページを参照しつつ、Flutter + AWS Amplifyの環境を構築していたら、
手順書通りにやっているのに、Amplifyのコンストラクタが見つからないって言われる。

https://aws.amazon.com/jp/getting-started/hands-on/build-flutter-app-amplify/

- 実際のコード

```dart:main.dart
  // こいつがエラーになる
  final _amplify = Amplify();
  final _authService = AuthService();
```

-  エラー内容

**The method 'Amplify' isn't defined** for the type '_MyAppState'.
Try correcting the name to the name of an existing method, or defining a method named 'Amplify'.


# 解決
以下の二点が手順書間違い。

0. Amplifyのライブラリ[amplify_core]を[amplify_flutter]に変更する。
0. 
```yaml:pubspec.yaml
  # amplify_core: '<1.0.0'
  amplify_flutter: '<1.0.0'
```

0. Amplifyは静的クラスとなっているので、インスタンス作らなくて良い。

```dart:main.dart
  // 削除
  // final _amplify = Amplify();
  final _authService = AuthService();


  ～～


  // 変更
  // await _amplify.configure(amplifyconfig);
  await Amplify.configure(amplifyconfig);
```

これでビルドエラーは消えました！
numpyとmatplotlibによる半波長ダイポールアンテナのE面指向性利得の描画

# おことわり
この記事は，アンテナの基礎的な用語をはじめとした，アンテナの基本事項に関する説明はしておりません．

# 目的・やること
半波長ダイポールアンテナの角度$\theta$に対するE面指向性利得(単位:dBi)の図を，numpyとmatplotlib.pyplotを使用して極座標形式で描画する．

# 理論・前提知識

## 半波長ダイポールアンテナのE面指向性
角度$\theta$に対する半波長ダイポールアンテナのE面指向性$D(\theta)$は，
$$ D(\theta) = \frac{\cos\left (\frac{\pi}{2}\cos{\theta} \right)}{\sin{\theta}} $$
をプロットすることで得ることができます．
これをnumpyを用いて実装します．

## numpyによる実装方針
numpyで実装する場合には，できるだけfor文等の**ループを使用せずに**実装します．
ここでは，numpyによる半波長ダイポールアンテナの角度$\theta$に対する半波長ダイポールアンテナのE面指向性$D(\theta)$の計算を取り上げます．

まず，$0<\theta < 2\pi$の範囲の角度ベクトルを用意します．角度$\theta$の間隔は各自で決めていただいて問題ありませんが，今回は0.01ずつとします．

```python
theta = np.arange(0.01, 2*np.pi, 0.01)
````

続いて，$D(\theta)$の通りに実装を行います．このときsinとcosを計算する際にnumpyの関数を使用します．そうすることでループを使用せず角度$\theta$の各値に対していっぺんに計算を行うことができます．

```python
def HW_dipole_np(theta):
    """
    角度ベクトルtheta(ndarray)に対して半波長ダイポールアンテナのE面指向性値ベクトル(ndarray)を返す．
    """
    return np.abs(np.cos((np.pi/2.0) * np.cos(theta)) / np.sin(theta))
```

なお，ここでは指向性図の描画のために$D(\theta)$の絶対値をとっています．

## 指向性(真値)から指向性利得[dBi]を得る
角度$\theta$に対する受信電界強度$|E(\theta)|$が，$|E(\theta)|=|D(\theta)|$~~という超絶好条件~~であると仮定すると，指向性$D(\theta)$から指向性利得[dBi]を得ることができます．
まず，受信側アンテナの開口面積を1と仮定した上で受信電力(単位:dBm)を以下の式
$$
P(\theta) = 10\log{\left(1000 \times \frac{|E(\theta)|^2}{120\pi}\right)}
$$
で計算します．$|E(\theta)|=|D(\theta)|$であるので，先程の計算結果をそのまま使用できます．
続いて，計算した受信電力をdBi値(絶対利得)に換算します．半波長ダイポールアンテナの絶対利得は2.15[dBi]であるので，受信電力の最大値$P_{max}$[dBm]$=2.15$[dBi]となるように値を修正します．具体的には各角度での受信電力$P(\theta)$[dBm]に対して，
$$
P(\theta)\mathrm{[dBi]} = P(\theta)\mathrm{[dBm]} + (2.15 - P_{max})
$$
と計算してやります．
以上から，指向性(真値)より指向性利得[dBi]を得ることができます．


## matplotlib.pyplotによる極座標グラフの描き方
matplotlib.pyplotで極座標(偏角$\theta$に対する大きさ$r$)のグラフを描くには，subplotの引数`projection`に対して`polar`を渡します．

```python
ax = plt.subplot(111, projection="polar")
ax.plot(theta, r)
plt.show()
```



# ソースコード全体

```python
#coding: utf-8

import numpy as np
import matplotlib.pyplot as plt


def HW_dipole_np(theta):
    """
    角度ベクトルtheta(ndarray)に対して半波長ダイポールアンテナのE面指向性値ベクトル(ndarray)を返す．
    """
    return np.abs(np.cos((np.pi/2.0) * np.cos(theta)) / np.sin(theta))

def to_dBi(d_real, dBi=2.15):
    """
    指向性d_real(真値)の絶対値=電界強度であると仮定し，d_realから指向性利得[dBi]を得る．
    """
    #受信電力[dBm]を計算
    PdBm = 10 * np.log(1000 * np.power(d_real, 2) / (120*np.pi))
    #角度に対する最大受信電力が2.15[dBi]となるように受信電力を変換して返す．
    Pmax = np.max(PdBm)
    return PdBm + (dBi - Pmax)

def plotd(theta, d):
    """
    角度thetaに対する指向性dを極座標形式で描画する．
    """
    ax = plt.subplot(111, projection="polar")
    ax.plot(theta, d)
    plt.show()


if __name__=="__main__":
    theta = np.arange(0.01, 2*np.pi, 0.01)
    D = HW_dipole_np(theta)
    plotd(theta, D) #指向性(真値)を描画
    plotd(theta, to_dBi(D)) #指向性利得[dBi]を描画

```

# 実行結果
角度$\theta$に対する指向性(真値)の描画結果は以下の通りとなりました．
![HW_dipole_real.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183396/93a4b65c-92a5-9be6-1210-1533ad6e900f.png)


また，角度$\theta$に対する指向性利得[dBi]の描画結果は以下の通りとなりました．
![HW_dipole_dBi.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183396/cd410686-687e-349b-1cc9-fb37831d46f4.png)
[SwiftUI] sheet modifierは1つしか持つことができないらしい

# やりたいこと
- NavigationBarItemとFloating action buttonでそれぞれシートをpresentする

# とりあえず実装してみた
Boolの`@State`を2つ`sheet` modifierを２つ並べとけばええやろ

```swift
struct SomeView: View {
    @State private var isScheduling: Bool
    @State private var isSharing: Bool

    var body: some View {
        VStack(alignment: .leading) {
            // ...

            // fab
            HStack {
                Spacer()
                Button {
                    isScheduling.toggle()
                } label: {
                    Image(systemName: "plus")
                        .foregroundColor(.white)
                        .font(.title2)
                        .shadow(radius: 3)

                }
                .frame(width: 60, height: 60)
                .background(Color.primary)
                .cornerRadius(30.0)
                .shadow(color: .gray, radius: 3, x: 0, y: 0)
                .padding(.bottom, 16)
            }
        }
        .navigationBarItems(trailing: Button {
            isSharing.toggle()
        } label: {
            Image(systemName: "person.badge.plus")
        })
        .sheet(isPresented: $isScheduling) {
            ScheduleView()
        }
        .sheet(isPresented: $isSharing) {
            ShareView()
        }
    }
}
```

## 問題点
- これだと後から宣言されたmodifier（ここではshareの方）だけが生きて、先に宣言した方は死ぬ
- どうやらViewは**ひとつの`sheet` modifierしか持つことができないらしい**


# 改善
```swift
struct SomeView: View {
    private enum ActiveSheet: Identifiable {
        case schedule
        case share

        var id: Int {
            hashValue
        }
    }

    @State private var activeSheet: ActiveSheet?

    var body: some View {
        VStack(alignment: .leading) {
            // ...

            // fab
            HStack {
                Spacer()
                Button {
                    activeSheet = .schedule
                } label: {
                    Image(systemName: "plus")
                        .foregroundColor(.white)
                        .font(.title2)
                        .shadow(radius: 3)

                }
                .frame(width: 60, height: 60)
                .background(Color.primary)
                .cornerRadius(30.0)
                .shadow(color: .gray, radius: 3, x: 0, y: 0)
                .padding(.bottom, 16)
            }
        }
        .navigationBarItems(trailing: Button {
            activeSheet = .share
        } label: {
            Image(systemName: "person.badge.plus")
        })
        .sheet(item: $activeSheet) { item in
            switch item {
            case .schedule:
                ScheduleView()
            case .share:
                ShareView()
            }
        }
    }
}
```

これで2つのsheetがpresentできるようになる
あとすっきりした

---
2021/5/9　追記

一つの子Viewに対しては1つ以上の`sheet`や`fullScreenCover`は持てないが、別のViewに持たせてしまえばいくらでも追加できた


### 参考
https://stackoverflow.com/questions/58837007/multiple-sheetispresented-doesnt-work-in-swiftui
VSCodeとGitHubの連携について

# 初めに
環境設定......なにそれおいしいの？
そんな自分が出会った，やらなければいけない事orzについて，備忘録として記載していきます．
（文章力が無いので読みづらい場合はすいません...）

本稿では，VSCodeとGitHubの連携について記載していきます．
ここで，GitHubに関しては，プライベートのリポジトリを用いております．

## 参考記事について
以下の記事が凄く分かりやすかったです．
参考：[【初心者向け】VSCodeとGithubの連携 for Windows ～連携操作からプッシュまで～](https://breezegroup.co.jp/202102/vscode-github-windows/)

ただし，ここで用いられているリポジトリは公開用でしたので，本稿では，非公開用のリポジトリとの連携について記載できればと思います．

# GitHubとの連携
上記記事を参考に非公開用（Private）のリポジトリを作成したことを前提に話を進めます．
非公開用のリポジトリを作成した場合，以下の引用文のところで躓きます．

> 連携後にVSCodeに戻って「リポジトリのクローン」をクリックします。
再度「GitHubから複製」をクリックすると作成したリポジトリが表示されます。

あれ？作成したリポジトリが表示されないよ？ってなった方は，読み進めてください．

非公開用のリポジトリを作成した場合，そのリポジトリは他の人から見えてはいけないので，本人確認を行う必要があります．
そこで，SSH接続を用いてVSCode君がGitHub君の家にいつでも入れる鍵を作ります．
これにより，VSCodeを開くだけでGitHubと常に連携する関係を構築出来ました．
（因みに，毎回本人確認——つまりログインすればいいのかもしれませんが，その方法は調べていないので分かりません）

## SSH接続
早速，SSH接続をしていきます．
...と説明したいところですが，参考にした記事が分かりやすいので，そちらをご覧ください．
参考：[VSCode – GitHubにSSHで接続する](https://www.premium-tsubu-hero.net/technology/it/visual-studio-code/vscode-github-ssh-connection/)

# 最後に
ただただ参考にした記事を載せただけになってしまった...
もしマナー違反であったり，規則違反であれば教えて頂けると幸いです．

ということで，次回は...まだ決まっていません．
やっと今までやってきたことに記事が追い付いたので，今後はもっと画像を交えて記載できたらなぁと思います．
一時的にプロンプトをシンプルにしたいとき

#### 実行コマンド

```zsh
$ PROMPT='$ '
```

#### 戻す際のコマンド( [zsh](https://ja.wikipedia.org/wiki/Z_Shell)を利用の場合 )

```zsh
$ source ~/.zshrc
```

※環境によって `$ source ~/.bash_profile` など柔軟に対応ください
javascriptを使わずカテゴリ別に表示させる

#はじめに
クチコミサイトを作成している中で、登録商品をカテゴリ別に表示させたいなーと思い、実装しましたのでその過程を残しておこうと思います。
ページ遷移させず表示するにはjavascriptの知識が必要ということで、今回はページ遷移させて表示させていきます。
こんな感じです。
![GIF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/f2e96f2c-12d3-7319-f6a3-977c352124f0.gif)




#実装
今回の流れは以下のようになります。
①categoryモデルの作成。
②itemモデルとcategory_idを紐づける。
③アイテム一覧のページでカテゴリを選択した際に、カテゴリーコントローラーのインデックスアクションに飛ぶように設定。
④カテゴリーのインデックスアクションで、category_idに紐づいているアイテムを表示。


①categoryモデルの作成。
今回は各itemにcategoryが紐づく形にしたいので、categoryモデルを作成します。

```
$ rails g migration AddCategoryToItems category:reference
```
そして作成されたファイルに以下のように記述します。

```ruby:日付_add_category_to_items.rb
class AddCategoryToItems < ActiveRecord::Migration[5.2]
  def change
    add_reference :items, :category, foreign_key: true
  end
end
```

②itemモデルとcategory_idを紐づける。
itemモデルとcategoryモデル内にbelong_toとhas_manyを追記する。

```ruby:models/item.rb
class Item < ApplicationRecord
   belongs_to :category, optional: true
end
```

```ruby:models/category.rb
class Category < ApplicationRecord
    has_many :items
end
```

③アイテム一覧のページでカテゴリを選択した際に、カテゴリーコントローラーのインデックスアクションに飛ぶように設定。
次にカテゴリ別に表示したいページにてリンクを作成する。

```ruby:views/items/index.rb
~省略~
  <div class="nav-link active"><%= link_to category.category_name, categories_path(category_id: category.id),  %></div>
```
ここでは商品を一覧表示しているページにカテゴリリンクを作成しています。
末部をcategories_pathだけにするとパラメータが渡らないので、categories_path(category_id: category.id)
とする必要があります。
これによってURLの末尾が「categories?category_id=」となり、パラメータの値がしっかりと渡せるようになります。


④カテゴリーのインデックスアクションで、category_idに紐づいているアイテムを表示。

```ruby:app/controller/categories_controller.rb
class CategoriesController < ApplicationController
  def index
    @items = Item.where(category_id: params[:category_id]).page(params[:page]).per(12).search(params[:search])
    @categories = Category.all
  end
end
```

#補足
各アイテムの登録時にcategory_idがしっかりと紐づくよう引数に注意してください。
例えば以下のようにすると上手く引数が渡りません。

```ruby:views/items/new.html.erb
~省略~
<%= f.label :category_name, "カテゴリ" %><br>
  <%= f.collection_select :category_name, Category.all, :category_name, :category_name, class: "form-control", include_blank: "選択して下さい"   %> 
```

正しくは以下のようになります。

```ruby:views/items/new.html.erb
<%= f.label :category_name, "カテゴリ" %><br>
  <%= f.collection_select :category_id, Category.all, :id, :category_name, class: "form-control", include_blank: "選択して下さい"   %> 
```
【AWS】EBSの概要(インスタンスストアとの違いとEBSの特徴)

#プログラミング勉強日記
2021年5月25日

#EBSとは
　EBSはElastic Block Storeの頭文字をとったもので、EC2インスタンスと一緒に利用されるブロック型のストレージ。インスタンス上のワークロードなどに利用する。EC2インスタンスを使ってデータベースを作るときには、データベースのストレージ領域にEBSを使って処理する。
　基本的にはOSやアプリなどのデータの置き場として様々な用途で使われる。実態はネットワーク接続型ストレージで、高可用性。サイズは1GB ~ 16TBでサイズを指定することができる。利用期間で課金される。

　EBSの選択としてストレージの違いを知っておく必要がある。AWSでは3つの形式のストレージサービスがある。

　<b>ブロックストレージ</b>：EBSとインスタンスストアがブロックタイプのストレージ。EC2インスタンスにアタッチして(一緒になって)使っていくストレージ。ブロック形式でデータを保存し、高速・広帯域幅。
　<b>オブジェクトストレージ</b>：S3やGlacierがオブジェクトタイプのストレージ。安価で高い耐久性を持つオンラインストレージで、オブジェクト形式でデータを保存する。デフォルトでは複数AZに冗長化されている。
　<b>ファイルストレージ</b>：EFSがファイルタイプのストレージ。複数のEC2インスタンスから同時にアタッチ可能な共有ストレージサービスで、ファイル形式でデータを保存する。

##EBSとインスタンスストアの違い
　インスタンスストアは無料で扱えるホストコンピューターに内蔵されたディスクでEC2と不可分のブロックレベルの<font color = blue>物理ストレージ</font>。EC2の一時的なデータが保存されて、<font color = blue>EC2の停止・終了と共にデータがクリアされる</font>。そのため、長期的なデータの保存はできない。ただ、物理的にアタッチされるので性能は優れている。

　EBSは別途料金がかかる<font color = blue>ネットワークで接続されたブロックレベルのストレージ</font>で、EC2とは独立して管理されている。EC2を終了してもEBSデータは保持することができる。(デフォルトでは削除される設定なので変更する必要がある)　SnapshotをS3に保持できる。

#EBSの特徴

- ボリュームデータはAZ内で複数内のHWにデフォルトでレプリケートされていて、冗長化は不要
- 単一のAZ内で冗長化されているため、AZの障害には弱い
- セキュリティグループによる通信制御対象外で、全ポート閉じてもEBSは利用できる(EC2インスタンスとネットワーク接続できる)
- データは永続的に保存可能
- EC2インスタンスは他のAZ内のEBSにはアクセスできない
- 1つのEBSを複数のインスタンスで共有することも基本はできない
- EC2インスタンスに複数のEBSを接続することはできるが、EBSを複数のインスタンスで共有することはできない(ただ、2020年からプロビジョットIOPSのみ複数インスタンスで共有することができる)
- 同じAZ内のインスタンスのみ付け替えができる
【初心者でもわかる】CSSで水滴を再現

#どうも7noteです。大きさも自由に変更可能な水滴をCSSで再現。

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/e7bd0091-378a-2ecf-e190-081be928f835.png)

## ソース

```index.html
<div class="drop"></div>
```

```style.css
.drop {
  width: 100px;
  height: 80px;
  border-radius: 50%;
  background: radial-gradient(transparent 30%, #CDCDCD 80%);
  box-shadow: 2px 2px 2px #737373;
  position: relative;
}
.drop::before {
  content: '';
  width: 15%;
  height: 15%;
  background: radial-gradient(rgba(255,255,255,0.8) 50%, transparent);
  border-radius: 50%;
  display: inline-block;
  position: absolute;
  top: 10%;
  left: 25%;
}
```

![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/62f215ae-0dec-6afe-9007-6f1ca14c6e03.png)


widthとheightの大きさを変えれば様々な大きさの水滴が作れます。

![スクリーンショット 2021-05-23 11.38.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/05f418d6-96b2-dd90-1610-4a6abc2cdb97.png)
![スクリーンショット 2021-05-23 11.37.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/dfb8661c-4cb5-25f6-ae49-5e61ebbef7b3.png)


#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
Rubyの基本メモ

# Rubyの基本メモ
初めてRuby on Railsをやってみようと思っています。
まずはRailsチュートリアルから始めようと思いましたが、
その前に基本構文すら知らなかったので、いつでも見れるように簡単にまとめました。

## 配列と文字列の中での出力

配列を代入する変数名は慣習上、複数形にすることが多い。

``` ruby
names = ["Honda","Fukumoto","Horiuchi"]
puts names
puts "私は#{names[0]}です"
```

出力結果

```shell
Honda
Fukumoto
Horiuchi
私はHondaです
```

## ハッシュ

ハッシュも配列と同じく複数のデータをまとめて持つが、

それぞれのデータに**キー**をつけることができる。

```ruby
変数 = { :key1 => 値a, :key2 =>値b}
```

キーは文字列かシンボルを使うことができるが、一般的に**シンボル**を使う。

### シンボル

シンボルは先頭に:(コロン)をつけた文字列で、普通の文字列よりも処理が高速になる。文字列に通し番号を割り振ることで、裏ではただの整数として管理している感じ。

上の例の:key1は、先頭に:がついているため、シンボル。



### if文

``` ruby
if 条件1
  処理1
elsif 条件2
  処理2
else
  処理3
end
```



## 繰り返し

### while文

```ruby
num = 1

while num <= 3
  puts num
  num += 1
end
```

```shell
1
2
3
```



### 配列の繰り返しeachメソッド

```ruby
wdays = ["月","火","水","木","金"]

wdays.each do |wday|
  puts wday + "曜日"
end
```

```shell
月曜日
火曜日
水曜日
木曜日
金曜日
```



.eachはメソッドなので、この時のendはwhile~endみたいにeach~endではない。do~endのブロック。|wday|はブロック変数。

#### eachメソッドに範囲演算子を組み合わせる

開始値と終了値が決まっている場合に使う。

```ruby
(1..3).each do
  puts "Hello world"
end
```

```shell
Hello world
Hello world
Hello world
```

####ブロック変数を使ってみると

```ruby
(1..3).each do|cnt|
  puts "Hello world" + cnt.to_s
end
```

```shell
Hello world1
Hello world2
Hello world3
```



## メソッド

```ruby
def hello
  puts "Hello"
  puts "World"
end

hello
```

出力結果

```
Hello
World
```



### 引数、戻り値がある場合

```ruby
def メソッド名(引数)
  処理
  return 戻り値
end
```



## クラスの作成

```ruby
class クラス名
  attr_accessor :シンボル名1, :シンボル名2
end
```



### クラスに属性を持たせる

クラスに属性を持たせるには、**attr_accessor(アトリビュートアクセサ)メソッド**を使う。

~~attr_accessorメソッドは3つの役割がある。~~

~~.名前が@で始まるインスタンス変数を作成する。~~

attr_accessorメソッドは2つの役割がある。

読み取り専用メソッドを作成する。

書き込み専用メソッドを作成する。



役割的にはセッターゲッターみたいなもの？

また、アクセサメソッドを作成するためのメソッドはattr_accessorメソッドと合わせて以下の3種類ある。

| メソッド                                       | 処理                                         |
| ---------------------------------------------- | -------------------------------------------- |
| attr_accessor : 変数名(アトリビュートアクセサ) | 読み取り用と書き込み用の両方のメソッドを作る |
| attr_writer :変数名(アトリビュートライター)    | 書き込み用メソッドだけを作る                 |
| attr_reader 変数名(アトリビュートリーダー)     | 読み取り用メソッドだけを作る                 |



### インスタンスを作ってクラスを利用する方法

newする（newメソッドを使う）

```ruby
変数 = クラス名.new
変数.属性 = xx
puts 変数.属性
```

例:Carクラス、属性が色

```ruby
class Car
  attr_accessor :color
end

car = Car.new
car.color = "red"
puts car.color
```

```
red
```



### 継承

```ruby
class 新しく作成するクラス < 継承するクラス
```



例：ApplicationRecordクラスを継承したTaskクラスを作成する

```ruby
class Task < ApplicationRecord
```
AWSブログサービスを構築する(1)

2021/05/26 一部修正追記しました。

教材
--
この記事はAWS初学者を導く体系的な動画学習サービス
「AWS CloudTech」の課題カリキュラムで作成しました。
https://aws-cloud-tech.com

やったこと
--
「シングル構成のAWSブログサービスを構築する」を実施しました。

①～⑩の順に作成する。
サービスや用語がわからなくても、図を見ながら順番に作成すると概要をつかめる。

用意するもの
--
Windows10のPC・Teraterm

今回の完成形
--
（勉強させていただきました学習サービス
「AWS CloudTech」 https://aws-cloud-tech.com
の図とAZの向きが違います）

![AWSブログ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178985/169294f4-52f0-7d0b-a892-61f23239bf1d.jpeg)

※この図は「draw.io-14.6.13-windows-installer.exe」をダウンロード、インストールして作成しました。

追記：ブラウザで https://draw.io/ からも利用できるそうです！

VPC
--
①作成

サブネット
--
②作成したVPCに、アベイラビリティゾーン1aと1cに、PublicとPrivateをそれぞれ作成

EC2
--
③作成して置いておく

⑩RDSを作成したらWPをインストールする
EC2にインストールする。RDSではなく、EC2。
Teratermでログインし、WPをインストールする。

SG
--
④作成する
作成したいサービスに適した、例えば
**ssh22番にマイIPなどアクセス元情報を登録してあるか**を確認
HTTP80番を追加、など

キーペア
--
⑤作成して忘れずにローカルPCにダウンロード
（あちこちで使います）名前と場所を覚えておくこと。
WindowsでWinSCPを使うので鍵を変換してしまう人は、「.pem」の鍵も無くさないこと。

igw
--
⑥作成してVPCにアタッチ

ルートテーブル
--
⑦Publicサブネットの**ルートテーブル**に
送信先　　ターゲット
**0.0.0.0/0** 　　**igw**
を追加して保存

⑧お手元のPCからEC2にssh接続する
>
Windowsの場合
Teratermをダウンロード
新しい接続→ホスト「EC2のパブリックIP」サービスssh でOK
ユーザ名「ec2-user」パスワードは空
秘密鍵に⑤で作成したキーペアファイルを指定する

接続OK


DBサブネットグループ
--
⑨参照

RDS
--
⑨まずサブネットグループを作成する

RDSを作成する
終業後は、料金がかかるので、スナップショットを取って削除する

追記：スナップショット保管にも課金されてしまうそうなので、不要なスナップショットは削除したほうがいいです

DBインスタンスサイズ
db.t2micro
**アベイラビリティゾーンは1a** EC2に合わせる
SGはいったん新規に作成して（あとでWEBからのみ通信できるようにする）

**追加設定
最初のデータベース名**を設定する

出来上がったらRDSのSGを編集し、 WEBサーバからのみ通信できるようにする

→先ほどのEC2に戻る

追記
もしもRDSのアベイラビリティゾーンを間違えて作成、起動してしまったら。
シングルAZからマルチAZに変更して、再起動したら変更できる、という記事をみかけたので
試しましたが、ちっさいスペックで作成している為か、できませんでした。
素直に作り直しました。
GCPサーバレスサービスの比較

## はじめに
Cloud FunctionsとCloud Runはどのように使い分けたらいいのか？
そもそもサーバレスはどのような状況で使用するべきなのか。
本記事ではGCPにおける各サーバーレスサービスの違いについて、これらの疑問を解決できるようまとめました。
記事内でははCloud Functions, Cloud Run, App Engineの３つを比較しています。

## サーバレスコンピューティングについて

サーバーレスコンピューティングは、従量制のバックエンドサービスを提供する方法です。ユーザーはインフラなどを意識することなく、コードを書き込んだりデプロイしたりすることができます。

### メリット
- インフラの管理が不要
- 自動拡張(Scalability)
- 料金管理の最適化

サーバレスのメリットは大きく上の３つだと私は考えています。
これらのメリットのおかげで開発者はコードを書くことに集中できるので、スタートアップやベンチャー企業を中心に広く使われているみたいで、メルカリの技術ブログなどでも時たま取り上げられています。

### ユースケース

- ステートレスなHTTPアプリケーション
- Web、モバイルのバックエンド
- リアルタイム、イベントドリブンなデータ処理
- 機能のプロトタイプ

**注意：サーバを持たないのでデータ等の保存は外部にサーバを立てるなどする必要があります。**

## GCPのサーバレス
GCPでは、Cloud Functions, Cloud Run, App Engineの三種類のサーバレスアーキテクチャがあります。
Cloud FunctionとCloud Runについて以下の表にまとめました。

|          | Cloud Functions         | Cloud RUn        |
|----------|------------------------|------------------|
| トリガー  | HTTP or Event          | HTTP             |
|実装方法    | 関数               | Container or GKE |
| language | JS/Node.js, Python, Go | 言語、ライブラリに依存せずなんでも使える         |

大きな違いは実装方法がFunctionsの方は関数で実装しなければならないので使用できる場面が限定的であるのに対し、Cloud Runではコンテナーベースの実装となっているため、ライブラリや言語に依存せずに柔軟に使用することができます。また、Cloud RunはGoogle Kubernates Engine(GKE)にもデプロイすることができ、これにより、ステートフルなサーバレス環境を構築することができるのも大きな特徴の一つです。

よって自分がよくする各サーバレスサービスの使い分けとしては、
Functionsの要件内で事足りる比較的軽めの処理、もしくはリアルタイムイベント駆動を実装する必要がある場合にはCloud Functionsを用います。
すでにDockerコンテナでパッケージ化しているもの、もしくはステートフルなサーバレスアーキテクチャが必要な時はCloud Runを用います。
そしてApp EngineはWebアプリ全体をデプロイしたい場合に使用します。

また、使用感としては、App Engineが最も費用が高く、Cloud Functionsが最も低いです。

また、Cloud Functionに関して、Azure FunctionsやAWS Lambdaと比較すると、使用可能な言語が極端に限られていたり、ランタイムの制限が短かったりと若干使いづらいです。
AWS Lambdaがランタイム制限も1番長く、使用可能な言語も豊富でC#なども使えます。

そして、Cloud FunctionsがNodeやPythonなどの処理の遅い言語で描かれることが多いことから、、軽く速度が求められていない処理はCloud Functionsで行い、重い処理を伴うものはCloud RunやApp Engineことがベストプラクティスです。
テスト34

```vb

'クラスモジュール：MyClass1

Private Sub Class_Terminate()
    Call Module2.msg(1)
End Sub

'-------------------------------
'標準モジュール
Public Sub TestClassSub1()
    
Dim obj As Variant

On Error GoTo Err_Exit
Set obj = New MyClass1

'エラーがあってもデストラクタは発生させられる
'    Err.Raise Number:=1014

'この時にデストラクタが発生
'    Set obj = Nothing

'--------------------------------------------------
'Endステートメントではデストラクタは発生しない
'End
'--------------------------------------------------

'この時にデストラクタが発生
Exit Sub

MsgBox "test"
    
'On Error GoToステートメントを最初に設定しておけば、エラーがあってもデストラクタが発生する
Err_Exit:
    
    
End Sub

'================================
Sub msg(ByVal num As Long)

MsgBox num

End Sub
Devtoolset環境で-O2より-O3のが遅い

## 概要

CentOS + devtoolset + Intel C++環境では、`-O2`オプションよりも`-O3`オプションを付けた方が計算速度が遅くなる場合がある（devtoolsetを自前コンパイルした場合は回避できるかも）。

原因はデフォルトでリンクされる`libstdc++`がOS標準のものであるため。解決策としては、コンパイルオプションに`-static-libstdc++`を付けることでdevtoolset内のものがリンクされて計算速度も改善する。

## 環境


- CPU：Intel Xeon Gold 6248 (Csacadelake)
- OS: CentOS 7.8 (3.10.0-1127.19.1.el7.x86_64)
- ライブラリ：devtoolset-9, Intel MPI
- コンパイラ：Intel C++ (icpc 2021.2.0 20210228)

## モチベーションと問題

科学技術計算の一つとしてMolecular Dynamics(MD)関連のC++コードをチューニングしていました[^1]。AVX-512がバッチバチに効くようにするには、十分にinline展開されることが重要です。そこで、Intelコンパイラのオプションで`-inline-factor=400`などと指定して、inline展開の判断の上限を変えて計算速度の変化を見ておりました。

主なコンパイルオプションは次のようなものです。


```
mpiicpc -std=c++17 -O2 -ip -inline-factor=400 -no-prec-div -xCORE-AVX512 -qopt-zmm-usage=high
```

ちなみに、`cpp`ファイルは単一で、他はヘッダオンリーライブラリになっているので`-ip`と`-ipo`に実質的な差は無いと考えています。

ここで、`-inline-factor`の数値以外にも、`-O2`の部分を`-O3`に変更して計算速度を比べました。時間測定は`MPI_Wtime()`関数を使いました。すると次のような結果になりました（具体的コードと計算対象は省略させてもらいますがご容赦ください）。

|`-inline-factor`の数値|`-O2`の場合の計算時間[s]|`-O3`の場合の計算時間[s]|
|---|---|---|
|100 (default)|33.992533|32.275774|
|200|33.077171|31.213558|
|300|28.193719|30.905700|
|400|28.431761|30.406196|
|500|28.878089|30.671972|

この例ですと、`inline-factor=300`以上からinline展開されてAVXがより効きます。それ以下では一部のループがSIMD化されません。もちろん、inline展開を過度にするとバイナリサイズが大きくなり、キャッシュの問題と相まって遅くなると予想されます。

しかし、なぜかある時点から`-O3`オプションでコンパイルしたものが、`-O2`オプションでコンパイルしたものよりも遅くなっています。

## 解決策

なぜ遅くなるのか原因がわからず悩みました。

`-O3`にすることでバイナルサイズが増えたためか？しかし本当に微増しただけでした。

`-O3`でinline展開やSIMD化が変わったのか？しかし主要な計算部分では殆ど変化が無いように見えます。

以前に、`std::chrono`が遅いという記事[^2]を書きました。そういえば今回の時間計測で`std::chrono`を使ってしまっていないか疑ったものの、上述のように`MPI_Wtime`を使っております。その記事の調査からも、`MPI_Wtime()`は`libstdc++`のリンクには寄らず高速であることがわかっています。今回のコードでは`std::chrono`はどこでもcallしていません。

しかし、その試行錯誤自体はビンゴで、結果的にコンパイルオプションに`-static-libstdc++`を付けると次のように`-O3`での速度が改善しました。

|`-inline-factor`の数値|`-O2 -static-libstdc++`での計算時間[s]|`-O3 -static-libstdc++`での計算時間[s]|
|---|---|---|
|100 (default)|35.054073|32.014642|
|200|34.101968|31.211953|
|300|28.266521|27.761617|
|400|27.664209|27.641717|
|500|28.185959|27.892363|

どうやら`std::chrono`以外にもOS標準の`libstdc++`では速度の出ない関数があったのだと想像できます。もしくはリンク時インライン展開(`-ipo`ではないけど多分)で問題になるところがあったのか。そこをdevtoolset付属のものにしたことで解決したのでしょう。

ただし`-O2`でinline展開が十分でない場合には速度が低下しているので注意は必要です。

では原因は何なのかという話になると断言できず。この込み入ったMPIのコードから一部分を切り出して原因となる関数を特定するのはとても困難で、現状諦めたい気持ちでいっぱいです。

## おわりに

原因を完全には特定せず、中途半端なレポートで申し訳ないです。MPIでのベンチは本当に魔境で辛過ぎ。そもそもinline展開の上限を上げないとSIMD化できないような私のクソクラス設計に問題があるのは否めません。ですので、とてもレアなケースかもしれません。

また、`gcc`や`clang`(もしくはIntelの`icpx`)ならどうだという疑問もありそうですが、MPIのインストール状況などから今回は調査を断念します。

とりあえずdevtoolset環境で`-O3`を使う際は`-static-libstdc++`も併用してオプションに指定した方がよさそうです。誰かのお役に立てば幸いです。

  

[^1]: 正確にはMDのエンジンをコアに使ってMPMDでヘテロジニアスな計算を行うシミュレーションという特殊なものなので、一般論として今回の事例が良く起こるのかはちょっと自信がないです。

[^2]: [ある環境でstd::chronoが遅い](https://qiita.com/pochman/items/997fcf9b04afe574a0b4)
React＋nginx＋uWSGI＋Djangoでデプロイする際の設定

##はじめに


フロントエンドとしてReact、バックエンドとしてDjangoで実装されたアプリを、ひとつのEC2上で同時に動かした際に、設定で時間を食ってしまったので作業メモに残す。  
ついでにDjangoが開発用サーバで動かしていたので、uWSGIを入れた状態で動かす。    
  
WSGIサーバを入れた方がいい理由は、以下参照。  
[Djangoの開発サーバーをプロダクション環境で使わないように、という話](https://qiita.com/charon/items/e4eea83c3de3825f864a)
  


## 前提

- Reactのフロントエンド、Djangoのバックエンドを実装し、EC2上に配置
- npm、nginxをEC2にインストール  
- ローカルや別々のEC2にnginx＋ReactとDjangoを単純に配置して動作する状態

参考：  
[丁寧解説】秒速でもDjango 3アプリをAWS EC2で公開【Nginx, gunicorn, postgresqlデプロイ】](https://qiita.com/Bashi50/items/d5bc47eeb9668304aaa2)  
[React/Next.jsアプリケーションを作成し、AWS EC2を使って本番環境にデプロイするまで](https://qiita.com/longtime1116/items/18553e43bfb44cbc9d81)


## アプリの構成

ひとまず、別々のサーバにいたものをそのまま並べた構成とする。  
Webブラウザ <--> nginx  <--> Reactアプリ(Port:3000)<--> uWSGI <--> Djangoアプリ(Port：8000)
  

## uWSGIのインストール、動作確認

```
$ pip install uwsgi
```
Djangoアプリの構成時に、(Djangoアプリフォルダ)/config/wsgi.py が配置されていれば特別な設定は必要なし。  
動作確認等でチュートリアルの和訳記事を参照した。
[Django + uWSGI + nginx (uWSGIチュートリアルの和訳)](https://qiita.com/Ningensei848/items/e91fbeef5f03685a7a0b)


## ファイルの設定内容

### React
アクセス先のDjangoのURLはEC2のパブリックアドレスを指定する。
(localhost、127.0.0.1ではうまく繋がらなかった)  
  
```javascript:(Reactアプリフォルダ)/src/views/foo.js
    axios.get(`http://(EC2インスタンスのパブリックIP):8000/api/… `)
                   // ↑port:8000のDjangoのAPIにアクセス
```
  

### nginx 

/etc/nginx/conf.d に.confファイルを作成。
プロキシとしてport:3000に飛ばす設定のみ。バックエンドとしてのDjangoの設定はなくても動作した。  

```/etc/nginx/conf.d/react.conf
server {
    listen 80;
    listen [::]:80;

    server_name (EC2のパブリックアドレス);

    location / {
        # プロキシの設定
        proxy_set_header Host $http_host;
        # proxy_pass http://127.0.0.1:3000; ←こちらでもOK　
        proxy_pass http://(EC2のパブリックアドレス):3000; 

    }
}
```

/etc/nginx/nginx.conf に、以下の記述があることを確認しておく。これで、/etc/nginx/conf.d/の設定がnginx起動時に読み込まれる。


```/etc/nginx/nginx.conf
http {
    …
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*; 
}
```
/etc/nginx/sites-enabled/* に関する記述は、nginxで複数のサイトを扱う際に、サイトごとの設定をsites-enabled/ に保存するために必要(今回は未使用)。

設定については以下も参照。
[nginxについてまとめ(設定編)](https://qiita.com/morrr/items/7c97f0d2e46f7a8ec967)

### Django
settings.pyの"CORS_ORIGIN_WHITELIST"で、EC2のパブリックアドレスを指定する。
(localhostや127.0.0.1ではうまく動かなかった)
port:3000のあるアドレスとないアドレスの両方を登録しておく。
 

```python:(Djangoアプリフォルダ)/config/settings.py 
CORS_ORIGIN_WHITELIST = [
    'http://(EC2のパブリックアドレス):3000',
    'http://(EC2のパブリックアドレス)',
]
```

## アプリの起動

### Djangoアプリ起動(uWSGI)
Djangoアプリのメインフォルダに移動し、wsgi.pyファイルを指定してuWSGIを起動する。

```
$ cd (Djangoアプリフォルダ)
$ uwsgi --http :8000 --module config.wsgi　
                            　↑(Djangoアプリフォルダ)/config/wsgi.pyを指定している
```


### React、Nginxを起動

```
$ cd (Reactアプリフォルダ)
$ npm start
$ sudo systemctl start nginx
```

## おわりに

今回はフロントエンドとバックエンドを別々に配置したが、次はReactをDjango側に配置して動かす予定。


## その他参考サイト

[Python Django + React](https://qiita.com/namutaka/items/da5db3ef6efcfebf43c8)
[React+Nginx+Django Rest Frameworkでデプロイ](https://coders-shelf.com/react-django-rest-framework-deploy/)
[uWSGIでDjangoアプリを動かす基礎](https://django.kurodigi.com/uwsgi-basic/)
Ruby on Railsのサーバーが立ち上がらない件 

[結論]
rails new sample_app --webpacker

を実行すると、webpacker設定済みのrailsフォルダができあがる。

以下、私のトライ&エラーの記録です。

[エラー]

![スクリーンショット 2021-05-25 18.57.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1019167/9be7a9d4-b9c2-21a4-ec9e-8627fedaf441.png)

エラーメッセージ
Webpacker configuration file not found /Users/nakamurasatoshi/sample_app/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /Users/nakamurasatoshi/sample_app/config/webpacker.yml (RuntimeError)

[原因]
webpackerがインストールされていない

こちらの記事を参考にしました
「Webpacker の概要」
https://railsguides.jp/webpacker.html

「WebpackerはRails 6.0以降デフォルトでインストールされます。」
・・？

筆者のRailsのバージョンは 6.1.3.2でした。
なんか、最初にRailsをインストールしたときのバージョンは古くて
その後バージョンアップしたような気がしないでもないです。

「Webpackerを使うには、Yarnパッケージマネージャー（1.x以上）とNode.js（10.13.0以上）のインストールが必要です。」

「Yarnとは」
https://qiita.com/akitxxx/items/c97ff951ca31298f3f24

JavaScript(Node.js)のパッケージマネージャだそうです。
ターミナルからインストールするためには、npmというものが必要そう。
(じゃあnpmってなんだ・・？)

「npmとは」
https://qiita.com/akitxxx/items/05f973df9c54cec23419
Node.jsのパッケージを管理するもの。

「npmはNode.jsをインストールすると一緒についてくる。」
なるほど。

まずは記事通りにnodebrewをインストール。
(homebrewはインストール済み)

「nodebrew install-binary latest」
こちらを実行した段階でエラーになりました。
![スクリーンショット 2021-05-25 19.11.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1019167/31bd3fa6-98ef-9aa3-fc24-522828a6e6f1.png)

なんかつまずいてきたので、あらためて下の記事を参照。
「Rails6 開発時につまづきそうな webpacker, yarn 関係のエラーと解決方法」
https://qiita.com/NaokiIshimura/items/8203f74f8dfd5f6b87a0

まずはyarnをインストールしました。

しかし、
「rails webpacker:install」を実行しても
Usage:
  rails new APP_PATH [options]
が表示されます。コマンドが反映されていなさそうです。

「rails 環境構築ができない。」
https://teratail.com/questions/249727

「ふつうはrailsアプリ用のフォルダを作って、そのフォルダの中で
rails環境を構築します。」
なるほどなるほど、rails用のフォルダの中に
設定ファイルを保存していくようなイメージですね。

ここまで自分は、Macの環境設定を行っていると思っていました。
しかしwebpackerなどのファイルは、プロジェクトに保存していくようなイメージなんですね。(語彙力)

記事中の、Rails環境構築手順を引用させていただきます。

***
手順はこんな感じです。（コマンドラインでの実行を想定）

railsアプリ用のフォルダを作ってその中に入る
bundle init (Gemfileの原型ができる)
Gemfileの修正 (注釈になっているRailsを有効にする、railsのバージョンも指定できる)
bundle install (オプションでgemのインストール先を指定)
bundle exec rails new . (rails構築)
bundle exec rails s (rails起動)
***

というわけで、あらためてRailsのプロジェクトを作成していきます。

rails new sample_app --webpacker

これで成功しました！
記事を書くときに便利なコマンド、Max OSのバージョンを sw_vers コマンドで確認する

技術系の記事を書くときには、検証をした環境・再現できる環境などを書いてあげることが大切なことかと思います。
mac OSだと、 `画面の左上のリンゴマーク` > `About This Mac` から確認することもできますが、コマンドで簡単にしてしまいたいときに、 `sw_vers` コマンドが利用できます。

```zsh
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.7
BuildVersion:   19H1030
```

おそらく **s**oft **w**are **ver**sion **s** の **sw_vers**かなと。

それ以外の mac OS の Utility コマンドは以下にまとめられています。
https://github.com/herrbischoff/awesome-macos-command-line
よく使う `pbcopy` `pbpaste` も同じ Utilityコマンドです。
シェルスクリプト・bash用テストフレームワーク bats が開発終了したので bats-core に移行しましょう

## TL; DR

開発停止状態だった [Bats: Bash Automated Testing System](https://github.com/sstephenson/bats) プロジェクトがアーカイブされ開発が完全に終了しました。後継プロジェクトは [Bats-core: Bash Automated Testing System (2018)](https://github.com/bats-core/bats-core/) です。

## これまでの流れ

シェルスクリプト（bash）用のテストフレームワークでもっとも有名なものと言えば bats でしょう。bats は 2011 年に登場し bash 用のテストフレームワークとして多くのプロジェクトの開発を支えてきました。しかし積極的なメンテナンスは 2014 年頃までで 2015 年に僅かな修正が行われたのを最後に開発が停止していました。2016 年の初期に開発を続けるのに十分な時間がないという理由で開発者自らがメンテナを募集しておりユーザーのコメントも多数寄せられてたのですが何故かその後開発者の反応が全くなくなってしまいそのまま放置されていました。そして 2017 年 9 月 19 日 プロジェクトがフォークされコミュニティベースの bats として bats-core が登場しました。

フォークが作られてからもオリジナルの bats はアーカイブもメンテナンスもされることもありませんでした。そのためプロジェクトの状況を知らないユーザーから度々 Issue や Pull Request が作られましたが、それでも開発者の反応はなくユーザーから bats-core へ案内されるという状態が繰り返されていました。bats-core はフォーク後すぐには開発は進みませんでしたが、少しずつ軌道に乗り始め 2019 ～ 2020 年頃より継続的に開発が進められるようになっています。

そして本日 2021 年 5 月 25 日、bats プロジェクトのリポジトリは突如アーカイブされました。明確な発表はないようですがどうやら bats プロジェクトは完全に終了したようです。長年開発が停止していたためすでに移行している人も多いと思いますが、まだの人はこれを機に bats-core に移行してみてはいかがでしょうか？また以前に記事を書いていた人は記事を更新しリンクを bats-core に変更しましょう。（古い記事が検索に引っかかってしまうので）
pdfファイルをcsvファイルに加工し、いらない行を削る

#前書き
pdfで保存された個人情報満載の表をnumberで編集できるようにしたいと思って、やり方をググると大体一度ワードに変換するとか Adobe Acrobat Reader(有料版)で変換するとか言われました。
私はwordもAdobe Acrobat Readerも持っていないので困りましたが、検索で出てきたやり方を組み合わせることで変換ができたので、自分向けに記録したものを公開します。

###前提
1.Macユーザー
2.jupyter notebookユーザー
3.pandasがinstallされている
　(pandasはpip3 install pandasで簡単にインストールできます)
4.homebrewが入っている


#使ったもの
1.tabula
2.pandas

#手順
###1.tabulaのインストール
ターミナルで以下を実行します。

```php
pip3 install tabula
```

###2.javaの環境の構築(途中まで)
tabulaはjava環境を必要とするので、その構築をします。
具体的には、

####2-1.homebrewでjavaのインストール

```php
brew install java11
```
と打ち込むだけです。
参考:https://qiita.com/ponsuke0531/items/9be8dee67a91c6c78d4f

####2.2java環境の構築とpathの設定
https://qiita.com/suke_masa/items/f9af0fb84ad9447ae961
をみながら環境の構築を行います。私はこちらのJDKというものをインストールしました。

###3.jupyter でtabulaを使って読み込む

```php
#必要なモジュールのインポート
import pandas as pd
import tabula
from tabula import read_pdf
from tabula import convert_into

convert_into("yomikomi.pdf","kakidashi.csv", stream=True , output_format="csv", pages='all')
#yomikomi.pdf:読み込みたいpdf
#kakidashi.csv:書き出すcsvファイル
#streamは罫線だったと思われる
```
参考:https://bunkyudo.co.jp/python-tabula-01/

###4.読み込んだcsvファイルでいらない行を削る
今回は欠損値が一つでもある行を消したかったので、
https://qiita.com/yuta-38/items/122e607770b88d445d2e
を参考に、jupyterで以下を書きました。

```php
#必要なモジュールのインポート
import pandas as pd

#ファイルの読み込み(さっきcsv形式にしたファイル)
df = pd.read_csv('kakidashi.csv')

#欠損値が一つでもある行を消したものをdddと定義する
ddd = df.dropna(how='any').dropna(how='all', axis=1)

#dddを"hozon.vsv"という名前で保存
ddd.to_csv("hozon.csv", index=None)

```

終わり。


##その他
基本的に本記事は冒頭に述べたとおり、いろんなところからコピペしたものを組み合わせているスクリプトな訳ですが、コピペ元に著作権が発生するかを考えておりました。
(例えば

```php
brew install java11
```

に著作権は発生するのか？)
ただこれで著作権侵害していると判断される場合、qiitaの記事は大体全て著作権侵害してることに気がしますので、参考にした記事を明記するにとどめ、公開いたします。


書く途中に参考にしたサイト:
https://a7xche.hatenablog.com/entry/2020/04/11/213756
mac OS Catalina(10.15.7)で brew install をしたら Error: Permission denied @ apply2files というエラーが出た際の対応

# 経緯

`brew install`や `brew upgrade` などをした際に、以下のエラーが表示されてしまった

# エラー内容

```zsh
Error: Permission denied @ apply2files - /usr/local/lib/docker/cli-plugins
```

# うまくいった対応

```zsh
$ sudo chown -R $(whoami) $(brew --prefix)/*
```

## コマンドの意味

`brewコマンドでのインストール先のファイル・ディレクトリの所有者を現在のユーザーに変更します`

### 細かく調査

*実際にコマンドを打ってみたらすぐわかりました*

- `brew --prefix`
    - brewコマンドでのインストール先のルートディレクトリを表示
- `$(brew --prefix)/*`
    - brewコマンドでのインストール先のファイルたちを指定
- `whoami`
    - 現在のユーザー名を表示
- `chown -R`
    - `man chown` をすると書いてありました
        - `The chown utility changes the user ID and/or the group ID of the specified files.  Symbolic links named by arguments are silently left unchanged unless -h is used.`
    - `-R` については
        - `Change the user ID and/or the group ID for the file hierarchies rooted in the files instead of just the files themselves.`
        - 要するに指定したファイル以下のファイルのユーザーIDやグループIDを再帰的に変更


## ちなみに

`sudo brew`　はもうダメみたいでした

```zsh
Error: Running Homebrew as root is extremely dangerous and no longer supported.
As Homebrew does not drop privileges on installation you would be giving all
build scripts full access to your system.
```
aws-cliでロールを引き受ける

# はじめに
aws-cliでロール権限でコマンドを実行する方法。
awsのマネージメント画面からはロールを切り替えるのは簡単だけどcliはどうすんだっけってことでメモ

## プロファイルを追加する

```terminal
% vim ~/.aws/config
```

でconfigファイルにプロファイルを追加する

```
[profile プロファイル名]
role_arn = arn:aws:iam::123456789012:role/marketingadminrole
source_profile = default
```

ちなみに多要素認証している場合はmfa_serialも必要で、MFAを追加する

```
[profile プロファイル名]
role_arn = arn:aws:iam::123456789012:role/marketingadminrole
source_profile = default
mfa_serial = arn:aws:iam::128716708097:mfa/cli-user

```

## 実行

```terminal
% aws s3 ls --profile プロファイル名
```

上記のように実行するときに「--profile プロファイル名」をつければ良い

参考
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html

## 困った。。。
ciで2段階認証入れてる場合にどうやったらいいのだろうか。。って困った
プロファイルじゃ無理な気がするし、、、どうしたらいいのでしょう
Nuxtで作ったアプリをHerokuで公開するときに環境変数を参照できるようにする

## はじめに
Nuxtで作ったアプリをHerokuで公開するときに環境変数をどうやってHerokuに設定すればいいのか分かりませんでした。
調べてできるようになったので、忘備録として残しておきます。

### 前提
@nuxtjs/dotenv を使用している
.envファイルに環境変数を記述している
​Heroku CLI​ を使用している


### nuxt.config.js にenvを追加
nuxt.config.jsの最後に追記します。

```
env: {
  FIREBASE_API_KEY:process.env.API_KEY
}
```


### herokuで環境変数を設定

```
heroku config:set ENV_VAR_NAME="value"
```
Java屋さんのMaven使うのなんでを考察する

## これはなんですか？
タイトル。

この記事を読むとよいかもしれない対象者は「なんでMavenとGradleでビルドツールが２分化されているのか」について疑問に思っている人に対してJava屋さんが一つの考察を開示するものです。

ここ２年間で５回位聞かれたことなので、記事になるかなーと、考えを記すことにしました。

## 本題

メリット。
1. 昔から使ってるのでやりたいことの9割以上のことがMavenで**かんたんに**できてしまう
1. 資産として溜め込んだプラグインの使い方をGradleに移植するのが面倒
1. Gitで公開していあるそこそこ歴史あるプロジェクトはビルドツールにMavenを使っていることが多く、絶滅するおそれが少ない
1. やりたいことのプラグインも探せばだいたい出てくる

デメリット。
1. XMLだるい
1. 初心者がとっつきにくい
1. Java以外の言語だと最適ではない場合がある
 
長くJavaと寄り添ったツールとして発達し、支持されているため、その世界最強ですが、kotlinやgroovyのプロジェクトではgradle使うべきかなーとも思います。

Gradleの自由度は魅力だと思いますし、今から始める人はGradleでよいのではないでしょうか。

敢えてXMLで読みづらい Maven を無理して採用することもありませんし、他の人がプロジェクトを構築した結果、ビルドツールがGradleだったとしても、全てを赦し小姑のように build.gradle の手直しを始めるくらいには gradle **も** 使えるといいでしょう。

参考までに、手元のプロジェクトで使っている dependencies のビルドツールをいくつかピックアップ

| Project  |  Build Tool  |
| ---- | ---- |
| OpenJDK | **Make** |
| Spring Boot |  Gradle |
| Jackson |  Maven  |
| AWS SDK | Maven |
| Flyway | Maven |
| Openapi Generator | Maven |
| Swagger | Maven |

というわけでMake最強。
解散！！

## 参考記事

MavenやGradleの歴史については、こちらの方が執筆された記事によくまとまっております、併せてご参照ください。
https://qiita.com/MahoTakara/items/ff73338e218b656bedfa

Maven to Gradle コンバータありましたが、dependenciesしか移してくれない・・
https://sagioto.github.io/maven2gradle/
カフェでプログラミングしてる風（でも何もやってない）Goコード版

[カフェでプログラミングしてる風（でも何もやってない）Java（クソ）コード](https://qiita.com/3S_Laboo/items/660883a0184dabaea65b) からインスパイアされたGo版です。

詳細は [ソースコード](https://github.com/e10ulen/sandbox/blob/master/fakeStatusChange/main.go) です。

## なんで作った？
習作（Goを書くのが久々）のため、なんか面白そうなのないかなって思って書きました。

## カフェでｯﾀｰﾝはかっこいい
かっこいい

##　ソースコードはこうなってる
（もっといい書き方があるはず）

```go:fakeStatusChange.go
package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	fakeStatusChange()
}

func fakeStatusChange() {
	sentence := 50
	countup := 0
	var delay time.Duration
	lineout := 0
	rand.Seed(time.Now().UnixNano())
	for {
		if sentence != countup {
			fmt.Printf("#")
		} else {
			//	50文字になったら「done + 改行を出力する。
			//	何かが終わった感じを出力する。
			fmt.Printf(" done!!\n")
			//	countupをリセット
			countup = -1
			//	無限ループを脱出するためにカウントアップしておく。
			lineout++
		}
		//	カウントしていく
		countup++
		//	高速に出力するとそれっぽくないので、waitをかけて遅延をする。
		//	ランダム値にマッチすると待ち時間を更に遅くさせる。
		//	delayを作る。
		delay = time.Duration(100) * time.Millisecond
		if 5 < countup && countup <= 10*lineout {
			time.Sleep(delay)
		}
		//	10行書かれたらbreakして無限ループを終わらせる。
		if lineout == 10 {
			time.Sleep(1000)
			break
		}
	}
}
```

## まだDungStatusChange.javaしかコピーできてない。
マジで、もう一個の報も書かなきゃね。
引数でStatusChangeとCompile分けれたら一個のバイナリで済むから実装しようかな。

### 動作風景とかは録画できてません（VM上撮影とかちょっとよくわかんない）
ブランチに上流ブランチはありません。このブランチを公開しますか?



<img width="300" alt="エラー.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/696940/7b27bd4f-acc6-bd2a-dcf8-e1e924b394de.png">

#はじめに
これまでGithub Desktopを使用していたためVScodeでのGit操作になれず、Githubからクローンしたデータからカレントブランチを正常に作成できなかったので、調べてわかったことをまとめます。

#結論
リモートのmainブランチからカレントブランチを作成することで発生するエラーだった為、ローカルのmainブランチからカレントブランチを作成する必要があった。

##動作環境
・MacOS big Sur
・Visual Studio Code バージョン: 1.56.2
・git version 2.31.0

##根拠
・「ブランチに上流ブランチはありません。このブランチを公開しますか?」の表示
origin/masterブランチにカレントブランチを作成すると発生。

・vscode左下のブランチ名のクローン時のブランチ名の master
このmasterはリモートの origin/masterブランチのこと

##git clone後にカレントブランチを作成する正規の手順
1. gitクローンを行う。
2. リモートの origin/master ブランチから、ローカルの master ブランチへの移動
3. 新しい分岐によりカレンとブランチの作成

注意:リモートのorigin/master ブランチ及び、 ローカルのmasterブランチ切り替えの際、左下の記述はmasterとなる。

##追記

・Githubがorigin/mainブランチのみの環境からクローン、origin/mainブランチからカレントブランチを作成しpushした際の「ブランチに上流ブランチはありません。このブランチを公開しますか?」はそのまま公開すると、ローカルのmainブランチに作成したカレンとブランチ同様の動作をする。(推奨しない)

##おわりに
まだまだ駆け出しですが、これからエンジニアを目指す誰かのお役に立てたらと思います。
pythonスクリプトの実行時間計測

#前提
IPython(jupyter notebookなど)で実行

#やり方

```py
%timeit %run (スクリプト名).py
```
でスクリプトファイルの実行時間を計測できる。
複数回実行した平均時間と、ばらつきが表示される。

#時間がかかっている処理の調査
```py
%prun %run (スクリプト名).py
```
で各関数と実行時間の表が表示される。
Ruby 問題⑤ if,else問題　〜ポイント編〜

##はじめに
またもやif else問題です。

本日受けたスクール独自のスキルチェックテストも3割はif,else問題でした。

それほどしっかり身につけなければいけないと思うので本日もしっかりアプトプットしていきます。

##問題

サッカチーム、テルフィーFC（ウイイレ風）のーショップでグッズを買うとポイントがついてきます。
購入金額が4,999円以下の場合、5%のポイント
購入金額が5,000円以上の場合、10%のポイント
このように付与されるポイントを出力するメソッドを作りましょう。

ただし試合でチームが勝利したの場合はポイントが5倍になります。
勝ちの場合はtrue, 負けの場合はfalseで表します。
また、小数点以下をすべてのポイント計算が終わったあとに切り捨てましょう。

```.rb
purchase_points(4000, false) → 200ポイント獲得です
```

##ヒント

・これまたif,elseで条件分岐します

・5月30日がCL決勝です。（関係なし）

・小数点を切り捨てるメソッドは？

##解答

```.rb
def purchase_points(amount, winning)
  if amount <= 4999
    point = amount * 0.05
  else
    point = amount * 0.1
  end
  if winning
    point = point * 5
  end
  puts "#{point.floor}ポイント獲得です"
end
```

解説します。

まずは引数で

```
purchase_points(amount, winning)
purchase_points(4000, false)
amount = 購入金額　winning = 勝ち、負け（ture,falseで表します）
```

続いて条件分岐です。

もし、購入金額が4,999円以下の場合、5%のポイントがつき
購入金額が5,000円以上の場合、10%のポイント

という記述になります。

```.rb
def purchase_points(amount, winning)
  if amount <= 4999
    point = amount * 0.05
  else
    point = amount * 0.1
  end
end
```

これで購入金額についての記述が終わりました。

次は勝ち負けについてです。

もう1つ条件分岐が必要です。

もし、勝ったときはポイント10倍、負けたら何もなしという条件分岐です。

```..rb
 if winning
    point = point * 5
  end
```

簡単な記述ですね！

これらを合わせて解答になります。

```.rb
def purchase_points(amount, winning)
  if amount <= 4999
    point = amount * 0.05
  else
    point = amount * 0.1
  end
  if winning
    point = point * 5
  end
  puts "#{point}ポイント獲得です"
end

purchase_points(3150, true)
#出力　787.5ポイント獲得です
```
ポイントには普通小数点はいらないですよね。。。
そこで.floorメソッドを用います。

```
irb(main):001:0> 4.1.floor
=> 4
irb(main):002:0> 4.9.floor
=> 4
```

```.rb
 puts "#{point.floor}ポイント獲得です"
```
Raspberry Pi、サブPC化計画

今までvimの話ばっかメモしてきたんですけど、たまーに他のメモを残しておきたくなるので、今回がそれです。もしかすると、今後Raspberry Piの話題も増えていきそうなんですけど、それは今後の活用ペース次第ですね。

# Raspberry Piは　いいぞ

というわけで、我が家にもRaspberry Pi 4が届きました。本当はキーボード付きが魅力で400を待とうと思ったんですけど、もし何かの意向で持ち歩くことになると結局トラックボールも持っていくことになるんですよね。[^trackballer]そう考えると、今余しているThinkpadキーボードとRasPi4の組み合わせでも持ち歩く時のカサは変わらなそうだしじゃあいいや、ってことになりました。これならトラックボールいらんし快適かなと。

[^trackballer]: Kensington以外はポインティングデバイスに非ず……ってノリなんですけど、実際はトラックポイントに頼ったり、サブで[DEFT](https://www.elecom.co.jp/products/M-DT1URBK.html)持っていたりします。

で、実際どう使いたいかというとサブモニタみたいにしたいわけです。メインのラップトップでゲームしてたらtwitterとdiscord開いててほしいし、暇なときにはtwitchとかでいい感じの配信開いててほしいし……っていうめちゃめちゃ怠惰な使い方をしたいんです。その実現方法に関しては紆余曲折あるんですけど、それはさておき今回のRasPi4は[Raspberry Pi OS](https://www.raspberrypi.org/software/)を起動しっぱなしにしつつ、都合にあわせてブラウザなり**VLCなり**アレコレ起動できるようにしましょということなんです。

# ブラウザも開かずにネット動画とな!?

## TL;DR

firefox
↓ [Open With Add-on]
↓ [ssh]
↓ [streamlink]
vlc

## Open With add-on

というわけで、ブラウザから簡単にコマンドを扱える[Open With add-on](https://github.com/darktrojan/openwith)を使いました。これに関しては今回の目的以外にも、例えば「[ニコニコ生放送](https://live.nicovideo.jp)のコメントビューアを直に開く」なんてケースでも対応してくれるイカした奴です。色々試した結果、パス周りや文字のエスケープをあまり考えずに済むよう、sshを介する部分にスクリプトを書いて処理しています……

```
pwsh c:\path\to\script.ps1 %s
```

……として、pwshのスクリプトに色々と書いてある感じです。これならurlをいじくって動画はRasPiで、コメントはメインPCでポップアップなんてことも出来そうですよね。

## streamlink

ここからはRasPi側のシェルの処理になります。[streamlink](https://streamlink.github.io/)は対応している動画サイトのURLからパイプ処理してビデオストリームを出力してくれる気の利いた悪ガキみたいなツールです。[^atYourOwnRisk]サイトによっては引数として認証情報も渡す必要があるのですが、基本は……

```
streamlink --default-stream [パイプする動画の品質] [url] -p [動画プレイヤーのパス]
```

となります。で、streamlink自体は簡単なツールなのですが、ある程度ハマったのでtips的なハマリポイントだけ列挙しておきます。

[^atYourOwnRisk]: 基本的にこの方法、すべてアンオフィシャルな視聴方法となります。ご自分の判断でどうぞ。

冷静になれば当然のことなんですけど、sshから最終的にguiの動画プレイヤーを起動するので、guiの出力先が必要です。そんなことやったことないので「色々試すか」と`export DISPLAY=:0.0`としてみたらアッサリ出来てしまったので、一連の処理のどこかで環境変数を追加しておいてあげる感じです。前述の通り認証情報が必要になるケースを踏まえて、今回は受け取ったurlはシェルスクリプトで条件分岐をしているので、その際に追加してあげるといい感じです。

また、この部分をシェルスクリプトにしておいてあげると、RasPi内のターミナルから扱う場合も手軽になります。もちろんメインPC側同様にOpen Withアドオンで右クリック一発も可能なんですけど、やっぱりパス周りは融通利かないので、特にstreamlinkをpip経由でインストールしている場合は`~/.local/bin`にパスが通っているか確認が必要です。

実際のスクリプトはこんな感じです。

```
url=$1
player="vlc"
args=""
cap="720p60,720p,720p_alt,best="

export DISPLAY=:0.0

case $url in
# urlごとの処理いろいろ
esac

nohup ~/.local/bin/streamlink $args $url -p $player > /dev/null 2>&1 &
```

1080p60の動画再生がきつかったので、`$cap`変数で制限をかけています。

# 〆

昨今は「何某さんはコメントの魅力があるからコメント入力が遠くなる形態での視聴をさせたくない」とか、「何某さんは付き合うプロダクションの都合でやっぱDRMないと」とか、そういうことに絡めとられて「モニタがあるのに動画が見られない」というケースが増えています。その辺のことをすべて忘れて、とりあえず右クリックしとけば動画が見られるのですこぶる快適です。自分で作ってしまったので、何かあったら自分でメンテしないとならないという点において全くお勧めできないんですけど、シングルボードコンピュータの下世話な使い倒し方として目に留めておいてもらえれば……
Git LFSで一度でもコミットしたファイルをtrackする方法

# 背景
基本的に100MB以上のファイルは `git push` 時にエラーになってしまいます。
今回残念ながら130MBのファイルをアップロードしようとしてエラーになってしまいました。。。
そのときのエラーメッセージで `Git LFS` を使うように促されるわけですが、すでにコミットしてしまっているファイルを後から `git lfs track` しても物理ファイルは残ったままなので、やはりpush時にエラーになってしまいます。
いろいろ調査した結果、解決手段としては下記：

* `git reset --soft HEAD^` でファイルを追加する前の履歴まで戻す
    * gitは履歴にファイルが有る限りpushしようとしてしまいます。つまり `git rm --cached file` してもダメ
* `git lfs migrate import` を使って後から物理ファイルをLFSポインターに変換する
    * 参考になったissue: https://github.com/git-lfs/git-lfs/issues/3338
    * 注意：このコマンドでは過去のコミットも修正してしまい、過去が書き換わってしまいます

今回は後者で解決しました。

```
$ git lfs migrate import --include="public/heavy.pdf" --everything
```

すると `--include` で指定したファイルは下記のようにLFSポインターで書き換えられます。

```
$ cat public/heavy.pdf
version https://git-lfs.github.com/spec/v1
oid sha256:fd73228fc4e238160a8f7da967b4834aa0b66c30731cdcb889e77c2a362805e3
size 138638207
```

これでpushすればOK!