OmniAICreator/Qiita-1.07M huggingface dataset:
Bash 4.2以降ではprintfでUNIX時間の取得と日常の日付への変換が簡単にできる

## はじめに

シェルスクリプトの互換性問題で意外と困るのが日付処理です。`date` コマンド自体は POSIX で規定されていますが共通で使えるオプションが少なく Linux (GNU) と macOS (BSD) 間での互換性は低いです。

そこで日付処理の選択肢の一つとして使える bash の `printf` の機能を紹介します。bash 4.2 以上（または ksh93）を使うことが前提となりますがシェルに搭載されている機能であるため `date` コマンドに依存することなく使用することができます。注意事項として macOS でデフォルトでインストールされている bash は 3.2.57 とバージョンが低いので Homebrew などで最新版をインストールする必要があります。

## 使い方

引数を何も指定しない場合、現在の日時が表示されます。

```console
$ printf '%(%F %T)T\n'
2021-08-15 16:13:33
```
引数には UNIX 時間を指定することができます。

```console
$ printf '%(%F %T)T\n' 1629011613
2021-08-15 16:13:33
```

また特殊な値として `-1` （現在時刻） と `-2` （シェルスクリプトを実行した時刻） を指定することができます。

```console
$ printf '%(%F %T)T\n' -1
2021-08-15 16:22:47
```

```console
$ printf '%(%F %T)T\n' -2
2021-08-15 16:20:25
```

### 書式

日付の書式は `strftime` と同じ `datefmt` の[書式](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/strftime.3.html)が利用可能です。（注意 全て問題なく使用できるかは検証していません）

```console
$ printf '%(%s)T\n' # UNIX タイム
1629012592

$ printf '%(%Y/%m/%d %H:%M:%S)T\n'
2021/08/15 16:32:18
```

### 変数への割当

UNIX 時間を取得できたならば、それを変数に代入したくなることでしょう。では現在の UNIX 時間を変数へ代入・・・

```sh
now=$(printf '%(%s)T')
```

っと、このコードは書かないでください。コマンド置換はサブシェルが生成される為遅いです。こちらが推奨される方法です。

```sh
printf -v now '%(%s)T' 
```

ちなみに 100 倍以上の差があります。

```console
$ time for i in $(seq 10000); do printf -v now '%(%s)T'; done

real	0m0.090s
user	0m0.058s
sys	0m0.032s

$ time for i in $(seq 10000); do now=$(printf '%(%s)T'); done

real	0m12.482s
user	0m8.382s
sys	0m4.985s
```

## さいごに

さて、実はこの日付出力機能は ksh93 の情報を調べていて気づきました。今までも目にしてた記憶はあるのですが読み飛ばしていましたね。bash の日付出力の機能の残念なところは、日常の日付から UNIX 時間への変換ができないということです。

```console
$ bash -c "printf '%(%s)T\n' '2021-08-15 16:13:33'"
bash: line 1: printf: 2021-08-15 16:13:33: invalid number
2021

$ # ksh93 ならできる
$ ksh -c "printf '%(%s)T\n' '2021-08-15 16:13:33'"
1629011613
```

いや、実に惜しい。これさえできればシェルだけで簡単に時間計算ができたのですが。

でも大丈夫、UNIX 時間と日常の日付の相互変換はシェル関数だけ（外部コマンド不要）で実装することができます（参照「[シェルスクリプトでUNIX時間⇔日付の相互変換を行う関数（POSIX準拠）](https://qiita.com/ko1nksm/items/e61728f863c1b2bc829d)」）。UNIX 時間にさえ変換してしまえば、1 週間前の日付を計算するのも簡単なわけで、これらを組み合わせると外部コマンドを使用することなく現在の日付の取得と時間計算を行うことができます。
【初心者向け】Gitって何！？

#はじめに
　これからプログラミング関連の知識を簡潔にまとめた記事をどんどん投稿していこうと思いますが、もし誤っている部分があればすぐに修正しますので、ご指摘方よろしくお願いいたします。

早速ですが、本題に入っていきましょう。

#Git とは

簡単に言うと・・・
###ソースコードやファイルの変更履歴を分散して管理することができるシステム
です。

もう少し詳しく説明すると、
Gitでは、ファイルの変更履歴、つまりファイルのバージョンを「コミット」という単位で管理することができます。
また、共有サーバー上にある大元のフォルダのコピーを手元（各自のPC上）に置いて自由に編集することができます。
これによりどのようなメリットがあるかというと...
###①古いバージョンに戻すことができる
不具合が発生したときや、やっぱり前のファイルに戻したいなってときに、簡単に古いバージョンに戻すことができます。
###②チーム開発をより効率的に行うことができる
コミットの履歴をたどれば、いつ誰がどこに変更を加えたのかがチーム内の誰でも分かるので、チーム内での情報共有がしやすくなります。
また、分散して管理することができるので、複数人が同時進行で別の機能を実装していくことができます。
万が一、2人が同時に同じファイルを編集してしまった場合でも、競合が発生していると教えてくれ、先に編集した人の内容が消えてしまうというような事態を防ぐこともできます。

#まとめ
プログラム言語の勉強はもちろん大事ですが、Gitもしっかりおさえておきましょう。
Velocityで自動HTMLエスケープする

##問題

WEBアプリで、velocityを使用してHTMLテンプレートを記述する場合、[EscapeTool](https://velocity.apache.org/tools/1.4/generic/EscapeTool.html)を使用してエスケープ処理を行うのが普通だが、項目出力の都度エスケープ処理を記載しなければならず、記載忘れでクロスサイトスクリプティングなど重大な脆弱性を埋め込むおそれがある。

##解決方針

デフォルトでHTMLエスケープを行うようにして、コーディング時の負担を軽減する

##課題

全ての項目をエスケープすれば良いわけではない(出力項目の中にはHTMLタグを埋め込んでやる必要があることもある)。
[ココ](https://velocity.apache.org/engine/2.3/developer-guide.html#registering-event-handlers)に記載のあるように、VelocityプロジェクトでHTMLエスケープを自動で実施する仕組みを作っていたこともあるが、一律同じエスケープ処理を行うことは「実用的でない」としてdeprecatedになっている。
→一律エスケープするのではなく、デフォルトでエスケープはするが、エスケープしない場所を指定できるようにすれば良いのでは、と思った。

###実装案

* [ココ](https://velocity.apache.org/engine/2.3/developer-guide.html#registering-event-handlers)を参考にして、ある変数が定義されている場合のみエスケープを行う拡張を実装する。
* エスケープをするかどうか判断する変数の中身を入れ替えるマクロを定義する
* テンプレート記述時、エスケープをしたくない箇所のみ、マクロを使用してエスケープ対象から除外する。

→デフォルトでエスケープ処理し、セキュリティを担保しつつもエスケープしてはいけない箇所をコーディング時に切り分けることができる


###コード例

springboot1.2系での使用を想定
実務がこのバージョンだから。。。

* エスケープ処理

```java:ReferenceInsertionEventHandler.java
package com.example.demo;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.velocity.app.event.implement.EscapeReference;
import org.apache.velocity.context.Context;
import org.apache.velocity.util.ContextAware;

public class ReferenceInsertionEventHandler extends EscapeReference implements ContextAware {
    private final String ATTR_KEY = "__escape_html__";
    private final String ATTR_VALUE = "__raw__";
    private Context ctx;

    protected String escape(Object o) {
        if(ctx.containsKey(ATTR_KEY) && ATTR_VALUE.equals(ctx.get(ATTR_KEY))){
            //エスケープ除外用の変数が定義されていたらそのまま出力
            return o.toString();
        } else {
            //エスケープ除外用の変数が定義されていなかったらエスケープして出力
            return StringEscapeUtils.escapeHtml(o.toString());
        }
    }

    protected String getMatchAttribute()
    {
        return "eventhandler.escape.html.match";
    }

    public void setContext(Context context) {
        this.ctx = context;
    }
}

```

* マクロ

```:escape.vm
#macro(raw)
  #set( $__escape_html__ = "__raw__" )
#end

#macro(endraw)
  #set( $__escape_html__ = "__" )
#end
```


* テンプレート

```
#parse("escape.vm")

エスケープされる:<br />
${attributeA}<br />
${attributeB}<br />


#raw()
エスケープされない:<br />
${attributeA}<br />
${attributeB}<br />
#endraw()


エスケープされる:<br />
${attributeA}<br />
${attributeB}<br />
```

##イケてないところ
* javascriptのエスケープは？
* 変数名かぶるかも


##解決策
* ThymeleafやFreeMarkerに移行する
* プロジェクト開始時からきちんと考えて準備しておく
→最初からしっかり決めておけば苦労は少ないけど、後から全部修正するのは大変な苦痛を伴う
tmux起動時にserver version is too old for clientエラー

# はじめに
tmuxのバージョンが2→3系にアップデートされていたのでアップグレード。
その際にbrewのバージョンも低かったので一旦アンインストールしてインストールをしなおし。
エラーが出たので解決方法

まずはインストール

```
$ brew install tmux
```

そして起動

```
$ tmux
server version is too old for client
```

# 解決
アップグレード前のtmuxのセッションがうまくいってないことが原因のよう
アンインストールなど色々試してだいぶハマってしまった。昔も同じ問題でハマった気がしてきた


一度セッションを切ってやれば良い
```
$ tmux kill-server
```

# 終わりに
ドットファイル系を見直してたら思わぬところでハマってしまった。
ドットファイル系はある程度時間が経つと、バージョンが古くてエラーになったり、今のトレンドと違ったりで、直すのが大変なのと思い出すのも大変。vimrcのプラグインマネージャもデフォルトで配備されたようなので試しに使ったり。
Pythonでエラトステネスの篩を使って対象の数までの素数の個数を求めてみる

# Pythonでエラトステネスの篩で対象の数までの素数の個数を求めてみる
アルゴリズムの勉強の一環でエラトステネスの篩を使って対象の素数の個数を求めるツールを組んでみました。世の中に色々と出尽くしている感はありますが、自分なりに考えてやってみた次第です。


## 実際のソースコード
```python:sieve_of_eratosthenes.py.py
import sys
import math
import time

def main():
    print('start!' )
    start = time.time()
    args = sys.argv
    
    if len(args) == 1:
        print('Please specify an argument.')
        exit()

    if args[1].isdigit() == True:
        eratosthenes(int(args[1]))
    else:
        print('Please specify a numerical value for the argument.')

    elapsed_time = time.time() - start
    print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")
    print('end!')

def eratosthenes(number):
    print('check number: ' + str(number))
    
    if number == 1:
        print('prime number is nothing.')
        return

    # 平方根にして整数化する、これが検索のMAX
    max_limit = int(math.sqrt(number))
    #print('Max: ' + str(max_limit))

    # 3以上の奇数のリストを作る(2より大きい偶数は素数でないので無視)
    odd_numbers = [i + 1 for i in range(2, number, 2)]
    #print('odd_numbers: ' + str(odd_numbers))
    
    # max_limitまでの奇数のリスト
    max_limit_odd_numbers = [i + 1 for i in range(2, max_limit, 2)]
    #print('max_limit_odd_numbers: ' + str(max_limit_odd_numbers))
    
    # max_limitから素数だけにする
    max_limit_prime_numbers = make_prime_list(max_limit_odd_numbers, max_limit_odd_numbers)
    #print('max_limit_prime_numbers: ' + str(max_limit_prime_numbers))
    
    # 返却用のリスト(2は素数なので入れておく)
    ret_prime_list = [2] + make_prime_list(odd_numbers, max_limit_prime_numbers)
    #print(ret_prime_list)
    print('prime number quantity is :' + str(len(ret_prime_list)))

def make_prime_list(num_list1, num_list2):
    prime_list = []
    for num1 in num_list1:
        add_flag = True
        for num2 in num_list2:
            
            if num1 <= num2:
                add_flag = True
                break

            if num1 % num2 == 0:
                add_flag = False
                break

        if add_flag == True:
            prime_list.append(num1)
    return prime_list

if __name__ == "__main__":
    main()

```

## 実行結果例
```
root@070f0854c823:/code# python sieve_of_eratosthenes.py 1000000
start!
check number: 1000000
prime number quantity is :78498
elapsed_time:3.1015725135803223[sec]
end!
root@070f0854c823:/code#
```
rustと動かないWSL

WSLでubuntu20.04

プログラミング言語入門通りにやっていたら
WSLのインストール→できた
rustインストール→できた
helloworldファイル作成→できた
起動→ビルドできない
buildコマンドでもrustcコマンドでもできない

linker `cc` not found
がでてきている。公式の
https://users.rust-lang.org/t/ghostbsd-freebsd-error-linker-cc-not-found/43928
とか見ると
cコンパイラがなさそう
gcc--version　してみたらやっぱりないっぽい
というわけで
$ sudo apt install build-essential
してみる
Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/g/gcc-10/libquadmath0_10.2.0-5ubuntu1~20.04_amd64.deb  404  Not Found [IP: 2001:67c:1360:8001::23 80]  
みたいなえらーがいっぱい出てきた
パッケージリストが悪さをしているらしい
https://qiita.com/miriwo/items/bc2c0f18ee7d6f337ed0
 $ sudo rm -rf /var/lib/apt/lists/*
したあとに再度
$ sudo apt install build-essential
Reading package lists... Done                                                                                           Building dependency tree                                                                                                Reading state information... Done                                                                                       E: Unable to locate package build-essential

ってなってしまった。とりあえず
 $ sudo apt-get update
$ sudo apt install build-essential
してみる→無事gcc入った
 $cargo　run　で無事helloworldできました

追記
モジュールのインポートができない。原因不明
RubyのFiberクラス

# 定義

　Fiber クラスは、他の言語で coroutine や semicoroutine と呼ばれる軽量スレッドであるファイバーを提供するクラスです。明示的に指定しない限りコンテキスが切り替わらないことや親子関係を持つなど、Thread クラスを提供するスレッドとは異なる挙動と持ちます。
　Fiber.new メソッドにブロックを渡すと、Fiber クラスのオブジェクトであるファイバーが生成されます。このファイバーはインスタンスメソッドである resume メソッドでコンテキストがファイバーに切り替わります。また Fiber.yield メソッドで親である呼び出し元へコンテキストが切り替わります。

# 事例

```ruby:fiber_sample.rb
f = Fiber.new {
  print "A "
  Fiber.yield "B "
  print "C "
}

print "D "
print f.resume
print "E "
```

# 結果

```
[3] pry(main)> f = Fiber.new {
  print "A "
  Fiber.yield "B "
  print "C "
}
print "D "
print f.resume
print "E "

D A B E => nil
```

# 解析

　Fiber のブロック内は f.resume が呼び出された時に評価され、 Fiber.yield まで実行します。 Fiber.yield が呼ばれると、引数の"B"と共に元のコンテキストに処理を戻します。もし再び f.resumeが呼ばれると Fiber.yield の次の行から実行します。

```
[4] pry(main)> print f.resume
C => nil
```
最適化アルゴリズムの更新式まとめ

# 最適化アルゴリズムの更新式

理論は置いておいて、各アルゴリズムをパッと見れるようにまとめてみた。
ちゃんとした理論はわかりやすいページがいいっぱいあるので。

https://qiita.com/omiita/items/1735c1d048fe5f611f80

https://tech-lab.sios.jp/archives/21823

## 勾配降下法
勾配降下法による更新式を下記とした場合の更新式。
全ての式は、ここから始まった。
要するに、重み w を求めたい。

```math
w_{t+1} =  w_t - \eta \nabla E(w_t)
```

```math
\Delta w_t =  - \eta \nabla E(w_t)
```

## モメンタム
前回の重みを考慮した計算。
過去の勾配の指数関数的減衰平均。

```math
V_t = \mu V_{t-1} - \epsilon \nabla E \\
w^{(t+1)} = w^{(t)} + V_t
```

## NAG (Nesterovの加速勾配法)
モーメンタム係数$\mu$で勾配の振動を抑制している

```math
\Delta w_t = \mu\Delta w_{t-1} -(1-\mu) \eta \nabla  E(w_t + \mu w_{t-1})
```

## AdaGrad
パラメータが100個、200個あった時に全てのパラメータについて同じ学習率で良いか？というと、そうではない。
軸方向に更新量を変えていく。

NAGは勾配の１次の情報を使っているが、AdaGrad は2次の情報を使っている。

```math
\Delta w_t = - \frac {\eta}{\sqrt{\sum_{k=1}^t( \nabla E (w_k)_i)^2}} \nabla E(w_t)_i
```

## RMSProp
AdaGrad だと最初に大きな更新をすると、その後、一気に更新量が少なくなる。0になると0から戻らないので、それを回避。

指数的な移動平均 $v_{i,t}$を適用。

```math

v_{i,t} = \rho v_{i,t-1} + (1 - \rho)( \Delta E(w_t)_i)^2 \\

\Delta w_{t(i)} = - \frac{\eta}{\sqrt{v_{i,t}} + \epsilon} \nabla E(w_t)_i
```

## AdaDelta
ニュートン法を勾配降下法で近似。
ロバストな学習率を実現

他と比べて学習率 $\eta$を含まない。
また、AdaDelta だけ左辺と右辺の単位が同じ。

```math
u_{i,t} = \rho u_{i,t-1} + (1-\rho)(\Delta w_{i(t)})^2\\

v_{i,t} = \rho v_{i,t-1} + (1 - \rho)( \Delta E(w_t)_i )^2 \\

\Delta w_{t(i)} = - \frac{\sqrt{u_{i,t-1} + \epsilon}} {\sqrt {u_{i,t} +\epsilon}} \nabla E (w_t)_i

```

# 比較
それぞれの最適化アルゴリズムについて、違いがわかるように表にしてみた。
ちょっと表にするとブラウザの横幅大きくしないと見にくいかも。。。

|アルゴリズム|重みの計算式|各パラメータ|改善点|
|---|---|---|---|
|勾配降下法|$w_{t+1} = w_t - \eta \nabla E$||学習率が固定。|
|モメンタム|$w_{t+1} = w_t + V_t $|$V_t= \mu V_{t-1} - \epsilon \nabla E$|勾配の振動を抑制。|
|NAG <br> (Nesterovの加速勾配法)|$w_{t+1} = w_t + V_t $|$V_t= \mu V_{t-1} - \epsilon \nabla E(w-V_{t-1})$|勾配の振動を抑制・変化の加速。|
|AdaGrad|$w_{t+1} = w_t - \epsilon \frac{1}{\sqrt{h_t} + \theta } \nabla E $| $h_0 = \theta$ <br> $h_t = h_{t-1} +( \nabla E)^2 $|パラメータ方向に応じて学習率を補正。勾配が大きいと学習率を大きくする。|
|RMSProp|$w_{t+1} = w_t - \epsilon \frac{1}{\sqrt{h_t} + \theta } \nabla E $| $h_t = \alpha h_{t-1} + (1- \alpha) (\nabla E)^2 $|AdaGradの単調な学習率低下を改善。|
|AdaDelta| $w_{t+1} = w_t - \frac { \sqrt {s_{t-1} + \epsilon}} {\sqrt{h_t + \epsilon}}$ | $h_t = \alpha h_{t-1} + (1- \alpha) (\nabla E)^2$ <br> $s_{t} = \alpha s_{t-1} +(1-\alpha) V_{t-1}^2 $ <br> $ V_t = \frac { \sqrt {s_{t-1} + \epsilon}} {\sqrt{h_t + \epsilon}} $ |ニュートン法を購買降下方で近似。ロバストな学習率を実現。|
|Adam|$w_{t+1} = w_t - \beta \frac{V_t}{\sqrt{h_t + \epsilon}}$ |$V_t = \mu V_{t-1} - \epsilon \nabla E$ <br> $h_t = \alpha h_{t-1} + (1-\alpha) (\nabla E)^2 $ |AdaGradとRMSPropを合わせたような感じ。|
Macbook AirにHomebrewをインストールしようとすると「/opt/homebrew/bin is not in your PATH」が発生した場合

#はじめに
初めてMacを購入して、rubyの開発環境を整えようとしている中で遭遇したエラーです。
自分の記事を書く練習として、記録に残します。
[progate:Rubyの開発環境を用意しよう！](https://prog-8.com/docs/ruby-env)

#結論
この方の記事で解決できました。
ありがとうございました。
[Homebrewインストール時に「/opt/homebrew/bin is not in your PATH」が発生した際の解決方法](https://chicog.me/articles/1/)

#内容
rubyの開発環境を整えようと思い、ターミナルで↓を実行すると、

```
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

まず、macにログインするときのパスワードを入力を求められるので、入力しました。
![スクリーンショット 2021-08-09 21.40.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501159/35950c78-61de-879d-c669-0add72bba8da.png)
スクリーンショット 2021-08-09 21.40.07)

入力すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501159/ee2ce0aa-b6e7-2fec-0d53-6353c86f133f.png)

ここで一度止まるのでEnterを押すと、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501159/fd99c227-1409-cd8b-66a4-d282d2acce73.png)

成功したかなと思いましたが、途中でWarningが出ていました。

brew -v をしても、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501159/486d4f8c-2b71-dace-4c28-0a4d9ef10053.png)

zshにコマンドないよということだったので、書き込みます。

#解決
これでファイルを開いて、書き込みます。

```
vi ~/.zshrc
```

```
#開いた後に下記を入力し、保存する。
export PATH=/opt/homebrew/bin:$PATH

#保存の仕方は、;wq(shift押しながら;でwq入力する。)　+ ENTER
```
[参考: viコマンド（vimコマンド）リファレンス](https://qiita.com/pe-ta/items/0510bee10bcfd88afeee)

ターミナルに戻ってきたら、

```
source ~/.zshrc
```

これで環境設定終了。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1501159/57065d1d-c26d-d271-789a-710777afa7b4.png)
UnityのAndroid開発でエラーもなく突然激重になる現象とそれを対処した方法

こんにちは、[ハニカムラボ](https://www.honeycomb-lab.co.jp/)の[おの](https://twitter.com/tkyko13)です.

## 現象や状況
* Unity2020系、Unity2019系で発生
* Unity上のエディタでは発生しない
* 実機（Android6系と7系）で発生確認
    * 3種類ほどのタブレット端末で発生
    * Android5系のスマートフォンでは発生せず
* 10分から40分画面スリープもなく放置していると発生
    * 操作していても発生することも
* 見た目はほぼフリーズしている状態だが、画面遷移など時間が立つと起こるためたぶんすごいFPSが下がっているという状況
* Android Logcatなどでもエラーが発見できない
    * ただ、警告がずっと出続けていた（EGL_BAD_PARAMETER）

## 結果

[![Image from Gyazo](https://i.gyazo.com/298fcb4084cc020dc7c2273332039ac7.png)](https://gyazo.com/298fcb4084cc020dc7c2273332039ac7)

`Optimized Frame Pacing` の項目のチェックをはずすと警告が消え、フリーズ現象がなくなった

### Optimized Frame Pacingとは

https://unity.com/ja/releases/2019-2/platforms-and-editor

* 2019.2から追加されたっぽい
* > 低変動でのフレームの分散を可能にすることで、安定したフレームレートとよりスムーズなゲームプレイ体験を実現します
    * だそうだ

https://kan-kikuchi.hatenablog.com/entry/OptimizedFramePacing

* この記事とは別の現象だったが、不具合があるらしい
* 2020.3.8fではまだまだ不具合があるっぽい
* この機能に全く対応できない古すぎる端末だと動くのかなと予想
    * Android5系のスマートフォンで動いた理由

### 対処した方法など

今回単純なエラーが出たわけでもなく、そのエラーを見つけるのも大変だったため、色々試してみたのでその共有です。

* Firebaseなど外部ライブラリとUnityのバージョンの相性確認
    * https://firebase.googleblog.com/2020/08/firebase-compatibility-with-unity-20201.html
    * http://halcyonsystemblog.jp/blog-entry-732.html
* 警告を消す
* DOTweenの警告を消した
    * https://qiita.com/neusstudio/items/f4429024ea0f54d727fc
* Android Logcatを利用
    * Unity内でも見れるのもある：https://baba-s.hatenablog.com/entry/2018/12/25/090000
* Unity内にLogViewerを入れた
    * https://assetstore.unity.com/packages/tools/integration/log-viewer-12047?locale=ja-JP
* Android StudioのProfilerでCPUやメモリ確認
    * https://developer.android.com/studio/profile/cpu-profiler?hl=ja
* シーン内のオブジェクト全部削除
* 新規プロジェクトの作成
* 端末で他のサードパーティ製アプリで同じく放置してみる
* Unityのダウングレード
* 色々な端末向けにビルド
    * iPhone向けにしてみたり、PC向けにしてみたり
* 色々なビルド設定で虱潰しに
DHCP Discoverのパケットをscapyで解析してクライアントのホスト名を表示する

# はじめに
多くのブロードバンドルーターはDHCP ( Dynamic Host Configuration Protocol ) を用いてネットワーク機器に自動的にIPアドレスを割り当てる。DHCPでは初めにDHCPクライアント（ネットワーク機器）がDHCPサーバー（ブロードバンドルーター）に問い合わせをするためにLAN内の全ての宛先（ブロードキャスト）にDHCP Discoverメッセージを送信する。多くの場合、このDHCP Discoverメッセージの中のオプションにクライアントのホスト名が含まれる。このホスト名を抽出することが今回の目標である。


# 環境
Raspberry Pi OS (32-bit)
Python 3.7.3
scapy==2.4.5

# DHCP Discoverメッセージ（DHCPクライアント->DHCPサーバー）をtcpdumpで取得する

```
sudo apt-get install tcpdump
```
tcpdumpをインストール

```
sudo tcpdump -i wlan0 dst port 67 -w test.pcap
```

- `-i wlan0`: 監視するネットワークインターフェースを指定。`wlan0`は無線LAN。
- `dst port 67`: 宛先ポートが67であれば真。67はDHCPクライアントがDHCPサーバ宛にパケットを送る際のポート番号。
- `-w test.pcap`: `test.pcap`というファイル名でログを保存。


# scapyでパケットを解析しホスト名を表示する

```
pip3 install --pre scapy[basic]
```
pipでscapyをインストール。

```parse_dhcp_discover_packet.py
from scapy.all import *
from datetime import datetime

pcap_path = "test.pcap"

packets = rdpcap(pcap_path)

for packet in packets:
    try:
        options = packet[DHCP].options
        for option in options:
            if option[0] == 'hostname':
                hostname = option[1].decode()
                print('Time: {} | Hostname: {}'.format(datetime.fromtimestamp(packet.time), hostname))
    except IndexError as e:
        print(e)
```

```
python3 parse_dhcp_discover_packet.py
```
パケットが送信された時刻とDHCPクライアントのホスト名が表示される。


**上記のコードを補足**

```python
from scapy.all import *
from datetime import datetime
```
必要なモジュールをインポート。

```python
pcap_path = "test.pcap"

packets = rdpcap(pcap_path)
```
tcpdumpで取得したログ（test.pcap）をrdpcapで読み込む。

```
<Ether  ... |<IP  ... |<UDP  ... |<BOOTP  ... |<DHCP  options=[... hostname=[ホスト名] ...] |>>>>>
```
packetは上記のように構成されている。`packet[DHCP]`とすることでDHCPの情報のみ取得できる。
`packet[DHCP].options`でoptionsを取得する。`options`はiterableなのでforで`option`を一つ一つ取り出す。
`option`のキー`option[0]`が`'hostname'`であるとき、`option[1].decode()`がホスト名となる。


# 参考
- TCP/IP - DHCP: https://www.infraexpert.com/study/tcpip13.html
- Download and Installation: https://scapy.readthedocs.io/en/latest/installation.html
- Scapy入門: https://qiita.com/Howtoplay/items/4080752d0d8c7a9ef2aa
- Scapy 2.4.5 documentation: https://scapy.readthedocs.io/en/latest/api/scapy.utils.html
- Usage: https://scapy.readthedocs.io/en/latest/usage.html
Formsで実施したアンケート結果を指定フォーマット（Excel）へ自動転記する方法

こんにちは。
本日は、Microsoft365アプリケーションの1つであるアンケート作成ツールFormsで実施した
アンケート結果（Excel）を指定のExcelフォーマットへ自動転記してみました。

#作成理由
アンケート結果を指定フォーマットに転記する仕事は上司に指示された仕事で、私の仕事の1つでもあります。
上司から仕事を任される前に指定フォーマットについて、「意見があるなら言ってください」と言われていたものの、上司を目の前にして意見を言うことなど出来ず、結局めんどくさい仕事をするという羽目になりました。
（私は毎月8名分を指定フォーマットに転記しなければならない中、誰一人として8月分まで終わってないという実態・・・）
なので少しでも楽に早く仕事を終わらすことができないかと考え、作成することにしました。



#作成の流れ
**実施したいこと**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811930/3933ab34-b071-881c-0baf-098586f7f1b4.png)
**メインフローの処理**
フォルダの中に入れたアンケート回答結果を立ち上げ、サブフローの処理を実施。
処理が終わったら、自動保存しExcelを閉じてくれるように設定しています。
アンケート回答結果分が実施できるようにループ設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811930/89989047-9853-7a69-68c0-d756db85aee7.png)
**サブフローの処理**
サブフローでは、アンケート結果を読み取り、
指定フォーマットに処理してくれるように設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811930/3e48b267-21a9-5857-e756-b1d4d5ab8ed9.png)

**完成物**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811930/d08e2dc6-1018-4a8d-5c59-3483c5aad04e.png)



実際のPower Automate Desktopの流れはこちら
<iframe width="560" height="315" src="https://www.youtube.com/embed/ABXJMtZZxcM" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>






#使用したもの
Power Automate Desktop

#感想
初めから「もっと楽に転記できるように設定してください」と言えばよかったと後悔はしましたが、
上司に改善策を持って意見することができるようになったので良かったかなと思います。

今後、私に部下ができたときは部下の仕事が少しでも楽になるよう
自動化の設定をして仕事を託そうと思います。

最後まで読んでいただき、ありがとうございました。
Window関数についての知識をまとめた(その2)

## はじめに

データ分析における重要な関数そうなので、何章かに分けて、Window関数についてまとめています。

前回の記事は👇

https://qiita.com/ryosuketter/items/abf629ba3eb4e5daa861

今回もいくつかのサンプルを用意して説明します。

今回は、Window関数の機能一覧の紹介と、Window関数の典型的な利用ケースである移動平均を紹介していきます。

今回もSQLの実行は 「DB Fiddle」というWebサービスを使ってみます。

https://www.db-fiddle.com/

## Window関数の機能一覧の紹介

Window関数の機能を1枚絵で俯瞰してみましょう。

![スクリーンショット 2021-08-15 15.54.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/e1137e31-fc97-d28a-3363-7c3595a53dc1.png)

以下の論文から引用してます。

[Efficient processing of window functions in analytical SQL queries \| Request PDF](https://www.researchgate.net/publication/282463017_Efficient_processing_of_window_functions_in_analytical_SQL_queries)

3つの機能から成り立っていることが分かります

- PARTITION BY 句によるレコード集合のカット
- ORDER BY 句による順序づけ
- フレーム句による現在の行を中心とした範囲の定義

## Window関数で移動平均を算出

当日と前日の単純移動平均を計算してみましょう

参考

https://www.jma.go.jp/jma/menu/menureport.html

Schema (MySQL v8.0)

```sql
CREATE TABLE temperatures (
  id INT NOT NULL PRIMARY KEY auto_increment,
  date DATE,
  city_name TEXT,
  avg_temp FLOAT
);

INSERT INTO temperatures VALUES
	(1, '2020-12-01', '東京', 10.0),
	(2, '2020-12-02', '東京', 9.0),
	(3, '2020-12-03', '東京', 8.0),
	(4, '2020-12-04', '東京', 7.0),
	(5, '2020-12-01', '愛知', 11.0),
	(6, '2020-12-02', '愛知', 10.0),
	(7, '2020-12-03', '愛知', 9.0),
	(8, '2020-12-04', '愛知', 8.0);
```

Query

```sql
SELECT
	date AS 日付,
    city_name,
	AVG(avg_temp) OVER avg_temp_2days AS '移動平均2日間'
FROM temperatures
WINDOW avg_temp_2days AS (
	PARTITION BY city_name
   ORDER BY id ASC
   ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
);
```

ウィンドウ関数のフレーム句で使用できるオプション

- ROWS: 移動単位を行で指定
- n PRECEDING: nだけ前（小さい方）へ移動する
- CURRENT ROW: 現在行

Results

| 日付         | city_name | 移動平均2日間 |
| ---------- | --------- | ------- |
| 2020-12-01 | 愛知        | 11      |
| 2020-12-02 | 愛知        | 10.5    |
| 2020-12-03 | 愛知        | 9.5     |
| 2020-12-04 | 愛知        | 8.5     |
| 2020-12-01 | 東京        | 10      |
| 2020-12-02 | 東京        | 9.5     |
| 2020-12-03 | 東京        | 8.5     |
| 2020-12-04 | 東京        | 7.5     |

[View on DB Fiddle](https://www.db-fiddle.com/f/cWYC2BCKjhA5h47sEAkgss/2)

## 参照

https://www.amazon.co.jp/dp/4798157821/

29 - 35p 

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103
8月13日よりgithubでパスワードでプッシュできない。


プッシュできなくて焦りました。
どうやらトークンが必要とのこと。

```
% git push origin main
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
```



##自分の場合(mac)
*環境や今までのpush方法が異なる方もいらっしゃるかもしれないので、
実行は個人判断でお願いします。

 GitHubで 
Settings → Developer settings → Personal access tokens　と進んで、

Generate new Tokenで新しく作成、
期限を記入して、
repoとadmin:repo_hookとdelete_repoのチェック。
画面下部のGenerateTokenで生成完了。

![スクリーンショット 2021-08-15 16.34.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244070/bc40bed8-4574-c0c5-0567-71d5606fc677.png)

生成したTokenをコピー。



finderでチェーンアクセスを検索
チェーンアクセスでgithub.comのを検索（種類はインターネットパスワード）
![スクリーンショット 2021-08-15 16.30.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244070/6f5a9cc5-5cdf-344a-46ea-c97f397011fd.png)

パスワードを表示から、既存のパスワードを削除して、先程のトークンを記入。
![スクリーンショット 2021-08-15 16.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244070/2098c298-181d-a9c9-e2a2-71698a3987c0.png)


私の手元ではpushできました。

```
% git push origin main
```



*タイムリーな話なので、追記修正あったらご教授いただけますと幸いです。


###キーチェーンがない場合(追記)

git push した時のgithubのユーザー名とパスワードで、
パスワードをさっきコピーしたtokenを入れるとOKです。



公式
https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/
https://docs.github.com/ja/github/getting-started-with-github/getting-started-with-git/updating-credentials-from-the-macos-keychain
https://docs.github.com/ja/github/authenticating-to-github/keeping-your-account-and-data-secure/creating-a-personal-access-token

参考
https://zenn.dev/suzuki_hoge/articles/2021-08-github-access-f732e5b9868137
散布図と相関係数、ざっくり目視確認



#1.目的と結果

【目的】
　2つの分布(ここでは平均0、分散1の正規分布)の散布図と相関係数の値の関係がざっくりわかるGIFファイルをつくること。

【結果】
　以下のようにできた。

![相関θ依存.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613560/d24ffbff-9785-eca0-b24e-740f2981bae9.gif)


#2.乱数の準備
それぞれ独立に平均0,分散1の正規分布に従う乱数$x_1,x_2$を生成。
(ここで分散1の分布を扱うので、以下では共分散算出値＝相関係数として扱う)

```python
import numpy as np
import pandas as pd

np.random.seed(1) #乱数を再現できるようにnp.random.seed(1)としておく
df=pd.DataFrame() #DataFrameに複数サンプルデータを格納する
df['x_1'] = np.random.normal(0, 1, 2000)
df['x_2'] = np.random.normal(0, 1, 2000) 

```

#3.乱数の変換
上で生成した相関のない乱数$x_1,x_2$を以下(1)式のような変数変換で相関のあるデータ$y_1,y_2$を生成。

```math
\begin{eqnarray}
y_1 &=& x_1 \tag{1} \\
y_2 &=& x_1 \sin{\theta} + x_2 \cos{\theta} \tag{2}
\end{eqnarray}
```

ここでは$y_2$の分散を1にするため、式(2)右辺の$x_1$、$x_2$のそれぞれの係数を$\sin{\theta}$、$\cos{\theta}$としている。
「4.グラフ(gifファイル)作成」のグラフでは$\theta$を振ってグラフの分布を変えている。

相関係数は(1)、(2)より$\sin{\theta}$となる。
(gifファイル出力の「相関係数(計算値)」は$\sin{\theta}$。なお乱数から相関係数を算出した結果は「相関係数(実測値)」と暫定的に名付けた)

#4.グラフ(gifファイル)作成

以下のコードでgifファイルを作成。

```python
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_aspect('equal')

def plot(deg):

    plt.cla()
    
    theta = 2*np.pi*(10*deg)/360
    
    y_1 = df['x_1'] # 式(1)部分
    y_2 = np.sin(theta)*df['x_1'] + np.cos(theta)*df['x_2']# 式(2)部分

    corr_cal = np.sin(theta) #グラフタイトルの相関係数(計算値)の値
    corr_sample =y_1.corr(y_2) #グラフタイトルの相関係数(実測値)の値

    plt.plot(y_1, y_2,"o", c='blue',alpha =0.1)
    
    plt.xlim(-4,4)
    plt.ylim(-4,4)
    
    plt.xlabel('$y_1$')
    plt.ylabel('$y_2$')
    plt.grid()

    plt.title('θ={}°、相関係数(計算値)={:.2f}、相関係数(実測)={:.2f}'
              .format(deg*10,corr_cal,corr_sample),fontname="Meiryo")

# アニメーション作成
anim = FuncAnimation(fig, plot, frames=36,interval=750)
anim.save('相関θ依存.gif', writer='Pillow')
```

ここから出力される`相関θ依存.gif`がつくりたかったgifファイル。
今回は正規分布に従う乱数で行ったが、
`df['x_1'] = np.random.normal(0, 1, 2000)`と`df['x_2'] = np.random.normal(0, 1, 2000)`を変えれば
他の分布についても同様のことができるはず。


#6.参考URL
以下のサイトを勉強し、参考にさせていただきました。

・[[Python/matplotlib] FuncAnimationを理解して使う](https://qiita.com/osanshouo/items/3c66781f41884694838b)
・[matplotlibのanimationで一枚ごとに違うタイトルを付けたい](https://teratail.com/questions/159258)


以上。
【アニメーション向け】async/await で待機時間を指定し順次実行する方法

# 目的
- `async/await` を使って順次実行する方法を例示する。
- アニメーションなど、待機時間を指定して順次実行するもの例示とする。


# 前提
`async/await` の処理でよく例示されるのは `API` 周りのものが多いと思う。
一方アニメーション関連で、 `async/await` を使いたいと感じたが例が少ないと思ったのでまとめる。

# やりたいこと
自然言語で書くと、以下のようになる。
これをネストなどなくシンプルに書きたい。

```
・ 500msかけて ボールを投げる
・ 100msかけて バットを振る
```

# 準備
時間指定をして実行を遅らせる `delay` メソッドを作っちゃえば事足りる。
`duration` の時間だけ実行を遅らせる。

```ts
const delay = (duration: number) => {
  return new Promise((resolve) => {
    setTimeout(() => resolve(null), duration);
  });
};
```

# 使い方
## シンプルな使い方
一番単純には、以下のようになる。 
`startThrowingBallAnimation` と `startSwingingBatAnimation` は アニメーションを開始させるだけで、アニメーションの終了をフィードバックしたりはしない。

```ts
(async () => {
  startThrowingBallAnimation();
  await delay(500);
  startSwingingBatAnimation();
  await delay(100);
}();
```

## メソッドをまとめる
待ち時間と実行アニメーションをメソッドにまとめると便利になる。
`async` をつけて、 `delay` と アニメーションのメソッドを一緒にする

```ts
const throwBall = async () => {
  startThrowingBallAnimation()
  await delay(100);
}
```

引数を取ることや、戻り値を取ることもできるので、待ち時間を可変にしたりアニメーションメソッドの戻りを返したりもできる。

```ts
const swingBat = async (duration: number) => {
  const bat = startSwingingBatAnimation()
  await delay(duration);
  return bat;
}
```

自然言語に近い書き方で記述できた。

```ts
(async () => {
  throwBall();
  const bat = swingBat(100);
}();
```
年月日入力時のバリデーション実装(PHP)

##日付入力のバリデーションを実装したときの記録

今回は年月日の入力の際のバリデーションを実装した。
入力して欲しい形式は(YYYY-MM-DD)とした。(月日は1桁でもデータベースには登録できるが今回はこの形式にした)

段階としては下記の2段階で行った
1. 日付の形式が正しいかどうかチェック(YYYY-M-DやYYYYMMDDなどが入力されたときにエラー)　
2. その日付が存在するかどうかチェック

###実際に使用したコード

```php
    if ((preg_match('/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $internship['test_date']) == false)) {
        $errors['test_date'] = 'WEBテスト締め切り日の形式が正しくありません';
    } else {
        list($year, $month, $day) = explode('-', $internship['test_date']);

        if (checkdate($month, $day, $year) == false) {
            $errors['test_date'] = 'WEBテスト締め切り日が正しくありません';
        }
    }
```
AWS上にサーバーを作る（その04：Amazon EC2インスタンスを起動）

前回の投稿
[AWS上にサーバーを作る（その03-02：Amazon VPCの設定）](https://qiita.com/aa_ha1uhik0/items/8ee966001fdfefd5eeff)


# インスタンスを起動
開始するには、クラウド内の仮想サーバーである Amazon EC2 インスタンスを起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/58e3dea3-9e36-9e9a-8ec7-d0223468a812.png)

## ステップ 1: Amazon マシンイメージ (AMI)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/c40f9145-6d02-82f0-e766-f3c73fd034e3.png)

> AMI は、インスタンスの作成に必要なソフトウェア構成 (OS、アプリケーションサーバー、アプリケーション) を含むテンプレートです。 AMI は、AWS が提供するもの、ユーザーコミュニティが提供するもの、または AWS Marketplace に掲載されているものを選択できます。独自の AMI のいずれかを選択することもできます。

ここで、作成する仮想マシンのベースとなるイメージを選択します。
とりあえず、安くすませたいので、今回は「Amazon Linux」かつ「64ビット(Arm)」を選択。
一応、Windows ServerやRedHatみたいなイメージも準備されているので選べる。

## ステップ 2: インスタンスタイプの選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/b0297992-a8f8-e040-8f61-7bcad6ef6688.png)

> Amazon EC2 では、異なるユースケースに合わせて最適化されたさまざまなインスタンスタイプが用意されています。インスタンスとは、アプリケーションを実行できる仮想サーバーです。インスタンスタイプはさまざまな CPU、メモリ、ストレージ、ネットワークキャパシティの組み合わせによって構成されているため、使用するアプリケーションに合わせて適切なリソースの組み合わせを柔軟に選択できます。インスタンプタイプおよびそれをコンピューティングのニーズに適用する方法に関する[詳細はこちら](https://aws.amazon.com/ec2/instance-types/)。

ここでは、仮想マシンのスペックを選択。
ここでも安くすませたいので、タイプ：t4g.nanoを選択。

## ステップ 3: インスタンスの詳細の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/bef0da0f-7961-86d6-60af-9aa3836cb8d8.png)
> 要件に合わせてインスタンスを設定します。同じ AMI からの複数インスタンス作成や、より低料金を実現するためのスポットインスタンスのリクエスト、インスタンスへのアクセス管理ロール割り当てなどを行うことができます。

## ステップ 4: ストレージの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/71f8d0b2-b76c-3579-91cc-a4df24361ec7.png)

> インスタンスは次のストレージデバイス設定を使用して作成されます。インスタンスに追加の EBS ボリュームやインスタンスストアボリュームをアタッチするか、ルートボリュームの設定を編集することができます。また、インスタンスを作成してから追加の EBS ボリュームをアタッチすることもできますが、インスタンスストアボリュームはアタッチできません。Amazon EC2 のストレージオプションに関する詳細はこちらをご覧ください

サイズ (GiB)も最低限でよいので「8GiB」を指定。

## ステップ 5: タグの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/87a838e5-6fcc-53ca-503b-39b0a1984b4b.png)
> タグは、大文字と小文字が区別されるキーと値のペアから構成されます。たとえば、キーに「Name」、値に「Webserver」を使用してタグを定義することができます。
タグのコピーは、ボリューム、インスタンス、またはその両方に適用できます。
タグは、すべてのインスタンスとボリュームに適用されます。Amazon EC2 リソースのタグ付けに関する 詳細はこちら。

分かりやすい名前タグを付けておくことにする。

## ステップ 6: セキュリティグループの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520646/1605e4cc-5df7-a52c-9b01-02d009fa7b3f.png)

> セキュリティグループは、インスタンスのトラフィックを制御するファイアウォールのルールセットです。このページで、特定のトラフィックに対してインスタンスへの到達を許可するルールを追加できます。たとえば、ウェブサーバーをセットアップして、インターネットトラフィックにインスタンスへの到達を許可する場合、HTTP および HTTPS ポートに無制限のアクセス権限を与えます。新しいセキュリティグループを作成するか、次の既存のセキュリティグループから選択することができます。Amazon EC2 セキュリティグループに関する 詳細はこちら。

ようはファイアウォールですね。
一旦、今接続している場所のグローバルIPアドレスのSSHだけ許可しておく。
ちなみに「ソース」のところで、「マイIP」を選択すると、自動で現在のグローバルIPを入力してくれるみたい。

## ステップ 7: インスタンス作成の確認

> インスタンスの作成に関する詳細を確認してください。各セクションの変更に戻ることができます。[作成] をクリックして、インスタンスにキーペアを割り当て、作成処理を完了します。

最終的に設定内容を確認して、「起動」ボタンをクリック。

# 次回の内容
ようやく仮想マシン起動まできた！！
次は起動した仮想マシンに接続するところから？？（まだ引っ張る）

To be continued...
ローカルで起動しているapacheを停止する方法

docker-compose upをした際に、「Cannot start service laravel.test: Ports are not available: listen tcp 0.0.0.0:80: bind: address already in use」と表示された。

ローカルのapacheが起動しており、80ポートを使っているのが原因だったが、apacheを停止するのに意外と手間取ったので忘備録として書いておく。


```
ps aux | grep httpd
XXXXXXXXX        80825   0.0  0.0  4277624    692 s001  S+    3:36PM   0:00.00 grep httpd
_www             80823   0.0  0.0  4298400    808   ??  S     3:36PM   0:00.00 /usr/sbin/httpd -D FOREGROUND
root             80819   0.0  0.0  4298528   3168   ??  Ss    3:36PM   0:00.40 /usr/sbin/httpd -D FOREGROUND
```

やはり起動している。止めようと思って「sudo apachectl stop」を実行してみても、httpdは起動していないと言われる。

```
sudo apachectl stop
httpd (no pid file) not running
```

apatchctlが実行されているパスを調べてみる。

```
 which apachectl
/usr/local/bin/apachectl
```

httpdのプロセスが起動しているパスは「/usr/sbin/httpd」だったので、どうやらローカルの違う場所にあるhttpdが実行されているらしい。

ということで、apachectlをフルパスで指定してstopを実行。

```
sudo /usr/sbin/apachectl stop
```

無事httpdのプロセスが停止して、docker-compose upが実行できた。
【初心者向け】GitHubのHTTPS認証方法について

##1. はじめに
2021/8/13以降、GitHub の HTTPS 認証時にベーシック認証が使用できなくなりました。
というのも、リモートリポジトリにプッシュする際にベーシック認証を使用している場合、以下のようなエラーが出るようになったからです。

`remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: unable to access 'リモートリポジトリのURL': The requested URL returned error: 403`

##2. 記事対象者
Macユーザーでかつ2021/8/13以降に Github のリモートリポジトリにプッシュしようとしている人。
または一度設定はしたけど認証方法について忘れた人向け。

##3. やること
1. GitHub 上でパーソナルアクセストークンを発行する
2. Keychain Access に登録されているパスワード情報を編集する

**GitHub 上でパーソナルアクセストークンを発行する**
GitHub にログインし、Settings > Developer settings > Peresonal access tokens を開く。
↓
トークンに渡したい権限を設定し、名前をつけてトークンを生成する。
↓
生成したパーソナルアクセストークンをコピーする。

**Keychain Access に登録されているパスワード情報を編集する**
`command + space`で Spotlight Search を開き、 Keychain Access を開く。
↓
Search から github.com を検索して開く。
↓
Show password をクリックし、表示されたパスワードをパーソナルアクセストークンで置き換えて保存する。

**パスワード情報を編集した後**
パーソナルアクセストークンに設定した期限が切れたら、同様の作業にてパスワードのアクセストークンを入れ替えて作業する。
【6章】Javaを学ぼう

今回の記事はif文、条件分岐について記事を書いていきたいと思います。
私自身のアウトプットの場となりますので、よろしくお願いいたします！

#条件分岐
特定の状況のときだけある処理を行う、ということを**条件分岐**といいます。
##if文について
最もよく使う条件分岐である**if文**について解説していきたいと思います。

```java:Main.java
if(条件式) {
 処理;
}

//条件式、処理を当てはめる
if (天気 == 雨) {
 傘を持っていく;
}
```

ifは英語で「もし〜なら」という意味です。この「〜」に当たる部分が、ifの後の()の部分です。これを**条件式**と呼びます。条件式がtrueなら{}内の処理を行い、反対に条件式がfalseなら何もしません。
それではもう少し具体的に、if文を使ってみたいと思います。


```java:Main.java
//if文①
int x = 5;
if(x == 5) {
 //trueになる  
 System.out.println("xは5です");
}

//if文②
int x = 10;
if(x == 5) {
 //falseになる  
 System.out.println("xは5です");
}

```

出力結果↓

```java:コンソール
//if文①
xは5です  //trueのため実行される

//if文②
        //falseのため実行されない

```

##ブロック
if文で{ }という記号を使っていますが、複数の処理をまとめたいときに使います。これを**ブロック**と呼び、条件がtrueのときに行う処理を、ブロックを使ってまとめています。

```java:Main.java
int x = 10;
if(x > 5) { 
 System.out.println("条件はtrue");
 System.out.println("xは5より大きい");
 //複数の処理をまとめている
}

```

出力結果↓

```java:コンソール
条件はtrue

xは5より大きい
```

##elseについて（ifとelseの組み合わせ）
ifとelseを組み合わせると、「もし〜なら◯◯、そうでなければ△△」という条件分岐が可能になります。
{ }の位置など注意してください！

```java:Main.java
//if文①
int x = 5;
if(x < 15) {
 //trueになる  
 System.out.println("xは15より小さい");
} else {
 System.out.println("xは15以上");
}


//if文②
int x = 10;
if(x < 5) {
 //falseになる  
 System.out.println("xは5より小さい");
} else {
 System.out.println("xは5以上");
}

```

出力結果↓

```java:コンソール
//if文①
xは15より小さい

//if文②
xは5以上

```

##else ifについて
if文ではelse ifを用いて、さらなる条件分岐が可能です。
ifとelse if、elseを組み合わせると、「もし〜なら◯◯、そうではなくてもし××なら△△、どちらでもない場合は□□」という条件分岐を可能にできます。

```java:Main.java
//if文①
int x = 30;
if(x >= 35) {
 //falseになる  
 System.out.println("xは35以上");
} else if(x > 25){
 //trueになる
 System.out.println("xは25より大きく、35より小さい");
} else {
 System.out.println("xは25以下");
}


//if文②
int x = 15;
if(x >= 35) {
 //falseになる  
 System.out.println("xは35以上");
} else if(x > 25){
 //falseになる
 System.out.println("xは25より大きく、35より小さい");
} else {
 System.out.println("xは25以下");
}

```

出力結果↓

```java:コンソール
//if文①
xは25より大きく、35より小さい

//if文②
xは25以下
```

else ifは必要なだけ並べることができますが、複数の条件に合致しても、実行されるのは**最初に合致した条件だけ**になります。注意してください。

以上がif文についての説明になります。次章では、条件分岐の時に使用する、もう一つの構文である**switch文**について記事を書きたいと思います。よろしければご覧になってください！

最後までご覧いただきまして、ありがとうございました！
「受領しました」と返信する作業やOutlookで受信したPDFデータを1つのファイルへ保存する作業を自動化したい！

##「受領しました」と返信する作業やOutlookで受信したPDFデータを1つのファイルへ保存する作業が非常に面倒くさい！
毎月Outlookで取引先から、請求書のPDFが送付されてくるが、各社毎1通ずつ送付されてくる為、手作業で、一つのファイルにまとめて、内容を確認する作業が非常に面倒くさいと思う今日この頃です。
また、失礼がないように、「受領しました」と簡単な言葉になりますが、メールに記載し、返信する事も非常に面倒くさいと思っております。PDFデータを自動で一つのファイルに集約してくれる機能やメールを自動で返信してくれる機能があると便利だな～と思いながら、今回PowerAutomateDesktopを活用し、課題解決に繋がるシステムを制作してみました。

##【制作したもの】
・指定の宛先から、受信したPDFデータを1つのファイルへ自動集約
・「受領しました」と自動返信

【PowerAutomateDesktopフロー】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/cbea07a3-c520-2760-5f45-726e38ef623a.png)

①Outlookを起動します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/bf96d142-d190-2521-5b32-b8735536cc38.png)
②Outlookからメッセージを取得します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/cb33094c-8872-598a-c77b-60ef892d8c11.png)
③フォルダ内のファイルを取得
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/5d1e89a7-8c34-c968-6677-373a2cb44ea9.png)
④For each
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/5509e368-00ff-e77b-3e70-e2fc7faed5a5.png)
⑤PDFからテキストを抽出
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/a029e40d-1c93-1961-00ec-700fc40b0855.png)
⑥メッセージを表示する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/674813d9-c9bf-82fb-8819-e78f8c9be60f.png)
⑦End
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/495192f2-cac1-2b41-c067-e3cc7bfcd287.png)
⑧Outlookからのメールメッセージの送信
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/361376e4-e849-7786-f940-6abef72cf327.png)
⑨Outlookを閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/da189f95-987e-d357-6379-6be10fcf3a06.png)
##【完成イメージ】
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1793863/62b7ee7a-f8fd-07ee-c846-4807d7d44754.png)

##【まとめ】
日頃の業務課題について、改めて見直し、PowerAutomateDesktopを活用し、業務効率化に繋がる仕組みを制作致しました。
まだまだ技術的課題が多いが、スキルを磨き、より使いやすく業務効率化に繋がる仕組みを構築していきたいと思います。

【今後解決したい課題】
https://twitter.com/EgashiraYosuke/status/1426554429050822657
AWS CLI でS3のバケット名を変更した

## はじめに

教材でAWS演習をこなして学習している中、
S3のバケット名を曖昧に決めてしまったことが原因で
Route53でドメイン名を取得できないことに気づく。

「じゃあ、S3を作り直すか…」と思っていたが、
`AWS CLIを使ってバケット名を変更する方法がある`と情報をゲット。
（学習教材にもその場合はググって調べたら何とかなると書いてあった。）

そこで、学習がてらネットで情報収集して
解決できたので対応記録としてまとめる。

`OS：MAC`


## 教材

・ゼロからわかる Amazon Web Services超入門



## そもそもAWS CLIって？

AWSは、マネジメントコンソールからGUI（ボタン操作など）で
EC2やS3などのインスタンス作成したり、VPCのネットワークを構成したりなど
インフラ構成ができる。

それに対して、CLIはターミナル内で
コマンドを入力して、各種インフラ構成をすることと
ざっくり認識しておく。

おそらく、細かく言うとできることも異なると思う…



## 目的

目的は`S3のバケット名を変更すること`

恥ずかしいことに、私の場合はS3を下記のようなバケット名にしてしまっていた。

■バケット名
www.〇〇〇〇〇.▽▽▽▽▽.com

Route53で「〇〇〇〇〇.▽▽▽▽▽.com」ドメイン取得しようとしたら
登録できないと言われてしまった。

一方で.▽▽▽▽▽の部分を削除すると取得できるみたいだった。
演習だからといってテキトーに決めすぎた自分が悪い。笑

ということで、AWS　CLIで

www.〇〇〇〇〇.com

に修正しよう！という目論見。



## 早速CLI使ってみる

ネットで、`S3バケット名の変更`に関連する
AWS　CLIコマンドを発見したので、試してみる。

```:ターミナル

% aws s3 mb s3://www.〇〇〇〇〇.com    

```

すると、下記エラーが発生。

`AWS fatal error: Unable to locate credentials`

aws公式ページが下記エラーの原因を示してくれていたので、
自分が`AWS CLIの基本設定を行えていない`と気づけた。

https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-locate-credentials-error/



## では、AWS CLIの基本設定


aws公式ページより基本設定の手順に従って基本設定を行う。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-region

この時、設定するためのaws configureコマンドをする前に、

`1.マネジメントコンソールでIAMを開き、指定ユーザーのアクセスキーを作成`
`2.使用するリージョンを確認`
`3.出力形式の種類を理解`

を用意しておく。

※上記のうち、`1.は特に理解して進める。`
（手順はaws同ページに参照されている。）

```:ターミナル

% aws configure

AWS Access Key ID [None]: アクセスキーID
AWS Secret Access Key [None]: 秘密鍵のコード
Default region name [None]: リージョン（ap-northeast-1など）
Default output format [None]: json

```

上記のように、aws configureコマンドで一つ一つ入力して
４つの基本設定を完了させる。

これで、AWS CLIコマンドがターミナル上で使用できる。


## S3のバケット名を変更

前置きとして、`S3には作成後にバケット名を変更する機能はない。`
そのため、以下手順で進めていく。

`１、新しくS3のインスタンスを作成`
`２、既存のS3内にあるデータを、新しいS3にコピー`
`３、既存のS3を削除`

※参考URL

https://code-examples.net/ja/q/279687a


コマンドは以下の通り。

```:ターミナル

% aws s3 mb s3://新規S3のバケット名

% aws s3 sync s3://既存S3のバケット名 s3://新規S3のバケット名

% aws s3 rb --force s3://既存S3のバケット名


最後に本当にS3を作成できたか確認
% aws s3 ls 


```

上記まで完了すれば、マネジメントコンソール上でも反映されていることが確認できる。



## 終わりに

AWS CLIコマンドの使用は、現時点で必須ではなかったが
失敗を機会に出会えて良かった。

恐らく、インフラのコード化する際にも
お世話になるのではないかな？と想像している。

最後までお読み頂き、ありがとうございました。
Window関数についての知識をまとめた(その1)

## はじめに

データ分析における重要な関数そうなので、何章かに分けて、Window関数についてまとめてみます。

ドキュメントばかり見てもわかりにくいので、いくつかのサンプルを用意して説明します。

今回は、トリアヘズ動かして、集計関数との違いをまとめています。

## MySQL における Window 関数

自分はMySQLをよく使うのでMySQLにおけるWindow関数について述べます。

MySQL でも 8.0 から Window 関数が使えるようになったそうです。

https://dev.mysql.com/doc/refman/8.0/en/window-functions.html

自分のローカルの環境では、バージョンが古く使えないので、試せない。

```
$ mysql --version
$ mysql  Ver 14.14 Distrib 5.6.47, for osx10.13 (x86_64) using  EditLine wrapper
```

そこで、ブラウザ上からMySQL 8.0 の環境を試せる 「DB Fiddle」というWebサービスを使ってみます。

https://www.db-fiddle.com/

## Window関数とは

現在の行に対して、指定したグループ全体から見た集計値を計算する関数

GROUP BYなどの集計関数との違い

- 集計関数： 同じカラム値をもつ全行を一つに集計する（1行に集約される）
- Window関数： 行ごとに単一の値を返す（対象の行はそのまま残る）

BigQuery StandardSQLのドキュメントに Window関数 は 分析関数と呼ばれています。

そこでは、以下のように書かれています。

> 分析関数は、行のグループに対して値を計算し、各行に対して 1 つの結果を返します。これは、行のグループに対して 1 つの結果を返す集計関数とは異なります。

https://cloud.google.com/bigquery/docs/reference/standard-sql/analytic-function-concepts?hl=ja

### 実行してみて違いを見てみよう

Schema (MySQL v8.0)

```sql

    CREATE TABLE tests (
        id INT NOT NULL PRIMARY KEY auto_increment,
        category_id INT NOT NULL,
        val INT NOT NULL
    );
    
    INSERT INTO tests VALUES
        ( 1, 100,     1),
        ( 2, 200,     2),
        ( 3, 100,    10),
        ( 4, 200,    20),
        ( 5, 100,   100),
        ( 6, 200,   200),
        ( 7, 100,  1000),
        ( 8, 200,  2000),
        ( 9, 100, 10000),
        (10, 200, 20000);
```

Query

```sql
    SELECT
      category_id,
      SUM(val) AS total
    FROM tests
    GROUP BY category_id;
```

Results

| category_id | total |
| ----------- | ----- |
| 100         | 11111 |
| 200         | 22222 |


予想通りの出力かなと思います。

Window関数を用いると...

Query

```sql

    SELECT
    	id,
      category_id,
      val,
      SUM(val) OVER (PARTITION BY category_id) AS total
    FROM tests;
```

Results

| id  | category_id | val   | total |
| --- | ----------- | ----- | ----- |
| 1   | 100         | 1     | 11111 |
| 3   | 100         | 10    | 11111 |
| 5   | 100         | 100   | 11111 |
| 7   | 100         | 1000  | 11111 |
| 9   | 100         | 10000 | 11111 |
| 2   | 200         | 2     | 22222 |
| 4   | 200         | 20    | 22222 |
| 6   | 200         | 200   | 22222 |
| 8   | 200         | 2000  | 22222 |
| 10  | 200         | 20000 | 22222 |

---

[View on DB Fiddle](https://www.db-fiddle.com/f/jMBaDT7t2R9uMBsgmhZA7/1)

行ごとに単一の値（計算結果）を返す（対象の行はそのまま残る）

とはこのことです。実際に実行してみるとイメージは詳細になりましたね。

次回はもう少し詳しく見ていきます。

## 参照

https://www.amazon.co.jp/dp/4798157821/

26-29p

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103
Laravel Forgeにvue.jsだけのSPAをデプロイする方法

## やりたかったこと

Laravel をよく使うので、Laravel Forge + Vultur を使っています（[Forge + Vultr ではじめてLaravelアプリをデプロイするときにつまずいたこと](https://qiita.com/seihowlow24/items/9a663e7640fd1898c866))。

最近、Laravelを使わず vue.jsだけのアプリ（SPA）を作り、本番公開しようとしました。

vue.jsのアプリであればNetlify、GithubPageなどが簡単にできるようですが、せっかく有料でForgeを契約しているのだし等いろいろ事情があり、どうしてもLaravel Forgeにデプロイしたかったのです。


## vue.jsアプリの概要
- vue version 2.5.2
- webpack version 3.6.0

## Github にレポジトリを公開

やり方は簡単です。まずは下準備。

Laravel Forgeは、Githubからソースコードを取り込み、デプロイすることができます。

そのため、Githubレポジトリを作成し、vueアプリのソースコード一式をpush しておきます。



## Laravel Forge でのディレクトリ設定

次に、いつも通りLaravel Forge で新規サイトを設定します。

![スクリーンショット 2021-08-15 15.04.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32771/25f0e520-bc9f-9677-f93a-730c563a2686.png)


この時のポイントは２つ。

１つめは、サイトの種類をStatic HTMLではなくGeneral PHP/Laravel で設定すること。Static HTML だと上手くできませんでした。

２つめは、初期ディレクトリを /dist に設定すること。これは、コンパイルされたファイルがdist フォルダに生成されるためです。



## デプロイスクリプトの書き換え

Laravel Forgeにて、デプロイスクリプトを次のように書き換えます。



```bash
cd /home/forge/www.domain.com
git pull origin $FORGE_SITE_BRANCH
npm install
npm run build

( flock -w 10 9 || exit 1
    echo 'Restarting FPM...'; sudo -S service $FORGE_PHP_FPM reload ) 9>/tmp/fpmlock
```



npm を２行だけ、追加しています。

最初に調べていた時、Laravel Forgeでnpmするとタイムアウトする...などといった情報が出てきましたが、デプロイは普通に実行できました。

デプロイスクリプト以外でコマンドを叩くと、確かにエラーになっていました。

## Nginx Configration File を編集する

最後に、Nginx の設定を変えます。画面下のFilesというメニューからEdit Nginx Configurationを選びます。

![スクリーンショット 2021-08-16 23.01.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32771/0f08d8bb-ae9d-0baf-18e2-55e71a441bad.png)

index.php となっているところを、index.html に変えます。最低限、この１箇所。

```bash
    location / {
        try_files $uri $uri/ /index.html?$query_string;
    }
```
この設定でデプロイすると、vue.jsだけのアプリも公開できます。

## 参考

こちらの解説が大いに参考になりました。

https://www.blog.plint-sites.nl/deploy-vue-single-page-app-on-laravel-forge/
PCについて①

自分が分からなかったことを調べた時のメモです。かなり初心者なので、どしどしご指摘お願いします。

###マザーボード
パソコンの土台となる基板的なやつ。マザーボードには様々なパーツ（CPU、メモリ、電源など）が接続されている。

###CPU（Central Processing Unit）
計算処理や制御を行う、パソコンの頭脳みたいなもの。おおまかに（本当はもっと複雑ですが、、、）コア数・クロック周波数・キャッシュによってこの頭の良さが決まる。
######コア数
作業する人数。ちなみに物理コア・論理コア（スレッド）とあり、例えば4コア8スレッドだと、実際作業する人は4人だけど、みんな右手と左手で合計2つずつ仕事ができて、実質8人分仕事してる感じ（例えが下手くそですみません）
######クロック周波数
1秒間で、電気（信号）を「off(0)」と「on(1)」で切り替えられる回数
######キャッシュ
（何だかよく分かりません。お勉強しといてよ。）

###メモリ
よく机の大きさといわれる。実態はわかりませんが、もうそうやって理解しています(笑)

###ストレージ
データを保管する、棚の大きさみたいな感じ。

###グラフィックカード
モニターに映像を映し出すためのチップ（GPU）が搭載されたボード

###IPアドレス
IP=Internet Protocolの略。（ちなみにProtocolは議定書という意味で、ここでは通信の約束事のことらしい。）PCを識別するための番号。
RSpec内で実装しているAPIリクエストのヘッダーどうする

# RSpec内で実装しているAPIリクエストのヘッダーってどうする
- チーム開発でRSpecでリクエストスペックを書いていたときに人によってRSpec内で定義しているAPIリクエストのヘッダーの書き方がまちまちだったので、ちょっと調べてみた話
- 具体的にはJSONを受け取って、JSONを返すAPIのRSpecの話
- 人によっては `Content-Type: application/json`, `Accept: application/json` を両方つけたり、片方だけ、またはつけていないといったケースがあった

## そもそもRSpecで定義したリクエストでヘッダーつけるか
- 細かい話ですが、下記の理由からつけたほうが良さそうかと思います
- テストコードを書くからにはテストコードからある程度仕様を読み取れたほうが良い
  - クライアントがどんな形式のデータを渡すことを期待しているかは仕様としてわかったほうが良い
  - 実装を読めばどんなデータを受け取っているかはわかるものかもしれないですが、ヘッダーはクライアントとやりとりするデータ形式を記載する場所なのでそれに従うならば書いておくべきかなぁと思いました


## 何をつけるべきか
- 今回はJSONを受け取って、JSONを返すシンプルなAPIなのでヘッダーのフィールド値は少なくとも `Content-Type` と `Accept` が必要そうです
- それぞれの具体的な役割を一応記載しておきます

| ヘッダー名 | 送信(クライアント側で指定可能) | 受信(サーバーサイド側で指定可能) | 説明 |
|----|----|----|----|
| Accept | ○ || ブラウザが、画像の種類など扱えるメディアの種類の候補を送信する。サーバーはこのリストと自分が対応可能な種類を比較し、返すファイルの種類を決める |
| Content-Type | ○ | ○ | 送受信するファイル情報のMIMEタイプを指定する。 text/html, image/png など。(今回の場合は「フロントから送信するデータはJSONですよ」ということを示す情報) |

## `Content-Type` と `Accept` どっちをつけるべきだろうか :thinking: 
- どちらもつけておいたほうが良さそうかなぁと思いました
- というのも今回の場合については `JSONを受け取って、JSONを返す`APIをテストしているのでクライアントから受け取るデータ、サーバーから返すデータについてデータ形式を正しく指定したほうがテストとしては再現性高そうと思ったからです

## おまけ）RSpecでの指定のheader指定の仕方
- [フロントへ返すデータにJSONを指定する](https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec#requesting-a-json-response)

```
require "rails_helper"

RSpec.describe "Widget management", :type => :request do

  it "creates a Widget" do
    headers = { "ACCEPT" => "application/json" }
    post "/widgets", :params => { :widget => {:name => "My Widget"} }, :headers => headers

    expect(response.content_type).to eq("application/json")
    expect(response).to have_http_status(:created)
  end

end
```


- [フロントから渡すデータにJSONを指定する](https://relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec#providing-json-data)

```
require "rails_helper"

RSpec.describe "Widget management", :type => :request do

  it "creates a Widget and redirects to the Widget's page" do
    headers = { "CONTENT_TYPE" => "application/json" }
    post "/widgets", :params => '{ "widget": { "name":"My Widget" } }', :headers => headers
    expect(response).to redirect_to(assigns(:widget))
  end

end
```

- 参考）
  - [Real World HTTP 第2版 ―歴史とコードに学ぶインターネットとウェブ技術](https://www.amazon.co.jp/Real-World-HTTP-%E7%AC%AC2%E7%89%88-%E2%80%95%E6%AD%B4%E5%8F%B2%E3%81%A8%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%8D%E3%83%83%E3%83%88%E3%81%A8%E3%82%A6%E3%82%A7%E3%83%96%E6%8A%80%E8%A1%93/dp/4873119030/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=AX0EHIWYJ8EB&dchild=1&keywords=real+world+http+%E7%AC%AC2%E7%89%88&qid=1629008082&sprefix=real+wo%2Caps%2C266&sr=8-1)