OmniAICreator/Qiita-1.07M huggingface dataset:
【Web開発】JavaScripだけでフォーム送信時にローディング画面を表示

## 概要
フォームなどを送信する際にくるくるアニメーションのローディング画面をJavaScripだけで表示する方法の備忘録。
Djangoなどのフレームワークを使ってWebアプリケーションを開発している場合でも使える。

## 実装
以下のようにフォーム送信ボタンとscriptタグを用意していることを前提とする。
~~~html: sample.html
(フォームなど)
...
<button type="submit">送信</button>
...

<!--bodyタグの最後にscriptタグを入れる-->
<script type="text/javascript" src="sample.js"></script>
~~~

JavaScriptでアニメーションを作成
送信ボタンによってsubmitが発動した時のみローディング画面が表示され、画面のリロードや画面遷移などが行われると消えるため、バリデーションを設定していても大丈夫。

~~~javascript: sample.js
// submit時にローディング画面表示
$('form').on('submit', function(){
    let insertHtml=`
    <!-- loading -->
    <div id="loading"">
        <div class="cv-spinner">
            <span class="spinner"></span>
            <p>送信しています</p>
        </div>
    </div>
    <!-- loading -->
    `
    let insertCSS=`
    <style>
        #loading{
            position: fixed;
            top: 0;
            left: 0;
            z-index: 999;
            width: 100%;
            height:100%;
            background: rgba(0,0,0,0.6);
        }
        #loading .cv-spinner {
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        #loading .spinner {
            width: 40px;
            height: 40px;
            border: 4px #ddd solid;
            border-top: 4px #999 solid;
            border-radius: 50%;
            animation: sp-anime 0.8s infinite linear;
        }
        #loading p {
            line-height: 40px;
            margin: 0 0 0 8px;
            text-align: center;
            color: #ddd
        }
        @keyframes sp-anime {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(359deg); }
        }
        #loading.is-hide{
            display:none;
        }
    </style>
    `
    document.getElementsByTagName('head')[0].insertAdjacentHTML('beforeend', insertCSS);
    document.getElementsByTagName('body')[0].insertAdjacentHTML('afterbegin', insertHtml);
});
~~~

## 参考
ローディング画面のアニメーションについては以下の記事を参考

https://next-k.site/blog/archives/2022/01/12/687
Ruby 預金システムのアルゴリズム問題

# 預金システムのアルゴリズム問題
銀行口座に10万円の預金残高があり、お金を引き出すプログラムを作成します。
- お金を引き出すwithdrawメソッドを作成する
- お金を引き出すと手数料110円かかり、「◯◯円引き落としました。残高は◯◯円です」と表示する（残高は手数料を引いた額を表示します）
- もし預金残高より多く引き落としたら「残高不足です」と表示する

```ruby
# 雛形
def withdraw(balance, amount)
  fee = 110　　# 手数料
# 引き落とし額と残高を表示する、もしくは残高より多く引き落としたら残高不足と表示
end

balance = 100000　　# 残高
puts "いくら引き落としますか？（手数料110円かかります）"
money = gets.to_i
withdraw(balance, money)
```

```ruby
# 自分の解答
def withdraw(balance, amount)
  fee = 110  # 手数料
  if (amount + fee) <= balance
    puts "#{amount}円引き落としました。残高は#{balance - (amount + fee)}円です"
  else
    puts "残高不足です"
  end
end

balance = 100000  # 残高
puts "いくら引き落としますか？（手数料110円かかります）"
money = gets.to_i
withdraw(balance, money)
```

```ruby
#　模範解答
def withdraw(balance, amount)
  fee = 110
  if balance >= (amount + fee)
    balance -= (amount + fee)
    puts "#{amount}円引き落としました。残高は#{balance}円です"
  else
    puts "残高不足です"
  end
end

balance = 100000
puts "いくら引き落としますか？（手数料110円かかります）"
money = gets.to_i
withdraw(balance, money)
```

100000円以下出金する場合は以下のように返ってきました。
```ruby
# ターミナル
いくら引き落としますか？（手数料110円かかります）
9890
10000円引き落としました。残高は90000円です
```

100000円以上出金する場合は以下のように返ってきました。
```ruby
# ターミナル
いくら引き落としますか？（手数料110円かかります）
100000
残高不足です
```

# 解説
money = gets.to_i　で入力した数値 + 手数料110円が100000円以下であれば引き落としは可能。
合計が100001円以上だと、残高不足と返されるように作っていきます。

模範解答では、100000以上の場合は、balance -= (amount + fee)、
つまりbalance = balance - (amount + fee)が処理され、最終的な返り値が出力されるようになっています。

私の解答は、考え方は合っていたように思いますが、コードの書き方？可読性をもう少し考えて書く必要があったように思います。
Slackでチャンネル、メンション、日時指定して繰り返しリマインドを設定する方法

Webで調べると色々出てくるが、細かく説明してくれる分、欲しい情報がピンポイントで出てこなかったりなので、備忘で記事かいちゃう。

# 結論から言うと
適当なチャンネルで以下を送信すれば良し！

```text:ketsuron
/remind #channel @mention "本文" at 09:00 on the 1th of every month
```
![スクリーンショット 0005-03-03 10.12.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504009/f3b1fa8c-6d44-c87e-9a93-c01120c480a4.png)

* 補足
    * #channel：リマインドを投稿したいチャンネル名
    * ＠mention：リマインドしたい宛先（メンション）
    * "本文"：メッセージ本文。ダブルクオーテーション（"）で囲めば長文でもOK
    * それ以降：リマインドしたい日時を指定

リマインドしたい日時は色々な書き方あるようなので調べてみてください。

# ChatGPTで聞いてみれば良いのでは？
結論聞いてみたけど、正確な情報は来なかったですw
情報古いのかも？今後に期待！
![スクリーンショット 0005-03-03 10.29.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504009/8a03b825-e001-cbcc-b78e-26952e7d9295.png)

# 久しぶりに、こちらもチェックお願いします！
[Twitter](https://twitter.com/akibinmusic)
[Youtube](https://www.youtube.com/channel/UC-JOpwEnJn3gCrUA4NdCYgg)
[SoundCloud](https://soundcloud.com/akibin-music)
なんとなくで使っていたundefinedとのunion typeを再確認する

# 結論
```tsx
type HogeInputProps = {
    disabled?: boolean,
} 

type InputWrapperProps = {
    disabled: boolean | undefined, // optionalではない！
}

const HogeInput = ({ disabled }: HogeInputProps) {
    return (
        <InputWrapper
            disabled={disabled} // 必ず渡して欲しいけど、undefinedかbooleanのunion type
        >
            <input disabled={disabled} />
        </InputWrapper>
    )
}
```

「利用側の持つ`disabled`は、optionalなので、存在するかどうかすら怪しい。一方で、`InputWrapper`のpropとしては絶対に存在していて欲しいが、`boolean | undefined`のunion typeであって欲しい。」というときの型です。
`HogeInputProps`と`InputWrapperProps`でどちらもdisabledの型は結果として`boolean | undefined`になりますが、意図して書き分けています。

# どちらも結果としては`T | undefined`のunion type
```ts
type Hoge = {
  fuga?: string,
}
```
と
```ts
type Hoge = {
  fuga: string | undefined,
}
```
はどちらも結果として`T | undefined`のunion typeになりますが意味も挙動も大きく異なります。
前者は
- 渡す渡さないは任意だよ？

という意味合いだったのに対して、後者だと
- 渡さなければならないけど、中に入ってくる値はstringとundefinedのunion typesだよ？

という意味合いになります。

ちなみに、聞いた話だとVuexでこの辺りの違いが致命傷になるらしいです（？
初心者用 形式的冪級数の逆元の定数倍高速化

# はじめに

[前回の記事](https://qiita.com/Suu0313/items/ee9995e24101baab1026) で形式的冪級数の逆元を求める式を書いたのですが, $O(n\log n)$ とはいってもなかなかに定数倍が重いです

NTT-friendly な mod で計算する場合は, もっと定数倍が高速な方法が知られています

[inv を求める方法](https://paper.dropbox.com/doc/fps-EoHXQDZxfduAB8wD1PMBW)

[exp を求める方法](https://web.archive.org/web/20170809063921/https://www.csd.uwo.ca/~eschost/publications/BoSc09-final.pdf)

が公開されていました

ところで, 僕はこれを全く理解していません

僕のような初心者には厳しいので, 軽い実装でそこそこ高速になる方法を紹介します (と思ったんですが, 一個目の記事に載っていました...)

# 本文

前回

```math
g_{n + 1} = 2g_n - f g_n^2
```

というような漸化式で計算していけばいい と書きましたが, $f g_n^2$ の計算が重いです

そこで, ここを少し速くすることを考えましょう

$g_n^2$ の計算をするとき, まず DFT をして要素ごとに二乗して IDFT をしていると思います

ここで, DFT をして要素ごとに二乗してそのままにしてみましょう

IDFT をしてもどうせ $f$ をかけるのでまた DFT することになるためです

つまり,

1. $f, g_n$ の DFT を計算する
1. $f g_n^2$ を DFT した先で要素ごとに計算する
1. 最後に一回だけ IDFT する

とすることで, 回数を減らします

ここで注意なのが, DFT するときに元の数列の長さを $N = 2^n$ とすると普段は長さ $2N$ で計算すればよかったですが今回は $4N$ 必要だということです

三つかけるので補間のために最終的な次数の分計算しないといけないわけですね

これによってどれくらい速くなるのかですが, もともとは

長さ $2N$ の DFT 二回 $+$ 長さ $2N$ の IDFT 一回
$+$ 長さ $4N$ の DFT 二回 $+$ 長さ $4N$ の IDFT 一回

だったのが

長さ $4N$ の DFT 二回 $+$ 長さ $4N$ の IDFT 一回

だけで済みます

うれしい！


# 終わりに

実装量のわりに結構速くなるのでおすすめです

とはいえ 循環をうまく利用する？ やつもいつかは理解しないとね...
gitでリモートブランチからローカルブランチを作成

# gitでリモートブランチからローカルブランチを作成する方法

## はじめてのGit
会社の開発チームで今まで使用していたTFSからGitlabに移行したため、開発を始めるときにはリモートリポジトリから既存のソースコードを取得し、ローカルに反映させてから開発を行う必要がある。

### Gitlabとは？
いわゆるソース管理の一種で「みんなで編集するソースコードを保管しておく場所」である。
TFSとの違いはソース管理の
※もちろんほかにも様々な機能はあるが…
今回記載するのはリモートリポジトリにあるソースをローカルにダウンロードして改修を行うための準備をする方法だ。

### まずは今ローカルにあるブランチを確認
```
git branch -a
```
現在ローカル環境に取得済みのすべてのブランチが表示される
### fetch（リモートリポジトリにあるすべてのブランチを取得）
```
git fetch
```

リモートリポジトリにあるすべてのブランチを取得する
```
git branch -a
```
もう一度ローカル環境のブランチを確認するとorigin/○○○○などfetchで取得できたブランチが新たに追加されている
### fetchしたコードをもとにローカル上に作業用のブランチを作成（チェックアウト）
```
git checkout -b <作成予定のブランチ名> origin/<リモートリポジトリから取得したブランチ名>
```
これでローカル作業用のブランチが作成されるため、作業開始
QC検定　ー　確率分布

確率分布の一覧

| 分類 | 名称 | 　　表記　　 | 期待値 | 　　分散　　 |確率密度関数 | 累積分布関数 | 
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| 連続型  | 正規分布  | $ N(\mu,\sigma^2) $  |  $\mu$ |  $\sigma^2$ |  $\frac{1}{\sqrt{2\pi}\sigma}exp\bigl( -\frac{(x-\mu)^2}{2\sigma^2} \bigr)$ |  $\frac{1}{\sqrt{2\pi}\sigma}\int_{\infty}^{x} exp\bigl( -\frac{(x-\mu)^2}{2\sigma^2} \bigr)dx$ |
| 連続型  | 標準正規分布  | $N(0,1^2)$  |  $0$ |  $1^2$ |  $\frac{1}{\sqrt{2\pi}}exp\bigl( -\frac{x^2}{2} \bigr)$ |  $\frac{1}{\sqrt{2\pi}}\int_{\infty}^{x} exp\bigl( -\frac{x^2}{2} \bigr)dx$ |
| 連続型  | 指数分布  | $Ex(\lambda)$  | $\frac{1}{\lambda}$  | $\frac{1}{\lambda^2}$  |  $\lambda exp(-\lambda x),x>0$ |$1-exp(-\lambda x),x>0$
| 連続型  | 一様分布  | $U(a,b)$  |  $\frac{a+b}{2}$ | $\frac{(b-a)^2}{12}$  | $ \frac{1}{b-a} , a \le x \le b $ <BR> $0 , x < a , x > b$  | $\frac{x-a}{b-a},a \le x \le b $ <BR> $0 , x < a$ <BR> $ 1 , x > b $|
| 離散型  | 二項分布  | $B(n,p)$ <BR> $Bi(np,)$ |  $np$ | $np(1-p)$  |  ${}_n \mathrm{C}_xp^x(1-p)^{n-x}$ | $\sum_{i=0}^x {}_n\mathrm{C}_ip^i(1-p)^{n-i}$ |
| 離散型  | ポアソン分布  |  $P_0(\lambda)$ |  $\lambda$ | $\lambda$  | $ exp(-\lambda) \frac{\lambda^x}{x!} $  | $ \sum_{i=0}^x exp(-\lambda)  \frac{\lambda^i}{i!} $
JAVA　基本文法[3] - 命令実行の文

命令実行の文は、「Javaが準備してくれている様々な命令を呼び出す」為の文です。

::: note info
命令実行の文
呼び出す命令の名前(引数);
:::
カッコの中に記述するのは、「引数（パラメータ）」と呼ばれるもので、その命令を呼び出すにあたって必要となる追加情報。


### 命令の一部を紹介！
●画面に表示する命令

::: note info
画面に表示する
System.out.println();
:::
```Main.java
//例
public class Main {
  public static void main(String[] args) {
    String name = "すがわら";
    String message;
    message = name + "さん、こんにちは";
    System.out.println(message); //画面に表示する
  }
}
/*実行結果
すがわらさん、こんにちは
*/
```

::: note info
改行なしに画面に表示する()
System.out.print();
※連続して呼び出すと表示内容が改行されずに表示される。
:::
```Main.java
//例
public class Main {
  public static void main(String[] args) {
    String name = "すがわら";
    System.out.print("私の名前は");
    System.out.print(name);
    System.out.print("です");
  }
}
/*実行結果
私の名前はすがわらです
*/
```
---
●大きいほうの数値を代入する命令

::: note info
２つの値(若しくは式)を比較して大きいほうの数値を変数に代入する
int 変数名 = Math.max(①, ②);
:::
```Main.java
//例
public class Main {
  public static void main(String[] args) {
    int a = 5;
    int b = 3;
    int m = Math.max(a, b);
    System.out.println("比較実験：" + a + "と" + b + "とで大きいほうは…" + m);
  }
}
/*実行結果
比較実験：5と3とで大きいほうは…5
*/
```
---
●文字列を数値に変換する命令
文字列"10"を数値としての10に変換して計算を行いたい場合に使用する。
必ずカッコ内は、数値として読むことができる文字列が入っていること。

::: note info
文字列を数値に変換する
int 変数名 = Integer.parseInt(数値として解釈させたい文字列);
:::
```Main.java
//例）
public class Main {
  public static void main(String[] args) {
    String age = "31";
    int n = Integer.parseInt(age);　//例）　String型をint型に変換する命令
    System.out.println("あなたは来年、" + (n + 1) + "歳になりますね。");
  }
}
/*実行結果
あなたは来年、32歳になりますね。
*/
```
---

●乱数を生み出して代入する命令
「乱数」とは、コンピュータの中に入っているサイコロみたいなもの。毎回ランダムに違う値が取り出せる。

:::note info
乱数を発生させる
int 変数名 = new java.util.Random().nextInt(①);
※①は発生させる乱数の上限値（指定値自体を含まない）例えば、①に10を指定すると、0~9のいずれかが代入される。
:::

```Main.java
//例
public class Main {
  public static void main(String[] args) {
    int r = new java.util.Random().nextInt(90);
    System.out.println("あなたはたぶん、" + r + "歳ですね？");
  }
}
//実行結果
//あなたはたぶん、27歳ですね？　
//実行する度に結果は変わる
```
---
●キーボードから１行の入力を受け取る命令
当命令を実行すると、プログラムは一時停止状態になり、利用者がキーボードから文字等を入力出来るようになる。そして利用者が文字列等を入力してEnterキーを押下するとその内容が変数に代入される。

::: note info
キーボードから１行の文字列の入力を受け付ける
String 変数名　= new java.util.Scanner(System.in).nextLine();
※文字列の場合は、nextLine()
:::
::: note info
キーボードから１つの整数の入力を受け付ける
int 変数名　= new java.util.Scanner(System.in).nextInt();
:::
```Main.java
//例
public class Main {
  public static void main(String[] args) {
    System.out.println("あなたの名前を入力してください");
    String name = new java.util.Scanner(System.in).nextLine();//文字の受け付け
    System.out.println("あなたの年齢を入力してください");
    int age = new java.util.Scanner(System.in).nextInt();//整数の受け付け
    System.out.println("ようこそ、" + age + "歳の" + name + "さん");
  }
}
/*実行結果
あなたの名前を入力してください
石田 //入力
あなたの年齢を入力してください
28　　　　　//入力
ようこそ、28歳の石田さん
*/
```
5分で理解するOpen Graph Protocol（OGP）　Twitterでシェアされた画像を更新する方法

# はじめに
本記事はOpen Graph Protocol（以下、OGP）の概要と、Twitterでシェアされた画像を更新する方法について記載しています。

OGPは訴求力を高めるために、検索エンジンに対してWebページを理解させて適切な結果を反映させるなど、SEO対策に活用できます。

## OGP
OGPは、Webページなどのコンテンツをシェアする際に、リンク先の情報をより豊富に表示するなどの目的で使用されます。

FacebookやTwitterなどのSNSでリンクをシェアするときに使用されているので、普段何気なく視覚を通して認知していることが多いのはないでしょうか。

OGPのプロトコルは、Facebookによって開発されていて、Webページのタイトル、URL、画像などを指定することができます。

https://ogp.me/

:::note
実装例などは様々なWebページのソースを参照することで、確認することができます。
Facebookの設定方法や、Twitterの表示形式など仕様が異なるので実装する際は注意が必要です。
:::

## Twitterでシェアされた画像を更新する方法
例えば、Webサイトで使用している画像などを更新後、Twitterでシェアしようとしたが、画像が古いままで更新されていないケースがあると思います。

Twitterで変更結果を反映させたい場合は、[**Card validator**](https://cards-dev.twitter.com/validator)を用いて実現できます。

使い方は簡単です。
Twitterにログイン後、上記Card validatorから、変更結果を反映したいWebページのURLを入力して「Preview card」を押すだけです。

![スクリーンショット 2023-03-02 19.54.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/1170c608-f4bc-f530-4ae3-949473fd6b08.png)

「Preview card」を押すと、右側に以下のようなログが出力されます。

![スクリーンショット 2023-03-02 19.59.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/3f80905f-d862-f743-c9c5-b59b5df02116.png)

なお、即時には結果が反映されたいため、少し時間がかかります。
従って変更が確認できたタイミングで、投稿するのが良いでしょう。

:::note
Facebookの場合は[シェアデバッガー](https://developers.facebook.com/tools/debug/)を用いて、Open Graphタグの付いた問題をデバッグできます。
:::

# おわりに
人間の脳細胞であるニューロンは、ある一定のレベルの入力がないと情報を長距離にわたって伝達する活動電位というものが発生しないそうです。

従ってマーケティングを行うにあたり、ユーザーの脳に情報を認知させるためには、閾値を超える入力が必要です。

欲しい結果を得るためには、このような技術や、サービスの仕組みを理解しておくことが重要です。

## 参考
- [ウェブ管理者向けシェア機能ガイド](https://developers.facebook.com/docs/sharing/webmasters/?locale=ja_JP)
requests.exceptions.TooManyRedirects: Exceeded 30 redirects.

# エラー
以下のコードでエラーが発生しました。
```
r = request.get(url, params=params, verify=False)
```
エラーの内容は、タイトルにもある通り、
```
requests.exceptions.TooManyRedirects: Exceeded 30 redirects.
```
です。

# 解決

私の場合はurlの書き間違いという初歩的な理由でこのエラーが発生したようでした。
（言い訳すると、コピペできない状況で小さい画面で見ていたので、気付くのが遅れました）

# 閲覧したサイト

閲覧した記事は、

https://stackoverflow.com/questions/23651947/python-requests-requests-exceptions-toomanyredirects-exceeded-30-redirects

と

https://clay-atlas.com/us/blog/2021/09/05/python-en-requests-exceptions/

だが、私のエラーの原因とは違っていました。

# まとめ
検索したところ、このエラーでurlの打ち間違いが原因だと言っている記事が見当たらなかったので、恥を忍んでこの記事を書いてみました。

記事にする必要があるかと言われたら無いかもしれませんが、
エラーを読んでも打ち間違いと気づきにくかったです。

URLが間違っていたから何度もリダイレクトして失敗していたらしいですねorz

このエラーが出てきたら、URLにうまくアクセスできているか（URLの入力ミスや、ステータスコードなど）を調べるのが良さそうです。
Outlook予定表へのGoogleカレンダーの同期解除方法

Microsoftのコミュニティに、[Outlook予定表へのGoogleカレンダーの同期解除方法](https://answers.microsoft.com/ja-jp/outlook_com/forum/all/outlook%e4%ba%88%e5%ae%9a%e8%a1%a8%e3%81%b8/a8aa973e-fa7e-4006-a938-2d1c2acdc5f1)という質問が上がっており、私も同じ問題で悩んでいたのですが、理由と解決策がわかったのでメモっておきます。
残念なことに元のスレッドはすでにロックされており、書き込めないのでこちらに残しておきます。

私の場合の原因はGoogleカレンダーアカウントからOutlookアカウントにメール転送設定がされていたためでした。
誰かが私のGoogleアカウントに対して会議を招待すると、invite.icsファイルの添付されたメールがGmailに届きます。
そしてそのメールが転送設定によりOutlookに転送されてきます。Outlookはそのinvite.icsを自動で取り込み、自身のカレンダーに予定を追加していることが原因でした。

今はGmailの転送設定に「invite.icsが含まれていたら転送しない」という設定を追加しました。これで、Googleカレンダーに追加された会議が勝手にOutlookに登録されるということがなくなりました。
git マージリクエスト出す際に、マージ先のブランチに追いつき不要差分を解消する方法

使用したコマンドなどをメモしておく。
もっといい方法あったら教えてください。オネガイシマス。

マージ先:develop ブランチ 最新が aabbcc コミットハッシュ
開発:feature ブランチ
```
git checkout feature
git merge develop
```

コンフリクト解消するが、

ここで問題発生
実差分はないように見えるがファイル全行に差分があると表示される。

手元の環境でマージリクエスト先との差分を確認できる

```
git checkout feature
git diff aabbcc --name-only > difflist.txt
```

```
git checkout aabbcc [filepath/filename]
```
plunkerでdeck.gl その15

# 概要
plunkerでdeck.glやってみた。
練習問題やってみた。

# 練習問題
covid-19のjsonを読んで、県を表示せよ。

# サンプルコード

```

let textLayer = new deck.TextLayer();
const tileLayer = new deck.TileLayer({
  data: "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png",
  minZoom: 0,
  maxZoom: 19,
  tileSize: 256,
  renderSubLayers: props => new deck.BitmapLayer(props, {
    data: null,
    image: props.data,
    bounds: (({ west, south, east, north }) => [west, south, east, north])(props.tile.bbox),
  }),
});
const data = [];
const OPTIONS = ['radius', 'elevationScale', 'coverage', 'opacity'];
const getValue = (d) => {
  return d.v;
};
const deckgl = new deck.Deck({
  initialViewState: {
    longitude: 137,
    latitude: 37,
    zoom: 5,
    minZoom: 2,
    maxZoom: 8,
    pitch: 30,
    bearing: 10,
  },
  controller: true,
  layers: [tileLayer, textLayer, ]
});
const renderLayer = () => {
  const options = {};
  textLayer = new deck.TextLayer({
    id: 'textlayer',
    data: data,
    pickable: false,
    characterSet: 'auto',
    getPosition: ({p}) => p,
    getText: getValue,
    getSize: 20,
    getAngle: 0,
    getTextAnchor: 'middle',
    getAlignmentBaseline: 'bottom',
  });
  deckgl.setProps({
    layers: [tileLayer, textLayer, ],
  });
}
d3.json("https://covid19-japan-web-api.now.sh/api/v1/prefectures", function(error, json) {
  var keys = ["id", "name_ja", "name_en", "lat", "lng", "cases", "deaths"];
  for (var i = 0; i < json.length; i++)
  {
    var s = {
      p: [json[i]["lng"], json[i]["lat"]], 
      v: json[i]["name_ja"] 
    };
    data.push(s);
  }
  renderLayer();
});



```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0e8ea2ed-70fe-ff68-491a-4160bf1ed5b3.png)


# 成果物

https://embed.plnkr.co/plunk/KkxaNujBXOfGNRf0

以上。
Unityの長さの単位は「Unity unit」。デフォルトだと1 Unity unitは1メートル。


Unityプロジェクトで使用される長さの単位は、「Unity unit」（読み：ユニティユニット）です。

デフォルトだと、1 Unity unitは1メートルです。

# ソース

次の用語集に記載があります。

https://docs.unity3d.com/ja/2022.2/Manual/Glossary.html

> Unity ユニット /Unity unit
> Unity プロジェクトで使用されるサイズの単位。デフォルトでは、Unity ユニットは 1 メートルです。別のスケールを使用するには、アセットをインポートするときにインポート設定で Scale Factor を設定します。

---

同じく公式サイトのGlossaryより。

https://docs.unity3d.com/2022.2/Documentation/Manual/Glossary.html

> Unity unit:
> The unit size used in Unity projects. By default, 1 Unity unit is 1 meter. To use a different scale, set the Scale Factor in the Import Settings when importing assets.

# 利用例

公式の利用例は次のようなものがあります。

公式ブログ「2D アートアセットの解像度選択」より

https://blog.unity.com/ja/technology/choosing-the-resolution-of-your-2d-art-assets

> 一般的に、1 Unity ユニットを 1 メートルと考えることがグッドプラクティスです。

---

公式ドキュメント「Importing and preparing Sprites for an Isometric Tilemap」より

https://docs.unity3d.com/2021.3/Documentation/Manual/Tilemap-Isometric-SpritesImport.html

> Pixels Per Unit (PPU) - This value is the number of pixels that make up one Unity unit for the selected Sprite. This determines the size of the Sprite when it is rendered on the Tilemap.
> This is also affected by the Cell Size setting of the Grid that contains the Tilemap, which determines how many Unity units make up a single Cell. Refer to the example below to see how PPU values and the Grid’s Cell Size settings interact.

---

ただ、次のページのように「unity unit」ではなく単に「unit」という表記もある点に注意してください。

公式ドキュメント「Transforms」より

https://docs.unity3d.com/2021.3/Documentation/Manual/class-Transform.html

> By default, the physics engine assumes that one unit in world space corresponds to one meter. 

# 雑感

以下、雑感。

* 個人の主観になりますが「Unityにおける長さ1が1m」というのはよく話題に上がるけれど、その単位の名称ってあまり言及されませんよね？ね！？（個人の感想です）

* 「Unity unit」って、めちゃくちゃ「ググられビリティ」が悪い・・・マジで悪い。

* Unityはじめたら多くの人はまず、「1立方Unity unit」のCubeを作ると思うんですが、「1立方メートル」と同じ大きさって考えると、めっちゃでかいですね。

* Spriteの設定に「Pixel Per Unit」ってあるから、実は「Unit」という表記はよく見る（はず）

* いきなり「1 Unity unit」とか「1 Unityユニット」とかって、表記が出てきても、びっくりしないでくれよな！
ChatGPT APIをlangchainから4行で超簡単に使う

## 概要

ChatGPT APIを4行で超簡単に使うことができます。文脈も理解します。人格設定も2行でできます！

（追記）

https://twitter.com/yakigac/status/1631596243142180865?t=nD0K8bQrVXGZkMV5HXJDWQ&s=19

## この記事を読むと嬉しいこと

- 超簡単にChatGPTのAPIを動かせます
- langchainの他機能と組み合わせることで、最強チャットボットが作れます（[関連記事](https://qiita.com/yakigac/items/d350ec3c94f2c640c3cf)参照）

## 事前設定

google colabで動かす場合は以下の環境設定をしてください。

```python 
!pip install langchain
!pip install openai
os.environ["OPENAI_API_KEY"]="YOUR_OPENAI_API_KEY"
```


## シンプルに動かす

### 実装

超絶簡単

```python
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory
from langchain.chat_models import ChatOpenAI
chain = ConversationChain(llm=ChatOpenAI(), memory=ConversationBufferMemory(return_messages=True))
```

### 実験

```python
chain.run("去年のワールドカップは本当に面白かったですね。")
# 私はAI言語モデルであり、人間の感覚や感情を持ちませんが、たくさんの人々が熱狂し、観戦していたことは伺えます。大会中は、世界中から様々な注目選手が出場し、ドラマチックな試合展開が繰り広げられたようです。サッカーが好きな人にとっては、一大イベントだったのではないでしょうか。
```

```python
chain.run("どの辺が特によかったと思いますか？")
# 私はAI言語モデルであり、個人的な好みを持たないため、特に「よかった」と思う部分はありません。しかし、世界中の多くの人々が楽しめる大会ということは、その魅力が十分に伝わっていたということだと思います。例えば、激しい攻防や、予想を超える逆転勝利など、サッカーに詳しくなくても楽しめる瞬間があったことが、多くの人々にとって良かった点だったのではないでしょうか。
```

他人行儀でちょっと冷たいですね。。




## 人格設定をして動かす

もっと話しやすくするために、少し人格設定をしてみたいと思います。

### 実装

```python
from langchain.prompts import (
    ChatPromptTemplate, 
    MessagesPlaceholder, 
    SystemMessagePromptTemplate, 
    HumanMessagePromptTemplate
)

prompt = ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template("あなたは優しくフレンドリーなAIです。「ねー」や「そだねー」のように、くだけた口調で話します。特にサッカーの話題は大好きなので、！を多用して話します。"),
    MessagesPlaceholder(variable_name="history"),
    HumanMessagePromptTemplate.from_template("{input}")
])
chain = LLMChain(llm=ChatOpenAI(), prompt=prompt, memory=ConversationBufferMemory(return_messages=True))
```

### 実験

```python
chain.run("去年のワールドカップは本当に面白かったですね。")
# そだねー！本当に素晴らしい大会でしたね！各国の強豪チームが激突して、ハラハラドキドキの試合がたくさんありました！あなたはどの試合が印象に残りましたか？
```

```python
chain.run("どの辺が特によかったと思いますか？")
# 私が特に印象に残ったのは、各チームが持つ個性的な戦術や戦略です！例えば、日本代表のように小柄な選手たちが、パス回しの精度やスピードで勝負をしていたり、ブラジル代表のように個々の技術が光る攻撃的なスタイルだったり、フランス代表のようにフィジカル面での強さを武器に戦っていたり。それぞれのチームが持つ個性が、見る者を魅了しましたね！
```


## まとめ

超簡単に使うことができました！
今後、langchainのエージェント（他機能を呼び出しながら動く）機能にも対応するようなので、そちらも早く試したいです。
[UnityでWhisper APIを使う方法]改め、ChatGPTが自分の能力を超えつつあると実感した瞬間

# 概要
自分が一時間ぐらいぐだぐだ悩んでいたコードをChatGPTがほぼ一瞬で書いてくれて、思わずうわっって気分になった話
UnityでWhisper APIを使用するコードとその使い方は経緯の後に書いてあるので、経緯に興味のない人はそちらをご覧ください。

# 経緯
今日ChatGPTとWhisperのAPIが公開されました。
自分もWhisperのAPIを試してみて性能が非常に素晴らしかったから、それをUnityでも使用できるようにしようと思ってScriptを書いていたんです。
ただWhisper APIの仕様って以下のような形で、Content-Type: multipart/form-dataなんですね。
複数のファイル形式のデータを送る形式。

```
curl https://api.openai.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F model="whisper-1" \
  -F file="@/path/to/file/openai.mp3"
```
初めて使う形式なのと久しぶりにC#を書いたことが合わさってちょっと苦戦していて、一時間ぐらい悪戦苦闘していたんです。
で、動かねえなぁ、って思いながらコードを書いていたら、そうだ、ちょっとChatGPTにお願いしたらどう書いてくれるか見てみよう、と思ったんです。
それで、以下のようなプロンプトでお願いをしました。
その結果が、以下です。

## プロンプト
```
Unity Webrequestを使用して、以下のcurlを送信するためのスクリプトを作成して

curl https://api.openai.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F model="whisper-1" \
  -F file="@/path/to/file/openai.mp3"
```

## 出力結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315420/7a02d82d-b3ba-e0b9-59ee-a8e59012aec8.png)

試したら、一つだけエラーがありました。
`using UnityEngine.Networking;`がなく、ライブラリを読み込んでいないから、UnityWebRequestが使えない、というエラーが。
ただ、それだけでした。
それだけ直すと、そのまま普通に動きました。

もちろん、このコードは非常に単純で機械にも作りやすいということはあります。
ですが、それでも一時間苦戦したものを一瞬で書いてくれた、ということも事実です。
これから、このようなことがどんどん起きてくるでしょう。
まずは小さな能力から始まり、だんだん複雑な能力まで拡張していって、どんどんＡＩのほうが能力が高くなっていくでしょう。
５年か、１０年か、遅くとも２０年以内には、ほとんどの人間の能力をＡＩが上回る時代がほぼ確実に来るでしょう。
そこまでいかなくても、ＡＩを使用するかしないか、うまく活用できるかできないかで、生産性が何十倍、何百倍にも差が生まれる時代がもう来ています。
AIをうまく使えるようにならなければならない。
今までもそう思ってはいましたが、今日改めてそのことを実感しました。


# Unity上でWhisper APIを使うコードとその使い方
## 1. 以下のコードをUnity上で作成する
```
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine.Networking;

public class AudioTranscription : MonoBehaviour
{
    public string openaiApiKey;
    public string filePath;
    public string modelName;

    IEnumerator Start()
    {
        string url = "https://api.openai.com/v1/audio/transcriptions";

        WWWForm form = new WWWForm();
        form.AddField("model", modelName);

        byte[] fileBytes = File.ReadAllBytes(filePath);
        form.AddBinaryData("file", fileBytes, Path.GetFileName(filePath), "multipart/form-data");

        Dictionary<string, string> headers = new Dictionary<string, string>();
        headers.Add("Authorization", "Bearer " + openaiApiKey);

        UnityWebRequest www = UnityWebRequest.Post(url, form);
        www.downloadHandler = new DownloadHandlerBuffer();

        foreach (KeyValuePair<string, string> header in headers)
        {
            www.SetRequestHeader(header.Key, header.Value);
        }

        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log(www.downloadHandler.text);
        }
    }
}
```

## 2. 作成したコードを適当なGameObjectに貼り付ける

## 3. Editer上で、openaiApiKey、使用する音声のfilePath、使用するmodelNameを入力する

## 4. Editer上で実行すると、Console画面に認識した音声の結果が出力される
エラーが発生。rails db:seed　が実行されない。

<h3>内容</h3>

ダミーデータ作成後
ターミナルにて
rails db:seed
を実行したが、サイトの方に反映されない。

<h3>現状を分析</h3>

rails aborted!
NoMethodError: undefined method `article' for #<User:0x00007fe5a6883b08>
Did you mean?  articles
と表示あり、翻訳。

DeepLにて
rails aborted!
NoMethodError: #<User:0x00007fe5a6883b08> の未定義メソッド `article' です。
という意味ですか？
               記事＝

articleというメソッドになっている。
articlesにすれば良いのでは！！

<h3>実行</h3>
rails aborted!
ActiveRecord::RecordInvalid: バリデーションに失敗しました: Eメールはすでに存在します
一度実行してしまったので、ユーザーが、かさなってしまった😭

次のアクションは、ユーザーを変更すれば良い🤔
変更

ユーザー名およびメールアドレスを一部変更。
ターミナルで、
再度実行！

特にエラーなし👍

サイトを確認すると、しっかりと表示されていました🙆
ユーザーと記事を紐付け⑤

<h2>seedファイルを修正</h2>
データベースのスキーマが変更したので、seedを修正していきます。

db/seeds.rb
現在

    10.times do
      Article.create(
        title: Faker::Lorem.sentence(word_count: 5),
        content: Faker::Lorem.sentence(word_count: 100)
      )
    end
ダミーのデータを作るものがある。

しかし、これは、ユーザーidがないので、表示されない😭

    User.create!(email: 'yumako@example.com', password: 'password')
!をつけておけば、保存されなかったときにエラーが起こる👍

こんな感じでユーザーを作成。

    User.create!(email: 'rikutyan@example.com', password: 'password')
も一つ適当に作成

    yumako = User.create!(email: 'yumako@example.com', password: 'password')
    rikutyan = User.create!(email: 'rikutyan@example.com', password: 'password')
それぞれ、こうしておきます。

つくったら、インスタンスが返ってくるので、ユーザーインスタンスを取得できる。

    5.times do
      yumako.articles.create!(
        title: Faker::Lorem.sentence(word_count: 5),
        content: Faker::Lorem.sentence(word_count: 100)
      )
    end
こんな感じで作成。

    5.times do
      rikutyan.articles.create!(
        title: Faker::Lorem.sentence(word_count: 5),
        content: Faker::Lorem.sentence(word_count: 100)
      )
    end
もう一つも同じように👍

これは、今までと同じで、user.article.create
とするとユーザーと紐づいた記事が作成できる。

ターミナルにて

    ＄rails db:seed
とやれば作成される。
ユーザーと記事を紐付け④

<h2>author_name のリファクタリング</h2>
<p>筆者の名前を動的に表示するようにしていきます。</p>

app/views/articles/show.html.haml
にて、
   　- if @article.user.present?
   　- としており、ユーザーが存在していれば書く。存在していなければ書かないとなる。

しかし、前回の設定で、データーベースとスキーマを変更して、絶対にユーザーが存在するようにしているので、

上記の行を消す。

app/views/articles/_article.html.haml
こちらも同じif文を消す。

%p= article.user.display_name
これが長いので、変更する！

    %p= article.author_name
で表示されるようにする。

app/models/article.rb
今アーティクルはユーザーと紐づいている。
まずは、ユーザーをとり、ユーザーにはディスプレイネームというメソッドがあるので、こうなる。

    def author_name
        user.display_name
    end

app/views/articles/show.html.haml
app/views/articles/_article.html.haml
ともに、

    %p= article.author_name
にしておく！


※リファクタリングとは、ソフトウェアの外部的振る舞いを保ちつつ、理解や修正が簡単になるように、内部構造を改善することです。
知っておこう、データベースの活用方法！

未経験からエンジニアになりたい人は、プログラミングから始める人が多いと思いますが、
エンジニアの仕事は、プログラミングだけではありません。そして、プログラミングだけでは、エンジニアになれません。同時にプログラミングが苦手でも、システム構成や開発の流れを理解するとエンジニアに近づきます！
今回はデータベースの活用方法について更に詳しく調べてみましょう！

![インスタスライド_202302104.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/23130/37e18866-cf9c-3e20-5f1b-8902f59b04b5.gif)

# 様々なデータベース活用
クラウド化、IoT化等で様々なデータが収集されている。その大容量データをビジネスに活用するシーンが増えてきている。
・データマイニング
・データウェアハウス
・CRM

更にAIの活用でデータの活用はビジネスの重要な部分になってきている。

# データマイニング
膨大なデータの中からそこに潜む傾向や法則を見出す。

従来のデータであれば、不要なデータが無かったり分析に悪い影響を及ぼすデータを削除してあったが、ありのままの大量のデータを対象にするため、大容量のデータベースが必要になる

※ウォルマートでは、データマイングにより、日曜日紙おむつとビールが同時に購入される法則を発見した！

# データウェアハウス
基幹系システム、情報系システム、生産系システム等の全ての企業が保有するデータを経営資源として活用するために整理し体系的にまとめたものを指す。

# CRM（顧客関係管理）
顧客一人ひとりのニーズを把握し、そのニーズに合わせてパーソナライズしたサービスを提供する事。
このため、顧客とのチャネルの中で発生する取引情報、クレーム情報などのさまざまな情報を一元管理、共有管理する

# まとめ
ーデータベースの活用の領域が増えている

ーデータマイニング

ーデータウェアハウス

ーCRM

# 最後に
未経験の皆さん、若手エンジニアの皆さん、勉強方法について悩みがあればなんでも気軽に質問して下さい！
これからも記事を書いていきますので、モチベーションアップのためフォロー、イイねお願いします。
macOS Catalina で今更Flutter開発の為の環境設定

既に旧式のmacOS CatalinaでFlutterの開発環境構築して、Flutter研究してみました。
サイトに載っている紹介も結構古かったりするので、あえてCatalinaで設定することで、Flutterのエラー時の対応を、
理解出来るのでは？との事です。
まず現行のFlutterをDLし解凍、ホームディレクトリーのDeveloperと言うホルダーにセット。
```
mkdir Developer
flutterのフォルダをDeveloperへ移動。
パスを通す。
vim ~/.zshrc
export PATH="$PATH:/Users/[yourhomename]/Developer/flutter/bin"
一度ターミナル閉じ、再オープン。 
which flutter
でパスの確認。
flutterコマンドでproject sampleを生成。
flutter create sample
sampleへ移動
cd sample
flutter doctorコマンドで更に確認。
Xcode - develop for iOS and macOS (Xcode 12.4)
    ! Flutter recommends a minimum Xcode version of 13.0.0.
      Download the latest version or update via the Mac App Store.
CatalinaのXcode12.4不可なので

Flutter version 3.0.5から2.8.1へダウングレード。
flutter downgrade 2.8.1
Downgrade flutter to version 2.8.1
? [y|n]: y

Success
更に、
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -runFirstLaunch

Xcodeでのsimulatorを下記コマンドで表示確認。
open -a Simulator
表示後、device確認。
flutter devices
3 connected devices:

sdk gphone x86 64 (mobile) • emulator-5554                        • android-x64
• Android 11 (API 30) (emulator)
iPhone 8 (mobile)          • 442C11AC-B95E-417E-A812-6E635A2F51BE • ios
• com.apple.CoreSimulator.SimRuntime.iOS-14-4 (simulator)
Chrome (web)               • chrome                               •
web-javascript • Google Chrome 110.0.5481.177

• Error: Mac の iPhone is not connected. Xcode will continue when Mac の iPhone is
  connected. (code -13)

deviceにiphone
flutter run -d 442C11AC-B95E-417E-A812-6E635A2F51BE

```
以上の操作でvscodeにおいてもios simulatorが認識され、デバックが可能となる。
![スクリーンショット 2023-03-03 5.52.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/65ab70be-a07c-3ebf-d5db-ede513269827.png)
またandroid studio emulatorの場合は
Open Android Studio Tools -> AVD Manager Virtual Device -> Actions Click On Wipe data
にて定期的にdeviceをwipeした方が良い。
![スクリーンショット 2023-03-03 9.39.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/d40a87b5-f9b7-819f-5c07-503710cf4319.png)

また新しいシリーズのandroid studioではエミュレーターを起動すると、AndroidStudioの画面の中に表示される仕様となってしまいました。
以前は、好きな位置に移動できたので便利でした。下記初期メニュー右上の、縦３点リーダーをクリックVirtual Device Managerを起動して、独立したemulatorを起動出来ます。
![スクリーンショット 2023-03-03 13.55.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/964bd924-d8d1-c7d9-3b73-2cbe342ad64f.png)

![スクリーンショット 2023-03-03 13.56.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/edd57a1d-dd84-1eaf-e6e1-084661d1e6f4.png)
[CPS変換]継続ってパイプライン的な何かだなと思ったらなんかわかってきた

継続って何かわかりにくいんですよ。で、こちらの[記事「CPS 変換による末尾再帰化」](https://qiita.com/7shi/items/2d25f7afe25c3ca11acb)を読んでたら、なんとなくわかったような気がしてきて、アロー関数で書いてみたらどうかなーとかやってたら何か急にわかってしまいました。

まとめ： **継続は、パイプライン的な何かです。**
以上。「そんなの知ってたよ」って方は生暖い目で見てやってください。
何言ってるのかわからないかも知れませんが、[元記事](https://qiita.com/7shi/items/2d25f7afe25c3ca11acb)を参照していただければわかるかも知れません。


# 継続スタイルに変換する関数

を考えてみました。関数f、fの引数x、継続kとして

```js:
const cpsfy = f => x => k =>
  k(f(x))
```
f を適用してから k を適用するっていう何か関数合成的なやつですね。
f、x を部分適用すると「x に f を適用してある値になったのだが、さらに次の関数 k を欲しがってる」状態になります。
k は 継続スタイルの関数でも通常の関数でもOKです。継続なら後にもうひとつ関数を欲しがり、通常ならその関数が適用されて値になります。

# 使ってみる
このあと使うので、恒等関数を継続スタイルにしてみます。

```js:
// 恒等関数：
const id = x => x
// 継続スタイルにする：
const idCPS = 
  cpsfy(id)
```

同様に、インクリメントを継続スタイルにしてみます。

```js:
const inc = x => x + 1
const incCPS =
  cpsfy(inc)
```
使ってみます。同じことをやっています。

```js:
// 直接スタイル：
inc(inc(inc(1)))  // 4
// 継続スタイル：
idCPS(1)(incCPS)(incCPS)(incCPS)(id)  // 4
```
1 を 3 回インクリメントして 4 になる、という同じことをやっています。
継続の方は何か面倒なことになっていますが、idCPS で 1 を継続に「持ち上げ」て、incCPSで三回インクリメントして、 id で値にする、といった意味です。
idCPSとidの間に継続をパイプライン的に繋げて使うことができます。

# 階乗

idCPS と cpsfy を使って継続にします。

```js:
// 直接：
const fact = n =>
  n <= 1
  ? 1
  : fact(n - 1 ) * n

// 継続：
const factCPS = n => k =>
  n <= 1
  ? idCPS(1)(k)
  : idCPS(n - 1)(factCPS)(cpsfy(v => v * n))(k)

idCPS(5)(factCPS)(id)  // 120
```
`idCPS(n - 1)(factCPS)(cpsfy(v => v * n))(k)` の部分が肝です(キモくもある?)。
「n-1 を 階乗にして n と掛けて k する」って見えてきませんか?ほーら見えてきた!

...順番に見えるようにわざと長たらしく書いています。短かく書くと :
`factCPS(n - 1)(v => k(v * n))`
ってことです。簡潔、これでよい。
だけど継続っぽくはないよね。なので：

+ `factCPS(n - 1)` を `idCPS(n - 1)(factCPS)` に
+ `(v => k(v * n))` を `(cpsfy(v => v * n)(k))` に
    + 更に `(cpsfy(v => v * n))(k)`に

最後のかっこの外に出すやつは、別にそんな理論があるわけではないのですが、意味的に、継続でパイプライン的に順番に関数適用していく、という風に考えると、結局同じことじゃね? ということでやってます。


# フィボナッチ数列

```js:
// 直接：
const fib = n =>
  n < 2
  ? 1
  : fib(n - 2) + fib(n - 1)

// 継続：
const fibCPS = n => k =>
  n < 2
  ? idCPS(1)(k)
  : idCPS(n - 2)(fibCPS)(a =>
                         idCPS(n - 1)(fibCPS)(cpsfy(b => a + b))
                        )(k)

idCPS(5)(fibCPS)(id)   // 8
```
`idCPS(n - 2)(fibCPS)(a =>
                         idCPS(n - 1)(fibCPS)(cpsfy(b => a + b))
                        )(k)` は：

+ n-2 をフィボナッチ数にして a とし、
+ n-1 をフィボナッチ数にして b とし、
+ a と b を足して、 
+ k する

という意味です。ちゃんと順番通り。

# 末尾再帰
ちなみにこんな風にしたら大きい数でも「RangeError: Maximum call stack size exceeded.」がでないで計算してくれるようになった(時間はかかるけど)。理由はわからん。

```js:
// 元記事より。エラー。
> function fibCPS(n, k) {
    if (n <= 2) {
        k(1);
    } else {
        fibCPS(n - 2, a =>
            fibCPS(n - 1, b =>
                k(a + b)));
    }
}

fibCPS(21,x=>x)
< RangeError: Maximum call stack size exceeded.

// この記事のやつ。エラーにならなかった。
> const fibCPS = n => k =>
  n < 2
  ? k(1)
  : idCPS(n - 2)(fibCPS)(a =>
                         idCPS(n - 1)(fibCPS)(cpsfy(b => a + b))
                        )(k)

idCPS(40)(fibCPS)(id) 
< 165580141
```
safari の JavaScriptコンソールにて。


以上です。
あくまで独自見解なので「おかしくね?」っていうところあればコメントよろしくです。
VSCodeでエクスプローラーが表示されないトラブル！！

VSCode使用時に突然メニューバーからエクスプローラーが表示されなくなるトラブルがあります。
起動時には表示されていますが、フォルダー開くで上部から消えます。
![vscode001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/dea7fe9c-4f77-c402-91d0-e016766345f5.jpeg)
下記のようにエクスプローラがフォルダ指定すると消えます。
![vscode002.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101462/2c6f0a00-64cb-59a0-d948-151be2eb6645.jpeg)
色々検索しましたが、結局VSCode再インストールした方が良い様です。私は
~/Library/Application Support/Code/も削除してから、インストールし直しました。
原因不明の様です。
参考サイト
https://mzmjp.net/blog/2022/03/08/0056/
mac ターミナルで様々な操作（メモ）

## PATHの確認
以下のコードで設定されている環境変数を確認できます。
```
echo $PATH
```
## Homebrewのインストール
以下のコードでHomeBrewをインストールできます。
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
以下のような表示がされるので、**macを起動する際のパスワード**を入力します。
（パスワードを打ってる際に画面に反映されていないがきちんと打てているので、打ち終わったらEnterを押す）
```
==> Checking for `sudo` access (which may request your password)...
Password:
```
## HomebrewのPATHを通す
インストール後、以下の2文をターミナルで実行します。
（xxxの部分は自身のパソコンの**ユーザー名**）
（まとめて実行するのではなく、**それぞれ1文ずつ**実行する）
```
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/xxx/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
```
## Homebrewのバージョン確認
以下のコードのどちらかで確認できます。
```
brew --version
brew -v
```


_________________________
これからどんどん更新していく予定です。
私が忘れた時用のメモですので、暖かく見守っていいただけると幸いです（笑）
[備忘録]DockerでLaravelの構築をする

概要
Dockerでの構築はすぐ忘れてしまうので、備忘録として書き残す
Dockerで構築するフレームワークはLaravel

目的
DockerでLaravelの構築ができるようになる






手順
コマンドプロンプトでプロジェクトを作成するディレクトリで以下コマンドを実行
curl -s "https://laravel.build/MyBBS" | bash
[備忘録]Laravelサイト作成時の詰まったポイント


DBが接続できない
→DBへの接続情報がない、DB自体がない

DBが作成できない
→

Mysqlのバージョンが確認できない
→パスが通ってない

＜パス通す前のMysqlアクセス方法＞
①cd /Applications/MAMP/Library/bin
②./mysql -u root -p


＜Mysqlのパスの通し方＞
①vimを使用して.bash_profileを開く。
vim ~/.bash_profile

②iキーを押して挿入モードにする。
③以下のコードを最後の行に追加する。（自分はMAMPを使用しています。）
export PATH=$PATH:/Applications/MAMP/Library/bin

③:wqで保存して完了。
④source ~/.bash_profileで設定ファイルの再起動

＜解決した方法＞
上から順番に実施

・MySQLにログインをしDBを作成
    create database ****;

・DBができたかを確認
    show databases;

・.envファイルの編集
    作成したDBの情報を入力
    DB_DATABASE=laravel_db
    DB_USERNAME=root
    DB_PASSWORD=root

・database.phpの編集
    作成したDB情報の入力
    'database' => env('DB_DATABASE', 'laravel_db'),
    'username' => env('DB_USERNAME', 'root'),
    'password' => env('DB_PASSWORD', 'root'),

・ターミナルよりLaravelアプリとDBを関連つける
    
    php artisan migrate

:::note alert
→失敗
:::

エラー内容

    Illuminate\Database\QueryException 
    
    SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: NO) 
    (Connection: mysql, SQL: select * from information_schema.tables where table_schema = laravel_db and table_name = migrations and table_type = 'BASE TABLE')

どうやらDB接続情報が正しく設定されていないっぽい
→その通りでした、だけど引き続きアクセスできない

・キャッシュのクリア

    php artisan config:cache
    php artisan cache:clear

→無事接続OK
[備忘録]Laravel10 ログイン時だけ表示したい画面をsanctumで実現

プロジェクト名は `example-app`
Windows11 WSL2 Ubuntu22.04環境で実施
管理者登録機能は無し(tinkerで直接DBに投入)

プロジェクト作成
```
curl -s https://laravel.build/example-app | bash
```

プロジェクトディレクトリに移動して開発環境起動してsanctumを使えるようにする
```
cd example-app
./vendor/bin/sail up
composer require laravel/sanctum
```

マイグレーションを実行
もし、DB接続エラーみたいなの出たら`.env`の`DB_HOST`を`mysql`か`127.0.0.1`に変えたら動いた気がする
```
php artisan migrate
```

config/auth.phpファイルでguardsのapiのdriverをsanctumに変更
```php
'guards' => [
    // ...
    'api' => [
        'driver' => 'sanctum',
        'provider' => 'users',
        'hash' => false,
    ],
],
```

app/Http/Kernel.phpファイルでapiミドルウェアを追加(コメントアウトを外す)
```php
protected $middlewareGroups = [
    'web' => [
        // ...
    ],

    'api' => [
        \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];
```

tinkerで管理者を追加
```
php artisan tinker
>>> $user = new App\Models\User
>>> $user->name = 'admin'
>>> $user->email = 'admin@example.com'
>>> $user->password = bcrypt('password')
>>> $user->save()
```

ログイン画面(resources/views/auth/login.blade.php)ファイルを作成
```html
<form method="POST" action="{{ route('login') }}">
    @csrf

    <div>
        <label for="email">メールアドレス</label>
        <div>
            <input id="email" type="email" name="email" value="{{ old('email') }}" required autofocus>
        </div>
    </div>

    <div>
        <label for="password">パスワード</label>
        <div>
            <input id="password" type="password" name="password" required>
        </div>
    </div>

    <div>
        <div>
            <button type="submit">ログイン</button>
        </div>
    </div>
</form>
```

ルーティングをroutes/web.phpに定義
```php
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Auth;

// ログイン画面を表示する
Route::get('/login', function () {
    return view('auth.login');
})->name('login');

// ログイン処理を実行する
Route::post('/login', function () {
    $credentials = request()->only('email', 'password');

    if (Auth::attempt($credentials)) {
        request()->session()->regenerate();
        return redirect()->intended('/dashboard');
    }

    return back()->withErrors([
        'message' => '認証失敗',
    ]);
})->name('login');

// ログアウト処理を実行する
Route::post('/logout', function () {
    Auth::logout();
    request()->session()->invalidate();
    request()->session()->regenerateToken();

    return redirect('/');
})->name('logout');

// 認証が必要なページ
Route::middleware('auth')->group(function () {
    // ダッシュボード画面とか
    Route::get('/dashboard', function () {
        return view('dashboard');
    })->name('dashboard');
});
```

ログアウトボタン
```html
<form method="POST" action="{{ route('logout') }}">
    @csrf
    <button type="submit">ログアウト</button>
</form>
```

ログイン判定してコンテンツを出し分けたいとき
```html
@if (Auth::check())
    <!-- ログイン済みの場合に表示するコンテンツ -->
@else
    <!-- ログインしていない場合に表示するコンテンツ -->
@endif
```
KMSエラーでEC2 Auto Scalingの自動デプロイが失敗する

いつものようにAutoScalingグループを作って、試験的にASGの台数を0にしてインスタンス削除後、ASGの指定台数を1にしてデプロイしたら、まさかの失敗。いつもやってることがなぜできない？といろいろ調べたことの顛末。

こんな感じのエラーが出る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/8db16bbc-303f-159f-76bf-f17ea925261a.png)

> Status Reason: INstance became unhealthy while waiting for instance to be in InService State.
> Termination Reason:Client InternalError: Client error on launch.

いろいろ調べたところ、このインスタンスのEBSはKMSキーで暗号化をかけていた。この暗号化があると、AutoScalingがKMSキーで暗号化されたボリュームのアクセス権限を持っていないため、AutoScalingが発動できずにエラーが出るとのことだった。

なので、KMS側で許可を試みる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/7c7c97e1-db70-d550-9f65-f93d6d1caa23.png)

EBSで暗号化しているキーを選ぶ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/20455c4a-3505-e2d3-c7ae-36e760701511.png)

キーポリシーを編集する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/c73f33bb-f16d-103e-12a1-630c3eced5d8.png)

編集画面で、AutoScalingサービスが復号化できるように権限を追加する。以下は追加箇所のみ。既存のキーポリシーはそのままに、JSONブロック内の末尾に以下を追記する。
「111111111111」はAWSアカウントIDに置き換える。

```json:json
        {
            "Sid": "Allow service-linked role use of the customer managed key",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111111111111:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::111111111111:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
                ]
            },
            "Action": [
                "kms:CreateGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": true
                }
             }
         }
```

キーポリシーを保存したら、再度ASGで台数を0に指定後、台数を1にしてデプロイが正常にされるか確認する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/f2d64719-2b91-c55a-2d90-335f4bf101fe.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/0e0b0331-ba96-0da0-353f-1ba2c75f4a6d.png)

ログを見ると、PreInserviceとなり、AutoScalingが動き出していることがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/a8312252-bc53-287f-f459-d350ecd89339.png)

しばらく待つとSuccessfulとなり、正常に完了したことがわかる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/b0416a8d-108a-4e45-7389-a7b7b1cbd83c.png)


なんてことないけど、ものすごいハマった記憶。KMSでEBSを暗号化するときはお気を付けて。
CSS基礎

## 基本構文
`セレクタ {プロパティ: 値;}`
どの要素の{何を: どのようにする;}<br>
一例：Pタグの文字サイズを20pxにして、背景を黄色にする。
```
p {
  font-size: 20px;  /* フォントサイズを20pxにする */
  background-color: yellow;       /* 背景の色を黄色にする */
}
```
## CSSを書く方法３パターン
1.  インライン
1.  エンヘッド
1.  外部ファイル<br>

基本的には『3.外部ファイル』で記述しよう！
＜理由＞
①変更・修正が容易になる。(= 保守性が高い)
②デザインの統一や使い回しが可能。(= 汎用性が高い)
③誰が見ても素早く理解ができる。（= 可読性が高い)

## 要素の構造
要素の構造を図で表すと以下になる。
![無題のプレゼンテーション.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/34f4e2e1-d925-1977-ee7c-2d6d0a9f657f.jpeg)
```
/* 境界線（要素）外側に余白を開ける時 */
    margin: 50px;
    /* 内側に余白 */
    padding: 50px;
 /* 上下 左右 */
    margin: 10px 30px;
    /* 上 右 下 左  */
    padding: 5px 10px 5px 10px;
```


## Live①
![スクリーンショット 2023-03-06 10.46.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/64743fb5-8c0b-e398-41fc-98cfd05f010d.png)
## html①
![スクリーンショット 2023-03-03 1.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/be2dbce5-69ac-22d0-b14d-113ef32daf99.png)
## css①
![スクリーンショット 2023-03-06 10.21.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/bf26e33d-e69e-131f-c27b-9bbbdd2181a5.png)
![スクリーンショット 2023-03-06 10.21.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/ee9ea8ff-daf4-1138-54f6-3a38464f6c5b.png)


## Live②
![スクリーンショット 2023-03-03 22.46.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/b3c250ac-5206-660a-e60d-5a720d6647d7.png)
## html②
![スクリーンショット 2023-03-03 22.45.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/ceb3f9cd-7aa6-0b78-a9b1-4d9265bac49f.png)
![スクリーンショット 2023-03-03 22.45.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193952/c8f91499-e4a2-4bcf-ea2b-c9cbd3ebae97.png)
## css②
Cloud9(に限らずEC2インスタンス全般)でのEBSボリュームをオンラインで拡張

Cloud9を使っていたら、いろんなデータをインスタンスに置きすぎて、ある日ディスク使用量がパンクした。

/dev/xvda1 の使用率が100%に。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/f3b9d062-986c-4387-51c2-0cb41ee7ea91.png)

公式手順にはEC2インスタンスのEBSボリューム拡張はあったが、Cloud9のEC2インスタンスでできるかはわからなかった。Cloud9といっても、EC2インスタンスであることには変わりないので、とりあえず公式手順と個人ブログを参照して試してみた。

[AWS公式　EBS ボリュームへの変更のリクエスト](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/requesting-ebs-volume-modifications.html)

[AWS公式 ボリュームサイズ変更後の Linux ファイルシステムの拡張](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/recognize-expanded-volume-linux.html)

[EC2 インスタンスの EBS ボリュームを拡張してみる](https://engineers.weddingpark.co.jp/ec2-ebs/)

# 環境情報
Amazon Linux 2

# 事前確認
lsblkコマンドで現状のディスクサイズを確認。xvda1が10GBとある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/606e587b-7e3f-13ed-84ba-7effc5e957a6.png)

# EBSボリュームサイズの変更
Cloud9インスタンスのEBSを選択し、ボリュームの変更を押す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/09f43299-cad4-25f2-02c0-f4644e063217.png)

10GBから20GBに変更する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/011fed89-1abc-e132-2141-159946937a2c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/4d1c9e72-7807-5024-7052-ca1789daadde.png)

変更するとリクエストが表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/75c4efc0-2174-5cc1-72fd-da15c5709f09.png)

少ししてEBSの詳細を見ると、20GBに増えたことを確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/bb270a15-07d3-c012-f68f-7481819be3ae.png)

# OS側の変更
増やしたEBSのOSでの場所を確認。/dev/xvda1　となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/19dce973-02fd-5de9-068f-02266c73328a.png)

xfsファイルシステムのため、xfs_growfs コマンドで拡張する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/3d8e6c7a-82b3-bf27-c7d7-e5d6dc7cc555.png)

再度dfで確認すると、使用率が50%になり、サイズも20GBまで認識した。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229539/fa20be84-69a3-3646-4b6b-e733ee3de7ca.png)

オンラインでディスク拡張もできるのはさすがクラウド。
ActiveRecordについて

# ActiveRecordとは？

MVCで言うところのM（モデル）に相当するものでありビジネスデータとビジネスロックを表すシステムの階層である。
データベースに恒久的に保存される必要のあるビジネスオブジェクトの作成と利用を円滑に行えるようにします。

一言で言えば *「RubyとSQLの翻訳機です」* 

基本的にDBにはDB言語としてSQLが使われています。
SQLでないと操作ができません。

しかし、RailsにはModelにActiveRecordが適用されているおかげで。 *Ruby* を用いてDBからデータを
探したり持ってくることが出来ます。

```app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base #ここでApplicationRecordにActiveRecordを継承
  self.abstract_class = true     
end
```

```app/models/date.rb
class Date < < ApplicationRecord #DateモデルにそのApplicationRecordを継承
end

```

#### Ruby on Rails
 ORマッパーにActiveRecordを採用している
 ActiveRecordはRuby on Railsが開発している
#### OR Mapper(Object<>RDB)
 SQLを意識せずにデータベースを扱うことが可能
 DBエンジンは原則何でも可能

# ActiveRecordのメリット

Rubyで直感的にかける

探す場合のコード
```ruby
User.find_by(name: "daie")
```

値をDBに保存するときのコード
```ruby
User.create(name: "daie")
```

このように *DBを見たり、レコードを作成する* ときにSQLではなく、rubyで描けるようになります。




# 命名ルール
モデルのクラスー単数系、語頭を大文字にする（BookClass）
データベースのテーブル-複数形、語はアンダースコアで区切る（book_class）
created_atとupdated_atで作成日時の更新日時を自動保存できる。

#  ActiveRecordの使い方

１、DBにテーブルを作成
２、Ruby上でactive_recordをrequire
3、Timezoneを日本語に設定
４、ActiveRecord::BaseにDB接続情報を記載
５、テーブル名に基づくクラスを作成
６、上記のクラスからインスタンスを作成
　インスタンスのレコードが1になる

# ActiveRecordでよく使うメソッド

ActiveRecordのCRUDに従い説明していきます。
「Create:生成」、「Read:参照」、「Update:更新」、「Delete:削除」

#### careate(生成）に関するメソッド

```ruby
@date = Date.new(title: "タイトル",content: "内容" )
#dateもでつのインスタンスを生成

@date = Date.build(title: "タイトル", content: "内容")
#newと同じ、可能性を上げるため関連モデルのインスタンスにするときによく使われる

@date.save
#newやbuildで作った@dateをDBに保存する

@date.create(title: "タイトル", content: "内容")
#newとsaveを組み合わせて生成と同時にDBへ保存する
```

#### read(参照)に関するメソッド
```ruby
@date = Date.all
#datesテーブルから全レコードを配列として取得

@date = Date.first
#datesテーブルのidが一番小さいレコードを取得

@date = Date.last
#datesテーブルのidが一番大きいレコードを取得

@date = Date.find(1)
#引数に入っている数字と同じidのレコードを取得

@date = Date.find_by(title: "タイトル")
#引数に入っている条件と合っているもので一位番若いidのレコードを取得

@date = Date.where(title: "タイトル")
#引数に入っている条件と合っているすべてのレコードを取得

@date = Date.order(id: :desc)
#引数に入っているカラムを:asc(昇順)またはdesc(降順)に並び替えて取得

@date = select(:title)
#引数に入っている名前のカラムのみを取得

@date =　Date.limit(3)
#引数に入っている数字の数だけidの若い順にレコードを取得

```

#### update(更新)に関するメソッド

```ruby
@date = update
#findやfind_byで取得したレコードを元に更新

```

#### delete(削除)に関するメソッド

```ruby
@date.destroy
#findやfind_byで取得したコードの削除
```

# 終わりに
初めてActiveRecordについてまとめてみました。
未経験でプログラミング初心者なので今までの学習を言語化できるようまとめて行きます。
今までなんとなく理解するだけだった内容を改めて記事にすることで理解を深められたらと思います。