OmniAICreator/Qiita-1.07M huggingface dataset:
Laravel PHPUnit Logファサードのモックを作って使う

# 概要

- リクエスト情報をログに出力するミドルウェアを作成した。そのミドルウェアのUnitテストを記載したい。LogファサードのメソッドをMockeryを使ってモックしてみたので簡単にまとめる。

# セオリー

- モックを定義する際は、当たり前だが、テストでテスト対象のメソッドが実行される前に、テスト対象のメソッド内で実行されるメソッドをモックしておく必要がある。
- モックする際は「メソッド名」、「引数」、「戻り値」を定義して上げる必要がある。

# テストで確認したいコード

- テストで確認したいコードの一部を下記に記載する。

    ```php
    Log::channel('request_response_log')->info('Request:', [
        'is_client_ip_unreliable' => $isClientIpUnreliable,
        'client_ip' => $clientIp,
        'method' => $request->method(),
        'url' => $request->fullUrl(),
        'headers' => $request->headers->all(),
        'body' => $request->getContent(),
    ]);
    ```

# テストメソッド

- 下記にテストメソッドを記載する。

    ```LogRequestTest.php
    public function test_リクエストのログ出力(): void
    {
        // Log facadeのメソッドをモックで用意
        Log::shouldReceive('channel')
            ->with('request_response_log')
            ->andReturnSelf();
        Log::shouldReceive('info')
            ->withArgs(function ($message, $context) {
                $this->assertSame('Request:', $message);

                $this->assertArrayHasKey('is_client_ip_unreliable', $context);
                $this->assertArrayHasKey('client_ip', $context);
                $this->assertArrayHasKey('method', $context);
                $this->assertArrayHasKey('url', $context);
                $this->assertArrayHasKey('headers', $context);
                $this->assertArrayHasKey('body', $context);

                return true;
            });

        // ミドルウェアを作成
        $middleware = new LogRequestAndResponse();

        // リクエストとレスポンスを作成
        $request = new Request();
        $response = new Response();

        // ミドルウェアを実行
        $middleware->handle($request, function ($req) use ($response) {
            return $response;
        });
    }
    ```

# Mockeryのメモ

### shouldReceiveメソッド（※メソッド名の指定）

- モックするメソッド名を引数で定義する。

### withメソッド（※引数の指定）

- モックするメソッドの引数を定義する。

### withArgs（※引数の指定）

- モックするメソッドの引数でクロージャを設定したい場合に使う。
- クロージャがtrueを帰す場合に初めて適用されるので注意する。

### andReturnSelfメソッド（※戻り値の指定）

- 戻り値として自身のオブジェクトを返す。

# 参考文献

https://readouble.com/mockery/1.0/ja/index.html

https://readouble.com/mockery/1.0/ja/expectations.html?header=
QiitaでGASのコードをシンタックスハイライトしたい

GASのプログラムはJavaScriptがベースとなっているので、jsを指定するのがベターかと思います。
ファイル名の箇所に「GAS」と記入しておくと親切かも。

\`\`\`js:GAS
console.log('hoge')
\`\`\`

```js:GAS
console.log('hoge')
```
Foxgloveで見るvisualization_msgs(など)が大変良い

# Foxglove
FoxgloveとはROS2やmcapで保存されたデータ(rosbag)を可視化するためのツールです。高機能なマルチプラットフォーム対応rviz2だと思って差し支えありません。よく有料なのではという疑問を目にしますが、クラウドでrosbagを共有する機能など特定の機能を使用しない限り、基本的には無料で利用できます。

インストールはこちらから可能です。ブラウザ版がありますが無難にDesktop版をお勧めします。

https://foxglove.dev/download

# Foxgloveで表示できるメッセージ

大体のメッセージがこのページで確認できます。

https://foxglove.dev/docs/studio/panels/3d

ですが一部、ドキュメントに表示例が無くどのように表示されるか気になったので確認してみます。

### ROS markers
ROS2 : [visualization_msgs/msg/Marker](https://github.com/ros2/common_interfaces/blob/master/visualization_msgs/msg/Marker.msg)

- SPHERE (球体)
    ![Screenshot 2023-07-14 at 22.51.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/4049246c-dbe7-52e2-a5e5-1a72e90a8d80.png)

- ARROW
![Screenshot 2023-07-14 at 22.56.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/c8afe22d-2579-3280-92fa-b4c2a13f40e9.png)

- LINE_STRIP
![Screenshot 2023-07-14 at 23.02.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/2baed188-74ba-905f-385b-563835142667.png)

- CUBE
![Screenshot 2023-07-14 at 23.03.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/dbba9686-471a-256d-e88e-f9034b7af40b.png)

- CYLINDER
![Screenshot 2023-07-14 at 23.07.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/63b43f73-98e7-d6a3-7115-4b7347cee7ae.png)

### ROS polygons
ROS2: [geometry_msgs/msg/PolygonStamped](https://github.com/ros2/common_interfaces/blob/master/geometry_msgs/msg/PolygonStamped.msg)

![Screenshot 2023-07-14 at 23.12.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/cc184038-190f-f4ad-f74f-1863828c5ce6.png)


### Path
ROS2: [nav_msgs/msg/Path](https://github.com/ros2/common_interfaces/blob/master/nav_msgs/msg/Path.msg)

![Screenshot 2023-07-14 at 23.13.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/4a9673f8-4708-5c2c-660e-b47fa0da3bec.png)


### Pose
ROS2: [geometry_msgs/msg/PoseStamped](https://github.com/ros2/common_interfaces/blob/master/geometry_msgs/msg/PoseStamped.msg)

![Screenshot 2023-07-14 at 23.19.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/899689/63b0b5e1-0199-066d-8f0e-0ae972d078f8.png)


# 最後に
個人的にはrivz2より見やすくて良いのかなと思っています。誰でも簡単に使えますので是非試してみてください。
GitHub Actionsでself-hosted runnersをDockerで作る

https://docs.github.com/ja/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners

諸事情あってセルフホステッドランナーをDockerから作る機会があったので

Dockerfileを作るついでにやったことをまとめました。
使用するDockerfileは以下です。

```dockerfile:Dockerfile
FROM ubuntu:23.04

ARG PERSONAL_ACCESS_TOKEN
ARG HOST=https://github.com
ARG ORGANIZATION
ARG REPOSITORY

ENV BINARY_URL=https://github.com/actions/runner/releases/download/v2.296.3/actions-runner-linux-x64-2.296.3.tar.gz

ENV RUNNER_NAME=myrunner
ENV RUNNER_GROUP=Default
ENV RUNNER_LABELS="self-hosted,Linux,X64"
ENV RUNNER_WORKDIR=_work

RUN apt-get update && \
    apt-get install -y dotnet-sdk-6.0 curl sudo && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN useradd runner && \
    echo "runner:runner" | chpasswd && \
    chsh -s /usr/bin/bash runner && \
    usermod -aG sudo runner && \
    mkdir /actions-runner && \

    chown runner:runner /actions-runner

USER runner
WORKDIR /actions-runner

RUN curl -fsSL -o actions-runner.tar.gz -L $BINARY_URL && \
    tar xf actions-runner.tar.gz && \
    rm actions-runner.tar.gz && \
    echo $PERSONAL_ACCESS_TOKEN && \
    ./config.sh \
        --unattended \
        --url $HOST/$ORGANIZATION/$REPOSITORY \
        --pat $PERSONAL_ACCESS_TOKEN \
        --name $RUNNER_NAME \
        --runnergroup $RUNNER_GROUP \
        --labels $RUNNER_LABELS \
        --work $RUNNER_WORKDIR

CMD ["./run.sh"]

```

Ubuntuから作っています。

そのまま使う場合はパーソナルアクセストークンを発行して環境変数を付与してください。

```bash
docker build . -t self-hosted-runner \
  --build-arg PERSONAL_ACCESS_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
  --build-arg HOST=https://github.com \
  --build-arg ORGANIZATION=octocat \
  --build-arg REPOSITORY=Hello-World
```

イメージを作った後はそのまま実行することでself-hosted runnersを待機状態にすることができます。

```
docker run self-hosted-runner
```

# 困ったこと
## Ubuntuのデフォルトのユーザーはrootで実行できない
デフォルトの状態(rootユーザー)でconfig.shを実行すると怒られる

```
# ./config.sh
```
> Must not run with sudo

```
#./run.sh
```
> Must not run interactively with sudo
Exiting runner...

のでユーザーを作る。

```bash
useradd runner && \
  echo "runner:runner" | chpasswd && \
  chsh -s /usr/bin/bash runner && \
  usermod -aG sudo runner && \
```


## .netが必要と書いてない。

self-hosted runnersの追加の仕方は以下ですが、dotnetのことは言及されてません。動かす時になってようやくわかります。

https://docs.github.com/ja/actions/hosting-your-own-runners/managing-self-hosted-runners/adding-self-hosted-runners

しかも.net自体のインストールも分かりづらい不親切っぷり
https://learn.microsoft.com/ja-jp/dotnet/core/install/windows?tabs=net70

結局.net 6が必要になりました。

```
apt install dotnet-sdk-6.0
```


## tokenが使えない

config.shを動かす時にtokenが必要なのですがこのtokenを発行する方法が見つかりませんでした。
そういうAPIがあったりスクレイピングすればいけるか？と思いいろいろ調べたところ以下のissueに当たりました。

https://github.com/actions/runner/issues/1264

config.shにpatを使えるオプションがあったのでそれを使うと無事GitHub Actionsに登録することができました。


```bash
./config.sh \
    --unattended \
    --url $HOST/$ORGANIZATION/$REPOSITORY \
    --pat $PERSONAL_ACCESS_TOKEN \
    --name $RUNNER_NAME \
    --runnergroup $RUNNER_GROUP \
    --labels $RUNNER_LABELS \
    --work $RUNNER_WORKDIR
```
【Swift】引数にある謎の`&`について

# はじめに
Swiftのコードを読んでいて、関数の引数に謎の`&`がついていたので調べてみました。

# 例
以下のコードを見てください。

```swift
func increment(number: inout Int) {
    number += 1
}

var number = 0
increment(number: &number)
print(number) // 1
```

`increment(number: &number)`を見ると、引数に`&`がついています。
これは、`inout`引数というものです。

# inout引数とは
`inout`引数は、関数内で引数の値を変更することができます。
例のコードを実行すると、`increment(number: &number)`で`number`の値を変更していることが確認できます。

# inout引数を持つ関数の作り方
`inout`引数を持つ関数を作るには、引数の型の前に`inout`をつけます。

```swift
func increment(number: inout Int) {
    number += 1
}
```

# inout引数を持つ関数の使い方
`inout`引数を持つ関数を呼び出す時は、引数の前に`&`をつけます。

```swift
var number = 0
increment(number: &number)
```

# おわりに
Swiftには便利な機能がたくさんありますね。この記事が参考になったという方は、いいねとフォローしていただけると嬉しいです☺️

# 参考
https://stackoverflow.com/a/30541262

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations/#In-Out-Parameters
区間推定

# Abstract
区間推定の概要を述べる。
(本記事を参照にしつつ、[この記事](https://qiita.com/DeepMata/items/78321ace881706f3406e)を読めば、区間推定についての理解が深まるであろう)
# 信頼区間
ある母集団の母数$\theta$について、
$Pr(A_{-}\leq \theta \leq A_{+})\geq1-\alpha$
を満たすような確率変数$A_{-},A_{+}$について、区間$[A_{-},A_{+}]$を「$100(1-\alpha)$パーセント信頼区間」という。
$A_{\pm}$は統計量になっている: $A_{\pm} = A_{\pm}(X_1,\dots,X_N)$
ただし、\{$X_1,\dots,X_N$\}は母集団の標本.

区間$[A_{-},A_{+}]$は確率変数なので、標本をとってくる度に毎回変動する。
繰り返し標本を取ってきて繰り返し区間の実現値を計算したときに、
たくさんある区間のうち$1-\alpha$の割合が、(真の値である)母数$\theta$を含んでいる。

# 母平均の信頼区間
## 正規母集団の場合
[定理]
確率変数$X_1,\dots,X_N$が互いに独立に同一の正規分布に従う時、母平均$\mu$の信頼区間は以下のようになる:
$$
 \begin{cases}
    [A_{-},A_{+}] &  \\\\
    A_{\pm} = \bar{X} \pm t_{\alpha/2}(N-1)\sqrt{\frac{U^2}{N}} & 
  \end{cases}
\\\\
\Rightarrow \bar{X} - t_{\alpha/2}(N-1)\sqrt{\frac{U^2}{N}} \leq \mu \leq \bar{X} + t_{\alpha/2}(N-1)\sqrt{\frac{U^2}{N}}
$$

($\bar{X}$は標本平均、$U^2$は不偏分散)
($t_{x}(m)$は自由度$m$の$t$分布の上側$100x$パーセント点(※))

※パーセント点については、例えば[ここ](https://qiita.com/aeba_chan/items/2d579d05c78db625c5e1)を参照。


$N$が大きい時は$t$分布は正規分布に近似できる($t(m) \sim N(0,1)$)ので、
$A_{\pm} = \bar{X} \pm z_{\alpha/2}\sqrt{\frac{U^2}{N}} $
と近似できる。

また、元から母分散$\sigma^2$が与えられている時は、上式で$U$と置き換えて
$A_{\pm} = \bar{X} \pm z_{\alpha/2}\sqrt{\frac{\sigma^2}{N}} $
としてよい。

## 指数分布の母集団の場合
[定理]
確率変数$X_1,\dots,X_N$が互いに独立に同一の指数分布に従う時、母平均$\mu$の信頼区間は以下のようになる:
$$
 \begin{cases}
    [A_{-},A_{+}] \\\\
    A_{-} = \frac{2N \bar{X}}{\chi^2_{\frac{\alpha}{2}}(2N)}\\\\
    A_{+} = \frac{2N \bar{X}}{\chi^2_{1-\frac{\alpha}{2}}(2N)}
  \end{cases}
\\\\
\Rightarrow \frac{2N \bar{X}}{\chi^2_{\frac{\alpha}{2}}(2N)} \leq \mu \leq \frac{2N \bar{X}}{\chi^2_{1-\frac{\alpha}{2}}(2N)}
$$

($\bar{X}$は標本平均)
($\chi^2_{x}(m)$は自由度$m$の$\chi^2$分布の上側$100x$パーセント点)

## ポアソン分布の母集団の場合
[定理]
確率変数$X_1,\dots,X_N$が互いに独立に同一のポアソン分布に従う時、母平均$\lambda$の信頼区間は以下のようになる:
$$
 \begin{cases}
    [A_{-},A_{+}] \\\\
    A_{-} = \frac{\chi^2_{1-\frac{\alpha}{2}}(d-2)}{2N}\\\\
    A_{+} = \frac{\chi^2_{\frac{\alpha}{2}}(d)}{2N}
  \end{cases}
\\\\
\Rightarrow \frac{\chi^2_{1-\frac{\alpha}{2}}(d-2)}{2N} \leq \lambda \leq \frac{\chi^2_{\frac{\alpha}{2}}(d)}{2N}
$$

($d=2(X_1 + \dots + X_N + 1)$)
($\chi^2_{x}(m)$は自由度$m$の$\chi^2$分布の上側$100x$パーセント点)

# 母分散の信頼区間
## 正規母集団の場合
[定理]
確率変数$X_1,\dots,X_N$が互いに独立に同一の正規分布に従う時、母分散$\sigma^2$の信頼区間は以下のようになる:
$$
 \begin{cases}
    [A_{-},A_{+}] \\\\
    A_{-} = \frac{(N-1) U^2}{\chi^2_{\frac{\alpha}{2}}(N-1)}\\\\
    A_{+} = \frac{(N-1) U^2}{\chi^2_{1-\frac{\alpha}{2}}(N-1)}
  \end{cases}
\\\\
\Rightarrow \frac{(N-1) U^2}{\chi^2_{\frac{\alpha}{2}}(N-1)} \leq \sigma^2 \leq \frac{(N-1) U^2}{\chi^2_{1-\frac{\alpha}{2}}(N-1)}
$$

($U^2$は不偏分散)
($\chi^2_{x}(m)$は自由度$m$の$\chi^2$分布の上側$100x$パーセント点)

# 母比率の区間推定
[定理]
確率変数$X_1,\dots,X_N$が互いに独立に同一の二項分布に従う時、カテゴリ$C$に属するデータの個数(の確率変数)を$M$とすると、母比率$p$の信頼区間は以下のようになる:

$$
 \begin{cases}
    [A_{-},A_{+}] &  \\\\
    A_{\pm} = \frac{M}{N} \pm z_{\alpha/2}\sqrt{\frac{\frac{M}{N}(1-\frac{M}{N})}{N}} & 
  \end{cases}
\\\\
\Rightarrow \frac{M}{N} - z_{\alpha/2}\sqrt{\frac{\frac{M}{N}(1-\frac{M}{N})}{N}} \leq p \leq \frac{M}{N} + z_{\alpha/2}\sqrt{\frac{\frac{M}{N}(1-\frac{M}{N})}{N}}
$$
Sorbetを使ってRubyでAbstract Classを使う


RubyKaigiで以下のセッションでRBIとRBSの比較がいろいろ紹介されていました。
その中で、RBIの機能としてAbstract classの説明があり、面白そうだったので使ってみました。

https://rubykaigi.org/2023/presentations/Morriar.html#day3

## Abstract Classについて

Abstract Class, Abstract Moduleは1つ以上のAbstract Methodを持つクラス、モジュールです。

以下のように定義します。

```diff_ruby:base_engineer.rb
# typed: true

class BaseEngineer
  extend T::Helpers
  extend T::Sig

+ abstract!

  def initialize(name:)
    @name = name
  end
end
```

すると、このAbstract Classのインスタンスを作成しようとすると、型エラーを発生させます。

```rb
# typed: true

engineer = BaseEngineer.new(name: 'kyntk')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/3ecde75a-f5e4-9e7a-5267-4160834e4eef.png)

また、以下のようにAbstract Methodを定義したとき、 `BaseEngineer`を継承やinclude, extendしたclass等で `greet` methodを定義しなかった場合、これも気づくことができます。

```diff_ruby:base_engineer.rb
# typed: true

class BaseEngineer
  extend T::Helpers
  extend T::Sig

  abstract!

  def initialize(name:)
    @name = name
  end

+ sig { abstract.void }
  def greet; end
end
```

```ruby:backend_engineer.rb
# typed: true

class BackendEngineer < BaseEngineer
end
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/f8eaa987-9e7f-d95e-1943-1c0fc0090cda.png)

Rubyには他の言語のようにAbstract ClassやAbstract Methodは存在しません。
Rubyで実装しようとした場合、以下のようにエラーをraiseする方法があります。
しかしこれらはランタイムエラーであり、実行するまで気づくことができません。

```rb
class AbstractClassError < StandardError; end

class BaseEngineer
  def initialize
    raise AbstractClassError
  end

  def greet
    raise NotImplementedError
  end
end
```

そこで、SteepやSorbetを使うことで、プログラムの実行前に気づくことができます。それに加えて、これらのエラーはエディタの拡張を用いれば実装中に即座に気づくことができます。

Abstract Class
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/178a9b99-43a7-a8ce-ac13-ea2b24f18907.png)
Abstract Method
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/e5763f19-c014-64a5-6669-119d521c60d4.png)

### Mixinで使う

継承以外にもinclude等で使うこともできます。

```rb
# typed: true

module Programmer
  extend T::Helpers
  extend T::Sig

  abstract!

  sig { abstract.returns(String) }
  def language; end
end
```

```rb
# typed: true

class BackendEngineer
  include Programmer
end
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/3ae842d7-ba3d-3278-79ed-0eaf5787cb77.png)

RBIには Interface もあるのですが、`interface!` を使った場合、すべてのメソッドがAbstract Methodだけという制約がつきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/7f9661ca-69b4-0909-81d4-25ddae009da4.png)

## Abstract Methodをオーバーライドする

`override` を使ってメソッドの定義を行います。

```rb
# typed: true

class BackendEngineer
  extend T::Sig

  include ProgrammerInterface

  sig { params(language: String).void }
  def initialize(language: )
    @language = T.let(language, String)
  end

  sig { override.returns(String) }
  def language
    @language
  end
end
```

## その他

ドキュメントを見ると、色々と柔軟にできそうです。
Rubyとしての機能が拡張されている感じがしておもしろいなと思いました。

https://sorbet.org/docs/abstract

## 参考

https://rubykaigi.org/2023/presentations/Morriar.html#day3

https://sorbet.org/docs/abstract
業務で使うショートカット

日々の業務でよく使っているショートカットをツールごとにまとめます。

# VS Code

|操作|コマンド|
|:----|:----|
|Swagger Preview|Shift&Alt&P|
|MDプレビュー|Ctrl＆K→V|
|PlantUMLプレビュー|Alt&D|
|パネルを閉じる/開く|Ctrl＋J|
|統合ターミナルを開く|Ctrl＋@|
|Explorerに移動|Ctrl＋Shift＋E|
|すべて折りたたみ|ctrl+k ->0|
|すべて展開|ctrl+k ->j|
|レベル２で折りたたみ|ctrl+k ->2|
|展開|ctrl+k ->]|
|単語選択|ctrl+shift+L|


# Excel

|操作|コマンド|
|:----|:----|
|名前を付けて保存|F12|
|シート移動|Ctrl+(Fn)+PageUp/PageDn|
|セル移動|Enter、Tab|
|データの端に移動|Ctrl+十字キー|
|選択セルに入力|Ctrl＋Enter|

### 高速選択
|操作|コマンド|
|:----|:----|
|行の挿入|Alt、I、R|
|:----|:----|
|列の挿入|Alt、I、C|
|セルの書式設定|Ctrl+1|
|セルの色を変える|Alt、H、H|
|塗りつぶしなし|Alt、H、H、N|
|罫線|Alt、H、B、A|
|罫線なし|Alt、H、B、N|
|列の選択|Ctrl+Space|
|行の選択|Shift+Space|
|全選択|Ctrl+A|

### 高速化

|操作|コマンド|備考|
|:----|:----|:----|
|行列の削除|行列を選択した状態で、Ctrl+-| |
|列幅調整|Alt、H、O、I| |
|折り返し|Alt、H、W| |
|シートの追加|Alt、I.W　/Shift+F11| |
|形式を選択して貼り付け|Ctrl+Alt+V|→V（値のみ）。→T（書式のみ）|
|行列を入れ替えて貼り付け|Ctrl+Alt+V→E| |
|連続データの入力|Alt、E、I、S|E（ええかんじで）I（一個づつ）S（数字を増やす）|
|オートフィル|Alt、E、I、S→Alt+F| |
|フィルター|Alt、A、T|選択：Ctlr+Space　※半角ならSpaceのみでOKだが、全半角を意識するのも手間なので、Ctlr+Spaceを使う。|
|フィルター解除|Alt、A、C| |
|データ並び替え|フィルター→「昇順（S)」→「降順（O)」| |
|空白行のみ抽出|フィルター→F→E→Enter| |
|キーワード抽出|フィルター→F→A| |

### その他

|操作|コマンド|備考|
|:----|:----|:----|
|曜日入力|Ctrl+1で書式設定開く⇒ ユーザ定義→aaa　⇒Ctrl+; で日付入力| 曜日の連続入力は、オートフィル（Alt、E、I、S→Alt、F）|
|ドロップダウン選択|Alt+↓| |




# Chrome

|操作|コマンド|
|:----|:----|
|新規タブ|Ctrl&T|
|閉じたタブを開く|Ctrl&Shift&T|
|タブを閉じる|Ctrl&W|
|タブ移動|Ctrl+PgUp/PgDn|
|タブ移動|Ctrl＋Tab|
|アドレスバーにカーソル移動|Ctrl&L|
|検索|Ctrl＋K|



# エクスプローラー

|操作|コマンド|
|:----|:----|
|エクスプローラー|Win+E|
|よくアクセスする場所|Alt+F|
|フォルダ移動|Alt+十字キー|
|アドレスバーにフォーカス|Alt+D|
|履歴|F4|
|フォルダ・ファイルのプロパティ|Alt+Enter|
|検索ボックス|Ctrl＋E|
|フォルダーウィンドウに移動|Tab→Tab|
|ナビゲーションウィンドウに移動|Alt＋Tab|
|フォルダ名コピー（パス有り）|dir /b /s /ad | clip|
|↑（パス無し）|dir /b /ad | clip|
|閉じる|Alt＋F4|


# Windows

|操作|コマンド|
|:----|:----|
|右クリック|Shift+F10|
|スタートメニュー|Win+X|
|デバイスマネージャー|Win+X→M|
|Windowsの設定|Win+I|
|タスクバーに登録されているアプリを起動|Win+数字|
|ウィンドウをすべて閉じる
デスクトップをアクティブにする|Win+D|
|入力して検索|Win+Q|
|コントロールパネル|Win＋Pause|


# Outlook

|操作|コマンド|
|:----|:----|
|アーカイブに移動|Ctrl+Shift+1|
|予定表に移動|Ctrl+2|
|メールの内容で会議設定|Ctrl+Alt+R|
クラスのこと改めて勉強します

MVVMの理解を深めていこうというところで``abstract``とか``implements``とか聞いたことない、もしくは見たことあるけど見て見ぬ振りしてたというようなものがいくつか見受けられたのでその辺りも含めて改めて学習していく。

## extends (継承)
言わずと知れた``extends``を使うことでクラスを継承できるというもの。
子クラスのコンストラクタの``super``で親クラスのコンストラクタも呼んでいる。
``@override``を使うことで親クラスのインスタンスやメソッドを上書きすることができる。
```dart
class Person {
  final String name;
  Person(this.name);
}

// Personクラスを継承
class Birthplace extends Person {
  String hometown;
  //superで親クラスのコンストラクタも呼んでいる
  Birthplace(String name, this.hometown) : super(name);

  @override
  void introduce() {
    print('私は$hometownに住んでいます。');
  }
}

void main() {
  final information = Birthplace('太郎', '札幌');
  information.introduce(); //私は札幌に住んでいます。
}
```

## abstract (抽象)
```dart
abstract class クラス名 {
  String メソッド名();
}
```
上記のようにclassの前に``abstract``をつけて宣言されたクラスを``抽象クラス``と呼ぶ。
抽象クラスは継承されることを前提としたクラスでインスタンスかすることができない。
抽象メソッドという処理内容を記述できないメソッドを定義することができる。
「抽象的」と調べると出てきたかなり確信をついた一文↓
「共通した要素を抜き出して一般化していること、または具体性に欠けていて実態が明確ではないことである。」

## implements
こちらのサイトがわかりやすかった↓

https://www.gixo.jp/blog/5159/

``implements``をつけるとそのクラス(下記でいうPersonクラス)の変数やメソッドなどといった要素を必ず実装しなければならない。
変数やメソッドの実装を強制するという約束のようなもの。
```dart
class Person {
  final String name;
  Person(this.name);
  void introduce() {
    print('私の名前は$nameです。');
  }
}

class Birthplace implements Person {
  //強制実装！
  final String name;
  String hometown;
  Birthplace(this.name, this.hometown);
  //強制実装！
  void introduce() {
    print('私は$nameです。$hometownに住んでいます。');
  }
}
```

## mixin, with
mixinを使うとクラスの拡張パックのようなもの(状態やメソッド)を定義できて、
withを使うことで拡張パックの内容をクラスに追加実装できるというイメージ。
```dart
mixin infomation{
  void askAge(){
    print('何歳ですか？');
  }

  void askHobby(){
    print('趣味は何ですか？');
  }
}

class Person with infomation {
  final String name; 
  Person(this.name);
}
```
↑これが
こうなるイメージ↓
```dart
class Person{
  final String name; 
  Person(this.name);

  void askAge(){
    print('何歳ですか？');
  }

  void askHobby(){
    print('趣味は何ですか？');
  }
}
```
これで忘れることはないだろう
はてなブログ {entry_id}を取得してみた

[はてなブログAtomPub](https://developer.hatena.ne.jp/ja/documents/blog/apis/atom/#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%81%AE%E6%8A%95%E7%A8%BF)のAPIにて、entry_idを取得するサンプルです。色々やり方はあると思いますが、GASを利用して下記画像(HTTPレスポンス）の選択しているところを正規表現で引っこ抜くだけのシンプルなプログラムです。

![スクリーンショット 2023-07-14 22.27.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041517/44ff8209-f7d7-95e0-4809-53e382ec5727.png)

```js:GAS
//ブログエントリ結果を取得(諸々省略して結果取得のみ）
var ret = UrlFetchApp.fetch(url,options);

//レスポンスから正規表現でentry_idを抽出
var m = ret.getContentText().match(/atom\/entry\/([0-9]+)/g)
var entry_id = m[0].replace("atom/entry/","")

console.log(entry_id)
```

投稿元データと合わせてentry_idを保存しておくと、更新や削除に利用できるので便利です。
【Next.js】Intercepting Routesを使用したモーダルが閉じない場合の対処法【AppRouter】

## 状況

次のようなディレクトリ構成でIntercepting Routesを使用したモーダルを作成したところモーダル内のボタンから他の画面へ遷移した際にモーダルが表示されたままになりました。

```terminal
app
├── @modal
│   ├── [...catchAll]
│   │   └── page.tsx
│   ├── default.tsx
│   └── users
│       └── [id]
│           └── page.tsx
└── users
    ├── [id]
    │   └── page.tsx
    └── page.tsx

```

## 対処法

`./@modal/users/[id]/page.tsx`またはその子コンポーネントで`usePathname`を使用して`/users/`を含む場合にのみ`<Modal></Modal>`を返すようにすると改善します。

```tsx
'use client'
import { usePathname } from 'next/navigation'

export default function Sample() {
	const pathname = usePathname()
	const shouldShowModal = pathname.includes("/users/")

	return shouldShowModal && <Modal>{/* ... */}</Modal>
}
```

公式ドキュメントに他のURLへ遷移する際には`[...catchAll]`を使用するように記載がありますが、これがうまく機能していないようです。`[...catchAll]`は削除しても正常に動作します。

## 参考

https://github.com/vercel/next.js/issues/49662

上記の中で`@modal`直下に`null`を返す`page.tsx`を作成する方法が記載されていますが、こちらは`@modal/page.tsx`に対応するURL（`app/@modal/page.tsx`の場合は`/`）に遷移する際にのみ効果があるようです。
ModSecurityのログをmlogcでリモートサーバにリアルタイムに転送する

# ModSecurityについて
オープンソースのWAFで最もメジャーと思われるWAF(Web Application Firewall)。Apache httpdなんかでCGIなどに処理が渡る前にリクエストをチェックして、必要に応じてブロックしてくれる。

RHELクローンだと以下の関連パッケージが提供されている。

```
# yum list | grep mod_security
mod_security.x86_64             2.9.6-1.el8            appstream
mod_security-mlogc.x86_64       2.9.6-1.el8            appstream
mod_security_crs.noarch         3.3.4-1.el8            appstream
```

# CRSとは
Core Rule Setの略で、[OWASPによってメンテナンスされている](https://owasp.org/www-project-modsecurity-core-rule-set/)らしいModSecurity（および互換WAF）用の汎用ルールセット。

そのまま導入するとやりすぎで不具合が出ることが多いと思うが、これについては今回は詳細を省略。

# mlogcとは？？
今回のネタ。

```# yum info mod_security-mlogc``` してみると、ModSecurity Audit Log Collectorの略らしい。
で、これは何をするものか？と調べてみると、リモートサーバにHTTPでログを（ほぼ）リアルタイムで転送するらしい。転送先のサーバでログをAuditConsoleを利用することで、ログの可視化が可能になる。
ちょうどWAFの生ログを見るのが嫌になっていたので、「AuditConsoleを導入したらいいんじゃね？」と考えた。

AuditConsoleについてググって見つけた[ブログ記事](https://smitch.hatenablog.com/entry/2018/04/04/125111)だと、[https://www.jwall.org/web/audit/console/](#)からダウンロードできるとあるが、現時点ではウェブサイトがなくなっている様子でダウンロードできない…
いろいろ探してみたけど手に入らなくなっているようなので諦めて、日次でローテートしたWAFログをcronで別サーバに転送、集計して表示するWebアプリを自分で適当に作成した。**おしまい。**

# リブート
Webアプリを作成したものの、遅れがひどいため、リアルタイムに近いログ確認の欲求が再燃。でもAuditConsoleが見つけられてない…

**結論：mlogcからログを受け取って表示する仕組みを自前で用意すればいいんじゃね？**

# mlogcの仕組み
mlogcの詳細について調べようにも、ググっても見当たらない…。とりあえずmlogcの動作の仕組みから調べる。　<- "俺得ニッチ"部分

ModSecurityでログをリクエストごとに指定した場所に個別ファイルとして保存する設定としておき、mlogcを呼ぶことで（以前に転送失敗したログも含め）指定したエンドポイントに送信する様子。（正確にはHTTPリクエストがエラーにならなければ転送したファイルを消す。）

試行錯誤した結果、以下のように設定。あと、パースが楽になるのでJSONにしておく。

```diff:/etc/httpd/modsec-audit.conf
-   SecAuditLog /var/log/httpd/modsecurity.log
+   SecAuditLog "|/usr/bin/mlogc /etc/mlogc.conf"
+   SecAuditLogType Concurrent
+   SecAuditLogFormat JSON
+   SecAuditLogStorageDir /var/log/mlogc/data
```

また、*/etc/mlogc.conf* も **ConsoleURI** を編集。**SensorUsername** と **SensorPassword** はmlogcがAPIエンドポイントの **ConsoleURI** へのリクエストヘッダにBASIC認証として送信される。

```diff:/etc/mlogc.conf
-   ConsoleURI          "https://CONSOLE_IP_ADDRESS:8888/rpc/auditLogReceiver"
+   ConsoleURI          "https://<REMOTE_SERVER>/api/auditlog/"
    SensorUsername      "SENSOR_USERNAME"
    SensorPassword      "SENSOR_PASSWORD"
```

これでModSecurityでログが記録されるたびに **https://\<REMOTE_SERVER\>/api/mlogc/** にリクエストが飛ぶことになる。ModSecurityがパイプでmlogcを呼び出すので、mlogcのデーモンなどはない。

# 受け側の用意
HTTPリクエストが飛ぶようになっても受ける側が無いと意味がないので、mlogcからのリクエストを受け取る方法をソースを読んだりしながら引き続き調査。

mlogcでは **ConsoleURI** で指定したエンドポイントに対し、PUTでリクエストを送っている様子。
PHPだとPUTリクエストの内容は *php://input* から受け取れるので、以下のようなテストコードを書いて動作を確認。実際には適当に処理してDBなんかに突っ込むと思う。

```php:index.php
<?php
$data = file_get_contents('php://input');
file_put_contents(time(), $data);
```

正常に処理が完了した場合はHTTPステータスコード 200を、エラーの場合はHTTPステータスコード 409が返ってくることを期待しているようなので、そのようにしてやる必要がある。「PUTなら201か204だろ！」とかやるとNG。

BASIC認証は **apache_request_headers()** を使うか、フレームワークに任せる。
【Laravel】PHPバージョンアップ後にphp.iniを確認する

# 詰まったこと
AzureにLaravelをデプロイする準備をしている中、ローカル開発環境のLaravelは7.2.1を使っているのにAzureのAppServiceの設定をPHP8.0.1にしてしまったので、ローカルもPHP8.0.1にあげた。

conposer.jsonと環境変数を変えて、いざcomposer updateを実行して出たエラーに時間を取られたので最終的な解決方法メモ

```
composer update

  [Composer\Exception\NoSslException]                                                                                                                      
  The openssl extension is required for SSL/TLS protection but is not available. If you can not enable the openssl extension, you can disable this error   
  , at your own risk, by setting the 'disable-tls' option to true.                                                                                         
                                                                                 
```

# 環境
PHP 8.0.1
Laravel Framework 6.18.43
MAMP利用

# 設定ファイルを確認

Laravelのconposer.jsonでPHPバージョンを8.0.1を見るように変更
``` json
"require": {
        "php": "^8.0",
===省略===
"config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "platform": {
            "php": "8.0.1"
        }
    },

```

phpinfo()を見るといいという記事が多かったので、パスを確認してその場所に置いてあったphp.iniのextentionのコメントアウトを解除したりしてサービス再起動。
でもエラーは変わらない…

https://nodoame.net/archives/8958
```
extension_dir = "ext
～～～
extension=openssl
```

# php.iniの配置場所が間違ていた
https://blue-goheimochi.hatenablog.com/entry/2014/09/15/Laravel4%E3%81%A7composer_install%E3%81%97%E3%81%9F%E3%82%89openssl%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A0%E3%82%88%E3%81%A3%E3%81%A6%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%81%9F%E4%BB%B6

色々な記事でも「php.ini-developerが～」と言われていたが、php.iniを見に行っていた先がphpinfo()と異なっていた。

phpinfo()で見ていたフォルダ　⇒C:\MAMP\conf\php8.0.1\php.ini
実際に配置して直ったパス　⇒C:\MAMP\bin\php\php8.0.1

C:\MAMP\bin\php\php8.0.1内にあるphp.ini-developerをコピーして同フォルダ内に配置。
名前を「php.ini」に変えて必要なextensionのコメントを外して再起動するとcomposer updateが通った
4つの波形を出力する555ジェネレーターキットを作る

「はんだづけの練習となる電子工作キットを考える」
https://qiita.com/nanbuwks/items/2f0f1992a82360e81e3b

において、マイコンを使わずにLチカができるものをとして、タイマIC555を使ったキットを紹介しました。

今回はその中の
「その1 4つの波形を出力するジェネレーター」を実際に作ってみます。


# 内容物

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/bec584d3-ed45-0024-7f75-261e6e7649b6.png)
※トランジスタは写真に1つしか写ってませんが2つが正解です!



# 組み立てよう

背の低いパーツから取り付けていきます。

まず、抵抗からはんだづけします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/e26bc56d-8e76-b197-9e79-a0b7dead10dc.png)

ダイオード、ICソケット、トランジスタを向きに中止して取り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/128b8537-12c6-22b3-9883-6e9472a09c6b.png)

C1,C7 に コンデンサ「103」(0.01μF) を取り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/00f8a23a-1bf9-f8a3-0913-3a745bcaa8fc.png)

C3 にコンデンサ「104」(0.1μF) を取り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/ffdffba1-90a3-ecf3-1a2d-4cedc65c0dca.png)

C2,C4,C5,C6 にコンデンサ「473」(0.047μF) を取り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/767ab2b5-7b9c-2622-f3a2-734623a35e21.png)

VT2 を取り付けるのを忘れてました! 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/01d60452-5e85-6b5d-492a-750edc28ae02.png)

半固定抵抗 503 (50kΩ)を取り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/2799fa79-2058-d6d6-7f46-122e246378c6.png)

半固定抵抗 203 (20kΩ)を取り付けます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d3074782-3146-9761-2b9b-32d8fdef4581.png)

シグナル選択ピンを取り付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7d6c5fa5-2cb3-1fbf-8ed4-4f8a0acc75cb.png)

電源入力と、信号出力は、都合によって適当な接続をしてください。今回はピンヘッダを取り付けました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/a2ef45b8-0c8e-7ec8-24d7-ce4d2441f6fa.png)

電解コンデンサを向きに注意して取り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/d81326e8-a11d-d2a9-23f0-f33d1b3887d4.png)

電源線、出力線を取り付けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/b1ef6ec7-7982-00b0-7cf9-3ce8691d19af.png)

出力波形。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/2e1e9f05-9c5e-9b9d-d146-f25670420d3d.png)


RP2で電圧が変わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/df3e3625-be80-acc3-5538-b57677acfc7d.png)

RP1で周波数が変わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/aded3204-5c83-bd27-5611-4fd6d96a9518.png)


波形を変えたところ。矩形波以外はあまり電圧が出ない感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/f7cae575-596d-3725-a9ed-1e72f8f53897.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/dd65bf05-f7c2-7736-cbe6-67d55a237add.png)
はてなブログ エラー「Invalid login」

[はてなブログAtomPub](https://developer.hatena.ne.jp/ja/documents/blog/apis/atom/#auth)のAPIを利用してBasic認証を実行しようとしたところ、下記エラーが返ってきました。

```
<p class="error-box">Invalid login</p>
```

ログインできへんで〜、と。これは、IDもしくはパスワードが間違っている場合に発生するようで、私の場合はIDが全角になっているという凡ミスが原因でした。

GASのエディタでは全角が半角よりも小さいので気づかなかった。。
![スクリーンショット 2023-07-14 22.09.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1041517/7a986ad7-8da8-173a-62f1-6e9d1c1e2f3e.png)

下記URLをブラウザで叩けば、BASIC認証を求められるので、まずはそこで認証が通るか確認してみてください。
https://blog.hatena.ne.jp/{はてなID}/{ブログID}/atom/entry/
SPAでcookie付与

# 背景

drf+reactでローカルで開発中。

ログインでaccessトークンを発行していたのだが、cookieにsetされない。

特にエラーも出ない。しかしクッキーは保存されない。

クッキーについて調べてみた。

# 調査

アクセストークンを発行するのに以下のライブラリ使用。

dj-rest-auth,simpleJWT

調査には大きく３つ。

- Cookieの属性
- CSRF
- CORS

まずはCookieの属性。

その設定が以下。

```python
REST_AUTH = {
    'USE_JWT': True,
    'JWT_AUTH_COOKIE': 'my-app-auth',
    'JWT_AUTH_HTTPONLY':True, 
    'JWT_AUTH_COOKIE_USE_CSRF' : True,
    # 'JWT_AUTH_SAMESITE':'None',
    # 'JWT_AUTH_SECURE':True
}
from datetime import timedelta
# JWT setting
SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(hours=1),
}
```

よく分からず設定していたので調査。

設定項目で必要そうなcookieの属性とやらを調べた結果。

## Secure属性

https通信でしかcookieの送信は許さない。Secureに通信するための属性。

## httpOnly属性

JavaScript の document.cookie では値を取得することができません。また document.cookie に対して HttpOnly 属性がついた値を Cookie に書き込むこともできません。xss攻撃に有効。

## SameSite属性

A というサイトから B というサイトへリンクなどを経由して遷移するときに、ブラウザに保存されている B の Cookie を送信するかどうかのコントロールをおこなうための属性です。

ドメインの異なるサイト間でcookieを送信するのかってこと。

None、Lax、Strictの3つを設定可能。

NoneはなんでもOK。

Laxはgetだけ許す。

Strictは禁止。

NoneにしておけばOKだが、Secure属性をtrueにしとかないといけないらしい。

正味、localで開発する場合オリジンは異なるがドメインは異ならないのでNoneにする必要はないが、、、

---

次にCSRFトークン。

何となくの理解で、csrf攻撃を防ぐためのトークンという認識。

その設定が以下。

```python
CSRF_TRUSTED_ORIGINS =["http://localhost:3000"]
# CSRF_COOKIE_SAMESITE ='None'
# CSRF_COOKIE_SECURE =True
```

csrfトークンに関してもsamesiteとsecureが設定可能。

---

次にCORS。

これは以前調査したので大体は理解している。

cors-headersライブラリ使用。

corsの設定。

```python
CORS_ALLOWED_ORIGINS = [
    "http://localhost:3000",
]
CORS_ALLOW_METHODS = (
    "DELETE",
    "GET",
    "OPTIONS",
    "PATCH",
    "POST",
    "PUT",
)
CORS_ALLOW_HEADERS = (
    "accept",
    "authorization",
    "content-type",
    "user-agent",
    "x-csrftoken",
    "x-requested-with",
    "access-control-allow-origin",
    "access-control-allow-credentials",
)
```

上から

リクエストを許可するオリジン、メソッド、header項目。

https://pypi.org/project/django-cors-headers/

axios設定。

```jsx
export const axiosInstance = axios.create({
  baseURL: API_URL,
  headers: {
    "Access-Control-Allow-Origin": "http://localhost:3000",
    "Access-Control-Allow-Credentials": "true",
  },
});

~~~~~~~~
const response = await axiosInstance.post(
        "/auth/login/",
        {
          email,
          password,
        },
        { withCredentials: true }
      );
```

リクエストにクッキーを付与するためにwithCredentialsを。

# 解決策

localhostで行う場合は、samesite,secure設定はデフォルトでいい。（ライブラリの違いがあるためデフォルト値を確かめる。）

私が誤っていたのは2点。

- CORS_ALLOW_HEADERSに"access-control-allow-credentials"を設定したら、リクエストにクッキーを付与する許可になると思っていた。（access-control-allow-originがそうだったから、、同じようにすればいいと、、、、、）
- axiosの設定で"Access-Control-Allow-Credentials": "true"は必要ない。

CORSでCookieのやり取りをした場合、Access-Control-Allow-Credentialsをtrueにしないといけない。

Access-Control-Allow-Credetials＝trueってのを設定するためにはバックエンドは

****CORS_ALLOW_CREDENTIALS****

という値を設定する必要がある。(drfだったら)

またフロントもaxiosのheadersに"Access-Control-Allow-Credentials": "true"を書いても意味ない。

withCredentials:trueでCookieなどの資格情報を使用することができる。

gitのissueにもあった。
https://github.com/iMerica/dj-rest-auth/issues/192


express使ったときは

https://qiita.com/att55/items/2154a8aad8bf1409db2b

にAccess-Control-Allow-Credetials＝trueを設定する方法が載っていた。


httpsでローカルでやりたい人はコンテナを使えば楽。
steveltn/https-portalイメージを使用してみたがとても簡単にhttps設定ができた。
RHEL7にOpenFOAM-10をインストール

# はじめに

会社の計算サーバー(RHEL7)にOpenFOAM-10をインストールしてほしいと頼まれて試行錯誤した結果をまとめました。[公式ページ](https://openfoam.org/download/10-linux/)ではDockerを使ったインストール手順が書かれていますが、なぜか上手くいかなかったのでソースコードをコンパイルしてインストールしました。
OpenFOAM-11のインストールも試してみましたが、ParaViewのバージョンが上がりQt 5.12をRHEL7にインストールできなかったためインストールできませんでした。

The OpenFOAM FoundationがリリースしているOpenFOAMはGcc&Ubuntu以外の対応があまりできていないようなので、RHELにおいてはOpenCFDが提供している方(openfoam-v2212など)を使う方がよさそうです。

https://www.openfoam.com/current-release

# 環境

OS: RHEL 7.9

# 手順

以下はすべて管理者権限で実行します。まず依存パッケージをインストールします。

```bash
yum install openmpi openmpi-devel bison zlib-devel flex flex-devel gnuplot \
      readline-devel ncurses-devel libXt-devel boost-devel \
      qt5-qtbase-devel qt5-qttools-devel qt5-qtx11extras-devel
```

OpenFOAMのコンパイルにはgcc 5.4以上が必要なので、devtoolset-7をインストールします。

```bash
yum install devtoolset-7
```

またCMakeも新しいバージョンが必要なので、最新版のバイナリを[公式ページ](https://cmake.org/download/)からダウンロードしておきます。

```
wget https://github.com/Kitware/CMake/releases/download/v3.26.4/cmake-3.26.4-linux-x86_64.sh
chmod +x cmake-3.26.4-linxu-x86_64.sh
mkdir /opt/cmake/cmake-3.26
./cmake-3.26.4-linxu-x86_64.sh --prefix=/opt/cmake/cmake-3.26 --skip-license
```

[公式ページ](https://openfoam.org/download/10-source/)に従ってソースコードを`/opt/OpenFOAM`の下にダウンロードします。

```bash
mkdir /opt/OpenFOAM
cd /opt/OpenFOAM
wget -O - http://dl.openfoam.org/source/10 | tar xvz
wget -O - http://dl.openfoam.org/third-party/10 | tar xvz
mv OpenFOAM-10-version-10 OpenFOAM-10
mv ThirdParty-10-version-10 ThirdParty-10
```

次にOpenFOAMのバグを修正します。`$WM_PROJECT_DIR/src/OpenFOAM/db/dictionary/entry/entryIO.C`の159行目を下記の様に修正します。

```diff
- && functionName == functionEntries::inputSyntaxEntry::typeName
+ && functionName == functionEntries::inputSyntaxEntry::typeName_()
```

ここまでで準備ができたのでコンパイルします。

```bash
export PATH="/opt/cmake/cmake-3.26/bin:/usr/lib64/qt5/bin:/usr/lib64/openmpi/bin:$PATH"
scl enable devtoolset-7 bash
source /opt/OpenFOAM/OpenFOAM-10/etc/bashrc
cd /opt/OpenFOAM/ThirdParty-10
./Allwmake
# ParaViewをコンパイルするときの並列数は環境変数WM_NCOMPPROCSで指定できる。
export WM_NCOMPPROCS=20
./makeParaView
wmRefresh
cd /opt/OpenFOAM/OpenFOAM-10
# OpenFOAMを並列コンパイルするときの並列数はjオプションで指定できる。
./Allwmake -j 20 
```
はてなブログ エラー「Entry limit was exceeded」

[はてなブログAtomPub](https://developer.hatena.ne.jp/ja/documents/blog/apis/atom/#%E3%83%96%E3%83%AD%E3%82%B0%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%81%AE%E6%8A%95%E7%A8%BF)のAPIを利用して数百件の記事をはてなブログへ投稿しようとしたところ、下記エラーが発生しました。

```
<p class="error-box">Entry limit was exceeded</p>
```

はてなブログの仕様で、２４時間以内に投稿（下書き含む）ができる記事の上限が１００記事に制限されているようです。

はてなブログダッシュボードから投稿しようとしても、下記メッセージが表示されます。

```
24時間以内に書ける記事数の上限に達しています。しばらく時間をおいてから再度お試しください。
(24時間以内に書ける記事数には、保存した下書きやインポートした記事も含まれます。)
```

はてなブログProの場合でも制約にはかかるようなので、短時間で大量の記事を投稿したいのであればWordPressが良いかと思います。
【SwiftUI】onChangeの古い値を取る方法

# はじめに
`onChange`で古い値を使いたくなったのでやり方を調べたら可能そうだったので記録しておきます。

# 実装
```swift
import SwiftUI

struct ContentView: View {
    @State private var text = ""
    var body: some View {
        TextField("", text: $text, axis: .horizontal)
            .onChange(of: text) { [text] newValue in
                print("古い値:", text)
                print("新しい値:", newValue)
            }
    }
}
```

# おわり
こんなことできるの知りませんでした

# 参考記事
https://blog.code-candy.com/swiftui_onchange/
【VB.NET 学習】Web フォームのTEXTの表示制御

# はじめに
VB.NETで業務アプリの開発を行っており、その中で
データベースから取得したデータの内容によりgridviewへの表示を制御する処理を作成で少し躓いたのでここにメモとして残すことにしました。

# やりたかったこと
データベースから取得した値が空文字でない場合、TEXTとして値を表示
空文字の場合は、値なしを表示する
以上から、以下のコードを記載した
```
 Text='<%#If(Not "".Equals(Eval("値")), Eval("値"), "値なし")  %>'
```

しかし想定した動きにならない！

何度か確認した後、条件式が間違っていることに気付いた。
以下の記述に修正したところ想定通りの動きとなった。

```
 Text='<%#If(Not "　".Equals(Eval("値")), Eval("値"), "値なし")  %>'
```

に変更したところ、想定通りの処理が実現した

# 結果
全角文字を出力しようとしていたのに、条件式では半角文字を設定していた
どんなデータを出力しようとしているのかを確認すること、把握しておくことの必要性を感じました。
Mac VScode 現在設定されているショートカットを確認する

# 概要

- MacのVScodeにて現在設定されているショートカットの一覧を確認するショートカットをまとめておく。

# 方法

- 下記のショートカットキーを押下することで、現在設定されている各種ショートカットを確認する事ができる。

    ```
    「command」 + 「k」実行後に「command」 + 「s」
    ```
[CDGC] Youtube の技術系動画

# はじめに
[インフォマティカ](https://www.informatica.com/jp/)では、技術系の[Youtubeチャンネル](https://www.youtube.com/@INFASupport)を開設しており、2,800本以上の動画で最新技術動向をキャッチアップ頂けます。
英語コンテンツが多いですが、Youtubeの翻訳字幕機能を使うことで、日本語でも十分、理解していただくことが可能です。2023/07時点の情報を元にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110338/1850eb22-756b-bf17-ac20-e89d29f5cec6.png)




<!-- 各チャプター -->
# Youtube チャンネル
- [Informatica Support : @INFASupport](https://www.youtube.com/@INFASupport)
主に技術情報を解説しているチャンネルです。数分から1時間を超えるものまで多種ありますが、主には5分以内くらいで一つの技術トピックを、デモを交えて解説している動画が多くあります。
特定の機能やサービスを深掘りしたい場合に最適です。

https://www.youtube.com/@INFASupport

# CDGCに関する、再生リスト
上記のInformatica Supportチャンネルは、製品毎に再生リストが用意されており、CDGCに関しても既に28本を超える動画が用意されています。
https://www.youtube.com/watch?v=QP8IBKUkffg&list=PLmi6HWWEAjKpTb4RvblYmY1I6bPlHmLYv

- お勧め動画
    - [What's New in Cloud Data Governance and Catalog - April 2023](https://www.youtube.com/watch?v=-wlIw53TNvY)
年数回に実施されるメジャーバージョンアップのアップデートをコンパクトに紹介しています。

    - [Custom Lineage in CDGC](https://www.youtube.com/watch?v=wZM0ksDHPDE)
少しマニアックな機能ですが、カスタムでリネージュを設定するためのHow to動画です。ドキュメントからは読み取りづらい情報を動画で解説されているので、理解が深まります。

    - [Best Practices for Implementing Cloud Data Governance and Catalog](https://www.youtube.com/watch?v=E5Bo1AUYLS8)
少し長い動画ですが、アーキテクチャからサイジング、各種機能の開設など、設計・構築に関わるノウハウを提供します。

    - [Scanning & Data Discovery Best Practices in Cloud Data Governance & Catalog](https://www.youtube.com/watch?v=Wd3NiwKcRGU)
こちらも少し長い動画ですが、メタデータのスキャンに関するノウハウを提供しています。



:::note warn
動画内ですべての機能・パラメータを紹介しているわけではないので、マニュアルやナレッジベースも参照しながら、調査・理解することをお勧めします
:::


# 参考文献
- [Informatica @InformaticaCorp](https://www.youtube.com/@InformaticaCorp)
インフォマティカの企業公式Youtubeチャンネルです。イベントやインタビューの動画が多くアップされています
go基本構文メモ

すぐ見れるようにメモしておく

## for
```go
for i := 0; i < 10; i++ {
	sum += i
}
```	

## for (range)
```
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}

for i, v := range pow {
	fmt.Printf("2**%d = %d\n", i, v)
}
```

https://go-tour-jp.appspot.com/moretypes/16

## if
```go
if x < 0 {
	return sqrt(-x) + "i"
}
```	

### if short style
```go
if v := math.Pow(x, n); v < lim {
    return v
}
```

### if and else
```go
if v := math.Pow(x, n); v < lim {
    return v
} else {
    fmt.Printf("%g >= %g\n", v, lim)
}
```
https://go-tour-jp.appspot.com/flowcontrol/7

## Switch

### switch
```go
switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("OS X.")
case "linux":
    fmt.Println("Linux.")
default:
    // freebsd, openbsd,
    // plan9, windows...
    fmt.Printf("%s.\n", os)
}
```
https://go-tour-jp.appspot.com/flowcontrol/9

### switch with no condition
```go
t := time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("Good morning!")
case t.Hour() < 17:
    fmt.Println("Good afternoon.")
default:
    fmt.Println("Good evening.")
}
```
https://go-tour-jp.appspot.com/flowcontrol/11

## Defer
### defer
```go
func main() {
	defer fmt.Println("world")

	fmt.Println("hello")
}
```

https://go-tour-jp.appspot.com/flowcontrol/12


----

## 文字列のフォーマット
```go

text := fmt.Sprintf("id: %d, value: %s", index, value)
```
Selenium4.10.0でwebdriver.Chrome()でエラー

# 事象
pip install seleniumで、7月14日時点で最新バージョンの4.10.0をインストール。

webdriver.Chrome(WEB_DRIVER_EXE)で以下の警告が現れる。
「Expected type 'Optional[Options]', got 'str' instead 」

```python
# Chromeドライバ
WEB_DRIVER_EXE = r'chromedriver.exe'

driver = webdriver.Chrome(WEB_DRIVER_EXE)

```

実行すると、
AttributeError: 'str' object has no attribute '_ignore_local_proxy'
となってコケる。

なお、chromedriver.exeは.pyと同フォルダにもちろん配置済み。

# 対応

seleniumのバージョンを4.8.3にさげたら通った。
djangoで所有者でないレコードにアクセスできないようにする

# はじめに
djangoで、Recordというモデルがあるとします。そのRecordには所有者(owner)というフィールドをもっているとします。更新画面のURLではRecordのプライマリキーを持たせるようにしていて各Recordの更新画面にアクセスしています。「ログインしているユーザー」と「アクセスしようとしているRecordの更新画面の所有者」が異なる場合、アクセスを拒否させたいです。これの実現方法を3つ模索しました。紹介していきます。

- get_object関数に所有判定を書く
- dispatch関数に所有判定を書く
- get関数に所有判定を書く

# get_object関数に所有判定を書く
### サンプルコード
```.py
class RecordUpdateView(LoginRequiredMixin, UpdateView):
    #...

    def get_object(self, queryset=None):
        # 所有者でないレコードにアクセスできないようにする
        record = super().get_object()
        if self.request.user == record.owner:
            return record
        else:
            raise PermissionDenied

    #...
```
### 考察
- これが一番無難な実装かなと個人的には思います。
- 仮に他のViewで同様のことがしたい場合、`SingleObjectMixin`を継承しているViewクラス(DeleteViewなど)でないと使えないかもしれません。`SingleObjectMixin`が`get_object`関数を持っているためです。

# dispatch関数に所有判定を書く
### サンプルコード
```.py
class RecordUpdateView(LoginRequiredMixin, UpdateView):
    #...

    def dispatch(self, request, *args, **kwargs):
        # 所有者でないレコードにアクセスできないようにする
        record = super().get_object()
        if self.request.user == record.owner:
            return super().dispatch(request, *args, **kwargs)
        else:
            raise PermissionDenied

    #...
```
### 考察
- ChatGPTに質問して、返ってきた提案です。
- 未ログインの状態で該当のURLにアクセスした場合も所有者判定が行われてしまいます。これは違和感を感じる方も出てくるのではないかと思います。

# get関数に所有判定を書く
### サンプルコード
```.py
class RecordUpdateView(LoginRequiredMixin, UpdateView):
    #...

    def get(self, request, *args, **kwargs):
        # 所有者でないレコードにアクセスできないようにする
        record = super().get_object()
        if self.request.user == record.owner:
            return super().get(request, *args, **kwargs)
        else:
            raise PermissionDenied

    #...
```
### 考察
- `get`関数というだけあり、GETメソッド場合しか判定がされないと思います。
- `get`関数は多くのViewクラスで持っているため、応用すれば`SingleObjectMixin`を持ってないクラスでも使用できそうです。(Recordを親としたデータリストのViewなど)

以上です。

# 参考

https://selfs-ryo.com/detail/django_class-based-view_methods#get_object
ファイブフィンガーの発表をきいての感想

# はじめに
アウトプットを目的にはじめた
Qiita執筆活動ですが
今回は技術的なことから少しはずれて、
チームの取り組みについて書きます。

2023/06/28に、大崎にあるfreeeさんのオフィスで開かれた
TechBrew　というイベントに参加しました。
感じたことの中でも、印象に残った「ファイブフィンガー」について、
非スクラムマスターの立場から書いていきたいと思います。

https://findy.connpass.com/event/283154/

## ファイブフィンガーとは
ファイブフィンガーとは、参加メンバーが一斉に 0 から 5 の 6 段階の投票をする手法です
指の本数の意味は下記のようになり

| 指を上げた数 | 状態 |
|:-:|:-:|
|  ５ |  最高 |
|４|  まあ良い調子 |
| ３  |  普通 |
|  ２ |  あまり良くない |
|   １|   良くない|
|   ０|  最低 |（）

一目で可視化された個人の意見を確認でき、
尚且つ投票タイミングも同時なので、他人の意見に影響されずに
個人の意見を見ることができます。

## 感想
LT会の発表では
リファインメントなどの文脈で使用されていますが
弊社では日々の調子を発表する文脈で使われています

**結論　良い投票方法だと思います。**

理由は「他人の意見に引っ張られることなく自身の素直な感想が言えるから」です。
上記のLT会でも登壇されていたおおいしさんの記事を「参考」に記載しましたが、
その中に、まさにその通りだと思った文言が下記の言葉です。

>異議があるけど空気を読んで言い出しにくかったり、なんとなく不安だけど皆が大丈夫そうなので言わなくていいやと思ってしまいがちです。

「優秀な誰かがそう言っているからそうだろう」
そう思うことは不自然なことではないと思います。

自身の社会人経験を思い返した時、
チームに自分より優秀な人がいて、
得てしてその優秀な人が最適解を最短で出し、
その人から説明をきいて
「確かにそうですね」と思うケースが何回もあったなと思いました。
チームメンバーも新人からベテランまでいる場合、
経験の差もあり、答えを出すスピードが変わってくるのは当然ですが、
新人が自分の意見を発表せずに、
ベテランの意見を聞くだけというのは、
ある意味「成長機会を奪うこと」になるのではないかと思いました。

同時に意見をだす仕組みを作ることで、
新人にも意見を出す場が生まれます。
その上でベテランとの意見の差を知るというのは
とても意味のある体験になるなと感じました。

そういった意味ではとても良い取り組みだと思います。
ただ、日々の体調を発表する文脈で
毎日やっていると「4」が
「つっこまれない」ベストアンサーみたいになってしまう状況が生まれてしまう可能性もあるなと思います。
みんなが「４」をだすのがある意味「当たり前」になると
「３」をだして心配されたり
「５」をだして突っ込まれたり
をさけて「４でいいや」という状況が生まれたりする可能性もあるので
「４」の人にもランダムで「今日の開発内容は順調そう？」などきく
などしてもいいのかなと考えました。

## さいごに
LT会にはじめて参加しましたが、わからない単語もあり
まずいなと思ったのと、
自分のエンジニアとしてのスキル感も肌で感じることができました。
今後もLT会に出ていきたいと思います。

## 参考
https://zenn.dev/bicstone/articles/fist-to-five
Docker+Next.jsでgetdata()するとTypeError: fetch failedする問題について


docker上でnextを使用したフロントエンドを開発しているときにgetdata()をするとfetch failedというエラーが発生する問題に直面しました。

```
TypeError: fetch failed
    at Object.fetch (/frontend/node_modules/next/dist/compiled/undici/index.js:1:26669)
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  cause: Error: connect ECONNREFUSED 127.0.0.1:8080
      at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1247:16)
      at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
    errno: -111,
    code: 'ECONNREFUSED',
    syscall: 'connect',
    address: '127.0.0.1',
    port: 8080
  }
}
```

以下のページでは、「localhostではなく、127.0.0.1を指定する」という解決法がありましたが、これを試しても解決しませんでした。

https://github.com/vercel/next.js/issues/44062

悪戦苦闘しつつも、なんとか解決できたので共有させていただきます。

# 結論
例えば、以下のようなコードの場合、「localhost:8080」をコンテナのIPに置き換えると解決できます。

```ts
async function getData() {
  try {
    const res = await fetch('http://localhost:8080/posts', {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      }
    });
```

コンテナのIPは以下の方法で確認できます。
まず、以下のコマンドでコンテナIDを確認します。

```
docker ps
```

次に、以下のコマンドを「コンテナID」を先ほど確認したコンテナIDに置き換えた上で実行します。
```
docker inspect コンテナID | grep IPAddress
```
すると、"IPAddress"としてコンテナのIPが表示されます。

# コンテナのIPを固定する
コンテナのIPはコンテナを起動し直すたびに変更されてしまうため不都合です。そこで、docker-compose.ymlでコンテナのIPを固定することで不都合を解決することができます。

```docker
version: "3.3"

services:
  frontend:

    ...

    networks:
      fixed_compose_network:
        ipv4_address: 10.254.249.89

    ...

networks:
  fixed_compose_network:
    ipam:
      driver: default
      config:
        - subnet: 10.254.249.0/24
```
こうすることで、毎回IPアドレスを書き換える必要がなくなります。


# 最後に
本番環境で独自ドメインにfetchをする際には、当該ドメインを指定すれば問題なく動作しました。ローカルで開発するときだけ、少し変則的な対応が必要なようです。

## 参考資料

https://mebee.info/2021/08/05/post-40153/

https://zaki-hmkc.hatenablog.com/entry/2021/02/26/234357

https://www.fullstackchannel.com/questions/129
Macのトラックパッドを使いVScodeで「戻る」と「進む」を実現する方法

## はじめに
MacでVSCodeで開発をしていて、ロジクールのMX Master3のマウスを愛用していて特に「進む」と「戻る」がキーボードではなく、マウスでてきるのが良いなーって思ってましたが、最近マウスをよく持っているとやはり手がよく疲れてきて悲鳴を上げてしまってました。

そこで最近マウス離れをするために、Macのトラックパッドをよく使うようになりかなり手が楽になってたのですが、、、
なんとまぁ「戻る」と「進む」のショートカットはよく使うために、マウスでなくキーボードでやるのがやたら億劫にｗ

そんなこんなでどうにかMacのトラックパッドで戻るや進むをVSCodeの設定だけで、やろうとしたけどどうやら難しそう・・・
そこで色々調べてみると、なんと下記の救世主が・・・！！

- **BetterTouchTool**
    - BetterTouchToolの試用期間が終わった後、自動的に有料プランに移行することはありません。
    - 試用期間が終わると、アプリケーションは一部の機能が制限されるか、もしくは全ての機能が利用できなくなる。
    - 45日間無料
    - 買い切りの永久ライセンス有り($21)


| ライセンス          | 料金        |
|---------------------|-------------|
| Standard License    | $9          |
| Lifetime License    | $21         |
| SETAPP              | 月額$9.99~  |



https://folivora.ai/

## 今回やること
- VSCodeにて、Macトラックパッドで**戻る**&**進む**を[`BetterTouchTool`](https://folivora.ai/)を用いて実現させる。

## 前提(準備)
- VSCodeがインストール済
- PCがMacなこと
- マウスで手が疲れていて、トラックパッドに移行したい人向け

## 実際にやってみる
まず、VS Codeのデフォルトの「戻る/進む」のショートカットは以下のとおりです。

- 戻る：`Ctrl + -`
- 進む：`Ctrl + Shift + +`

**※自分は進むを`Ctrl + Shift + -`ではなく、`Ctrl + +`に変えていたのですが、そこは適宣変更ください。**

では、`BetterTouchTool`を使ってMacのタッチパッドでの3本指ジェスチャをVSCodeの進む・戻るに設定する手順をざっくり以下に記載します。


1. [`BetterTouchTool`](https://folivora.ai/)をインストールして権限周りOKして開いたところまでいきます
![スクリーンショット 2023-07-14 19.22.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/b0cb6dad-37e6-3326-91e9-24e0bea1b210.png)

2. 下記の+ボタンを押します
![スクリーンショット 2023-07-14 19.29.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/1b76ba12-00bf-b0e0-d595-7f366a40ffbe.png)

3. VSCodeを選んで追加します
![スクリーンショット 2023-07-14 19.30.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/38904c75-91b4-1b19-d9e1-293ea8d57bdc.png)

4. 上部のメニューから「トラックパッド」を選択します
![スクリーンショット 2023-07-14 19.30.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/2024beda-ecbc-6b5f-f08e-f325e5246708.png)

5. トリガーを選択して、3本指のジェスチャーを選択して、「3本指で右にスワイプ」を選択(お好みで)
![スクリーンショット 2023-07-14 19.31.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/9c97cd19-2d99-f01b-e146-1e4761d408ca.png)


6. キーボードショートカットを送信するをクリックして、VSCodeで「進む」に設定しているショートカットを入力(赤文字で表示されているやつは、VSCodeを選んで設定していたら無視しても大丈夫です)
![スクリーンショット 2023-07-14 19.45.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/e740634f-67a7-f0ea-706d-a8f331a7ca18.png)

7. 同様に戻るも設定します

８. 完了（他は特に設定してなくて大丈夫です)
![スクリーンショット 2023-07-14 19.33.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1040483/75663609-7751-14c5-9309-cac9acc2af5d.png)

以上で設定は完了です。
VSCodeを開き、3本指のスワイプ(お好み)で「進む」「戻る」が行えることを確認してみてください！

## 終わりに
トラックパッド疲れなくて快適ですね！！
自分は無料版終わったら、永久ライセンス購入するつもりです！！

- BetterTouchTool

https://folivora.ai/