OmniAICreator/Qiita-1.07M huggingface dataset:
unplugin-fontsでViteでGoogleフォントを使えるようにする

大したことないメモですが、まだまだViteに関する情報は少なかったので一応書き留めておきます。

## 使用するプラグイン
https://github.com/cssninjaStudio/unplugin-fonts

## 導入方法
インストールは公式様の手順通りです。

```sh: install
npm i --save-dev unplugin-fonts
```

使いたいフォント名を以下のように指定します。
```js:vite.config.js
import Unfonts from 'unplugin-fonts/vite'

export default defineConfig({
  plugins: [
    vue(),
    Unfonts({
      google: {
        families: [
          'Noto Sans JP'
        ],
      }
    }),
  ],
})
```

するとCSSで使えます。
```css: sample.css
font-family: 'Noto Sans JP', sans-serif;
```

## つぶやき
手順をよく見ずになんとなくdependenciesに入れてたんですけど、devDependenciesで良いんですね。
netlifyでgit fetch --prune を実行したい時の方法

## やり方

Deploys画面にあるtrigger deployから、Clear cache and deploy siteをクリックしてデプロイを実行すると、キャッシュが全て削除されるため、結果として`git fetch --prune`を実行したのと同じ状態にすることができる

![スクリーンショット 2023-09-08 16.22.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328421/35ec42bd-42f4-bfc9-9cb1-ddf4afbf2357.png)
IP（ネットワーク層）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/1363758c-bf9f-65ef-2b55-e1482ef7d754.png)
１：IPバケット
　IPでは、データをパケット（正確にはデータグラムと言いますという形にしてあえて先まで配送しますパケットには、ヘッダがついており、宛先/送信元アドレスなどの制御常歩いうが書かれています。身近な例では、ヘッダは、荷物を送る時に外箱に貼り付ける送付伝票の役割です。なお、宛先/送信元アドレスはIPアドレスで指定します。）

２：IPアドレスの体系
　IPアドレスは３２ビットのアドレスです。書き表す時には、８ビット単位に区切って４つの１０進数にし、各１０進数を「。」で区切って書きます。

　IPアドレスは、ネットワーク部とホスト部に分かれます。ネットワーク部で、どのネットワークに属しているのかを表します。ホスト部は、ネットワーク内のどのホストなのかを表します。したがって、同一ネットワーク内のホストのIPアドレスは、ネットワーク部がすべて同じ値です。当初はクラスA〜Cに分類されていて、
①クラスA：先頭８ビットがネットワーク部、残り２４ビットはホスト部
②クラスB：先頭１６ビットがネットワーク部、残り１６ビットはホスト部
③クラスC:先頭２４ビットがネットワーク部、残り８ビットはホスト部
と決まっていました。IPアドレスがどのクラスに属すのかは、IPアドレスを２進数表記した時の先頭１〜３ビットの部分で判断できます。

　IPアドレスには、グローバルIPアドレスとプライベートIPアドレスがあります。グローバルIPアドレスは、インターネット上で利用できる正式なIPアドレスです。各国のNIC（Network Information Center）で、ばんん号が重複しないように管理しています。プライベートIPアドレスは、LAN内で自由にリヨづえきるIPアドレスです。インターネット上では利用できません。プライベートIPアドレスは、次の範囲を使います。

①クラスA：10.0.0.0〜10.255.255.255
②クラスB：172.16.0.0〜172.31.255.255
③クラスC：192.168.0.0〜192．168.２５５.２５５

３：サブネットマスク値
　サブネットマスク値は、IPアドレスのどの部部がネットワーク部なのかを表すための値です。ネットワーク部に該当する部分を１,をホスト部に該当する部分を0として値を作ります。

　サブネットマスク値の代わりに、「/」で区切って、ネットワーク部のビット数を書く方法もあります。
例として、
 IPアドレス：192.168.130.76 
 サブネットマスク値：255.255.255.0

と、IPアドレスとサブネットマスク値の両方を書く代わりに、
　IPアドレス：192.168.130.76/24
と簡単に書くこともできます。/24は、先頭から２４ビット分がネットワーク部であることを表しています。

４：サブネット分割
　１枚のクッキーを４等分して、４つのクッキーにできるのと同様に、１つのネットワークアドレスを分割して複数のネットワークアドレスを作ることができます。これをサブネット分割と言いますクッキーの場合と同じで、分割して個数を増やすことはできますが、その分、１つのサイズ（１ネットワークで扱えるホスト数）は小さくなります。

　サブネット分割は、今までホスト部であった箇所の一部を増やします。サブネット分割を行った時には、IPアドレス（ネットワークアドレス）と共に必ずサブネットマスク値を書きます。

５：特殊な用途のIPアドレス
　ネットワークアドレス、ブロードキャストアドレスという特殊な用途のIPアドレスがあります。これらは、ホストに割り当てることができません。
①ネットワークアドレス：ネットワークそのものを表すアドレス。ホスト部のビットをすべて０にしたアドレス。

②ブロードキャストアドレス：ネットワーク内のすべてのホスにパケットを送る時に指定するアドレス。ホスト部のビットをすべて１にしたアドレス。

６：DHCP
　DHCP（Dynamic Host Configuration Protocol）は、IPアドレスを自動的にクライアントに配布する手順（プロトコル）です。あらかじめサーバに登録されているIPアドレス農地の１つをクライアントに貸し出します。クライアントは、IPアドレスを使い終えると、サーバに返却します。パソコンのIPアドレスを自動的に取得するおち雨設定は、DHCPを利用してIPアドレスを取得するかどうかの設定です。また、一般家庭でインターネット接続に用いるルータ（ブロードバンドルータ）にはDHCPサーバ機能が付属していることが一般的です。

７：アドレス変換技術
　プライベートIPアドレスとグローバルIPアドレスを相互に変換することで、グローバルIPアドレスを持たない内部ネットワークのPCからもインターネットが利用できるようになります。アドレス変換技術には

①NAT：プライベートIPアドレスとグローバルIPアドレスを１体１で変換する

②NAPT（IPマスカレード）：プライベートIPアドレスとグローバルIPアドレスを１対多で変換する。１つのグローバルIPアドレスを複数のPCで共用できる。
PHP 5.6 の使い方

PHP 5.6 を使っているサイトを動かす方法です。
Ubuntu 23.04 に、LXD で　Ubuntu 22.04 をインストールしました。

22.04 を使う理由はこちらです。
[ppa:ondrej/php on Ubuntu 23.04 (Lunar)](https://dev.to/pallade/ppaondrejphp-on-ubuntu-2304-lunar-ia1)

>LTS versions でなければ、Ondrej's PPA　は使えないということです。

次のページを参考にしました。
[Ubuntuのapache2で異なるバージョンのPHPを使用する](https://linuxer2006.blog.jp/archives/65974776.html)

## Ubuntu 22.04 のインストール

```bash
lxc launch ubuntu:22.04 sandbox
```

環境設定は、こちら
[LXD で Ubuntu を使う](https://qiita.com/ekzemplaro/items/39ffcc47e69d50ada8dc)

## PHP 5.6 のインストール

```bash
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
```

```bash
sudo apt update
sudo apt upgrade
```

```bash
sudo apt install php5.6
sudo apt install php5.6-cli php5.6-xml php5.6-mysql
sudo apt install php5.6-mbstring
```

バージョンの確認

```text
$ php --version
PHP 5.6.40-68+ubuntu22.04.1+deb.sury.org+1 (cli) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
```

## Apache2　で使われているバージョンの確認

```php:test_a002.php
<?php phpinfo();
?>
```

ブラウザーでアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/d780a1f2-7135-c63f-5042-90947b0fdb37.png)
Invalid Bundle. The bundle at '〇〇〇〇〇〇' contains disallowed file 'Frameworks'.のエラー解消方法

GitHub ActionsからApp Store Connectにアップロードする時に以下のようなエラーが出た際の解消方法をご紹介します。


## エラー内容
```
Invalid Bundle. The bundle at '〇〇〇〇〇〇' contains disallowed file 'Frameworks'.
```

## 解消方法
エラー内容の〇〇部分で指定されたTargetのBuild Settingを開いて、
**Always Embed Swift Standard Libraries：Yes⇒NO**に変更する。
![スクリーンショット 2023-09-07 18.45.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370083/d650638b-1bb8-8026-8a67-7d91ae26012c.png)
This step has been truncated due to its large size. Download the full logs〜でGithub Actionsが止まった時のエラー特定方法

GitHub ActionsでApp Distributionに配布する際、以下のような内容で止まってしまいました。
![スクリーンショット 2023-09-08 14.53.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370083/f2efbdf9-aee0-406c-d7cf-90f4647dd424.png)
**検索してもエラー（❌)が出てこない…**

■エラーメッセージ内容
This step has been truncated due to its large size. Download the full logs from the ⚙ menu once the workflow run has completed.
>翻訳内容：
サイズが大きいため、このステップは省略されました。
ワークフローの実行が完了したら、⚙ メニューから完全なログをダウンロードします。

ログが長すぎて切ったよ。あとは自分で見て！という事らしい…


## ■エラー特定方法

エラー内容通り、ログを確認してみましょう。
![スクリーンショット 2023-09-08 15.08.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370083/44b946cd-9d50-7830-1274-1254990724e6.png)


**ログの中にエラー（❌)が隠されていました！！**
![スクリーンショット 2023-09-08 15.29.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2370083/d0942a89-9994-b536-2430-80dad158a245.png)
変なところで折り返されて文章が読みにくいときは、spanとdisplay: inline-blockの出番！

🌻変なところで折り返されて文章が読みにくい！！
　👉spanとdisplay: inline-blockの出番！

①折り返したく無い分のかたまりをspanタグで囲む
②↑のspanタグに、display: inline-blockを指定する

こんなに読みやすくなります✨
（HTMLが少し汚くなるのが難点）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525847/42004067-4169-67b5-ee01-ae907404274d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2525847/4f35d373-0ba5-a70d-d3a8-2e329e4d46bf.png)


~~~html:index.html
<div class="about__right">
    <span>お客様にとって、</span><span>不動産に関する情報が入手しにくい、</span><span>取引が複雑でわかりにくいといった</span><span>課題を解決し、</span>
</div>
~~~

~~~css:style.css
.about__right span {
    display: inline-block;
}
~~~
[Linux 初期設定] インストール済パッケージの一括アップデート

Linux 初期設定シリーズ

変更内容：インストール済パッケージの一括アップデート
確認OS：Red Hat Enterprise Linux release 9.2 (Plow)
対象ファイル：－
反映：－

１．インストール済パッケージの一括アップデート

```test.sh
sudo dnf -y update
```

２．ベース、開発ツールパッケージ群インストール

```test.sh
sudo dnf -y groupinstall base
sudo dnf -y groupinstall development
sudo dnf -y groupinstall network-tools
```
[Linux 初期設定] sudo対処タイムアウト時間を変更

Linux 初期設定シリーズ

変更内容：sudo対処タイムアウト時間をデフォルトの5分から60分に変更
確認OS：Red Hat Enterprise Linux release 9.2 (Plow)
対象ファイル：/etc/sudoers
反映：即時

１．設定ファイルのバックアップ

```test.sh
sudo cp -an /etc/sudoers{,.$(date +%Y%m%d)}
sudo ls -alF /etc/sudoers*
```

２．タイムアウト時間の変更

```test.sh
echo "Defaults    timestamp_timeout = 60" | sudo EDITOR='tee -a' visudo > /dev/null
```

３．設定の確認

```test.sh
sudo grep timestamp_timeout /etc/sudoers
sudo diff /etc/sudoers{,.$(date +%Y%m%d)}
```

その他．設定の解除
※echo コマンドを複数回実行してしまった場合にも使える

```test.sh
sudo sed -e '/timestamp_timeout/d' /etc/sudoers | sudo EDITOR=tee visudo > /dev/null
```
Pythonでメール作成・自動送信(添付ファイル）

# 添付ファイルなして、送信対応は以下を参照してください。
https://qiita.com/taidong5588/items/731c7f226e80c5b908d5

# Pythonでメール作成・自動送信(添付ファイル）
```py
# ライブラリ設定
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from pathlib import Path
import os

# メール情報の設定
from_email ='test1@gmail.com' 
to_email = 'test2@gmail.com' + ',' + 'xxx@gmail.com'
cc_mail = ''
mail_title = 'メール件名'
message = '''
ここにメール本文を記入
'''
# MIMEマルチパートでメールを作成
msg = MIMEMultipart()
msg['Subject'] = mail_title
msg['To'] = to_email
msg['From'] = from_email
msg['cc'] = cc_mail
msg.attach(MIMEText(message))

# ログイン名の取得/getpassで取得OK
# import getpass
# username = getpass.getuser()

# ログイン中のユーザー名
username = os.getlogin()
filepath= f"C:\\Users\\{username}\\Desktop\\HO\\test.csv"
filename = os.path.basename(filepath)

# ファイル読込
with open(filepath, 'rb') as f:
    attach = MIMEApplication(f.read())
    
# ファイル添付
attach.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(attach)

# サーバを指定してメールを送信する
smtp_host = 'smtp.gmail.com'
smtp_port = 587
smtp_password = 'password'

server = smtplib.SMTP(smtp_host, smtp_port)
#サーバー・ポート接続
server.ehlo()
# TLS暗号化
server.starttls()
# SMTPサーバーログイン
server.login(from_email, smtp_password)

server.send_message(msg)
#SMTPサーバー遮断
server.quit()

print("メールを送信しました。")
```

# 解説
```py
from email.mime.multipart import MIMEMultipart
```
```email.mime.multipart ```モジュールから``` MIMEMultpart ```クラスをインポートします。
MIMEMultipartクラスを使用することで、1つのメールに何種類ものデータを「添付」する事ができます。
```py
from email.mime.application import MIMEApplication
```
ファイルを添付するために ```from email.mime.application``` モジュールから``` MIMEApplication ```クラスをインポートします。
```py
from pathlib import Path
```
添付ファイルのファイル名操作のために ```Pathlib``` の ```Path``` クラスをインポートします。
👆　今回は```os```で実装しましたが、 ```Pathlib```よく利用しているようです。

```py
msg = MIMEMultipart()
```
MIMEMultipartオブジェクトを生成して msg に格納します。
```py
msg ～略～
msg.attach(MIMEText(message))
```
テキストメッセージはMIMETextクラスでオブジェクト化して、MIMEMultipartオブジェクトへ「添付」します。

```py
# ファイル読込
with open(filepath, 'rb') as f:
    attach = MIMEApplication(f.read())
```
添付ファイル```filepath```をバイナリファイル ```f ```として開き、```MIMEApplication```クラスの引数に ```f.read()``` を指定して、添付ファイルオブジェクト ```attach ```に格納します。
```py
attach.add_header('Content-Disposition', 'attachment', filename=filename)
```
添付ファイルにヘッダ情報を付与。引数 'Content-Disposition', 'attachment' は、添付ファイルをダウンロードしてローカルに保存することを指定。
第三引数は添付ファイルの表示名を指定。
```py
msg.attach(attach)
```
MIMEMultipartクラスの```attach()```メソッドで、添付ファイルオブジェクトを指定して、オブジェクトに添付します。
AS400のシステムログを確認

システムログの表示
```
DSPMSG *SYSOPR
```

もっと詳細なシステムログをスプールに落とすコマンド
例：2023/9/5 14:30～15:00 のシステム詳細ログをスプールに落とす
```
DSPLOG PERIOD(('14:30:00' '2023/09/05') ('15:00:00' '2023/09/05')) OUTPUT (*PRTSECLVL)
```

出力したスプールをPCにダウンロードしたい場合は、Navigator for i（iナビ）でダウンロード可能。
【Swift】シミュレーターで通知許可したけどローカルプッシュ通知がこない

コードは間違っていない+通知許可はした、のにローカルプッシュ通知が来ませんでした。
ですが以下の方法で解決しました。

## 結論
1 別のシミュレーターを立ち上げる
2 パソコン再起動

私は、１の方法で試したところ解決しました！
ちなみに、通知が来なかったシミュレーターは、iPhone14 Pro、これを立ち上げた状態で別のシミュレーターも同様に起動->ボタンタップして通知処理を走らせたらなおりました！

## やったこと
AppDelegateファイルに以下のコードを入力
```AppDelegate.swift
class AppDelegate: NSObject, UIApplicationDelegate {
    // MARK: - Methods
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        // 通知許可の取得
        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options: [.alert, .sound, .badge]) {
            guard $1 != nil else { return }
            $0 ? print("通知許可") : print("通知キャンセル")
        }
        return true
    }
}
```
これで端末起動時に通知許可orキャンセルする選択項目が出てくるので許可をしました。

ボタンを押すとローカルプッシュ通知処理が走るようにしました。
```ContentView.swift
Button {
    Task {
        await sendNotificationRequest()
    }
} label: {
    Text("通知する")
}

// 以下はsendNotificationRequestメソッドの中身
func sendNotificationRequest() async {
    let content = UNMutableNotificationContent()
        content.title = "title"
        content.body = "message"

    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
    let request = UNNotificationRequest(identifier: "通知No.1", content: content, trigger: trigger)
    do {
        try await UNUserNotificationCenter.current().add(request)
    } catch {
        print(error.localizedDescription)
    }
}
```

## 参考記事
https://tech.amefure.com/swift-notification#google_vignette
FinalIK健忘録

**モデルのインポート**
mmdモデル(pmx)はunityでは使用できないため、fbxに変換するツールであるMMD4mecanimを使用する。

MMD4mecanim　アニメーション、アバター作成を自動で実施してくれる。

アニメーションをvrm(mmd用)からunity用に変換したい場合、fbxアバター作成と同時にvrmデータを読み込ませる必要がある。

animator はmotionを管理するオブジェクトである。　
motion を直接アバターに適応することは出来ない。
AnimatorコンポーネントにAnimatorでmotionを線で結び付けたオブジェクトと入れることでmotionを対応させる。

:::note warn
警告
アバターの設定でrig を humanoidに設定しapplyする必要がある　
→　ボーンが反映されないため、アニメーションが適応されない
:::
CloudSchedulerでEDINETデータの取得

# 1.はじめに
* EDINET APIのバージョン2が8/21から使えるようになった。
* （自分の）注目はxbrlデータをcsvデータに変換したデータがとれる!、ということで、このデータを自動で蓄積できるように設定した。

# 2. 試したもの
* 毎回colaboratoryを使って起動して、、という形も考えたけれど、たぶん忘れるだろう、ということでボツ。
* 次に[Workflows](https://cloud.google.com/workflows?utm_source=google&utm_medium=cpc&utm_campaign=japac-SG-all-en-dr-SKWS-all-all-trial-DSA-dr-1605216&utm_content=text-ad-none-none-DEV_c-CRE_655856181023-ADGP_Hybrid%20%7C%20SKWS%20-%20BRO%20%7C%20DSA%20~%20All%20Webpages-KWID_39700076131767822-aud-1596662388934%3Adsa-1456167871416&userloc_9167920-network_g&utm_term=KW_&gclid=CjwKCAjw6eWnBhAKEiwADpnw9gv6vW8tNT4ic8MJy2YhCf_u5-duIzH3NVNO0iqu3Izbe2gTqkk5rBoCKtQQAvD_BwE&gclsrc=aw.ds&hl=ja)を使ってうまくやれればいいと思ったけれど、zipファイルの扱いがうまくできず断念。そもそもこれはGoogleCloudの各サービスを組み立てる際に使うものなのでだめだったかも。

```yaml
#断念したもの
main:
    params: [input]
    steps:
    - downloadzip:
        call: http.get
        args:
            url: 'https://api.edinet-fsa.go.jp/api/v2/documents/****'
            query:
                Subscription-Key: ***
                type: 5
        result: wikiResult
    #getしたzipファイルをどうすればいいか、わからなくなる。
    - returnOutput:
            return: "OK"
```



# 3. コード
* 結局、[CloudScheduler](https://cloud.google.com/scheduler?hl=ja)でCloudFunctionsを呼び出す形に。
* 毎日１回実行して、その日にあった有価証券報告書をGCSにアップロードする、という処理。
* ありがたいことに設定などすごく簡単だった。

```python
@functions_framework.http
def hello_http():
    from datetime import date
    today = date.today()
    #有償系のdocidのもののみリスト化
    doc_id_list = make_doc_id_list([today])
    tmpdf = pd.DataFrame(doc_id_list)
    df = tmpdf.T.rename(columns={0:"doc_id",1:"comname",2:"secCode",3:"desc"})

    for FNAME in df["doc_id"].tolist():
        url = "https://api.edinet-fsa.go.jp/api/v2/documents/"+ FNAME + "?Subscription-Key=***fec&type=5"
        r = requests.get(url)
        filename = FNAME + ".zip"
        urlretrieve(url, filename)

        blob_name = filename
        path_to_file = filename
        bucket_name = "*****"
        upload_to_bucket(blob_name, path_to_file, bucket_name)

    return 'OK!'

```

あとは[CloudScheduler](https://cloud.google.com/scheduler?hl=ja)で指定していけばOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385220/ffe566ea-d148-0aef-feac-89c0b8457f3b.png)

* CloudFunctionsのURLを指定。内部で日付を取得するので、引数はなしでOK.
複雑さに立ち向かうためのコードリーディング入門まとめ

# 一言まとめ

認知プロセスの観点から読み方を学ぼう。

# 注意事項

この記事はiOSDC 2023で[shizさん](https://twitter.com/stzn3)が発表された「[複雑さに立ち向かうためのコードリーディング入門](https://fortee.jp/iosdc-japan-2023/proposal/6229ba41-0675-4f62-839e-6cde07311585)」の一部を松本が自分なりの理解を含めてテキスト化したものです。

こちらの記事の公開を許諾をしていただいたshizさんに感謝します。


発表スライド

https://speakerdeck.com/shiz/fu-za-sanili-tixiang-kautamenokodorideinguru-men

shizさんが共同著者（翻訳）の本　
Good Code, Bad Code ～持続可能な開発のためのソフトウェアエンジニア的思考

https://amzn.asia/d/0l8bPgM


# 3つの認知プロセス

物事を理解する際、3つの認知プロセスが連携する。
`短期記憶`・`長期記憶`・`ワーキングメモリ`
- `短期記憶`に新しく取得した情報をキャッシュする。
- `長期記憶`から関連する情報を検索する。
- `ワーキングメモリ`\*は短期記憶のキャッシュと長期記憶の検索結果を紐付けるといった作業をする。<br>*（メモリとついているが記憶ではなく処理を担当する機能。）<br><br>
# 3つの困難さの原因
コードを理解する際の困難は3つの不足から生じる。
`キャッシュした情報の不足`・`長期記憶の検索結果の不足`・`処理能力の不足`
#### キャッシュした情報の不足
`キャッシュした情報が不足する原因`は短期記憶は4〜7項目を30秒程度しか保持できずキャッシュに限界があるため。
`キャッシュした情報の不足を解消する`には、情報を細切れの状態ではなく一つのまとまり（チャンク）として捉えることでキャッシュを容易にすると良い。
  例：
1. c, a, t, s, l, i, k, e, f, i, s, h という12字を覚えるのは困難だがcats like fishという3単語は容易。
1. ViewModelと言う概念を知っていたら、あるクラスがViewModelのとき、それのおおよその役割がわかる。
    
なお情報をチャンク化して認知するにはそのパターンが長期記憶に保存され、それに慣れている状態である必要がある。
#### 長期記憶の検索結果の不足
`長期記憶の検索結果が不足する原因`はそもそも記憶されていないか、検索に時間がかかりすぎているから。
`長期記憶の検索結果の不足を解消する`には長期記憶の`保存強度`と`検索強度`を高めると良い。
`保存強度`はどれだけ長く記憶できるか。
`検索強度`はどれだけ速く検索できるか。
上記2点を意識しつつ以下4点をすると良い。
1. 定期的に情報に触れる
1. 複数の感覚で学ぶ（視・聴・嗅・味・触)
1. チャンク化して認識する
1. 深掘りし関連情報も記憶することで`スキーマ`\*を強化する
    *スキーマとは類似する記憶同士の結びつきのネットワーク構造のこと。
#### 処理能力の不足
`処理能力が不足する原因`は処理能力に対して負荷が大きすぎるから。
`処理能力の不足を解消する`には処理の負荷を減らすと良い。
処理の負荷（認知負荷）は3つに分類できる。
`学習関連負荷`・`課題内在性負荷`・`課題外在性負荷`
  
- `学習関連負荷`は長期記憶する際の負荷。         （軽減は困難）
- `課題内在性負荷`は問題本来の難しさによる負荷。  （軽減できる。例：複雑な数学的処理）
- `課題外在性負荷`は問題と無関係な負荷。         （軽減できる。例：特定の実装の複雑さ）<br><br>

  `課題内在性負荷を削減するには`例えば「状態遷移図を書き、場合分けすることで一度に考慮すべき事象を削減する」といったように、問題そのものの複雑さを分散する。
  `課題外在性負荷を削減するには`、例えば「自分の読みやすいコードに変える（例：map -> for in）」といったように、問題を取り巻く複雑さを軽減する。
    
上記の認知プロセス及びその負担の軽減方法を踏まえて、`コードの意図が掴めない時`は以下を心がけると良い。

# コードの意図を掴む手法


  - コードの全体的な雰囲気を掴む（例：全体を流し読みして直後に思い出すよう試みることでチャンク化して認知できたか確認する）
  - 重要な点を列挙する（着目すべき点を制限することで問題を取り巻く複雑さを排除する。）
  - 点から理解を拡げる（例：変数の役割という一点から考えることで問題を取り巻く複雑さを排除する）
  - 視覚化する（例：依存関係図や状態遷移図など）
  - 内容を要約する（例：ソースドキュメントを書く）
  - …

# 認知プロセス全体に有効な施策
- 余計な情報を遮断する。（例：机上は整理する。静かな環境を作る。作業中に𝕏しない。）
- 割り込みを低減する。（例：集中タイムを作る。一人で作業する。通知を一定時間切る。）
- 割り込みからの復帰を容易にする。（例：コンパイルエラーにしておく。メモを残す。問題を分割することで思い出すべき量を低減する。）
CustomVisionサンプルテスト

## 目的
#### 受信した注文書の自動仕分け

## 今回は・・
これです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/2afee57c-6bfb-eff7-9f52-2eae50e5fbca.png)
### 参考：CustomVisionのトレーニングが失敗したら・・

https://jpaiblog.github.io/blog/2022/03/25/how-to-troubleshoot-custom-vision-training-issue/

参考サイト：

https://jpaiblog.github.io/blog/2022/03/25/how-to-troubleshoot-custom-vision-training-issue/


## 前処理：画像の変換
フォルダ内のbmpファイルを全てpngファイルに変換後、出力
＊chatGPTでプロンプト→OK

```bmptopng.py
import os
import sys
from PIL import Image

def bmp_to_png(folder_path,output_dir):
    try:
        # フォルダが存在するか確認
        if not os.path.exists(folder_path):
            raise FileNotFoundError(f"The folder {folder_path} does not exist.")

        # 出力ディレクトリが存在しない場合、作成する
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)

        # フォルダ内のファイル一覧を取得
        file_list = os.listdir(folder_path)

        # BMPファイルをPNGに変換
        for filename in file_list:
            if filename.lower().endswith(".bmp"):
                bmp_path = os.path.join(folder_path, filename)
                png_path = os.path.join(output_dir, os.path.splitext(filename)[0] + ".png")

                # BMPファイルをPNGに変換
                with Image.open(bmp_path) as img:
                    img.save(png_path)

                print(f"Converted {bmp_path} to {png_path}")

        print("Conversion completed.")
    
    except FileNotFoundError as e:
        print(e)
    except Exception as e:
        print(f"An error occurred: {e}")

if __name__ == "__main__":
    folder_path = r''
    output_directory = ''
    output_dir = os.path.join(os.getcwd(), output_directory)

    bmp_to_png(folder_path,output_dir)

```

## 画像の水増し
以下サイトより、コード活用させていただきました。ありがとうございます。

https://qiita.com/bohemian916/items/9630661cd5292240f8c7

## Azure Portalからの・・・
Settingはスキップさせていただきます。

参考：

https://zenn.dev/mochan_tk/articles/9a25dd3e0863d2

## Classification, Multiclass
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/74e85810-ceca-1b29-f109-6ae24ba09539.png)

## General[A2]でやってみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/b5d2ae91-94b8-6137-1e48-972489b68dca.png)

## とりあえずAdd Images & Set Tag
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/90ebd4ff-f7ab-4147-eb17-eb0d8c2ed381.png)

## Train
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/27a79618-3ab0-896d-3c33-bdeb183f18c7.png)
Quickでチャレンジ。
実際はより詳細にチューニング必要です。

## 完成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/7b45bed8-3474-fb22-342e-7e7cb1502b5b.png)

サンプルが少ないと精度は低下しますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448426/ccc12906-2362-0af2-2f63-8bdaf1ff9fbb.png)


## 精度の確認
大まかなフォームはまず合致する。
フォームが同様で、注文先が異なる場合は別途考慮する必要あり。
でもかなり面白いし簡単である。

後はコストとの兼ね合い。。
AWS Backupでローカルタイムゾーンを日本に選択できるようになりました

# AWS Backupでローカルタイムゾーンを日本に選択できるようになりました

>[2023年8月29日に、AWS Backupサービスのバックアッププランでローカルタイムゾーン選択のサポートが発表されました。](https://aws.amazon.com/jp/about-aws/whats-new/2023/08/aws-backup-local-time-zone-selections/)

既存のバックアッププランをUTCタイムゾーンから他のタイムゾーンに指定が可能になりました。
新しい機能か追加されたので早速確認してみました。

## マネジメントコンソールでの確認
マネジメントコンソールでは、日本ゾーンだけでなく、さまざまなタイムゾーンが選択できるようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330696/ae6fd837-7eb6-8f66-b50b-bb3787a2f10d.png)

## CloudFormationで実装方法

CloudFormationテンプレートに、`ScheduleExpressionTimezone` を追加することで、ローカルタイムゾーンを指定できます。
以下、[CloudFormationテンプレート](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-backup-backupplan-backupruleresourcetype.html#cfn-backup-backupplan-backupruleresourcetype-scheduleexpressiontimezone)の一部です。

```
  CompletionWindowMinutes: Double
  CopyActions: 
    - CopyActionResourceType
  EnableContinuousBackup: Boolean
  Lifecycle: 
    LifecycleResourceType
  RecoveryPointTags: 
    Key: Value
  RuleName: String
  ScheduleExpression: String
  ScheduleExpressionTimezone: String
  StartWindowMinutes: Double
  TargetBackupVault: String
```



## タイムゾーンをAsia/Tokyoに設定

次に、`Asia/Tokyo` を値として指定してAWS Backupのスタック作成してみました。

```
ScheduleExpressionTimezone: Asia/Tokyo
```


## スタック作成後、マネジメントコンソールのバックアップルールからの結果
スタック作成後、マネジメントコンソールのバックアップルールからの結果では、日本のローカルタイムゾーンでバックアップを実行できることが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330696/49eee216-c918-6372-26c2-69471502edba.png)

Asia/Tokyo時間になっているのが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3330696/029557df-5532-edcd-c16e-80045f27ec53.png)
WSLにKali linuxをインストールする際にエラーが出た話

WSLでKali-linuxをインストールして使う際に発生したエラー
Error: 0x80004005
についての解決策
```
wsl --update
```
WSLのアップデートをしてから再度インストールし直すことでエラーが発生せず無事にインストール，初期設定ができました
form_withを使ったフォームの送信時のアラートをI18n対応させる方法

### 解説する内容

・form_withで作成したフォームの送信時に「本当に登録してもいいですか？」的なアラートを表示させる。
・その表示させたアラートをI18n対応させて翻訳可能にする。

ログアウト時などにアラートを表示させる方法は多々見かけましたが、フォーム送信時はあまり見かけなかったので備忘録として残しておきます。

simple_formを使用している場合も同じ手順で実装できます。

# フォームの実装
今回は単純なユーザー登録画面を例に実装していきます。
### View
```erb:view.html.erb
<%= form_with(model: @user, local: true) do |form| %>
  <%= form.text_field :username %>
  <%= form.text_field :password %>
  <%= form.submit "登録" %>
<% end %>
```
コントローラーは今回は全くいじらないので、省略します。

# 送信前にアラートを表示させる
submitボタンに`data: { confirm: "アラートで表示させたい内容" }`オプションを設定することでアラートを表示できます。
```erb:view.html.erb
<%= form_with(model: @user, local: true) do |form| %>
  <%= form.text_field :username %>
  <%= form.text_field :password %>
  <%= form.submit "登録", data: { confirm: "本当に登録してもいいですか？" } %>
<% end %>
```

# I18n対応させてアラートを翻訳可能にする
では続いて表示されるアラートの文字をI18n対応させていきます。
これまた単純です。
```erb:view.html.erb
<%= form_with(model: @user, local: true) do |form| %>
  <%= form.text_field :username %>
  <%= form.text_field :password %>
  <%= form.submit "登録", data: { confirm: I18n.t("alert.are_you_sure?") } %>
<% end %>
```
`data: { confirm: confirm: I18n.t("alert.are_you_sure?") }`
このように変更して、
`alert.are_you_sure?`の部分にパスを指定してあげればOK。
以上になります！

間違い等あればご指摘いただけると助かります！

参考記事

https://paranishian.hateblo.jp/entry/rails/show-confirm-on-submit-form
WordPress 自作プラグインの作成方法

構成ファイル
plugin
|- main.php
|- templates - subu1.php , subu2.php
|- assets - style.css
|- images - 画像ファイル

```php
main.php
<?php

/*
Plugin Name: プラグインの名前
Description: プラグインの名前
Version: 1.1.1
Author: 製作者
*/

// 直接アクセスされた場合は終了
if (!defined('ABSPATH'))
    exit;

// プラグインのファイルパスとURLを定義
define('MY_PLUGIN_NAME_PATH', plugin_dir_path(__FILE__));
define('MY_PLUGIN_NAME_URL', plugin_dir_url(__FILE__));

// ショートコードを使用して複数のテンプレートファイルを結合して表示するコード
function display_su_bmenu_contents() {
    ob_start(); // バッファリングを開始
    
    // 複数のテンプレートファイルを順番に結合して表示
    include MY_PLUGIN_NAME_PATH . 'templates/subu1.php';
    include MY_PLUGIN_NAME_PATH . 'templates/subu2.php';
    
    return ob_get_clean(); // バッファの内容を取得して出力
}
add_shortcode('display_submenus', 'display_su_bmenu_contents');


// 管理画面メニューの追加とコンテンツの表示
function wp__add_menu()
{
    add_menu_page(
        'メニュー',// ページのタイトルタグ<title>に表示されるテキスト
        'メニュー',// 左メニューとして表示されるテキスト
        'manage_categories',// 必要な権限 manage_options:管理者のみ manage_categories:管理者＋編集者
        'wp_mainmenu',// メニューのスラッグ名 URLのパラメータ /wp_-admin/admin.php?page=wp__menu
        'wp_mainmenu_page_contents',// メニューページを表示する際に実行される関数
        'dashicons-menu',// プラグインのアイコン　https://developer.wordpress.org/resource/dashicons/#menu
        65// メニューが表示される位置のインデックス(0が先頭) 5=投稿,10=メディア,20=固定ページ,25=コメント,60=テーマ,65=プラグイン,70=ユーザー,75=ツール,80=設定
    );

    add_submenu_page(
        'wp_mainmenu',// 親メニューのスラッグ
        'サブメニュー1',// ページのタイトル
        'サブメニュー1',// サブメニューに表示されるテキスト
        'manage_categories',// 必要な権限
        'wp_mainmenu',// ページのスラッグ（URLで使用）
        'wp_mainmenu_page_contents', // ページのコンテンツを出力する関数
        0
    );

    add_submenu_page(
        'wp_mainmenu',
        'サブメニュー2',
        'サブメニュー2',
        'manage_options',
        'wp_subu2',
        'wp_subu2_page_contents',
        1
    );
}
add_action('admin_menu', 'wp__add_menu');

// CSSファイルを読み込む
function wp_enqueue_styles()
{
    wp_enqueue_style('wp-plugin-style', MY_PLUGIN_NAME_URL . 'assets/style.css');
}
add_action('admin_enqueue_scripts', 'wp_enqueue_styles');

// メニューページのコンテンツ表示
function wp_mainmenu_page_contents()
{
    // メインメニューページのコンテンツ
    include MY_PLUGIN_NAME_PATH . 'templates/subu1.php';
}

function wp_subu2_page_contents()
{
    // サブメニューSNSのコンテンツ
    include MY_PLUGIN_NAME_PATH . 'templates/subu2.php';
}


```
【Rails】pluralizeとsingularize

今回の記事ではpluralizeとsingularizeの2つのメソッドについて紹介したいと思います。
railsでの開発中に単数形や複数形に変換できたら便利なのに…と思ったことはありませんか？そんなときに役立つのがpluralizeとsingularizeです。
# pluralize
`pluralize`メソッドは、指定した文字列を複数形に変換します。
### 使い方
例えば以下のように使うことができます。
```ruby
pluralized_word = "book".pluralize
# 出力: "books"

# カウントに基づく複数形の変換
count = 3
pluralized_word = "book".pluralize(count)
# 出力: "books"
```
### 定義
定義は以下のリンクから確認することができます。

https://github.com/rails/rails/blob/7-0-stable/activesupport/lib/active_support/core_ext/string/inflections.rb


### オプション
`pluralize`メソッドにはさまざまなオプションがあります。
例えば、不規則な複数形を指定したり、カスタム辞書を使用したりすることができます。
これにより、不規則な複数形や非可算名詞を扱えるなど柔軟性が向上します。

# singlarize
`singlarize`メソッドは、指定した文字列を複数形に変換します。

### 使い方
例えば以下のように使うことができます。
```ruby
singularized_word = "books".singularize
# 出力: "book"

# 複数形の単語を単数形に変換
singularized_word = "dogs".singularize
# 出力: "dog"
```
### 定義
定義は以下のリンクから確認することができます。

https://github.com/rails/rails/blob/7-0-stable/activesupport/lib/active_support/core_ext/string/inflections.rb

### オプション
`singularize`メソッドにはカスタム辞書を使用するオプションがあり、特定のルールに従わない単語を正確に変換できます。





このようにRailsのpluralizeとsingularizeメソッドは、文字列の変換を簡単に行える強力なツールです。
これらのメソッドを積極的に活用し、開発プロセスを効率化に役立ててみてください。


#### 参考
https://railsguides.jp/active_support_core_extensions.html#pluralize
【Next.js13】Dynamic Routesで動的にパスを生成したい

## 概要
はじめまして！

最近Next.jsの学習をはじめましたが、個人開発において動的にパスを生成したくなったので、Dynamic Routesについて少しまとめてみました。

## Dynamic Routes is 何？

https://nextjs.org/docs/pages/building-your-application/routing/dynamic-routes

> Convention
A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]. For example, [id] or [slug].

> Dynamic Segments can be accessed from useRouter.

> Example
For example, a blog could include the following route pages/blog/[slug].js where [slug] is the Dynamic Segment for blog posts.

Next.js13系では、app/配下のディレクトリがルーティングと紐づいており、ディレクトリ名がそのままパス名になる仕組みになっています。

例えば、カラムとして保持してるslugをパスとして指定したい場合、ブラケット付きのディレクトリ名``[slug]``で作成することで　そのカラム名で動的にパスを作ることができます。

## 現在のディレクトリ構造
```
.
└── app
    ├── favicon.ico
    ├── globals.css
    ├── layout.tsx
    ├── page.tsx
    └── works
        └── page.tsx
```
## やりたいこと

現状は``/works``に遷移できます。
この``/works``から、``/works/trial``や``/works/basic``のように単一ページでパスを作れるようにします。
```javascript:app/works/page.tsx
import Link from 'next/link';

export default function () {
	return (
		<div>
			<h1 className="text-3xl font-bold">/worksだよ</h1>
		</div>
	);
}
```
[![Image from Gyazo](https://i.gyazo.com/fc99322ed12607fe3de26e8f2b5dff4a.png)](https://gyazo.com/fc99322ed12607fe3de26e8f2b5dff4a)

## 検証
ドキュメント通り、works配下にブラケット付きの``[slug]``ディレクトリと``page.tsx``を作成します。

```
tree
.
└── app
    ├── favicon.ico
    ├── globals.css
    ├── layout.tsx
    ├── page.tsx
    └── works
        ├── [slug]
        │   └── page.tsx
        └── page.tsx
```

``works/page.tsx``にリンクを追加します。

```javascript:src/app/works/page.tsx
import Link from 'next/link';

export default function Home() {
  return (
    <div>
      <h1 className="text-3xl font-bold">/worksだよ</h1>
	    <nav>
		  <ul>
		    <li>
			  <Link href="/">Home</Link>
			</li>
			<li>
			  <Link href="/works/trial">Trial</Link>
			</li>
			<li>
			  <Link href="/works/basic">Basic</Link>
		    </li>
			<li>
			  <Link href="/works/intermediate">Intermediate</Link>
		    </li>
	     </ul>
      </nav>
  </div>
  );
}
```

``works/[slug]/page.tsx``に受け取ったパスを表示できるようにします。
```javascript:src/app/works/[slug]/page.tsx
'use client';

import { usePathname } from 'next/navigation';

export default function Page() {
	const Pathname = usePathname();
	return <h1 className="text-3xl font-bold">パス: {Pathname}</h1>;
}
```
表示を確認します。
[![Image from Gyazo](https://i.gyazo.com/63399a8eafff1ff465e934b335bb30c0.png)](https://gyazo.com/63399a8eafff1ff465e934b335bb30c0)
[![Image from Gyazo](https://i.gyazo.com/8d15cfcdaabaebfad2b21d4ed3bb42b7.png)](https://gyazo.com/8d15cfcdaabaebfad2b21d4ed3bb42b7)
無事に表示が確認できました！

## まとめ
Next.jsを学んでいますが、レンダリングの選択肢や、コンポーネント設計、Hookの使い方など、たくさん勉強することがあるのでこれからも地道に勉強していきたいです！
最後まで読んでいただき、ありがとうございました！
ReactでURLを直接打ち込むと本番サーバで404表示になる

react-routerを使ったソースコードをサーバにアップしたのはよかったんですが、
直接ページに行こうとすると404エラー（そんなページ無いですよ！）って表示されて困ったので調べました。

参考：
https://qiita.com/Jey/items/fe98cb6773c057b1a4c8

.htaccessの記述を変更して、URLを直打ちした場合は`/react-project/`にリダイレクトされるように修正。
以下を.htaccessに追加↓
```
RewriteRule . /react-project [L]
```
【Swift】UIImageの空判定をする

今回は、UIImageを空判定する方法で「こんな判定の仕方があったんだぁ」と思ったので書き留めておきます。
文字列の空判定を行う`isEmpty`のUIImage版です。
※　ちなみにUIImageにisEmptyは存在しません。

前提として中身が`UIImage()`だったときの判定方法です！

----
例１

```swift
let image = UIImage()

if image.size == CGSize.zero {
    // 中身が空のときの処理
    print("空")
} else {
    // 中身が空じゃない時の処理
    print("空じゃない")
}
```

例２
```swift
if image.size.width == 0 || image.size.height == 0 {
    // 画像が空の場合の処理
    print("空")
} else {
    // それ以外の場合の処理
    print("空じゃない")
}
```

例3
```swift
if image.size.equalTo(.zero) {
    // 画像が空の場合の処理
    print("空")
} else {
    // 空じゃない
    print("空じゃない")
}
```

----

### まとめ
こんな感じで画像の中身のsizeが０だった判定すれば空判定ができるはず
PHPのコードレビューこんなんやってる（その１）

# 概要
意外とそんなにパターン無いのではと思い、整理と今後の備忘がてら記載してみました。実際にメンバーにしたレビュー内容をもとにしています。ちなみに思い立ったきっかけはこちらのツイート（X）でした。

https://twitter.com/HouseToma/status/1699942212891742713

※写真は全く関係ない

# 前提
以下の内容を踏まえてもらえるとひょっとしたら何かの参考になる度合いが
* PHPです
* 1年目にしたレビューが元になっています

# レビュー内容

* returnでなんか値返すfunctionなら、命名に「set◯◯」って付けるのは辞めたほうが良さそう
* functionまるごとifの条件文で囲われてるから、条件を逆にして早期return
* 片方の条件に引っかかったときにreturnしちゃっていい

## returnでなんか値返すfunctionなら、命名に「set◯◯」って付けるのは辞めたほうが良さそう
class全体の中でfunctionがどういう役割なのかは一旦置いておいて、役割が想像できる命名にはしておきたいという内容ですね。

### before
```PHP
function setShopList()
{
    (何らかの処理)

    return $shopList;
}
```

### after
```PHP
function getShopList()
{
    (何らかの処理)

    return $shopList;
}
```

## functionまるごとifの条件文で囲われてるから、条件を逆にして早期return
なんやかんやネストを浅くする心がけは要所でやっていますね。

### before

```PHP
function getCustomerAd($customer)
{
    if(!empty($customer['adId']) {
        ($customer['adId']でデータを取ってくる処理)
        return $adData;
    }

    return [];
}
```

### after
```PHP
function getCustomerAd($customer)
{
    if(empty($customer['adId']) {
        return [];
    }

    ($customer['adId']でデータを取ってくる処理)

    return $adData;
}
```

## 片方の条件に引っかかったときにreturnしちゃっていい
同上＋返り値が確定した段階でreturnしてしまった方が、返り値も安定するよなあという気持ちで整理はよくしますね。
### before
```PHP
function getCustomerComment($customer)
{
    $comment = '';

    if(!empty($customer['staffId']) {
        ($customer['staffId']でスタッフコメントデータを取ってくる処理)
        $comment = $staffComment;
    } elseif ($customer['shopId']) {
        ($customer['shopId']で店舗コメントデータを取ってくる処理)
        $comment = $shopComment;
    }

    $comment;
}
```

### after
```PHP
function getCustomerComment($customer)
{
    if(!empty($customer['staffId']) {
        ($customer['staffId']でスタッフコメントデータを取ってくる処理)
        return $staffComment;
    }

    if ($customer['shopId']) {
        ($customer['shopId']で店舗コメントデータを取ってくる処理)
        return $shopComment;
    }

    return '';
}
```

# 終わり
まだまだあるような気もするし、そんなにパターンがないような気もします。
できれば単発企画にならないように、継続してけたらいいなあというところですね。
NPMとは何なのか？

JavaScript系列のフレームワークを使う際、お世話になる`npm ~~~`コマンド。
このnpmとは何者なのか。
公式ドキュメントはこちらー＞ https://docs.npmjs.com/about-npm

NPMとは
------------
「Node Package Manager」の略。Node.jsがJavaScript系列のパッケージ（React,Vue,TypeScript,jQueryなどのフレームワークやライブラリの総称）を管理してくれる。（なので、Node.jsを最初にインストールしておくことが必要）
「Aのパッケージを使いたい！」となったとき、「じゃあ、Aのパッケージを使うにはBとCのパッケージも必要だから一緒にインストールしておくね！」と、依存関係にあるものを一緒にインストールしてくれる。まさにマネージャ。

Node.jsとは
------------
じゃあ、そのNode.jsってなんなんだい。
そもそもJavaScriptはブラウザ上で動くことのできる言語で、Rubyなどのバックエンド言語と違って、OSへのアクセス権を持っていない。一部アクセス権をブラウザが仲介することでweb会議などができるようになる。
基本的にフロントエンドといわれる部分で動けるのがJavaScript。でも、Node.jsはバックエンドの分野でも動くことができる特別なやつ。Node.jsはJavaScriptのうちのフレームワーク（ReactやVueなどJavaScriptをベースにより扱いやすくになった言語） __ではなくて__ 、__JavaScriptの実行環境__ のことを指す。ちょっとややこしいね。
ブラウザ経由でないとOSへのアクセスができないJavaScriptだけど、そのブラウザの代わりを務めるのがNode.jsになる。

参考記事はこちら↓
すごくわかりやすいです。
https://qiita.com/non_cal/items/a8fee0b7ad96e67713eb

まとめ
------------

:::note info
・Node.jsはバックエンドでも動けるJavaScriptであり、実行環境である。
・NPMはjsパッケージの管理をしてくれる便利な奴。
:::
Google Workspace でのSSOエントリポイントURL作成

# 概要

Google WorkspaceをIdPとして設定、サービス側からアクセス(SP-initiated)した場合のURLが分からず、少し調べたので記録しておきます。

## どういうことか

具体的には下記のようなことです。

1. あるサービスで、認証部分をGoogle WorkspaceのIdPへ任せる設定にしている
2. Googleのアプリケーションランチャーからサービスへアクセスすると正しく利用できる(IdP-initiated)
3. Googleへログインしていない状態でサービスへアクセスした場合はそのままでは利用できないので、Googleのログイン画面へ遷移し、ログイン後、サービスへ戻ってきて欲しい(SP-initiated)

一般的なフローだと思いますが、上記 3 のケースでアクセスすべきURLが分からないので何とかした、という内容です

## Google Workspace SAMアプリケーションのSSO設定

設定ページに表示されるURLとしては [SSO の URL] がありますが、このURLアクセスしても目的は達成できません。

# SSOエントリポイントURLの作り方

1. 対象のウェブアプリページへアクセスします
1. [メタデータをダウンロード] をクリックし、 [SSO の URL] 末尾の `idpid=xxxx` 部分をメモします(idpid)
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/c5527a83-d053-f64b-addb-e452df81357c.png)
1. アドレスバーの末尾の数字をメモします(spid)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/a4140c13-1f0b-99e9-d55a-7c7bb4aaefd0.png)
1. 2つの値を下記のようににあてはめ、パラメータ付きURLを作成します

```
https://accounts.google.com/o/saml2/initsso?idpid=A123456&spid=1234567890
```

# 確認
作成したURLへアクセスしてGoogleログインページへリダイレクトされることを確認します。
アプリケーションの設定によると思いますが、一般的には正しくログインすると、設定したサービスへリダイレクトされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/2c00e622-0491-caab-57e7-de521b83cbf2.png)


# 感想

Google Workspaceの管理画面に最初から表示してくれれば良いのに。と思いました。
Dockerインストールしたらエラーになった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/1523e1c1-c1a1-037a-8b37-f6995eb6bffe.png)
Windows11の環境でDockerを入れようと思ったら、画像のエラーが出てしまいました。

Google翻訳で直訳するとWSLのカーネルバージョンが低いですよって言っていますね。
調べたら以下の手順があったので、参照して進めてみました。
https://learn.microsoft.com/ja-jp/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/bc51efd0-28a1-3470-b37e-2c36f59303b0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/600e900e-d16d-4596-abde-3a8c1596623b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3489679/e4828630-9175-4d70-92d7-952745995dbe.png)

無事に表示されました！
VSCodeでGoの開発環境を作成する

基本的にJetBrains製の開発環境を使っていたため、
VSCodeはメモ帳代わりにしか使った事がないが、
新しい会社ではリモートモブプロ含め、VSCodeをメインで利用されてるようなので、
GoLandから乗り換えてみる。

## 前提

Goがインストールされていること。

## VSCodeの拡張機能のインストール

### Go

1. Ctrl + Shift + XでEXTENSIONS: MARKETPLACEを開く。
2. Go for Visual Studio Codeを検索してきてインストールする。

#### 開発に必要なツールの更新

1. Ctrl + Shift + Pでコマンドパレットを表示する。
2. Go: Install/Update toolsを検索する。
3. 全てをチェックし、OKを押す。

## 実行とデバッグ

1. Ctrl + Shift + DでRun and Debugを表示する。
2. ▷ボタンから実行する。

## 感想

もしかして、Goプラグインのみを入れれば動くのかなこれ。
下記記事などをみると、なんか他にもlinterみたいなやつとか必要な気がするが、いまいち何がよいのか分かっていない。

https://yurupro.cloud/2531/

しばらく使ってみつつ、他のプラグインを入れて検討しつつ、この記事を更新してみる。

## 参考

https://learn.microsoft.com/ja-jp/azure/developer/go/configure-visual-studio-code
行列式、固有値、固有ベクトル

### 行列式とは？誰でも理解できるようにわかりやすく解説
https://www.headboost.jp/definition-of-determinant/

### 固有値、固有ベクトル - Eigenvectors and eigenvalues | Chapter 14, Essence of linear algebra
https://www.youtube.com/watch?v=PFDu9oVAE-g
C#またはVB.NETでPDF を PDF/A に変換する

PDF/Aは、長期保存のための特別なファイル形式であり、電子文書の信頼性を確保するために設計されています。PDF/Aに変換することで、伝統的なPDF形式では長期保存時に互換性や可読性の問題が発生する可能性がありますが、それを解決することができます。以下に方法を紹介します。

## ツール
* Visual Studio 2022 
* [Free Spire.PDF for .NET](https://www.e-iceblue.com/Introduce/free-pdf-component.html)
このライブラリは、無料でPDFファイルを作成、編集、変換することができますが、ページ数の制限があります。または、有料版の製品の無料トライアルを申し込むこともできます。
[Spire.PDF for .NET](https://www.e-iceblue.com/Introduce/pdf-for-net-introduce.html)

## インストール
* [Free Spire.PDF for .NET](https://www.e-iceblue.com/Download/download-pdf-for-net-free.html)をダウンロードします。
* Visual Studioで新しいプロジェクトを作成します。
* 「Solution Explorer」で「References」を右クリックし、* 「Add Reference」>「Browse」を選択します。
* BINフォルダ内のdllファイルを見つけて、「OK」をクリックします。

## コード
C#:
```c#
using Spire.Pdf.Conversion;
using System;

namespace ConvertPdf2Pdfa {
    
    class Program {
        
        private static void Main(string[] args) {

            //ファイルパスを指定する
            string inputFile = "C:\\Users\\Administrator\\Desktop\\sample.pdf";
            string outputFolder = "C:\\Users\\Administrator\\Desktop\\PDF\\";

            //PdfStandardsConverterインスタンスを作成し、inputFile パスをパラメータとして渡す
            PdfStandardsConverter converter = new PdfStandardsConverter(inputFile);

            //PDFをPDF/A1Aに変換する 
            converter.ToPdfA1A((outputFolder + "PDFA1A.pdf"));
        }
    }
}
```
VB.NET:
```vb
Imports System
Imports Spire.Pdf.Conversion

Namespace ConvertPdf2Pdfa
    
    Class Program
        
        Private Shared Sub Main(ByVal args() As String)

            'ファイルパスを指定する
            Dim inputFile As String = "C:\Users\Administrator\Desktop\sample.pdf"
            Dim outputFolder As String = "C:\Users\Administrator\Desktop\PDF\"

            'PdfStandardsConverterインスタンスを作成し、inputFile パスをパラメータとして渡す 
            Dim converter As PdfStandardsConverter = New PdfStandardsConverter(inputFile)

            'PDFをPDF/A1Aに変換する
            converter.ToPdfA1A((outputFolder + "PDFA1A.pdf"))
        End Sub
    End Class
End Namespace
```
同様に、他の PDF/A 形式に変換する場合も、コードを少し変更するだけで済みます。
たとえば、PDF から PDFA/1B へ：「**PdfStandardsConverter.ToPdfA1B()**」
![2023-09-08_110035.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/1c887170-8009-8c44-8df3-acce10ca3e69.png)
【Python】Pandasのデータフレームをクエリする方法

# はじめに
DBを使わずにPandasのデータフレームをテーブルのように扱っているなど、大きなデータフレームから特定の値を抽出するクエリをする場合の方法をまとめました。
最初はデータフレームの基本的な説明をし、後半にクエリの方法を説明します。

# データフレームについて
Pandasのデータフレーム(DataFrame)はこのようなコードです
```python
import pandas as pd

# DataFrameの作成
data = {'名前': ['田中', '佐藤', '鈴木'],
        '年齢': [25, 30, 35],
        '職業': ['エンジニア', 'デザイナー', 'マネージャー']}

df = pd.DataFrame(data)
#    名前  年齢   職業
# 0  田中   25  エンジニア
# 1  佐藤   30  デザイナー
# 2  鈴木   35  マネージャー
```

続いてデータフレームを操作する方法です。
### 列の指定
SQLのselect '年齢" from...のように対象の項目を設定します。

+ 1つの列を取得
```python
age = df['年齢']
# 0    25
# 1    30
# 2    35
```

+ 複数列を取得
```python
data = df[['名前', '職業']]
#    名前     職業
# 0  田中   エンジニア
# 1  佐藤   デザイナー
# 2  鈴木   マネージャー
```
### 集計
SQLのgroup byのように対象の項目で集計します
```python
# 職業毎に平均年齢を集計
avg_age = df.groupby('職業')['年齢'].mean()
#   職業
# エンジニア     25.0
# デザイナー     30.0
```
mean()で平均値を取得しています。他には
+ min() :最小値
+ max() :最大値
+ sum() :合計

Pandasのデータフレームの基本をご紹介したので
続いてクエリの方法をご紹介します。

# クエリする方法
```python
# 年齢が30歳以上の行を取得
result = df.query("年齢 > 30")
#    名前  年齢   職業
# 2  鈴木  35  マネージャー
```

ここからはデータ量を増やして複雑なクエリを実行してみます。
```
import pandas as pd

# DataFrameの作成
data = {'名前': ['田中', '佐藤', '鈴木', '山本', '高橋'],
        '年齢': [25, 30, 35, 40, 45],
        '職業': ['エンジニア', 'デザイナー', 'マネージャー', 'エンジニア', 'デザイナー'],
        '給与': [500, 600, 700, 800, 900]}

df = pd.DataFrame(data)
```
### andを使用
年齢が30以上で、かつ給与が700以上の行を取得します
```python
result = df.query("年齢 >= 30 and 給与 >= 700")
#    名前  年齢    職業     給与
# 2  鈴木  35   マネージャー  700
# 3  山本  40   エンジニア   800
# 4  高橋  45   デザイナー   900
```

# orを使用
年齢が30以下、または職業がエンジニアの行を取得します
```python
result = df.query("年齢 <= 30 or 職業 == 'エンジニア'")
#    名前  年齢   職業     給与
# 0  田中  25   エンジニア  500
# 1  佐藤  30   デザイナー  600
# 3  山本  40   エンジニア  800
```

# isinを使用
職業がエンジニアまたはデザイナーの行を取得します
```python
result = df[df['職業'].isin(['エンジニア', 'デザイナー'])]
#    名前  年齢   職業     給与
# 0  田中  25   エンジニア  500
# 1  佐藤  30   デザイナー  600
# 3  山本  40   エンジニア  800
# 4  高橋  45   デザイナー  900
```

# クエリ条件で絞り込み集計する
年齢が30以上の人で、職業毎の平均給与を計算します
```python
result = df[df['年齢'] >= 30].groupby('職業')['給与'].mean()
#   職業
# エンジニア     800.0
# デザイナー     750.0
# マネージャー    700.0
```

### 2つのデータフレームを結合してクエリする
データ分析する時にデータフレーム同士を結合して集計することがあります。
ここでは2つのデータフレームを内部結合してクエリを実行してみます。

2つのデータフレームを作成します
```python
import pandas as pd

# DataFrame1の作成
data1 = {'ID': [1, 2, 3, 4],
         '名前': ['田中', '佐藤', '鈴木', '山本'],
         '年齢': [25, 30, 35, 40]}

df1 = pd.DataFrame(data1)

# DataFrame2の作成
data2 = {'ID': [3, 4, 5, 6],
         '職業': ['マネージャー', 'エンジニア', 'デザイナー', '営業'],
         '給与': [700, 800, 600, 550]}

df2 = pd.DataFrame(data2)
```

2つのデータフレームを結合します
```python
merged_df = pd.merge(df1, df2, on='ID', how='inner')
#    ID  名前  年齢    職業     給与
# 0   3  鈴木  35   マネージャー  700
# 1   4  山本  40   エンジニア   800
```
IDの値を元に内部結合しました

結合したデータフレームに対してクエリします
```python
result = merged_df.query("年齢 >= 40 and 給与 >= 700")
#    ID  名前  年齢    職業     給与
# 1   4  山本  40   エンジニア   800
```
Azure Cognitive Search のセマンティックランカーモデルがアップデート

Azure Cognitive Search で現在プレビュー中のセマンティック検索機能の一つである、[セマンティックランキング](https://learn.microsoft.com/ja-jp/azure/search/semantic-ranking)に用いられている Microsoft 製の Turing モデルがアップデートされました。セマンティックランキングは BM25 ベースのキーワード検索のリランカーとして用いられており、モデルのアップデートに合わせて `@search.rerankerScore` の分布も変更されています。

現状以下のような更新がかかっております。

- モデルのアップデートによる精度向上
- `@search.rerankerScore` の分布が変更
- 検索結果に複数の言語のドキュメントが混在している場合、フィールドの言語アナライザーに指定した言語以外のドキュメントも上位に表示するように変更
- セマンティックランキング生成用のトークンが 128→256 に拡張
- 昔のモデルは使えない

## モデルのアップデートによる精度向上
古いモデルが上書きされてしまっているので、比較ができない状況です…
以前デモで実施したセマンティック検索の結果を見る限り、確かにランキングは変化しています。

### 1. 古いモデルのセマンティックランキング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674344/12fe2ffa-6612-1dfb-d86d-23503716cc55.png)
クエリー：**「１３人の合議制に含まれるメンバー一覧」**
1. 源頼家-7.txt: `@search.rerankerScore`: 1.4289
1. 北条義時-3.txt: `@search.rerankerScore`: 1.0621

### 2. 新しいモデルのセマンティックランキング
ランキングが明確に変わりました。`@search.rerankerScore` も 1.0 くらい増えています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/674344/53f9a329-3875-f934-0fce-f0097c7ec958.png)

1. 北条政子-8.txt: `@search.rerankerScore`: 2.5723
1. 八田知家-0.txt: `@search.rerankerScore`: 2.4946

セマンティックアンサーの結果およびスコアは変化がありません（score: 0.7744）が、ランキングの中にセマンティックアンサーに選ばれたドキュメントが含まれるようになっています。このように明確に変わったため、アプリケーションにセマンティックランカーの `@search.rerankerScore` を閾値として用いている場合は再試験が必要です。

## 言語アナライザー依存から非依存への変更
検索結果に複数の言語のドキュメントが混在している場合、フィールドの言語アナライザーに指定した言語以外のドキュメントも上位に表示するように変更されました。これは例えば `en.lucene` が指定されたフィールドに日本語コンテンツが存在している場合でも、クエリーに近ければ上位に持ってきてくれるということです。

## セマンティックランキング生成用のトークンが 128→256 に拡張
セマンティックランキングを生成するためには[セマンティック構成](https://learn.microsoft.com/azure/search/semantic-how-to-query-request?tabs=semanticConfiguration%2Cportal#create-a-semantic-configuration)を作成する必要があります。この機能はインデックス内のどのフィールドがセマンティック検索に最も重要であるかをモデルに伝える役割を担っています。この時指定するフィールドの言語アナライザーがコンテンツをトークン化するのですが、これまで 128 トークンまでしか含められないという制限がありました。この制限が 2 倍の 256 トークンへ拡張されたため、ランキング生成に使えるトークンが増えたことによる精度の向上が期待されます。

ここでのトークンは、言語アナライザーによる分割単位のことで、例えば `ja.lucene` 場合「源実朝の趣味って何？」は「源実朝」「趣味」「何」の 3 トークンに分割されます。それでも、256 トークンって少ない気がしますが、content フィールドは特に。。。

# 参考
https://qiita.com/nohanaga/items/4b9506c62b9e5796f405

https://qiita.com/nohanaga/items/e156d8be60622b42e8eb
Let'Encryptの更新作業メモ

# 背景
初めてLet'Encryptの更新時期が来て、苦戦するのではないかとおびえていましたが、
意外と簡単にできたので、メモで残したいと思います。

# 環境
* Apache2.4
* CentOS
* ドメインは取得・設定済み

# Apacheの停止
Apacheは一度停止しないとエラーがでるそうです。
サーバー上のターミナルで以下のコマンドを打ってApacheを一旦停止します。
```
apachectl stop
```

# テスト環境でLet'Encryptをお試し更新
Let's Encryptは厳しめのレート制限があり、エラーなどでミスし続けると一定時間操作できなくなる可能性があるので、末尾に「--dry-run」をつけてテスト環境でお試し。
```
sudo certbot renew --dry-run
```
そうすると以下のように出ます。最後にsuccessと出ていれば成功です！

```
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/(ドメイン名).conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Account registered.
Simulating renewal of an existing certificate for (ドメイン名)
Performing the following challenges:
http-01 challenge for (ドメイン名)
Error while running apachectl graceful.

Job for httpd.service invalid.

Unable to restart apache using ['apachectl', 'graceful']
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of apache server; fullchain is
/etc/letsencrypt/live/(ドメイン名)/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/(ドメイン名)/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

# 本番環境で更新
テスト環境でできることを確認したら「--dry-run」を消して本番で実行します。

```
sudo certbot renew
```
同じくsuccessと出ていたら成功です！
```
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/(ドメイン名).conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator apache, Installer apache
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Renewing an existing certificate for (ドメイン名)
Performing the following challenges:
http-01 challenge for (ドメイン名)
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of apache server; fullchain is
/etc/letsencrypt/live/(ドメイン名)/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded: 
  /etc/letsencrypt/live/(ドメイン名)/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

# Apacheの再起動
最初に一旦停止したApacheを再起動します。
```
apachectl restart
```
# ブラウザでアクセスしてできるかどうか確認
ブラウザでアプリケーションにアクセスしてhttpsになっていればOK。

# 最後に
私もまだ初心者でわからない部分も多くあります。
お気づきの点があれば教えていただければ幸いです！

以下のサイトを参考にしました。
https://it-jog.com/khow/serv/renewletsencrypt
EMANの量子力学 - memo

## EMAN（広江　克彦）さんのホームページの個人的な補足
https://eman-physics.net/quantum/contents.html

### 第２部「行列形式をマスターしよう」
#### 座標表示
導入部分の波動関数をデルタ関数を含む形での導入は以下のページの3節を参照するとわかりやすい
https://whyitsso.net/physics/quantum_mechanics/quantum8.html