OmniAICreator/Qiita-1.07M huggingface dataset:
フレッツ光をAndroid USBデザリングにしてみた

フレッツ光を解約してしまったので、ネット接続がなくなり不便なのでAndroidのデザリングを使ってネットアクセスできるようにしてみた。

![moto.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/0fada099-374f-e332-96a9-3f608cdc7362.png)

元の構成を変えるのは面倒なので、インターネットの口をFreeBSDのブリッジでインターフェース間をL2のスルーで設定することにした。

![br2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/e80cc90e-6a37-0b08-b0df-173a026b3e24.png)

AtermはWifiを使っているのでノーマルで、PPOEの設定になっていたものをローカルルーターに変更します。

FreeBSDはi386の12.3RでマシンはPen IIIのValueStarです。PCIにfxpとUSB 2.0のボードが入っているのでcardbusでrl0を生やします。

```
#!/bin/sh
ifconfig bridge0 create
ifconfig bridge0 addm ue0 addm rl0 up
ifconfig ue0 up
ifconfig rl0 up
```

ue0でNATする方法も考えたのですが、設定が複雑になり、またfxp0にも干渉することが考えられたので、この方法が一番簡単だと思います。

Windows updateのような悪質なアクセスは何らかの方法でブロックするのが良いかもしれません。

Y!モバイルの3Gの容量がのこりわずかなので、これはFreespotで書いています。調べてみたら繰り越しが無いプランになっていました。

実際はドコモ光だったのですが、モデム返せって言われたのですが、連絡がきません。電話つながらないし要を得ないし、ドコモ光の管理は結構怪しいです。
フォームオブジェクトでCarrierWaveを使うとアップロード先が…！

## はじめに
CarrierWaveでファイルをアップロードできるようにしたモデルから作ったフォームオブジェクトでファイルをアップロードすると、アップロード先が違ってしまい参照できなくなってしまいました。
少し工夫して参照できるようにしたので、同じようなことで困ってましたら、参考にしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/c8c3e949-6aeb-6974-7e24-6846b36458af.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/1c862ef4-c745-c978-5248-52dd1d483373.png)


## ソース
修正前: https://github.com/ken1flan/carrierwave_store_dir_sample
修正: https://github.com/ken1flan/carrierwave_store_dir_sample/pull/2

## 修正前のコード
Articleと、それを継承したForm::Articleというフォームオブジェクトがあったとします。

```ruby:app/models/article.rb
class Article < ApplicationRecord
  mount_uploader :image, ImageUploader
end
```

```ruby:app/models/form/article.rb
class Form::Article < Article
end
```

ArticleがマウントしているのはCarrierWaveのジェネレータで作ったままのものです。

```ruby:app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # この下は全部コメントだったので省略
end
```

## フォームオブジェクトでファイルをアップロードすると参照できない

`Form::Article`でレコードを作成すると、`uploads/form/article`以下にアップロードされてしまい…。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/e106cee8-4569-b109-2f42-10afdc358910.png)


## 原因

`ImageUploader#store_dir`の実装を見てみると、クラス名をスネークケースにしたものをディレクトリ名に採用しているからでした。フォームオブジェクトだとその部分は`form/article`になってしまいます。

```ruby:app/uploaders/image_uploader.rb
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
```

## 修正

`ApplicationRecord`にモデル名をスネークケースにして返すメソッドを準備しておいて…

```ruby:app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class

  def self.carrierwave_store_id
    to_s.underscore
  end
end
```

それを使うように`ImageUploader#store_dir`を書き換えて…

```ruby:app/uploaders/image_uploader.rb
  def store_dir
    "uploads/#{model.class.carrierwave_store_id}/#{mounted_as}/#{model.id}"
  end
```

フォームオブジェクトでは`'article'`を返すようにオーバーライドするようにしました。

```ruby:app/models/form/article.rb
class Form::Article < Article
  def self.carrierwave_store_id
    'article'
  end
end
```

## 結果
想定通りのディレクトリに保存できて、無事に参照できるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/4fa8bb2f-bf64-f936-6c91-5144652703a4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/53404235-cff3-c10a-6972-8983920d0e49.png)

## おわりに
Rails5でモデルの継承元がActiveRecord::BaseからApplicationRecordに変わったのですが、これが地味に助かることが多くて…。
長く広く使われているフレームワークの強みを感じました。
AtCoder Beginner Contest 252 参戦記

# AtCoder Beginner Contest 252 参戦記

## [ABC252A - ASCII code](https://atcoder.jp/contests/abc252/tasks/abc252_a)

1分で突破. 書くだけ.

```python
N = int(input())

print(chr(N))
```

## [ABC252B - Takahashi's Failure](https://atcoder.jp/contests/abc252/tasks/abc252_b)

4分半で突破. 書くだけ.

```python
N, K = map(int, input().split())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

x = max(A)
if len(set(B) & set(i + 1 for i in range(N) if A[i] == x)) > 0:
    print('Yes')
else:
    print('No')
```

## [ABC252C - Slot Strategy](https://atcoder.jp/contests/abc252/tasks/abc252_c)

35分で突破. 「ここで、$S_i$​ は $0, 1, \ldots , 9$ がちょうど $1$ 回ずつ現れる長さ $10$ の文字列です。」を読み飛ばして、揃わない数字もある難しい問題に勝手にして自滅. シミュレートを `heapq` で高速化して解いたけど、高速化しなくても問題なかった模様.

```python
from heapq import heappush, heappop

N = int(input())
S = [[int(c) for c in input()] for _ in range(N)]

result = 10 ** 15
for i in range(10):
    q = []
    for j in range(N):
        heappush(q, S[j].index(i))
    used = set()
    while len(q) != 0:
        x = heappop(q)
        if x in used:
            heappush(q, x + 10)
        else:
            used.add(x)
            t = x
    result = min(result, t)
print(result)
```

冷静になって考えればシミュレートする必要もなくダブった分だけ10を積み増せばいいと分かる.

```python
N = int(input())
S = [[int(c) for c in input()] for _ in range(N)]

result = 10 ** 15
for i in range(10):
    t = {}
    for j in range(N):
        x = S[j].index(i)
        t.setdefault(x, 0)
        t[x] += 1
    result = min(result, max(k + (t[k] - 1) * 10 for k in t))
print(result)
```

## [ABC252D - Distinct Trio](https://atcoder.jp/contests/abc252/tasks/abc252_d)

7分半で突破. 過去に似たような問題を解いたような. 組み合わせの問題なのでソートしても大丈夫. ソートさえすれば、真ん中に対し、左右がどこまで移動できるかがにぶたんで $O(\log N)$ で取れるので、$O(N \log N )$ で解ける.

```python
from bisect import bisect_left, bisect_right

N, *A = map(int, open(0).read().split())

A.sort()

result = 0
for j in range(1, N - 1):
    i = bisect_right(A, A[j] - 1)
    k = bisect_left(A, A[j] + 1)
    result += i * (N - k)
print(result)
```
パナソニックグループプログラミングコンテスト2022 (AtCoder Beginner Contest 251) 参戦記

# パナソニックグループプログラミングコンテスト2022 (AtCoder Beginner Contest 251) 参戦記

## [ABC251A - Six Characters](https://atcoder.jp/contests/abc251/tasks/abc251_a)

2分で突破. 書くだけ.

```python
S = input()

print((S * 6)[:6])
```

## [ABC251C - Poem Online Judge](https://atcoder.jp/contests/abc251/tasks/abc251_c)

10分?で突破. オリジナルでないものを弾いて、得点、提出順の2キーソートをして終わり. 2キーソートが無ければ、安定ソートで提出順、得点の順で2回ソートすればOK.

```python
from sys import stdin

readline = stdin.readline

N = int(readline())
a = []
s = set()
for i in range(N):
    S, T = readline().split()
    T = int(T)
    if S in s:
        continue
    s.add(S)
    a.append((T, -i, S))
a.sort(reverse=True)
print(-a[0][1] + 1)
```

## [ABC251B - At Most 3 (Judge ver.)](https://atcoder.jp/contests/abc251/tasks/abc251_b)

19分?で突破. B問題なのに分かんねーとなって、結局牛刀を用いた.

```python
from itertools import combinations

N, W, *A = map(int, open(0).read().split())

a = [x for x in A if x <= W]
s = set(a)

for x, y in combinations(A, 2):
    v = x + y
    if v > W:
        continue
    s.add(v)

for x, y, z in combinations(A, 3):
    v = x + y + z
    if v > W:
        continue
    s.add(v)

print(len(s))
```

そうか、3重ループで良かったのかー. 全探索はC問題だったはずなのに.

```python
N, W, *A = map(int, open(0).read().split())

t = A[:]

for x in range(N - 1):
    for y in range(x + 1, N):
        t.append(A[x] + A[y])

for x in range(N - 2):
    for y in range(x + 1, N - 1):
        for z in range(y + 1, N):
            t.append(A[x] + A[y] + A[z])

print(len(set(x for x in t if x <= W)))
```

## [ABC251E - Takahashi and Animals](https://atcoder.jp/contests/abc251/tasks/abc251_e)

30分?で突破. 2回連続で取らないということは許されないので、今回取るのが必須かどうかと、最後取るのが必須かどうかの4パターンについて最小値を DP すれば解ける.

```python
N, *A = map(int, open(0).read().split())

# last: must, this: must
a = 0
# last: optional, this: optional
b = A[0]
# last: must, this: optional
c = 10 ** 15
# last: optional, this: must
d = 10 ** 15
for i in range(1, N - 1):
    # from a
    nc = a + A[i]
    # from b
    nb = b + A[i]
    nd = b
    # from c
    na = c
    nc = min(nc, c + A[i])
    # from d
    nb = min(nb, d + A[i])
    a = na
    b = nb
    c = nc
    d = nd
a += A[N - 1]
c += A[N - 1]
d += A[N - 1]
print(min(a, b, c, d))
```

## [ABC251D - At Most 3 (Contestant ver.)](https://atcoder.jp/contests/abc251/tasks/abc251_d)

突破できず. 解説を読んで、だからおもりの個数が300個以下だったのかーってなった.

```python
W = int(input())

print(297)
print(*sum(([x, x * 100, x * 10000] for x in range(1, 100)), []))
```
CH340KでESP単体に1.5Mbpsで書き込む

# 動機
今まで[devkit-c](https://akizukidenshi.com/catalog/g/gM-15673/)で我慢していたが16MBに惹かれてで [32E 単品(¥360)](https://akizukidenshi.com/catalog/g/gM-15675/)を買ってしまったので書き込み回路を用意する必要がでてきた
そもそも3.3VのUSB→シリアルがあまり売っていないしどれも高いし自動書き込みも欲しかったので作ることにした

# シリアル変換ic
必要条件は
- 3.3V対応
- 自動書き込み回路で使うDTRとRTS端子があること

の2つ
(自動書き込み回路については調べればたくさん出てくるので割愛)

手始めに秋月さんでいつも通り安い順にして下から当たっていく
するとCH340E, CH340Nに続いて3番目にCH340Kが出てくる
EとNはDTR端子が無いがKはある

データシートを見るとコンデンサ2つを繋ぐだけで使えてしまうようである
便利便利
とりあえず買う

ところで信号のHighの出力電圧はVcc(5.0V)-0.5=4.5Vらしいんですけど
データシートでは5Vも3.3Vも2.5Vも1.8Vでも通信できちゃうんだぜどや
って言ってて逆流防止のダイオードがあるとはいえ中の人まだ理解できていない

つまり恐らくリセットピンとしてDTRを引き出せば5VなArduinoも書き込める……?

# その他部品
CH340K(¥70)に加えて
- [0.1uF(¥2.5)](https://akizukidenshi.com/catalog/g/gP-13374/) x3
- [NchFET(¥4)](https://akizukidenshi.com/catalog/g/gI-04232/) x2
- [USB Aオス(¥50)](https://akizukidenshi.com/catalog/g/gC-02236/)
- [Fサイズスルーホール基板(¥15)](https://akizukidenshi.com/catalog/g/gP-12731/)

を使った
合計はなんと¥150.5
0.1uFは2個でも良いが安定化のためにGND-EN間に入れると良いらしいので入れた

# 回路
結果から言うとこの回路で正常に動作した
出力はTXD→RXD,RXD→TXDそれ以外はそのままESP側の同じシルクの端子に繋ぐ
使うにはESPに電源が供給されていてENはプルアップされている必要がある

データシートを読んで分かったことそのままである
V3はコンデンサを挟んでGNDに繋ぐことで3.3V出力にする端子らしい
電源に挟む0.1uFをケチるとPCが壊れたUSBだって言い張ってくるので注意
![A44A9FBF-575D-4E74-876E-131B8D3623ED.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/5a18774e-85e9-7a73-d559-b228ff16a30a.jpeg)


# 試作
電源の0.1uFをケチって動かなかったのでダメ元で繋いでみたら動いた
書き込んで動作させた様子
写真左上のUSBがそれ
![92F79F05-2FCF-4248-A78F-4EE578494D66.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/573e9d09-4850-b061-85f5-0b703d7bdd4c.jpeg)

# 本番
青が表面の部品白が裏面の部品
鉛筆はUEWの配線
どうせジャンパ線で繋ぐので近い順に引き出した
![EF247C97-1B1F-4D41-96BE-520061ECE8FE.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/dc879cde-a109-1ee6-67e0-843df1a4390e.jpeg)
足を折らないように注意して曲げる
![428D6702-DA27-4CD7-A0F6-CC0DB87FB07C.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/fe1c9c8c-8ea0-1bfd-53e4-e57a764cc461.jpeg)
USBは4本のピン以外切って半田で固定した
完成品
![BA767929-0D38-4469-A9D0-B6B16C82635A.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/3224a465-50a2-3143-3f61-80054d8bcaa4.jpeg)![2580CE66-580C-4C11-B86E-2100BC5B5F8A.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/28c85875-c637-9309-3be8-dfb23e864f64.jpeg)

# 1.5Mbps
[2022/5/27 追記]2Mbpsの挙動がだいぶ怪しかった(個体差?)ので1.5Mbpsに下げました
Arduino IDEのCtrl+,で設定を開いて下にある詳細設定のリンクを押してアプリのフォルダを開く
適当に漁って packages\esp32\hardware\esp32\...\boards.txt にたどり着いたらそれらしいところに
```
esp32.menu.UploadSpeed.1500000=1.5M (CH340K)
esp32.menu.UploadSpeed.1500000.upload.speed=1500000
```
を追記
Arduino IDEを起動するとメニューに項目が増えているのでそれを選択してやると1.5Mbpsで書き込むようになる

![0DDA3ADE-42EE-4075-B52B-012C103683FD.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479627/040d3d53-7332-4d0a-b62c-ce544a2556a5.jpeg)
ESP側のRXをプルアップすれば2, 3Mbpsも行けるらしい

# おしまい
ESP単体(¥360)+これ(¥150.5)=¥515.5
Devkitの¥1280が高く見えるようになった
MotionLayoutの例を試してみる(キーフレームの循環)

前回はキーフレームの補間をやりました。

[キーフレームの補間](https://qiita.com/yuta317/items/f27a553603a3e179e5fa)

# 公式リファレンス
https://developer.android.com/training/constraint-layout/motionlayout/examples?hl=ja

https://developer.android.com/training/constraint-layout/motionlayout/ref?hl=ja



リンク先に公式サンプルがあります。
[キーフレームの循環](https://developer.android.com/training/constraint-layout/motionlayout/examples?hl=ja#keyframe_cycle)

```
<KeyFrameSet>
  <KeyCycle
    android:translationY="0dp"
    motion:framePosition="100"
    motion:motionTarget="@id/button"
    motion:waveOffset="0"
    motion:wavePeriod="0"
    motion:waveShape="sin" />
  <KeyCycle
    android:translationY="200dp"
    motion:framePosition="20"
    motion:motionTarget="@id/button"
    motion:waveOffset="0"
    motion:wavePeriod="1"
    motion:waveShape="sin" />
  <KeyCycle
    android:translationY="0dp"
    motion:framePosition="0"
    motion:motionTarget="@id/button"
    motion:waveOffset="0"
    motion:wavePeriod="0"
    motion:waveShape="sin" />
</KeyFrameSet>
```

# KeyCycle

framePositionとmotionTargetに関しては前回に書いたので今回は説明しないです。


android:translationY今回は上下の振れ幅の大きさになります。


waveShapeは『sin | square | Triangle | sawtooth | reverseSawtooth | cos | bounce』を設定できます。これは波形の形を決めています。


wavePeriodは波形のループする回数です。今回は１なので上下のアニメーションが1回です。


以上となります。
これでキーフレーム関係は終わりです。
[2022年版]実体験をもとに独学でプログラミング学習するためのロードマップを紹介

# はじめに

今回は「**独学でプログラミング学習するロードマップ**」について紹介していきます。

「**独学でプログラミング学習したいけど何すれば良いかわからない...**」

「**独学でプログラミング学習してるけど、このやり方でいいのかな？**」

「**独学でエンジニアなるに何したら良い？**」

あなたはこんな悩みを抱えていませんか？

この記事を読むことで、「**独学でプログラミング学習する手順**」がわかり、**エンジニアになるにはかなにをすればよいか**までわかります。

前置きは早々に早速ロードマップを見ていきましょう！

# ロードマップ全体

まずは独学でプログラミング学習するロードマップの全体を見ていきましょう。

::: note
- 下調べ
- 動画でインプット
- 書籍でインプット
- 基礎アウトプット
- 応用アウトプット
:::

この５ステップが全体の構成です。

１つ１つ丁寧に確認していくので少し長くなってしまいますが、ぜひエンジニアを目指している方や独学でプログラミング学習しようとしている方、学習中の方の参考になれば幸いです。

# 下調べ

「**いきなり何の下調べするの？**」

「**すぐにプログラミング学習した方がいいんじゃない？**」

こんな声が聞こえてきそうですが、この部分が一番重要です。

ただしこの段階に時間をかける必要はありません。

1日ほどで調べ終わりますが、今後自分が進むべき道が定まるので、ぜひスキップせずやってみてください。

(もちろん現在プログラミング学習中の人にも役立つことです。)

では見ていきましょう。

## エンジニアの種類を知る

エンジニアと一口に言ってもさまざまな種類があります。

「**フロントエンドエンジニア**」、「**バックエンドエンジニア**」、「**インフラエンジニア**」、「**機械学習エンジニア**」、「**データサイエンティスト**」、「**iOSエンジニア**」…

パッと思いつくものだけを書いてもこれだけあります。

このことについて調べると、「**自分がやりたいこと**」、「**自分が辿るべき道**」が明確になってきます。

例えば「**機械学習エンジニア**」を目指しているのに、スマホアプリの学習やデザインの学習をしてしまうとだいぶ遠回りになってしまいます。

自分が目指す未来へ最短で辿り着くために、しっかり調べましょう。

## 言語を選ぶ

前章のエンジニアの種類を知るで「**自分がやりたいこと**」、「**自分が辿るべき道**」が明確になりました。

次にするべきことは「**プログラミング言語**」を決めることです。

普通の言語を学ぶ際、

「**どの言語でもいいからとにかく日本語以外を学びたい！**」

なんてことをする人はほとんどいません。

プログラミングでも同様で、

「**自分がやりたいことを実現できる**」

プログラミング言語を選ぶべきです。

そのためにはプログラミング言語ごとの特徴などを調べて、1番自分が学んでみたいというが言語を1つに絞りましょう。

## 計画を立てる

前章までで、「**自分がやりたいこと**」と「**学習するプログラミング言語**」が決まりました。

最後にすることは「**学習計画を立てる**」ということです。

「**計画立ててる間に学習した方が良くない？**」

「**計画立てるのめんどくさい…**」

という声が聞こえてきますが、重要なことなので飛ばさず読んでください。

まずは計画を立てる理由から説明していきましょう。

計画を立てる理由はシンプルで、

「**ダラダラ学習を避ける**」

ためです。

独学だと特に初めのうちは一緒に学習する仲間もいなければ、課題などもありません。

そのため、ダラダラと学習してしまい、ほとんど進まず1年が経って挫折。

こんなことが起こりやすいです。

これを避けるために、「**いついつまでにここまで終わらす！**」という計画を立てる必要があるのです。(もちろん計画を立ててもできない人はできないです。)

ではその計画はどのように立てれば良いのか？

計画と聞くと細かく細かく決める必要がありそうですが、今回の場合はざっくりで大丈夫です。

例えば書籍を使用しているなら、

「**第1章から第5章までを今日で終わらして、残りの章は明日で終わらす**」

などです。

できれば1ヶ月から数ヶ月先まで計画を立てられると良いですね。

1ヶ月目はインプットメインで進め、2ヶ月目からはアウトプットメインで進めるなど、外枠を決めてから詳細を決めていくのもありです。

改めて、ここで大事なのは「**ダラダラ学習を避ける**」ことなので、細かく決めすぎないでください。(あまり細かく決めすぎると、ほぼ計画通りに進まず挫折するきっかけになります。)

## まとめ

では「**下調べ**」ついて簡単にまとめていきましょう。

::: note
- エンジニアの種類をしる。
  - エンジニアの種類を知り、「自分がやりたいこと」を実現できるものを選択する。
- 言語を選ぶ
- プログラミング言語ごとの特徴をしり、「自分がやりたいこと」に合った言語を選ぶ。
- 計画を立てる。
  - 学習計画を立てて挫折を防止。
:::

下調べができたらたら次章から早速学習の手順を見ていきましょう。

# 続き

これより先は以下の記事にまとめています。

https://chaldene.net/learn-programming

より詳しくロードマップについて解説しているので、興味がある方はぜひ！
（もちろん無料です！）
5.5 (標準) 順序統計量1

## 方針

順序統計量は同値変形によって分布関数を考える．

## 答案

![5.-11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/4f25367e-dd8d-7afc-0d2b-ef79a4e9d84d.jpeg)

## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
トランシーバーの規格について

インフラエンジニアをしております。
検証環境構築の際に調べた、トランシーバーの規格についてまとめました。
適切なトランシーバーを搭載することで、リンクアップやFCSエラー回避につながります。
雑多なメモですが参考にしていただければ幸いです。


# トランシーバ規格

例：SFP-10G-SR
　　①　②　③

※規格によって①～③の表記の順番に差異がありますが、大体同じ

①：大きさ/伝送速度
②：伝送速度
③：到達距離/動作温度範囲


# ③：到達距離/動作温度範囲について
※動作温度範囲については、「商用動作温度範囲 23 ～ 158ºF（-5 ～ 70ºC）」がほどんとですので割愛します

### マルチモード(短距離/波長850nm)
|適応ケーブル|種類|ケーブル長さ|
|:---------------------------------|:--------------|:-------------|
|MMF（橙色のケーブルが多い）|SR(Short Range)|最大300m|
|MMF|SX|220m~550m|


### シングルモード(長距離/波長1310nm O-Band)　
|適応ケーブル|種類|ケーブル長さ|
|:----|:--------------|:-------------|
|SMF（黄色のケーブルが多い）|LR(Long Range)|最大10 km|
|SMF|LR(Long Range)|最大10 km|
|SMF|LH|最大10 km|
|SMF|LX|最大10 km|
|SMF|EX|最大40 km|

### シングルモード(長距離/波長1550nm C-Band)　
|適応ケーブル|種類|ケーブル長さ|
|:----|:--------------|:-------------|
|SMF|ER  |最大40 km|C-Band|

### マルチ&シングル兼用
|適応ケーブル|種類|ケーブル長さ|
|:----|:--------------|:-------------|
|MMF & SMF|LRM  |最大40 km|C-Band|

参考リンク：https://www.cisco.com/c/ja_jp/td/docs/sw/wanswt/mgx8200edgeconcentrators/rn/001/78-15160.html


# その他

■伝送速度&伝送距離は何に依存するか
　・伝送速度：光多重化

　・伝送距離：波長
　　┗波長によって何が変わるか
　　　┗減衰値
　　　　┗減衰値が小さければ、その分長距離通信が可能になる
　　　　┗1410nmぐらいで減衰値は一回上がる↓下記資料参照

参考
https://www.janog.gr.jp/meeting/janog45/application/files/6715/7984/3115/032_100gdci_02-kato.pdf



■CFP2-ACO/DCO　トランシーバについて
　・特徴
　　┗長距離（100km以上？）
　　　┗https://mpls.jp/2020/presentations/shtsuchi-400GZR.pdf
　　┗転送容量が多い

　・使用箇所
　　┗伝送装置


■CFP2-ACO/DCO　で使われている技術
　・光多重化（WDM）
　　┗光ケーブルの中を通る光信号は、波長が違うと干渉しない
　　　┗疑似的に複数本のケーブルをしようしている感じにできる
Ruby で素数計算プログラムを作る (無限長)

# コード

```rb
prev_numbers = []

# 1は素数ではないので、2からカウントアップする
2.step do |current_number|
  not_prime_number = false

  # 今までに出てきた数全てで今の数を割る
  prev_numbers.each do |prev_number|
    if (current_number % prev_number).zero?
      not_prime_number = true
      break
    end
  end

  # 次の数を「今までの数全て」で割るために、今までの数を覚えておく
  prev_numbers.push current_number

  puts current_number unless not_prime_number
end
```

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89618/0b034452-ae67-d8f2-8fbf-977dba5e0034.png)




<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
neosでlogix その84

# 概要
neosでlogixやってみる。
Playback Stateノードを使ってみる。

# 写真

![2022-05-21 20.56.27.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/6a8a5409-a731-d1bc-f73b-6e416cd6207b.jpeg)

# Playback State

```
Inputs
 	IPlayable	Source
Outputs
 	Bool	IsPlaying
 	Bool	Loop
 	Float	Position
 	Float	NormalizedPosition
 	Float	ClipLength
 	Float	Speed
```


# 手順

- devtooltipを装着。
- 新規->3d->box
- インスペクターを開き、コンポーネントを追加
- Assets>StaticAudioClipProvider
- Audio>AudioOutput
- Audio>AudioClipPlayer
- logixtooltipを装着。
- インターフェースを取り出す。
- ノードブラウザを表示。
- Playback>Playをスポーン。
- Playback>Playback Stateをスポーン。
- つなぐ

# サンプルコード

```

[Category("LogiX/Playback")]
[NodeName("Playback State")]
public class PlaybackReadState : LogixNode {
	public readonly Input<IPlayable> Source;
	public readonly Output<bool> IsPlaying;
	public readonly Output<bool> Loop;
	public readonly Output<float> Position;
	public readonly Output<float> NormalizedPosition;
	public readonly Output<float> ClipLength;
	public readonly Output<float> Speed;
	protected override void OnEvaluate() {
		var playable = Source.EvaluateRaw();
		if (playable != null)
		{
			IsPlaying.Value = playable.IsPlaying;
			Loop.Value = playable.Loop;
			Position.Value = playable.Position;
			NormalizedPosition.Value = playable.NormalizedPosition;
			ClipLength.Value = playable.ClipLength;
			Speed.Value = playable.Speed;
		}
		else
		{
			IsPlaying.Value = false;
			Loop.Value = false;
			Position.Value = 0f;
			NormalizedPosition.Value = 0f;
			ClipLength.Value = 0f;
			Speed.Value = 0f;
		}
	}
	protected override void OnCommonUpdate() {
		var source = Source.Evaluate();
		if (source != null && source.IsPlaying)
			NotifyInputChange();
	}
}

```
以上。
【Kotlin】RoomでDateを扱う方法（ついでにSimpleDateFormatを使って表示）

RoomでDate型を扱うときにコツがいるのを知ったのでそれをまとめていきます（ちなみに、めっちゃ簡単でした）

## この記事で分かること

- RoomでDate型を使用する方法
- 日本時間に合わせ、「2022/05/22(日)」のようなスタイルでDateを表示する方法


## 実際にやってみる

このようなメモアプリの一覧画面で実際に説明していこうと思います。
※コードは必要な部分だけを取り上げていきます。

![Screenshot_20220522_030017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1630025/eed50398-ab7c-4834-c0d9-754184d3ab77.png)

### Before

以下のように作成日時を `Date` 型で持つようなMemoエンティティを作成したところ、動きませんでした…。どうやらRoomでは `Date` をそのまま扱えないようです。

``` kotlin:Memo.kt
@Entity(tableName = "memo")
data class Memo(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,

    @ColumnInfo(name = "title")
    val memoTitle: String,

    @ColumnInfo(name = "created_at")
    val createdAt: Date
)
```

（`MemoDatabase` も後で改善するので、この段階で登場させてます）

``` kotlin:MemoDatabase.kt(Before)
@Database(entities = [Memo::class], version = 1, exportSchema = false)
abstract class MemoDatabase : RoomDatabase() {
    abstract fun memoDao(): MemoDao
}
```

### After：`@TypeConverter` ・ `@TypeConverters` を使用

以下の2点を行うだけでDateを使用できます

1. `@TypeConverter` を活用し、コンバータークラスを作成
1. 定義したコンバータークラスをRoomが認識できるように、`@TypeConverters` を `MemoDatabase` に追加

``` kotlin:DateConverters.kt
class DateConverters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }

    @TypeConverter
    fun dateToTimestamp(date: Date?) : Long? {
        return date?.time
    }
}
```

``` kotlin:MemoDatabase.kt(After)
@Database(entities = [Memo::class], version = 1, exportSchema = false)
@TypeConverters(DateConverters::class) // ここを追加！！
abstract class MemoDatabase : RoomDatabase() {
    abstract fun memoDao(): MemoDao
}
```

これだけでOKです！
ちなみに、Databaseにはこのような形で保存されています。（一部今回は使用していないので伏せました）
![スクリーンショット 2022-05-22 034434.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1630025/d445dd2e-e641-e41d-c7a6-7d9218bbe502.jpeg)


### おまけ：`SimpleDateFormat`を活用して作成日時を画面に表示

ついでに日本時間に合わせ、「2022/05/22(日)」のようなスタイルで画面に表示して確認してみましょう。
ここも少し工夫が必要です。

``` kotlin
fun bind(memo: Memo) {
    // フォーマットを設定
    val sdf = SimpleDateFormat("yyyy/MM/dd(EEE)", Locale.JAPAN)

    // タイムゾーンを設定
    sdf.timeZone = TimeZone.getTimeZone("Asia/Tokyo")

    binding.apply {
        memoTitle.text = memo.memoTitle

        // フォーマットを適用
        dateText.text = sdf.format(memo.updatedAt)
    }
}
```

## 結論


- RoomでDate型を使用するには…
    - [@TypeConverter](https://developer.android.com/reference/androidx/room/TypeConverter) でコンバータークラスを作成
    - [@TypeConverters](https://developer.android.com/reference/androidx/room/TypeConverters) を `xxDatabase` に追加
- 日本時間に合わせ、「2022/05/22(日)」のようなスタイルでDateを表示する方法
    - `SimpleDateFormat("yyyy/MM/dd(EEE)", Locale.JAPAN)` でフォーマットを設定
    - `TimeZone.getTimeZone("Asia/Tokyo")` を使用し、タイムゾーンを設定
    - `format` で適用



### 参考資料

https://developer.android.com/training/data-storage/room/referencing-data

https://developer.android.com/reference/kotlin/java/text/SimpleDateFormat

https://developer.android.com/reference/kotlin/java/util/TimeZone



## おわりに

ここまで読んでいただき、ありがとうございました！
何かありましたら、コメントをお願いいたします。
Chromeで、aタグのURLとテキストをCSVで取得(自分用メモ)

# jQueryの読み込み
jQueryのバージョンはコピペなので古い。。。

```javascript:
    if(typeof jQuery === "undefined") {
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = '//code.jquery.com/jquery-3.5.1.min.js';
        document.head.appendChild(script);
    }

```

# CSV保存関数

```javascript
var downloadAsTextFile = function(fileName, content) {
    var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
    var blob = new Blob([bom, content]);
    var url = window.URL || window.webkitURL;
    var blobURL = url.createObjectURL(blob);

    var a = document.createElement('a');
    a.download = fileName;
    a.href = blobURL;
    a.click();  
};
var downloadAsCSVFile = function(fileName, rows) {
  var content = "";
  for( var i in rows) {
    var ary = rows[i];
    for (var j = 0, m = ary.length; j < m; ++j) {
      content += '"' + ("" + ary[j]).replace('"', '""') + '"';
      if (j !== m) {
        content += ',';
      }
    }
    content += '\n';
  }
  downloadAsTextFile(fileName, content);
};
var Queue = function() {
  this.promise = Promise.resolve(true);
  this.async = (action)      => this.promise = this.promise.then(() => new Promise((resolve) => action(resolve)));
  this.sync  = (action)      => this.async((resolve) => { action(); resolve(); });
  this.delay = (delay)       => this.async((resolve) => setTimeout(resolve, delay));
  this.open  = (url, action) => this.async((resolve) => {
    var w = window.open(url, "dummy", 'width=100,height=100');
    $(w).on('load', () => { action(w); w.close(); resolve(); });
  });
};

```

# aタグ取得
```javascript
tbl = $('div#divSettingList tr td div a').map((i, e) => [[e.text, e.href]]).get()
downloadAsCSVFile('hoge.csv', tbl)
```

# おまけ

SBIの積立設定一覧から項目を取得。
前も作った気がするけど、ページ構成が変わって使えない・・・

```javascript
var q = new Queue();
var rows = [];
$('div#divSettingList tr td div a').each((i, e) => {
    var name = $(e).text()
    var amount = $(e).closest('td').find("p:contains('設定金額')").text();
    q.open(e.href, (w) => {
        var t = $(w.document);
        var category = t.find("p:contains('モーニングスターカテゴリ')").closest("p").next("p").text().trim()
        var code     = t.find("p:contains('協会コード')").closest("tr").next("tr").text().trim()
        var cost     = t.find("p:contains('信託報酬')").closest("tr").next("tr").text().trim()
        var row = [name, amount, category, code, cost]
        rows.push(row);
        console.log(row)
    })
})
q.sync(() => downloadAsCSVFile('hoge.csv', rows))


```
AndroidStudio 等で github連携してpushしようとすると but initial push failed: remote: Repository not found. と出てプッシュできないときにすること

- リモートリポジトリは作れる
- なのにプッシュができない

そういうときは古い資格情報が残っている可能性があります


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48695/fd35c334-2ee7-bbad-6475-870993e37573.png)

コントロールパネルのWindows 資格情報の管理 を開きます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/48695/b22244f5-d928-d3fe-343d-9c63abb7eff0.png)

`git:https://github.com` を探して、削除してください

削除後、Android Studio側でもう一度pushをしようとすると git credential managerへの認可が求められると思うので、突破してください

その後もう一度Android Studioでpushします
Wordpress　JSなしで投稿記事のループをアコーディオン表示する方法　備忘録

いちばん最初に参考にした記事:
https://webdesignday.jp/inspiration/technique/css/5316/

<h2>困ったこと</h2>
チェックボックスをフラグにするのですが、input(id="")とlabel(for="")を同じにしないと、チェックボックスを消した時に動作しない・・・。foreachで回している記事に連番を付けるには・・・
あれこれ試行錯誤して、できたのがPHPのループを使ってしまうこと。
<h2>解決法</h2>

            
<?php if(have_posts()): ?>
            <?php $i =1; foreach($posts as $post): $id = $i++;?>
            <input  class="acd-check" id="<?php echo$id;?>" type="checkbox">
            <label class="acd-label" for="<?php echo$id;?>">Q.<?php the_title(); ?>
            </label>
            <div class="acd-content">
            <div class="a">A.</div>
            <?php the_content(); ?>
            </div>
             <?php endforeach; endif; ?>```
いちばん最初のリンクのコードを使用して、
あとはこのように$idを++で連番にして入れていくと、無事に１から連番でIdがinput/labelと同じになるので、チェックボックスを非表示にしても問題なくアコーディオンになる。

ポイント！
echoしないと表示されないのでidに付与されません。```<?php echo$id;?>```と書いてくださいね！
【入門】kubernetes勉強メモ②：Jetson Xavier NXでKubernetes

# わざわざローカル環境？
Kubernetesといえば、AzureのAKSやAWSのEKS,GCPのGKEのようなクラウドサービスを使うのが一般的だと思いますが、
ローカルで試せると以下のようなメリットがあります。
 + クラウドの管理コスト削減
 + 手元でコンパクトに試せるので開発速度の向上
 
ということで、物は試しやってみよう
（訳あって実行結果は載せられません。sry）

# Kubernetesとは
ざっくり言うと、コンテナ化されたアプリを自動的にデプロイ、スケーリングおよび管理してくれるいい感じのシステムです。
コンテナオーケストレーションと呼ばれてます。
詳しくは前回の記事を読んでみてください～

https://qiita.com/samurai_master/items/c41686d905adff7977a6


# 実行環境
デバイス：Jetson Xavier NX
OS：ubuntu 18.04

# やることまとめ
０．事前準備
１．Kubectlのインストール
２．minikubeのインストール
３．minikube起動
４．Kubernetesでechoserverを立てる

# ０．事前準備
まずは、Dockerをインストールしましょう！
（Dockerじゃなくてもいいんですが、とりあえず今回の環境では一番簡単だと思うのでDockerにしておきます）
公式サイト↓を参考にインストールしてください。

https://docs.docker.com/engine/install/ubuntu/

# １．Kubectlのインストール
次にKubernetesのためのCLIであるKubectlをインストールしましょう！
公式ドキュメントはこちらです↓

https://kubernetes.io/ja/docs/tasks/tools/install-kubectl/#install-kubectl-on-linux

注意点は、Xavier NXはarm64です！
そのため、以下のようなコマンドになります。
なお、環境によってはsudoでの実行が必要になります。
```
$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/arm64/kubectl"
```

次に、Kubectlバイナリの権限を変更します。
```
$ chmod +x ./kubectl
```

最後に、バイナリをPATHの中へ移動させます。
```
$ sudo mv ./kubectl /usr/local/bin/kubectl
```

インストールの確認をして終わりです。
```
$ kubectl version --client
```

# ２．minikubeのインストール

公式ドキュメントはこちらです↓

https://minikube.sigs.k8s.io/docs/start/

今回の実行環境では、以下のコマンドになります。

```
$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-arm64
$ chmod +x minikube
$ sudo install minikube /usr/local/bin/
```
とりあえず、これで各種ツールのインストールは終わりです。
次からは、インストールの確認もかねてminikubeを起動します。

# ３．minikube起動
それでは、minikubeを起動させます。
```
$ minikube start 
```

※エラーが出る場合あり。解決策としては、以下のURLのように①ユーザを追加する、②minikube start --force --driver=dockerあたりがある。

https://stackoverflow.com/questions/68984450/minikube-why-the-docker-driver-should-not-be-used-with-root-privileges

https://forums.docker.com/t/exiting-due-to-drv-as-root-the-docker-driver-should-not-be-used-with-root-privileges/113328

# ４．Kubernetesでechoserverを立てる
minikube startした後、以下のコマンドでまずはdeploymentを作成します。
deploymentとは、Pod管理のためのオブジェクトです。Podを用意するための前段階のものという感じ？

https://www.designet.co.jp/faq/term/?id=RGVwbG95bWVudA

ここでPod作成のためのイメージを持ってくるのですが、
注意点として、こちらもarm64のイメージを選ぶようにしましょう。
一例として、以下のコマンドがあります。
```
$ kubectl create deployment echoserver-minikube --image=e2eteam/echoserver:2.2-linux-arm64(ここは任意のarm64用イメージ)
```

そして、上のdeploymentを使って、サービスを公開します。
```
$ kubectl expose deployment echoserver-minikube --type=NodePort --port=8080
```

Podが作成されたかを確認します。
```
$ kubectl get po -A
```

公開されたServiceのURLは以下で取得します。
```
$ minikube service echoserver-minikube --url
```

Podの削除とdeploymentの削除は以下のコマンドです。

```
$ kubectl delete services echoserver-minikube
$ kubectl delete deployment echoserver-minikube
```

以上でローカル環境へのKubernetes導入は終了です。
お疲れさまでした。
（Xavier NX上のDocker コンテナ内にminikube導入しようとして苦しんだ話もいつかできたら・・・）

# 参考にさせていただいた記事

https://minikube.sigs.k8s.io/docs/start/

https://qiita.com/khara_nasuo486/items/08d7918690c4416ec28c

https://zenn.dev/castaneai/articles/local-kubernetes-networking
現場で使ったSQLの句や関数

現場ででデータベースの中身を確認する作業を行なっていて初めて使用する句・関数・演算子が多くあったので、忘備録として残しておく。
自分はまだ経験も浅く、ググっても求めている内容になかなかたどり着けなかったので、自分なりに残しておくことですぐに見返せるようにしておきたいという考えから本記事を残す。

索引的な感じで残すので詳細の部分までは記載しない。


# IS NULL

主にWHERE句の条件の中で使用する。
関数名の通り、値がNULLのものをチェックして抽出してくれる。

・使用例

テーブルサンプル(usersテーブル)
| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |   |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |

```
SELECT * FROM users WHERE age IS NULL;
```

出力結果
| id| name | age |
|:-:|:-:|:-:|
|  1 |  katou |   |



# IS NOT NULL

IS NULLと逆で値がNULLではないものを抽出してくれる演算子。


| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |   |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |

```
SELECT * FROM users WHERE age IS NOT NULL;
```

出力結果
| id | name | age |
|:-:|:-:|:-:|
|  2 |  saitou | 34  |
|  3 |  tanaka |  22 |



# UNION

2つのSELECTの抽出結果を統合することができる。

users1
| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |  33 |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |

users2
| id | name | age |
|:-:|:-:|:-:|
|  4 |  miyauchi |  25 |
|  5 |  miyasako |  18 |


```
SELECT * FROM users1
UNION
SELECT * FROM users2;
```

出力結果
| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |  33 |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |
|  4 |  miyauchi |  25 |
|  5 |  miyasako |  18 |


これと同じような句でUNION ALLというものがある。

違いは重複を含めるか含めないかである。

UNION:重複を含まない

UNION ALL:重複を含む


# IN
 IN句で指定した値に一致するデータを抽出することができる。


| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |  33 |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |


```
SELECT * FROM users WHERE name IN('katou', 'tanaka');
```

出力結果
| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |  33 |
| 3|  tanaka |  22 |


# NOT IN

IN句の逆で指定した値に一致しないデータを抽出することができる。


# MAX

指定した列名の中で最大値が含まれるレコードを取得する関数。


| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |  33 |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |


```
SELECT MAX(age) AS maxAge FROM users;
```

出力結果
| id| name | age |
|:-:|:-:|:-:|
| 2 | saitou  | 34  |


MAX関数とは逆で最小値を抽出するMIN関数がある。



# GROUP BY
指定したカラムの値をキーにしてグループに分けることができる。


| id| name | age |
|:-:|:-:|:-:|
| 1  | katou  |  33 |
| 2 | saitou  | 34  |
| 3|  tanaka |  22 |
| 4 | oono  | 34  |
| 5 | saitou  | 53  |
| 6 | saitou  | 31  |
| 7 | tanaka  | 27  |



```
SELECT name FROM users GROUP BY name; 
```

出力結果
| name |
|:-:|
|  katou|
|saitou|
|tanaka|
|oono|


GROUP BYと集約関数を合わせて使用することができる。
現場ではCOUNT関数を使用することでPK重複が発生しているレコードの調査を行ったりした。

```
SELECT name, COUNT(name) AS 重複数 FROM users GROUP BY name;
```

| name | 重複数 |
|:-:|:-:|
|  katou |  1 |
| saitou  |  3 |
|  tanaka |  2 |
| oono  |  1 |


今後も新しいものを使用したら更新していく予定。
PATHについてまとめた

# PATHとは
コマンド検索パスのこと。

# コマンド検索パスとは
シェルがコマンドの実行ファイルを探すパスのこと。
`ls`というコマンドの実行ファイルは、/bin/lsにあるが、`ls`と打つだけでも実行できるのは、コマンド検索パスに/binが設定されているから。

コマンド検索パスに/bin登録すると、/binディレクトリの中にlsファイルがあるか探して、あったら実行してくれる。

# つまり、PATHを通すとは
コマンド検索パスを追加すること。

# PATHの確認方法
PATHは環境変数$PATHに設定されているので、環境変数の確認方法である`echo 環境変数名`で確認できる。
```:コマンド
echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```
パスは:で区切られていて、左のパスの方が優先度が高い。
例えばaという実行ファイルが/usr/local/binと/sbinの中にあった場合、/usr/local/binのファイルが実行される。

# コマンド実行ファイルがどこにあるか確認する方法
`which ファイル名`で確認できる。
```:コマンド
which cat
/bin/cat
```

# 参考記事
https://qiita.com/soarflat/items/09be6ab9cd91d366bf71
https://atmarkit.itmedia.co.jp/ait/articles/1605/09/news013.html
MACでLinux仮想マシン(Alma Linux)環境を構築

#### ◯環境概要
ホストOS　: macOS Monterey 12.3
仮想マシン　:　VirtualBox 6.1.32　r149290
ゲストOS　: Alma Linux 8.5 X86_64　4.18.0-372.9.1.el8.x86_64

###### 1.事前準備　パッケージ管理システムのインストール
依存性の解決をするのに必要と思われる。
コンソールで以下コマンドを実行しインストールする。
>/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

###### 2.MACへViertual Boxをインストール
ダウンロードサイトからインストールイメージを入手しインストールする。
特に特殊な手順は無かった。
>https://www.oracle.com/jp/virtualization/technologies/vm/downloads/virtualbox-downloads.html

###### 3.MAC上でViertual Boxの実行許可
ダウンロードしたアプリケーションの実行を許可。
システム環境設定 - セキュリティーとプライバシー - 一般タブを開く
鍵をクリックして編集を有効にしてから
「開発元”Oracle America, Inc.”のシステムソフトウェアがアップデートされました。」の「許可」を押下

許可が無いと以下のようなメッセージが出て起動できない。
>　Kernel driver not installed (rc=-1908)

> 参考URL
> https://www.nemotos.net/?p=3707

###### 4.Alma Linuxのディスクイメージを入手
>URL
>https://almalinux.org/ja/

>お馴染みの理研のFTPサイト
>http://ftp.riken.jp/Linux/almalinux/8.6/isos/x86_64/
ディスクに余裕があるなら「AlmaLinux-8.6-x86_64-dvd.iso」をダウンロード。
ネットワークインストールはここでは触れない。

###### 5.VertualBoxにゲストOSをインストール
①仮想マシンを構成
　新規を押下し仮想マシンの構成を決める。多少時間が掛かるが、ストレージイメージは固定長にする方がリスクが少ない。
　あとは、マシンの許容できる範囲でリソースを割り振る。
　仮想マシンが構成できたら。

②ディスクイメージをマウント
　構成を作成した仮想マシンを選択し「設定」を押下する。
　ストレージを開き光学ドライブのアイコンをクリックしダウンロードしたディスクイメージをマウントする。

③仮想マシンを起動しLinuxをインストール
　GUIのLinuxインストール画面が出る為、任意にLinuxを構成する。

注意：仮想化に対応していないCPUの場合、このタイミングでエラーが出て中断されてしまう！


###### 5.画面解像度を調整
①Linuxをシャットダウンし、文字サイズが見やすいサイズまで拡大する
　VirtualBoxから作成したLinux仮想マシンを選択し設定を押下する。
　ディスプレイ「表示倍率」をみやすいサイズに調整。
　150~300ぐらいで調整するのが良いと思う。

②Extension Pack をダウンロード
　以下のサイトの「VirtualBox 6.1.34 Oracle VM VirtualBox Extension Pack」・All supported platforms　をダウンロード
>URL
>https://www.virtualbox.org/wiki/Downloads

③Extension Packを追加
　VirtualBoxのマネージャを開きツールを右クリックする
　環境設定 - 拡張機能タブ -　拡張パッケージ　へダウンロードしたパッケージを追加
　 
④Extension Packをマウント
　Linux仮想マシンを選択し「設定」を押下する。
　ストレージを開き光学ドライブのアイコンをクリックし追加した拡張パッケージを選択しマウントする。

⑤Linux仮想マシンへパッケージをインストール
 Linuxのターミナルを開き以下ディレクトリまで移動
>/run/media/[ユーザ名]/VBox_GAs_6.1.32へ移動

 事前に必要な物をインストール
>yum -y install epel-release
>yum -y groupinstall "Development Tools"
>yum -y install dkms bzip2 gcc make kernel-devel kernel-
　
　拡張パッケージをインストール
>sh ./VBoxLinuxAdditions.run

>参考URL
>https://urashita.com/archives/34216
>https://qiita.com/boscoworks/items/76c31a163d39a08bf81b

⑥Linux再起動
　再起動後画面リサイズに合わせて解像度が変わる
　
　機動直後は画面の描写が遅れたり、真っ黒になることがある
　その場合、リサイズを行い強制的にリフレッシュを走らせる必要がある
久しぶりのPython3系環境構築でエラーにハマった

# 前提条件
- MacBook Pro (14インチ、2021)
- macOS Monterey
- バージョン 12.2.1
- チップ Apple M1 Pro

# 事前確認
新型MacBook ProはデフォルトでPython2系がインストールされています。
```
$ python -V
Python 2.7.18
```
Python3もインストールされてるか確認します。
ひとによっては入ってないかも。
```
$ python3 -V
Python 3.8.9
```
# pyenvのインストール
```
$ brew install pyenv
$ pyenv -v
pyenv 2.3.0
```
# 「.zshrc」と「.zprofile」の設定
ここが問題でpyenvのアップデートでpythonの環境変数を指定しないといけなくなったことが原因らしいです。下記コマンドを叩いてください。

```
// .zshrc
$ echo 'eval "$(pyenv init -)"' >> ~/.zshrc
$ cat .zshrc

// .zprofile
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile
$ echo 'eval "$(pyenv init --path)"' >> ~/.zprofile
$ cat　.zprofile
```
最終的にこんな感じです。vimでベタ書きでもOKです。
```
# .zshrcに以下を記載
eval "$(pyenv init -)"

# .zprofile に以下を記載
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
```
ここが変更点です。<font color="Red">eval "$(pyenv init --path)"</font>

```
// 環境変数を再読み込みします
source ~/.zshrc
```

# Xcodeインストールしてない方へ
XcodeはApp Storeからインストールしてください。
有線LAN推奨、<font color="Red">2時間くらい</font>掛かりました。。。
Wi-fiの場合は、スリープ中もダウンロードが続く「Power Nap」を一応確認してください。(デフォルトON)

```
// インストール中のログ確認(あまりに遅かったため)
tail -fn 100 /var/log/install.log

// インストールされてるか確認
xcode-select -v
xcode-select version 2392.
```

# デフォルトVersion切り替え
```
$ pyenv versions
* system (set by /Users/user_name/.pyenv/version)
$ pyenv install --list
$ pyenv install 3.10.4
$ pyenv versions
* system (set by /Users/user_name/.pyenv/version)
  3.10.4
```
ここでpyenv install 3.8.9(失敗)
環境構築可能なバージョンは、3.9.8以降のようです。

それより古いと下記のビルドエラーが出ます。
<font color="Red">python-build: use zlib from xcode sdk
BUILD FAILED (OS X 12.2.1 using python-build 20180424)</font>


```
// ローカルのPythonバージョンの切り替え
$ pyenv global 3.10.4

// ローカルのPythonバージョン確認
$ Python -V
Python 3.10.4
$ python3 -V
Python 3.10.4
```
これでPython3系環境構築完了です。

結構、色々と調べて苦戦してしまいました。。。
何かあればコメントお願いします。

# 参考
[pyenvでPython2系と3系を切り替える【macOS】](https://qiita.com/yyyyy__78/items/29634fdbecd84b9a59da)
[【随時更新予定】macOS 12.2 Monterey上のpyenvで環境構築可能なPythonのバージョンの備忘録](https://qiita.com/y-vectorfield/items/895fe8d140ddccd061b7)
[Python pyenv アップデートでpathの設定が変更](https://timesaving.hatenablog.com/entry/2021/05/15/150000)
[MacでPower Napをオン/オフにする](https://support.apple.com/ja-jp/guide/mac-help/mh40774/12.0/mac/12.0)
Autonomous Database ユーザー作成

Oracle CloudのAlwaysFreeを使ってユーザー作成する際、いつも通りCreateUser文でユーザー作成しようとしたらGUIでユーザー作成が出来た。権限などもここで制御出来る。

Databaseを作成後、以下の操作。
※Database作成は機会があれば別途記載。

前提：Databaseが使用可能状態であること
※今回はATPを作成し確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/91b6095d-9199-d72b-71d9-3d57e242b66f.png)

画面上部のメニューの「データベース・アクション」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/6426b900-134f-fa1f-137b-06f712c9285a.png)

管理　の「データベース・ユーザー」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/a0614f06-d919-a6f3-218f-39fefd5d5ef3.png)

画面右上の「＋ユーザーの作成」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/6728e819-0160-4025-54b2-0840c39fc4d9.png)

ユーザーの情報を入力し、必要事項を入力したら右下の「ユーザーの作成」ボタンが有効になるので押下すると作成される。
※必須項目であるユーザー名、パスワードを入れればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/e77bc599-6fdb-905a-d02b-0c7ec568df5d.png)

それ以外の選択項目、入力項目については追って記載。

作成後、ユーザーの一覧に以下のように作成したユーザーが表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/3afe8eb7-dd65-ab87-5daa-94f40f7548ed.png)

右下の新しいタブで開くボタンを押すと、新しいタブで作成したユーザーメニューが出てくる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/8f4b783f-96ee-b0f5-5b1e-6ae48d462a40.png)

SQLを押下するとADMIN同様チュートリアルが始まり、無事作成したユーザー権限で操作する事が出来るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/2e2f1883-3eb5-1f78-8aa6-96d58e398629.png)


RESOURCE権限が当たっていたので無事テーブルも作成出来た。
一旦ここまで。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2607243/3d3e3394-21d2-6bf6-9d65-fe3e84164da2.png)
連想配列とは？

JavaScriptの開発で連想配列を使ったので調べてまとめてみました！
間違っていればご指摘お願いします！
# 結論
**「連想配列とは、配列で添字（インデックス）に数字を与えているのに対して、好きな文字を与えることができる配列のことである。」** 
```sample.js
// 配列
var result_array = [
  '70点',  // 値１
  '60点',  // 値2
  '92点'   // 値3
];

// 連想配列
var result_associative_array = {
  tarou : '70点',  // キー1 : 値１
  jirou : '60点',  // キー2 : 値2
  hanako : '92点'  // キー4 : 値3
}
```
# Hashと同じじゃないの？
それって、RubyでいうHashのことじゃないのかなと思ったので調べたところ、厳密には違うみたいです。
## Rubyにおける連想配列（Hash)
Rubyの[リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/class/Hash.html)によると、Rubyにおける連想配列とは、ハッシュテーブルによる連想配列で、任意のオブジェクトにいるキーと、任意のオブジェクトによる値とを関連付けしています。
つまり、文字列のオブジェクトを配列の添え字に使い、値となるオブジェクトを関連付けし、変数として使えるものがRubyにおける連想配列（Hash)です。
```sample2.rb
result_hash = {
  "tarou" => "70点",
  "jirou" => "60点",
  "hanako" => "92点"
}
```

## JavaScriptにおける連想配列
JavaScriptにおける連想配列は、ObjectとMapが存在します。どちらもキーを値に設定したり、それらの値を受け取ったり、キーを削除したり、キーに何かが格納されているかどうかを判定したりすることができます。この意味で (そして他の内蔵オブジェクトがなかったため)、従来ObjectはMapとして使われてきました。今では、連想配列としては、Mapが利用されており、Objectは連想配列として扱ってはいけないようです。詳しくは下記のの記事を参考にしてみて下さい！
- [連想配列はMapを使うべきは本当か？](https://qiita.com/raccy/items/816a322fb330193e788b)
- [ObjectとMapの違い](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map#objects_vs._maps)


# まとめ
- **「連想配列とは、配列で添字（インデックス）に数字を与えているのに対し、好きな文字を与えることができる配列のことである。」**
- Rubyにおける連想配列はHashだけど、ハッシュテーブルによる連想配列である。
- JavaScriptにおける連想配列はMapであり、Objectは連想配列として扱ってはいけない。
- 「純粋な連想配列」、「RubyのHash」、「JavaScriptのMap」、「JavaScriptのObject」は、似て異なるものだった！

# 参考
https://docs.ruby-lang.org/ja/latest/class/Hash.html

https://jsprimer.net/basic/object/

https://www.pasonatech.co.jp/workstyle/column/detail.html?p=2639

https://style.potepan.com/articles/35482.html

https://zenn.dev/zassou/articles/333aa8d8dfe2da

https://qiita.com/eggc/items/9019869dae760f55e60c

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Map

https://zenn.dev/standard_soft/articles/7458d1f49fd2ef

https://qiita.com/raccy/items/816a322fb330193e788b
STM32G031J6M6(PA11 PA12,STM32 MCU based boards 2.2.0)でI2C(0x40(8ビット0x80))に「A」を連続出力する。



x 動作確認済み2022/5/22 1:20

目的
バージョン　2.2.0である
8ピンを潰すと書き換えが面倒なためPA11,PA12でI2Cを使用する
プログラムは、出来ている。
ほぼ、1日いろいろ試すに使ったので説明。
「はじめて見るおともだちに説明しなくてはならない」


なぜかわからないが下記の文法で動いた


```


  Wire.setSDA(PA12);
  Wire.setSCL(PA11);
  Wire.begin(); //pa12 pa11



```

イメージです。

![o_con480.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/26b7a9a1-e075-d894-5b27-e26bebfb7ceb.jpeg)


イメージです。


![o_con481.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/14ed5c16-0610-8b00-8871-1be2a65bb690.jpeg)



![o_con478.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2cacddbe-da99-3b5b-518f-1b44011b5d00.jpeg)


![o_con479.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a2df51e8-1588-6715-121d-63c3b6fa52fb.jpeg)




プログラム


```c++



//I2C_A_031_1

#include <Arduino.h>
#include <Wire.h>

//STM32G031J6M6 i2cピンの定義
#define sdaPin PA12    // ArduinoA4
#define sclPin PA11    // ArduinoA5

//#define en     PB7     // 1pin

#define ADDR1  0x40

//初期化
void setup() {

  delay(3000); //not Delete

//  //GPIOの初期化
//  pinMode(en, OUTPUT);

  //i2cの初期化
  //Wire.begin(sdaPin, sclPin); //STM32G031J6M6
  //Wire.begin(); //pb7 pb6 OK
  //Wire.setSDA(PB7);
  //Wire.setSCL(PB6);
  //Wire.begin(); //pb7 pb6 OK
  Wire.setSDA(PA12);
  Wire.setSCL(PA11);
  Wire.begin(); //pa12 pa11




}//setup

//メインループ
void loop() {

//  digitalWrite(en, 1); //LED ON debug

  //I2Cに送信
  Wire.beginTransmission(ADDR1);
  Wire.write('A');
  Wire.endTransmission();

  delay(500);//0.5秒待つ


//  digitalWrite(en, 0); //LED OFF debug
  delay(500);//0.5秒待つ

}//loop



```
Postgreの内部関数の()の有無がややこしすぎる

例えば、日時取得する情報関数
```
()有                      ()無し
clock_timestamp()         current_timestamp
statement_timestamp()     current_date
                          current_time
```  
等々・・・
()の有無は何かで決まっているのだろうか。
current_userはコマンドを実行したユーザー取得だけど、これも()いらないし...。current_database()には必要だし...。
これがすごいややこしいけど、覚えるしかないかなあ。
OSSDB Silver合格目指して！
【Google/IO 2022】忙しい人のための「What's new in app performance」

## はじめに
Google I/Oの [What's new in app performance](https://www.youtube.com/watch?v=DYdHLqLVspY&t=12s)の要点をまとめます。

Androidフレームワークの改善のパートは割愛しておりますのでご了承ください。


## 01 ツール
![](https://i.imgur.com/rh2VSxn.png)

### Android Studio Profiler / Perfetto
- Android StduioのProfilerでトレースできる
- それを保存しチームに共有することもできる
- またPerfettoを使用することで、Android Studioがなくても詳細に分析できる。
- 相互運用可能。Profilerでトレースした内容は、Perfettoでも開ける

### Android Vitals
- Google PlayConsoleの一部
- 実際にデバイスを使用してくれている人のさまざまなパフォーマンスを情報を確認できるのがメリット



## 02 アプリの起動
アプリの起動時間はユーザに良い影響を与える反面、悪い影響も与える。


### そもそも起動時間を短縮するのにメリットはあるのか？
アプリの起動速度を改善すると、ビジネス指標にめっちゃいい影響でる。

Google Mapsが30%起動速度を上げたら、2.4%検索が増えた。
![](https://i.imgur.com/FLxztSI.png)

zomatoはアプリの30%起動速度を上げたら、600K注文が増えた。
![](https://i.imgur.com/FQFAbLW.png)

### まずパフォーマンスを計測してみる
「自分のアプリがどれだけのパフォーマンスか？」を計測できるものがある。

それが「Macrobenchmarkライブラリ」。

アプリの起動速度、フレームのタイミングなどに関するデータを取得できる。

![](https://i.imgur.com/1y5uPEU.jpg)


Githubにサンプルあります。
https://github.com/android/performance-samples


## 03 Baseline profiles
アプリのパフォーマンスを高速化できる、非常に信頼性が高く、実装が迅速な方法。
![](https://i.imgur.com/S1gUoHn.png)

Baseline Profilesとは？
> APK に含まれるクラスとメソッドのリスト。ベースライン プロファイルは APK に含まれるクラスとメソッドのリストです。Android ランタイム（ART）がインストール時に、マシンコードへのクリティカル パスを事前コンパイルするために使用します。
引用: https://developer.android.com/studio/profile/baselineprofiles 

要は、起動時に必要な処理を事前に示しておけば、アプリの起動速度が上がりますよ的な話

開発者ブログにも詳しく書かれてます。
https://android-developers.googleblog.com/2022/01/improving-app-performance-with-baseline.html


### Baseline Profilesの導入方法
下記の2ステップ。
1. 専用のmacrobenchmarkを記述し、プロファイルを作成する
2. アプリinstall中に使用できるようにする

![](https://i.imgur.com/wQIzKUb.png)


### 「App starup」ライブラリも使える
アプリのスタートアップ中のリソースの競合を回避するのに役立つ。
起動中にContentsProviderを使用する必要がなくなり、パフォーマンスとコンポーネントの初期化が高速化する。

![](https://i.imgur.com/WeRDYIu.jpg)




## 04 Jankの監視
- フレームを落としたり(カクカクする)などの、ジャンクを発生させないことも重要
- だいたいメインスレッドでたくさん処理をすると発生する
- ANRにもつながる。

### この改善をするとどういう美味しいことがあるの？

45% フレーム落ちを少なくしたら、10%のエンゲージメントがあがった
![](https://i.imgur.com/uBxKLhE.png)


ANRを減らしたら、20%良いレビューが増えたぜ。アンインストールも5%減ったぜ。
![](https://i.imgur.com/8uqr8aP.png)

OK CreditもANRを減らしたら、トランザクション増えた。
![](https://i.imgur.com/3PBse48.png)


### 検出方法
Profilerでジャンクの検出もできる。
１クリックで問題の詳細がわかる。
![](https://i.imgur.com/tL6lPp5.jpg)


### ジャンクの再現が難しい場合もある
ただ、ジャンクを再現するのが難しい場合がある。
たとえば、実際はジャンクが発生しているのに、トレースしたときたまたま、フレーム落ちがなくて問題なく見えてしまうなど、タイミング的な要素が絡んでくる。

### MicroBenchmarkを使えば、統計的に有意な結果が得られるまでコードをテストしてくれる
これを使えば、VitalsやProfilerで見たジャンク的なものが、単なるまぐれなのかどうかまで、示してくれる。
![](https://i.imgur.com/0iF611E.jpg)


### スペックが低いデバイスのパフォーマンス計測はどうするか？
ただ、スペック的にうんこなAndroid端末を使用してパフォーマンスを計測できるとはかぎらん。

そこで　「Jank Stats」(alpha)

ユーザのデバイスで発生したジャンクをログに記録して追跡することができる。
![](https://i.imgur.com/gsxkepa.png)

下記の3ステップでジャンクを報告する。
![](https://i.imgur.com/rrv2UBH.png)


## 感想
- PerfettoはAndroid Profilerにとって変わられたものだと思ってたけど、立ち位置としては、Android Studioでのトレースをより詳しく確認したり、Android Studioなしで結果を見たりみたいな用途っぽい
- BaseLineProfilesのファイル作成しておけば、起動速度速くなる魔法感がすごい
- Jank Statsは、アプリに入れとけば、ジャンクが発生してたらレポートしてくれるみたいな便利ものなのか？ちなレポートはどこに保存されるんだ？
- 計測の方法はいろいろあるけど、CIとかに組み込んで、定期的にパフォーマンスのチェックをしたいな
sedでファイルの先頭or末尾に文字列を挿入

# sedでファイルの先頭or末尾に文字列を挿入する方法

この投稿はsedで下記の目的で使う方法のメモです。

- [本文](#用例)
	- ファイルの先頭に文字列を挿入する
	- ファイルの末尾に文字列を追加する

- [おまけ](#蛇足のおまけ)
	- ファイルに先頭行を挿入する
	- ファイルに末尾行を追加する

## 用例

用例を見ていただければ大体何しているかわかると思います。

全用例の前提として、inという名前のファイルをカレントディレクトリに作ってあります。
その内容は下記とします。

```:in
foo
bar
```

### ファイルの先頭に文字列を挿入する

下記がそのシェルコマンドです。

`sed -e '1s|^|head-|g' in > out`

結果、outの内容は、inの先頭に「head-」という文字列を挿入した内容になります。
下記がその内容です。

```:out
head-foo
bar
```

### ファイルの末尾に文字列を追加する

下記がそのシェルコマンドです。

`sed -e '$s|$|-tail|g' in > out`

結果、outの内容は、inの末尾に「-tail」という文字列を追加した内容になります。
下記がその内容です。

```:out
foo
bar-tail
```


## 蛇足

### オプションと引数の説明

投稿本文中でsedの-eオプションに与えている文字列について少し説明します。

文字列は、 sedコマンド|置換前文字|置換後文字 の順で並んでいます。

ここではsedコマンドは置換前文字を探す範囲を指定しています。
先頭に挿入する方法で書いた`1s`というsedコマンドは、ファイルの一行目を範囲指定します。
末尾に挿入する方法で書いた`$s`というsedコマンドは、ファイルの最終行を範囲指定します。

置換前文字の"^"と"$"ですが、これらは下記対象の正規表現です。

```:正規表現
^ : 行頭
$ : 行末
```

本文中のsedコマンドでは、これらのsedコマンドと正規表現(置換前文字)を利用して、ファイル先頭・末尾を指し示して、置換を行っています。

### 蛇足のおまけ

ちなみに、置換後文字にも正規表現を含めることができます。
例えば、下記に示すようにファイル先頭行・末尾行を追加できます。

```:正規表現
\n : 改行
```

#### ファイル先頭行を追加する

`sed -e '1s|^|head-\n|g' in > out`

```:out
head-
foo
bar
```

#### ファイル末尾行を追加する

`sed -e '$s|$|\n-tail|g' in > out`

```:out
foo
bar
-tail
```

＊`echo -tail>> in`と同じことをしています。

## あとがき

まだsedを使い始めてから間もないです。
なるべく覚えやすい書き方を知りたいです。

この投稿の背景は、テキストエディタで開けない大容量のバイナリファイルの編集をする必要があったことです。
ファイル先頭と末尾に文字列を追加する必要がありました。
sedに興味があるので、sedを使おうと思いました。
sedは大容量のファイルの編集にも役立つと知りました。面白いです。

ただ、使い慣れていないので、sed実行後にちゃんと望み通りの文字を追加できたか確認したくなりました。
先頭と末尾への追記をそれぞれ確認するには、下記のようなコマンドが役に立ちました。

| 位置 | シェルコマンド | 出力文字列 |
|:-:|:-:|:-:|
| 先頭  | head -c 5 out  | head- |
| 末尾  | tail -c 5 out  | -tail |

(先頭および末尾から5文字分の出力をしています)

### スクリプトの区切り文字に`|`を使った理由

通常、sedスクリプトの区切り文字には`/`を使うことが多いと思います。
今回は、あえて`|`を使ってみました。
理由は、もし、置換前文字や置換後文字がパス文字列等(e.g. `/usr/bin`)を含むならば、区切り文字`|`を使うことによってエスケープシーケンスを省略できるからです。
覚えたてなのでエスケープシーケンスが少ない方が、見た目的にとっつきやすく感じたり、考慮することが少ないと感じています。

| 区切り文字 | シェルコマンド |
|:-:|:-:|
| `/`  | sed -e 's/\\/bin/\\/usr\\/bin/g in > out  |
| `\|`  | sed -e 's\|/bin\|/usr/bin\|g' in > out  |

区切り文字については次の記事を参考にしました : [sed でエスケープ処理をしないでURLの置換を行う](https://hacknote.jp/archives/8163/)

## 次に読みたいもの

[gnu公式サイトのsedコマンドマニュアル](http://www.gnu.org/software/sed/manual/sed.html)
[gnu公式サイトのsedコマンド一覧](http://www.gnu.org/software/sed/manual/sed.html#sed-commands-list)
[sedで使う正規表現の仕様(IEEEのもの)](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03)