OmniAICreator/Qiita-1.07M huggingface dataset:
ABC229 - D - Longest X

https://atcoder.jp/contests/abc229/tasks/abc229_d

`XX...X.X.X.`のような文字列で、$K$回まで`.`を`X`に置き換えてよい。連続する`X`の数の最大値を求める。

# 解法1

[公式解説](https://atcoder.jp/contests/abc229/tasks/abc229_d/editorial)
書き換える場所の両端を尺取法で走査する。
書き換える区間の途中にある元々の`X`の数を累積和で保持しておく。

# 解法2

書き換える場所の両端を管理するのではなく、書き換え後の連続した`X`の両端を尺取法で走査する。
累積和を計算する必要がない。さっきやってみたが出来そうでまだ出来てない。

# 解法3

元の文字列

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 | 11|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|`X`|`X`|`.`|`.`|`.`|`X`|`.`|`X`|`.`|`X`|`.`|

両端に`.`を追加する。追加しても結果は変わらない。

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 | 11| 12|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|`.`|`X`|`X`|`.`|`.`|`.`|`X`|`.`|`X`|`.`|`X`|`.`|`.`|

$ $`.`の場所を記録する。右から $i$ 番目の`.`の場所が $d_i$ になるようにする。
上の例だと、$d = [0,3,4,5,7,9,11,12]$。


| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 | 11| 12|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|`.`|`X`|`X`|`.`|`.`|`.`|`X`|`.`|`X`|`.`|`X`|`.`|`.`|
|$d_0$|||$d_1$|$d_2$|$d_3$||$d_4$||$d_5$||$d_6$|$d_7$|

$ $こうすると、`.`から`X`に変える場所の左端が $d_l$ のとき、右端は $d_{l+k-1}$　になる。
これが便利なのは、書き換え後の`X`の両端が $O(1)$ で求まること。

下は $(l,r)=(1,2)$ のとき。

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |10 | 11| 12|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|`.`|`X`|`X`|`X`|`X`|`.`|`X`|`.`|`X`|`.`|`X`|`.`|`.`|
|$d_0$|||$d_1$|$d_2$|$d_3$||$d_4$||$d_5$||$d_6$|$d_7$|
|→|左|||右|←|||||||

$ $観察すると、書き換え後の`X`の左端は $d_{l-1}+1$ 、右端は $d_{l+k}-1$ 。
なので、$l$ を変えていって $(d_{l+k}-1) - (d_{l-1}+1) + 1$ の最大値をとればよい。
ただし、元の`.`の数が$K$より少ない場合を分ける必要がある。
本番中はこれで通した。

```rust
use proconio::{input, marker::Chars};

fn main() {
    // 入力
    input!{
        s: Chars,
        k: usize,
    }

    // '.'の場所を記録する。両端を`.`で囲んでおく。
    let mut d = vec![];
    d.push(0);
    for i in 0..s.len() {
        if s[i] == '.' { d.push(i+1); }
    }
    d.push(s.len()+1);

    let mut ans = 0;
    if d.len()-2 <= k { // 全ての`.`が`X`に書き換えられる場合
        ans = s.len();
    } else {
        for l in 1.. {
            if !(l+k < d.len()) { break; }
            ans = ans.max( (d[l+k]-1) - (d[l-1]+1) + 1 );
        }
    }
    // 出力
    println!("{}", ans);
}
```

# Take Home Message

$ $１個ずつカウントする($1+1+1\dots$)のは時間がかかるので、 $f(r)-f(l)$ に変換できないか考える。
pythonでひとつ前のtxtファイルのデータを読み取ってlistの次の要素をtxtファイルに出力してくれるプログラム

#前回

前回こういうものを作りました

https://qiita.com/akechiakechi/items/86316b7d1b872f3b5a47

#今回やること
今回は前回のプログラムを少し変えて
ひとつ前のtxtファイルのデータを読み取って
listの次の要素をtxtファイルに出力してくれるプログラムをつくります

#例えば
letter.txtの中に「あ」とだけ書かれていて
このプログラムを実行すると
５０音順で次の「い」がletter.txtに上書きされる
というものです

#テキストファイルを読み込む
以下のサイトを参考にしました

https://atmarkit.itmedia.co.jp/ait/articles/2104/13/news024.html

まずコードをのせます

```py
f = open('letter.txt') 
letter = f.read()  
f.close()
```
これをすることによって，letter.txtの文字を読み取って
letterの中に文字列として入れてくれます

#５０音の何番目なのかを知る
以下のサイトを参考にしました

https://note.nkmk.me/python-list-index/

```
japanese_list = ["あ","い","う","え","お",\
         "か","き","く","け","こ",\
         "さ","し","す","せ","そ",\
         "た","ち","つ","て","と",\
         "な","に","ぬ","ね","の",\
         "は","ひ","ふ","へ","ほ",\
         "ま","み","む","め","も",\
         "や","ゆ","よ",\
         "ら","り","る","れ","ろ",\
         "わ","を","ん"]

number = japanese_list.index(letter)
number = number + 1
letter = japanese_list[number]
```

もしletter.txtに「き」という文字が入っていた場合
indexメソッドをつかって
numberに6を代入してくれます（0から数え始めるため）
そしてnumberに１を足して7になり
numberのインデックスを持つjapanese_listのリストの要素である「く」を
letterに代入してくれます

#ファイルの出力
以下のサイトを参照しました

https://work-life-enj.com/python-write-text-csv/


```py
f = open('letter.txt', 'w')
f.write(letter)
f.close()
```
これによってletter.txtに次の新しい文字が出力されます

#これでできます
丸ごとコピーしてください

```py
japanese_list = ["あ","い","う","え","お",\
         "か","き","く","け","こ",\
         "さ","し","す","せ","そ",\
         "た","ち","つ","て","と",\
         "な","に","ぬ","ね","の",\
         "は","ひ","ふ","へ","ほ",\
         "ま","み","む","め","も",\
         "や","ゆ","よ",\
         "ら","り","る","れ","ろ",\
         "わ","を","ん"]

f = open('letter.txt') 
letter = f.read()  
f.close()

number = japanese_list.index(letter)
number = number + 1
letter = japanese_list[number]

f = open('letter.txt', 'w')
f.write(letter)
f.close()
```

これを実行すると
letter.txtにもともと「あ」が入っていると
「い」をだしてくれます
Explore - "Quick tutorial - Modelling and Render Glass Bottle in Blender #oe244"

https://www.youtube.com/watch?v=yTAyPnYYbRI

# 知っていたけどできていないこと
+ Alt + LMB での連結辺の一括選択
+ M(merge)での頂点の統合。
+ Solidfyモデファイア。手動で厚みづけをしているので使える時は使ってく。

# 知らなかったこと
+ Glass BSDF　: これを使えば簡単にガラスのマテリアルが作成できる。
+ 背景画像の設定方法 : "World Propeties -> Color -> EnviromentTexture -> 画像の追加"で背景の設定ができる。自分は草原しかなかったので作品ではそれを使っている。
+ Shadow Cacher : これはオブジェクトに写る影だけを描写する機能。動画ではこれとPlaneを組み合わせて机の影を作っている。使い方は"ObjectPropety -> Visility -> Shadow Cacher"を選択するだけ。

# 感想
今までガラスのマテリアルはデフォルトのものを調整して作っていたのでこれは便利なりと思った。

# 作品
![Bottle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2316614/308c9b93-54a9-302f-b5ce-c86556dab084.png)
背景はやっつけなり。
Bad owner or permissions on /home/(user)/.ssh/config,エラーの対処法

##背景
githubにEC2からSSH接続しようとしたところ↑のように怒られた。

##原因
セキュリティが緩いので、厳しくする必要がある
(エラー発生時の権限状態↓)

```
-rw-rw-r--
```
##実行したこと

```
chmod 600 ~/.ssh/config
```

をすることで所有者のみに読み書きの与える権限を与えてセキュリティ強化した。
pythonでランダムで50音の一文字をテキストファイルに出力してくれるプログラムを作ろう！！


#目的
タイトルに書いた通りの
プログラムが必要になったからです
最後の項目にいくと
コピーだけすればいいようになっているので
すぐに使いたい方は
最後だけ見てくれればいいと思います


#ファイルの出力方法
以下のサイトを参照しました

https://work-life-enj.com/python-write-text-csv/

以下のようにすると
同じディレクト内に
out.txtとしてssssと書いてあるテキストファイルが作られます
aの中身を別の文字にすると別の文字がout.txtに上書きされます


```py
f = open('out.txt', 'w')
a = "ssss"
f.write(a)
f.close()
```

#リスト内からランダムに一つを選ぶ
以下のサイトを参照しました

https://www.delftstack.com/ja/howto/python/python-randomly-select-from-list/

https://www.delftstack.com/ja/howto/python/how-to-convert-a-list-to-string/

randomモジュールをimportして
stringに50音をうちこみました
こちらのプログラムを使うと
ランダムで一文字がstringに入ります

```py
import random

japanese_list = ["あ","い","う","え","お",\
         "か","き","く","け","こ",\
         "さ","し","す","せ","そ",\
         "た","ち","つ","て","と",\
         "な","に","ぬ","ね","の",\
         "は","ひ","ふ","へ","ほ",\
         "ま","み","む","め","も",\
         "や","ゆ","よ",\
         "ら","り","る","れ","ろ",\
         "わ","を","ん"]
string_list = random.choice(japanese_list)
string = "".join(string_list)
```


#さぁこれでできます!!
丸ごとコピーしてください

```py
import random

japanese_list = ["あ","い","う","え","お",\
         "か","き","く","け","こ",\
         "さ","し","す","せ","そ",\
         "た","ち","つ","て","と",\
         "な","に","ぬ","ね","の",\
         "は","ひ","ふ","へ","ほ",\
         "ま","み","む","め","も",\
         "や","ゆ","よ",\
         "ら","り","る","れ","ろ",\
         "わ","を","ん"]
string_list = random.choice(japanese_list)
string = "".join(string_list)

#output part
f = open('string.txt', 'w')
f.write(string)
f.close()
```
これでstring.txtに文字が出力されたはずです！！
Fortranで利用可能なライブラリ(２０２１年版)

# この記事で何を書いているか
2019年初頭に、Fortranから利用可能なライブラリを列挙した[Qiita記事](https://qiita.com/sakamoti/items/accc481868ec70bc1548)を書いた。この記事は、著者が利用する範囲で当時知っていたライブラリを列挙したものであるが、2年を経る間に、海外を中心にFortranを取り巻く環境が劇的に変化していることから、2021年末時点の情報として改めて情報を整理した。

# 2019年〜2021年にかけてのFortranを取り巻く変化

Fotranは [netlib](https://www.netlib.org/) などの膨大な過去の資産があるとはいえ、長らく標準ライブラリやパッケージマネージャの整備がなされておらず、近年人気を博しているPythonと比較すると、新規学習者にとって取り組みやすさの点で見劣りする状況であったと思う。しかし、2019年になって、下記のような新たな取り組みが [Sympy](https://www.sympy.org/en/index.html) 開発者の一人である Ondřej Čertík 氏らによって開始された。
 
- [fortran-lang](https://fortran-lang.org/) : Fortranコミュニティが立ち上がり、fortranに関する最新の情報が集約されるページができた。
- [stdlib](https://github.com/fortran-lang/stdlib) : Fortranのデファクトスタンダードを目指した標準ライブラリの開発がコミュニティ主導で始まった。実装予定機能は下記の通り。
    - ユーティリティ（文字列処理、ファイル処理、OSと実行環境の統合、ユニットテスト、ロギング、...）
    - アルゴリズム（サーチ&ソート、マージ、...）
    - 数学（線形代数、疎行列、特殊関数、高速フーリエ変換、乱数、統計、常微分方程式、数値積分、最適化、...）

- [fpm](https://github.com/fortran-lang/fpm) : Fortran用パッケージマネージャであり、オープンソースソフトウェアを利用したFortranによる開発プロジェクトの立ち上げが容易になった。

オープンソースのコンパイラとしては[gfortran](https://gcc.gnu.org/wiki/GFortran)が広く利用されていると思われるが、新しく[LFortran](https://lfortran.org/)の選択肢が増えた。LFortranは開発途上であり、2021年時点ではまだf2003以上の機能を十分に実装できていないものの、[jupyter](https://jupyter.org/)カーネルとして動作させることで、Python, Julia, Rのように、インタラクティブにFortranを実行できる点が特長の一つである。

また、国際学会 [FortranCon2021](https://tcevents.chem.uzh.ch/event/14/)が開催されるなど、ここ2年間のFortranを取り巻く環境は、従来と比べて非常に活発になっている。これらの取り組みの甲斐あってか、Fortranの人気は[TIOBE](https://www.tiobe.com/tiobe-index/)インデックスで20位以内に上昇してきた。
 
# Fortranで利用可能なライブラリ

[fortran-lang(packages)](https://fortran-lang.org/packages/)では多数の興味深いライブラリが紹介されている。この中で、個人的に気になるライブラリを下記にピックアップして列挙する。なお、[Qiita記事(2019年版)](https://qiita.com/sakamoti/items/accc481868ec70bc1548) で記載したライブラリはf77やf90のものが多いが、本記事ではf2003以降の記法を用いたものが多い。

## ファイルIO
- [h5fortran](https://github.com/geospace-code/h5fortran) : [HDF5](https://www.hdfgroup.org/solutions/hdf5/)ファイルの入出力が非常に簡単になる。
- [fortran-csv-module](https://github.com/jacobwilliams/fortran-csv-module) : CSVファイルの読み書きを行う。
- [NPY-for-Fortran](https://github.com/MRedies/NPY-for-Fortran) : Fortranの配列を、Numpyで利用可能なデータ形式で書き出し。


## データの描画
- [ogpf](https://github.com/kookma/ogpf) : fortranからgnuplotを使う。アニメーションも可。
- [pyplot-fortran](https://github.com/jacobwilliams/pyplot-fortran) : fortranからpython(matplotlib)のpyplotを使う。
- [VTKFortran](https://github.com/szaghi/VTKFortran) : VTKファイルの取り扱い。

## 数学・数値解析
- [bspline-fortran](https://github.com/jacobwilliams/bspline-fortran) : Bスプライン関数の取り扱い。
- [FOODIE](https://github.com/Fortran-FOSS-Programmers/FOODIE) : 常微分方程式の初期値問題解法。
- [NumDiff](https://github.com/jacobwilliams/NumDiff) : 数値微分。

## その他
- [FLAP](https://github.com/szaghi/FLAP) : コマンドラインパーサ。
- [FORD](https://github.com/Fortran-FOSS-Programmers/ford) : ドキュメント生成ツール。

# おわりに

fortranの最新情報が欲しければ、[fortran-lang](https://fortran-lang.org/) を見れば良いという状況になってきている。また、fortranの利用方法も、Pythonのライブラリやパッケージシステムのように、洗練されて使いやすいものへと変貌しつつある。コミュニティーを通したfortran界隈の今後の発展に期待が持てそうだ。
enumとintが同じ型だと仮定しないようにしよう

眠い中数時間デバッグさせられた怒りに任せて書いています。

起こったこと :
3DSの自作ソフトのソースコード中で、かの有名なFFmpegのlibavfilterを初めて使ったところフィルターグラフ構築した後のavfilter_graph_config()が失敗を返す。

調べたところFFmpegのデバッグログを見るといいとか書いてあったからログのコールバック関数設定してエラーを見たら"Duplicated sample format"とのこと。このエラーがGoogleで微塵も引っ掛からない。

仕方がないのでFFmpegの中に潜り込んでいろいろデバッグ表示させたら以下のようなコードが原因なことが判明 :
※以下のコードにある2つの関数は本来別々のファイルにあります。

```c++
enum AVSampleFormat {
    AV_SAMPLE_FMT_NONE = -1,
    <省略>
};
static int query_formats(<省略>)
{
    <省略>
    static const enum AVSampleFormat sample_fmts[] = {
        AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P,
        AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP,
        AV_SAMPLE_FMT_NONE
    };
    <省略>
    formats = ff_make_format_list(sample_fmts);
    <省略>
}
AVFilterFormats *ff_make_format_list(const int *fmts)
{
    <省略>
    int count = 0;
    if (fmts)
        for (count = 0; fmts[count] != -1; count++);
    <省略>
}
```
`AV_SAMPLE_FMT_NONE` が-1に等しいので番兵の役割をしています。
ところがデバッグ表示していると `ff_make_format_list` の方では `count` が620にもなっているではないですか。
嫌な予感がしながら `sample_fmts` の要素の型を `enum AVSampleFormat` から `int` に変えると直ってしまいました。
つまり`enum AVSampleFormat`が4バイトではなかったようです。
実際この環境で

```c++
enum X {
    ABC = -1,
    DEF,
    GHI,
    JKL
};
```
に対して `sizeof (enum X)` は1になりました。

普通の環境のGCCだと`enum`はデフォルトでは`int`でコンパイル時に`-fshort-enums`を付けると必要最小限のバイト数になるらしいですが今回`-fshort-enums`は付けていないつもりです。

余裕があったら本家にちょっとissueっぽいの立てるかもしれないけどあっちがどこまで変な環境をサポートするつもりなのかは調べてから行かないとダメそうですね。

しかしライブラリの中いじることになったのは初めてだ
CircleCiでテスト時にCaused by PDOException: SQLSTATE[42P01]: Undefined table: 7 ERROR:  relation "users" does not exist LINE 1:

##環境
laravel 6.20.37
phpuit 8.5.21
##エラー内容

```
Caused by
PDOException: SQLSTATE[42P01]: Undefined table: 7 ERROR:  relation "users" does not exist
LINE 1: insert into "users" ("name", "email", "email_verified_at", "...
                    ^
```
##原因
DatabaseTransactionsを使用していたことが原因のようでした。

```php:AnswerControllerTest.php
use DatabaseTransactions;
```
RefreshDatabaseを使用することでエラーがなくなりました。

```php:AnswerControllerTest.php
use Illuminate\Foundation\Testing\RefreshDatabase;

use RefreshDatabase;
```

RefreshDatabaseは各テストの後にデータベースをリセットできるので前のテストがその後のテストデータに影響しないのに対し、DatabaseTransactionsは各テストケースをデータベーストランザクションでラップしてデータベースをリセットするという違いがあるようです。
##参考

https://readouble.com/laravel/5.6/ja/database-testing.html

https://readouble.com/laravel/5.4/ja/database-testing.html
Box最新テクノロジーを自分のためだけに使う

:::note info
この記事はBox Advent Calendar (2021/12/1)の参加記事です。
Special thanks to @tokotan 
:::


https://qiita.com/advent-calendar/2021/box


##この文書のココあとで使えそう！だけど、、、
あとからアレどこだっけな？:sweat_smile:ってなること多いですよね？

特にページ数の多いドキュメント:page_facing_up:だと
このネタどこかで使えそうだからメモしておきたいけど、、、絶対忘れる:laughing:

電子書籍:iphone:なら、`ハイライトした部分`を自分だけで確認できるマイノート機能がありますネ

Boxでもこれを実現するために
最新テクノロジーを使って、自分だけのハイライトを作って代わりに覚えておいてもらいましょう

##アノテーションを利用した自分だけのマイノートの作り方

:one:自分が所有者で誰もコラボしていないフォルダを用意します[^1]
<font color="Gray">もちろん共有フォルダでもOKですが、この記事ではあくまで個人的に使うことを目的にしています</font>

:two:フォルダ所有者が自分あること、黄色のフォルダであることを確認しましょう
<font color="Gray">企業によっては管理者から提供された個人フォルダの場合は青い場合もありますが気にせずに！</font>
![_5__Advent_Calendar___Powered_by_Box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2317768/43e567bc-c3cf-e9e6-0093-ba761cb464c5.png)
:three:電子書籍にハイライトするようにアノテーションするだけ！[^2]
![DXレポート2_1_pdf___Powered_by_Box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2317768/0fa3f684-5bec-0cd1-a6f4-149f8e9077b2.png)
:four:あとから見返したときも全文読まずに検索せずに、アクティビティから目的の場所に飛ぶことができます
![DXレポート2_1_pdf___Powered_by_Box.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2317768/4acc1090-18ea-e326-610c-94b848be71cf.png)


[^1]: 気づいてくれた方ありがとうございます。コメント待ってます
[^2]: [サンプル文書_経済産業省 DXレポート2.1](https://www.meti.go.jp/press/2021/08/20210831005/20210831005.html)
php -vで確認したバージョンとは違うバージョンですとエラーに言われて困った話

#### 環境
 M1 Macbook Air
 MAMP


Cakephpの環境構築過程でcomposer updateを実施したところ下記のエラーが発生。

```
$ composer update
Loading composer repositories with package information
Updating dependencies                                 
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires php <8.0 but your php version (8.0.13) does not satisfy that requirement.
  Problem 2
    - phpunit/phpunit[6.0.0, ..., 6.5.14] require php ^7.0 -> your php version (8.0.13) does not satisfy that requirement.
    - Root composer.json requires phpunit/phpunit 6.* -> satisfiable by phpunit/phpunit[6.0.0, ..., 6.5.14].
```

composer.jsonで指定しているphpのバージョンの範囲が、私の環境にあるphpのバージョンの範囲外らしい。(こっちは8.0より低いバージョンが必要だけどあなたのphpのバージョンが8.0.13なので無理ですよ〜と言っている)

なので下記コマンドでphpのバージョンを確認してみたところ

```
$ php -v
PHP 7.4.21 (cli) (built: Oct  1 2021 11:18:30) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.21, Copyright (c), by Zend Technologies
```

あれ？　7.4.21だぞ？　なんで8.0.13じゃないんだ？
ここで詰まりました。

# 解決法
compose.jsonのconfigに、下記のようにphpのバージョンを指定し、再度composer updateすることで解決しました。

```
    "config": {
        "minimum-stability": "dev",
        "platform": {
            "php": "7.4.21"
        }
    },
```
そもそもなぜバージョンのところでエラーが出たのかという話なのですが、私がphp -vで参照した7.4.21のphpは、元々macにインストールされていたphpのバージョンであったのに対し、composer.json側ではHomebrew側のphpを参照していたことが原因のようです。

### 余談
composer updateが完了した後、ふと思い立ち再度php -vをしたところ

```
$ php -v
PHP 8.0.13 (cli) (built: Nov 24 2021 11:11:54) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.13, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.13, Copyright (c), by Zend Technologies
```

上記のように変化していました。
あれ？いつ変わった。。？
Homebrew側のphpのPATHを追加して反映させたタイミング？
あれ？でもエラーの前には反映させていたような。。
PythonのGILを取り除く試み

こんな記事を見つけたので気になって調べてみました。

https://www.infoworld.com/article/3637073/python-stands-to-lose-its-gil-and-gain-a-lot-of-speed.html

この記事は、Pythonの開発者専用のメーリングリストに、Sam GrossというFacebookの開発者が投稿した、GILを外したCPythonの実装(nogil)の提案について書かれています。

https://mail.python.org/archives/list/python-dev@python.org/thread/ABR2L6BENNA6UPSPKV474HCS4LWT26GY/

彼は、Global interpreter lock (GIL)を外したCPythonの概念実証のための実装とメモを投稿しました。メモのリンクはこちらです。

https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsDFosB5e6BfnXLlejd9l0/edit

## Global Interpreter Lock (GIL) とは

Python(のReference ImplementationであるCPython)は、マルチスレッドに対応していますが、スレッドセーフティを確保するためにGIL(Global Interpretation Lock)という仕組みがあります。

複数のスレッド処理を行っても、GILの仕組みにより、Pythonの命令は一つずつ処理され同時に処理できません。計算負荷の高い処理する際に、複数のCPUコアを搭載しているマシン上でも複数のフレッドによる同時の並列処理が出来ないので、マルチスレッドの恩恵をあまり受けられません。この問題を回避する方法として、

1. マルチプロセスでの並列処理を使用
1. Ｃなどネイティブのライブラリ内でマルチスレッド化する

などの方法がありますが、１の場合異なるプロセスでデータを共有したい場合、通常メモリが共有されていないため、プロセス間通信や共有メモリの仕組みを利用することになります。しかし、大きなデータを共有するためには、プロセス間通信ではデータをシリアライズする必要があったり、共有メモリではプリミティブな型しか共有できなかったりと、いろいろと大きなデータ上での高計算負荷の処理を行うにはハードルがあります。マルチスレッドで同時並列処理が実現できればそのような問題は解決します。
Sam Grossは、そのための概念実証を投稿したというわけです。

参考：https://wiki.python.org/moin/GlobalInterpreterLock

## Guido van Rossumのコメント

Pythonの生みの親Guido van Rossumが、次のビデオSamの取り組みに言及しています（29:17あたりから）。GILを取り除く試みは、直近ではLarry HasitingsがGilectomyという名のプロジェクトでGILの除去を試みたものの、元々のシングルスレッドベースのでの処理速度が著しく低下し、うまくスケールせず失敗に終わった事をコメントしています。

https://www.youtube.com/watch?v=_r6bFhl6wR8&t=1757s

このビデオがそのGilectomyについてのLarryによるプレゼンです。

https://www.youtube.com/watch?v=fgWUwQVoLHo

Larryのプレゼンでは、GILの歴史が述べられています。GILが追加されたのは92年で、Pythonが誕生して間もない頃で、30年近く経った今も本質的な設計は変わっていません。92年頃は殆どのコンピュータはシングルコアだったでしょうが、マルチコアが当たり前の今の時代にGILの制約の影響は大きいと言えます。

下記の記事ではGilectomyが事実上頓挫した事が書かれています。

https://lwn.net/Articles/754577/

Guido自身はSamの試作を深く調べた訳ではないので、成功に確証を持っているわけではなさそうですが、Larryの試みよりはより多くの時間と努力を注ぎ込んだようだと期待しているようです。

## Next Step

Python Software Foundation の Developer in ResidenceであるŁukasz Langaは、下記のブログにはnogilのネクストステップについて書いています。

https://lukasz.langa.pl/5d044f91-49c1-4170-aed1-62b6763e6ad0/

* Samの試作は、パフォーマンスをある程度維持しつつスケールする方法でGILを取り除くことは可能であることを実証している。
* Samの試作をすぐに3.11に取り込むことはない。CPyhonへ取り込むにはかなりの労力が必要。
* 後方互換性と移植の入念な計画が必要。移植が適切でないと判断する事もあり得る。
* nogilを取り込には様々な考慮が必要だが、メモリアロケータなど部分的には比較的早期に取り込めるかもしれない。


[参照カウント]:https://ja.wikipedia.org/wiki/%E5%8F%82%E7%85%A7%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88

[遅延参照カウント]:https://www.memorymanagement.org/glossary/d.html#:~:text=Deferred%20reference%20counting

[偏った参照カウント]:https://dl.acm.org/doi/10.1145/3243176.3243195
SSH接続時のパーミッションエラー解消方法について 

#事象
SSHにてサーバに秘密鍵ファイルを用いてリモート接続しようとすると、下記エラーが出力される。

```linux:エラーメッセージ
[ec2-user@ip-10-0-0-187 tmp]$ ssh -i test-keypair.pem ec2-user@10.0.2.79
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'test-keypair.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "test-keypair.pem": bad permissions
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```

エラーの内容を読んでみると、パーミッションが「0644」となっており、同じグループや他ユーザーから秘密鍵ファイルの読み込みができてしまうため、セキュリティ上問題があると言っているようだ。

#解決方法
パーミッションを確認

```
[ec2-user@ip-10-0-0-187 tmp]$ ls -l test-keypair.pem
-rw-r--r-- 1 ec2-user ec2-user 1704 Nov 27 08:42 test-keypair.pem
```

上記のように「0644」となっている。
ここで、秘密鍵ファイルのパーミッションを「0400（自分のみ読み取り可能）」に変更してみる。

```
[ec2-user@ip-10-0-0-187 tmp]$chmod 400 test-keypair.pem
[ec2-user@ip-10-0-0-187 tmp]$ls -l test-keypair.pem
-r-------- 1 ec2-user ec2-user 1704 Nov 27 08:42 test-keypair.pem
```


再実行すると、ちゃんと繋がるようになりました。

```
[ec2-user@ip-10-0-0-187 tmp]$ ssh -i test-keypair.pem ec2-user@10.0.2.79

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
[ec2-user@ip-10-0-2-79 ~]$
```

#終わりに
自分に読み取り権限が無ければ接続できないのは勿論ですが、グループや他ユーザーに読み取り権限がある場合でも接続できないんですね。
NrealLightで半透明な物を録画したくて色々ためした

<img width="640" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/7edcfe4a-0f8f-4f30-37cc-ed5c3d550284.gif" />

これは [STYLYアドベントカレンダー](https://qiita.com/advent-calendar/2021/styly) の2日目の記事です！


# STYLY for Nrealの一人称録画機能を開発した

STYLY for Nrealの一人称録画機能を開発しました。
NrealとはARグラスの一種です。
一人称録画機能とは、NrealLightについているカメラで現実世界を撮影したものを、AR映像と合成し、動画ファイルに出力する機能です。

STYLY for Nrealにご興味のある方は、こちらをご参照ください。

https://styly.cc/ja/manual/stylyfornreal-manual/



# NRSDKの `First Person View Video Capture` を使った

NRSDKには `First Person View Video Capture` という機能があります。STYLYでも内部的にはこのSDKを利用しています。

https://developer.nreal.ai/develop/unity/video-capture

基本的に、このサンプルコード通りに実装すれば、一人称録画機能は作れるのですが、一部のオブジェクトが録画に映らないという現象に遭遇しました。
（グラス越しにはちゃんと見えています）



# 半透明なオブジェクトが録画に映らない

サンプルアプリを試してみたところ、一部のオブジェクトが録画に反映されていませんでした。

フレームデバッガー等で調査したところ、 **`Render Queue` が `Transparent` だと録画に映らない** ことがわかりました。

NRSDKのコードを調査したところ、 **NRSDK\Resources\Record\Shaders\AlphaBlend.shader** に以下の行を見つけました。

```hlsl
fixed3 col_tex = lerp(col_bg.rgb, col.rgb, col.a)
```

ここで、実写映像 `col_bg.rgb` と CG映像 `col.rgb` をαブレンドしているのですが、 `RenderQueue` が `Transparent` の場合、 `col.a` が `0` になっており、CG映像が消えていることがわかりました。



# `Render Queue` を `AlphaTest` にすると録画に映る

`Render Queue` を `AlphaTest` にすると、半透明な物でもNrealの録画に映ることがわかりました！

以下の映像は、 `Transparent` の箱と `AlphaTest` の箱を並べて、Nrealで撮影したものです。
ご覧の通り、 `Transparent` の箱は映っていませんが、 `AlphaTest` の箱は映っています！

<img width="640" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/7edcfe4a-0f8f-4f30-37cc-ed5c3d550284.gif" />

（ちなみに、箱の中にある玉は `Opaque` です。）

念のため、Nreal Communityにも投稿しました。

https://community.nreal.ai/t/im-having-trouble-capturing-video-about-transparent-object/769

とりあえず録画に映したければ `AlphaTest` にするのが手っ取り早いです。
しかし、 `Render Queue ` をいじることによる弊害もあります。



# `Render Queue` をいじると前後関係が不自然になる

`Render Queue` をいじると、前後関係が不自然になります。

以下の図をご覧ください。

- 左側の箱はRenderQueueが `Transparent (3000)` 
- 右側の箱はRenderQueueが `AlphaTest (2450)`
- 箱の中にある玉はすべて `Opaque (2000)`

![af83f030-d4f7-016a-afc6-a8f8519bb248.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/1620881b-9c45-1ede-946f-3844fd73879f.gif)

`Transparent` の箱の奥に `AlphaTest` の箱がある時は見えますが、 `AlphaTest` の箱の奥に `Transparent` の箱がある時は見えません。玉は常に見えます。

これは描画順が  `Opaque (2000)` <  `AlphaTest(2450)` <  `Transparent(3000)` だからです。

ご覧の通り、前後関係が不自然に見えるため、  `AlphaTest` の多用は避けたいところです。

ただ、録画に半透明なオブジェクトを映す方法は、今のところこれしか見つけていないので、どうしても映したいときは、この方法を使わざるをえないのが現状です。




# さいごに

なんともモヤっとしますが、調査は以上です。
録画時にしか再現しない現象だったため、調査・対策にかなり時間がかかってしまいました。

今後、同じ症状に遭遇した人の助けになれば幸いです。

本記事作成にあたり、以下の情報を参考にさせていただきました。ありがとうございました。



- [STYLY Manual | STYLY for Nreal マニュアル](https://styly.cc/ja/manual/stylyfornreal-manual/)
- [Nreal Developer | First Person View Video Capture](https://developer.nreal.ai/develop/unity/video-capture)
- [Nreal Community | I’m having trouble capturing video about transparent object](https://community.nreal.ai/t/im-having-trouble-capturing-video-about-transparent-object/769)
新たなプログラミング言語に挑戦するときは見栄を捨てようという話

仕事ではdotnet（C#）アプリ開発、プライベートでSwift/SwiftUIでiOSアプリの開発をしています。
現在AppStoreへの初リリースを目標に黙々と手を動かしている途中ですが、その際に得られた感覚について共有できればと思います。
万人に共通するわけではないと思いますが誰かの気づきの一助になれば幸いです。

# 今までの経験に対して期待しすぎない

Swift/SwiftUIについては見習いレベルですが、dotnet(C#)開発をそこそこやってきたという見栄により「ちゃんと設計しなきゃ」という意識が働き、最初にしっかりと設計をしてからコーディングに移ろうとしていました。

その際の図（ちょっと変則的なTODOアプリをClean architecture、あわよくばVIPERパターンに則って作ろうとしていました）

![RoutineCommander-Classのコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2088399/919e075f-5bed-c685-bf00-ece2829a033e.png)

結果、Swiftの言語使用等を十分に理解してない中での設計ということもあり、上記設計での実現は困難な部分が多く断念しました。断念するまでは設計のし直しなどかなり手間をかけていたと思います。
現在は、多少汚いコードでもいいからまずは動くものを完成させることを最優先に実装を進めています。

ちゃんと設計することで可読性やメンテナンス性の向上など期待できることは多いですが、初心者のうちはまだそのステージに立っていない（特に独自で設計するとき）ことを自覚しないといつまでたってもリリースできないことに気がつきました
Pandasで列を抜き出すときはreindexを使った方がいいと思った話

# 要約
事前に列の存在をチェックしないでPandasのDataFrameから列を抜き出すのはやめよう．
DataFrameから列を抜き出す際は，

- 事前に列の存在を確認してから抜き出す
- reindex関数を使って抜き出す

のどちらかにしましょう．


# よくあるサンプル

```Python
import numpy as np
import pandas as pd

df = pd.DataFrame(
        np.arange(12).reshape(3, 4),
        index=["X", "Y", "Z"],
        columns=["A", "B", "C", "D"]
    )

print(df)
#    A  B   C   D
# X  0  1   2   3
# Y  4  5   6   7
# Z  8  9  10  11


# AとB列だけ抜き出す
df_AB = df[["A", "B"]]

print(df_AB)
#    A  B
# X  0  1
# Y  4  5
# Z  8  9


# 存在しない列を抜き出そうとするとエラー
df_PD = df[["P", "D"]]
# KeyError: "['P'] not in index"
```

存在しない列をとろうとするとエラーなのはいいとして，pandasの関数を使うと，知らぬ間に列がなくなっていることがあります．

```sample_data.csv
日付,店舗,売上
2019-12-31,A,100
2019-12-31,B,200
2019-12-31,C,300
2020-01-01,A,100
2020-01-01,C,300
2020-01-02,A,100
2020-01-02,C,300
```

```Python
from datetime import datetime
import pandas as pd

# あるスーパーの店舗ごとの売り上げをCSVから読み取った例
df = pd.read_csv(
        "sample_data.csv",
        index_col=[0, 1],
        parse_dates=[0,]
    )

print(df)
#                売上
# 日付       店舗
# 2019-12-31 A   100
#            B   200
#            C   300
# 2020-01-01 A   100
#            C   300
# 2020-01-02 A   100
#            C   300

# unstack関数を使って，店舗を列方向に並び替える
df_unstack = df.unstack()
print(df_unstack)
#             売上
# 店舗         A      B      C
# 日付
# 2019-12-31  100.0  200.0  300.0
# 2020-01-01  100.0    NaN  300.0
# 2020-01-02  100.0    NaN  300.0

# 店舗ごとの売り上げが日ごとに分けられて見やすくなった


# 2020年のデータだけ抜き出して同じことをしてみると・・・
df_only_2020 = df.loc[df.index.get_level_values("日付").year == 2020]
print(df_only_2020)
#                売上
# 日付       店舗
# 2020-01-01 A   100
#            C   300
# 2020-01-02 A   100
#            C   300

df_only_2020_unstack = df_only_2020.unstack()
print(df_only_2020_unstack)
#             売上
# 店舗         A      C
# 日付
# 2020-01-01  100.0  300.0
# 2020-01-02  100.0  300.0

# 店舗Bのデータが列にないからこの状態で取り出そうとするとエラーになる
```

# なので
DataFrameから列を抜き出すときは存在の確認をするかreindexを使いましょう．
個人的にはreindexがおすすめなのでreindexの場合の結果をチラっと．

```Python
from datetime import datetime
import pandas as pd

# あるスーパーの店舗ごとの売り上げをCSVから読み取った例
df = pd.read_csv(
        "sample_data.csv",
        index_col=[0, 1],
        parse_dates=[0,]
    )

print(df)
#                売上
# 日付       店舗
# 2019-12-31 A   100
#            B   200
#            C   300
# 2020-01-01 A   100
#            C   300
# 2020-01-02 A   100
#            C   300

# 2020年のデータだけ抜きだす
df_only_2020 = df.loc[df.index.get_level_values("日付").year == 2020]
print(df_only_2020)
#                売上
# 日付       店舗
# 2020-01-01 A   100
#            C   300
# 2020-01-02 A   100
#            C   300

# 列方向に店舗を並べる
df_only_2020_unstack = df_only_2020.unstack()
print(df_only_2020_unstack)
#             売上
# 店舗         A      C
# 日付
# 2020-01-01  100.0  300.0
# 2020-01-02  100.0  300.0

# 上記のデータから3店舗分のデータをreindexで取り出す
df_only_2020_ABC = df_only_2020_unstack.reindex(columns=["A", "B", "C"])
print(df_only_2020_ABC)
#             売上
# 店舗         A      B      C
# 日付
# 2019-12-31  100.0    NaN  300.0
# 2020-01-01  100.0    NaN  300.0
# 2020-01-02  100.0    NaN  300.0

# 店舗BのデータはNaNで埋めてくれる
```
ダウンロード と インストール

## 勉強前イメージ

インストールがちゃんと読み込みしてるイメージだけど
ちゃんとは答えられない・・・

## 調査

### それぞれ確認

- ダウンロード とは

インターネットなど他の場所からファイルを保存する

- インストール とは

ソフトウェアやアプリケーションなど、端末で使用できるように設定を行うこと

### 違い

ダウンロードでファイルを持ってきて、
そのファイルを使用できるようにするのがインストール

## 勉強後イメージ

いつもセットだと思っててちゃんと認識してなかった

## 参考

- [「ダウンロード」と「インストール」の違いとは？意味や方法も解説](https://biz.trans-suite.jp/36572)
Conoha VPS （Ubuntu）にDockerでUbuntu20.04＋Python3.8環境を構築する


Conoha(Ubuntu18.04)にDockerでUbuntu20.04＋Python3.8環境を構築しようと思って調べた内容をまとめる。（コピペで動きます）

# imageをpull

```sh
docker image pull ubuntu:20.04
```

# imageを確認
```sh
docker images
```

# Docker imageを解凍
（ubuntu2004の部分は自由に名前を変更してください）

```sh
docker container run -it -d --name ubuntu2004 ubuntu:20.04
```

# image内に入る
```sh
docker exec -it ubuntu2004 /bin/bash
```

# gitをインストールする
```sh
sudo apt-get install git
```
※bash: sudo:command not foundと出たときは「apt update＆apt install sudo」する。

#git clone
```sh
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
```

# vimをインストールする
```sh
sudo apt-get install vim
```

#profile をvimで編集
```sh
vi ~/.profile
```
#profile に以下を追記
```sh
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
eval "$(pyenv init -)"
```
#再読み込みする
```sh
source ~/.profile
```

#libffi-devをインストール
```sh
sudo apt install libffi-dev
```

#curlをインストール
```sh
apt install curl
```
#aria2cをインストール
```sh
apt install aria2c
```
#wgetをインストール
```sh
apt install wget
```

#いろいろインストール（途中地域選択あり）
```sh
apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```

#python3.8.10 をインストール
```sh
pyenv install 3.8.10 
pyenv global 3.8.10
```

#バージョン確認
```sh
python3 --version
>Python 3.8.10
```

#（おまけ）ついでにpipをインストール
```sh
apt install python3-pip
```

Dockerfileにまとめれたら、また記事を書こうかな。
Git・GitHub 「"error: src refspec master does not match any" "error: failed to push some refs to 'github.com:〇〇/intro_git.git'"」のエラーへの対処法

こちらのUdemyの講座を受講している際、タイトルのようなエラーに遭遇しました。
https://www.udemy.com/course/intro_git/learn/lecture/6449730#notes
（3分29秒）

ys@mbp intro_git % git push origin master
↓
```
error: src refspec master does not match any
error: failed to push some refs to 'github.com:〇〇（GitHubのユーザー名）/intro_git.git'
```

結論
git push origin master ではなく
git push origin main を使う

ys@mbp intro_git % git push origin main
↓
```
Enumerating objects: 19, done.
Counting objects: 100% (19/19), done.
Delta compression using up to 8 threads
Compressing objects: 100% (14/14), done.
Writing objects: 100% (17/17), 1.66 KiB | 567.00 KiB/s, done.
Total 17 (delta 4), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (4/4), done.
To github.com:〇〇（GitHubのユーザー名）/intro_git.git
   4817446..7f3dadd  main -> main
```

参考サイト
https://deepblue-ts.co.jp/git/git-push-error/
意外と知らない？コピーと保存の小技達

:::note info
この記事はBox Advent Calendar (2021/12/7)の参加記事です。
Special thanks to @tokotan 
:::


https://qiita.com/advent-calendar/2021/box


:one: [Boxにある画像を文書ファイルに秒でコピー](#boxにある画像を文書ファイルに秒でコピー)
:two: [メール添付ファイルを秒でBoxにコピー](#メール添付ファイルを秒でboxにコピー)
:three: [フォルダやファイルをワンクリックで別画面で開く](#フォルダやファイルをワンクリックで別画面で開く)

##Boxにある画像を文書ファイルに秒でコピー


アノテーション機能が実装されてから
画像のコピーができなくなった！:cry:と思ったら簡単な操作でできました

Boxで画像をプレビューした直後に右クリックしても「コピー」が表示されません
![image_2021-11-25_202418_jpg___Powered_by_Box_と_Boxのカレンダー___Advent_Calendar_2021_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2317768/1f0a80a5-7e87-4182-10d8-0bb82060e6be.png)
そんなときはアノテーションアイコンをクリックして、アノテーションをオフにしてください
コピーオプションがでてきますので、コピーしてそのまま文書ファイルへの貼付けができます
![image_2021-11-25_202418_jpg___Powered_by_Box_と_Boxのカレンダー___Advent_Calendar_2021_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2317768/438b239a-a4ce-afe1-4ef1-b49e258bff89.png)

## メール添付ファイルを秒でBoxにコピー
:::note info
Mac標準メーラーでは動作しました。
他のメールアプリで試してみてメーラー名をコメントいただけると嬉しいです！
:::

操作は簡単！
メールを開いて！
添付があったら？
~~Boxのリンクで送ってこいよ。という気持ちをぐっとおさえて~~

Boxブラウザーにドラック＆ドロップするだけ🤪
![copy_attached.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2317768/9c8f1476-d043-9dd3-a24b-d27cd75a5406.gif)



##フォルダやファイルをワンクリックで別画面で開く

コピーしたり、保存するためのフォルダを別タブで開きたい時の小技です。

Boxに限った話ではないのですが
ブラウザーを別タブで開きたい時
`Shift(or command) + 左クリック`してませんか？

マウスにクルクル回すスクロールボタンついていますか？

別タブで開きたいBoxフォルダやファイルを
`クルクルボタンでクリック`してみてください
（そうです、クルクルボタンも押せるんです！）

ね？別タブで開いたでしょ？:upside_down:
2画面折りたたみデバイスに対応したCSSメディアクエリ

Galaxy foldシリーズやSurface Duoシリーズなどが登場し、今後2画面折りたたみデバイス向けにWebサイト、Webアプリの対応が求められるようになるかもしれません。
ブラウザの対応も少しずつ進んでいるようなので、調べたことをまとめます。

# 2画面デバイスを検出するための CSS メディアクエリ
最新のMicrosoft Edge（バージョン96）で試験的な実装ではありますが、二画面デバイスを検出するビューポートセグメントメディアクエリが提供されています。

```CSS:CSS
@media (horizontal-viewport-segments: <count>) { }
@media (vertical-viewport-segments: <count>) { }
```

`<count>`は水平(横長)、または垂直(縦長)の画面デバイス数を設定します。
例えば Surface Duo の2画面デバイス表示では以下の値になります。

水平の場合
`horizontal-viewport-segments: 2`

垂直の場合
`vertical-viewport-segments: 2`

![スクリーンショット 2021-11-27 202955.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325666/867b4130-d151-6932-0300-5cb688e540f0.png)

# CSS環境変数
各ビューポートのプロパティは、次の環境変数定義で取得できます。

```
env(viewport-segment-width <x> <y>);
env(viewport-segment-height <x> <y>);
env(viewport-segment-top <x> <y>);
env(viewport-segment-left <x> <y>);
env(viewport-segment-bottom <x> <y>);
env(viewport-segment-right <x> <y>);
````

x座標とy座標は、左上の画面デバイスを00とした画面デバイスの座標です。
Surface Duoの場合、次の値を使用して、各画面デバイスの座標を使用します。

![スクリーンショット 2021-11-27 214001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325666/d4e0b924-65f6-045e-163f-6a0f555ad2db.png)

これらの値を利用して、各画面デバイスの四隅の座標や幅、高さを取得できます。
![スクリーンショット 2021-11-27 213358.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325666/17e8c0ae-f6af-5493-26b6-c5b023d262df.png)

ヒンジの寸法を計算することもできます。

```
/* 水平(横長)の時のヒンジの幅 */
calc(env(viewport-segment-left 1 0) - env(viewport-segment-right 0 0))
/* 垂直(縦長)の時のヒンジの高さ */
calc(env(viewport-segment-top 0 1) - env(viewport-segment-bottom 0 0))
```

# 使用例
携帯電話は画像とテキストが縦並び、2画面デバイスでは左側のデバイスにテキスト、右側のデバイスに画像を表示するようなレイアウトの場合

![スクリーンショット 2021-11-27 220006.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325666/414f5ed6-5a32-1dc0-b45a-f049034bd622.png)

```HTML:HTML
<body>
   <figure class="image">
      <img src="/image.jpg"alt="My image">
   </figure>
   <article class="article">
       ・・・
   </article>
</body>
```

```CSS:CSS
/* 最大幅が 420px の一画面デバイスの時 */
@media (max-width: 420px) {
    ・・・
}

/* 二画面デバイスの水平(横長)の時  */
@media (horizontal-viewport-segments: 2) {
   .article {
       position: absolute;
       left: env(viewport-segment-left 0 0); /* 左側のデバイスに表示する */
       top: env(viewport-segment-top 0 0);
   }
   .image {
      width: env(viewport-segment-width 1 0); /* 右側のデバイスの幅の大きさで表示 */
      position: absolute;
      left: env(viewport-segment-left 1 0); /* 右側のデバイスに表示する*/
      top: env(viewport-segment-top 1 0);
   }
}
```

# テスト
二画面デバイス表示に対応したCSSをWebブラウザ上でテストするには、最新バージョンのデスクトップバージョンのEdgeまたはChrome（devtoolsシミュレーターの場合）をダウンロードし、edge://flags（またはchrome://flags）を介して機能フラグを有効にします。

[参考]
https://docs.microsoft.com/ja-jp/dual-screen/web/desktop-developer-tools

# まとめ
想定していたよりも簡単に二画面デバイスに対応したレイアウトを組めそうです。
正式リリースに期待ですね。
Aplleが折り畳み式のiPhoneを開発中との噂もあるので、一足先に触れておくのもありかなという印象です。

# 参考サイト
https://docs.microsoft.com/ja-jp/dual-screen/web/css-viewport-segments
https://devblogs.microsoft.com/surface-duo/foldable-css-javascript-edge-96/
【Ruby】早期return

##早期リターン
式の値を戻り値としてメソッドの実行を終了。式が省略された場合には nil を戻り値とする。
条件分岐のネストが深くなりすぎてコードを読みにくくなってしまうときに使用すると可読性が高まる。
「Guard Clause」「ガード節」「ガード条件」「ガード構文」と呼ばれることもある。


```ruby
def invalid_permission?(user)
  if user.present?  #<= この例外処理はGuard Clauseで書き直せる
    case user.permission
    when 1,2,3
      false
    else
      true
    end
  else
    true
  end
end
```

```ruby
def invalid_permission?(user)
  return true if user.blank? #<= この1行で例外チェックをネストなしで完了できる

  case user.permission
  when 1,2,3
    false
  else
    true
  end
end
```

##参考

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#return

https://techracho.bpsinc.jp/hachi8833/2016_10_11/26950
スマホで見るとレスポンシブが効かない。viewport入れてもダメな時は？

viewportを入れてるのに
スマホで見るとレスポンシブデザインが効かない。

だけど
パソコンで横幅をスマホサイズに小さくすると
しっかりレスポンシブデザインが効いている。

こういうケースがあります。

わたしはこの問題にぶつかったのですが、
viewportのタグを入れてからしばらく時間を置いたら
問題が解決しました。

１viewportを入れてる
２パソコンで横幅を小さくしてみるとレスポンシブが効いている

この二つをクリアしている場合
しばらく時間をおいてみてください。
おそらく問題が解決すると思います。
AWS Certified DevOps Engineer - Professional を取得した

#前回のお話

https://qiita.com/morio1101/items/1f78c46fe7538140e2ba

#はじめに

本記事は、将来再認定を受けるときの備忘録でもあります
本記事を見る時点で大体AWS認定試験のことや、DevOps Engineer - Professional のことはほかの記事のほうが詳しく書かれていると思うので、省略してまとめたいと思います


#試験を受ける前の私のスペック

* AWS を使った業務経験は最低限はある
    * EC2 関連がメインであり、その他機能についてはほぼ知らないに等しい状態
* 知識ベースの指標としては、AWS認定試験は以下を取得した
    * アソシエイト資格3種
    * プロフェッショナル1種
        * ソリューションアーキテクトプロフェッショナル
    * スペシャリティ 試験4種
        * データアナリティクス
        * セキュリティ
        * ネットワーク
        * データベース

#学習教材

* AWS WEB 問題集で学習しよう
※ 模擬試験はやりませんでした

#学習期間

11/1 - 11/27

## AWS WEB 問題集で学習しよう（11/1 - 11/27）

みんなの合格記を見る限り ♯1-56 の問題が満遍なく出てくると書かれていたので、1-56の問題を3週実施した

* 1周目
    * 4-7割程度の正解率で満点比率は低め
* 2周目
    * 7割-満点の正解率で満点は半々ぐらい
* 3週目
    * 7割-満点の正解率で満点の比率は高め

問題の解き方は、間違えたor正解しているが運で正解したものはしっかり解説を読む
アソシエイトレベルもしくはほかの試験で得た知識で答えれたものはスルーする形で実施した
1周目は約2週間掛けて実施した。2、3周目は1週間単位で実施した

# 試験結果

他の試験と比べると狭く深くという印象で、問題集で得た知識だけである程度は自信を持って解くことができた
試験自体は1周目で残り60分、見直しで残り15分と結構ギリギリでした。（試験中に別のことを考えたりしてて、試験に集中できてなかった＋試験終盤は集中力が完全に切れていたのが要因ではある）
一通り解いて、2択ぐらいに絞り込むand全くわからない問題が15、16問ぐらいあった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532289/3dd969cc-516b-4292-376e-a5479687fe06.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532289/25ff1887-c1ee-d7f4-8428-cf57fd4e7121.png)

点数的には予想通りより少し高い結果でした
ポリシーと標準の自動化については弱いという結果だったので、精進しないとですね

# 試験を受けて思ったこと

一般的にはソリューションアーキテクトのほうが難しいという話題がWEBを徘徊する出回っている
個人的に思うのは、狭くそこそこ深い試験と、広く深そうな試験という点で、ソリューションアーキテクトのプロフェッショナルは後者
覚えることが多いのって結構しんどいし、実際に触ったことがない機能が試験範囲にいくつも含まれつつも、知識だけを頭に突っ込んで試験に挑むので、応用力が乏しくなるのは致し方がない部分があるのかもしれない

DOP については、デプロイ方法や構成、障害復旧時の対応方法を求められるケースが多く、設問内に重要視している点が含まれているので、読み解いて適切な解を導き出す力が求められるように感じた
そこで点が取れると6、7割は取れるように感じている

#最後に

残すところMLSのみとなった
問題があるとすれば、AWSサービス以外に機械学習の知識が必要になるらしい
そこのハードルがどれほどのものなんだろうか、、、
ブラックフライデーでUdemyの商材を買うか結構悩みどころですね:sweat_smile:
初学者がpyenvの仮想環境の管理に困った話


　pyenvの扱いにハマったときのことを書き残します．マイナーな事例かもしれません．あと思い出しながら書いているので再現性は低いかも...

# (蛇足ですが)はじめに

　pyenvはPythonのバージョンや仮想環境を管理できるツールです．local設定をすると作業ディレクトリに移動するだけで環境が切り替わってくれるので便利．
(公式リポジトリは[こちら][pyenv])

[pyenv]:https://github.com/pyenv/pyenv

　自分はWSL2を使っているのでホームディレクトリにcloneしました．macの方はbrewでもインストールできます．

# 起こったこと

　普通に環境を作って`pip install`して使っていたところ，あるとき突然モジュールが`pip list`には入っているのに`import`できない...といった問題が発生しました．他の人に聞いても「それは謎」「ちゃんと使ってればそんなことにはならないはず（意訳）」と言われてしまいました．

　しょうがないので`python -m pip install`でだましだまし使っていましたが，このままではpyenvを使っている意味が薄れてしまうので，調査を進めてみます．

# 調査内容・顛末

　とりあえず`pip show`してみると，なぜか`~/.local`以下にあることに．ここを探してみるとPythonやpipが入っていたので，アンインストール（削除）．

　その後`which python`してみると，これまた変なところ（確か`/usr/bin`直下）を指し示されました．よってこれも削除．

　終わったか...？とpipを試してみると，

```
subprocess.CalledProcessError: Command ‘(‘lsb_release’, ‘-a’)’ returned non-zero exit status 1.
```

というエラーに遭遇．調べると[こんな記事][p]を見つけたので，この通りファイルを書き換え，念のためpyenvから入れ直して終了．

[p]:https://hacker.trickstorm.com/?p=1748


　無事環境ごとに入れるモジュールを区別するという，pyenv本来の使い方をできるようになりました．


# まとめ・感想

　いろんなパスを辿りつつ手探りでなんとか解決できましたが，sudoで無理やりファイルを消してたりするので本当はあまり良くないのかも．余裕があるならUbuntuから入れ直した方が安全だと思います．

　Pythonはpyenv経由でしか入れてないはずですし，そもそも新調したてのマシンなのでどさくさに紛れてグローバルなところに入っていた...っていうのも考えにくく，原因は未だ不明です．ただ気を付けるべきこととしては，

- 今いる仮想環境が何か常に意識する（これはプロンプト表示の変更で解決）
- これから使うPythonやpipがどこに入っているか確認する

といったことが挙げられるでしょうか．仮想環境はちゃんと使い分けるから便利なのであって，前提となる部分を蔑ろにしてしまうのは良くないよね～という教訓を得ました．
産業用ロボット販売営業職からエンジニアになってみて

##前職の内容
制御機器を取り扱う商社でSE("セールス"エンジニア）をやっていました。
要は、メーカーの生産技術の方などに、省人化の提案をし、ロボットを買ってもらう営業の仕事です。

##エンジニアになろうと思ったきっかけ
慣れてくると、作業をこなすだけの仕事をやるのが自分の性には合わなかったんです。エンジニアは技術の移り変わりが比較的早い職業ですし、どんどん新しい事にチャレンジできますよね。

まず前職の仕事に飽きが来たというお話をします。
SEと言っても技術的には、物体を掴んで別の場所に移動させて置くだけの簡単なプログラムを書くだけの事しかやりません。
しかもそのプログラムとは、メーカー専用のタブレットのGUI上でボタンを押し、ツリー上に各処理を追加していくだけの操作なのです。
SEといっても、やはり営業なので、いかに製品の良さを顧客に伝えれるかに注力し、顧客に買ってもらうのがメインのお仕事です。
買ってもらうためにはどうしたら良いか、次の発注に繋げるためにはどうしたら良いか、という試行錯誤はあったものの、技術的な試行錯誤をし、できなかった事をできるようにする過程がなかったので、仕事の喜びをあまり感じる事ができませんでした。
最初は楽しかったんですが、慣れてくると、同じようなプレゼンを繰り返す毎日で、飽きが来たんです。

さて、ここからがエンジニアに興味を持ったお話です。
2年ほど前に、youtubeでたまたまエンジニアの仕事を語っている方の動画を見ました。誰でも稼げるとか、本当なのか？？と思うような内容ではありましたが、エンジニアとして仕事ができるようになるまでの学習の流れがわかったので、まずはちょっとprogateってサービスでプログラム書ける見たいだし、macかっこいいし、mac買ってやってみるかあ〜くらいの気持ちでやってみました。

macの画面綺麗！！見た目かっけぇ！！こんな簡単にwebのページ作れるんか！！
ちょっとプログラミング面白いな。しかもリモートで働いていたり、私服勤務が多いみたいで、自分にはいいかもしれない。
という気持ちになり、エンジニアを目指す事になった訳です。
カッコ良いし割と自由そう。という気持ちが一番です。
人間、何をやるにしてもモチベーションが一番大事だと私は思っているので、きっかけとしては、これで十分でした。

##エンジニアとして働いてみた感想（前職と比べてどう変わったか）
・私服通勤
・オフィスで音楽流れてるしオフィス自体オシャレ
・スペック高いmac支給
・定時10時〜19時
という状態で、働く環境的には大きく変わりました。

前職は、古くから続く企業なので、まあ堅苦しい感じでした。
・リモート勤務中に私服で会議に参加したら怒られる
→私服で仕事すると売り上げが落ちるんでしょうか？？
補足すると、隣の営業部の課長が毎日のように怒る人でした。
自分の部署の課長的にはリモート時の服装は私服でもokだったんで、隣の営業部の課長が堅い人だった訳です。

・髭が濃いだけで怒られる
→髭剃ってますけど画質の問題で濃く見えていたみたいです。逆に見た目の事言うとかひどくないですかね、髭濃いの私ちょっと気にしていますし。

さて、働く環境のお話は終わりにして、次は仕事内容です。
単純に良かった点、良くないと感じた点に分けた方が書きやすかったので、分けました。

###良いところ
エンジニアであれば当たり前ですが、
・勤務中pcと向き合える
・やりたい技術で開発をやらせてくれる

これが自分にとって良かったです。

・勤務中pcと向き合える
営業をしていると、移動時間が必ず発生します。
少しなら良いんですが、私の場合、都内行ったり千葉行ったり茨城行ったりしていたので、一日の大半が移動時間みたいな日も当然ある訳で、時間がもったいないし、変に移動で疲れたりしました。
エンジニアは基本pcと向き合って仕事をするので、移動時間が無いです。
割と一定のリズム感で一日の仕事ができます。

・やりたい技術で開発をやらせてくれる
これは会社によって大きく違うところなので、私の会社の場合は、という前置き付きです。

会社の方針と大きく外れていなければ基本的に好きな技術で開発をさせてくれます。受託と自社開発両方やっていますが、クライアントがいわゆる開発会社では無くハイブランド系の会社なので、クライアントからの技術指定が無いです。なので、開発を行う側の私たちは、好きな技術選定ができる訳です。
自分はフロント側はVue3（言語はTypeScript）, サーバー側はRuby on Rails（言語はRuby)で開発をしています。
iOSアプリ開発がやりたいと言えば、今すぐにとは行かないものの、希望は通るでしょう。

次の案件の開発は何を取り入れようかといった具合で、新しいチャレンジをさせてもらえています。入社してから成長の実感を得られているし、当初の目的であった新しいチャレンジもできているので、ひとまずこの調子でやっていこうと思えています。

###良くないと感じているところ

良くないという言い方は適切ではないかもしれませんが、要するに気をつけないといけない事の話です。

・体調不良になりやすいかもしれない
・力技で案件をこなさないようにする

・体調不良になりやすいかもしれない
自分の会社でも足腰を痛めている人や、首を痛めている人がいます。エンジニアという職種に直接関係しているかは定かではありませんが、前職の営業の会社では、40歳を超えても元気な人ばかりだったので、人と話す事や、移動する事が日常の人の方が、健康で居やすいかもしれないと感じています。

・力技で案件をこなさないようにする
技術の移り変わりが早いので、移り行く環境に対応していく必要があるのですが、力技でプログラムを書いたり、ただただやり方を暗記したりして、日々を過ごし、年齢を重ねてしまうと、若者との差が対して開かないので、後々きついと感じています。
私は、今のところ実力のある方からのレビューを通して、１ヶ月前の自分のレベルの低さを実感できているので、引き続き成長したい気持ちです。
力技使うとすぐ指摘を喰らいますね。笑

##今後はどんなエンジニアを目指したいか
まずはwebの分野で日々の業務を半日で終わらせられるエンジニアを目指したいです（本当は数時間で）。で、残りの時間を自分の時間（スキルアップとか）に当てたいです。

今はある程度仕事ができるようになってきてはいますが、事前に計画を立て、ゴールまでの道筋を正確に描き、そのために必要な働きかけを主体的にできているとは言い難いので、上記ができるエンジニアを目指します。

余裕がなく日々残業しているようでは、イレギュラーな対応が来たら、その時点で計画は破綻し、計画がシンプルに遅れるか、無理をするかしか道はないですし、そのような状態では仕事を頼む側の人も仕事を頼みにくいですから。

##最後に
ここまで読んでいただきありがとうございます。
私と同じように感じていただける人がいれば嬉しく思います。
営業が別に嫌いな訳ではないので、エンジニアに飽きが来たら、SE的な事しても面白いかもと思ったりもします。

新しい事にチャレンジするのは確かにしんどい事ですが、やらなければ良かったと後悔した経験はほとんどないので（多分皆さんも）、色々とやっていきたいと思う所存です。
【Rails】global source lines

##global source lines　
Gemfileに記述されるgemに対してsource、git、pathのオプションを指定しなければ、Gemfileの一行目にある引数のサイトから取得される。

```ruby
source "https://rubygems.org"
```

このsourceメソッドの行はマニュアル内で global source lines と呼ばれる事がある。

###sourceオプション　
gemを検索するサイトを取得

```ruby
gem "gem_name", source: "url"

#全てのオプションで、ブロックを用いて一括で書ける
source 'url' do
  gem 'gem_name1'
  gem 'gem_name2'
end
```

####pathオプション　
ファイルシステム内のパスを指定し、gemの取得先とする

```ruby
gem "gem_name", path: "url"
```

###gitオプション　
作成されたgemのgitリポジトリから取得

```ruby
gem "gem_name", git: "url"
```
【PyTorch】AttributeError: 'GeneralizedRCNNTransform' object has no attribute 'fixed_size'

# TL;DR
GPU環境で学習したモデルを`torch.save`で保存し、CPU環境で`torch.load`で読み出し推定を行うとエラーが発生する場合がる。

**解決方法**  
`torch.load`ではなく各種学習モデルのクラスからインスタンス化して`load_state_dict`で学習したパラメータを読み出す。

# 詳細

[[PyTorch] TORCHVISION OBJECT DETECTION FINETUNING TUTORIAL](https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html)を基に物体検出を試す

## 環境

CPU側

- anaconda3 Python 3.8.10
- pytorch 1.10.0-py3.8_cpu_0
- torchvision 0.11.1-py38_cpu

## 原因

`torch.save, torch.load`でモデルを保存・読み込みすると、`__init__()`経由でインスタンス化されず`None`のクラスメンバが未定義となってしまう。結果として`AttributeError`で落ちる。

```py:train.py
import torch
import torchvision
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor

# モデルの定義
device = torch.device("cuda")
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
# get number of input features for the classifier
in_features = model.roi_heads.box_predictor.cls_score.in_features
# replace the pre-trained head with a new one
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, 2)

# 学習処理
# ~中略~

# モデルの保存
torch.save(model, "path/to/model.pth")
torch.save(model.state_dict(), "path/to/model_weight.pth")
```

```py:predict.py
import torch
from PIL import Image
from torchvision.transforms import functional as F

device = torch.device('cpu')
model = torch.load("path/to/model.pth", map_location=device)
model.to(device)
model.eval()

img = Image.open("path/to/image").convert("RGB")
img = F.to_tensor(img)
imgs = [img.to(device)]
with torch.no_grad():
     out = model(imgs)
     print(out[0]["boxes"].numpy())
```

## 修正

```diff:predict.py
- model = torch.load("path/to/model.pth", map_location=device)
+ model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
+ in_features = model.roi_heads.box_predictor.cls_score.in_features
+ model.roi_heads.box_predictor = FastRCNNPredictor(in_features, 2)
+ model.load_state_dict(torch.load("path/to/model_weight.pth", map_location=device))
```
truffle migrateを実行したら、insufficient fundsエラーが発生

https://www.oreilly.co.jp/books/9784873119342/

P84

truffle migrate --network goerliを実行して、ガス代不足でデプロイ失敗。

```
$ truffle migrate --network goerli

Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



Migrations dry-run (simulation)
===============================
> Network name:    'goerli-fork'
> Network id:      5
> Block gas limit: 8000000 (0x7a1200)


1_initial_migration.js
======================

   Replacing 'Migrations'
   ----------------------

Error:  *** Deployment Failed ***

"Migrations" could not deploy due to insufficient funds
   * Account:  0x357D5b3B1527f642Da8765b98b4717e907a930eC
   * Balance:  0 wei
   * Message:  sender doesn't have enough funds to send tx. The upfront cost is: 584634000000000 and the sender's account only has: 0
   * Try:
      + Using an adequately funded account
      + If you are using a local Geth node, verify that your node is synced.

```

MetaMaskを確認したら、確かにETHが入っている。やっぱり、設定などの間違いか。。。

![スクリーンショット 2021-11-27 21.19.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360525/40bb3b4b-8f28-e366-eaca-356b43e5a80f.png)


truffle-config.jsを調べたら、やっぱり、デプロイ先をローカルのGanache　（```http://127.0.0.1:8545```）　に向いている。

```
    goerli: {
      provider: () => {
        const mnemonic = process.env["MNEMONIC"]
        return new HDWallterProvider(mnemonic, "http://127.0.0.1:8545");
      },
      network_id: "*",
    },
```

MetaMaskのネットワーク設定を開き、goerliテストネットワークのRPCのURLをコピーして、GanacheのURLを置き換える。
![スクリーンショット 2021-11-27 21.27.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360525/ed865480-a9bd-2396-6f52-3a3d081cf1ca.png)

```
    goerli: {
      provider: () => {
        const mnemonic = process.env["MNEMONIC"]
        return new HDWallterProvider(mnemonic, "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161");
      },
      network_id: "*",
    },
```
truffle migrate --network goerliを再実行、デプロイは上手くいった。
flex grow, shrink, basis

##  flex-grow
* 子要素全ての幅を足しても親要素の幅100%にならない時、その余白を各子要素間でどの程度負担するかを表す。
* デフォルト0。余白があってもほったらかし。負担しない = 伸びない

#### 前提
* 子1にwidth 30%
* 子2にwidth 30%
* => 余白は40%。

### 子要素間の合計が1以上のケース

* 子1にflexGrow1, 子2にflexGrow3を設定すると、余白を1:3 で負担することになるので子1が10%, 子2が30%広がる
* 他の全ての子が0(デフォルト)で、子2だけに1以上が設定された時、余白の全てを子2が負担する事になるので、子2が40%広がり合計70%を占める。

### 子要素間の合計が1未満のケース
* 余白は40%なので、flexGrow0.5を設定すると、余白を1とした割合である20%伸びる。
* 子1がflexGrow0.1, 子2がflexGrow0.1だと、それぞれ4%増える。合計それぞれ34%になり余白はまだある状態。
* もし、子1と子2にflexGrow0.8設定し合計が1を超える場合、子要素間の合計が1以上の時と同じ挙動になる

## flex-shrink
* 子要素全ての幅を足すと親要素を越える時、その越えた分を各子要素間でどの程度負担する = 縮む かを表す
* デフォルト1。子要素全てが1なので、超えた分を子要素間で均等に負担する。
* 例えば子1はwidth 80%,子2はwidth80%の時、Flex無しだと合計160%になり60%はみ出してしまうが、親要素にFlexを適用した途端、はみ出した60%を子要素がそれぞれ30%負担し、widthは80%-30%で50%になる
* 固定widthが設定されていない要素を含む親要素に対してFlexを設定すると想定外に縮むことがありハマることがある。Flexの子要素全てのwidthは固定されていることを確認するべき！！！
* `<div>{ comment }</div>` みたいな子要素があると、子要素が伸びて親要素を超えた分を子要素間で均等に負担し縮んでしまう。縮んでほしくないときも縮んでしまうことがある。
* `flex-shrink: 0`は超えても負担しない = 「縮まない」ということ。他の縮むことができる子要素間で超えた分を負担して縮む。もし全部の子要素がflex-shrink0だとどれも縮まず超えた分は超えたままになる。
* 子要素間のflex-shrinkの合計が1以上の場合は、それらの比率によって負担割合が決まる。
* 子要素間のflex-shrinkの合計が1以下の場合は、超えた分を1とした時の割合分縮む。

## flex-basis
* これまで、「本来の子要素の幅」を基準に考えてきたが、それをflexのプロパティとして設定できこれを基準にflexの計算がされる。本来のwidthを上書くイメージ。ただflexのdirectionが縦になるとwidthではなくなることがwidthとは違う。
* デフォルトはauto。本来の子要素の幅がそのままflexの計算をする基準値になる
* 子1と2にflex-basis: 40%を設定すると、合わせて80%のため残り20%は余白になる
* 子1にwidthを80%, 子2にwidth 200%と設定後、それぞれflex-basis: 50%とすると結果のwidthは50%になり上書きされるイメージ
* pxの絶対値でも設定可能。

## flex
* grow, shrink, basisを一度に設定できるプロパティ。
* `flex: <grow> <shrink> <basis>`
* `flex: 0 1 20%`　と書く


参考
https://fuuno.net/web02/flex/flex.html
https://fuuno.net/web02/flex02/flex02.html
https://developer.mozilla.org/ja/docs/Web/CSS/flex