OmniAICreator/Qiita-1.07M huggingface dataset:
Passport.js v0.6.0で認証後のリダイレクト時にセッション情報が保持出来ていない問題の対処方法




# はじめに

**Passport.js v0.6.0を利用している方向けの内容です**

Passport.js v0.6.0ではログインをすると、デフォルト設定の場合、それ以前のSession情報が破棄されてしまいます。

SAML認証自体は問題なく出来るのですが、例えば、ログインしていない状態でURLにアクセスすると、「流入元のURLの情報がログイン処理中に失われて、流入元URLにリダイレクトできない」です。

**Passport.js v0.4.1** を利用して実装している「[ローカル環境のみで完結するSAML SSOサンプル(node, express, saml-idp利用)」](https://qiita.com/murasuke/items/9bf5ca8083d1da3dd66f) で紹介されている[サンプルコード](https://github.com/murasuke/simple-saml-auth)(の routes/auth.ts）では、ログインしていない状態でURLにアクセスをすると、下記の流れで処理が進むと思いますが、**v0.6.0では同様の挙動をしてくれません**。

1. 認証チェックのロジックに入り、 `req.session.requestUrl` にアクセスしたURLをセットする
1. ログイン画面に遷移し、ログインをする
1. POST /login/callback が呼ばれて、`req.session.requestUrl` にセットされたURLにリダイレクトする

```（抜粋）auth.ts

// <省略>

const authModule = passport.authenticate('saml', { failureRedirect: '/login/fail' });

// <省略>

 /**
  * idpで認証後のコールバックURL
  * ・この時点で、認証されたユーザ情報が「req.user」にセットされる
  * ・リクエスト時のURLにリダイレクトする
  */
router.post('/login/callback', authModule, (req, res) => {
  if ((req as any).session) {
    res.redirect((req as any).session.requestUrl);
    delete (req as any).session.requestUrl;
  } else {
    res.redirect('/');
  }   
});


// <省略>

/**
* 認証チェック
* ・全てのReact側からの通信に対して、認証チェックを行う
*   ⇒認証されていない場合は、saml認証を行う
*/
router.all(['/*'], (req, res, next) => {
  
  // <省略>

  console.log(`${req.url} Not authenticated. Redirect to /login`);
  // リクエストされたurlをセッションに保存してから、idpへ認証を依頼
  (req as any).session.requestUrl = req.url;
  return authModule(req, res, next);
});
```


[サンプルコード](https://github.com/murasuke/simple-saml-auth) をv0.6.0を利用して動かすと、３の処理で `req.session.requestUrl` の値が `undifined` になってしまい、流入元のURLにリダイレクトできません。
これは1の処理のセッションと３の処理のセッションが異なっていることが要因です。
（＝sessionIDが違う。 `req.sessionID`を各処理でconsole.logで出力することで確認できます。）

# 対応策

Passport.js v0.6.0で v0.4.1と同様の挙動にするには、 `passport.authenticate` のオプションに `keepSessionInfo: true` を設定すればよいです。

```js
const authModule = passport.authenticate(
    'saml',
    {
        failureRedirect: '/login/fail',
        keepSessionInfo: true, // これ！！
    }
);
```

# 参考記事

- [ローカル環境のみで完結するSAML SSOサンプル(node, express, saml-idp利用)](https://qiita.com/murasuke/items/9bf5ca8083d1da3dd66f)
- [Session is reconstructed completely after login method #949](https://github.com/jaredhanson/passport/issues/949)
- [passport/CHANGELOG.md](https://github.com/jaredhanson/passport/blob/1e8f112bd233dbffb1904d4dd2051780d81b0a22/CHANGELOG.md)
社内サイト構築勉強⑤(さくらのレンタルサーバ+Laravel)：新規画面の作成

# 前提・概要
プロジェクトは前回記事にて作成したものを想定。

# 本日の完成形
カスタマイズした画面を表示できるようにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284198/7f6c8beb-6f3d-0422-8119-2c3472cda60e.png)

## 1.新規画面の作成
新規画面を作成する。ディレクトリ構成は下記を想定。
（名称の想定としては、受注した案件データを表示できる画面を想定。）
```bat:
app
　└　Http
　　　└　Controllers
　　　　　　└　OrderController.php　・・・3
resources
　└　views
　　├　welcome.blade.php (topページ)・・・1
　　└　daily
　　　　└　order
　　　　　　　└　index.blade.php・・・4
routes
　└　web.php　・・・2
```


### ①topページからのhref設定
topページから新規ページへの画面遷移する設定を行う。

```php:welcome.blade.php のメニュー部分
    ・・・
    <a class="collapse-item" href="/order">受注データ一覧</a>
    ・・・
```

### ②web.phpでのルーティング設定
業務ロジックになるためコントローラー経由にする。
```php:web.php
    //追加
    Route::get('/order', [App\Http\Controllers\OrderController::class, 'index'])->name('order');
```
### ③コントローラーの作成
HomeController.php をコピーし、OrderController.phpを作成。
将来的には、indexメソッド以外に諸々作成すると思われる。
```php:OrderController.php
// mod start
// class HomeController extends Controller
class OrderController extends Controller
// mod end
・・・
    public function index()
    {
        // mod start 
        // return view('home');
        return view('daily.order.index');
        // mod end
    }
}
```

### ④index.blade.phpの作成
テスト用にとりあえずの作成。
```php:index.blade.php
test
```

### ⑤疎通確認
ローカルサーバを起動しておきメニューで設定した部分をクリック。
「test」と表示されるか確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284198/4d826e89-fe6a-589a-e595-6451d8ca360c.png)


## 2.画面を共通化
画面追加の際の手順は共通であるため、追加方法を一般化できるようにする。
（メニューバーはそのままだったり、タイトル部分を変えたりとかは同じなので）

イメージとしては、topページのメニューバー以外の部分をコンテンツとしておき、
各ページ内容を埋め込むイメージ。

### ①トップページにコンテンツが共通部分であることを定義する
- タイトルの部分を埋め込みに変更
- コンテンツの部分を埋め込みに変更

```php:welcome.blade.php のメニュー部分
welcome.blade.phpのContent Wrapperの部分を全て削除し、yieldに置き換える。

    // mod start
        <!-- <title>SB Admin 2 - Dashboard</title> --> // ←　削除する
        <title>@yield('title')</title>
    // mod end

    // mod start
    <!-- Content Wrapper -->
        <!-- ・・・ --> // ←　削除する
        @yield('content')
    <!-- End of Content Wrapper -->
    // mod end
```

### ②index.blade.php
先程作成した、index.blade.phpにて、title・contentの内容を作成する。

```php:index.blade.php
@extends('welcome')
@section('title', '受注データ一覧')
@section('content')

受注データ一覧

@endsection
```

### ③動作確認
サーバ起動し、ブラウザにてアクセス。
タイトルおよびコンテンツの部分が変わっていることを確認する。
今後、画面を追加する際には、同様の手順で変更される部分だけを実装していく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284198/7f6c8beb-6f3d-0422-8119-2c3472cda60e.png)
Python でコマンドライン引数のリストを取得してみました

## 概要

pythonプログラムでコマンドライン引数のリストを取得する２つの方法を確認しました。

### 実行環境

macOS Ventura 13.0
python 3.8.12

---

### １． sysモジュールのargvを使用する方法

実行するプログラムは以下となります。

```python:func_variable_args.py
import sys

def func_args(args):
    print('args = ', args)
    args = sys.argv
    if len(args) > 1:
        print('Argument is ', str(len(args)))
        for i in range(1, len(args)):
            print(args[i])
    else:
        print('Arguments is not good')

if __name__ == '__main__':
    args = sys.argv
    func_args(args)
```

プログラムを実行してみます。

```
$ python func_variable_args.py 2023-01 2023-02
args =  ['func_variable_args.py', '2023-01', '2023-02']
Argument is  3
2023-01
2023-02
```


### 2． argparseモジュールを使用する方法

実行するプログラムは以下となります。

```python:func_list_args.py
import argparse

def func_args(args):
    print('args = ', args)
    print('Argument is ', str(len(args)))
    for i in range(0, len(args)):
        print(args[i])

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='list引数の確認')
    parser.add_argument('--alist', type=str, required=True, nargs="*", help='a list of str variables')
    args = parser.parse_args()
    func_args(args.alist)
```

プログラムを実行してみます。

```
$ python func_list_args.py --alist 2023-01 2023-02
args =  ['2023-01', '2023-02']
Argument is  2
2023-01
2023-02
```

---

### まとめ

ケースバイケースで使い分けていきたいと思います。
WSL2環境でapt-get updateに失敗する

# 問題
WSL2環境にてapt-get updateに失敗する

## 原因
セキュリティソフトが原因()
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442933/457f08d4-8a68-16f3-d0da-1fbd007d8ffe.png)

## エラー内容


**Some index files failed to download. They have been ignored, or old ones used instead.**

```powershell
~$ sudo apt-get update
Ign:1 http://security.ubuntu.com/ubuntu jammy-security InRelease
Ign:2 http://archive.ubuntu.com/ubuntu jammy InRelease
Ign:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Ign:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Ign:1 http://security.ubuntu.com/ubuntu jammy-security InRelease
Ign:2 http://archive.ubuntu.com/ubuntu jammy InRelease
Ign:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Ign:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Ign:1 http://security.ubuntu.com/ubuntu jammy-security InRelease
Ign:2 http://archive.ubuntu.com/ubuntu jammy InRelease
Ign:3 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Ign:4 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Err:1 http://security.ubuntu.com/ubuntu jammy-security InRelease
<!-- 省略 -->
W: Some index files failed to download. They have been ignored, or old ones used instead.
```

## 解決方法
解決方法は２つあります。

### 1.Symantecくんを消す
+ 消すことができる環境であれば、最も手軽で楽な方法です。
(学校・企業などでは消せないことも...)

### 2.Proxyを経由させる

1. Proxyのインストール
https://squid.diladele.com/

1. bashrcを編集してProxyを経由させる
    > nano ~/.bashrc
    ```
    export http_proxy="http://<windows host ip address>:3128"
    export https_proxy="http://<windows host ip address>:3128"
    ```

1. リソースの再読み込み
    > source ~/.bashrc
1. 再度アップデートを実行する
    > sudo apt update

## 心の声
Symantecくん...私の時間を返して...
Javaを基本からまとめてみた【配列】

## 配列
- 配列は同じデータ型の変数を複数まとめて管理するもの
- 配列の生成には『new』を使う。生成時にデフォルト初期値が設定される。
※ 初期値：整数や少数なら０,文字なら空文字 ("") , 真偽値ならfalseが設定される
る

```
データ型[]配列名 = new データ型[要素数];
例)int[] score = new int[3];
score[0]= 80; 　//添字([]内の数字)は０から
```
- 配列の初期化

```
データ型[] 配列名 = {値１, 値２,・・・}
```
- 配列名.lengthで配列の要素数を取得できる


```sample.java
public class Array01 {
	public static void main(String[] args) {
		int score[] = new int[3];
 
		score[0] = 35;
		score[1] = 64;
		score[2] = 43;

        String[]name = {"A","B","C"};
 
		System.out.println(name[0]+"さん：" + score[0] + "点");
		System.out.println(name[1]+"さん：" + score[1] + "点");
		System.out.println(name[2]+"さん：" + score[2] + "点");
        System.out.println("受験者数：" + score.length + "点");
	}
}
```
## 多次元配列
- 配列の配列を作る

```
データ型[][] 配列変数名
例) int[][] num;

```

```sample.java
public class Array02 {
	public static void main(String[] args) {
		int allScore[] = new int[2][3];
 
		allScore[0][0] = 15;
        allScore[0][1] = 34;
        allScore[0][2] = 65;
        allScore[0][3] = 95;
        allScore[0][4] = 75;

        //多次元配列の初期化　
        int[][] allScore ={{1,2,3},{4,5,6}};

		System.out.println(allScore[0][0] + "点");
		System.out.println(allScore[0][1] + "点");
        System.out.println(allScore[0][2] + "点");
        System.out.println(allScore[1][0] + "点");
        System.out.println(allScore[1][1] + "点");
        System.out.println(allScore[1][2] + "点");

        System.out.println("allScore.length:" + allScore.length);
        System.out.println("allScore[0].length:" + allScore[0].length);
	}
}
```




## 参考サイト
[配列の使い方やメモリ内の動きを理解しよう！多次元配列、コマンドラインからのデータ入力も解説【Java入門講座】2-4 配列](https://www.youtube.com/watch?v=nSmO1s-dkxY)
2023年四半期カレンダー（３月版）

四半期に１回，自分の知識をまとめてアウトプットできる場がほしいなと思い，今回からやってみます

以下の予定（その日に投稿されるとは限らない）で考えています（投稿したらリンクを貼っていきます）
＊内容は予告なく突然変わることがあります
| 日程 | タイトル |
| --- | --- |
| 3/6 | [2023年四半期カレンダー（３月版）](https://qiita.com/0917laplace/items/663c7b78854b5a0d47f7) |
| 3/7 | [耐量子計算機暗号の最新動向（2023年３月版）](https://qiita.com/0917laplace/items/c5d5aab255003cfa9e3e) |
| 3/8 | [格子暗号を用いた準同型暗号の最新動向（2023年３月版）](https://qiita.com/0917laplace/items/f1b66213c1830dc984e0) |
| 3/9 | [TFHEの最新動向（2023年３月版）](https://qiita.com/0917laplace/items/e9f699db183c6e6e0d7f) |
| 3/10 | 「CKKS解説ブログ」を解説する 1/5 |
| 3/13 | 「CKKS解説ブログ」を解説する 2/5 |
| 3/14 | 「CKKS解説ブログ」を解説する 3/5 |
| 3/15 | 「CKKS解説ブログ」を解説する 4/5 |
| 3/16 | 「CKKS解説ブログ」を解説する 5/5 |
| 3/17 | カードベース暗号に入門する 1/4〜シャカパチと秘密計算〜 |
| 3/20 | カードベース暗号に入門する 2/4〜five-card trick〜 |
| 3/22 | カードベース暗号に入門する 3/4〜ランダム二等分割カット〜 |
| 3/23 | カードベース暗号に入門する 4/4〜４枚版five-card trick〜 |
| 3/27 | TFHEを１から実装する 1/5〜前提条件, TLWE〜 |
| 3/28 | TFHEを１から実装する 2/5〜TRLWE, TFHE暗号方式〜 |
| 3/29 | TFHEを１から実装する 3/5〜GGSW暗号方式〜 |
| 3/30 | TFHEを１から実装する 4/5〜Blind Rotation〜 |
| 3/31 | TFHEを１から実装する 5/5〜Key Switching〜 |

＊土日祝と3/24は修了式のためお休みです

ざっくりテーマごとに分けると
3/7-3/9 : ePrintサーベイ
3/10-3/16 : CKKS（理論）
3/17-3/23 : カードベース暗号（理論）
3/27-3/31 : TFHE（実装）
です

がんばります〜
Vue2 × Vuetify でポップアップ画面を実装してみた

## はじめに
Vue.jsのフレームワークであるVuetifyを用いて、ホームページに使うようなポップアップを実装してみました。
大まかな流れは以下のとおりです．

1. ボタンの配置
1. ポップアップ画面の配置
1. ボタンクリックでポップアップ画面が表示されるようにする

## 開発環境
- Windows 11
- Vue CLI 5.0.8
- Vue 2.7.14
- npm 6.14.14
- Node.js 14.17.5


## 実装

### ボタンの配置
ボタンを押すと、ポップアップ画面が表示されるようにしたいので、まずはボタンを追加します。
今回は、以前の記事で作成したプロジェクトの「アカウント」ページに実装していきます。
同じように実装したい方は、こちらの記事を参考にしてください。

https://qiita.com/tatsuki-tsuchiyama/items/bd6a288ec17a57a79a74

![screencapture-localhost-8080-2023-03-04-14_08_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/49a75ef1-7d98-25b4-6fee-bdb1b536e523.png)
ここにボタンを追加します。

ボタンはv-btnタグを使えば追加することができます。

```Account.vue
<template>
    <v-app> 
      <div>
        <p>アカウントのページです。</p>
        <v-btn
        outlined
        class="ma-1"
        color="blue"
        >
          詳細
        </v-btn>
      </div>
    </v-app>
</template>
```
outlinedで枠と文字のみに色を付けることができます。
class="ma-1"でmarginを少しつけます。
color="blue"で枠と文字の色をblueにします。

ここまで完成すると以下のようになります。
![screencapture-localhost-8080-2023-03-04-14_30_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/8a604116-6d22-fd52-bca7-9f51c0b16f4a.png)

### ポップアップ画面の配置
次に、ポップアップ画面を配置します。
v-dialogタグでポップアップ画面を作成することができます。
v-cardタグでカードっぽいデザインにすることができます。

```Account.vue
<template>
    <v-app> 
      <div>
        <p>アカウントのページです。</p>
        <v-btn
        outlined
        class="ma-1"
        color="blue"
        >
          詳細
        </v-btn>
      </div>

      <div>
        <v-dialog 
        v-model="dialog" 
        width="400px"
        >
          <v-card
          width="400px"
          class="mx-auto"
          >
            <v-card-title>アカウントの詳細です。</v-card-title>
          </v-card>
        </v-dialog>
      </div>
    </v-app>
</template>
```

ただ、今のままではイベントを設定していないので、表示はそのままです。

### ボタンクリックでポップアップ画面が表示されるようにする
次にイベントを作成して、ボタンとポップアップ画面を紐づけていきましょう。
dialogという変数がtrueの時はポップアップ画面を表示、falseの時は非表示にするコードを記述します。

以下3点です。
1. v-btnタグにはクリックしたときにdialogをtrueにする記述
1. b-dialogタグにはdialog変数と同期させる記述
1. scritのdataでdialogの初期値をfalseに設定する記述

```Accoumt.vue
<template>
    <v-app> 
      <div>
        <p>アカウントのページです。</p>
        <v-btn
        outlined
        class="ma-1"
        color="blue"
        @click="dialog=true" <!--追加-->
        >
          詳細
        </v-btn>
      </div>

      <div>
        <v-dialog 
        v-model="dialog"  <!--追加-->
        width="400px"
        >
          <v-card
          width="400px"
          class="mx-auto"
          >
            <v-card-title>アカウントの詳細です。</v-card-title>
          </v-card>
        </v-dialog>
      </div>
    </v-app>
</template>

<!--以下、追加-->
<script>
export default {
    data: () => ({
      dialog:false,
    }),
}
</script>
```

これでボタンをクリックすると、以下のようなポップアップ画面が表示されます。
ポップアップ画面の外側をクリックすると閉じることができます。
![screencapture-localhost-8080-2023-03-04-16_09_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/3d10a19b-464f-8e57-6590-fc5460a8abff.png)

## まとめ
Vuetifyにはいろんなタグが用意されていて便利ですね。
今回はテスト用でしたが、デザインなどを改善し、実際の開発に生かしていきたいと思います！
pydata-sphinx-theme v0.13.0で"イベント のハンドラ 'builder-inited' で例外が発生しました。 (exception: 'icon_links')"というエラーが発生

# 環境
* Python3.11.2
* sphinx v6.1.3
* pydata-sphinx-theme v0.13.0

# 背景
sphinxでドキュメントを生成しています。

# エラー
`pydata-sphinx-theme`をv0.12.0からv0.13.0にバージョンアップしたら、ドキュメント生成時に`イベント～のハンドラ 'builder-inited' で例外が発生しました。 (exception: 'icon_links')`というエラーが発生しました。

```python:docs/conf.py
project = "bar"
copyright = "2020"
author = "alice"
language = "ja"
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

html_theme = "pydata_sphinx_theme"

html_theme_options = {
    "github_url": "https://github.com/foo/bar",
}
```

```
$ cd docs
# `-T`でトレースバックを出力
$ sphinx-build . _build/ -T
Sphinx v6.1.3 を実行中
翻訳カタログをロードしています [ja]... 完了
保存された環境データを読み込み中... 完了

Traceback (most recent call last):
  File "/workspaces/annofab-cli/.venv/lib/python3.11/site-packages/sphinx/events.py", line 96, in emit
    results.append(listener.handler(self.app, *args))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/annofab-cli/.venv/lib/python3.11/site-packages/pydata_sphinx_theme/__init__.py", line 202, in update_config
    theme_options["icon_links"].insert(
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^
KeyError: 'icon_links'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/workspaces/annofab-cli/.venv/lib/python3.11/site-packages/sphinx/cmd/build.py", line 279, in build_main
    app = Sphinx(args.sourcedir, args.confdir, args.outputdir,
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/annofab-cli/.venv/lib/python3.11/site-packages/sphinx/application.py", line 262, in __init__
    self._init_builder()
  File "/workspaces/annofab-cli/.venv/lib/python3.11/site-packages/sphinx/application.py", line 335, in _init_builder
    self.events.emit('builder-inited')
  File "/workspaces/annofab-cli/.venv/lib/python3.11/site-packages/sphinx/events.py", line 107, in emit
    raise ExtensionError(__("Handler %r for event %r threw an exception") %
sphinx.errors.ExtensionError: イベント <function update_config at 0x7f0f624ff880> のハンドラ 'builder-inited' で例外が発生しました。 (exception: 'icon_links')

Extension error (pydata_sphinx_theme):
イベント <function update_config at 0x7f0f624ff880> のハンドラ 'builder-inited' で例外が発生しました。 (exception: 'icon_links')
```

# 原因
`pydata-sphinx-theme`v0.13.0のバグのようです。

https://github.com/pydata/pydata-sphinx-theme/issues/1220

# 対策
`html_theme_options`dictに`icon_links`キーの空listを追加することで、`sphinx-build`コマンドはエラーなくドキュメントを生成することができました。

```python:docs/conf.py
project = "bar"
copyright = "2020"
author = "alice"
language = "ja"
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

html_theme = "pydata_sphinx_theme"

html_theme_options = {
    "github_url": "https://github.com/foo/bar",
    "icon_links": []
}
```
変数のスコープ(Python)

***Python3***の変数のスコープのプログラム例です。

```python3
# 変数のスコープ
#  2023/3/6

def get_price(a,b,c):
  # 仮引数 値が代入された変数→ローカル変数
  # 値が代入されていない変数→外のスコープを探す
  # ローカル変数
  total = (a + b + c) * rate
  return format(total,'.0f')

rate = 1.08
print(get_price(300,700,200))

```

値が代入されていない変数は**外のスコープ**を探します。
【Snowflake】ADD_MONTHSとDATEADDの使い分けるときの考え方

# これからはなすこと
+ ADD_MONTHSとDATEADDは条件によって動きが違うこと
+ どのような条件下で動きが違うのか


# 目次
1. ADD_MONTHSについて
2. DATEADDについて
3. 注意点
4. 動きの違いを再現
5. おわりに


# 1.ADD_MONTHSについて
ADD_MONTHS関数について以下説明文引用しました。
>指定された月数を日付またはタイムスタンプに加算または減算し、月末情報を保持します。

```sql:構文.sql
ADD_MONTHS( <date_or_timestamp_expr> , <num_months_expr> );
```
https://docs.snowflake.com/ja/sql-reference/functions/add_months

**例**
```sql:例.sql
SELECT ADD_MONTHS('2023-07-31'::date, 1) AS RESULT;
```
**結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2992046/55bc136f-9d04-2d1e-03f2-e550908a3b1a.png)
元の日付の一か月後が表示されました。

# 2.DATEADDについて
次にDATEADD関数について、以下説明文を引用しました。
>指定された日付または時刻部分の指定された値を日付、時刻、またはタイムスタンプに追加します。

```sql:構文.sql
DATEADD( <date_or_time_part>, <value>, <date_or_time_expr> )
```
https://docs.snowflake.com/ja/sql-reference/functions/dateadd

**例**
```sql:例.sql
SELECT DATEADD(month, 1,'2023-07-31') AS RESULT;
```
**結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2992046/78f1e152-8d08-41b7-0890-e06106ad132c.png)
こちらも元の日付の一か月後が表示されました。

# 3.注意点
公式ドキュメントにはこのような注意点が記載されています。
+ **ADD_MONTHS**は、**MONTH**コンポーネントで使用される**DATEADD**とは少し異なる結果を返します。
    + **ADD_MONTHS**と**DATEADD**の両方で、
    結果の月の日数が元の日より少ない場合、
    月の結果の日は、結果の月の最後の日です。
    + **ADD_MONTHS**の場合のみ、
    元の日が月の最後の日である場合、
    結果の月の日は、結果の月の最後の日になります。

上記の注意点を読み解くと、以下のような解釈ができると考えました。
+ 月末の日付では動きが変わります。
+ （例１）2023年1月31日が元の日付の時、一か月後の結果は2023年2月28日になります。
+ （例２）2023年2月28日が元の日付の時、一か月後の結果は2023年3月31日になります。（**ADD_MONTHS**の場合のみ）


# 4.動きの違いを再現
実際に上記の通りになるか検証してみました。
```sql:1月末の一月後の結果.sql
SELECT
ADD_MONTHS('2023-01-31'::date, 1) AS RESULT,
DATEADD(month, 1,'2023-01-31') AS RESULT2;
```
**結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2992046/e85ade92-5c75-c51a-57fd-ed719b470194.png)

```sql:2月末の一月後の結果.sql
SELECT
ADD_MONTHS('2023-02-28'::date, 1) AS RESULT,
DATEADD(month, 1,'2023-02-28') AS RESULT2;
```
**結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2992046/ba9a54cf-31d5-bffe-fd62-ff9aa86fc94f.png)
注意点通りの結果になっていると思います。
また、マイナス値で日付を遡ることができるのですが、こちらも同じ現象になります。
下記検証結果
```sql:3月末の一月前の結果.sql
SELECT
ADD_MONTHS('2023-03-31'::date, -1) AS RESULT,
DATEADD(month, -1,'2023-03-31') AS RESULT2;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2992046/74ba414c-cf44-f946-e4d7-ead4680396cd.png)
```sql:2月末の一月前の結果.sql
SELECT
ADD_MONTHS('2023-03-31'::date, -1) AS RESULT,
DATEADD(month, -1,'2023-03-31') AS RESULT2;
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2992046/11906626-5e47-324a-5d34-e2ea81b0571e.png)

# 5.おわりに
どちらの関数も売上データ等、月末の日付を扱うものに大きく影響を与える関数だと思います。
例えば、任意の日付からLAST_DAY関数で月末日付を表示してから表題の関数を利用するみたいな感じでしょうか・・・

どちらを使うかはケースバイケースですが、この違いを認識しておくことでロジックを組む際の一助になればと思います。

https://docs.snowflake.com/ja/sql-reference/functions/last_day
Typescriptでメソッドの戻り値によって型付けを保証したい（Argument of type xxxx is not assignable to parameter of type xxxxの対処）


Typescriptを使っている際、よく下記のようなシチュエーション、書き方をしたくなりますよね。
①ある変数がnull、undefinedの可能性がある
②ある変数をisNotNullメソッドにてnull, undefinedでないことをチェックする
③nullでないことが保証されたある変数を別のメソッドに渡す
④Argument of type undefined is not assignable to parameter of type xxxxのエラー
いやいや、isNotNullメソッドでundefinedでないことチェック済やんけ。。。という感じなのですがtsc的にはエラーを出してきます。

### 例
```typescript
type Status = 'success' | 'failuer';
const messages: { [key in Status]: string } = {
  success: '成功',
  failuer: '失敗',
};

const isNotNull = (status: Status | undefined) => {
  if (status == null) {
    return false;
  }

  return true;
}

const getMessage = (status: Status) => {
  return messages[status];
}


let st;

if (isNotNull(st)) {
  console.log(getMessage(st));
  // undefinedではないことをisNotNull関数でチェックしているのに、エラーとなってしまう
  // Argument of type 'undefined' is not assignable to parameter of type 'Status'.
}
```



### 対処法①（Bad）
型アサーションや!を使って無理やり解決できますが、Typescriptの型システムを
台無しにしてしまうので避けたほうが良いです
```typescript
type Status = 'success' | 'failuer';
const messages: { [key in Status]: string } = {
  success: '成功',
  failuer: '失敗',
};

const isNotNull = (status: Status | undefined) => {
  if (status == null) {
    return false;
  }

  return true;
}

const getMessage = (status: Status) => {
  return messages[status];
}


let st;

if (isNotNull(st)) {
  console.log(getMessage(st as any)); // 型アサーションで無理やり解決する
}
```

### 対処法②（Good）
メソッドの戻り値に型付けを行えます。
下記で、isNotNullメソッドの戻りがtrueであればundefinedでないことを明示してみます。
ただし、isNotNull自体がバグっている場合でもtrueが返却されるとその型で認識されてしまうので注意が必要です。
（ここはなんだかなーというところ）

```typescript
type Status = 'success' | 'failuer';
const messages: { [key in Status]: string } = {
  success: '成功',
  failuer: '失敗',
};

// メソッドの戻り値で型付けを行う（status is Statusの部分）
// trueが返った場合、statusはStatus型であるという表現になる
const isNotNull = (status: Status | undefined): status is Status => {
  if (status == null) {
    return false;
  }

  return true;
}

const getMessage = (status: Status) => {
  return messages[status];
}

let st;

// isNotNullがtrueの場合、statusはStatus型であるとtscが認識するため、
// コンパイルエラーは出ない
if (isNotNull(st)) {
  console.log(getMessage(st));
}

// falseの場合はもちろんエラー出る
if (!isNotNull) {
  console.log(getMessage(st));
  // Argument of type 'undefined' is not assignable to parameter of type 'Status'.
}
```

私のレベルの問題かもしれませんが初めて知った時感動しました。
この手のエラーは困ることあるけど、ググり方もわからないし調べづらいので
お役に立てば幸いです。
Vue 3で簡単にlocalStorageを使う方法

## 結論

VueUseの`useStorage`を使う。

```bash
npm i @vueuse/core
```

```js
const storedValue = useStorage('key', value)
```

## 詳細

[VueUse](https://vueuse.org/)とは、Vue 3の[Composition API](https://ja.vuejs.org/guide/extras/composition-api-faq.html#what-is-composition-api)をベースにしたユーティリティ関数のコレクションです。
その中に[`useStorage`](https://vueuse.org/core/useStorage/)というユーティリティがあるので、Vue 3で`localStorage`を扱いたい場合はこちらを使用すると良いでしょう。

### インストール

- パッケージマネージャでインストールする場合

    ```bash
    npm i @vueuse/core
    ```

- CDNでインストールする場合

    ```html
    <script src="https://unpkg.com/@vueuse/core"></script>
    ```

:::note info
`window.VueUse`として公開されます。
:::

### 使用法

`useStorage()`は第1引数に参照に用いるキー名を、第2引数に保存する値を渡します。

```js
const storedValue = useStorage('key', value) 
```

#### 1. 値の保存と取得

便利なことに、`localStorage`では値の保存[`setItem()`](https://developer.mozilla.org/ja/docs/Web/API/Storage/setItem)と取得[`getItem()`](https://developer.mozilla.org/ja/docs/Web/API/Storage/getItem)は別々のメソッドが担っていましたが、`useStorage()`はこれ1つで保存と取得を行えます。
具体的には、上記のように書いた場合

- `localStorage`から`'key'`を探索する
    - `'key'`が存在すればその値を`storedValue`に代入する
    - 存在しなければ`value`をキー名`'key'`で`localStorage`に保存する

という処理が行われます。
また、`useStorage()`の戻り値はリアクティブな`Ref<typeof keyValue>`となるので、`<template>`セクションではそのままアクセスでき、`<script>`セクション内では`.value`でアンラップする必要があります。

#### 2. 値の削除

`localStorage`の削除[`removeItem()`](https://developer.mozilla.org/ja/docs/Web/API/Storage/removeItem)は、`null`の代入で行えます。

```js
storedValue.value = null
```

### デモ

```vue
<script setup>
  import { useStorage } from '@vueuse/core'

  const msg = useStorage('msg', 'Hello World!')

  function clear() {
    msg.value = null
  }
</script>

<template>
  <textarea v-model="msg"></textarea>
  <br />
  <button @click="clear">clear</button>
</template>
```

テキストエリアのテキストを編集して画面をリロードしても、編集した状態が保存されていることがわかります。
`clear`ボタンを押すと`localStorage`に保存された値がクリアされるので、再度リロードすると初期表示`Hello World!`に戻ります。

https://codesandbox.io/embed/vueuse-usestorage-oiyd0z?autoresize=1&fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.vue&theme=dark&view=preview
Standard受験編288

二つの放物線C
```math

C_{1}:y=x^2　と
C_{2}:y=x^2-6x+15の共通接線をlとする。\\
(1)lの方程式を求めC_{1},C_{2}およびｌを図示せよ\\
(2)C_{1},C_{2}およびｌによって囲まれた部分の面積を求めよ\\
```

## 解答
```python
from sympy import *
from sympy.abc import *
eq1 = x**2
eq2=x**2-6*x+15
eq3=m*x+n
print(eq1-eq3)#−𝑚𝑥−𝑛+𝑥^2
print(eq2-eq3)#−𝑚𝑥−𝑛+𝑥2−6𝑥+15
```
ここらか判別式を計算
```python
hanbetu1=(-m)*(-m)-4*(-n)#𝑚^2+4𝑛
hanbetu2=(-m-6)**2-4*(15-n)#4𝑛+(−𝑚−6)^2−60

solve([hanbetu1, hanbetu2], [m,n])#m=2 n=-1

```
グラフを書く
```python
import matplotlib.pyplot as plt
import matplotlib.pyplot as plt
import numpy as np
x=np.linspace(-5,8)
y1=m*x+n
y2=x**2
y3=x**2-6*x+15
plt.grid()
plt.plot(x,y1)
plt.plot(x,y2)
plt.plot(x,y3)


```
交点を求める
```python
#面積を求める
x = Symbol('x')
y2=x**2
y3=x**2-6*x+15

y4=y2-y3
y4
ans=solve(y4, x)
ans
```
交点を求める
```python


y1=m*x+n
y2=x**2
y3=x**2-6*x+15


y7=y2-y1
y8=y3-y1
```
```python

ans1=solve(y7,x)
ans2=solve(y8,x)
```
定積分を求める
```python
# 1     5/2
# 5/2   4

ans=integrate(y7, (x,1,5/2))+integrate(y8, (x,5/2,4))
ans
```
2.25=9/4になる。
AlphaFillを用いてAlphaFold2/ColabFoldで予測された構造とリガンド分子候補との複合体モデルを生成する

この記事にたどり着いた方であれば、AlphaFold2を用いた予測構造の精度が恐ろしく高いことはご存知のことだと思いますが、AlphaFold2は（まだ）リガンド分子との複合体構造を予測してくれません。これに対応するべく、[AlphaFill](https://alphafill.eu/)は入力されたタンパク質の配列や構造をもとに、そのリガンド候補を自動的にサーチし、その位置を自動的に当てはめた複合体構造モデルを返してくれます。コマンドラインでも利用可能ですが、多くの方にとってはブラウザからその機能を利用する方がとても簡単で助かることでしょう。しかしながら、AlphaFillはAlphaFold DBで配信されているmmCIFフォーマットにしか対応しておらず、AlphaFold2/ColabFoldで出力されたpdbフォーマットのタンパク質構造ファイルについては計算を行ってくれません。

この記事ではそれを簡単に解決する方法と、実際の使い方を紹介します。

## pdbファイルフォーマットではどうなる？

試しにATPと結合することがわかっているFur5というタンパク質で試してみます。AlphaFold2/ColabFoldで出力されたタンパク質構造はPDBフォーマットなので、これをAlphaFillにアップロードしてみようとすると

![ScreenShot 2023-03-06 12.03.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/0e97b4c7-8a44-1cf0-69db-d73c587d5a82.png)

Since the file did not start with a valid PDB HEADER line mmCIF was assumed, but that failed. と表示されて開始することができないようです。

## cifフォーマットへの変換

この目的を達成するには、wwPDBが想定するヘッダー情報を含んだmmCIFフォーマットに変換しなければなりません。最も簡単な方法は [PDBjのPDBフォーマット - PDBx/mmCIF 変換サービス
](https://mmcif.pdbj.org/converter/index.php)を利用する方法で、ここにファイルをアップロードして「送信」するだけです。

![ScreenShot 2023-03-06 12.09.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/ee46d011-b6f2-c25b-50b9-33ce5510aa88.png)

次のメニューではデフォルト設定のPDB format -> mmCIF, 改行コードLFのままでOKです。変換は（よほどサーバーが混雑していない限り）数秒で終わるので、メールアドレスを入力しなくても問題ないでしょう。押しましたら変換実行します。

![ScreenShot 2023-03-06 12.10.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/5fff576b-29f3-de6d-aba1-4b41bc7abed4.png)

数秒待ってから「変換処理を確認」ボタンを押して、完了と表示されていましたら、「変換ファイルをダウンロード」からそのmmCIFファイルをダウンロードすることができます。

## AlphaFillにcifファイルをアップロード

そのmmCIFファイルをAlphaFillのフォームからアップロードすると、計算が始まります。

![ScreenShot 2023-03-06 12.17.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/0b5e8769-45c4-920c-3753-2ac04accd62c.png)

およそ1分くらいすると、すでにPDBに登録されてある類縁のタンパク質構造から見つかったリガンド分子との複合体構造モデルを画面に表示してくれます。

![ScreenShot 2023-03-06 12.18.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224327/50da548d-1442-0b26-9863-ac29f2051df9.png)

上のStructure fileを押した場合は全リガンド候補がダウンロードされますが、Showの右側にある↓ボタンを押すと、画面に表示されているものだけがダウンロードされるようです。後者のほうがわかりやすいでしょう。
PHPにおけるオブジェクトとコンストラクタについて復習する

## はじめに
PHPを学習していくと、オブジェクトだったりコンストラクタについてよく出てくる。
laravelを学習し始めてあまり聞かなくなったのだが、最近laravelでもコンストラクタだったりを使うようになったので復習がてら何なのかまとめてみる。

## オブジェクトとは
PHPのオブジェクトは、クラスを定義してから、そのクラスを基にしてインスタンスを生成することで作成される。
オブジェクトを生成するためには、`new演算子`を使用する。

```test.php
class Person {
  // プロパティの定義
  public $name;
  public $age;
  
  // メソッドの定義
  public function sayHello() {
    echo "Hello, my name is " . $this->name . " and I am " . $this->age . " years old.";
  }
}

// Personオブジェクトの生成
$person1 = new Person();

// プロパティへのアクセスと値の設定
$person1->name = "John";
$person1->age = 30;

// メソッドの呼び出し
$person1->sayHello();
```

Personクラスを定義し、`$name`と`$age`の2つのプロパティを持ち、`sayHello()`メソッドを定義する。

次に、`$person1`という名前のPersonオブジェクトを生成し、そのプロパティ`$name`と`$age`に値を設定している。
最後に、`$person1`オブジェクトの`sayHello()`メソッドを呼び出して、中身を出力する。

このように、オブジェクトを生成して、そのプロパティに値を設定し、そのメソッドを呼び出すことで、オブジェクトに対して動作を指示することができる。

## コンストラクタとは
PHPにおけるコンストラクタは、オブジェクトの生成時に呼び出される特別なメソッド。
コンストラクタは、新しいオブジェクトが作成される際に、そのオブジェクトの初期化を行うために使用される。

コンストラクタは、クラス名と同じ名前のメソッドとして定義される。
コンストラクタには、通常、オブジェクトの初期化に必要なプロパティの値を引数として受け取ることができる。

```test.php
class Person {
  public $name;
  public $age;
  
  // コンストラクタの定義
  public function __construct($name, $age) {
    $this->name = $name;
    $this->age = $age;
  }
  
  public function sayHello() {
    echo "Hello, my name is " . $this->name . " and I am " . $this->age . " years old.";
  }
}

// Personオブジェクトの生成
$person1 = new Person("John", 30);

// メソッドの呼び出し
$person1->sayHello();
```

Personクラスに`__construct()`メソッドを追加し、`$name`と`$age`の2つの引数を受け取って、それぞれのプロパティに値を設定する。
$person1オブジェクトを生成する際に、引数として`"John"`と`30`を渡している。

このように、コンストラクタを使用することで、オブジェクトの初期化を簡素化し、プロパティの初期値を設定することができる。
また、コンストラクタを使用することで、オブジェクトの初期化を一貫して行うことができる。

以上。
「Rails7にBootstrap5を導入した」件

# 前書き
Rails7にBootstrap5を入れようと思い、公式ドキュメントの手順を踏んでみたものの各所でエラーを吐いてしまった。


エラーを回避した方法を含め、Bootstrap5の導入手順をここにまとめたい。
なお、既存のアプリに対して導入する手順なので、新規アプリ作成時に導入する方法は記載しない。

# 環境
WSL2
Ubuntu
Docker
Rails7
Ruby 3.1.3


# 実行手順
基本的には[公式ドキュメントに記載の手順](https://rubygems.org/gems/bootstrap)に従うものとする。

```:Gemfile
    gem 'bootstrap', '~> 5.2'
    gem 'mini_racer'
```

railsサーバー起動時にExecJS::RuntimeUnavailableというエラーが出る。これの対応としてmini_racerをGemfileに追記する。

[参考記事]
* [ExecJS::RuntimeUnavailableの解決方法](https://qiita.com/Kawanji01/items/7f1ee4a1306cb43951b8)
* [【Rails】ExecJS::RuntimeUnavailableの解決方法](https://qiita.com/oga_4528/items/7cdc6d8f0c784a9da726)

```:ターミナル
    $ docker compose build
```


`app/assets/stylesheets/application.css`の名前を、`app/assets/stylesheets/application.scss`に変更する。
その後ファイル内に記載の文字列を全て削除し、以下に示すように書き換える。

```scss:app/assets/stylesheets/application.scss
    @import 'bootstrap';
```

`importmap.rb`に追記する。

```ruby:config/importmap.rb
    pin "bootstrap", to: "bootstrap.min.js", preload: true
    pin "@popperjs/core", to: "popper.js", preload: true
```

`assets.rb`を書き換える。

```ruby:config/initializer/assets.rb
    Rails.application.config.assets.precompile += %w(bootstrap.min.js popper.js)
```

railsサーバーを起動して[localhost:3000](http://localhost:3000/)にアクセスする。

# 補足
サーバー起動後、`Asset was not declared to be precompiled in...`というエラーページに飛ばされることがあった。

エラーメッセージの後に続く文章に示された方法を試した。
以下の内容を`manifest.js`に追記する。

```js:app/assets/config/manifest.js
    //= link popper.js
    //= link bootstrap.min.js
```

# 補足②
ドロップダウンメニューなどが正常に動作しなかったため、その対応方法を調べた。
Javascriptの読み込みが必要で、下記に示す変更を行った。

```js:app/javascript/application.js
    import "popper" //追記
    import "bootstrap" //追記
```

# 終わりに
railsを半年ほど前から触りはじめましたが、まだまだ勉強不足に感じます。
拙い点が目立つと思われますが、どうかご容赦を......

私と同じくrails初学者の方あるいはそうでない方でも、この記事が誰かの参考になっていれば嬉しく思います。良きエンジニア・ライフを！
whoとwについて

## 環境
Ubuntu20.4

## who
whoは、現在ログインしているユーザーの一覧を表示するコマンドです。自分の環境では、ローカルでUbuntuを動作させており、基本的に自分だけしかログインすることがないため、自分のユーザー名（vagrant）だけが表示されています。**pts/0**はTTYと呼ばれる、仮想端末（ターミナル)名です。そして、ログインした時間と、括弧の中にログイン元が表示されます。

サーバーに複数ユーザーがログインして利用する環境であれば、サーバー管理をする場合に必要となるコマンドです。「これから、サーバーを再起動するので、ログインしている人はログアウトしてください」というアナウンスを出した後、「まだ、ログインしている人はいないだろうか」と、確認するときは、このコマンドで確認することができます。また、不審な人がログインしていないかを調べるときにも使います。
```
$who
vagrant  pts/0        2023-03-06 09:42 (10.0.2.2)
```

## w
whoによく似たコマンドでwというコマンドがあります。wを使ってもログインしているユーザーの一覧を表示することができますが、wでは更に、whoよりももっと詳細な情報を表示することができます。誰がログインしているかだけでなく、ログインしているユーザーが、現在何の処理を流しているのかを表示することができます。

ヘッダにはOSの稼働状況が表示されます。ヘッダに表示される情報は、左から、現在の時刻、ログインして何分が経過したかが表示されます。up 49 minと表示されているため、ログインして49分経過したことが分かります。次の表示は、ログインしているユーザー数です。現在ログインしているユーザーは自分だけなので、1と表示されます。load averageは負荷状況を表します。負荷状況は、１分間、５分間、１５分間と３種類が表示されます。現在の負荷状況は、何も処理を流していないため、全て、0.00が表示されています。**JCPU**は、ユーザーが、ログインしてから実行されたプロセスが何分だったかを表示します。**PCPU**は、現在、実行中のプロセスが何分実行されているかを表示します。**WHAT**は、ユーザーが現在何の処理を実行しているかを表示します。現在、自分はwコマンドを実行したので、wが表示されています。

複数人がサーバーにログインしている場合、誰が重たい処理を流しているのかをここで確認することができます。
```
$w
10:31:00 up 49 min,  1 user,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
vagrant  pts/0    10.0.2.2         09:42    1.00s  0.14s  0.00s w
```
niconicoアニメスクレイピングツールの紹介

こんにちは！今日は新しいniconicoアニメスクレイピングツールについて紹介します。このツールは、Pythonで書かれたスクレイピングダッシュボードです。

使い方はとても簡単です。最初に、リポジトリを自分の作業ディレクトリにクローンします。
```bash
git clone https://github.com/CodeDiggerM/niconico_scrping_tool.git

```

次に、必要な依存関係をインストールします。

```bash
pip install -r requirements.txt
```

最後に、streamlitでメインページを実行します。

```bash
streamlit run niconico_scraping.py
```

メインページのUIは以下のようになっています。
 ![MainUI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192752/cf68328a-3769-04a2-ceb9-769e2082b6b4.png)

このツールは、niconicoからアニメをスクレイピングするのに最適です。ストリーミング、検索、クリップなどのオプションを提供しており、アニメファンにとって非常に便利です。是非お試しください！

このniconicoアニメスクレイピングツールが役に立つと思ったら、ぜひリポジトリにスターをつけてください！あなたのサポートが私たちのモチベーションにつながります。スターをつけるには、リポジトリページに移動し、右上の「Star」ボタンをクリックしてください。どうもありがとうございます！
sidekiq-scheduler cronの実行時間指定方法

- Sidekiq schedulerで「Cron」を使って実行時間を指定します。
## config/sidekiq_scheduler.yml
```
:schedule:
  hello_world:
    cron: '*/30 * * * *' # every 30 minutes
    class: 'HelloWorld'
    queue: single
    description: 'Test'
```

- 基準はパラメタ５つを使って実行時間を指定します。
`
  Minutes Hours Days Months   DayOfWeek
`
例：
![スクリーンショット 2023-03-03 15.23.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989503/3bb34ef5-daa8-b8d1-b211-c23abb7965d2.png)

```
'1 * * * *'         # execute at 1 minute of every hour, ex: 12:01, 13:01, 14:01, ...
'0 0 * * *'         # Every day at midnight (毎日 00:00に実行)
'5 0 * * *'         # Every day after midnight (毎日 0時05分に実行)
'0 5 * * *'         # Every day at 5am (毎日 5時AMに実行)
'0 17 * * *'        # Every day at 5pm (毎日 5時PMに実行)
'0 /3 * * *'        # every 3 hours (３時間毎に実行)
'0 22 * * 1-5'      # at 22:00 on weekdays(週日朝22時に実行)
'0 17 * * 2'        # every tuesday at 5 pm (毎週火曜日午後５時に実行)
'0 17 * * 1,2'      # every tuesday and monday at 5 pm (毎週火曜日と月曜日午後５時に実行)
'15 14 1 * *'       # at 14:15 on the 1st of every month
'0 5 1-7 * 1'       # 05:00 on the first Monday of the month
```

- 秒毎に実行したいときは、「パラメタ６つ」を使います。
`
  Seconds Minutes Hours Days Months DayOfWeek
`
![スクリーンショット 2023-03-03 15.29.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989503/dcbadbe4-5b83-2644-ead9-d62e3eb1ccb9.png)
スタブ、ドライバ

# 結合テストにおいてのスタブ、ドライバ
モジュール群を順次結合させながら行うため、全体が正しく動作するかどうかを検証するためには、未完成の上位または下位に該当するモジュールが必要となる。
ここでテスト用に作成するダミーの上位モジュールを```ドライバ```
下位モジュールを```スタブ```と呼ぶ。

# スタブ
```トップダウンテストで必要なテスト用のモジュール```

```上位にあるテスト対象モジュールからの呼び出し```に対して、```下位モジュールが返すべき適切な値を返却```するなど、未完成の下位モジュールの代わりとして、その機能をシュミレートします。

## トップダウンテスト
```上位から下位モジュールへ順に結合しながら行う```。
未完成の下位モジュールがある場合は、その動作をシミュレートする```スタブ```が必要。

# ドライバ
```ボトムアップテスト```で必要となるテスト用のモジュール

適切な引数を渡して```下位にあるテスト対象モジュールを呼び出す```

## ボトムアップテスト
ユニットテストが終わった下位モジュールから上位モジュールへ順に結合しながらテストを行う。

### 気づき
テスト対象モジュールから下か上で呼び出されるか呼び出すかが決まり、テスト用のモジュールの呼び方が変わるのか。
わかりにくいがこれから分かっていこう。

# 出典
https://gihyo.jp/book/2022/978-4-297-12375-8

https://gihyo.jp/book/2022/978-4-297-13178-4
ターミナル起動時にconda activateを実行

#　はじめに
前回の記事で、
```
$ conda activate
```
をすると、Numpyを使えるようになることを学んだ。
Pythonの勉強中は、Numbyを頻繁に使うことになるので、毎回このコマンドを打つのは面倒だ。
このコマンドを自動で実行する方法はないだろうか？

# .bash_profileに設定
ホームディレクトリの.bash_profileにコマンドを追加するだけだ。
```
# ~/.bash_profile
# 今まで記述してきた環境変数やエイリアス

conda activate
```
.bash_profileは環境変数の設定、コマンド入力時のエイリアスの設定以外にも、自動でコマンドを実行する機能があるようだ。

# conda環境を終了したい場合
以下のコマンドを打つと、conda環境を終了できる。
```
$ conda deactivate
```

# まとめ
起動時に実行したいコマンドも.bash_profileに記述できることを学んだ。
echoができるのであれば、他のコマンドもできるのではと考えたのがきっかけだった。
bashに詳しい人にとっては当たり前かもしれないが、
私と同じように.bash_profileでコマンドを実行できるということを知らない人もいるかもしれないと思い、この記事を書いた。
.bash_profileでコマンドを実行したことがない人は、まずはechoからやってみよう。
現在適用中のテーマの判断

現在どのテーマが適用中なのかを判断するには　[$User.UIThemeDisplayed](https://developer.salesforce.com/docs/atlas.ja-jp.pages.meta/pages/pages_variables_global_useruitheme.htm)　を利用するとよい。

```Java
IF ($User.UIThemeDisplayed = "Theme4t"
    ,項目名
    ,HYPERLINK(Id , 項目名, "_self")
)
```

使用できる値は次のとおりです。
- Theme1 — 古い Salesforce テーマ
- Theme2 — Salesforce Classic 2005 ユーザインターフェースのテーマ
- Theme3 — Salesforce Classic 2010 ユーザインターフェースのテーマ
- Theme4d — 最新の「Lightning Experience」 Salesforce のテーマ
- Theme4t — Salesforce モバイルアプリケーションのテーマ
- Theme4u — Lightning コンソールのテーマ
- PortalDefault — カスタマーポータルにのみ適用され、エクスペリエンスビルダーサイトには適用されない Salesforce カスタマーポータルのテーマ
- Webstore — AppExchange のテーマ
相対パスでショートカットを作る

# 問題
USBメモリの中には、ツールやアプリなどを早く起動するためにショートカットを作成しました。
しかし、異なるPCではドライバの名前が異なるため、ショートカットが正常に動作しないことがよくあります。
相対パスを使用することで、この問題を解決できます。

# やり方
「Snipaste.exe」を例として、説明します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/0f02e450-e5fa-810f-594e-066cecbf17a6.png)

1. ショートカットを作成し、置きたい場所に移動する
   「Tools」フォルダの下に置いた
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/454fbe04-1b78-86de-32ef-a3a99166f5f8.png)
2. 下図の赤枠を修正する
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/71abcce8-664a-9592-d94f-fec956a0cf3c.png)
    ①　相対パスに変更する
    相対パスの前`%windir%\explorer.exe `を追加する
    `%windir%\explorer.exe "\Snipaste-2.8.3-Beta-x64\Snipaste.exe"`
    ②　空白にする
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/c2a29571-3a60-af54-8b4a-e120ee72089b.png)
3. 適用ボタンとOKボタンを押す
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2074893/3e2bd669-312b-4180-2fc7-7d72c2f44bb3.png)

できました。
「Tools」フォルダのパスを変更しても、ショートカットを起動できます。
InfluxDBシリーズのカーディナリティは、測定のフィールドキーの数に依存していますか?

influxdb.cardinality() メソッドによって返される値と、ドキュメントの定義に基づいて計算する値との間に不一致が見られるため、バケットのシリーズカーディナリティを計算するための正しいアプローチを理解しようとしています。

ドキュメント (このビデオでも TSM エンジンについて説明しています) によると、シリーズ カーディナリティは、InfluxDB バケット内の一意の測定、タグ セット、およびフィールド キーの組み合わせの数です。

1 つのタグと 2 つのフィールド キーのみで測定し、データを次のように仮定します (行形式)

m1,loc=abc speed=10,temp=20 m1,loc=xyz speed=10,temp=20

定義に基づいて、このバケットのシリーズのカーディナリティは 4 (1 つの測定値 * 2 つの一意のタグ値 * 2 つのフィールド キー) であると予想していました。

ただし、influxdb.cardinality() 関数を使用すると、シリーズのカーディナリティが 2 (1 測定 * 2 固有タグ) になります。これは、シリーズが複数のフィールドであるという印象を与えます。

import "influxdata/influxdb"
influxdb.cardinality(
  bucket: "test-cardinality",
  start: -4h
)

実は、答えはいいえです。つまり、InfluxDB シリーズのカーディナリティは、測定のフィールド キーの数に依存しません。

influx_inspect の reporttsi は、「データベース内の正確な系列カーディナリティの合計」を報告します。データベース内の正確な系列カーディナリティの合計を計算します。

コード層を層ごとにドリルダウンできます。ここの reporttsi コードから、システムがすべてのシャードを反復処理してから、すべての測定値を反復処理して、それらのシリーズ ID を計算していることがわかります。シリーズ ID は、こちらのコードで定義されています。測定とタグのみに関連していることがわかります。

// CreateSeriesListIfNotExists creates a list of series in bulk if they don't exist.
// The returned ids slice returns IDs for every name+tags, creating new 
    series IDs as needed.
func (f *SeriesFile) CreateSeriesListIfNotExists(names [][]byte, tagsSlice 
    []models.Tags) ([]uint64, error) {
PRUSA mk3i+

プルーサの1層目定着　　
* 気温が低い時、ヒートベッドのヒーターから離れた部分は温度が低くなり定着が甘くなるので、中央を使う。接触面積が小さい場合、周辺部まで使用する場合「プリム」で接触面積を大きくする。

* ヒートベットの温度センサーに使用されているワイヤーは硬く変形に弱い。マニュアル通りの組立で、ワイヤーが鋭角に変形するようであれば、断線の可能性が高い。ケースに入れずに途中からヒーターケーブルと合流。　
印刷も前後の移動を少なくする。

* スムースシートはPLA用、PETGには使用しない。定着が悪くなったら、洗浄。洗浄は水、アルコール、イソプロパノール。手油も禁物。手油は中性洗剤
* PETGには、テクスチャーシートを使用。
No module named 'numpy'

# はじめに
pythonコマンドを使用し、import numpy as npコマンドを実行したところ、このエラーが出た。
jupyter notebookではなく、ターミナルから使用するにはどうすればいいだろうか？

# バージョン
macOS: Ventura 13.1
Python: 3.12.0a5

# ダメだった方法方法
以下の方法はダメだった。
```
$ pip install numpy
```
```
$ pip3 install numpy
```
両方とも以下のところでPCが重くなり、最終的にはエラーになってしまった。
```
Building wheel for numpy (pyproject.toml) ... -
```
エラー文。
```
note: This error originates from a subprocess, and is likely not a problem with pip.
ERROR: Failed building wheel for numpy
Failed to build numpy
ERROR: Could not build wheels for numpy, which is required to install pyproject.toml-based projects
```

日本語にすると、
「note: このエラーはサブプロセスから発生していて、pipの問題ではない可能性がある。
ERROR: numpy用ホイールのビルドに失敗した。
numpyのビルドに失敗した。
ERROR: pyproject.toml ベースのプロジェクトをインストールするために必要な numpy 用のホイールを構築できませんでした。」
ということである。

検索しても、めぼしい解決法が見つけられなかった。
jupyter notebookではnumpyのインポートが成功するので、Anaconda関係から攻めることにした。

# うまくいった方法
結論から述べると、conda activateをしてから、pythonコマンドを実行すると、numpyをインポートできるようになった。
```
$ conda activate
(base) 
$ python
>>> import numpy as np
```

https://www.python.jp/install/anaconda/conda.html

によると、conda activateはconda環境を有効にするコマンドらしい。

# conda activateをターミナルの起動時に実行する方法

https://qiita.com/momiji-snow/items/c7303631462c6a0ce17a

に記事を書いたので、そちらを参照してほしい。
結論を書いてしまうと、.bash_profileに
```
conda activate
```
を追記するだけだ。

# まとめ
conda環境を有効にする記事はあった。このエラーにぶつかった人が質問している質問サイトもあった。
しかし、conda activateで解決している人は見つけられなかったので、記事にした次第である。

インタラクティブシェルを使う時はこの方法でいいかもしれないが、
通常の開発ではVS Codeを使いそう。

# 追記
conda環境に切り替えると、pythonコマンドを打った時のバージョンが3.9.16になった。（pyenvで*が付くバージョンは3.12.0a5だ。）

https://www.python.jp/install/anaconda/conda.html

に
「Conda環境は独立したPythonの実行環境で、他の環境に影響を与えずにPythonのバージョンを用途によって切り替えたり、パッケージをインストールしたりできます。」
と書かれているので、自動でバージョンを下げてくれているのだと思う。
今の所バージョンが下がることで不便を感じていないが、今後バージョン管理で苦しめられることがあるかもしれない。
Imagemagick（display）でpdfが使えない

## 問題
displayコマンドでpdfを確認しようとすると次のようなメッセージが出て確認できない場合があります．
```
display-im6.q16: attempt to perform an operation not allowed by the security policy `PDF' @ error/constitute.c/IsCoderAuthorized/421.
```
この問題はdisplayコマンドに限らず，Imagemagick関連のコマンドでpdfを扱うときに起こるようです．

## 解決法

この問題はGhostscript（postscriptを扱うソフト）の脆弱性対策のためにImagemagickがpostscriptやpdfファイルを無効化しているために起こるとのことです．次の手順で，postscriptファイル(ps, eps)とpdfファイルの無効化設定を無効化してやればpostscriptやpdfファイルがImagemagick関連のコマンドで使えるようになります．

- /etc/ImageMagick-6/policy.xmlを次のコマンドで開く．
```
sudo nano /etc/ImageMagick-6/policy.xml
```
- この部分
```
  <policy domain="coder" rights="none" pattern="PS" />
  <policy domain="coder" rights="none" pattern="PS2" />
  <policy domain="coder" rights="none" pattern="PS3" />
  <policy domain="coder" rights="none" pattern="EPS" />
  <policy domain="coder" rights="none" pattern="PDF" />
  <policy domain="coder" rights="none" pattern="XPS" />
``` 
を次のように変更します．
```
  <!-- <policy domain="coder" rights="none" pattern="PS" />
  <policy domain="coder" rights="none" pattern="PS2" />
  <policy domain="coder" rights="none" pattern="PS3" />
  <policy domain="coder" rights="none" pattern="EPS" />
  <policy domain="coder" rights="none" pattern="PDF" />
  <policy domain="coder" rights="none" pattern="XPS" /> -->
```

この対策方法は単純にpostscriptやpdfファイルを無効化している部分をコメントアウトしただけです．

## 補足

Ghostscriptの脆弱性が心配な方は，
```
gs --version
```
でGhostscriptでバージョンを確認してください．9.24以上であれば今回の問題と関係する脆弱性は修正されているとのことです．
getter setter deleter

```python
class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if not isinstance(value, int):
            raise TypeError("age must be an integer")
        if value < 0 or value > 120:
            raise ValueError("age must be between 0 and 120")
        self._age = value

    @age.deleter
    def age(self):
        del self._age
```

```python
person = Person("Alice", 25)

#nameのgetter
print(person.name)  # Alice 

#nameのsetter
person.name = "Bob"
print(person.name)  # Bob

#ageのgetter
print(person.age)   # 25

#ageのsetter if条件があります。
person.age = 30
print(person.age)   # 30

#ageのdeleter
del person.age
print(person.age)   # AttributeError: 'Person' object has no attribute '_age'
```

1. getterメソッド：プロパティの値を取得するためのメソッドです。通常、プロパティの値を取得する際には、プロパティ自体を呼び出すだけで取得できますが、場合によっては明示的にgetterメソッドを定義することがあります。

2. setterメソッド：プロパティの値を設定するためのメソッドです。@property.setterデコレータを使用する場合は、このsetterメソッドが自動的に作成されます。しかし、場合によっては明示的にsetterメソッドを定義する必要があります。

3. deleterメソッド：プロパティを削除するためのメソッドです。@property.deleterデコレータを使用することで、このdeleterメソッドが自動的に作成されます。

**デコレーターに関して**
例としてperson.nemeでプロパティにアクセスする場合@propertyデコレータを使ってnameプロパティを取得する際にはgetterメソッドの名前はプロパティの名前と同じにする必要がある。
dockerで立ち上げたlaravelのコードが即時反映されずハマったのでメモ

# はじめに
途中参加したlaravelプロジェクトにDockerfileはあったものの、ローカル開発環境の構築手順やdocker-composeファイルがなく手探りで構築した際にハマったのでメモ

# 用意されていたもの
・GitHubとソースコード
・Dockerfile

# 問題発生

docker-compose.yamlだけ書けばいけるっしょ！そう思っていました。
無事コンテナを立ち上げたまでは良かったがコードを変更しても反映されない、、
なぜだ。。
docker-compose.yamlでアプリのvolumeとか書き忘れたのか確認するも問題なし
なんなら`$ docker-compose down`してもう一度立ち上げたら反映されてるー
どっかキャッシュしてるんかな
あったー。ここだ、やられた。共有されたDockerfileローカル用に用意されたものじゃなかった。

# 結論
~~~php.ini
[opcache]
＃　ここが原因　ここを0にしてcache無効にする
opcache.enable=1
~~~

`docker-compose build --no-cache {service_name}`
でphpのコンテナだけ再ビルドしてあとは普通に
`docker-compose up`
で無事即反映されるようになりました。
VSCodeでSalesforceの本番組織からApexコードを削除する（備忘録）

# 対象
VSCodeですでにSalesforceの開発環境を構築してあること。

# 削除用のプロジェクトを作成
削除に必要な設定ファイルを置くためのフォルダをローカル環境に作成。

package.xmlとdestructiveChanges.xmlの2ファイルを置く。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229613/378998ca-4ecc-41aa-d6bf-98b5a48afb0d.png)

package.xmlは公式サイトからダウンロードしてきたものをそのまま使う。
```package.xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>codepkg</fullName>
    <version>55.0</version>
</Package>

```

destructiveChanges.xmlは削除したいクラス名を入力する
```destructiveChanges.xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>codepkg</fullName>
    <types>
        <members>room_R</members>
        <members>room_RTest</members>
        <name>ApexClass</name>
    </types>
    <version>55.0</version>
</Package>
```
# SFDXコマンドを使う
VSCodeのターミナルウインドウでコマンドを入力する。
```
sfdx force:mdapi:deploy --deploydir . --targetusername <ユーザー名> --testlevel RunLocalTests -w5
```
エラーになると以下のような表示がでる。
例：destructiveChanges.xmlに記載したApexクラス名が間違えている場合
![スクリーンショット 2023-03-05 14.03.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229613/a195f023-56e1-f4c2-dade-1e2b4ebea457.png)

デプロイが進むと以下のようにテストが実行される。
![スクリーンショット 2023-03-06 10.10.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229613/502aeedb-9145-e2df-be06-784d99f654f3.png)
テストが無事に終了するとTotal Test Timeが表示される。
![スクリーンショット 2023-03-06 10.10.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229613/f96bd6eb-2645-6b6d-b8cf-7c7e75e9bccc.png)
これで削除完了。
Pulsar RESTを使ってみた 

## はじめに
こんにちは。

本稿では、[Apache Pulsar](https://github.com/apache/pulsar)(以下、Pulsar)の[Pulsar REST](https://pulsar.apache.org/docs/2.11.x/client-libraries-rest/)を使って、簡単なメッセージの送信をしていきます。
Pulsar RESTでは、クライアントライブラリを使わずに、HTTPを使ってメッセージを送信することができます。
現在Pulsar RESTにはメッセージの受信は実装されていません。

今回は、MacOS上にPulsarサーバ(standaloneモード/v2.11.0)を構築し、そのサーバに向けてメッセージの送信を行います。
Pulsar standaloneモードを起動するにはJavaが必要になります。

## サーバ構築

Pulsarのバイナリパッケージをダウンロードし、standaloneモードで起動します。

```shell
# Pulsarのバイナリパッケージのダウンロードと展開
$ wget https://archive.apache.org/dist/pulsar/pulsar-2.11.0/apache-pulsar-2.11.0-bin.tar.gz
$ tar xzvf apache-pulsar-2.11.0-bin.tar.gz
$ cd apache-pulsar-2.11.0

# Pulsar standaloneモードの起動
$ ./bin/pulsar standalone
.
.
.
{
  "c-standalone-fw-localhost-8080" : {
    "originalNumAssignments" : 0,
    "finalNumAssignments" : 0,
    "instancesAdded" : 0,
    "instancesRemoved" : 0,
    "instancesUpdated" : 0,
    "alive" : true
  }
}

# 上記のようなログが出れば構築完了

```


## メッセージの送信

サーバが起動できたのでメッセージを送信していきます。
Producer(メッセージを送信する側)とConsumer(メッセージを受信する側)用にターミナルを2つ起動します。

まず、Consumerを起動してメッセージが流れてきたら受信するようにします。
```shell
# Consumer側のターミナル
# Consumerの起動
$ ./bin/pulsar-client consume -n 0 -s sub1 persistent://public/default/t1
.
.
.
2023-03-04T14:16:11,311+0900 [pulsar-client-io-1-1] INFO  org.apache.pulsar.client.impl.ConsumerImpl - [persistent://public/default/t1][sub1] Subscribed to topic on localhost/127.0.0.1:6650 -- consumer: 0

# 上記のようなログが出ればOK
```

次に、Producer側のターミナルで、curlを使ってメッセージを送信します。

```shell
# Producer側のターミナル
# メッセージの準備
$ cat messages.json
{
  "messages": [
    {
      "payload": "Hello World"
    },
    {
      "payload": "Hello World"
    },
    {
      "payload": "Hello World"
    }
  ]
}

# curlを使ってメッセージを送信
$ curl --location --request POST \
--header 'Content-Type: application/json' \
--data-raw "`cat messages.json`" \
'localhost:8080/topics/persistent/public/default/t1'

{"messagePublishResults":[{"messageId":"7:1:-1","errorCode":0,"schemaVersion":0},{"messageId":"7:2:-1","errorCode":0,"schemaVersion":0},{"messageId":"7:3:-1","errorCode":0,"schemaVersion":0}],"schemaVersion":0}

# 上記のようなログが出ればOK
```

すると、Consumer側のターミナルでメッセージが流れてきたことが確認できます。

```shell
# Consumer側のターミナル
----- got message -----
key:[null], properties:[], content:Hello World
----- got message -----
key:[null], properties:[], content:Hello World
----- got message -----
key:[null], properties:[], content:Hello World
```

## おわりに

本稿では、Pulsar RESTを使ったメッセージの送信を行いました。

今回、シンプルなメッセージを作成して試しましたが、他にも様々なオプションをメッセージに付与することができます。
公式ドキュメントが参考になるかと思います。

## 参考URL
- [Apache Pulsar](https://github.com/apache/pulsar)
- [Pulsar REST](https://pulsar.apache.org/docs/2.11.x/client-libraries-rest/)