OmniAICreator/Qiita-1.07M huggingface dataset:
AmazonLinux2023でcaddyインストール

# 概要

AmazonLinux 2023でEPEL repo が利用できず、caddyのインストールはマニュアルインストールしか手段が見当たらなかったので、その作業メモです

# 対象者

- ルール上でAny許可できるtcpポートがhttp/https等に限られている。わざわざALB用意したくない
- httpsには対応したい。だけど証明書の用意は面倒
- caddyで証明書付きのリバプロ構築しようとしたが、AmazonLinux2023でEPEL利用できず、つまづいた

# 対応手順

caddyを手動でインストールし、内部証明書を使ってhttps対応のリバースプロキシロを起動します。

## バイナリをダウンロード

```shell
curl -OL https://github.com/caddyserver/caddy/releases/download/v2.6.4/caddy_2.6.4_linux_amd64.tar.gz
tar -xvf caddy_2.6.4_linux_amd64.tar.gz caddy
sudo mv caddy /usr/bin/

# 実行可能であることを確認
caddy version
```

他のバージョン利用時はこちらから
https://github.com/caddyserver/caddy/releases

## 設定追加

caddy用のディレクトリおよび設定ファイルを配置

```shell
sudo mkdir -p /etc/caddy/conf.d

# 設定追加
cat <<EOF | sudo tee /etc/caddy/Caddyfile
http:// {
    redir https://{host}{uri}
}

import conf.d/*.conf
EOF

```

http → https のリダイレクトおよびimport設定追加
利用アプリケーション向けのリバプロ設定を追加  (ドメイン指定時はDNS登録もしくは名前解決可能であること)
※設定は利用環境にあわせて行ってください
  細かな設定方法は本記事では割愛します

`/etc/caddy/Caddyfile`

```shell
http:// {
    redir https://{host}{uri}
}

import conf.d/*.conf
```

`/etc/caddy/conf.d/myapp.conf`

```shell
vault.sample.net localhost 127.0.0.1 {
    tls internal
    reverse_proxy https://127.0.0.1:8200 {
        health_uri /v1/sys/health
        health_timeout 10s
        health_status 2xx
        transport http {
            tls_insecure_skip_verify
        }
    }
}
```

## systemd で起動設定

起動に使用するユーザー、グループ追加

```shell
sudo groupadd --system caddy

sudo useradd --system \
    --gid caddy \
    --create-home \
    --home-dir /var/lib/caddy \
    --shell /usr/sbin/nologin \
    --comment "Caddy web server" \
    caddy

```

`/etc/systemd/system/caddy.service` を作成

```shell
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

```

## 起動、動作チェック

```shell
sudo systemctl daemon-reload
sudo systemctl enable caddy
sudo systemctl start caddy

# 起動状況を確認
ss -lnt

# https 応答チェック
curl -k https://vault.sample.net/v1/sys/health

# httpが適切にリダイレクトされることを確認
curl -k http://vault.sample.net/v1/sys/health
curl --head http://vault.sample.net/v1/sys/health
curl -k -L http://vault.sample.net/v1/sys/health

```

# 最後に

マニュアルインストールの内容はほぼ公式ドキュメントのコピーです。
もし今後AmazonLinux2023用のインストール手順が追加されたら、そちらを参照してください。

# Link

https://caddyserver.com/docs/running
https://github.com/caddyserver/
WSL2に割り当てられるメモリ量について(反省)

# 1.この記事の内容

この記事では，WSL2に割り当てられるメモリ量とパソコンに搭載しているメモリ量がデフォルトで異なることを失念していたことに対する筆者の反省です．

本記事を執筆時点の下記バージョンでは，パソコンに搭載しているメモリ量の半分がWSL2に割り当てられるようです．

```
エディション	Windows 11 Home
バージョン	22H2
インストール日	‎2022/‎05/‎15
OS ビルド	22631.1972
エクスペリエンス	Windows Feature Experience Pack 1000.22658.1000.0
```

# 2.背景

WSL2上でJupyter NotebookをDockerで動かしている際に，大きなサイズのデータ処理をしていると，Jupyter Notebookが頻繁にクラッシュしました．
タスクマネージャーでメモリ使用量を見ても70%～80%程度しか使用していない状況でこの現象が発生し，ハマっていたのですが，WSL2に割り当てられたメモリ量をオーバーしていました．

# 3.反省と対策

ちゃんとDockerコンテナが使用しているメモリ量を計測せねばならないという反省をふまえ，``docker stats``で使用中のメモリ量をログに残す対策を丁寧にやろうと思います．

```bash
#! /bin/bash

while true; do
        docker stats --no-stream | tee --append docker_stats.log
        sleep 1
done
```

``docker stats``でデフォルトでは下記のように，1行目に項目名，2行目以降で動かしているDockerコンテナのプロファイルが出力されます．

```
$ docker stats --no-stream
CONTAINER ID   NAME                                 CPU %     MEM USAGE / LIMIT     MEM %     NET I/O         BLOCK I/O   PIDS
e477720561df   20230708_sake_name_searching_env_1   18.40%    4.562GiB / 15.55GiB   29.33%    146MB / 172MB   0B / 0B     71
```

``--format``オプションで出力形式を指定することができ，例えばコンマ区切りで出力するとcsv形式でログを残すことができます．

```
$ docker stats --no-stream --format "{{.Name}}, {{.MemUsage}}"
20230708_sake_name_searching_env_1, 4.582GiB / 15.55GiB
```

出力形式を指定する際にも，先頭に``table``指定をすることで，1行目に項目名を出力することもできます．

```
$ docker stats --no-stream --format "table{{.Name}}, {{.MemUsage}}"
NAME, MEM USAGE / LIMIT
20230708_sake_name_searching_env_1, 4.587GiB / 15.55GiB
```

# 4.関連リンク

- docker statsについて
　　- [docker stats](https://docs.docker.jp/engine/reference/commandline/stats.html)
  　　- [フォーマット（表示形式）](https://docs.docker.jp/engine/reference/commandline/stats.html#docker-stats-formatting)
- WSL2でのメモリ割り当てサイズについて
  - [Docker Desktop 環境のメモリ上限を変更するには？](https://nosubject.io/docker-desktop-memory-allocation-config/)
    ```
    Docker Desktop は WSL2 のメモリ制限に影響を受けます。
    Windows10のデフォルトだと WSL2 に割り当てられるメモリは ホスト側のメモリの80%となるようです。
    ```
  - [Windows Subsystem for Linux 2のメモリ管理を詳しく見る](https://ascii.jp/elem/000/001/981/1981180/)
    ```
    デフォルトでは、PC側のメモリの75％をWSL2の上限として割り当てているようだ。
    たとえば、物理メモリ4GBのマシンならば3GBが、8GBのマシンなら6GBが実装メモリとしてWSL2内からは見えている。
    ```
  - [WSL2 に割り当てるメモリサイズを手動で固定値を設定する方法](https://snowsystem.net/other/windows/wsl2-fixed-memory-allocation/)
    ```
    Microsoft のリリースノートのビルド 20175に以下の記載があります。
    WSL2 VM の既定のメモリ割り当てを、ホスト メモリの 50% または 8 GB のどちらか少ない方になるように調整します
    ```
  - [WSL2/Ubuntu/Raspberry Piでのメモリ不足を解消する](https://zenn.dev/karaage0703/articles/d38e17bd6efbaa)
    ```
    WSL2では、デフォルトだとメインメモリの半分しかメモリが割り当てられません。
    ```
「localhost」と「127.0.0.1」をわかりやすく説明します

## 「localhost」が初心者にとって便利な理由

まずは例を挙げて説明しましょう：
> サーバーアプリケーションを作成する際、まだリモートサーバーが実行されていない場合、自分自身のサーバーアプリをテストする方法について考えるかもしれません。「サーバーアプリをテストするにはどうすればいいのか？」という疑問が生じる瞬間です。そこで、「`localhost`」が登場します。なぜなら、アプリをテストするためにリモートサーバーは必要なく、自分自身のデバイスへのリクエストを送信できるからです。

## 「localhost」はどのように機能するのか？

ウェブサイトを呼び出そうとすると、コンピューターはインターネット上のリモートコンピューター（サーバーとも呼ばれる）に接続しようとします。リクエストを送信し、その結果としていくつかのコンテンツを受け取ります。

一方、「`localhost`」（または「127.0.0.1」）を呼び出すと、自分自身のデバイスにリクエストを送信します。コンピューターはアドレス（「localhost」または「127.0.0.1」）を認識し、インターネット上に送信する代わりに、ループバック機構を通じてリクエストを返します。先ほどのサーバーアプリの例を念頭に置くと、同じマシン上のサーバーはリクエストを受け取り、いくつかのコンテンツを含むレスポンスを送信できます。

リクエストとレスポンスは、コンピューター内部で完結します。言い換えれば、「`localhost`」を呼び出すことで、コンピューターは常に自己と対話しているのです。

## `127.0.0.1`とlocalhostの違い

### IPアドレス表記と特殊IPアドレス

IPアドレスは、ネットワーク番号とホスト番号の2つの部分から構成されています。ネットワーク番号（net-id）は、IPアドレスが所属するネットワーク番号を示し、ホスト番号（host-id）は、IPアドレスが所属するネットワーク内のホスト番号を示します。

`
IPアドレス ::=  { <ネットワーク番号>, <ホスト番号> }
`

特殊IPアドレスは特定の用途に使用されます。RFC1700で以下の特殊IPアドレスが定義されています。

1. {0,0}：ネットワーク番号とホスト番号がともに0であり、「このネットワークのこのホスト」という意味であり、ソースアドレスとしてのみ使用できます。

2. {127,}：ネットワーク番号が127であるIPアドレスのことです。これらはすべて内部ホストループバックアドレス（ループバック）であり、ホストの外部のネットワークでは決して現れません。

## 質問への回答

「127.0.0.1」と比較して、「localhost」はより意味を持っています。**「localhost」はドメイン名であり、IPアドレスではありません。** 大抵の場合、

私たちが使用するコンピューターでは「localhost」がアドレス「127.0.0.1」を指すとされています。Ubuntuシステムでは、`/etc/hosts`ファイルに以下の内容が含まれています：

```
127.0.0.1   localhost
```

ただし、ホストファイルを設定すると、「localhost」を異なるIPアドレスに関連付けることも容易です。なぜなら、このファイルにはIPアドレスとホスト名の対応関係が含まれているからです。

## 少しだけBINDについて説明します

### ネットワーキング
ネットワーキングとは、複数のコンピューターやデバイスを接続してネットワークを作成することを指します。これにより、これらのデバイス間での通信やデータ交換が可能となり、リソースや情報の共有が行えます。ネットワークは、地理的な範囲に応じて、ローカルエリアネットワーク（LAN）や広域ネットワーク（WAN）などの異なるタイプに分類されます。

コンピューターネットワークでは、IP（インターネットプロトコル）アドレスと呼ばれる固有のアドレスでデバイスが識別されます。IPアドレスは、IPv4（例：`192.168.0.1`）またはIPv6（例：`2001:0db8:85a3:0000:0000:8a2e:0370:7334`）の形式で表されることがあります。

### Bind（Berkeley Internet Name Domain）
BINDは、インターネット上で最も広く使用されているDNS（Domain Name System）ソフトウェアです。DNSは、ドメイン名（例：example.com）をコンピューターが理解できるIPアドレスに変換します。これにより、複雑なIPアドレスではなく、覚えやすいドメイン名を使用してウェブサイトにアクセスしたり、メールを送信したり、さまざまなインターネット関連の活動を行うことができます。

BINDには、DNSサーバー（named）とDNSリゾルバ（named-resolver）の2つの主要なコンポーネントがあります。DNSサーバーはドメイン名のクエリを処理し、権威ある回答を提供します。一方、リゾルバはクライアントからのクエリを処理し、ドメイン名の解決に関してDNSサーバーと対話します。

`named.conf`などの設定ファイルは、BINDの動作方法を指定するために使用されます。これらのファイルには、DNSサーバーの動作を制御するさまざまなディレクティブとオプションが含まれています。これには、以前に言及した「listen-on」ディレクティブも含まれます。

### 「listen-on」ディレクティブ
BINDの`named.conf`ファイルにおける「listen-on」ディレクティブは、DNSサーバーが受信クエリを待ち受けるためのIPアドレスとポート番号を指定します。デフォルトでは、BINDはループバックアドレス（127.0.0.1）のポート53で待ち受けるように制限されており、つまりローカルマシンからのクエリのみを受け付けます。

「listen-on」ディレクティブで「127.0.0.1」を「localhost」に置き換えると、BINDはそれをループバックアドレスと解釈し、外部からのクエリを許可するようになります。この動作は、ほとんどのシステムで「localhost

」が通常ループバックアドレスに解決されるためです。

BINDの動作は、バージョンや設定、プラットフォーム固有の設定によって異なる場合がありますので、複雑なBINDの設定を扱う際には、常にBINDの公式ドキュメントを参照するか、経験豊富な管理者の支援を求めることをおすすめします。
RustでAtCoderに取り組むときのメモ

RustでAtCoderに取り組むときにつまづいたところやメモなどを随時追記していきます。現行verのRust（執筆時1.71）ではOKですが、AtCoderのver1.42ではコンパイルエラーになる記法などもあります。

## input

```rs
    let input = || -> String {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).unwrap();
        s.trim_end().to_string()
    };
    
    // usage
    let n = input().parse::<u32>().unwrap(); 
```

## u32, i32, u64, i64のmax

```rs
pub const MAX: u32 = u32::MAX; // 4_294_967_295u32
pub const MAX: i32 = i32::MAX; // 2_147_483_647i32
pub const MAX: u64 = u64::MAX; // 18_446_744_073_709_551_615u64
pub const MAX: i64 = i64::MAX; // 9_223_372_036_854_775_807i64
```

## HashSetについて

`collect::<HashSet<String>>()`がコンパイルエラーになる。

```rs
    // CE
    let n = input().parse::<u32>().unwrap();
    let ｓ = (0..n)
        .map(|_| input().to_string())
        .collect::<HashSet<String>>();
```

上記はコンパイルエラー。下記ならOK

```rs
    let n = input().parse::<u32>().unwrap();
    let mut s = HashSet::new();
    (0..n).map(|_| input().to_string()).for_each(|a| {
        s.insert(a);
    });
```

## for .. in はイテレータにする

```rs
// CE
for t in ["dream", "dreamer", "erase", "eraser"] {
```

はコンパイルエラー

```rs
for t in ["dream", "dreamer", "erase", "eraser"].iter() {
```

こうする
docker メモ用紙

# Containerの削除　rm
```terminal
docker rm test -fv

docker build -t test . 

docker run 
    -d 
    -v ${pwd}:/usr/src/app 
    -v data:/usr/src/app/node_modules 
    --name test 
    -p 3000:4000 
    --env-file ./.env 
    test
```
# Dockerfile
```Dockerfile:Dockerfile
    FROM node:alpine3.18
    
    WORKDIR /usr/src/app
    
    COPY package.json .
    
    RUN npm install
    
    COPY . ./
    
    ENV PORT=3000
    
    EXPOSE ${PORT}
    
    CMD [ "npm", "run", "dev" ]

```
任意のSalesforceアプリケーションをブラウザで開くワンライナー

`sf org open`で`target-org`に設定されてる組織をブラウザで開ける。でも設定画面が開くので、毎回開発中のアプリをランチャーから選択して開き直さないといけいけない。できれば直接アプリを開きたい。

試行錯誤したところこんな感じでできた。

```
sf org open --path=/lightning/app/$(sf data query --query "SELECT DurableId FROM AppDefinition WHERE DeveloperName = 'アプリのAPI参照名'" --json | jq -jr ".result.records[].DurableId")
```

# 解説

`sf org open`の`--path`オプションでSalesforceの任意のページを開ける。
例えばリードの一覧画面ならこう:

```
sf org open --path=/lightning/o/Lead/list
```

`--path`オプションでSalesforceアプリケーションのパスを指定できればアプリを開ける。
しかしSalesforceアプリケーションは特定のURLを持たないっぽい。
なのでランチャーのリンクからパスを取り出す。手元のスクラッチ組織でセールスアプリのリンク先はこうなっていた。

```
https://app-app-881-dev-ed.scratch.lightning.force.com/lightning/app/06m1y000000UWNUAA4
```

このURLのパス部分を`--path`に渡すとセールスアプリがブラウザで開く。

```
sf org open --path=/lightning/app/06m1y000000UWNUAA4
```

このパスのIDのところを任意のアプリのものに変更すれば任意のアプリをブラウザで開くことができるはず。
このIDは、このヘルプからリンクされてる、

https://help.salesforce.com/s/articleView?id=000385203&type=1

このページによると、

http://www.fishofprey.com/2011/09/obscure-salesforce-object-key-prefixes.html

`06m`で始まるIDは`AppDefinition`オブジェクトのIDとのこと。
SOQLで叩いてみる。

```
$ sf data query --query "SELECT FIELDS(ALL) FROM AppDefinition LIMIT 1" --json
{
  "status": 0,
  "result": {
    "records": [
      {
        "attributes": {
          "type": "AppDefinition",
          "url": "/services/data/v58.0/sobjects/AppDefinition/06m1y000000UWNBAA4"
        },
        "Id": "000000000000000AAA",
        "DurableId": "06m1y000000UWNBAA4",
        "Label": "セールス",
        "MasterLabel": "salesforce",
        "NamespacePrefix": "standard",
        "DeveloperName": "Sales",
        "LogoUrl": "/img/salesforce-noname-logo-v2.svg",
        "Description": "世界で最も高い評価を受けた営業支援ソリューション",
        "UiType": "Aloha",
        "NavType": "Standard",
        "UtilityBar": null,
        "HeaderColor": "#0070D2",
        "IsOverrideOrgTheme": false,
        "IsSmallFormFactorSupported": false,
        "IsMediumFormFactorSupported": false,
        "IsLargeFormFactorSupported": false,
        "IsNavPersonalizationDisabled": false,
        "IsNavAutoTempTabsDisabled": false,
        "IsNavTabPersistenceDisabled": false
      }
    ],
    "totalSize": 1,
    "done": true
  },
  "warnings": []
}
```

取得できた。`DurableId`に先ほどのIDと似たものが見える。

`AppDefinition`オブジェクトを確認すると`DurableId`は「アプリケーションの一意の仮想 Salesforce ID」らしい。

[AppDefinition | Salesforce プラットフォームのオブジェクトリファレンス | Salesforce Developers](https://developer.salesforce.com/docs/atlas.ja-jp.object_reference.meta/object_reference/sforce_api_objects_appdefinition.htm)

`DeveloperName`がAPI参照名で一意になってそうなので、その辺りを踏まえてワンライナーにする。

```
sf org open --path=/lightning/app/$(sf data query --query "SELECT DurableId FROM AppDefinition WHERE DeveloperName = 'アプリのAPI参照名'" --json | jq -jr ".result.records[].DurableId")
```

これでできた。
Livebook で Erlang

## はじめに

2023/7/14 Livebook 0.10.0 がリリースされました

https://livebook.dev/

0.10.0 から Livebook で Erlang が実行できるようになりました

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/erlang.livemd

## Erlang セルの追加

今まで、新しいセルを追加するボタンの左端は "+ Code" でしたが、そこが "+ Elixir" になっており、しかもドロップダウンが出るようになっています

ドロップダウンを開くと "Elixir" と "Erlang" になっていて、 "Erlang" を選ぶことで Erlang コード実行用のセルが追加できます

![スクリーンショット 2023-07-16 19.14.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/3f84e084-a243-8f24-4651-3bf04ff831c4.png)

追加された Erlang セルは右上に Erlang のアイコンが追加されます

![スクリーンショット 2023-07-16 19.25.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/82306499-94bd-ca0c-8467-7da3845153ef.png)

## Erlang の実行

例えば、以下のコードを実行してみましょう

`,` で式を区切り、 `.` で式を終わらせるこの書き方は、 Elixir の文法とは全く異なります

```erlang
Taro = 1,
Jiro = 2.
```

![スクリーンショット 2023-07-16 19.42.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/10b800d1-6870-6600-271c-42979d5e4990.png)

実行できました

当然、このコードを Elixir セルで実行するとエラーになります

![スクリーンショット 2023-07-16 19.43.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/6813aae5-c872-0914-7d64-70ac591dc87d.png)

Erlang 関数の定義と実行ももちろん可能です

```erlang
Add = fun(A, B) -> A + B end,

Add(Taro, Jiro).
```

![スクリーンショット 2023-07-16 19.43.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/170aee1a-1d6d-79f0-8963-572311295c7c.png)

## Elixir から Erlang を参照

Erlang で定義していた変数は Elixir では先頭を小文字にすることで参照可能です

```elixir
taro + jiro
```

関数も先頭を小文字にすることで参照可能です

```elixir
add.(2, 4)
```

## Erlang から Elixir を参照

Elixir で定義した変数は先頭大文字にすることで Erlang から参照可能です

```elixir
list = [1, 2, 3]
```

```erlang
List.
```

![スクリーンショット 2023-07-16 19.38.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/4a7afc73-014b-3f7d-b92f-9a9f3bfc6732.png)

Elixir で定義したモジュールは 'Elixir.<モジュール名>'　で Erlang から参照可能です

```elixir
defmodule Hello do
  def world(), do: "Hello, world."
end
```

```erlang
'Elixir.Hello':world().
```

![スクリーンショット 2023-07-16 19.46.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/e6264f74-d96d-e72c-3a51-074c901a1ff8.png)

## まとめ

Livebook 上で Elixir と Erlang を自由自在に行き来できるようになりました

Erlang はまだ未修得の私ですが、これを機に Livebook で Erlang を学習したいと思います
CentOS7にJDK17をインストール

# 前提
23年ゴールデンウィーク現在、OpenJDKだとJava17はない。
Java11までしか出ていない。

```
yum search openjdk | grep 17
```

ということでOracleJDKを使うことにする。

# 手順
下記からダウンロードモジュールを選択。
https://www.oracle.com/java/technologies/downloads/#java17

CPUアーキテクチャの種類(x86, x64, arm)がわからない場合は下記で確認。

```
uname -m
```

ディレクトリ作成
```
cd /home/user
mkdir java
cd /home/user/java
```

tar.gzをダウンロード。
```
wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz
```

展開。
```
tar xvfz jdk-17_linux-x64_bin.tar.gz
```

環境変数に追加。
```
export PATH=$PATH:/home/user/java/jdk-17.0.7/bin
export JAVA_HOME=/home/vpsuser/java/jdk-17.0.7
echo $PATH
```
※$PATH: を付けずに export PATH=/home/user/java/jdk-17.0.7/binとしてしまうと、他の設定していたパスは失われ、/home/user/java/jdk-17.0.7/binにしかパスが通ってないという状態になってしまいます。

確認。
```
java -version
```

ただし、これだと、パスはログインしている間のみ有効で、一度ログアウトすると設定は失われてしまう。
永続的に設定したい場合は下記。

ユーザー単位で設定する場合は、
```
export PATH=$PATH:/home/user/java/jdk-17.0.7/bin
```
をホームディレクトリ配下の.bash_profile の最終行に追記。

※全ユーザ単位で設定する場合は、
```
export PATH=$PATH:/home/user/java/jdk-17.0.7/bin
```
を/etc/profileに追記すればいい模様。今回はユーザ単位での設定で良いため、.bash_profileに追記。

PATHを確認する。
```
echo $PATH
java -version
```
※コマンドプロンプトと違い、コンソールの再起動は必要ない。
Livebook で Live Doctests

## はじめに

2023/7/14 Livebook 0.10.0 がリリースされました

https://livebook.dev/

以前のバージョンでも Livebook 上で doctest を実行可能でした
（以前の記事参照）

https://qiita.com/RyoWakabayashi/items/5dfbec49ed456c579474

0.10.0 からは Live Doctests として、より見やすく結果が表示されるようになりました

実装したノートブックはこちら

https://github.com/RyoWakabayashi/elixir-learning/blob/main/livebooks/doctests.livemd

## テストが成功するケース

Livebook のセルで以下のコードを実行してみましょう

`"""` で囲まれたモジュールドキュメントのうち、 `## Examples` 以降が doctest です

`iex>` の行に関数の実行例、その次の行に想定される実行結果を書いています

```elixir
defmodule OKTest do
  @doc """
  Add two numbers

  ## Parameters

    - a: a number
    - b: a number

  ## Examples

  iex> OKTest.add(1, 1)
  2

  iex> OKTest.add(1.1, 2)
  3.1

  iex> OKTest.add("1", 2)
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  @spec add(number(), number()) :: number()
  def add(a, b) do
    a + b
  end
end
```

実行すると、以下のような表示になります

![スクリーンショット 2023-07-16 18.45.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/0b6d6130-f6ee-6aa6-a157-3e9372b49097.png)

doctest 各行の左に緑色の四角形が表示され、テストが成功したことを示しています

以前はセルの下に `3 doctests, 0 failures` という文字列で結果を表示していましたが、より直観的に表示されるようになりました

## テストが失敗するケース

以下のように、テストが失敗するコードを実行してみます

```elixir
defmodule NGTest do
  @doc """
  Add two numbers

  ## Parameters

    - a: a number
    - b: a number

  ## Examples

  iex> NGTest.add(1, 1)
  3

  iex> NGTest.add(1.1, 2)
  3.3

  iex> NGTest.add("1", 2)
  ** (RuntimeError) error!!
  """
  @spec add(number(), number()) :: number()
  def add(a, b) do
    a + b
  end
end
```

実行結果は以下のようになります

![スクリーンショット 2023-07-16 18.50.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/1d1d9175-6853-bc72-ba38-0dafff9d6d48.png)

失敗した doctest の左に赤い四角形が表示され、 `expected:` に想定していた値、 `got:` に実際の出力値が表示されます

例外の場合は全体的に赤い文字で想定と異なっていた旨の文章が表示されます

また、セルの下にも `3 out of 3 doctests failed (failures have been reported above)` と赤く表示されます

どのテストがどう失敗したのか、非常に分かりやすくなりました

## 成功と失敗が混じっているケース

2番目だけテストが失敗するケースです

```elixir
defmodule MixedTest do
  @doc """
  Add two numbers

  ## Parameters

    - a: a number
    - b: a number

  ## Examples

  iex> MixedTest.add(1, 1)
  2

  iex> MixedTest.add(1.1, 2)
  3.3

  iex> MixedTest.add("1", 2)
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  @spec add(number(), number()) :: number()
  def add(a, b) do
    a + b
  end
end
```

![スクリーンショット 2023-07-16 18.56.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1485835/dd5d1e00-dee7-e63e-eb56-75e2da43a92b.png)

2番目だけ失敗し、しかも出力結果のどこが違っているか、非常に分かりやすいですね

## まとめ

テストの実行結果が Livebook の UI/UX に統合され、正に Live Doctests になりました

モジュールの開発を Livebook で行うときにかなり生産性が上がりそうです
Ruby 配列 ブロックについて 3

# はじめに
- Rubyの配列やブロックの復習用（3回目）
- 学習したことの備忘録
- 「[Ruby 配列 ブロックについて 2](https://qiita.com/takayuki91/items/ad9098a258c7927e1f98)」の続き

# 学習内容
#### ブロック
- with_indexメソッド
- each_with_indexメソッド

# 参考にした教材
- [プロを目指す人のためのRuby入門]( https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERuby%E5%85%A5%E9%96%80-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E6%8A%80%E6%B3%95%E3%81%BE%E3%81%A7-Software-Design-plus%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA/dp/4774193976)
- [Ruby リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/doc/index.html)

# ブロック
```rb
foods = ["ラーメン", "ギョウザ", "チャーハン"]
```

<details><summary>変数foodsをmap処理しつつ、0〜2の番号を与える</summary>

`with_indexメソッド` 生成時のパラメータに従って、要素にインデックスを添えて繰り返す
```rb:例
puts foods.map.with_index{ |food, f| "#{f}: #{food}" } => 0: ラーメン
1: ギョウザ
2: チャーハン
```
</details>

<details><summary>変数foodsから「メン」を含み、偶数である要素を取り除く</summary>

`with_indexメソッド` 生成時のパラメータに従って、要素にインデックスを添えて繰り返す
```rb:例
puts foods.delete_if.with_index{ |food, f| food.include?("メン") && f.even? } => ギョウザ, チャーハン
```
</details>

<details><summary>変数foodsの各要素に0〜2の番号を与える</summary>

`each_with_indexメソッド` 要素とそのインデックスをブロックに渡して繰り返す
```rb:例
puts foods.each_with_index { |food, f| puts "#{f}: #{food}" } => 0: ラーメン
1: ギョウザ
2: チャーハン
```
</details>

>補足
どちらもデータを１つずつ取り出すことはできるが、位置情報を使いたい場合は「with_index」を使うべき。実際に、「each_with_index」では、
>```ruby
>foods.each_with_index(1) { |food, f| puts "#{f}: >#{food}" }
>
>=> ArgumentError
>```
>となり、任意の位置情報を与えられない。
一方で、「with_index」なら、
>```rb
>foods.each.with_index(1) { |food, f| puts "#{f}: #{food}" }
>
>=> 1: ラーメン 2: ギョウザ 3: チャーハン
>```
>と位置情報も与えられる。

# まとめ
- with_indexは任意の位置情報を与えられる
- ブロックパラメータの第2引数も上手く使っていきたい

⚠️学習4ヶ月目の初学者による投稿です。
⚠️間違いがあるかもしれません。ご容赦ください。
⚠️ご指導、ご教授いただけると幸いです。
SSH鍵の取り扱い.txt

間違っている点等ありましたら編集リクエストやコメントで教えてください。
~~~
=====SSH鍵の取り扱いについて=====
1. (ファイル名)
秘密鍵。誰にも見られないように安全なローカル環境にて保管。
持ち出し厳禁のUSBメモリに入れて保管するなども効果的。

主な用途
・SSH接続
・暗号化されたデータの復号
・データに電子署名

2.(ファイル名).pub
公開鍵。公開してもOK。
公開鍵暗号方式にてSSH接続する接続先に登録しておく。

主な用途
・接続先のサーバーに登録
~~~
【LINE API】LINEミニアプリとLIFFアプリの違い

## はじめに

### この記事で書くこと
LINEが提供するウェブアプリのプラットフォームである、LIFFアプリとLINEミニアプリで出来ることの違いを書きます。

### 参考文献

この記事は以下の情報を参考にして執筆しました。
https://developers.line.biz/ja/docs/


## LIFFアプリとは

[LIFF公式ドキュメント](https://developers.line.biz/ja/docs/liff/overview/)で以下のように説明されています。
>LINE Front-end Framework（LIFF）は、LINEが提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。

>LIFFアプリを使うと、LINEのユーザーIDなどをLINEプラットフォームから取得できます。LIFFアプリではこれらを利用して、ユーザー情報を活用した機能を提供したり、ユーザーの代わりにメッセージを送信したりできます。

LIFFアプリを使う**メリット**としては、

- 複雑な認証、認可を自分で実装することなく、LINEのプラットフォームからユーザのプロフィール情報を安全に取得でき、他の情報との紐づけなど開発で役立つ
- LIFFに用意されている[**シェアターゲットピッカー**](https://developers.line.biz/ja/docs/liff/developing-liff-apps/#share-target-picker)を利用することで、選択したグループまたは友だちにシェアすることを促せる
- ユーザがLIFFにアクセスした際に、[ボットリンク](https://developers.line.biz/ja/docs/line-login/link-a-bot/#redirect-users)という機能を使うことで友達登録フローを自然に促せる為、**友達追加してもらえる可能性が高くなる**
- LINE内だけでなくWebブラウザにも対応している




などがあります。

## LINEミニアプリとは

[LINEミニアプリ公式ドキュメント](https://developers.line.biz/ja/docs/liff/overview/)で以下のように説明されています。

>LINEミニアプリは、LIFF（LINE Front-end Framework）上で実行されるウェブアプリです。LINEミニアプリを使えば、ユーザーはアプリをインストールしなくてもサービスを利用できます。

LINEミニアプリを使うメリットとしては、

- 動作するブラウザ以外はLIFFのメリットとして上げた部分はすべて含んでいる（※ミニアプリはスマートフォン版LINEのみの動作）
- LINEのホーム画面からの導線が作れる、iOS端末であればiphoneのレコメンドにも表示される
- [サービスメッセージ](https://developers.line.biz/ja/docs/line-mini-app/develop/service-messages/#page-title)という無料で送信できるメッセージの配信ができる（LINE公式アカウントを友だち追加していなくてもメッセージを送信できる）
※販促を促す等の目的でのメッセージ送信は禁止されており、ユーザがミニアプリで操作したアクションに対する、確認や応答としてのみ送信できる（[※詳細 サービスメッセージの条件](https://developers.line.biz/ja/docs/line-mini-app/service/service-operation/#conditions-for-service-messages)）

などがあります。



LIFFとの違いで、
- **リリース審査がある**

という違いがある為、ミニアプリとして作成する場合は審査を通す必要があることを前提に開発を進める必要があります。
（[※審査の確認事項](https://developers.line.biz/ja/docs/line-mini-app/submit/submission-guide/)）




## LINEミニアプリとLIFFの違い

|  | LIFF | LINEミニアプリ |
|:-----------:|:------------:|:------------:|
| 審査       | なし        | あり         |
| 動作環境     | LINEアプリ（スマホ）<br> 外部ブラウザ（PC・スマホ）      |    LINEアプリ（スマホ）    |
| サービスメッセージ       | なし        | あり         |
| LINEホーム画面から開く<br>iphoneのレコメンドに表示         | なし          | あり           |
| ボットリンク       | あり     | あり      |

## 結論
ミニアプリでしかできない事がやりたくなったら、ミニアプリで作成する方向で考える。
それ以外はLIFFでスピーディーに開発をする。
VSCode 使用時 TypeScript ファイルのみ formatOnSave(Prettier) が効かないとき【自分用】【NestJS】

# 結論

TypeScriptのdefaultFormatterを明示的に指定したら解決した｡

```json:settings.json
{
  "prettier.prettierPath": "./node_modules/prettier",
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}
```

# 状況

OS: `WSL (Ubuntu-20.04)`
NestJS: `10.1.8`

NestJSで遊んでいるときVSCodeの`>Format Document`が機能しなくなった｡  

右下にはこんなマーク↓とエラーが｡

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/643955/d967694d-13a7-f3bb-ba05-10068a0f925a.png)

```text:VSCodeの出力 > Prettier
["INFO" - 6:10:13 PM] Attempted to load Prettier module from /home/me/.config/yarn/global/node_modules/prettier
["ERROR" - 6:10:13 PM] Failed to load module. If you have prettier or plugins referenced in package.json, ensure you have run `npm install`
["ERROR" - 6:10:13 PM] Cannot load Prettier version from package.json
Error: Cannot load Prettier version from package.json
	at t.ModuleResolver.loadPrettierVersionFromPackageJson (/home/me/.vscode-server/extensions/esbenp.prettier-vscode-9.19.0/dist/extension.js:1:4185)
```

作業フォルダ外のprettierを見に行っているようなので､ワークスペースの設定に

```json:settings.json
{
  "prettier.prettierPath": "./node_modules/prettier"
}
```
を追加｡  
JSONファイルのフォーマットが効くようになったのは確認できたが､
TypeScriptファイルのみまだフォーマットされないようだった｡(エラーの表示は消えている｡)

いろいろ試してみた結果､  

```json:settings.json
{
  "prettier.prettierPath": "./node_modules/prettier",
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}
```

これで動いてくれた｡良かった｡

# おわり
 
- 原因の解決ではないけど一応メモ｡
    - デフォルトですべてのファイルがフォーマット対象になるわけでは無いのかな

- あんまり関係ないけどVSCodeの`settings.json`を`setting.json`って書いてしまったときに軽いアラート出してほしい(1敗)
HTML <table> について（表の作成）

最近、HTML で`table`を使ったので、備忘録として書いておきます。

## element

`table` ... テーブル
`theader` ... テーブルヘッダー（無くても、成立する）
`tbody` ... テーブルボディ（無くても、成立する）
`tr` ... 行ごとの括り
`td` ... セル

## 例

以下が、コードと生成されるテーブルです。

<p class="codepen" data-height="400" data-default-tab="html,result" data-slug-hash="rNQdmeY" data-user="J-N-the-flexboxer" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/J-N-the-flexboxer/pen/rNQdmeY">
  Untitled</a> by J N (<a href="https://codepen.io/J-N-the-flexboxer">@J-N-the-flexboxer</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## style (css)

`element`に直書きする方法もありますが、`css`の設定で上書きされる場合があるため、基本的には`css`で書く方が望ましいです。

#### ボーダー（線）

`td`,`tr`に対して、`border`で設定することで表示される様になります。
`solid`を付け忘れると、線が表示されないため、注意が必要です。
`border-collapse`で`collapse`を設定した場合は、セル同士のボーダーが一体化した状態での表示になりますが、`separate`で設定すると、セルごとにボーダーが独立した状態で表示されます。

```css
td {
  /* 線の太さ、色、線の種類 */
  border: 3px #000000 solid;
}

table {
    /* 線をくっつける場合の設定 */
    border-collapse: collapse;

    /* 線を離す */
    border-collapse: separate;
}
```
authorization, AuthZ(認可)とauthentication, AuthN(認証)の自分用覚え方メモ



## はじめに

よく間違えるので、覚え方をメモしておく


## 結論

- `author` が権威、`認可` を与えるので `authorization`
- （対象に対して）本物にする = `認証`する `authentication`

## authorization

author -> authorize -> authorization

それぞれの語源を見てみる

### author

https://www.etymonline.com/word/author


和訳すると

> author(著者)の語源は古フランス語の auctor, acteor 「作者、発案者、創造者、扇動者」 (現代フランス語のauteur）
> 、ラテン語のauctor「推進者、生産者、父、始祖、建設者、創設者、信頼できる作家、権威者、歴史家、実行者、責任者、教師」から直接派生したもの

### authorize

https://www.etymonline.com/word/authorize

和訳すると

> 古フランス語の autoriser, auctoriser 「権威を与える」と、中世ラテン語の auctor に由来する auctorizare から直接派生した。

### authorization

https://www.etymonline.com/word/authorization

和訳すると

> 1600年頃、authorize から派生した動作名詞

### 覚え方

https://gogen-ejd.info/authorize/

著者が権威、`認可` を与える
システムの作者が認可を与えると考えるとわかりやすい気がする。

## authenticate

authentic -> authenticate

### authentic

https://www.etymonline.com/word/authentic

> mid-14c., autentik, "authoritative, duly authorized" (a sense now obsolete), from Old French autentique "authentic; canonical" (13c., Modern French authentique) and directly from Medieval Latin authenticus, from Greek authentikos "original, genuine, principal," from authentes "one acting on one's own authority,
> (省略)
> Traditionally in modern use, authentic implies that the contents of the thing in question correspond to the facts and are not fictitious (hence "trustworthy, reliable")

和訳すると

> 14世紀半ば、autentik「権威のある、正当に認可された」（現在は死語）、古フランス語autentique「正統な、正典的な」（13世紀、現代フランス語authentique）、および中世ラテン語authenticusから直接、ギリシャ語authentikos「オリジナルの、本物の、主要な」、authentes「自分の権限で行動する者」から
> (省略)
> 伝統的に現代では、authenticは、その内容が事実と一致し、架空のものではないことを意味する（それゆえ「信頼できる、信頼できる」）

`authentic` には 正真正銘の、本物の　と言う意味があるらしい

### authenticate

> "verify, establish the credibility of," 1650s, from Medieval Latin authenticatus, past participle of authenticare, from Late Latin authenticus (see authentic). Also "render authentic" (1650s). Related: Authenticated; authenticating.

和訳すると

> 「1650年代、中世ラテン語authenticatus、authenticareの過去分詞、後期ラテン語authenticus（authenticを参照）に由来する。また、「本物にする」（1650年代）。関連：認証された; 認証する.

### 覚え方

（対象に対して）本物にする -> 認証する
isset, empty, is_nullの違い微妙だから、書いてみる

イマイチわかってないから、とりあえず書き出してみて理解する
何が違うんだ？
間違ってたら、小学生でもわかるように解説お願いします。

# isset()
変数がセットされていて、それがNULLでないことを調べる
値が入っていればtrueになる、入ってなければfalse

変数がセットされていなかったらって表記したい時もあるから
その時は、！isset()ってつけることもあるみたい。
学習している講座でも使ってたんだけど、私の中ではempty()じゃダメなのか？ってなってる。


# empty()

変数が空かどうかを調べる
空( *空文字、* *０、* *NULL、* *FALSE、* *空の配列* )だったらtureそれ以外はfalseになる。

# is_null()
変数がNULLかどうかを調べる。
変数がNULLだったら、trueそれ以外だとfalseになる
変数がセットされていない場合の時もtrueを返すそうだが
セットされてる、されていないはisset()を使った方がいいんだって


## 表にまとめてみた
| 関数 | 未定義 | NULL | ０ | ””（空文字） | ”abc” |
|:-:|:-:|:-:|:-:|:-:|:-:|
| isset | false | false | true | true | true |
| empty | true | true | true | true | false |
| is_null | ture(Notice) | true | false | false | false |


# 書きながらまとめてたら!isset()の件わかったかも
例えばフォーム作成の際の性別で０か１の判定を行い、男性と女性に設定していたとする。
その際、男性か女性か選択するので、０か１の値がセットされることになる。

```diff_php
<input type="radio" name="gender" value="0"
<?php if(isset($_POST['gender']) && $_POST['gender'] === '0') ; ?>男性
<input type="radio" name="gender" value="1"
<?php if(isset($_POST['gender']) && $_POST['gender'] === '1') ; ?>女性
```


よし、バリデーション機能も追加しよう！となり、empty()を使用するとしよう。
変数が空だったら、trueだがempty()の空には0も含まれている・・・。
そうなってくると男性を選択した場合にエラーが出てしまう問題が発生するわけだ
なるほどなるほど。
だから、値が何もセットされていない場合の!isset()が必要になって来るわけね。

## まとめ
自分の解釈用で、書き出してみたんで
すんごく、わかりづらいかもですがこんな感じで(間違いあったら、指摘お願いします！)
気になった時に投稿していくと思うので、どうぞよろしくです♪
Javaでプログラムの作成手順の動作を確認してみた

# 概要
Javaでプログラムの作成手順の動作を確認してみました。以下のページを参考にしました。

Javaプログラム作成手順

https://www.javadrive.jp/start/before/

Javaを使ったプログラムの作成と保存

https://www.javadrive.jp/start/before/index2.html

プログラムをコンパイルしてクラスファイルを作成する

https://www.javadrive.jp/start/before/index3.html

Javaのプログラムを実行する

https://www.javadrive.jp/start/before/index4.html

# ソースファイルを作成しコンパイルし実行する
以下のファイルを作成しました。
```JSample3_1.java
class JSample3_1{
  public static void main(String[] args){
    System.out.println("Hello");
  }
}
```

以下のコマンドを実行しました。
```
$ javac JSample3_1.java
$ java JSample3_1 
Hello
```

# まとめ
何かの役に立てばと。
Javascriptのメソッドをおさらい

Svelte.jsのチュートリアルをやっていて、
メソッドいっぱい出てくるけど覚えてないやついっぱいあったので再確認。

# 配列メソッド：

push(): 配列の末尾に新しい要素を追加します。
pop(): 配列の末尾の要素を削除し、その要素を返します。
shift(): 配列の最初の要素を削除し、その要素を返します。
unshift(): 配列の最初に新しい要素を追加します。
slice(): 配列の一部を新しい配列として返します。
splice(): 配列から要素を削除または追加します。
map(): 配列の全ての要素に関数を適用し、その結果を新しい配列として返します。
filter(): 配列の全ての要素をテストし、テストをパスした要素から新しい配列を生成します。
reduce(): 配列の全ての要素に関数を適用し、単一の出力値を生成します。

# 文字列メソッド：

split(): 文字列を特定の文字で分割し、その結果を配列として返します。
join(): 配列の全ての要素を連結して新しい文字列を生成します。
slice(): 文字列の一部を新しい文字列として返します。
substring(): 文字列の部分文字列を返します。
charAt(): 指定された位置の文字を返します。
toUpperCase(): 文字列を大文字に変換します。
toLowerCase(): 文字列を小文字に変換します。
trim(): 文字列の前後の空白を削除します。

# 数値メソッド：

toFixed(): 固定小数点表記で数値を表現します。
toPrecision(): 指定した精度で数値を表現します。
toString(): 数値を文字列に変換します。
Math.floor(): 引数として与えられた数以下の最大の整数を返します。
Math.ceil(): 引数として与えられた数以上の最小の整数を返します。
Math.round(): 最も近い整数に四捨五入します。
RStudio に GitHub Copilot がやってくる！

## はじめに

[RStudio](https://ja.wikipedia.org/wiki/RStudio)とは、R言語のためのIDEです。Rを使う時はこれしか考えられないという人も少なくないのではないでしょうか。RStudioは素晴らしいIDEなのですが、GitHub Copilotを使うことができないという大きな弱点がありました。

![RStudioのスクリーンショット](https://upload.wikimedia.org/wikipedia/commons/e/ed/RStudio_IDE_screenshot.png)
画像出典：Wikipedia


[GitHub Copilot](https://ja.wikipedia.org/wiki/GitHub_Copilot)とは、Microsoftが開発しているプログラミングをサポートする人工知能ツールです。VSCodeを使ってプログラミングしている方は、GitHub Copilotを使っていらっしゃる方も多いと思います。

そこで、GitHubのissueに、GitHub Copilotを使いたいという要望を書きました。

https://github.com/rstudio/rstudio/issues/10148

> やあ！
>
> RStudio で Github Copilot を利用できるようにする計画はありますか？
> 
> RStudio は間違いなく素晴らしい開発環境です。 Copilot が利用できないのは残念です。
> 私はここ 1 ～ 2 週間、Ruby 言語で Copilot を使用してきましたが、次の 10 年間は Copilot のような補助なしでプログラミングすることは想像できないと確信しています。

軽い気持ちで書いたのですが、このissueが思わぬ支持を集めました。（私はR言語に詳しい人ではありません。たまにRを起動して、ググりながら電卓のように使う程度の人です）

このたび、RStudioがGitHub Copilotに対応することになったそうなので、最初にissueに要望を書いた人として、RStudioがCopilotに対応したことを宣伝しなければならない責任のようなものを感じ、この記事を書いています。

## RStudio に GitHub Copilot がやってくる

すでにRStudioのデイリービルドではCopilotに対応しています。次のメジャーアップデートで、Copilot対応のRStudioがリリースされるのではないかと期待されます。Copilot対応のRStudioを試してみたい人はこちらからダウンロードしてください。

https://dailies.rstudio.com/

## Copilotのはじめかた

RStudioを起動したら、Tools > Global Options で、設定パネルを開きます。左側の一番下に Copilot という項目があることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/69e42d08-a0ac-f7ef-3651-dd1ae940458f.png)

こちらをクリックしてサイインインしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/45509e57-3d32-3927-8e4f-c6e9b8866047.png)

サイインインに成功すると Coiplot が使えるようになります。補完が正常に動作することを確認してください。

↓こちらの記事は RStudioのCopilotの導入方法がより詳しく説明してあります。

https://zenn.dev/t_koreeda/articles/6beb2d070564d8

RStudioの開発者のみなさま、ありがとうございました。

今後もR言語とRStudioが末永く発展いたしますように！！
DeepL API を使ってHTMLを雑に翻訳する

## 概要

コマンドでwebページ全体をDeepLで翻訳できたらいいな[^detail]

と思っていたら、公式がpythonライブラリ[deepl-python](https://github.com/DeepLcom/deepl-python)を提供していたのでスクリプトを書いてみました。

サンプルスクリプト並みのクオリティですが、そこそこ使えたので共有してみます。

## スクリプト

```python
import deepl
import requests
import sys
from bs4 import BeautifulSoup
from urllib.parse import urljoin


auth_key = 'XXXXXX'


# 変換後も元のリンクを参照できるように、相対から絶対リンクに変換
def convert_relative_to_absolute(html, base_url):
    soup = BeautifulSoup(html, 'html.parser')

    for atag in soup.find_all('a'):
        href = atag.get('href')
        if href and not href.startswith(('http://', 'https://', '#')):
            absolute_url = urljoin(base_url, href)
            atag['href'] = absolute_url

    for link in soup.find_all('link'):
        href = link.get('href')
        if href and not href.startswith(('http://', 'https://')):
            absolute_url = urljoin(base_url, href)
            link['href'] = absolute_url

    for elem in soup.find_all('img'):
        href = elem.get('src')
        if href and not href.startswith(('http://', 'https://')):
            absolute_url = urljoin(base_url, href)
            elem['src'] = absolute_url

    return str(soup)


def translate(html):
    translator = deepl.Translator(auth_key)
    target_lang = 'JA'
    return translator.translate_text(
        html, target_lang=target_lang, tag_handling='html',
        splitting_tags=['pre'],  # codingブロックの翻訳
    )


url = sys.argv[1]

raw_html = requests.get(url).content.decode()
base_url = '/'.join(url.split('/')[:-1])
html = convert_relative_to_absolute(raw_html, base_url)

result = translate(html)

if isinstance(result, deepl.translator.TextResult):
    post_html = result.text
else:
    # 結果が分割されることがあるので結合
    post_html = [r.text for r in result]

print(post_html)

```

auth_key の取得は以下をご参照ください。

https://qiita.com/yaju/items/bf4613393cd4ee402d17#%E6%BA%96%E5%82%99

## できること
1コマンドでwebページ全体を翻訳し、htmlを出力することができます。
```
python html_translator.py https://en.wikipedia.org/wiki/Zen_of_Python > zen_of_python.html
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676735/15876846-87bf-69cd-a1e0-1082133f5729.png)
↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676735/f05c79c9-e91b-5fd4-92cd-37a95a015875.png)


## できないこと
- 長すぎるhtmlの翻訳
    - `413 Request Entity Too Large`となり翻訳できません
- 改行の再現
    - 特にRFC等、改行文字で改行が表現される場合つぶれてしまいます
- 完全なアーカイブ
    - cssや画像は外部を参照しています
- 無料枠リソースの節約
    - html全体を翻訳するので、無料枠である月50万文字を湯水のように消費してしまいます

## さいごに
より高度なことをしたい方はぜひ拡張してみてください！


[^detail]: chrome拡張でも十分だと思います。コマンドにした理由は、自動化しやすいそうというのと、直近でchrome拡張上のログインがうまくできなかったことぐらいです。
ポートフォリオ作成記録始めます

# 狙い・目標
- 目標：Web企業に就職。
- 途中目標: Webプログラミングで在宅バイト出来るようにする
    - ☞このバイトで収入を得る＆ポートフォリオの成果物も追加していく
    - とはいえ最低限の成果物は欲しいので下記の作品をなるべく早く手掛ける＆このポートフォリオ記録も含め作っていく

# 必要なもの
- サーバー
    - Conoha Wingで。
- ドメイン
    -お名前.comで。 
- サイト本体
    - AWSを開発環境に。HTML, CSS, JavaScript, PHPなどが現段階では使えるが、便利そうなフレームワークがあればそちらを優先的に使ってみるのもいい。
- 作品（重要）
    -なるべく自分自身の興味に絡めたほうが作りやすい？
    -e.g.) 筋トレ、ハーブ、その他体調管理ノウハウなど？
    -生成AIを用いた簡単な開発が出来ないか見てみる。

# 注意(自分自身への)
- しないといけないことは沢山あるが、一度に全部やろうと思わない。無理すると挫折するから。
- 続けるためのハードルは低くしても良い。けどなるべく自分自身の体調も整えるように心がける。
AWS Certified Solutions Architect - Professional (SAP-C02)を更新しました

# はじめに
AWS Certified Solutions Architect - Professionalが失効間近のため更新しました。

# 教材
1. [Tech Stock | AWS WEB問題集で学習しよう](https://aws.koiwaclub.com/exam/dbs/)
    - 有償のおなじみのやつです。
    - 581問(83セクションx7問)です。
    - 他者の合格記を見ると好評でしたので、Udemyは受講せず、これだけ勉強しました。結構よかったかと思います。
    - #01～#30は古いため、スキップしても良いと思います。
1. [試験問題サンプル](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-sa-pro/AWS-Certified-Solutions-Architect-Professional_Sample-Questions.pdf)
    - 無料の公式の試験問題サンプルです。
1. [Skill Builder: AWS Certified Solutions Architect – Professional Official Practice Question Set (SAP-C02 - Japanese)](https://explore.skillbuilder.aws/learn/course/13272)
    - 無料の公式問題集です。
    - 20問です。
1. [Skill Builder: AWS Certified Solutions Architect - Professional Official Practice Exam (SAP-C02 - Japanese)](https://explore.skillbuilder.aws/learn/course/14068)
    - 有料の公式問題集です。
    - 75問です。
    - 幾つか"AWS WEB問題集で学習しよう"と内容が重複していますが、解説がしっかりしています。
    - "AWS WEB問題集で学習しよう"だけでも良いですが、お金があれば、より合格率を高めるために受けても良いと思います。

# 感想
- 全く分からない問題が数問ありましたが、"AWS WEB問題集で学習しよう"効果で、スムーズに進めることができました。
激安リフロー炉の改造を改造して実測してみた件

しばらくまえに、[激安リフロー炉T-962を改造している方の情報をベースに、ファームウエアの温度制御を改良していました。](https://qiita.com/akita11/items/0f83f465e0d3f914c6ed
)それなりにリフローができていたので、そのまま使っていたのですが、ふと、設定温度が高すぎるような気がして、改めて調べてみると、どうも鉛フリーはんだ用の温度設定のようでした。また、ときどきコネクタが変形してしまったり（温度が高すぎ）、また場所によってはんだが融けていない場合もあります（温度が低すぎ）。

そこで改めて設定温度をやや低めに変更した上で、熱電対を貼ったダミー基板を炉内のいろいろな場所において置いて温度を計測してみました。共晶はんだ用ということで、予熱は150度-170度を60秒、本加熱は210-230度を20秒、としています。

炉内を大きく3（左・中央・右）×3（手前・中央・奥）=9の区画に分け、5×5cmのダミー基板（厚さ1mm）に熱電対を貼って温度を計測します。熱電対の計測は、[M5Stackの熱電対ユニット](https://www.switch-science.com/products/7655)（在庫数の関係で非絶縁型と絶縁型を併用）を3個、I2Cバスを分岐するPaHUBとともに使いました。1秒ごとに温度計測し、シリアル経由で出力するプログラムをはUIFlowでさくっと書きました。![スクリーンショット 2023-07-16 17.33.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/60e1ae6e-99a0-611a-9850-45d6bef72aca.png)

# 手前の温度がだいぶ低い

![graph1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/00bf6564-4de7-cf52-c22c-f3da21c524c5.png)

まず手前・右、中央・中央、奥・左の3箇所の温度がこちらです。奥のほうがだいたい制御側（リフローの熱電対の温度に合わせて制御している）と同じくらいになっていますが、中央がやや高めに出ますが、まあ許容範囲といえそうです。問題は手前で、最高でも185度くらいまでしかあがっていません。
![graph5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457605/f68aca8e-2547-da77-04d9-8579ade1dae6.png)

念のため、左右の分布をみるために、計測位置の左右を入れ替えてみましたが、手前がだいぶ低くなる傾向は同じようです。

結果として、炉内の温度分布が手前が低めに出る、ということでしょうから、温度制御ではどうしようもない、といえそうです。そのため、手前は使わないようにする、というのが現実的といえそうです。
【GO言語】mysqlへの接続でやらかしたこと

# やろうとしたこと
GO言語の公式チュートリアルのコードを基に（ほぼコピペ）ローカルのmysqlサーバに接続して、DBのデータを参照したり、書き込んだりするプログラムを書こうとしました。

# 書いたコード（エラー解消前）
以下、エラーが発生するコードです。
```main.go
package main

import (
	"database/sql"
	"fmt"
	"log"

	"github.com/go-sql-driver/mysql"
)

var db *sql.DB

type Album struct {
	ID     int64
	Title  string
	Artist string
	Price  float32
}

func albumByArtist(name string) ([]Album, error) {
	var albums []Album

	rows, err := db.Query("SELECT * FROM album WHERE artist = ?", name)

	if err != nil {
		return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
	}

	defer rows.Close()

	for rows.Next() {
		var alb Album
		err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price)
		if err != nil {
			return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
		}
		albums = append(albums, alb)
	}

	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("albumsByArtist %q: %v", name, err)
	}

	return albums, nil

}

func main() {
	//connect to DB
	cfg := mysql.Config{
		User:                 "user",
		Passwd:               "pass",
		Net:                  "tcp",
		Addr:                 "localhost:3306",
		DBName:               "recording",
		AllowNativePasswords: true,
	}

	//get a database handle
	var err error
	db, err := sql.Open("mysql", cfg.FormatDSN())

	if err != nil {
		log.Fatal(err)
	}

	pingErr := db.Ping()
	if pingErr != nil {
		log.Fatal(pingErr)
	}

	fmt.Println("connect to DB!")

	var albums []Album
	albums, err = albumByArtist("John Coltrane")

	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Albums found: %v\n", albums)

}
```
これを実行すると以下のエラーが発生します。
`panic: runtime error: invalid memory address or nil pointer dereference`

# エラーの原因
かなり初歩的なミスでしたが、`main()`内の`sql.Open()`の書き方にミスがありました。

* 正：`db, err = sql.Open("mysql", cfg.FormatDSN())`
* 誤：`db, err := sql.Open("mysql", cfg.FormatDSN())`

`=`とすべきところ、うっかり`:=`と書いてしまったことが原因でした。

複数の関数内で共通のDBのコネクションを使うためグローバル変数として定義する必要があります。
ところが、main()内のsql.Open()を実行する際に`:=`としてしまうと、
左辺のdbはmain()内のローカル変数として定義されてしまいます。

そして、albumByArtist()内でDBにクエリを投げようと、グローバル変数のDBのコネクションを利用しようとしても、グローバル変数のコネクションがnilなので上記のエラーが発生したというわけです。
（当然main()内のコネクションにはデータが格納されています。）

# 最後に
GO言語を勉強したてで、意識して`=`と`:=`の使い分けができていなかったため発生したエラーでした。
気をつけていきたいですね。
【Express】Node.jsファイルをルーティングする

## この記事の内容

以前の投稿では、Node.jsでWebページをホスティングする方法を紹介しました。

https://qiita.com/watsony/items/a6790d932d2f59589965



ここでは、Node.jsとExpressを用いてWebページのホスティングとルーティングをする方法を紹介します。


## Expressとは

> [Express](https://expressjs.com/)は、Node.jsのための軽量なWebアプリケーションフレームワークです。Expressを使用することで、簡単かつ効率的にWebサーバーを構築できます。ルーティングやミドルウェアの管理、HTTPリクエストとレスポンスの処理など、Webアプリケーション開発に必要な機能を提供します。Expressはシンプルで柔軟な設計が特徴であり、多くの開発者によって広く使用されています。


## 事前準備

- Node.jsをインストール
[Node.js](https://nodejs.org/ja)の公式サイトにアクセスして、インストーラーをダウンロードおよびインストールします。

- Node.jsとnpmのバージョン確認
次のコマンドで、Node.jsとnpmが導入済みであることを確認します。
バージョンが表示されたら正しく導入されています。（npmはNode.jsをインストールすると一緒に入ります）

```bash
node -v
npm -v
```

> 「npm」は、Node Package Manager（ノード・パッケージ・マネージャ）の略称で、Node.jsのパッケージ管理ツールです。npmを使用することで、JavaScriptのライブラリやモジュールを簡単にダウンロードし、プロジェクトで利用することができます。また、パッケージのバージョン管理や依存関係の解決も行えます。


## ExpressのHelloWorld

- 作業用フォルダを作成
```
$ mkdir qiita
```

> qiita/


- Expressをインストール

Expressをフォルダ内(qiita)にローカルインストールします
```bash
$ npm install express
```
Expressをインストールすると、自動的に`node_modules`, `package.json`, `package-lock.json` が作成されます

> qiita/
├ node_modules/
├ package.json
└ package-lock.json


コマンド`npm list`で、Expressのバージョンが表示されたら正しくインストールされています。
```bash
$ npm list
└── express@4.18.2
```

- JavaScriptファイルを作成

`hello-world.js`を作成

> qiita/
├ node_modules/
├ package.json
├ package-lock.json
└ hello-world.js


Expressの公式チュートリアルの通り、コードを`hello-world.js`に記述します。

https://expressjs.com/en/starter/hello-world.html

```javascript:app.js
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
```

- 実行

次のコマンドでホスティングします。

```bash
node app.js
```
[http://localhost:3000](http://localhost:3000) もしくは [http://127.0.0.1:3000](http://127.0.0.1:3000) にブラウザアクセスして

Hello World! 


が表示されら成功です。
RECOROKUを試しに使ってみた

## はじめに

『映像議事録』というのはなんか新鮮だったので、RECOROKUを使ってみます。

https://recoroku.com/?utm_source=qiita&utm_medium=referral&utm_campaign=qiita_article_submission


## なぜRECOROKUを試してみたいと思ったか？

[こういうイベント](https://qiita.com/official-events/f501b76c23086931fb42)があったのもきっかけの一つですが、業務で実験の様子を動画撮影することがあり、Vlogのようにチームメンバーに共有できたら便利かもと考えたためです。
動画の時間が長くなったりすると、後で見返したり、他のメンバーが動画確認するの面倒だったりするので...


## 環境
macOS Ventura 13.4.1
Google Chrome


## 使ってみた

適当な動画ファイル(mp4)を使って動作確認してみます。
チャンネル作成と会議作成を実施しましょう。
この場合はGoogle Meetでアップロードし、ファイルサイズは2GBまでのようです。
(RECOROKU NOTEから画面録画して動作確認しようとしていたのですが、録画停止後の映像アップロードに失敗してしまいました。)

![スクリーンショット 2023-07-20 22.38.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347723/3513c0ae-5cd4-a377-4719-8ca53721448f.png)



動画アップロード後にAll Playボタンをクリックすると、以下のような画面に遷移します。
(動画とか若干隠させていただきました。)

![スクリーンショット 2023-07-16 17.02.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/347723/6856ba0e-bf39-47ab-2ff2-87e302e75acf.png)

動画を確認しながらメモを追加でき、メモをクリックすると該当箇所の動画を確認できます。
つまり、「〇〇が発生！」といったメモから、動画で〇〇の様子が確認できそうです。
メモのリンクもコピーできるので、他のメンバーへの共有もしやすそうですね。


## おわりに

ちょっとはじめは使い方がわからず試行錯誤してしまいましたが、基本的にはシンプルで使いやすかったです。
ユースケースとして実験動画の共有にも使えそうですが、2GBの制限だと数十分くらいが限度でしょうか？
会議でも使用感を確認してみたいですね。
SQLSTATE[HY000] [1045] Access denied for user 'root'@'xx.xx.xx.xx' (using password: YES)の対処

## 現象
Docker ✖️ MySQL環境でマイグレーションを実行しようとすると、
```
 % ./vendor/bin/sail artisan migrate   
```
エラー発生。
```
 Illuminate\Database\QueryException 

SQLSTATE[HY000] [1045] Access denied for user 'root'@'xx.xx.xx.xx' (using password: YES) 
以下略
```

## 原因：作業用ユーザーを作成してないため
rootユーザーではマイグレーションを実行できないので、作業用のユーザーを作成する。

1, コンテナのIDを確認
```bash
% docker ps
```

2, DockerのMySQLコンテナに接続
パスワードを求められるので、rootユーザーのパスワードを入力。
設定してない場合はエンターキーで通る。
```bash
% docker exec -it [コンテナID] mysql -u root -p
```

3, 新しいユーザーを作成
```sql
> CREATE USER '[ユーザー名]'@'%' IDENTIFIED BY '[パスワード]';
```

4, 作成したユーザーに権限を付与
（※ここでは全権限を付与していますが、適宜調節してください。）
```sql
> GRANT ALL PRIVILEGES ON *.* TO '[ユーザー名]'@'%';
```

5, 権限を有効にするために、フラッシュ
```sql
> FLUSH PRIVILEGES;
```

6, .envを更新
```.env
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=データベース名
DB_USERNAME=作成したユーザー名
DB_PASSWORD=パスワード
```

7, マイグレーションを実行 → OK！
並列Lispで、たらいまわしをした話

# 動機
ISLispの生みの親の一人である伊藤貴康先生の論文を読みました。並列マシンの製作、その上で走るPaiLispに興味を持ちました。その論文を参考にしてISLisp規格のEasy-ISLisp（以下「EISL」)に並列構文、pletとpcallを追加、並列Lispで何ができるのだろうか？と試行錯誤しています。

# スレッドセーフ
インタプリタをスレッドセーフにするとともに、コンパイラが生成するLispオブジェクトもスレッドセーフにしました。EISLはLispコードをC言語にトランスパイルする方式です。スレッド番号を表す引数thを追加するようにしました。

```
int f_tarai(int x, int y, int z, int th){
    tarai(x,y,z,th)
}


int tarai(int x, int y, int z, int th){
    コード本体
}
```
C言語の引数はスレッドセーフですが、動的変数、シンボルや文字列を表すセルはスレッド間で共有していますので、これをスレッド番号ごとに管理するコードを生成するように変更しました。マーク＆スイープのGCスレッドごとに保護すべきセルなどのデータを保持し、スレッドセーフを実現しました。

C言語のPthreadライブラリを利用してスレッドに分割します。これによりマルチコアCPUであればそのスレッドが各コアで実行されるようになります。

# 並列構文
PaiLispの論文を参考にして次のように記述することとしました。

```
(defun ptarai (x y z)
    (the <fixnum> x)(the <fixnum> y)(the <fixnum> z)
    (if (<= x y)
        y
        (pcall ptarai (tarai (- x 1) y z)
                      (tarai (- y 1) z x)
                      (tarai (- z 1) x y))))

(defun pcount (n)
    (plet ((a (count 1 (div n 2)))
           (b (count (+ (div n 2) 1) n)))
     t))

(defun count (m n)
    (if (= m n)
        t
        (count (+ m 1) n)))

```

pcallは (pcall fn arg1 arg2 ...argn) という形式です。arg1,...argnをスレッドで起動、マルチコアで実行します。

pletはlet構文のマルチスレッド版です。式の部分をスレッドに分解して実行し、これをjoinで待機したのちにbody部を実行します。

余談ですが、EISLは型推論器をもっており、the構文により必要な情報を与えると最適化するようにしてあります。たらい回しのような単純な再帰コードの場合、C言語波の実行速度を出すことができます。



# 計測
インテルicore5で計測しました。Windows WSLで実行しています。


![bandicam 2023-07-16 18-24-45-538.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33927/71de6c66-9a62-21e3-ff71-0b73d0aa1aae.jpeg)



予想に反して並列のpfibの方が逐次のfibより若干遅いのでした。pthreadの設定の問題だろうか？などChatGPTに相手になってもらいかなり試行錯誤したのですが、残念ながら並列の方が遅くなっています。ARMラズパイ４００では並列の方が高速になっています。たらい回し、竹内関数の場合にはその再帰パターンは複雑なのでなかなか並列での性能が上げられないでいます。スレッドに分割するコストを考えても2倍くらいは高速になると予想していたのですが。ちょっとがっかり。


# CPUによる違い
英語版Reddit/Lispには凄腕Lisperがた出入りしているように思いました。記事を投稿し、いくつか助言をいただきまいした。改良の余地はあるかもしれません。また、コンカレントGCと並列動作とかまだ共存できずにセグフォを起こしています。並列動作を理解しつつじっくりデバグしています。

インテル、AMD、ARM　それぞれ設計方針が異なるようで並列動作したときのパフォーマンスが異なります。ARMの方が並列で効果を出せています。インテルicoreは単一スレッドの高速性を重視しているのかもしれません。


EISLはGithubにおいてります。よかったらお試しください。
https://github.com/sasagawa888/eisl