OmniAICreator/Qiita-1.07M huggingface dataset:
create-react-appで.envの値が読み込めなかったときにやったこと

`React`と`Ruby on Rails`を用いたポートフォリオを作成中に詰まった内容です。

## 問題
`create-react-app`で作成したプロジェクトで`.env`ファイルから環境変数を読み込めなかった。

## 現状

```jsx
import { useAuth0 } from "@auth0/auth0-react";

export const Home = () => {
  const { isAuthenticated,loginWithRedirect,logout } = useAuth0();

  return (
    <button onClick={() => loginWithRedirect()}>ログイン</button>
  )
}

```

auth0にリダイレクトするために、ログインボタンを実装。そしてログインボタンを押すと以下のようになる。

```url
https://undefined/authorize?https://undefined/authorize?client_idなんちゃらかんちゃら.......
```
![スクリーンショット 2021-08-12 13.24.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601125/168f869d-3e59-d38e-65d5-e00f6c4e503e.png)

## 結論
`.env`を設定したあと、一度コンパイルをし直した。
`Ctrl + C` から `npm start`を実行すれば環境変数を読み込みできた。

## やったこと
### 同じように悩んでいる記事がないか確認
auth0 DNS_PROBE_FINISHED_NXDOMAIN　で検索

↓ヒットした記事
https://community.auth0.com/t/auth0-login-undefined-authorize-redirect/49874

> Maybe my .env variables of domain and client Id aren’t being read in my index.jsx file?

> Any idea if it would be an issue with my front end not pulling from .env file? Given that the redirect is not working

とあったので、いったん

```index.js
const domain = process.env.REACT_APP_AUTH0_DOMAIN
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID

console.log(domain, clientId) // undefined, undefined
```

と出力された。

### .envを確認
`.env`から環境変数が読み込めていないことがわかったので、`.env`を確認。
create-react-appで作成したプロジェクトの場合、.envを読み込むためには
.env変数が`REACT_APP`から始まっている必要があるとのこと。

```.env
REACT_APP_
```

https://create-react-app.dev/docs/adding-custom-environment-variables/

これは大丈夫そう。

### .envがプロジェクト直下に配置されているか
create-react-appで作成したプロジェクト直下においてあるか確認。これも大丈夫だった。

https://qiita.com/wakeupsloth/items/ec19b9fbfddfb1cd58bb#3-env%E3%81%8C%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%9B%B4%E4%B8%8B%E3%81%AB%E4%BD%9C%E6%88%90%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84

### .envを設定後にコンパイル
これで解決した。
.envを設定したら、一度`Ctrl + C`で終了させ、もう一度`npm start`を実行する。
ネットワーク関連のコマンドまとめ

### ping

ネットが繋がるか調べる。

```
ping -c 3 8.8.8.8  
```

### traceroute

通信経路のルーターを調べる。

```
traceroute -I  8.8.8.8
```

### ip

端末のipアドレスとかルーティングテーブルを調べる。

```
ip address show
ip route show
```

### tcpdump

通信してるかを見る。

```
sudo tcpdump -tn -i any icmp
```
資料を何度も往復したくないから自動で申請書を作ってほしい

#申請書作成は複数ファイルを見ながらやるので処理が大変
新しい店舗ができるたびに申請書を書かないといけないのですが、情報の書いてあるファイルと申請書の2つのファイルを交互に見ながら作成するのが大変です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/5ccb7135-8be2-62a6-ca34-6fa254f8a7bb.png)
またテレワーク用のPCは画面が小さいので、さらにストレスがかかります。
今回はPower Automate Desktopを利用して、どこに対象のデータがあるかわかればファイルを見る事無く申請書を作る方法を試しました。
#ユーザー側の作業内容
①列を入力します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/3e7945f3-e192-9696-aed7-d7c26fe10e11.png)
②この店舗で良いか聞いてきますので、問題なければOKを押します。
![gamenn2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/69b0d6fc-043f-5f7b-fc66-9141fb031060.png)
③全部で何台必要なのかを入力します。
セル中身は規則性がないため、ユーザーが判断して入れてもらいます。
![gamenn3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/d14cab0b-b256-d3a3-9ede-9b9e33d45cae.png)
#フロー
メイン処理
元のデータと申請書のファイルを選択して、読取開始列が入力されたら処理を開始します。
![main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/b6da432a-99e9-8562-3a3f-bc3298d82d3b.png)
サブフロー①
店舗が間違っていれば処理を中断します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/696c8134-74f5-21f2-743b-3435f2375a29.png)
サブフロー②
入力したレジの数だけ処理を繰り返します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1806653/71a13deb-4bb8-9ac8-5530-3b1517fd7605.png)
#まとめ
PowerAutomateDesktopを使って始めて作ってみましたが、規則性がわかると非常に簡単です。
慣れない私でも調べながらやって2時間くらいで完成できたので、慣れてくればもっと早くできると思います。
今回は1店舗ずつ処理をし　ていく内容ですが、特定の範囲を指定してあげれば、次々に処理をしてくれるツールになると思う。
早速テレワーク中に資料を作ってみましたが、<font color="Red">いつもは20分くらいかかる作業が、5分くらいに短縮できました。</font>
他の人も使いたいと要望をもらったので、もっとクオリティを高めていけたらよいと思います。
#VBAとの比較
VBAでも似たような事が出来ますが、画面の作成が圧倒的に楽です。
またフローも視覚的にわかりやすいのでコメントの入れる手間もないのが個人的にうれしい。
自分だけのツールを作るならこれで十分だと思いました。
コマンドプロンプトで時刻付きのpingを行う(バッチファイル利用)

pingを利用していて時刻も併せて表示したくなったので、バッチファイルを作成してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/98113f91-31a6-aa07-7121-2f783f855d50.png)




#実行
バッチファイルを作成し、そのまま実行するかコマンドプロンプト上で実行できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/f51b510d-cc28-172b-f314-3fd92ad12922.png)


IPアドレスを入力すると、延々とping状況を1秒ごとに出力します。
終了する際はウィンドウの[x]で閉じるか```ctrl+c```で終了してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201787/24ce1872-b4a5-05da-f0e4-ae27b8eaaad7.png)



＃なお、IPアドレスを入力しない場合、GoogleDNS(8.8.8.8)へ通信します。

#バッチファイル

```bat:timeping_1line.bat
@echo off
setlocal enabledelayedexpansion

echo ### timeping_1line.bat start ###
set dt=null
set text=null
set res="からの応答 タイム 転送 宛先 見つかり"


SET /P ipaddr="IPアドレスを入力:  "
IF "%ipaddr%"=="" (
    set ipaddr=8.8.8.8
)
echo.


for /l %%I in (0, 0, 0) do (
    FOR /F "delims=," %%i in ('echo !date:~0^,4!/!date:~5^,2!/!date:~8^,2! !time:~0^,2!:!time:~3^,2!:!time:~6^,2!.!time:~9^,2!') DO @SET dt=%%i
    FOR /F "delims=," %%i in ('ping -n 1 %ipaddr% ^|findstr %res%') DO @SET text=%%i
    echo !dt!    !text!
    timeout 1 > nul
)

endlocal

rem EOF
```




#後記
pingコマンドと同じように引数形式にしたり、コマンド間隔をオプション化したり、IPv6対応させたりと修正点は尽きないですが、必要になったら対応しようと思います。

ちなみにpowershellだと以下1行。

```ps:timeping
ping -t 127.0.0.1 | %{(Get-Date).ToString() + " $_"}
```
【Laravel】画面遷移させる方法　例：一覧画面から登録画面に遷移

暇なときに予定を探せるアプリ[yoteiPicker](https://yoteipicker.com/)をリリースしました。

Laravelで画面遷移させる方法を簡単に解説します。

今回は例として、一覧画面から登録画面に遷移させてみます。

開発環境
Docker 20.10.7
PHP 7.4.22
Laravel 8.53.1

以下の記事の続きになります。
[【Laravel実務に使える】マイグレーションの作成から一覧画面表示まで](https://qiita.com/kamome_susume/items/4013dfcc9c0b93db7ce1)
[【Laravel8】レイアウト共通化 layoutsファイルのapp.blade.phpのコード例](https://qiita.com/kamome_susume/items/4cb10cf50a090e0d01f0)

#実際に書いていこう
編集するのはルーティングと一覧画面のビューだけです。
※登録画面とコントローラーの記述は事前に用意

コントローラーBookController.php

```php
    public function create(Request $request)
    {
        return view('book.create');
    }
```

まずはルーティングをいじります。

routes>web.php

```php
// 本の登録画面の表示
Route::get('/create', [BookController::class, 'create'])->name('book.create');
```

一覧画面のビュー
resources>book>index.php

```php
<a href="{{ route('book.create') }}">本の登録へ</a>
```

これで一覧画面から登録画面に遷移できます。

暇なときに予定を探せるアプリ[yoteiPicker](https://yoteipicker.com/)をリリースしました。

https://www.kamome-susume.com/enginner-job-change-site/
SpringBootの組み込みTomcatのバージョンだけアップする方法

# 背景
過去に何度かTomcatに致命的な脆弱性が見つかって対策パッチを適用したりバージョンを上げたりして対応することが何度かあったのだが、SpringBootみたいに組み込まれているTomcatのバージョンだけを上げたいような場合、どうやればいいのか気になったので調べてみた。

# 前提環境
バージョンを上げる前のバージョンは以下のとおり。

- SpringBoot 2.3.0.RELEASE
- Tomcat 9.0.35
- Gradle 5.6

```
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.0.RELEASE)


INFO 1431 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 1431 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.35]
```

# `tomcat.version`を設定するだけでいい
結論から言うと`build.gradle`に以下の記述を足すだけで良い。どうやらSpringBootは`spring-boot-dependencies`という部品がバージョン管理しているようで、この`spring-boot-dependencies`には**バージョンプロパティ**が用意されていて、この値を変更するだけでTomcatだけでなく他の依存ライブラリのバージョンも上げることができるようだ。

```build.gradle
ext['tomcat.version'] = '9.0.50'
```

- 公式ドキュメント
    - https://spring.pleiades.io/spring-boot/docs/2.3.0.RELEASE/gradle-plugin/reference/html/#managing-dependencies-customizing
- `tomcat.version`などのバージョンプロパティ一覧
    - https://spring.pleiades.io/spring-boot/docs/2.3.0.RELEASE/reference/htmlsingle/#dependency-versions-properties

```

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.0.RELEASE)

INFO 3146 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 3146 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.50]
```

# その他注意事項
バージョンプロパティに値を設定するだけでバージョンを変えること自体は容易だが、これによって依存していた処理が動かなくなることも考えられるので、動作確認はちゃんと行ったほうが良い。
また、今回はGradle5.6で試したが、[公式の記述にあるように](https://spring.pleiades.io/spring-boot/docs/2.3.0.RELEASE/reference/html/build-tool-plugins.html#build-tool-plugins-gradle-plugin)今回のやり方でバージョンを上げるには Gradle6.3以降が推奨されているので、もしGradleのバージョンが足りていないなら、Tomcatのバージョンを上げる前にGradleのバージョンを上げなければならない。あるいはGradleの前提としているJDKバージョンも上げないといけないかもしれない。となると、開発用のJavaバージョンと開発ツールのJavaバージョンをあわせているプロジェクトでは、このあたりの開発環境の影響も考慮したほうがいいだろう。
WordPress の編集画面でビジュアルエディターが使えなくなった原因と対処

WordPress で Web サイトを構築して、さぁ完成したぞとリリースしたところ編集画面でビジュアルモードが使えなくなる不具合に遭遇してしまった。

## 環境
- AWS EC2 インスタンス
- WordPress 5.8
- プラグインは色々入れているが不具合発生の前後で追加などはしていない

## 現象
すべての編集画面 (Gutenberg) が強制的に「コードエディター」になり、「ビジュアルエディター」へ変更するメニューも消えてしまった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/9251aaf0-7723-20e3-9295-1343d651f71a.png)

前まではこの「プラグイン」メニューの上のところに「エディター」というメニューがあったはずだが・・・？

## 試したけどダメだったやつ
- ユーザ設定の「ビジュアルリッチエディターを使用しない」にチェックが入っているのではないか？
    - → 確認したけど入っていなかった

## 判明した原因
0. 本番リリースにあたって CDN (CloudFront) を挟むように変更した
0. CloudFront はデフォルト設定だと User-Agent を「Amazon CloudFront」に書き換えて forward する
0. Gutenberg は User-Agent をみて「ビジュアルエディターが使えるかどうか」を判断しているらしく、「Amazon CloudFront」なる User-Agent は使えないと判断して無効にした

Gutenberg なんだその仕様・・・
せめて warning メッセージか何かを出してほしいな・・・

## 対応方法
CloudFront の Behavior の設定で User-Agent を forward するように設定した。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/43f8a491-4ec8-6591-cfa4-7cd289cdcc4b.png)

↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/4011a274-f778-a22b-ff13-08a26296d559.png)
WSL Ubuntu20.04 on windows10

備忘録

まず、初期設定で色々変更したいなら「WSLとPowerShellを両刀使いで進めていく」ということを頭に入れておくとよい。いろんなサイトを見ていると出てくる__"wsl"コマンドは基本的にPowerShell__の方で使用する。
#インストール
###① アプリストアから__インストールする前__に以下を確認

```:PowerShell
# wsl --list -v
  NAME            STATE           VERSION
* kali-linux      Stopped         1
  Ubuntu-20.04    Stopped         1
```

何か出てくれば既に何らかのWSLがインストールされているということ。何も出てこなければWSLはインストールされていないということ。自分は上記のような感じだったので、WSL1をインストール済みである。今回はここからWSL2へのアップグレードを行っていく。こちらの公式サイト(https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#step-4---download-the-linux-kernel-update-package) を参考に進めていくとできる。以下は備忘録。

###② WSL2カーネルパッケージのダウンロードおよびインストール
今回WSL2のカーネルパッケージが手元にないので、以下をDLして起動→「次へ」とか「はい」とか押して終了
https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi
アップグレードするディストリ名を指定して<versionNumber>には2を指定する。なお、色々なサイトを比較したところ、この<distribution name>は人によって表記のされ方が異なるっぽいので、必ず自分のPC上での名前を# wsl --list -v で確認したものを指定する。

```:PowerShell
# wsl --set-version <distribution name> <versionNumber>
```
![WSL_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/975449/02953533-d3fb-416a-ff7b-d90f4053ae4b.png)
上記赤枠の通りバージョンが2になったことが確認できる。

以後WSL2をデフォルトとして規定したい場合、以下のようにすることでこれ以降インストールするWSLに関しては全て2がインストールされることとなる。

```
# wsl --set-default-version 2
```

#初期設定
###① rootユーザのパスワード設定
WSLインストール最初に聞かれるユーザはsudoコマンドが使えるユーザになるが、rootユーザではない。かといって、以下のコマンドはrootが既にあるから使えないよと言われる。

```:WSL
$ sudo useradd root
```
なので以下のコマンドでrootユーザに環境ごと移行してパスワードを更新する。

```:WSL
$ sudo su -
New Password:
Retry Password:
```

これで以後一般ユーザからrootに変更する際は以下でパスワード入力すればはいれるようになる！

```WSL
[user01@hostname]$ su
                   Password:
```

###② コマンドプロンプト変更
デフォルトだとコマンドにはwindowsで認識しているホスト名と現在位置のフルパスになっているので、長ったらしい。これを変更する。
ホスト名の変更は「/etc/hostname」で変更してWSLを再起動すればよい。ここで、どうやってWSLを再起動すればいいのか？が問題になったwww　WSLからは #reboot を受け付けてくれないので、以下で対処する。

```:PowerShell
# wsl --shutdown
```
これでWSL2の方がシャットダウンされ、またアプリを立ち上げれば再起動ということになる。(なんて不便なんだ・・・)

次にコマンドプロンプトフルパス変更を行う。今回は1行目から2行目への変換を行いたい。
username@hostname:full path directory name
[username@hostname only current directory name]

__1) 一時的に変更するソフトコード__

```
# export PS1='[\u@\h \W]\$'
```

__2) 永続的に変更するハードコード__

```WSL
$ sudo vi ~/.bashrc   ---> 一般ユーザのコマンドプロンプト変更
# vi ~/.bashrc        ---> rootユーザのコマンドプロンプト変更
```
viの検索機能を使用して、PS1の「w」(小文字)を「W」(大文字)」に変更する。こうするとフルパスではなく、現在のディレクトリ名のみの表記になる。なお、[\033]とかで挟まれていると思うが、これは文字色を指定しているので、好きなカラーにするといい。詳細はこちら(https://shio-ax.hatenablog.com/entry/2019/05/27/174018)

後日、一般ユーザの方を以下に変更した。これでプロンプトは「username@WSL」になった。編集すべき箇所は__"PS1=～"__の3か所。

```:WSL
if [ "$color_prompt" = yes ]; then
    PS1='${debian_chroot:+($debian_chroot)}[\[\033[01;32m\]\u\[\033[00m\]@Ubuntu20.04 \[\033[01;34m\]\W\[\033[00m\]]\$ 'else
    PS1='${debian_chroot:+($debian_chroot)}[\u@Ubuntu20.04 \W]$ '
fi
unset color_prompt force_color_prompt

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u\a\]$PS1"
```

###③ インストールしておいた方がいいパッケージ
ifconfigコマンドが使えないww ので以下でネット関連のツールを入れておく

```:WSL
# apt-get install inet-tools
```
systemdのUnitファイルのパスを知らなくともUnitファイルを編集する方法

systemdのUnitファイルの配置先パスは[いっぱいあり](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#System%20Unit%20Search%20Path)、正直どこに置いていいのかわかりづらいです。
systemdを制御するsystemctl(1)には[editというサブコマンド](https://www.freedesktop.org/software/systemd/man/systemctl.html#edit%20UNIT%E2%80%A6)があり、Unitファイルのパスを知らなくともUnitファイルを編集できます。 `systemctl edit` の利点は2つです。

- 今使っているシステム内で利用すべきパス上でエディタが立ち上がる
    - Unitファイルの場所を知らなくても編集できる
- 編集後に `systemctl daemon-reload` を自動実行してくれる
    - 反映し忘れが無くなる

試しに以下のようにすると ssh.service のUnitファイルのパスを知らなくとも、エディタが立ち上がって編集できるようになります。

```console
sudo systemctl edit --full ssh.service
```

この時のエディタは `SYSTEMD_EDITOR` 環境変数、もしくは `EDITOR` 環境変数で指定されたものになります。
~~nano が立ち上がっても落ち着いてCTRL+Xしたら `apt autoremove --purge nano` してから再チャレンジ。~~

### `--full` 等のオプション

- `--full`
    - Unitファイル本体自体を編集します。つけない場合は上書き用Unitファイルを編集することになります。
- `--force`
    - Unitファイル本体編集時に、ファイルが無い(=新規)ならファイルを作成します。

### Unitファイルのパスを知りたい

Unitファイルのパスを知りたい場合は `systemctl cat UNIT_NAME` で表示される1行目を見ると良いでしょう。これ以外に方法が無さそうです。

```console
$ sudo systemctl cat ssh.service | head -1
# /etc/systemd/system/ssh.service
```

### 標準入力(stdin)から編集するには `SYSTEMD_EDITOR=tee`

teeを使えば標準入力からの流し込みも可能です。

```console
$ cat ssh_unit_contents.txt
[Unit]
Description = SSH daemon
$ cat ssh_unit_contents.txt | sudo SYSTEMD_EDITOR=tee systemctl edit ssh.service
```

```
$ cat << _EOT_ | sudo SYSTEMD_EDITOR=tee systemctl edit ssh.service
[Unit]
Description = SSH daemon
_EOT_
```

## `--full --force` と標準入力編集の組み合わせ

`--full --force` と標準入力編集を組み合わせれば、インストールが簡単になるでしょう。

```console
$ curl https://hoge.foo/bar.service | sudo SYSTEMD_EDITOR=tee systemctl edit --full --force bar.service
```

EoT
Juliaでcsvを開く

## JuliaでCSVを開く

意外と情報が錯綜していてよくわからん。

```julia
using DataFrames
using CSV
```

```julia
df = CSV.read("hoge.csv", DataFrame)
```

とりあえずこんな感じで動くっぽい。tsvでも全く同じ方法で読み込んでくれる。これが最善の方法かはわからん。

## 列名

```julia
names(df)
```
【解決】【Python】自作クラス内のlistに値を代入するときappendだと__dict__に代入されない

# 8/12追記

@shiracamusさんより丁寧に解説して頂き解決しました。
結論として変数をインスタンス化をしていなかったらとなります。

```python:
class Result:

  def __init__(self):  # 初期化をしていなかった
    self.result = []
```
初期化することでappendでも代入されることを確認しました。
ありがとうございます。

以下追記前の記事です。

# はじめに
PythonでクラスをJSONにシリアライズするときにハマったので書き落としておきます。
まだまだ初学者で根本的な間違いをしていそうなので、理由わかる方いましたらぜひ教えて頂きたいです。

# 環境
python 3.9.6
pipenv version 2021.5.29

# 本文
###0. 前準備
実行結果をまとめておくクラスに内包されたlistを用意しておきました。

```python:
  class Result:
    result: list[str] = []
```
###1. append
さて、ここに実行結果の文字列をどんどん代入していきますが最初はappendで追加していきました。

```python:
  def test_append(self):
    result = Result()
    result.result.append("a")
    result.result.append("b")
    result.result.append("c")
    json_string = json.dumps(result.__dict__, indent=4)
    print(json_string)
```

```python:実行結果
{}
```

???となったので中身を見てみます。

```python:
  def test_append(self):
    result = Result()
    result.result.append("a")
    result.result.append("b")
    result.result.append("c")
    tmp = result.__dict__
    print(tmp)    # 結果: {}
```
空ですね。

###2. 演算子
次に演算子で代入してみました。

```python:
  def test_assignment(self):
    result = Result()
    result.result += ["a"]
    result.result += ["b"]
    result.result += ["c"]
    tmp = result.__dict__  # {'result': ['a', 'b', 'c']}
    jsonString = AnJson.objectToJson(result)
    print(jsonString)
```

```:実行結果
{
    "result": [
        "a",
        "b",
        "c"
    ]
}
```

入ってる。。。なぜ。。。

# 終わりに
Pythonの配列を使うと毎回挙動で躓くので勉強が足りてない感がすごいです。
今回のは放置しておくと今後困りそうなので記事に落としました。
ご親切な御仁がいましたらこの挙動の理由を教えて頂きたいです。

以上

# 参考
https://qiita.com/Akio-1978/items/0bb4075ea05a8b4d53cc
セル内の文字を抽出する 

文字の右から抽出する
============
見本としてA1に「あいうえお」と入力しました。
ココから関数、VBAを使用して指定の文字数を抽出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/29aa0bff-025b-8058-609b-1065ae83f867.png)

Excel関数
------
関数で抽出する場合の書き方

```rb
=RIGHT(対象セル,抽出する文字数)

入力例
=RIGHT(A1,1)
```

対象セルと抽出する文字数を指定する事で末尾の文字を抜き出せます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/c39b2a30-7356-d186-75b6-1fb963725a3e.png)

例え抽出する文字数が元の文字数より多かったとしてもエラーになる事はありません。

ExcelVBA
------
VBAで抽出する場合の書き方

```rb

結果 = Right(対象セル,抽出する文字数)

```

書き方は上記の関数入力とほぼ同じですね。
結果のところを変数にしたり、セルを指定する事で応用が利くと思います。

以下の例文ではセルB1に直接結果を出力しています。

```rb

Sub 文字の右から抽出()
    
    'セルA1の右から2文字をセルB1に出力
    Cells(1, 2) = Right(Cells(1, 1), 2)
    
End Sub

```

使用例としてはクライアントPCの管理No.の末尾の数字で管理サーバが異なる場合などに重宝しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/c8a90f6e-6185-ebf1-dc91-f98bd6de0fde.png)


初めて記事を書いてみました。
不慣れではありますが、関数とVBAの比較、PowerShellのコマンドなど
自分への備忘を含めて記事にしていこうと思います。
君のオブジェクト指向は間違っている。

# はじめに
はじめに敢えて断言しよう、君のオブジェクト指向は間違っている。
もし君がオブジェクト指向とは何かと聞かれて以下のように答えるなら、君は僕の授業を聞いていく必要がある。

オブジェクト指向とは、

1. 手順ではなく、モノに着目する（車とか動物とか。てかオブジェクトの言葉そのままやん）
1. 変数と処理をまとめたものだ（カプセル化）
1. プログラムを再利用しやすくするためのものだ（継承）
1. ポリモーフィズムを使える（いまいち理解できていない人が用語だけ出してきた感）

ちなみに上記のリストはGoogleで「オブジェクト指向」と検索して出てくるページに書いてあることを挙げたものだ。全くなっていない。挙句の果てには「オブジェクト指向は何かという問には答えがないから、なんとなくのイメージを掴んでいれば良い」などと言ってのける強者までもが出現する始末である。私はこのような解説記事が世に蔓延していることに驚きを隠せない。まともな記事１つ出てこないではないか。多分そこそこにソフトウェア開発をやったこともない者が書いているのであろう。てか絶対そうだ。

# オブジェクト指向の本質はインターフェイス
オブジェクト指向というかソフトウェアの本質だが、重要なのは「それが何であるか」ということではなく「それが何をするのか」ということなのだ。これこそが機能と呼ばれるものである。ソフトウェアにおいて車が車であることなどどうでもよい。ただ目的地へ着けば良いのだ。これはソフトウェア特有の話であり現実世界であれば、車は車であることに価値がある場合もある。なぜなら現実世界のモノは見えるからだ。一方ソフトウェアにおいてそれが何であるかなど一般ピープルには見えない。それがどんな機能を持ちどんな効能をもたらすかにしか興味がないのである。
よって我々はモノに着目している場合ではない。機能に着目すべきなのだ。**インターフェイスとは機能をユーザー側の視点から記述したものだ。**これによって機能を構成するものの中でユーザーが知る必要のない情報（実装）を隠蔽するのである。各コンポーネントが自分が知る必要のあることだけを知ることで、現代の複雑かつ大規模なソフトウェア開発が可能になるのである。

# 変数と処理がどこにあるかなんてどうでも良い
これは言い過ぎかなと思うが、まあどうでも良いので仕方ない。カプセル化は大事だし全部の変数をpublicにしやがったら蹴っ飛ばしてやるところだが、実際これを最低限できてない人はあんまりいないんじゃないかな、皆ゲッターセッター大好きだしね。
私が言いたいのは**変数と処理は実装であり、実装などユーザーにとってどうでもよい**ということなのだ。ちなみにユーザーとは現実のユーザーのみならず、ソフトウェア内部で該当クラスを利用しているモジュールも含めている。

# 継承は禁止だよ。
敢えて断言しよう（二回目）。継承なんてオブジェクト指向には必要ない。どころか有害である。オフィスの窓開け放ってかなぐり捨てることに躊躇してはならない。私は継承をごりごりやらかしているイタいコードを見ると体中に蕁麻疹ができてしまい、それが私の目前で行われた日には、どうやってチームメンバーに継承をやめて頂こうかと考えるあまり夜も眠れなくなってしまう。
継承が持つ重大な問題は私が考えるに２つある。１つ目はソフトウェアにおける根源的な話だが、継承によりベースクラスに処理を共通化したり、オーバーライドしたりするというのはつまり実装に依存するということなのだ。実装は変わりやすい。そして変わりやすいコードへの依存は最小限に抑えるべきなのだ。２つ目はスコープが広がってしまうことだ。継承先のクラスのコードを読むときに、変数・関数共にそれがこのクラスのものなのか、それとも継承元のものなのか確認せねばならない。書いた本人はわかっているから良いが、読む方はいちいちどのファイルに該当のコードがあるのかを探しに行かなくてはならないのだ。これは何でもできるスーパークラスを作ってスコープ広げるよりもたちが悪い。だってたくさんファイル開かなきゃいけないから。
とはいえ何でもかんでも禁止とは流石に言わない。例えばGUIは「何であるか（どう見えるか）」に重きがあるという点で継承を使うことが理にかなっている場合もある。
私が言いたいのは「処理を共通化したいから継承」は止しなさいということで、それをするなら別クラス（or 関数）に共通処理を切り出してそれをクラスに持たせて使いなさい（合成）、ということなのです。

# さいごに
オブジェクト指向は非常に広範な事柄を指しているようで、実は突き詰めるとインターフェイスに行き着くのであります。皆様がこの記事をきっかけにオブジェクト指向についての考えを深めていただけると嬉しいです。
最後になりますが、散々人を間違え呼ばわりしてきましたが、次は私のターンだということは重々承知しておるつもりであります。はい、ブーメランですね。皆様どうかお手柔らかに…
GitHub Actions tag push ステージを１つのワークフローで管理する

# はじめに

GitHub Actions でデプロイパイプラインなどを構築する際に複数環境が対象となることは往々にしてあるかと思います。

例ですが、AWSアカウントにおいても環境やコストなど様々な理由でAWSアカウントごと分離して設計を行うように
ここではGitHub Actions でデプロイパイプラインなどを構築する際に１つのワークフローで管理する方法を検討します。

## ワークフローの管理

### 環境毎の管理の方法

方法としては２パターンです。

1. １つのワークフローで複数環境を管理する
1. 環境毎にワークフローを分けて管理する

`1.` については環境毎に比べて共通の処理が纏められるので管理は楽になりますが、判定条件を加えることによって可読性は著しく低下します。
また書き方を間違えると思わぬ事故(開発にデプロイするつもりが本番に)につながることもあるかもしれません。

`2.` については `1.` に比べて環境毎にワークフローが分離されるため、管理する対象は環境毎に増えるものの可読性を著しく低下させたり、書き方を間違えて事故に繋がったとしても影響範囲はその環境に限定されそうです。

それぞれにメリット、デメリットは他にもありますがこの記事では `1.` の方法を検討します。

## ワークフローの方針検討

### 方針

- １つのワークフローで複数環境を操作する
- ワークフロー実行には `push/tags` を利用する
- 想定する環境は以下
    - dev 開発環境
    - stg ステージング環境
    - prod 本番環境

### タグの命名規則

{任意の文字列、日付など}.{環境名}.{役割や用途など}.{連番もしくはバージョン番号}

例）
20210813.dev.version.1

## ワークフローの定義

早速完成版です

```yml:.github/workflows/get_ref_example.yml
name: Get Version
on:
  push:
    tags:
      - '[0-9]+.dev.version.[0-9]+'
      - '[0-9]+.stg.version.[0-9]+'
      - '[0-9]+.prod.version.[0-9]+'
jobs:
  pre:
    name: pre
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Load Environment
        id: get_envs
        run: |
          echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/}
          echo ::set-output name=STAGE::$(echo ${GITHUB_REF#refs/tags/} | awk -F. '{print $2}')
      - name: print
        run: |
          echo ${{ steps.get_envs.outputs.VERSION }}
          echo ${{ steps.get_envs.outputs.STAGE }}
      - name: Setup
        id: setup_config
        run: |
          case "${{ steps.get_envs.outputs.STAGE }}" in
          "dev" )
            echo ::set-output name=PARAM1::dev
            ;;
          "stg" )
            echo ::set-output name=PARAM1::stg
            ;;
          "prod" )
            echo ::set-output name=PARAM1::prod
            ;;
          esac
      - run: |
          echo ${{ steps.setup_config.outputs.PARAM1 }}
```

### タグからステージを取得する

`Load Environment` ステップではタグからステージを取得します。

ワークフローをトリガーしたブランチまたはタグ名は `GITHUB_REF` から取得します。
`refs/tags/{タグ名}` が格納されているため、`Shell Parameter Expansion` で `refs/tags/` を削除してタグ名のみを取得します。

https://docs.github.com/ja/actions/reference/environment-variables

https://docs.github.com/ja/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter

ステージ名はタグ名から `awk` コマンドで２つ目を切り出し、出力パラメータとして後続へ渡します。

### ステージ毎の処理の分岐

例ですが、case文で処理分岐します。
ここではステージ毎に処理分岐をして出力パラメータに設定された値がステージ毎に動的に設定されているかを確認しています。

## 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228453/a1d03048-5568-4960-fad3-522d467d4047.png)

ステージが取得できたので他にもステップに `if` キーワードで制御して環境毎に実行するしないも制御しやすくなりました。
gitlabでprojectを作る

# はじめに


ファイルをgitlabで管理したいが、ローカルにそのファイルがある場合と、ない場合でgitlabプロジェクトの作り方が異なる。

これを知らなかったため、ローカルにファイルをつくりgit管理、commitまではできたものの、いざremoteへpushするときに様々なエラーでハマった。忘備のためメモしておく。

#前提
下記が終了していること
 - [x] GitlabのSign up（ユーザー登録）
 - [x] SSH公開鍵の作成とGitlabへの登録
 - [x] 2段階認証のGitlabへの登録
 - [x] アクセストークンのgitlabへの登録

# 結論

プロジェクトを作るgitlabの画面(New project > Create blank project)で、**『Initialize repository with a README』**というオプションをオフにした。

![スクリーンショット 2021-08-12 112200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554997/123bf987-8545-d3c5-b95a-6a3c872f4bb0.png)


これは、**『READMEを作成する』**というオプションなので、チェックを外すと**『READMEを作成しない』**ことになる。つまりローカルとリモートが同じ状態になる。

# 学び

このようにローカルとリモートのファイルの差異によって、プロジェクトの作成の仕方に違いがあります。
まず始めにgitlabでプロジェクトを作ってからローカルでファイルを作成するようにする、とか自分なりのルール化しておく、など慣れるまではどちらか一方に統一しておくとよいかもしれない。


詳細はこちらを参照ください
https://qiita.com/tomotlab/items/40bc75ca81162bf9c789
ラズパイカメラ

ラズパイで高速で撮影したり、ストロボで同調させる方法はあるかな？

v1カメラだとグローバルシャッターは無いけど、グローバルリセット機能を使うことで瞬間の写真が撮れるとのこと。

https://www.raspberrypi.org/forums/viewtopic.php?t=277823

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter#introduction
Herokuで [CRITICAL] WORKER TIMEOUTと出た時に対処したこと[python]

ローカル環境では動いていたのに、Herokuにデプロイするとなぜか動かない…

$ heroku logs -t --app アプリ名
でログを見てみるとこんな表記を発見。
2021-08-11T02:53:56.976537+00:00 app[web.1]: [2021-08-11 02:53:56 +0000] [4] [CRITICAL] WORKER TIMEOUT (pid:9)

タイムアウトしてるじゃないか。

https://devcenter.heroku.com/ja/articles/request-timeout
ここを見ると、どうやら30秒でタイム・アウトするらしい。
これを乗り越えるために必要なのはバックグラウンドジョブによる処理だ。

RQ を使用した Python でのバックグラウンドタスク
https://devcenter.heroku.com/ja/articles/python-rq

ということで、ここに書いてあるとおり、RQを使ってバックグラウンドジョブに投げる必要がある。

## ハマったこと

### ジョブが投げられているかどうかが分からない
先程のリンクを見てみると分かるが、web dynoではなくworkerというdynoを使うことになる。
こいつのログを見るには

$ heroku logs -t -p worker --app アプリ名

でログを見る。
呼び出し側から正常に呼ぶことができていれば、workerのログに処理内容が流れる。
ちなみに、web dynoにも流れるが、これだけ見てるとしっかりworkerにジョブが渡っているかが分からないので注意。
web dynoだけ見て、処理されてるっぽいのになぜ…って結構な時間悩みました。

### 処理の書き方
q.enqueue(関数名,引数,job_timeout=3600)
job_timeout部分は必要に応じて

これはもうこの書き方じゃないと駄目です。
色々ハマってた時に、こんな形で書いてエラーが出なかったので安心していたのですが
q.enqueue(関数名(引数),引数名=引数,job_timeout=3600)

これだとworker側に渡りません。

ということで、ハマりました。
[pythonを使ってリアクティブなWebアプリを作りたい【開発編5】Herokuの開発環境と本番環境](https://qiita.com/geeorgey/items/b080617f5332ab7255c4)
これの開発中にハマったのですが、処理走ってるのにサーバーエラーが表示されるとか、フロントエンド側にどうやって返せばいいのか、みたいないろんなものが複合的に絡まって、混乱したんですよね。
無事に解決できてよかった。
以上です！
【話】G検定におそらく最速で受かった話

#こんばんはー
この記事ではJDLA協会が行っているG検定の2021#2に受かった時の話をしたいと思います。

G検定受けようと思ってるんだけどどれくらい勉強すればいいの？とか、どんな試験なのっていう人にピッタリの記事だと思います。

ただG検定自体シラバスの改定など変化の多い試験なので鵜呑みにはしないように。

# どのくらい勉強したか
僕がどのくらい勉強したかです。

まず最初に勉強はするべきです。するとしないとでは、本番での余裕に差が出ると思いますし、CBTだからといって全問検索しながら解くのは難しいと思います。したがって即答できる問題を作っておいて、より難しい問題に時間をかけるのが正攻法だと思います。

勉強期間はだいたい2日程度、時間にして10時間勉強すれば十分という感じでした。
参考書は以下のものを使用しました。

https://www.amazon.co.jp/%E6%9C%80%E7%9F%AD%E7%AA%81%E7%A0%B4-%E3%83%87%E3%82%A3%E3%83%BC%E3%83%97%E3%83%A9%E3%83%BC%E3%83%8B%E3%83%B3%E3%82%B0G%E6%A4%9C%E5%AE%9A-%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%A9%E3%83%AA%E3%82%B9%E3%83%88-%E5%95%8F%E9%A1%8C%E9%9B%86-%E5%85%89%E5%A4%AA%E9%83%8E/dp/429711609X/ref=sr_1_14?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=G%E6%A4%9C%E5%AE%9A%E5%8F%82%E8%80%83%E6%9B%B8&qid=1628731808&sr=8-14

この参考書を選んだ理由はレビューに「他の参考書よりも良い」ということが根拠とともに示されていたからです。本当に良い参考書なのかはわかりません。

まずこの参考書をてきとうに一周しました。一周目はELIZA効果やいろいろな知らない固有名詞が並び、分からない部分も多かったです。この参考書は最低限解説がされているので「間違って理解してる」のか「ただ単に知らないだけ」なのかが分かりやすくてよかったです。

勉強法としては回答を白紙に書いていき、後で答え合わせして間違えた問題に×をつけるという方式です。ここで重要なのはなるべくこまめに答え合わせをする、ということです。
章ごとだと答え合わせまでに時間がかかりすぎて問題を忘れてしまい、一問ごとだとページをめくったり戻したりが大変なので、僕は節ごと答え合わせをしていきました。

また、×をつけると二周目以降が一気に楽になります。

とくに教師あり学習などニューラルネットワーク以外の機械学習の部分は今まで蔑ろにしてきたこともあり、かなり大変でした。

逆にニューラルネットワークの部分は大学で理論から各モデルの構成まで詳しくやったこともあるため、かなり余裕がありました。


二周目はかなり問題も覚えていることもあり、これ以上やっても意味ないと感じたため×のついた問題のみ答えられるようにしておきました。
# 当日
CBTなので特に難しいことはないです。

まず開始すると問題のボタンがずらーっと並んだ一覧表が表示されます。この一覧表を使うと後でフラグを立てた問題に飛びやすくなる形です。当然左上にある第一問から解き始めていきます。

問題構成としては、参考書では内容ごとまとまっていましたが、本番では全部の内容がシャッフルされたような形で出題されます。なので最初から難しい問題が続いたりしますが特に慌てなくて大丈夫です。確信のない問題にはフラグをつけてどんどん進みます。

最初のうちは時間配分のために検索などはせずに分からなかったらフラグを立てて飛ばしていきましょう。

2020#2では問題数が190問？で時間が120分でした。ちょっと問題数は忘れましたが、例年よりかは問題数が少ないと思います。解いてる最中は残り時間が約何割であと何問残っているのかから計算してペースを調整します。

最後まで解き終わるとフラグのついてる問題が20問前後、残り時間は60分でした。かなり余裕があったのでフラグのついてる問題を最初からひとつづつ、ゆっくり検索しながら解いていきました。

ただ、中には検索しても解けない「やばい問題」もあります。最終的に3個近くはそのやばい問題でした。
このやばい問題とは問題文でうまく検索しても解説サイトがなく、ガイドライン系の堅いPDFしか当たらないような問題です。

まぁ分かってたら解けるのでしょうけど分からない人にとっては率直に「捨て問」だと思います。

# 結果
結果は例年通りだと9営業日後に返ってくるっそうですが、2020#2では個人成績のこともあってか少し遅れて結果が来ました。

![Desktop Screenshot 2021.08.12 - 10.57.31.82.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496596/610b2774-d244-f3a5-cec8-0d592c8d2182.png)

数理、統計は解いた覚えがないのですがこんな感じだそうです。

#まとめ
この記事の内容をまとめますと、

- そこまで対策はしなくていい、けど油断は禁物
- CBTなので固有名詞を完璧に覚えなくて良い
- フラグを立てて解いていけば自然と時間は余る

って感じです。思ったよりも内容薄かったですね。
まぁそこまで難しい試験でもないのでこれくらいでしょう。

では。
プロジェクト毎にflutter configを設定する

## 前提
- **2.0.0** より前のversion
    - `flutter config` を実施すると `~/.flutter_settings` に設定ファイルが作成さる
- **2.0.0** 以降のversion
    - `flutter config` を実施すると `~/.config/flutter/settings` に設定ファイルが作成さる

:warning:  プロジェクト毎にflutter confignを設定する場合、**2.0.0** 以降のversion である必要があります。
## 概要
あるプロジェクトだけしか使わない設定でも、`flutter config`  すると全般に効いてくるので、
特定のプロジェクトだけの `flutter config` にしたい。

※ もしかしたら需要無いかもですが、気になって調べた際のメモになります。なんかの参考になれば。。

## 方法
方法としては **2.0.0** 以降のversion で設定ファイルが作られる場所を見たら想像付くかと思いますが、
[XDG Base Directory仕様](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)になっているので、環境変数 **XDG_CONFIG_HOME** を設定しておけば、
`$XDG_CONFIG_HOME/settings` に設定ファイルが作成されるようになります。

## 運用例
例えば [fvm](https://github.com/leoafarias/fvm)を使っていて、複数プロジェクトそれぞれ別のflutter versionで開発していた場合に、
特定のプロジェクトだけ `--build-dir` を設定しているが、他のプロジェクトではデフォルトがいい場合、
[direnv](https://github.com/direnv/direnv)を使って、特定のプロジェクト直下に、`.envrc` を以下の内容で作成しておけば、
`fvm flutter config xxxx` で設定した内容が、`.fvm/settings` に設定されるようになります。

```
export XDG_CONFIG_HOME=$PWD/.fvm
```

この状態で `fvm flutter config --enable-web` と設定すると `.fvm/settings` に

```json
{
  "enable-web": true
}
```
が保存されます。

`fvm_config.json` と一緒にgit管理しとけばメンバー間で共有できて良さそうです :sparkles: 

:warning: 注意点としてXDG Base Directory仕様を採用している別のツールなどを一緒に使う場合はそちらも設定ファイルが
`.fvm` 配下に作られちゃいます。。

## 補足

実際にconfigを書き出している箇所を調べてみたら、[flutterのソース](https://github.com/flutter/flutter/blob/91f8b6be510093f6ac5ff4ec1e578641a4f7f9b3/packages/flutter_tools/lib/src/base/config.dart#L195)には↓の様になっていました。

```dart
  static String _configPath(
      Platform platform, FileSystem fileSystem, String name) {
    final String homeDirFile =
        fileSystem.path.join(_userHomePath(platform), '.${kConfigDir}_$name');
    if (platform.isLinux || platform.isMacOS) {
      if (fileSystem.isFileSync(homeDirFile)) {
        return homeDirFile;
      }
      final String configDir = platform.environment[kXdgConfigHome] ??
          fileSystem.path.join(_userHomePath(platform), '.config', kConfigDir);
      return fileSystem.path.join(configDir, name);
    }
    return homeDirFile;
  }
```
`kXdgConfigHome = XDG_CONFIG_HOME` で定義されています。
また、既に `~/.flutter_settings` が存在する場合は、そちらの内容を反映するようになっています。
この内容が反映されたのが、 [こちらのPR](https://github.com/flutter/flutter/pull/66645) がマージされたタイミングで
それ以前は以下の様な実装になっています。

```dart
class Config {
  factory Config(
    String name, {
    @required FileSystem fileSystem,
    @required Logger logger,
    @required Platform platform,
  }) {
    final File file = fileSystem.file(fileSystem.path.join(
      _userHomePath(platform),
      name,
    ));
    return Config._(file, logger);
  }

  // Reads the process environment to find the current user's home directory.
  //
  // If the searched environment variables are not set, '.' is returned instead.
  //
  // Note that this is different from FileSystemUtils.homeDirPath.
  static String _userHomePath(Platform platform) {
    final String envKey = platform.operatingSystem == 'windows'
      ? 'APPDATA'
      : 'HOME';
    return platform.environment[envKey] ?? '.';
  }
}
```
`$HOME/.flutter_settings` に書き込むようになっています。
フルHDの動画だけに整理したい

#動機
たまにビデオ編集しているのですが、
HDDの中で良い素材があったと思ったら、解像度が低くてげんなりしたので
フルHDの動画だけに整理したい思います

#サンプル動画
このサイトから、３種類の解像度をダウンロード
https://test-videos.co.uk/bigbuckbunny/mp4-h264

#必要なもの
ffprobe
https://evermeet.cx/ffmpeg/

#スクリプト
ffprobeの部分は、パスを記載

```shellscript:fhdmv.command
#!/bin/bash

if [ $# -ne 1 ]; then
  echo "実行するには引数が必要です。" 1>&2
  exit 1
fi

FHDDIR=/Desktop/qiita/FHD   #移動先
CDIR=$1
RES="1920,1080"
for file in `\find  $CDIR -maxdepth 1 -mindepth 1 -type f`; do

    echo $file 
    Resolution=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 $file )
    echo $Resolution
    
	if test $Resolution = $RES; then
		mv $file $FHDDIR
	fi
	
	
done
```


#起動
引数に動画ディレクトリを指定
fhdmv.command /Desktop/qiita/movie 

確認のログがでます
ファイル名の解像度とログの数値が一致しているのであっています

/Desktop/qiita/movie/Big_Buck_Bunny_1080_10s_1MB.mp4
1920,1080
/Desktop/qiita/movie/Big_Buck_Bunny_720_10s_1MB.mp4
1280,720
/Desktop/qiita/movie/Big_Buck_Bunny_360_10s_1MB.mp4
640,360


#確認
フルHDだけ移動できました

![last.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514937/a4a20690-6f4c-0b9f-26e5-14a461dedb0d.png)
venvをgitで管理するとソース管理に5000が表示される


##エラーの経緯
githubでリポジトリを制作後VScodeでローカルにクローンを作りました。そして、[Django Tutorial in Visual Studio Code](https://code.visualstudio.com/docs/python/tutorial-django)に示す通り仮想環境を作りおなじみのロケットがブラウザに表示するまで作業を行いました。
ここで、githubにプッシュしようとしたら以下のようにソース管理が5000となってしまいました。
![スクリーンショット 2021-08-12 102639.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1752668/578741ae-007a-42f5-bd07-d0797411b267.png)
##解消法
venvを使用するとき以下のコードを.gitignoreに指定すればほとんど解決します。[参考](https://github.com/github/gitignore/blob/master/Global/VirtualEnv.gitignore)

```:.gitignore
# Virtualenv
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
.Python
[Bb]in
[Ii]nclude
[Ll]ib
[Ll]ib64
[Ll]ocal
[Ss]cripts
pyvenv.cfg
.venv
pip-selfcheck.json
© 2021 GitHub, Inc.
```

そうするとだいぶすっきりしました。しかし、.pycのファイルがまだ7件くらい表示されていたのでもしそれを無視したければ以下のコードも.gitignoreに追加することで解決しました。

```:.gitignore
*.pyc
```

Ubuntuで仮想環境を作る時

```:.gitignore
*.whl
```

を追加するとよりスッキリする。
以上私のメモ代わりに記事を投稿させていただきました。
レーザーカッター　完成

#レーザーカッター完成
まだチョコチョコ手を加えたいところはありますが、
ひとまずレーザーカッター完成です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664748/cd6ab06f-5a09-cd2a-ba2c-ebe568df6d1d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664748/ddffb98b-649f-8910-85db-8f966696a9c1.png)

配線をもうちょっと綺麗にしたいです。横の黒いのは「やしがら活性炭」をいれたフィルターボックスです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/664748/f9b67918-b2a6-7bfa-8264-a2fffd71be8b.png)

今後は
・外部ダクト
・配線まとめ
・レーザーenable信号の外部ON/OFF
などをする予定。
島根県松江市における気象予報値をCSVに保存し、Webサイトで閲覧できるようにしたので、これをPandasで読み込んで可視化してみる。

# はじめに

以下のサービスを利用して気象予報値を入手し、業務システムで利用しているのですが、生データを加工するのがなかなか大変。

http://www.jmbsc.or.jp/jp/

ということで、とりあえず直近に必要なデータとして、島根県松江市における2日後の気象予報値をCSVで保存して、毎日23:30に更新するという仕組みを作ってみたので可視化も試してみた。

気象予報のデータを加工するのは以下の記事をご参照下さい。

https://qiita.com/ysomei/items/12d6622bed030f6ac793

# CSVのダウンロード

以下のURLにてCSVのダウンロードが可能です。
毎日23:30時点における翌々日の１日分の１時間ごとのデータ24点が確認できます。

[matsue.csv](https://blueomega.jp/20210812_gRfm/matsue.csv)
※ 2021年8月17日 他の地域を追加したため、ファイル名を変更

各項目については、以下のURLをご参照下さい。

https://ods.n-kishou.co.jp/tech/blog/detail/1923

# 可視化

とりあえず、データを読み込んで気温と日射量を可視化してみます。

```py:
import pandas as pd
import matplotlib.pyplot as plot

df = pd.read_csv("https://blueomega.jp/20210812_gRfm/matsue.csv")
df.index = pd.to_datetime(df.pop("datetime"))

df.TMP.plot(figsize=(15,5))
plt.show()

df.DSWRF.plot(figsize=(15,5))
plt.show()
```

実行結果。

![Unknown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114240/84fc4046-de4a-a68a-be91-d7daeb486cbf.png)

![Unknown-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114240/126a6dab-52ba-6835-8f7a-a057a965405c.png)

できた。

今日は12日だから2日後の14日の予報値が入っています。
実際には23:30時点での2日後なので、明日同じスクリプトを実行したら14日の予報値、明後日に実行したら15日の予報値が取得できることになります。

もし他の都市のデータが欲しいという方や違う期間のデータを同じように取得したいという方がおられましたらご相談下さい。
無償ではないかもしれませんが、ご協力できるかもしれません。

これからしばらく記録してみて、実績値と比較しようかな。
仕事用プロファイルでアプリをデバッグする

## やりたいこと
toB向けのアプリを開発していると、Androidの仕事用プロファイルとして起動した時のみに発生するバグに遭遇したりして、仕事用プロファイルでデバッグをしたい時があります。

## 事前準備
### adbのパスを通す
前提として、adbのパスを通しておきましょう。
Qiitaのこの記事を参考にすると良いと思います。
[ターミナルにadbのパスを通す(Mac)](https://qiita.com/piyonakajima/items/32cbd82f4b3c7e30e6ae)

### デバイスに仕事用プロファイルを設定する
そもそも実機に仕事用プロファイルが設定されていないと、アプリを仕事用プロファイルとしてインストールすることができません。
まず[Googleのドキュメント](https://support.google.com/work/android/answer/6191949?hl=ja)を参考にして、お手持ちのデバイスに仕事用プロファイルを追加しましょう。

## 一旦実機で実行する
仕事用プロファイルをアプリに入れたら、実機で実行してしまいましょう。
仕事用プロファイルが入っている状態で実行をすると、自分の個人用と仕事用プロファイルでどちらにもアプリが端末にインストールされるはずです。

個人用プロファイルにしかインストールされない場合、、、
- 個人用のアプリを消して再度実行
- **Run/Debug Configurations**の`Install for all users`にチェックを入れる

の上記2点を確認してみてください
後者の`Install for all users`は下の画像のようになっていればOKです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/1e1a7d8e-771f-c7db-8ed6-ee46a4e488be.png" width="800">

## ユーザーIDを調べる
仕事用プロファイルの入った実機をPCに繋いだ状態でターミナルで以下のコマンドを打ちます

```
adb shell pm list users
```

すると結果として以下のように返ってくると思います

```
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running
```
仕事用プロファイルが正しく作用しているデバイスであれば、２つの`UserInfo`が取得できるはずです。
仕事用プロファイルに当たるUserInfoは後者にあたります。
欲しいユーザーIDはここだと`10`です。

https://developer.android.com/work/managed-profiles#testing_tips

## ユーザーIDを指定してデバッグする
デバッグ対象のユーザーIDがわかったら、ユーザーIDを指定してデバッグが可能になります。
AndroidStudioのツールバーの『Run > Edit Configurations』を選択します。
**Run/Debug Configuration**のウィンドウが開いたら、**Launch Options**の**Launch Flags**に以下の文言を入力します。

```
--user 10
```

`--user `の後ろにはそれぞれの仕事用プロファイルのユーザーIDを入力してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82263/de420c99-f5e0-ffaa-a74a-a6965eb13db8.png" width="800">

これで実機デバイスで実行すれば、デバッグが仕事用プロファイルの方で行われるようになります。
CartPoleを強化学習ライブラリKeras-rlを使って学習させてみた

DeepLearningの勉強中なのですが、（全くわからないので）「とりあえず他人の模倣をする」という方針で、多くの皆様方がやっておられるOpenAIのCartPoleを強化学習ライブラリKeras-RLを使って学習させてみました。

#CartPoleとは

CartPoleは横に移動できるカートの上にポールが立っており、そのポールをいかに倒さず長く維持できるかを競うゲームになっています。言い換えるとCartPoleでは「4つの入力情報（カートの位置、カートの速度、ポールの角度、ポールの角速度）を与えて、2つの出力（左に押す、右に押す:押す強さは固定）のうちどちらか1つを選ぶ、DeepLearningのモデルを作りなさい」と言うことです。

![cartpole.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593076/62664196-5983-eb54-c5e6-6055c5fdc69e.png)

#動作環境

本投稿では下のライブラリを使っています。Keras-RL2が強化学習用ライブラリで、gymがCartPoleが入った実験環境を提供してくれるライブラリです。

* Tensorflow 2.5.0
* Keras-RL2
* OpenAI gym

```bash:
pip install tensorflow
pip install keras-rl2
pip install gym
```

なお、Keras-RL2はKeras-RLが入っていると（私の環境では）動作しませんでした。Keras-RLをuninstallしてからインストールしてください。

#プログラム

他のサイトを参考に作りました。深く理解はしていないのですが一応学習は成功しました。

```python:
import gym
from tensorflow.keras.models import Sequential,load_model
from tensorflow.keras.layers import Dense,Flatten,BatchNormalization
from tensorflow.keras.optimizers import Adam
from rl.memory import SequentialMemory
from rl.policy import BoltzmannQPolicy
from rl.agents.dqn import DQNAgent

env = gym.make('CartPole-v0') 
env.reset()

model = Sequential([
	Flatten(input_shape=(1,4)),
	Dense(32,activation='relu'),
	BatchNormalization(),
	Dense(32,activation='relu'),
	BatchNormalization(),
	Dense(32,activation='relu'),
	BatchNormalization(),
	Dense(2,activation='linear')
])
#model=load_model('cartpole')     #保存したモデルをロードする時に使う

memory = SequentialMemory(limit=50000, window_length=1)
policy = BoltzmannQPolicy()
dqn = DQNAgent(model=model,nb_actions=2,memory=memory,nb_steps_warmup=10,target_model_update=1e-2,policy=policy)
dqn.compile(Adam(lr=1e-3), metrics=['mae'])
dqn.fit(env,nb_steps=50000,visualize=True,verbose=2)
dqn.model.save('cartpole',overwrite=True)
dqn.test(env,nb_episodes=3,visualize=True)
```
[iPad] Colaboratory でコピペ出来るようにする設定

###初めに

意地でもiOSでColaboratoryを操作したい、ただそれだけです。Google Colaboratory をPCブラウザと同じように動かすことが目的です。

###環境

私の環境は以下になります。

* iPad Pro
* 物理キーボード(非純正)
* iOSのChromeブラウザ

###まずは「PC版サイトをリクエスト」
iPad の画面は大きいためデフォルトでPC版を表示してくれれば良いのですが、目下モバイル版サイトが表示されるようです。モバイル版ですと十字キーが使えなかったりとより不便になってしまいますので

Chromeブラウザの
共有メニュー > PC版サイトのリクエスト 

の操作が必要かと思います。


###仕上げにキーバインディングの変更
ここまでである程度操作できるようになったかと思います。然しコピペが上手くできませんよね。キーバインディングの変更が必要です。

Colaboratory画面内上部の
ツール > 設定 > エディタ > エディタのキーバインディング
ここで選べるのは以下3つです。

* default
* vim
* classic

**vim** を選択してください。
あとはvimエディタの要領で編集モードを使ってコピペが自在にできるかと思います。


:::note warn
注意
default と classic ではコピペが上手くできませんでした。
コピー時に、単なるスペースがノーブレークスペースになってしまうようでコードを実行するとエラーを吐きます。
:::

###最後に
これでiPadでもColaboratoyの操作が普通にできるかと思います。
では、良いiPad×Colaboratoy ライフを！！
AtCoderログ：0069 - ABC 047 B

# 問題

https://atcoder.jp/contests/abc047/tasks/abc047_b

## 問題文
> $xy$ 平面上に、左下の座標が $(0,0)$、右上の座標が $(W,H)$ で、各辺が $x$ 軸か $y$ 軸に平行な長方形があります。最初、長方形の内部は白く塗られています。
> すぬけ君はこの長方形の中に $N$ 個の点を打ちました。$i$ 個目 $(1 \le 
i \le N)$ 点の座標は $(x_i,y_i)$ でした。
> また、すぬけ君は長さ $N$ の数列 $a$ を決めて、各 $1 \le i \le N$ に対し、
> ・$a_i=1$ のときは長方形の $x<x_i$ をみたす領域
> ・$a_i=2$ のときは長方形の $x>x_i$ をみたす領域
> ・$a_i=3$ のときは長方形の $y<y_i$ をみたす領域
> ・$a_i=4$ のときは長方形の $y>y_i$ をみたす領域
> を黒く塗りました。
> 塗りつぶしが終わったあとの長方形内での白い部分の面積を求めてください。

## 制約
> ・$1 \le W, H \le 100$
> ・$1 \le N \le 100$
> ・$0 \le x_i \le W~(1 \le i \le N)$
> ・$0 \le y_i \le H~(1 \le i \le N)$
> ・$W,H$ (21:32 追記), $x_i,y_i$ は整数である
> ・$a_i~(1 \le i \le N)$ は $1,2,3,4$ のいずれかである

## 収録されている問題セット
- [AtCoder に登録したら次にやること](https://qiita.com/drken/items/fd4e5e3630d0f5859067) ([第07問類題](https://qiita.com/drken/items/fd4e5e3630d0f5859067#%E7%AC%AC-7-%E5%95%8F--abc-085-b---kagami-mochi-200-%E7%82%B9))

# 回答
## 回答1 (AC)
白い部分は常に長方形になるので、その 4 辺を xl (左の辺), yu (上の辺), xr (右の辺), yl (下の辺) という変数で位置を保持します。初期状態は xl=0, yu=h, xr=w, yl=0 です。

$a_i=1$ のとき、$x<x_i$ の部分は白く塗られるので、xl$<x_i$ ならば xl を $x_i$ で更新します。$a_i=2,3,4$ の場合も同様です。

最後に白い部分の面積を計算します。xl<xr かつ yl<yu のときは白い長方形が残っているので、その面積 (xr-xl)*(yu-yl) を出力して終了します。そうでない場合には白い部分はなくなっている(黒で塗りつぶされた)ので、面積 0 を出力します。

ここまでの処理をまとめると以下のコードになりました。

```C++:abc047b-1.cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
  int w, h, n;
  cin >> w >> h >> n;

  int x, y, a;
  int xl = 0, xr = w, yl = 0, yu = h;
  for ( int i=0; i<n; i++ ) {
    cin >> x >> y >> a;
    if ( a==1 ) {
      if ( xl<x ) {
        xl = x;
      }
    } else if ( a==2 ) {
      if ( x<xr ) {
        xr = x;
      }
    } else if ( a==3 ) {
      if (yl<y) {
        yl = y;
      }
    } else {
      if ( y<yu ) {
        yu = y;
      }
    }
  }
  if ( xr>xl && yu>yl ) {
    cout << (xr-xl)*(yu-yl) << endl;
  } else {
    cout << 0 << endl;
  }
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc047/tasks/abc047_b/editorial) → [公式解説](https://img.atcoder.jp/data/arc/063/editorial.pdf)
回答1と同じ方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0068 - ABC 213 B](https://qiita.com/RoadLynton/items/2f2e41ccbcfa65b29562)
MLOpsとは?

景気動向の高低に関わらず、ビジネスを推進に適したエンタープライズAI戦略を構築するには、戦略の転換や環境の変化に瞬時に対応すること、そのために、運用中のAIモデルを監視するシステムや、新しいAIモデルの導入、テスト、トレーニング、導入を迅速に行えることが重要です。それが MLOpsです。
![figure-climbing-ladder.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1196881/592ac77f-7466-bd63-7819-e8b1d4714d3e.jpeg)
[<font color="Blue"></font>*→ こちらより、O'Reillyの” Introducing MLOps”（英語）を無料ダウンロードいただけます。*</font>](https://pages.dataiku.com/oreilly-introducing-mlops)
<br>
##MLOpsとは?
モデルベースの機械学習とAIは、あらゆる大企業で急速にテクノロジーのメインストリームになってきています。そのベネフィットを最大限に享受するためには、モデルを本番環境に投入する必要がありますが、それを大規模に行うには新たな課題があります。機械学習モデルを本番環境で管理する上での基本的な課題は異なり、既存のDevOpsやDataOpsの専門知識だけでは十分ではありません。
そこで、機械学習のライフサイクル管理を標準化・効率化するMLOpsの出番となるわけです。これは、単にDevOpsのプラクティスを機械学習に適用するというだけではありません。実際には、機械学習のライフサイクルを大規模に管理することが困難である理由は3つあります。

1. **多くのことが依存しあっています。**すなわち、データが常に変化しているだけでなく、ビジネスニーズも変化しています。
2. **全員が同じ言語を話すわけではありません。**機械学習のライフサイクルには、ビジネスチーム、データサイエンスチーム、ITチームが関わっていますが、これらのグループが同じツールを使用しているわけではありませんし、そして多くの場合、同じ基本的なスキルを共有しているわけでもありません。
3. **(ほとんどの）データサイエンティストはソフトウェアエンジニアではありません。**多くのデータサイエンティストは、モデルの構築と評価を専門としており、必ずしもアプリケーションを作成する専門家ではありません。

##MLOpsを構築するためのケイパビリティー
堅牢な機械学習モデル管理プログラムは、以下のような質問に答えることを目的としています。:
- 本番用の機械学習モデルのパフォーマンスとメンテナンスに責任を持つのは誰か？
- 機械学習モデルは、モデルドリフト（モデルの性能低下）を考慮して、どのように更新されているのか、リフレッシュされているのか？
- モデルを開発・選択する際に、どのようなパフォーマンス指標を測定しているか、また、どの程度のパフォーマンスであれば、ビジネス部門に受け入れられるか？
 - モデルの劣化や、予期せぬ異常データや予測を検出するために、モデルはどのように長期的にモニタリングされているか？
 - モデルはどのように監査されているか、また、モデルを開発しているチーム以外の人にも説明できるか？

これらの質問は、機械学習モデルのライフサイクルの範囲にわたっており、その回答にはデータサイエンティストだけでなく、企業全体の人々が関わっています。すなわち、MLOpsが1つのチームや部門に限定されるものではないことを示しています。これらの質問に答えることは、任意のエクササイズではありません。データサイエンスと機械学習を企業レベルで効率的に拡大するだけでなく、ビジネスを危険にさらさない方法で行わなければなりません。

適切なMLOpsプラクティスを実施せずにデータサイエンスを展開しようとするチームは、とくに今日の予測不可能で前例のない、絶え間なく変化する環境においては、モデルの品質と継続性の問題に直面することになります。また、品質の低さよりも、MLOpsを実施していないチームは、ビジネスに実際に悪影響を与えるモデルを導入するリスクがあります（例：企業にネガティブな影響を与えるような偏った予測をするモデルなど）。
 
 
##MLOpsについて、詳細はこちら
MLOpsがもたらす課題、関係する人々、成功に必要な要素を包括的に理解するために、オライリーの最新のeBook「Introducing MLOps」を無料でダウンロードいただけます。
[<font color="LightSeaGreen"></font>**O'Reilly” Introducing MLOps”（英語）の無料ダウンロードはこちら**</font>](https://pages.dataiku.com/oreilly-introducing-mlops) 
 

原文：　[*What is MLOps?*](https://blog.dataiku.com/what-is-mlops-why-does-it-matter)
Power Automate でGitHubのリポジトリ(組織)を作成する

向井です。
Power AutomateのGitHubのアクション[「テンプレートを利用してリポジトリを作成する」](https://docs.microsoft.com/ja-jp/connectors/github/#%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B-(%E3%83%97%E3%83%AC%E3%83%93%E3%83%A5%E3%83%BC))を使う上で、つまずいた点を簡単にですがメモしておきます。


#やりたいこと
GitHubの個人アカウントで組織を作成しておき、その組織所有のリポジトリをPower Automateで作成する。

※CoE Starter Kit のALM Accelerator for Makersを使用したときにここの部分でエラーが出ていたためエラーを解消したい。

#つまづいた点
Power Automateを作成するときに所有者（Docs上は担当者となってます）に組織名を入力するとフロー実行時にエラーが出てリポジトリが作成されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/7f98c28d-93cb-f2d3-ba31-8fcdec8dddf5.png)
（エラーの詳細：The OAuth application is not authorized for access to tomom01kumukai.）

※所有者欄を空欄にすると問題なくリポジトリが作成される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/b6a6477c-a73d-b293-1518-2d498abec945.png)


#解決策
GitHubのThird-party access制限をオフにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/5a39f9f6-5d24-2bdf-4ee8-f4f09952bcc0.png)

これで解決しました！


#動作確認（おまけ）
Power Autemateの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/b0c63b06-f957-fedf-9e20-bd5b3fb13fa5.png)


GitHubに組織所有のリポジトリが作成された。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1004488/9be523ba-f1ad-f029-c30c-dc4e3c2eed75.png)
install(1) コマンドでディレクトリを作りつつファイルを配置する

[coreutils の install(1)](https://linuxjm.osdn.jp/html/gnumaniak/man1/install.1.html)はファイルコピー時のownerやmodeを設定できるだけでなく、ディレクトリの作成も一度に行ってくれます。

`hoge.conf` を `/etc/bar/` へ 0600 として配置する時には mkdir/cp/chmod と3つ行うことになりますが、install コマンドなら一発です。

カレントディレクトリの `hoge.conf` を `/etc/bar/` ディレクトリへ 0600 としてコピーする時にはこのようになります。この時 `/etc/bar/` が無ければ作成してく

```
$ sudo install -m 0600 -D -t /etc/bar/ hoge.conf
```

chown/chgrp相当も `-o` や `-g` で指定できます。詳しくは [install(1)](https://linuxjm.osdn.jp/html/gnumaniak/man1/install.1.html) をご覧ください。

### 注意点

ファイルのmodeやowner/groupは指定できますが、作成されるディレクトリは 0755 で固定です。(https://linuxjm.osdn.jp/info/GNU_coreutils/coreutils-ja_80.html)

## 比較内容

```console:mkdir/cp/chmodを使った場合
$ ls hoge.conf
hoge.conf

$ sudo mkdir -p /etc/bar/
$ sudo cp hoge.conf /etc/bar/
$ sudo chmod 600 /etc/bar/hoge.conf

$ ls -laF /etc/bar/
total 12
drwxr-xr-x   2 root root 4096 Aug 12 09:45 ./
drwxr-xr-x 118 root root 4096 Aug 12 09:45 ../
-rw-------   1 root root  484 Aug 12 09:45 hoge.conf
```

```console:installを使った場合
$ ls hoge.conf
hoge.conf

$ sudo install -m 0600 -D -t /etc/bar/ hoge.conf

$ ls -laF /etc/bar/
total 12
drwxr-xr-x   2 root root 4096 Aug 12 09:45 ./
drwxr-xr-x 118 root root 4096 Aug 12 09:45 ../
-rw-------   1 root root  484 Aug 12 09:45 hoge.conf
```

EoT
GitHub App の認証を Python でする場合

# はじめに

DocsにはRubyスクリプトが掲載されていたのですが、Pythonを利用したかったためそのサンプルです

## GitHub App による認証

https://docs.github.com/ja/developers/apps/building-github-apps/authenticating-with-github-apps

```ruby
require 'openssl'
require 'jwt'  # https://rubygems.org/gems/jwt

# Private key contents
private_pem = File.read(YOUR_PATH_TO_PEM)
private_key = OpenSSL::PKey::RSA.new(private_pem)

# Generate the JWT
payload = {
  # issued at time, 60 seconds in the past to allow for clock drift
  iat: Time.now.to_i - 60,
  # JWT expiration time (10 minute maximum)
  exp: Time.now.to_i + (10 * 60),
  # GitHub App's identifier
  iss: YOUR_APP_ID
}

jwt = JWT.encode(payload, private_key, "RS256")
puts jwt
```

GitHub App として認証するには、

- PEM フォーマットで秘密鍵を生成
- 秘密鍵を使用して JSON Web Token (JWT) に署名
- JWT を RS256 アルゴリズムを使用してエンコード


Pythonで取得するにあたって以下のパッケージを利用します。

- pyjwt
- cryptography

```sh
pip install pyjwt cryptography
```

```python
import jwt
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization

with open(YOUR_PATH_TO_PEM, 'r') as f:
    pem_bin = f.read().encode()

private_key = serialization.load_pem_private_key(pem_bin, None, default_backend())

unix_time_now = int(time.time())

payload = {
    # issued at time, 60 seconds in the past to allow for clock drift
    iat: unix_time_now - 60,
    # JWT expiration time (10 minute maximum)
    exp: unix_time_now + (10 * 60),
    # GitHub App's identifier
    iss: YOUR_APP_ID
}

jwt = jwt.encode(payload, private_key, algorithm='RS256')
```

掲載されているサンプルコマンドと同様にPythonから認証されたアプリの情報をAPIから取得します

```sh
$ curl -i -H "Authorization: Bearer YOUR_JWT" -H "Accept: application/vnd.github.v3+json" https://api.github.com/app
```

```python
import urllib.request

# jwt生成部分は冒頭スクリプト

headers = {
    "Authorization": f"Bearer {jwt}",
    "Accept": "application/vnd.github.v3+json"
}

url = 'https://api.github.com/app'
request = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(request) as response:
    content = response.read()
```