OmniAICreator/Qiita-1.07M huggingface dataset:
crond を実行する Docker コンテナを作成する

## ゴール

Amazon Linux 2 のイメージをベースに Supervisor 上で crond を実行する Docker コンテナを作成します。

この手順では、Amazon Linux 2 のイメージで Systemd を有効にするのではなく、フォアグラウンドで起動した crond を Supervisor で管理する戦略を採用します。

## 参考文書

* [How to install/run Cron in a Docker Container](https://gist.github.com/jdeathe/94d7b1681187a3a97c5cd4a7eee244f1). jdeathe. January 13, 2017.
* [martinrusev/cron_supervisord.ini](https://gist.github.com/martinrusev/7015e393d46647dbad15). martinrusev. January 9, 2015.
* [cron(8)](https://man7.org/linux/man-pages/man8/cron.8.html). The Linux Programming Interface. August 27, 2021.
* [Supervisor](http://supervisord.org/index.html). Agendaless Consulting and Contributors. February 06, 2022.

## 事前要件

この文書の手順は、次の環境で実施し、動作を確認しました。

* MacBook Air (M1, 2020)
* macOS Monterey 12.1
* Docker Desktop 4.4.2

## 手順

この手順は、最終的に次の構造のプロダクトを作成します。

```bash
ROOT
+-- Dockerfile
+-- cron
|   +-- root.conf
+-- supervisord.conf 
```

crond の動作確認で使用する cron の設定ファイル `root.conf` を作成します。

```conf:cron/root.conf
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=""

* * * * * /usr/bin/date >>/tmp/crontest.txt
```

root ユーザーが 1 分間隔で `date` コマンドの実行結果を `/tmp/crontest.txt` へ書き出すジョブを構成します。

Supervisor と Supervisor 上での cron の実行を制御する Supervisor の設定ファイル `supervisord.conf` を作成します。

```conf:supervisord.conf
[supervisord]
nodaemon=true
loglevel=info

[program:cron]
command=crond -n -m off -x sch
autostart=true
autorestart=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
```

Supervisor と crond をフォアグラウンドで実行するため、`supervisord.nodaemon` パラメーターは、必ず `true` に設定します。

`program:cron.command` パラメーターで指定する crond のオプションの意味は、次の通りです。

* `-n` - crond をフォアグラウンドで実行します。
* `-m off` - ジョブ実行時にメールを送信しないようにします。メールを送信したい場合、sendmail のようなメール送信プログラムのインストールが必要です。
* `-x sch` - ジョブスケジュールに関するデバック情報を出力します。

Supervisor の実行時に crond を自動で起動、再起動するため、`program:cron.autostart` と `program:cron.autorestart` パラメーターは、必ず `true` に設定します。

`stdout` と `stderr` で始まるログファイルに関するパラメーターは、Docker コンテナの起動後に crond のログを標準出力、標準エラー出力へリダイレクトするために設定しています。

Dockerfile を作成します。

```dockerfile:Dockerfile
FROM amazonlinux:2

RUN yum install -y cronie-noanacron
RUN sed -i -e '/pam_loginuid.so/s/^/#/' /etc/pam.d/crond
COPY cron/root.conf /var/local/cron/
RUN crontab /var/local/cron/root.conf

RUN yum install -y python3 && pip3 install supervisor
COPY supervisord.conf /etc/supervisord.conf

CMD ["/usr/local/bin/supervisord"]
```

crond をフォアグラウンドで実行する場合、crond で `pam_loginuid.so` モジュールを無効にする必要があるため、`sed -i -e '/pam_loginuid.so/s/^/#/' /etc/pam.d/crond` を実行しています。

```bash
docker build --rm -t cron-linux .
docker run --rm -it cron-linux /usr/local/bin/supervisord
```
「Kernel driver not installed(rc=-1908)」が発生しMacBookでVisualVox上Linnux(Ubuntu)がインストールできない時の解決方法

#「Kernel driver not installed(rc=-1908)」が発生しMacBookでVisualVox上Linnux(Ubuntu)がインストールできない時の解決方法

#目次
[1.はじめに](#1-はじめに)
[2.結論](#2-結論)
[3.詳細](#3-詳細)
[4.最後に](#4-最後に)

#1. はじめに
今回MacBookPro（Intel版）にて仮想環境上でLinux環境（ubunutu）を構築しようとした歳に「Kernel driver not installed(rc=-1908)」のエラーが出て、構築できなかったので、その際に解決した時の備忘録として記載しております。

#2. 結論
結論から言うと、私の環境ではVisualBoxをインストール後に設定のセキュリティとプライバシーのところにある「開発元"Oracle America, inc."のシステムソフトウェアの読み込みがブロックされました。」を許可にすることで解決して。

#3. 詳細
今回の「Kernel driver not installed(rc=-1908)」エラーがでた際にググったところ、VisualBoxをインストール後に設定のセキュリティとプライバシーのところにある「開発元"Oracle America, inc."のシステムソフトウェアの読み込みがブロックされました。」を許可にすることで解決するとの記事がありました。

しかし、実際に確認しても、そのような文面はなかったため、更に調べたところ、インストール後の30分間だけその「開発元"Oracle America, inc."のシステムソフトウェアの読み込みがブロックされました。」が表示されているとの記載があった。

そのため、再インストールを行い確認したところ、実際に「開発元"Oracle America, inc."のシステムソフトウェアの読み込みがブロックされました。」の記載が確認でき、許可をしたところ、Linux（ubunutu）んの起動に成功した。

#4. 最後に
WindowsからMacに乗り換えたのですが、そのような許可が必要だったとは・・・
まだまだMacに慣れていないが、操作を覚えながら学習していきます。
Proc Logisticの使い方

SASあるあるで日本語記事が少なく、英語記事は毎回探して読むのが面倒なのでまとめます。
誤り等ありましたらご指摘をお願いいたします。

##基本
```
proc logistic data = ;
    model y = x ;
run;
```

##詳細
```
PROC LOGISTIC < options >;
    BY variables ;
    CLASS variable <(v-options)> <variable <(v-options)>... > < / v-options >;
    CONTRAST ’label’ effect values <,... effect values>< =options >;
    FREQ variable ;
    MODEL response = < effects >< / options >;
    MODEL events/trials = < effects >< / options >;
    OUTPUT < OUT=SAS-data-set > < keyword=name:::keyword=name > / < option >;
    < label: > TEST equation1 < , ::: , < equationk >>< /option >;
    UNITS independent1 = list1 < ::: independentk = listk >< /option > ;
    WEIGHT variable </ option >;
RUN;
```

###classステートメント
自動的に説明変数のダミー変数を生成。（＝数量値は指定しなくてOK）
CLASSステートメントで PARAM=オプションを指定することでダミー変数の生成方法を指定できる。
PARAMオプションにはREF, EFFECT, GLM等色々あるので参考文献参照。

```
proc logistic data = Neuralgia ;
 class Treatment Sex / param=effect ;
 model Pain = Treatment Sex ;
run;
```


###modelステートメント
####モデルの推定結果の出力
上から順に、2値、2値（逆）、名義
※modelステートメントは一回のプロシジャ実行に付き一つしか記述できません。
下のコードは例であり、このままだとエラーになります。

```
model y(event='1') = <your model effects>;
model y(order=data) = <your model effects>;
model y(order=data descending) = <your model effects>;
model y(ref='1') = <your model effects>;
```

####Stepwise法

```
model remiss(event='1')=cell smear infil li blast temp
                / selection=stepwise
                  slentry=0.3
                  slstay=0.35
                  details
                  lackfit;
```
変数をモデルに入れるには0.3の有意水準が必要で (SLENTRY=0.3)、変数がモデルに残るには0.35の有意水準が必要です (SLSTAY=0.35)。slentryはselection entryの略だろうか。
変数選択プロセスの詳細な説明は、DETAILS オプションを指定することで要求されます。最終的に選択されたモデルのHosmer and Lemeshow適合度検定は、LACKFITオプションを指定することによって要求されます。

###estimateステートメント
工事中

###strataステートメント
工事中


###byステートメント
byで指定するとその変数ごとにそれぞれ回帰する。

###予測

```
*やり方1;
OUTPUT OUT=out P=predict;

*やり方2;
/* 推定したモデルの情報をデータセットMODELに出力 */
   PROC LOGISTIC DATA=A OUTMODEL=model;
     MODEL <モデル式の記述>;
   RUN;
/* データセットBに対する予測値を算出 */
   PROC LOGISTIC INMODEL=model;
     SCORE DATA=B OUT=out;
   RUN;
```

##参考文献
公式マニュアル（英語）: https://www.math.wpi.edu/saspdf/stat/chap39.pdf
https://www.sas.com/offices/asiapacific/japan/service/technical/faq/list/body/stat089.html
https://www.sas.com/offices/asiapacific/japan/service/technical/faq/list/body/stat083.html
https://www.yukms.com/biostat/takahasi/rec/archive/semi22.pdf
class:https://www.sas.com/content/dam/SAS/ja_jp/doc/event/sas-user-groups/usergroups14-a-03.pdf
Stepwise法: https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.4/statug/statug_logistic_examples01.htm
参考: https://www.croit.com/wp_croit2/wp-content/uploads/2018/12/04_01.pdf
【LeetCode】#80 Remove Duplicates from Sorted Array II

##LeetCode #80 ソートされた配列の重複要素を削除

###問題文

昇順の整数配列が与えられ、
配列の中に、同じ要素が2回以上表示されたら、その残りの要素を削除します。
要素の相対的な順序を保つ必要があります。
最後に、重複要素を削除した配列の長さを返します。

###DoublePointerで解く
まず、チェック用のファストポインタと止め用のスローポインタを用意します。
この問題では、要素が2回以上表示されたらアウトのため、ファストポインタとスローポインタはインデックス2の所に初期化して、そこから、どんどん比べていきます。


ファストポインタの数字と、スローポインタより二つ前と一つ前の数字を比べて、
2回以上表示されていないなら、ファストポインタの数字はこの配列の中に2回以上重複していないと証明できます。
逆に言うと、スローポインタより二つ前と一つ前の数字と比べて、何れも同じなら、ファストポインタの数字は3回以上表した数字なので、重複していない数字が表すまでに、止め用のスローポインタはそのまま移動させません。

ファストポインタが配列の最後まで移動したら、配列を既にチェック済みとのことで、スローポインタのインデックス番号をプラス1にしたら、重複していない配列の長さとなります。

###JavaScript Code
```javascript

var removeDuplicates = function(nums) {
    if(nums.length<=2) return nums.length
    
    let fast=2;
    let slow=2;
    while(fast<nums.length){
        if(nums[fast]!==nums[slow-1] || nums[fast]!==nums[slow-2]){
            nums[slow]=nums[fast]
            slow++
            fast++
        }else if(nums[fast]==nums[slow-1] && nums[fast]==nums[slow-2]){
            fast++
        }
    }
    
    return slow
    
};

```

###図解

youtube：
https://www.youtube.com/watch?v=RBM0WCXvu1Y&t=10s

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/161283de-3cb6-88bc-ee68-d3bcd55076b8.png)

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/f45deed9-c9f1-257d-cf95-80dd925cbac9.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/e38d0351-0b70-ec41-a7ea-30186b903ee9.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/5b32b9db-bea4-af49-98b2-e9e56cc9c899.png)
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/d71aa844-75e7-f0ff-8fc0-7751e8f3fa1d.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/bdfbbeed-aff3-2a17-c8ad-7be0b46f9532.png)
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/5f88f0c4-c4eb-eee8-1c06-61462b2675f9.png)
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/8f2d54bd-af92-b67d-c455-b13bc40bd6ec.png)
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/a5ae4ced-2d7e-237b-e652-3acf48e95f96.png)
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/29cc1cc5-83b6-8cb2-aed4-09be03347217.png)
![11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/d303a925-ebde-80bb-7aa8-025b736d1590.png)
![12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/23548269-3534-66db-3a7d-04f6c4d70906.png)
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/312c2e4f-088e-bb55-7628-ad4e04178639.png)
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/646cf6d7-57d9-4554-400c-b26e572cc093.png)
![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/31429387-ba39-111b-6cd9-185e39dff04d.png)
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/5e1afea9-80d7-47ce-c025-9b7b331977f5.png)
![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1082021/c9a1dd16-3cdc-4596-d0e0-b9c355291edb.png)
【AWS】ターゲットグループでEC2のヘルスチェックが失敗した

ターゲットグループで、EC2インスタンスのヘルスチェックが失敗していた。

## 試したけどダメだったこと

- Apacheの再起動
- EC2インスタンスを再起動
- Elastic IPの関連付けを解除
- 再度Elastic IPを関連付ける

などなど。ちなみにElastic IPを解除した直後数分のみヘルスチェックが成功していた。

## 解決方法

1. (学習用のため)EC2インスタンスに設定していたドメインを解除
2. EC2インスタンスにドメインを再設定
3. Apacheを再起動
ＧＡＮを英語でスラっと言うには

はっきり言ってＧＡＮを英語でスラっと言うのは、かなり苦しいと思う。

https://youtu.be/HGYYEUSm-0Q

#発音法

これを１０回言えば、何とか口が覚えるでしょう・・・

**Generative 　adversarial 　networks**

* **ジェネレーティブ　アドバシリアル　ネットワーク**
* **じぇな　リブ　あどば　セリア　ネット　沸く**
* **銭やで　　網走や　　熱とは？**  --> 　　　読み方は　「　ぜにやで　あばしりや　ねつとは　」
【UiPath バージョンアップされたことにより使用できないアクティビティの対処法について】

こんにちは。
入社2年目文系出身のエンジニアです。
UiPathを1年ぶりに触りました。
前の案件でよく使用していたのですが、
やはり全然触らなかったのか、
UiPathもバージョンがかなり上がっておりました。
アクティビティが新たに追加・修正されていました。
前まで存在していたアクティビティがバージョンアップされたことで、
使えなくなったり(というか表示されていない！？)していて困っていましたが、
復元方法をネットの記事を見て無事解決したので、
皆さんにも共有＋私の記憶定着のためにもと思い、
今回記事を書くことにしました。

### そもそもUiPathってなんやねん
開発言語一切不要で、簡単に画面上のロボットを動かせる仕組みになっています。
RPA業界のツールみたいなものです。
初心者でも気軽に利用することができます。
詳しいことは、後日記事にして書こうと思います。

### 私が困っていたこと
UiPathでは、様々なアクティビティが用意されており、
画面のように、シーケンスの中にアクティビティを配置することにより、
1つずつ画面を動かせるようになっています。
その画面を動かせる材料の一種である「ブラウザーを開く」というアクティビティがなかったのです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/86d08050-383c-e35f-0ae7-f6caa206b5e9.png)
拡大してみると、
![キャプチャ (2)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/541149ea-9393-95f6-57a5-4517ec412372.jpeg)
どうやらバージョンアップ後、「アプリケーション/ブラウザーを使用」という
アクティビティが新たに追加されていました。
使用してみようにも、使い方が分からない。。どうしようと頭を抱えました💦

私が現在使用しているのは、2021.10.4のバージョンです。
案件で使用していた時のバージョンは、確か2019.10.1でした。

どうしても「ブラウザーを開く」というアクティビティを使用したかったので、
調べてみると、記事を発見し無事解決することができました。

### 解決法
①赤矢印で書かれているプロジェクトパネルをクリックし、
作成したプロジェクトを右クリックする。
→黄色マーカーで記されているプロジェクト設定をクリック。
![キャプチャ(3)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/f3708437-02bd-80d3-119d-63d529fccb98.jpeg)
②プロジェクト設定を開き、黄色マーカーで記されているモダンデザインエクスペリエンスを「はい」から「いいえ」に変更し、ＯＫボタンをクリック。
![キャプチャ(4).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/6c73703e-0ed4-49fb-a131-b19bcf001f0d.png)
③「モダンデザインエクスペリエンスが変更されました。変更を適用するにはプロジェクトを再読み込みしてください」とモーダル画面が表示されるので、再読み込みボタンをクリックする。
![キャプチャ(5).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/a9f01031-da50-85d8-9378-15b6e930e9cf.png)
④アクティビティパネルに戻り、ブラウザーを検索する。
![キャプチャ(6).PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/a937862e-dcd7-14a4-bc5f-711512f1c43d.png)
拡大してみると、
![キャプチャ(7)_LI.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666359/343af2f1-1fc9-ff06-249b-e7a5b3a2b687.jpeg)
無事、「ブラウザーを開く」が使用できるようになりました。

### モダンデザインエクスペリエンスとはなんぞや
調べてみるとモダンデザインエクスペリエンスは、
どうやら20.10バージョンから使用できるようになっており、
オブジェクト認識を行う際、認識方法やUIが変化したものだそうです。
セレクターや画像の複数の認識情報を用いて、認識できるような機能らしいです。
使いこなせたら、精度の高いロボットが製造できるようになるかもしれないですね。
私自身、そこまでのレベルに到達するまで時間かかりそうです。。笑
今後、使えるようになったらまた共有していきたいです。

###最後に
ここまで読んでくださり、ありがとうございました。
久々にUiPathを使用する時、以前のアクティビティが使用できなくなった際、
ぜひ役立ててもらえたらと思います。

###参考URL
https://forum.uipath.com/t/topic/320946/5

https://docs.uipath.com/studio/lang-ja/docs/modern-design-experience
【機械学習初心者】新型コロナウイルス第6波の予測を検証してみた

#はじめに
　[前回の記事](https://qiita.com/JonnyBellwood/items/7921968267017cab06d8)で予測したモデルをもとに検証を行います。

#前提条件
環境、ファイル構成、必要モジュール、作成したプログラムは[前回の記事](https://qiita.com/JonnyBellwood/items/7921968267017cab06d8)を参照ください。

#結果
　前回出した予測値(1月31日まで)と最新(2月5日まで)のデータ[「情報:NHKまとめ」](https://www3.nhk.or.jp/news/special/coronavirus/data-all/)を比較して、予測の精度を検証したいと思います。

　出力すると以下のような結果が得られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626498/5c8ccdd1-3119-e9a1-8cab-9a60499a0b70.png)

#まとめ
　全く予測が当たってないことが一目瞭然にわかります。(あたるなんて思ってませんでしたが)
意外だったのが第3波、第4波よりは落ち着く予測でしたが、直近の数字が跳ね上がっているのがわかります。
オミクロン株は重症化しにくいと言われていた中でこの結果だったので少々驚きました。
まだまだウイルスとの闘いは続いていきそうです。
「成功」は、完璧な手法や状態でしか行き着けない訳ではない（アジャイルと失敗は共存する）

# １．「成功」の連続なんてあり得ない

　よくマネージメントの失敗談とそれをベースにした、改善策が語られます。その事自体は何も問題ないと思います。そうして問題を修正していくのが通常だと思います。

　たとえば、ウォーターフォールではなく、アジャイルでやろう。また、アジャイルでも、こういうケースはだめだから、こうしたほうが良いと。

　では、そこで得られた「うまくいく方法」をしたら、すぐに成功の連続が起こるでしょうか？
　実際、そんなにきれいに物事が運びますか？

# ２．「失敗しないアジャイル」という"表現"はおかしい

　日本人に多いのかもしれないですが、「完璧」でないと物事を進められないというのは、仕事ではあんまりよいことではないと思います。
実際、物事は思い通りにならないし、途中で調整もします。

　アジャイルとは失敗しそうな状況を調整するための「掛け声、視点」の集大成だと思います。
思い通り、計画通りになんてなかなかいかない。だからこそ、「Agile（機敏・臨機応変）」に対応する。

　でも、アジャイルを使っていてさえ、失敗が起きると、「アジャイルではないから、失敗が起きている」と言われることもあります。
そもそも、アジャイルとは失敗しないことではなく、失敗があっても調整することな気がします。

 「失敗するアジャイル」という考え方が自体が間違っている気もします。失敗してるから、調整することこそ、「アジャイル」だと思います。


# ３．「ゴールとしての成功」に行き着くまでに「失敗」はいろいろある

　いろいろなプロジェクトに参加していると、「私はプロジェクトを成功に導くことができる」という人がいます。そういう人もいるでしょう。
でも、だからといって、その過程すべてが成功の連続ではない気がします。

　私も失敗も成功もしたことはあります。特に、成功したプロジェクトですら、失敗がなかったかといえば、そんなことはありません。
ゴールに行くまでにいくらでも失敗しました。その都度、早めに失敗に気付き対策を立てました。
　そして、結果的に成功を手にしたように思います。

　「成功」とは、成功の連続ではないと思います。そして、それを調整する指標、掛け声が「アジャイル」というものではないでしょうか。


# ４．完璧主義者こそ失敗を招きかねない

　完璧主義者は、プロジェクトの最初から、失敗がみえると喚き散らします。もちろん、それは調整できるものであれば、調整すべきでしょう。
でも、昨今のソフトウェア業界では、人それぞれプロジェクトそのものに専念できない事情もあります。つまり、いろいろ立場や状況によって、失敗してしまうこともあります。
　それをつかまえて、「失敗する！！！」とわめいて、あるべき論をかざしてチームを撹乱しても意味がありません。
　人それぞれ、「理想的な状況」ではない人もいます。それすらも受け入れて、調整し、みんなが支えるのが「アジャイル」ではないでしょうか？

　完璧主義はいいことだと思いますが、それをどう実現するかが問題だと思います。人それぞれの状況を配慮し、そこに即した対処方法をしていかないと、チームメンバーの生産性が下がるばかりです。コミュニケーションが大切なのに、完璧主義をかざして喚いていると、コミュニケーションが取りにくくなります。
　
　仮にあるプロジェクトがなんとか成功しても、そのチームから離脱する人がでるという、もっと大きな意味での「失敗」を引き起こしかねません。　

# ５．「最終的な成功」のために、過程の失敗は喚くことではない

　繰り返しになりますが、結果的な成功に至るまでに、いろいろな失敗はあります。そして、都度調整は必要です。
また、人によっては、理想的な状況になれない人もいます。だからこそ、一見、ムダや失敗と見られるような状況でも、受け入れざるを得ない状況があります。

　「完璧主義」を最初からゴールまで貫徹する考えこそ、「アジャイル」に反するものだと私は思います。

　そして、過程による失敗はつきものです。それをチーム全体で「機動的」、「早い段階」で修正することこそ、アジャイルな動きだと思います。


# ６．塗り重ね、支え合い、最終的な成功

　過程はいろいろあるのがプロジェクトです。アジャイルは、ウォーターフォールのような「決められたプロセス」を提供するものではありません。個々の状況に応じたものを受けて、早めに調整が利くように促す「掛け声、視点」の集大成だと思っています。

　なので、過程で失敗が起きたからと言ってそれは即失敗ではないと思います。失敗だと思えるなら、みんなで意識共有をして、みんなの状況に合わせて修正していくべきな気がします。

　そうした、いろいろな対応の「塗り重ね」と「支え合い」の結果がとして、「成功」があるのではないでしょうか？

　
# 備考：「手続き主義・教条主義」をアジャイルに持ち込むことは本質からずれている

　アジャイルというか、スクラム開発ではある決まったやり方があります。それを実行することで早めに物事を明確に把握していくことができたり、色々とメリットはあります。

　ただ、「アジャイル」がそうした「手続きをすること」だと思っている現場があったりします。これは形式だけをみて、その本質をみていない感じがいつもします。その手続ですら状況によってはできないこともあります。そうしたときに、目的が何かを認識したうえで、臨機応変に調整して動くことこそ、アジャイルの本質な気がします。

　また逆に、スクラム開発の手法をすればアジャイルであり、物ごとが成功するのかというとそうでもありません。いくらスプリントを細かくわけてタスクを見積もり、こなそうと、コミュニケーションがなかったり、問題に早く気付け無いような状況では結局、無駄なことをスクラム開発の手法で流しているだけということにもなりかねません。

　もちろん、こうした失敗に気づいて修正していけばいいと思いますが、本質からずれているマネージメントをしていると、そこに気付きにくいことがあります。そして、短絡的に「アジャイルはだめだ」ということになりかねません。

　「アジャイル」で語られるものはやや曖昧な事が多く、なかなか実践するのは難しいようにも見えます。ですが、一つ言えるのは、「決められた手続きをいかなる時も実行すること」でないことは確かです。

　失敗はつきもの、臨機応変に動く。コミュニケーションをして、そうした問題に早く気付き、対応をすること。この失敗と変化を積極的に受け入れて、絶えず変化していくことこそ、アジャイルな状態だと個人的には思います。

　また、もっといえば、「アジャイル」、「スクラム」、「ウォーターフォール」などどのような手法を採用しようと、プロジェクト遂行をする本質は変わらないと思います。「アジャイル」はすべての手法の根底にあるべき考え方な気もしています。
Amazon AppStream 2.0 をネイティブアプリケーションモードで動かしてみた

# はじめに

[前回の記事](https://qiita.com/sugimount-a/items/dbfb9dbd5f60147c61b4)では、Amazon AppStream 2.0 の Workshop を行い、基本的なアプリケーションを操作する内容を確認しました。

今回は、Amazon AppStream 2.0 の専用クライアントをつかって、ネイティブアプリケーションモードで動かしてみようと思います。

ネイティブアプリケーションモードは、2020年2月に追加された機能で、ストリーム配信されているアプリケーションが、あたかもローカルで動かしているような感覚で操作できる機能です。従来の機能では、アプリケーション内の画面転送でしたが、よりスムーズに違和感がなくリモートアプリケーションを利用するための機能です。

今回の記事は、ネイティブアプリケーションモードを試してみる内容です。



# ネイティブアプリケーションモードを動かす

AppStream 2.0 の専用クライアントを稼働して、Start in native application mode のチェックをオンにして、接続を行います。

![image-20220206170625914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/d39647f2-e24e-cf4e-bbf1-88762b2ee2f7.png)



メールアドレスとパスワードを入れてログインをします。

![image-20220206170729519.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/357ec5b9-54fb-a9d1-6e4a-8c91db709f9a.png)



notepad ++ のアプリケーションを選択します。

![image-20220206170758197.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/2957ac84-f2df-04bc-bffd-3efccbdbb3ff.png)



Fleet を On-demand で構成しており、起動まで1~2分ほど待機します。

![image-20220206170825918.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/da771b20-0fc6-ff55-3465-4120eb3a3fd6.png)



ローカル側で動かしているアプリケーションと同じように、ウィンドウ画面が立ち上がりました。

![image-20220206171247208.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/372efd40-9317-8c58-9b06-51a047cb013e.png)



実態は画面を転送している形になるので、作成したファイルを保存しようとしたときの保存先は、リモート先の Windows 環境となります。AppStream 2.0 には、ローカルドライブをリモート環境に接続する機能もあるため、ローカル環境のファイルをそのまま扱えます。(もちろんネットワーク越しなので、多少のタイムラグは発生します。)

![image-20220206171431152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5c5aaa06-3a7c-8029-9093-aec7a3eee7ad.png)



接続したローカルドライブに保存すると、想定どおり、ローカル側にファイルが生成されます。あたかもローカルで動かしているような操作感で良い体験です。

![image-20220206171622485.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/b6392569-7175-2299-5453-5729bd329e1c.png)
Python read(), readline(), readlines()の違い

１．read()・・・readメソッドは開いたファイル全体を文字列として取得する。\nは含む

読み込んだファイルで文字数制限を付ける
例：read(5)　とすると、読み込んだファイルから5文字読み込む


２．readline()・・・そのまま実行すると、ファイルを１行だけ読み込む。


３．readlines()・・・ファイル全体を行ごとに分割したリストとして取得できる。


参照：https://qiita.com/kaonashikun/items/e670318803748b71f1e9
EC2インスタンスの通信状態をpingコマンドで調べる。セキュリティグループでインバウンドルールの設定が必要。

EC2インスタンスの通信状態を`ping`コマンドで調べたところ、タイムアウトになった。

![ping.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/2ce914d0-7ec8-d3ed-8544-9fd2a644f40d.jpeg)

ブラウザからアクセスすることはできる。

# 解決方法

セキュリティグループのインバウンドルールで下記の設定をして、pingコマンドによる通信を許可する。

- タイプ 全てのICPM-IPv4
- リソースタイプAnywhere-IPv4
- ソース 0.0.0.0/0

![inbound.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/96a9abca-5347-6a67-add2-fdba636bd8e2.jpeg)

結果

![pingok.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/d10d29be-6491-d8d9-2d32-1878dbacc616.jpeg)

pingコマンドで通信できた。


参考: [[AWS] EC2インスタンスをpingで確認できるようにする](https://a1-style.net/tips-aws-ec2-add-ping-icmp-to-inbound-rules/)
Huggingface Transformersによる日本語GPT-2モデルのrinnaを利用した推論の例

# Huggingface Transformersによる日本語GPT-2モデルのrinnaを利用した推論の例

## TL;DR

[Huggingface Transformers](https://huggingface.co/)により、日本語GPT-2モデルである[rinnaの公開モデル](https://huggingface.co/rinna/japanese-gpt2-medium)で以下の推論を行う場合のサンプルです。

* Zero-shot Learning
* Few-shot Learning
* 文書生成

## モジュールのインストール

```python
# Huggingface Transformersのインストール
!pip install transformers==4.4.2
# Sentencepieceのインストール
!pip install sentencepiece==0.1.91
```

## Modelのロード

```python
from transformers import T5Tokenizer, AutoModelForCausalLM

tokenizer = T5Tokenizer.from_pretrained('rinna/japanese-gpt2-medium')
tokenizer.do_lower_case = True  # due to some bug of tokenizer config loading

model = AutoModelForCausalLM.from_pretrained('rinna/japanese-gpt2-medium')
```

## Zero-shot Learning

```python
original_text = '''全身がだるい ='''

input = tokenizer.encode(original_text, return_tensors='pt')
output = model.generate(input, do_sample=False, max_length=60, num_return_sequences=1)
generated = tokenizer.batch_decode(output, skip_special_tokens=True)

predict_part = generated[0][(len(original_text.strip())):]
predict_part = predict_part[:predict_part.find(' ')]
print(original_text.strip() + ' ' + predict_part)
```

```
全身がだるい = 疲れている
```

```python
original_text = '''病名:
全身がだるい =
'''

input = tokenizer.encode(original_text, return_tensors='pt')
output = model.generate(input, do_sample=False, max_length=60, num_return_sequences=1)
generated = tokenizer.batch_decode(output, skip_special_tokens=True)

predict_part = generated[0][(len(original_text.strip())):]
predict_part = predict_part[:predict_part.find(' ')]
print(original_text.strip() + ' ' + predict_part)
```

```
病名:
全身がだるい = 風邪
```

## Few-shot Learning

```python
original_text = '''病名:
熱がある = 発熱
熱が高い = 高熱
風邪を引いた = 感冒
全身がだるい =
'''

input = tokenizer.encode(original_text, return_tensors='pt')
output = model.generate(input, do_sample=False, max_length=60, num_return_sequences=1)
generated = tokenizer.batch_decode(output, skip_special_tokens=True)

predict_part = generated[0][(len(original_text.strip())):]
predict_part = predict_part[:predict_part.find(' ')]
print(original_text.strip() + ' ' + predict_part)
```

```
病名:
熱がある = 発熱
熱が高い = 高熱
風邪を引いた = 感冒
全身がだるい = 倦怠感
```

## 文書生成

```python
original_text = '''本日はお日柄も良く、'''

input = tokenizer.encode(original_text, return_tensors='pt')
output = model.generate(input, do_sample=True, max_length=100, num_return_sequences=1, truncation=True)
generated = tokenizer.batch_decode(output, skip_special_tokens=True)

predict_part = generated[0][(len(original_text.strip())):]
print(original_text.strip() + ' ' + predict_part[0:predict_part.find('。')] + '。')
```

```
本日はお日柄も良く、 朝からたくさんの方にお越しいただき、 幸せいっぱいのオープンから無事に終了致しました。
```
ubuntu20.04でyqコマンドを使う

## yqコマンドについて

yq は YAML を操作できるコマンドラインツール
> 出典：[https://github.com/mikefarah/yq](https://github.com/mikefarah/yq)

install
> [https://github.com/mikefarah/yq/#install](https://github.com/mikefarah/yq/#install)
> [Install yq on Ubuntu 20.04](https://lindevs.com/install-yq-on-ubuntu/)

```
curl -LJO https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
sudo mv yq_linux_amd64 /usr/local/bin/yq
sudo chmod a+x /usr/local/bin/yq
```

```
$ yq --version
yq (https://github.com/mikefarah/yq/) version 4.19.1
```

## 使い方

以下のようなyamlファイルがあったとする

```yaml:file.yaml
a:
  b:
    - c: cool
x:
  y:
    z: foobar
person:
  name: ""
```

以下のように値にアクセスする

```bash
$ yq . file.yaml
a:
  b:
    - c: cool
x:
  y:
    z: foobar
person:
  name: ""
```

```bash
$ yq .a.b[0].c file.yaml
cool
$ yq .x.y.z file.yaml
foobar
```

以下のように値を更新する

```
$ yq -i '.a.b[0].c = "super_cool"' file.yaml
$ yq . file.yaml
a:
  b:
    - c: super_cool
x:
  y:
    z: foobar
person:
  name: ""
$ yq .a.b[0].c file.yaml
super_cool
```

シェルスクリプト化する場合は`""ダブルクオーテーション`でくくる

```sh:test.sh
STR="so_much_coool"
yq -i ".a.b[0].c = \"${STR}\"" file.yaml

echo "---"
yq '.a.b[0].c' file.yaml
```

```
$ bash test.sh
---
so_much_coool
```

# error `Error: Parsing expression: Lexer error: could not match text starting at 1:1 failing at 1:3.`

使い方が間違っているのでチュートリアルページを見てやりたいことをみなおす

```
Error: Parsing expression: Lexer error: could not match text starting at 1:1 failing at 1:3.
	unmatched text: "wr"
```

> [https://github.com/mikefarah/yq/issues/607](https://github.com/mikefarah/yq/issues/607)


# 参考
[https://github.com/mikefarah/yq](https://github.com/mikefarah/yq)
[Install yq on Ubuntu 20.04](https://lindevs.com/install-yq-on-ubuntu/)
[https://mikefarah.gitbook.io/yq/](https://mikefarah.gitbook.io/yq/)
IPアドレスを固定する（Elastic IPアドレスの設定）

##前提
EC2のパブリックIPアドレスはインスタンスを停止、再起動すると動的に変更される。
そこで、IPアドレスを固定するためにElastic IPアドレスを設定する。
##設定方法
マネジメントコンソール＞EC2＞Elastic IP
画面右上の【Elastic IP アドレスを割り当てる】を押下する。
![スクリーンショット 2022-02-06 16.40.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522959/b45498cd-bac6-952a-f87c-9267ceec2b96.png)
（今回は特に設定を変更せず）右下の【割り当て】を押下する。
![スクリーンショット 2022-02-06 16.45.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522959/360b7edb-a8ba-842a-8b27-10b2c6fc4a8d.png)
Elastic IPアドレス自体の作成は完了。
次に、既存のインスタンスに作成したElastic IPアドレスを設定する。
作成したElastic IPアドレスを選択して、
右上の【この Elastic IP アドレスを関連付ける】を押下する。
![スクリーンショット 2022-02-06 16.48.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2522959/0e530458-c4d8-da6f-7568-605d5a8a99eb.png)
リソースタイプ：【インスタンス】
インスタンス：【割り当てたいインスタンス】
プライベートIPアドレス：【割り当てたいインスタンスのプラベートIPアドレス】
全て選択後、【関連付ける】を押下する。
以上で設定完了。
##注意
Elastic IPアドレスはインスタンスに割り当てられていない状態だと料金が発生する。
Elastic IPアドレスが紐づいてない時やインスタンスを停止した際は、
Elastic IPアドレスを解放することを忘れないようにしましょう。
【M1 Mac】fish shellをデフォルトシェルに設定する

買いたてほやほやのMacbook Air（M1）の環境構築中にfish shellのインストールまわりでつまずいたので、備忘録として手順＆つまずきポイントを残しておきます！

会社のエンジニアさんに教えてもらってから、使いやすくて愛用しているfish shell↓

https://github.com/fish-shell/fish-shell


# 私の環境
PC：Macbook Air（M1/Apple silicon）
普段使っているターミナル：iTerm2
普段使っているエディタ：Visual Studio Code

# つまずきによる学び
:::note warn
Apple siliconでHomebrewを使ったインストールをする際は、インストール先が従来と異なることがあるらしい
:::
参考：[M1 Macでfishをデフォルトシェルにするときはパスに気をつけよう](https://zenn.dev/meihei/articles/390d6dbbb4c936)

# fishをデフォルトシェルに設定する手順【M1 Mac版】
## 手順１：fishをインストール
今回はHomebrewを使ってインストールしました。

```terminal
brew install fish
```
これが完了した時点で、VScodeではターミナルでfishが選択すれば使用できるようになりました。
起動時にデフォルトシェルとしてfishを設定したいので、作業を続けます。

## 手順２：デフォルトシェルにfishを指定
下記コードを実行すると、次回起動時からiTerm2・VScodeのターミナルともにfishがデフォルトシェルで起動されるようになりました。

```terminal
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fish
```

# おまけ：道中にぶつかったポイント集
### 参照先のパスが違う
公式や紹介記事等で説明されているのは↓ですが、Apple siliconはこのパスが違ったようです。
![Screen Shot 2022-02-06 at 15.41.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2487729/c1779176-f422-cea8-f3c0-fc9d580a18f6.png)
Apple siliconを利用している場合の正しいパスは手順２でもご紹介しましたが、

```terminal
chsh -s /opt/homebrew/bin/fish
```
です。

### デフォルトシェルの指定時に怒られる

```terminal
chsh: /opt/homebrew/bin/fish: non-standard shell
```
上記のエラーが表示される場合は

```terminal
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
```
を実行して、```shells```内の末尾に```/opt/homebrew/bin/fish```を追記してあげると解消されます。

# 振り返り
vimで```shells```を色々編集してみたりiTermのPreferenceを色々いじってみたり、あれこれ調べてようやくパスが違うという結論にたどり着きました。手順をまとめるとたった3つのコマンドでいけたという「なんだよ〜〜〜！」の気持ちでしたが、「M1だとHomebrewのインストール先が違ったりするのか〜！気をつけよう！」だったり、普段なかなかやらないvimでの編集などなど新しい視点や困ったときに試してみるアイデアが増えたので、いい経験でした。

修正したほうが良い表記や表現があればどんどん指摘して頂けますと喜びます！
プログラムの処理に制限時間を設ける方法

メモです。
RubyでいうTimer.timer gemをどう実装するか、の思考実験。



- タイマー用のスレッドを立てる①
    - このスレッドでは、システムコールで特定時刻になるまでブロッキングするようにする。特定時刻になったら元のスレッドの処理を中断させる
    - ブロッキングしているスレッドは基本的にプロセッサーの処理が飛ばされる(認識)なので、計算資源は食わないはず。
    - 時間ぴったしに終えることができる。

- タイマー用のスレッドを立てる②
    - このスレッドでは、定期的に時刻を取得するシステムコールを投げる。特定時刻を超えたら元のスレッドの処理を中断させる
    - ブロッキングしているスレッドは基本的にプロセッサーの処理が飛ばされる(認識)なので、計算資源は食わないはず。
    - 時間を超えることがある

- Cレイヤーのタイマ(alarm()関数)、インターバルタイマ(getitimer(), setitimer()関数)を使用する
    - 特定時間経過後にカレントプロセスにシグナルが飛んでくる。
    - SIGALARMに対するシグナルハンドラを登録し、処理を止めるようにする。
    - alarmはプロセスごとに一つしか登録できない(既にアラームがスケジューリングされていた場合には、アラームは上書きされる)のでマルチスレッドプログラミングで使用できないっぽい。
    - ref. LINUXシステムプログラミングP.340


- Cレイヤーのtimer_create関数群を使う
    - 作成、初期化、削除が分かれている
    - 複数のタイマの作成、管理が別々にできる。
    - 設定時間経過後の挙動として、何もしない、シグナル通知、スレッドの起動、callback関数実行から処理を選択できる。
    - ref. LINUXシステムプログラミングP.340
[DecoratorPattern]wikiのサンプルコードをpython3実装

wikiのdecoratorのサンプルコードをpython3.xで実装したコードです。(環境python3.9)
[Decorator パターン](https://ja.wikipedia.org/wiki/Decorator_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3 "Decorator パターン")

:::note warn
元がjavaのため、@propertyは使わず、そのままゲッターで実装しています。
:::

```python:decorator_pattern.py
"""UML
                        << Component >>
                        operation()  < -----------------
                        |       |                      |
    Concrete Component          Decorator(Component) :use Component
    operation()                 |
                                Concrete Decorator (Decorator)
                                operation()


    deco = ConcreteDecorator_A(
                ConcreteDecorator_B(
                    ConcreteComponent()
                )
            )
    deco.operation()
"""

from abc import ABC, abstractmethod


# Component
class Price(ABC):

    @abstractmethod
    def get_value(self) -> int:
        pass

# Concrete Component
class PrimePrice(Price):

    def __init__(self, value: int) -> None:
        self.__value = value

    def get_value(self) -> int:
        return self.__value

# Decorator
class MarginPrice(Price):

    def __init__(self, price: Price):
        self._price = price

# Concrete Decorator
class WholeSalePrice(MarginPrice):

    def __init__(self, price: Price, advantage: int):
        super(WholeSalePrice, self).__init__(price)
        self.__advantage = advantage

    def get_value(self) -> int:
        return self._price.get_value() + self.__advantage

# Concrete Decorator 2
class DoublePrice(MarginPrice):

    def get_value(self) -> int:
        return self._price.get_value() * 2



if __name__ == '__main__':

    prime_price = PrimePrice(100)
    print(prime_price.get_value())

    whole_sale_price = WholeSalePrice(prime_price, 50)
    print((whole_sale_price.get_value()))

    # double_sale_price = DoublePrice(prime_price)
    double_sale_price = DoublePrice(whole_sale_price)
    print(double_sale_price.get_value())

```
Laravelで画像をリサイズして表示する

#経緯

https://qiita.com/Hiroto0706/items/9cb509cff284783e2550

上の記事ではlaravelで画像を表示できるようにしました。
しかし、画像によっては大きく表示されてしまっていたので、画像のサイズを変更して表示したい！と思い画像をリサイズして表示することに挑戦！🐶

###やりたいこと
画像をリサイズして表示する

#環境
・M1 Mac
・Laravel Framework 8.82.0
・PHP 8.1.2
・docker



#やったこと
###①composerを使ってintervention/imageをインストール。
以下のコマンドを使って、`Intervention Image`という外部のライブラリをインストールする。

```terminal
composer require intervention/image
```

###②設定を行う
インストールできたら、configフォルダの中にある`app.php`で設定を行う！

```php:app.phpのproviders
 'providers' => [

        /*（省略）*/

         /*
         * Package Service Providers...
         */
        Illuminate\View\ViewServiceProvider::class,
        //大体１６０行目くらいに僕は追加しました
    ],
```

```php:app.phpのaliases
    'aliases' => [
        ///aliasesの一番下に追加しました
        'InterventionImage' => Intervention\Image\Facades\Image::class,
        //※ここでImageとするとImageモデルと被る可能性があるので、InterventionImageとした
    ],
```
設定はこれで終わり！簡単！🐶

###③画像のサイズを変更する
僕はこんな感じでcontrollerを書きました！
参考程度にどうぞ！

```php:僕が実際に書いたcontrollerのコード
//ここでuseするのを忘れないように！
use Illuminate\Support\Facades\Storage;
use InterventionImage;


public function store(Request $request)
    {
        $post = new Post();
        $post->title = $request->title;
        $post->body = $request->body;
        $post->image = $request->image;

        $file = $request->file('image');
        // アスペクト比を維持しつつ画像の幅を1920pxで保存している
        $resized = InterventionImage::make($file)->resize(1920, null, function ($constraint) {
            $constraint->aspectRatio();
        })->save();

        //画像の保存
        Storage::put('public/' . $post->image, $resized);

        $post->save();

        return redirect()
            ->route('posts.index');
    }
```

###④bladeに渡して表示
あとはこんな感じでbladeファイルに渡して表示するだけ！

```html:bladeファイル
 <div class="show_picture">
        <img src="{{asset('storage/' . $post->image)}}">
 </div>
```

![スクリーンショット 2022-02-06 16.41.40.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2038763/ea3b171e-b949-d186-7c57-20dd2c5fa5c1.jpeg)
画像の範囲が分かりにくいと思うんですけど、こんな感じで表示できました！（少しCSS使って調整もしました...）

#お世話になった方々
クソおせわになりました！
[【Laravel】画像をアップロードして、表示させる方法](https://taidanahibi.com/laravel/upload-image/)
[Laravelで画像サイズを変更して保存する方法がめちゃめちゃ簡単だった話](https://qiita.com/vain_vox/items/1dda22b4dcd1db132a21)
[Laravelで画像をリサイズ＆勝手に回転しないようにする【EXIF情報も削除】](https://qiita.com/nakaji0210/items/8d487c6a5683ca1be3da)

#まとめ
リサイズするだけで初めは「めんどくさっ」てなんたんですけど、わかれば結構簡単でした！
いろいろ参考にしながら自分で考えてやってみたところもあるので、間違ってるところもあるかもしれないです！
参考程度に見てくれると幸いです🐶
最後まで見てくださりありがとうございました！
【Rails 6】環境を指定してconsoleを起動する際に詰まったポイント

# はじめに
FactoryBotの挙動を確認するために`$ rails c`でコンソールを起動し`FactoryBot.create(:user)`等のコマンドを実行してもテスト用のDBに追加されなかった。
調べると、`console`コマンドにはいくつかオプションがありそこで環境を指定できることを知った。ただ実際に環境を指定してコンソールを起動したところエラーが発生したため本記事では環境の指定方法と詰まったポイント・解決方法を記録する。

#### 構成
**1. 環境の指定してコンソールを起動する方法**
**2. 詰まったポイント・解決方法**

#### 実行環境
Ruby 3.0.3
Rails 6.1.4
rspec-rails 5.0.2
factory_bot_rails 6.2.0

# 1. 環境を指定してコンソールを起動する方法
## consoleコマンド
* `console`コマンド（`c`と省略可能）でコンソールを起動することでRailsアプリケーションとやり取りすることが可能。

```bash
$ rails c
Running via Spring preloader in process 261
Loading development environment (Rails 6.1.4.1)
irb(main):001:0> 
```
* モデルを介してデータをDBに保存したり、定義したメソッドの挙動の確認したりする際に使用される。

```bash
irb(main):001:0> Article.create(title: "タイトル1", content: "内容1")
```

* 内部にirbが組み込まれているため、Rubyのコードを実行することが可能。
* Railsアプリケーションの環境を読み込んだ上でコードを実行することが可能

## 環境を指定する
Railsには以下3つの環境が用意されている

* develop: 開発環境
* test: テスト環境
* production: 本番環境

**Rails5**までは`$ rails c [環境]`で環境を指定することで対象環境でコンソールを起動することができる。

```bash
# テスト環境でコンソールを起動する場合
$ rails c test

# 本番環境でコンソールを起動する場合
$ rails c production
```

**Rails6**以降では上記の方法だとエラーが発生するため以下いずれかの方法で起動する

* `RAILS_ENV=[環境] rails c`
* `rails c --environment [環境]`
* `rails c -e [環境]`

```bash
# テスト環境でコンソールを起動する場合
$ rails c -e test
```

### デフォルトでは開発環境が指定されている
デフォルトでは開発環境に設定されているため何も指定せずに起動した場合は開発環境でコンソールが起動する.

```bash
$ rails c
Running via Spring preloader in process 71
Loading development environment (Rails 6.1.4.1)
irb(main):001:0> Rails.env
=> "development"
```

# 2. 詰まったポイント・解決方法
test環境でコンソールを起動したいため、以下コマンドを実行すると,エラーが発生した。

```bash
$ rails c -e test
/usr/local/bundle/gems/spring-3.1.1/lib/spring/application.rb:101:in `block in preload': Spring reloads, and therefore needs the application to have reloading enabled.
Please, set config.cache_classes to false in config/environments/test.rb.
```

**1. メッセージを見てみる**
「`spring`はreloadを行うので、アプリケーション側でreloadを有効にする必要がある。」
「`config/environments/test.rb`に記載されている`config.cache_classes`を`false`に設定してください」

**2. springとは何だ**
gemの一つで、Railsアプリケーションをバックグラウンドで起動させたままにしておく事で`rails`コマンドを実行する度にRailsを起動しないで済むため開発の効率向上を実現できる。

**3. `config/environments/test.rb`の`config.cache_classes`を見てみる**

```ruby:config/environments/test.rb
Rails.application.configure do
  ...
  config.cache_classes = true
  ...
end
```

現状では、なぜだか`true`となっており、キャッシュを使用する（リクエストごとにアプリケーションのクラスやモジュールをreloadしない）設定になっている。

※ Rails6以降の`config.cache_classes`のデフォルト値は以下のとおり
（参考: https://madogiwa0124.hatenablog.com/entry/2019/09/16/145657）

  * **development**: `false`
  * **test**: springがインストール済み ->`false`, 未インストール -> `true`
  * **production**: `true`

**4. falseに変更し、再度実行してみる**

```ruby:config/environments/test.rb
Rails.application.configure do
  ...
  config.cache_classes = false
  ...
end
```

```bash
$ rails c -e test
Running via Spring preloader in process 246
Loading test environment (Rails 6.1.4.1)
irb(main):001:0> FactoryBot.create(:user)
  TRANSACTION (2.0ms)  BEGIN
  ...
```

test環境でコンソールが起動されて、`FactoryBot.create(:user)`を実行することでテスト用のDBに正しくファクトリが保存された。

# 参考
https://madogiwa0124.hatenablog.com/entry/2019/09/16/145657

https://pikawaka.com/rails/rails-console

https://railsguides.jp/configuring.html#config-cache-classes
Python の 機械学習アプリや GUI アプリを PyInstaller でパッケージングするメモ

## 背景

機械学習アプリとか, GUI アプリなどをぺろっと配布したい.
ユーザーに conda 環境作って, pip install して... とかさせるのが面倒だったり, 動作環境(python version など)を固定させたいときなど. 特に Windows でユーザに環境一式そろえたのを提供したいときとか.

PyInstaller でいけました!

## 方法

PyInstallerでexeファイル化
https://qiita.com/takanorimutoh/items/53bf44d6d5b37190e7d1

PyInstallerによるPythonスクリプトのexe化とエラー対処方法まとめ
https://qiita.com/kunishou/items/b2e8754886107292926d

PyTorchで記述したPythonスクリプトをPyInstallerでexe化
https://qiita.com/noknmgc/items/ea4ff708131a0ff22ef9

ありがとうございます.

基本はとくに何も考えずによろしく変換してくれます.

## ttkbootstrap のサンプル

https://ttkbootstrap.readthedocs.io/en/latest/gettingstarted/tutorial/

あたりで適当に gui.py を作り, `pyinstaller gui.py` しました(Windows)

![Screenshot from 2022-02-06 16-07-33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/fdee097b-2691-7409-f911-3bd921484620.png)


あとは .exe をクリックすれば, python でスクリプト実行したときと同じようにいけます!

![Screenshot from 2022-02-06 16-07-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/147737e4-bcb0-05fa-9c88-1761825d2164.png)

Voila!

## native binary?

native c module などもパッケージングできるでしょう.
機械学習アプリを販売したりデモ用に提供したいが, 一部はバイナリにしてソースコード見せたくないようなときなど.
(python コード自体も, 難読化というのもあるかもしれません)

## 注意点

conda 環境でつくっていると, numpy など conda 環境に入っているのがいろいろ一式パッケージングされます.
とくに pytorch 入っているとサイズでかい(4 GB くらいになる)ので注意です! 上記 Qiita 記事にあるように, パッケージング用には別の conda 環境を作るのがよいでしょう.

GPL なのや, dll など一部の再配布時のライセンスに注意が必要かもしれません
(vc runtime dll とか. ライセンス一覧ファイルも自動で作ってくれる機能あるかしらん)
YOLOv5実行時のUnable to find a valid cuDNNエラーの原因と解決法

# 実行環境
OS: Ubuntu18.04
GPU: V100(16GB)

# YOLOv5実行中に以下のエラーが発生
```:実行コード
python train.py --img 3200 --batch 16 --epochs 10 --data data.yaml --weights yolov5s.pt
```
```:エラー内容
  (...)
  File "C:\Program Files\Python38\lib\site-packages\torch\nn\modules\module.py", line 727, in _call_impl
    result = self.forward(*input, **kwargs)
  File "C:\Program Files\Python38\lib\site-packages\torch\nn\modules\conv.py", line 423, in forward
    return self._conv_forward(input, self.weight)
  File "C:\Program Files\Python38\lib\site-packages\torch\nn\modules\conv.py", line 419, in _conv_forward
    return F.conv2d(input, weight, self.bias, self.stride,
RuntimeError: Unable to find a valid cuDNN algorithm to run convolution
```

# 原因と解決法
GPUのメモリ不足が原因のため、メモリ不足が起きない程度まで
`batch size`または`image size`を修正する。
PowerShellスクリプトでパイプ受け入れする

PowerShell スクリプトで標準入力から受け入れるとかあまりやらないので、備忘録として残しておきます。
使い方などなどはソースを見てくださいｗ＜おい！

ポイントは`[CmdletBinding()]`で明示してやらないと受け入れることができないというところかな。

使い方はこんな感じ。オプションは必要な時だけつければいい格好。

```PowerShell
cat ".\Sample.json" | .\StdinPipe.ps1 -RequireParam "必須パラメータ"
```

```PowerShell
# StdinPipe.ps1 [-InputObject] <string[]> [-ReqireParam] <string> [[-OptionalParam] <string>] [<CommonParameters>]
[CmdletBinding()]
param (
    [parameter(Mandatory=$true,ValueFromPipeline=$true,HelpMessage="標準入力か引数で受け取るデータ")]
    [string[]]$InputObject,
    [parameter(Mandatory=$true,ValueFromPipeline=$false,HelpMessage="必須パラメータ")]
    [string]$ReqireParam,
    [parameter(Mandatory=$false,ValueFromPipeline=$false,HelpMessage="オプションパラメータ")]
    [string]$OptionalParam
)
begin{
    # 初期化処理等はここに書く
    Set-StrictMode -Version Latest
    [string[]]$inputParam = @()

    # 関数はここに記述して置くと分離できて見やすいのかな？
    function Func( [Object]$dispParam ){
        $dispParam | Out-String
    }
}
process{
    Write-Verbose "Called-`"$InputObject`""
    $inputParam += $InputObject
}
end{
    # ここをメイン関数みたいに使うのがすっきりする

    # $inputParam は sting[]なのでそのままでは Write-Verbose出来ないため文字列に変換してやる
    # パターン１
    Write-Verbose "`$stringValue = Func `$inputParam; Write-Verbose `$stringValue"
    $stringValue = Func $inputParam
    Write-Verbose $stringValue
    # パターン２
    Write-Verbose "Write-Verbose `"`$inputParam`""
    Write-Verbose "$inputParam"

    # さらにパイプをつなぐような場合は、つぎに渡すオブジェクトを return。仕様は明確に！
    return $inputParam
    # バッチファイルのように失敗を明確化して返したい場合はexitを呼び出してやる($LASTEXITCODEで値が取れるようになる)
    # exit 数値
}
```
### おまけ

Write-Verbose は文字列しか受け取ってくれないので、複数行の場合はあらかじめ`Out-String`するか、`""`でくくってやらないとだめ。
JavaScript 関数 戻り値

_コード１_

```
const add=(a,b)=>{
  console.log(a+b);
};
add(3,7);
```
_出力_

```
10
```
コード１は、
受け取る引数をaとbとして、
関数の処理部分を「a+b」の値を出力するようにし、
引数に「3」と「7」を渡して関数を呼び出しています。

PC君がこのコードを処理していく流れ？的なものを私の勝手なイメージで想像すると

・『引数「a」「b」、処理「a+bを出力」』の関数を発見！
↓
・発見した関数の引数に「3」と「7」を渡してコンソールに呼び出してやろう！
↓
（コンソール側）
・関数が送られてきたな！
「a」が「3」で「b」が「7」を受け取っていて、
それを足せばいいから出力は「10」だな！

という感じで「10」が出力されているというイメージですかね？

_コード１−２_

```
const add=(a,b)=>{
  console.log(a+b);
};
const sum=add(3,7);
consol.log(sum);
```
_出力_

```
undefined
```
しかしコード1−２のように、
定数「sum」を定義し、関数の呼び出しを代入、
そして定数「sum」を出力すると、
「undefined(値が存在せず定義されていないという意味)」
と出力されます。
というのも「add(3,7);」は関数に「3」と「7」を渡して関数を呼び出すだけで、
「add(3,7);」自体が別の値に置き換わったりしないので、
「undefined」と出力されました。

これもPC君のコードを処理していく流れ？的なものを私の独断なイメージで想像すると

・『引数「a」「b」、処理「a+bを出力」』の関数を発見！
↓
・『発見した関数の引数に「3」と「7」を渡してコンソールに呼び出す』
という関数呼出方法（呼出依頼ではない）をサム箱（定数「sum」）に代入してるみたいだね！
↓
（コンソール側）
・まだ関数呼び出し依頼こないなぁ、、、
↓
・「console.log(sum);」ってことはサム箱（定数「sum」）の出力か！
コンソールさんサム箱わたすんで出力おねしゃす！
↓
（コンソール側）
・お！出力依頼来た来た！
えーっとこの「サム箱」の中身の出力依頼か、、
ん？この箱の中身は関数呼出方法だけで呼出命令が入ってないぞ？
これは何を呼び出せばいいかわからんなぁ。
出力内容の値がないから「undefined」で出力しまーす！

という感じ？(笑)で「10」ではなく「undefined」が出力されてしまいます。

この定数「sum」に代入する「add(3,7);」の意味が、
今回でいう関数呼出方法ではなくて
「10」となったらコンソール君も迷わず出力してくれるはずです！

ここで役に立つのが関数の処理部分に記述することができる
「戻り値（return 値;）」です

_コード２_

```
const add=(a,b)=>{
  return a+b;
};
const sum=add(3,7);
console.log(sum);
```
_出力_

```
10
```
「return 値;」を関数の処理部分に記述すると、
関数の処理結果を「呼出元」に返して、
関数を呼び出す『呼出元「add(3,7);」』を「10」に変えてしまいます。
この返された値である「10」を「戻り値」と言います。

コード２は、
関数の引数「a」「b」に、
「add(3,7);」により「3」と「7」を渡し、
「a」と「b」を足した値「10」を呼出元である「add(3,7);」に返して、
その返された戻り値「10」を定数「sum」に代入、
値「10」が代入された定数「sum」を出力。
という記述です。

またまたPC君のコードを処理していく流れ的なものを私の独断と偏見のイメージで想像すると

・『引数「a」「b」、処理「戻り値「a+b」を呼出元に返す」』の関数を発見！
↓
・発見した関数の引数に「3」と「7」を渡し、
「a+b」の値「10」を戻り値として呼出元「add(3,7)」に返しまーす。
↓
・値「10」を返されたことで、
『関数呼出君「add(3,7)」』が「10」に変身！
↓
・サム箱（定数「sum」）を作って
さっき変身した戻り値「10」をサム箱に入れちゃうよ！
↓
（コンソール側）
・まだ関数呼び出し依頼こないなぁ、、、
↓
・「console.log(sum);」ってことはサム箱（定数「sum」）の出力か！
コンソールさんサム箱わたすんで出力おねしゃす！
↓
（コンソール側）
・お！出力依頼来た来た！
えーっとこの「サム箱」の中身の値は「10」ね〜。
てことで「10」を出力しまーす！

みたいな感じ？で無事「10」を出力することができました！

ちなみに今までの説明でもわかるかもですが、
「呼出元」が戻り値として「値」を受け取った段階で、
そいつにはもう関数を呼び出す機能は備わっていません。なので

_コード３_

```
const number=(a,b)=>{
   return a+b;
 };
 number(3,7);
```
_出力_


```

```
コード３の記述では、
「 number(3,7);」はreturnにより戻り値「10」となっていて、
本来の「関数に引数を渡して呼び出す」という機能がなくなっており、
他に「console.log();」等の記述もないため、
コンソールには何も出力されないという状況が生まれます。
Rails + Vueでwebpack command not foundと言われるエラー

### 導入

Rails + Vueを使ったアプリをサンプルで作ってみようと思った時に導入地点でハマったので備忘録に記載しておく。

### エラー内容

![Screenshot - 2022-02-06 15.27.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/607264/bce5ac2c-a076-0d06-81a0-056bd9a6821b.png)


参考: [https://qiita.com/shizen-shin/items/38fd774ffc87bc8838c9](https://qiita.com/shizen-shin/items/38fd774ffc87bc8838c9)

こちらの記事を見たところcompileする必要があるとのことなので下記コマンドを入力したが、command not foundと言われてしまった。

```ruby
$ rails webpacker:compile
```

bin配下にwebpackは存在していたので原因がよくわからずnode_modulesを削除してwebpackerをinstallし直したりと試行錯誤していた中、以下のようなエラーメッセージを発見。

```
error @npmcli/fs@1.1.0: The engine "node" is incompatible with this module. Expected version "^12.13.0 || ^14.15.0 || >=16". Got "14.0.0"
```

今のnodeのバージョンに互換性がないとのことなのでnodeのバージョンを変更する。

参考: [https://qiita.com/sugasaki/items/8cb12c06d2a44515194a](https://qiita.com/sugasaki/items/8cb12c06d2a44515194a)

参考: [https://qiita.com/tonkotsuboy_com/items/5322d226b6783d25b5df](https://qiita.com/tonkotsuboy_com/items/5322d226b6783d25b5df)

こちらを参考にNode.jsのバージョン管理ツールのnodenvをインストールした後、

```
# 必要なバージョンをインストール
$ nodenv install (xx.xx.xx)

# インストールしたバージョンを該当のプロジェクトに反映させる
$ nodenv local (xx.xx.xx)

# バージョンが反映されているか確認
$ node -v

# package.jsonに定義されてる依存関係をインストール
$ yarn install
```

ひとまずはこれで解決できました。

Node.js関連の知識がまだまだ薄いので補足等いただけると大変助かりますm(_ _)m
なぜコンポーネントのdataは関数でなければいけないのか？(Vue.js)

なぜコンポーネントのdataは関数でなければいけないのか？

前提として、コンポーネントは一度定義すると使いまわせるという特徴を持っている。

```jsx
<div id="components">
  <TestComponent></TestComponent> {/* 同じコンポーネントを使い回している */}
  <TestComponent></TestComponent> {/* 同じコンポーネントを使い回している */}
  <Testcomponent></TestComponent> {/* 同じコンポーネントを使い回している */}
</div>
```

このように同じコンポーネントを3回使い回している場合、’count’というデータを

```jsx
data: {
  count: 0
}
```

と表記するとどのコンポーネントでも同じ’count’を参照することとなり、一つのコンポーネントで’count’を更新すると全てのコンポーネントで同じように値が更新されてしまうからです。

そうならないよう’data’を宣言するときは、

```jsx
data: function () {
  return {
    count: 0
  }
}
```

のように関数として宣言します。こうすることにより各コンポーネントが独自の変数として’data’を保持できるようになります。

「なんでだろ？」と思っていたことがスッキリしました。
Twitter API v2で引用ツイートを検索するときのクエリ

`GET /2/tweets/search/recent` のクエリの作り方のTipsです。APIのアクセス方法などは書いていません。
## 自分への引用ツイートを検索したい
公式　クエリの作り方
https://developer.twitter.com/en/docs/twitter-api/tweets/search/integrate/build-a-query

引用リツイートのみを検索する場合、個別の引用元ツイートIDを入れれば簡単に検索は出来ますが、アカウントごとの引用ツイートを集めるのは少し工夫が必要です。

結論、これをクエリに入れれば想定通り集められます。

```shell
url:"https://twitter.com/{username}/" is:quote
```

`url:` を使うのがコツです。また、 `is:quote` を付けない場合、リツイートも引っかかってくるので意図しない結果が多くなります。

### やりがちだがダメな例
引用ツイートは結局本文の末尾に引用元ツイートのURL（ `https://twitter.com/{username}/status/{id}` ）が含まれているので、それで検索できそうな気もしますが、`url:`オペレータを付けないと検索にかかりません。

▼これらだと引用ツイートは引っかからない（ `is:quote` の有無は関係なく）

```shell
"https://twitter.com/{username}/" is:quote
"https://twitter.com/{username}/status/" is:quote
"https://twitter.com/{username}/status/{id}" is:quote
"{username}/status" is:quote
　　などなど
```

一方で、はじめにも書きましたが、個別ツイートの引用RTを検索したい場合はIDでもOK

▼これはOK

```shell
{id} is:quote
```

また、`url:` `is:quote` などのオペレータはTwitter Webの検索窓とは少しだけ違うようなので、Web上からは使えません。

Webからの検索ではこのTweetDeck向けの説明書が役に立ちそうです。
https://help.twitter.com/ja/using-twitter/advanced-tweetdeck-features
Rails×Vue 「Hello Vue!」を表示させるまで


Rails×Vueで「Hello vue!」と表示させるまでのメモです

まずはrails new 

```file
% rails new Tasks --webpack=vue 
```

webpackのオプションにvueを指定してVue.jsを使えるようにします。

githubにリポジトリを作成し herokuにアプリをあげる予定なのでheroku creat後push。

アプリにbootstrapを使いたいので yarnでインストール。

```markdown
yarn add bootstrap
```

アプリのルートパスを設定していきます。controller名はhome_controllerとします。

```markdown
rails g controller Home index
```

Vueを使用したSPAを作成するのでページを表示するためのアクションはこの中に作成するindex アクションのみとなります。

indexアクションの作成

```controllers/home_controller.rb
def index; end  #　ユーザーがアプリに訪問したときの窓口となるだけなので何の処理も入れません
```

routes.rbの修正

```routes.rb
Rails.application.routes.draw do
  root to: 'home#index' # 追加
end
```

作成したindex.html.erbにVueを読み込ませるための記述をします。

```view/home/index.html.erb
<%= javascript_pack_tag 'hello_vue' %>
```

hello_vue.js(vueの各コンポーネントはこのファイルを通じてindex.html.erbに表示される)

に先ほどインストールしたbootstrapを読み込ませます

```javascript/packs/hello_vue.js
import Vue from 'vue'
import App from '../app.vue'
import 'bootstrap/dist/css/bootstrap.css' // 追加

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)

  console.log(app)
})
```
hello_vue.jsに読み込まれ、表示されるapp.vueの確認
vue.jsでは.vueという拡張子のファイルが描画されるテンプレートファイルになります。rails new をした時点でデフォルトで使用されるapp.vueというファイルが用意されています。

```javascript/packs/app.vue
<template>
  <div id="app">
    <p>{{ message }}</p> <!-- script内で設定したmessageの中身が描画される -->
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!" // Vue.jsで使用される変数
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>
```
最後にフロントエンド、バックエンド両方のサーバーを起動します。

```markdown
rails s 
```

```markdown
bin/webpack-dev-server
```

その後localhost3000にアクセスすれば「Hello Vue!」と表示されます。
destroyアクションの後、マイページにredirectする。

#はじめに
投稿した記事、イベントなどの削除後、
マイページへのredirectに戸惑ったのでメモがてら記載。
ログインユーザー＝current_userとして定義されている事が前提。

#環境
Ruby 2.6.8
rails 5.2.6

#実装方法
**ルーティング**

```routes.rb
resoueces :events
```

こうするだけで７つのアクションに対するルーティングを作成してくれます。
個別に書いてもOK。
欲しかったルーティング↓
　 DELETE /events/:id(.:format)      events#destroy

今回は投稿したイベント情報を削除するのでeventsとしているが、Postsでもなんでも。



**viewページ**

```events/show.html.erb
<%= link_to "/events/#{@event.id}", method: :DELETE do %>
  <button>イベント削除</button>
<% end %>
```

@eventには今閲覧してるevent情報が定義されている。
そのままDELETEを発射。

**controller**

```events_controller.rb
def destroy
  @event = Event.find(params[:id])
  @event.destroy
  redirect_to mypage_path(id: current_user.id)
end
```

*（mypage_path　→ 　get 'users/:id', to: 'users#show', as: 'mypage'　といったルーティングを設定してある。）*


パラメーターにくっついている:idで@eventをdestroy（削除）
その後、mypage_pathにログインユーザーのidを渡してあげる。
（今回ここの記法をど忘れして手こずったので、掲載を決意した。）

直接urlを書いても良いが、
わざわざ自分でroutesに設定したpathを使いたい時、
思い出そう。
Railsの覚えておいた方がいいことを書いておく

## コマンドたち

- rails s 起動（WEBサーバpumaが立ち上がる）
- rails g controller users index コントローラーの作成
- rails g model user name:string age:integer モデルの作成
- rails db:migrate DBへの反映
- rails dbconsole DB構成の確認(.qで抜ける)
- rake routes URLの設定を確認することができる

※railsコマンドがないって怒られたときは「bundle exec」を実行すると上手くいくことがある。

## 言葉たち

- ERB　htmlの中にRubyのコードを埋め込むことができる


## 仕様部分

- インスタンス変数（＠）はViewからアクセスできる