OmniAICreator/Qiita-1.07M huggingface dataset:
Notion数式を使って、Amazonの購入リンクを短縮して管理してみた

# 概要
私の勤める会社では書籍などを購入する際に、参照WebサイトとしてAmazonリンクを記載するフォーマットとなっています。
その際に、通常のAmazonのページで探してURLを張り付けると検索ワードや著者名がエンコードされた長いURLで表示されてしまします。

例えば、こんな感じです。「スティーブ・ジョブズ I 」を検索してみました。
```
https://www.amazon.co.jp/スティーブ・ジョブズ-I-ウォルター・アイザックソン/dp/4062171260/ref=tmm_hrd_swatch_0?_encoding=UTF8&dib_tag=se&dib=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=1710587710&sr=8-3
```

:::note info
AmazonのIdToken部分っぽい場所は、別文字列に置き換えています。
:::

こんな風にURLが長くなってしまうので、Excelなどの申請書のフォーマットに入力すると見栄えが悪くなるという問題があります。


## Amazonの商品ページURL
Amazonの商品ページURLは、書記であればISBNコード、それ以外の製品はASINの10桁の番号さえあれば、問題なく表示できます。
この10桁の番号はURLにおける```dp```ディレクトリの区切りの直後に配置されています。
ここさえ上記の```dp```10桁の番号を含めば、商品ページURLとして認識されます。

上記URLの例では、以下のようになります。
非常にすっきりしましたし、全商品が同じ文字数で表現できるはずです。
```
https://www.amazon.co.jp/dp/4062171260
```

上記のようにAmazonの商品ページURLを短縮するだけであれば、既に色々なツールやShellなどでのやり方は公開されています。
なので、単にURLを短縮したいだけであれば、このような方法を使えばよいかと思います。

https://howtobuyfromjapan.com/amazon_url_shortener.htm

https://zenn.dev/shuzon/articles/ec9f316298d030


# Notionで欲しい書籍リストを管理する
私は普段からNotionというアプリでタスク管理しているので、会社の申請書を作成する以外にも、欲しい書籍リストとして管理したいと考えていました。
タスクはこんな感じで管理しています。
![Notion1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3706974/1b960e8d-74d0-92b1-f0e8-663e36449a6d.png)


このNotion上の欲しい書籍リストから、会社の申請書にスムーズに移行できることが今回の狙いです。
（と言っても、Amazon商品ページURLを短縮表示＋購入状態＋読了状態を付与するだけですが・・・）


## Notion数式とは？
Notionではデータベースとして設定できるプロパティとして、テキストや数値、複数値から選択するセレクトなどが用意されています。
その中には数式というプロパティの種類があり、Excelのように他のプロパティを参照して値を加工するような数式を設定することができます。

どのような数式があるかは、Notion公式サイトでも解説があります。
そこまで複雑な数式はありませんが、今回できる部分までこのNotion数式を使って対応したいと思います。
https://www.notion.so/ja-jp/help/formula-syntax


# Notionで欲しい書籍リストを作ってみた
今回作成した欲しい書籍リストです。
```Amazon貼り付け```に検索したリンクをそのまま貼り付けることで、```Amazonリンク```に短縮URLの結果が表示されるようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3706974/52cdb9a4-813e-59cb-58a2-6f173ee4973d.png)


## Amazon購入リンクを短縮するNotion数式の設定
ここまで来てやって本題です。
```Amazonリンク```に設定した数式は以下のようになります。

```
"https://www.amazon.co.jp/dp/" + filter(split(prop("Amazon貼り付け"), "/"), length(current) == 10)
```

簡単に解説します。
* ```prop```関数で、データベースにおける他のプロパティ値を参照
* ```split```関数で、参照したプロパティ値を```/```を区切り文字としてリストに分割
* ```filter```関数内で、リスト内の値```current```の文字列を```length```で取得し、10文字に一致する場合の値を取得
* 抽出した値と```https://www.amazon.co.jp/dp/```を結合して表示


Notion数式に文字列を検索するような数式がなかったため、dpディレクトリの次にある10桁の番号を文字列の長さだけで抽出するようにしました。
今後Notionの数式バリエーションが増えれば、よりいい感じの数式が設定できると思います。


# まとめ
今回はNotion数式を使って、Amazon購入リンクを短縮して表示できる欲しい書籍リストについてご紹介しました。
改善点は色々ありますので、コメントなどで教えていただけると幸いです。
WSLのインストール済みディストリビューション一覧からデフォルトを確認し、任意のディストリビューションに変更する方法

# 記事化した経緯
- インストール済みディストリビューションの一覧表示コマンド、任意のディストリビューションを指定するコマンドがそれぞれ紹介されている記事はよく見かける
- が、一覧表示結果からどのディストリビューションがデフォルトに設定済みなのかを説明している記事を見かけなかった
- ので、自分用の備忘録のためにも残しておきます

# 実行環境
- windows 10 Pro
- Windows PowerShell
- WSL2

# 手順
### インストール済みディストリビューションの一覧からデフォルトディストリビューションを確認する
- 実行コマンド
```
$ wsl --list --verbose
```
※省略形は「wsl -l -v」
- 上記コマンドを実行するとインストール済みディストリビューション一覧と、その中からデフォルトに設定されているディストリビューションが確認できる
- 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329934/db675478-a1e3-fff4-4833-97b049d11d92.png)
- NAME列の左側に ＊（アスタリスク）がついているディストリビューションがデフォルト設定となっている
（現在は`Ubuntu`がデフォルトディストリビューションに設定されている）
- 現在だと`wsl`コマンドを叩くと、Name：Ubuntuのディストリビューションが立ち上がる

### デフォルトのディストリビューションを任意のディストリビューションに設定する
- 実行コマンド
```
$ wsl --set-default <任意のディストリビューション名>
```
※省略形は「wsl -s <任意のディストリビューション名>」
- 上記コマンドを実行するとデフォルトのディストリビューションが切り替わり、`wsl`コマンドでデフォルトに指定したディストリビューションが立ち上がるようになる
- 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329934/20d94e27-907b-239d-717e-056b95bab922.png)
- `wsl --set-default Ubuntu-20.04`のようにデフォルトに設定されていなかったディストリビューションを指定してコマンドを実行
- インストール済みディストリビューションを確認するとNAME列左側の＊が`Ubuntu-20.04`に切り替わっている
- この状態で`wsl`コマンドを実行するとデフォルトディストリビューションに切り替わった`Ubuntu-20.04`が立ち上がるようになる
【Ruby】paizaラーニング問題集解答（3けたごとにカンマ区切りで出力）

# 大きな数値を 3 けたごとにカンマ区切りで出力 (paizaランク C 相当)
https://paiza.jp/works/mondai/stdout_primer/stdout_primer__specific_split_step6
### 自分の解答
（分かりませんでした）
### ChatGPTの解答
```ruby
# 入力を受け取る
n = gets.chomp

# カンマ区切りで出力するための変数
output = ""

# 数値を3けたごとにカンマ区切りで出力する
(n.length / 3).times do |i|
  # 3けたごとの部分文字列を取得し、カンマを付けてoutputに追加
  output += "#{n[-3*(i+1), 3]},"
end

# 末尾のカンマを除去して出力
puts output.chomp(',')
``` 

このコードでは、まず与えられた数値Nを3桁ごとに区切ってカンマを付け、その後、末尾のカンマを除去して出力します。

### 自分の再解答
上記のChatGPTの解答では、以下のような入力と出力となる。
```terminal
入力
111222333
出力
333,222,111
```

そのため、以下のように修正した。
```ruby:practice.rb
# 入力の受け取り
input = gets.chomp.to_s

# 出力用変数の定義
output = ""

# 出力用変数に3桁ずつ区切った文字列とカンマを追加
input.length / 3.times do |i|
    output += "#{input[i*3,3]},"
end

# 末尾のカンマを除去して出力
puts output.chomp(",")
```
※不正解です。一旦ギブアップします...
### 学び
- 文字列のインデックスを実践的に使う方法を学んだ。
- `chomp`メソッドは改行だけでなく、`,`なども除去できる。
Cypressで画面遷移時に失敗するエラーを解消する

Cypressテストコードを書いている最中にエラーが起きた内容とその解決策を備忘録として書いておく。

エラーの起きたコード

```
visit(path)
wait(2 * 1000)

get(input).type("入力フォームに入力したいテキスト")
```
### 課題
画面遷移の時に、読み込み時間が2秒以上かかった場合に、inputタグがまだ表示されていなくて、エラーに落ちる

↓ 解決策
```
visit(path)

// inputのボタンが表示されるまで待つ（デフォルトで4秒）
cy.get("input").should("exist"); 

get(input).type("入力フォームに入力したいテキスト")
```

inputのボタンが表示されるされるまで待つようにすれば解消。

----

それでも、たまに同じ場所でエラーが出る場合があった。
cy.get("input").should("exist"); 
のところで、inputタグが見つかりませんでしたな内容。


### 画面遷移に時間がかかる場合がある
PCが重いなど何ら中の理由で、画面遷移に時間がかかっている。計測すると、基本は1~2秒の間で遷移しているが、時間がかかった場合、9秒かかる場合があった

実際に計測してみる。時間を測りたいところに↓のコードを追加(他にいい方法あると思う）

```
cy.visit(path)
// ページ名を含む要素を取得して、処理時間をログに出力
const start = Date.now();
cy.get('input', {timeout: 10 * 1000}).should('exist').then(() => {
    const end = Date.now();
    const executionTime = end - start;
    cy.log("処理時間：" + executionTime + "ms");
});
```
※  {timeout: 10 * 1000}について
shouldは、デフォルトで4秒しか待ってくれないので、プラスで10秒待つ（つまり14秒までは表示を待つようにしている。）
このコードを入れて、20回分テストして
```
cy.get('input').should('exist')
```
の実行時間を計測すると、
| 1 | 2 | 3 | 4 | 5 |
|:-:|:-:|:-:|:-:|:-:|
| 143ms  |140ms   | 166ms  |151ms   | 166ms  |
| 6 | 7 | 8 | 9 | 10 |
| 139ms  | 152ms  | 153ms  | 865ms  | 171ms  |
| 11 | 12 | 13 | 14 | 15 |
| 142ms  |  608ms |170ms   | 148ms  | 146ms  |
| 16 | 17 | 18 | 19 | 20 |
| 150ms  | 172ms  |  142ms | 139ms  | 159ms  |

というような結果に。

### 結論
こういうブレがあるため、wait(2 * 1000)としてしまうと、
処理時間に2000msを超えた時にエラーが発生してしまうので、（処理が早く終わったのに待つ手間も生まれる）
shouldで処理を待機するようにしようと学んだ。

### 感想
そもそもあまりwait(ミリ秒）は入れずに、shouldなどのアサーションで、適切な時間だけ待つようにしたほうが綺麗。
プレーリーカードを自作した話

# プレーリーカード（デジタル名刺）との出会いと自作のきっかけ

技術系のオフラインイベントに参加、終了後の懇親会で名刺を交換していた中で名刺じゃなくてカードをスマホで読み取らせている人がいた。
それ格好良いですね！と声をかけたら「プレーリーカードって言うんだよ」と教えてもらいました。

家に帰って早速調べて[サイト](https://prairie.cards/)にアクセス。

「格好良いけどちょっと高い。。。」

どれだけ使うかも分からなかったので、購入するのを躊躇。
考えた結果、「自作すれば良いのでは？」という結論になりました。

----
ここからはデジタル名刺の作り方を説明していきます。

# 用意するもの

* NFCタグ（カード型じゃなくてもOK）
* スマートフォン

以上。たったこれだけです。

自分は名刺入れに入れるためカード型にしました。また、白色だとチープになりそうなので値段は少し高くなりますが黒色を選択。

https://www.amazon.co.jp/gp/product/B0CGMFY5D7

# プロフィールページを作成する

こちらもゲストがアクセスできるURLがあればなんでも良いです。（もちろんQiitaのプロフィールでもOK）
ここでは無料で使えるプロフィール作成サービスを挙げておきます。

* [Unit.Link](https://unit.link/)
* [Lit.Link](https://lit.link/)
* [QR Code Chimp](https://ja.qrcodechimp.com/digital-business-cards)

# NFCタグに書き込む

## NFC Toolsのインストール
お使いのスマートフォンにストアから「NFC Tools」というアプリをインストールします。

Playストア

https://play.google.com/store/apps/details?id=com.wakdev.wdnfc&pcampaignid=web_share

App Store

https://apps.apple.com/jp/app/nfc-tools/id1252962749

## 書き込み
アプリを起動し、 書く > レコードを追加 > URL/URI > プロフィールページのURLを登録してOK の順に操作します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164059/200e5e51-628d-7bab-87cc-c9e70da50b0c.jpeg" width="300">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164059/c21771f3-61b7-f483-bc7d-ed3268532099.jpeg" width="300">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164059/fa4a5f06-a7e7-c3c6-ce4c-c2a338e9fe3c.jpeg" width="300">

NFCタグを用意し、書き込みボタンを押します。

# 完成!!

非常に簡単にデジタル名刺を作ることができました。
NFCタグは非常に安いので複数作っておけば名刺入れだけでなく財布などにも同時に入れっぱなしにできるので、急に名刺交換が始まってもスマートに対応できます。

デジタル名刺が気になっている方は試しに自作してみるのはいかがでしょうか？
[まとめ]有向グラフ描画ライブラリ（JavaScript）

## 有向グラフとは

有向グラフ（Directed Graph）とは、グラフ理論において、エッジ（枝、リンク）に方向性があるグラフのことを指します。有向グラフは、ノード（頂点）のセットと、これらのノードを結ぶ有向エッジのセットから成り立っています。

## 要素の整理

有向グラフを描画する際の主要な要素を整理します。

- ノード（Node）（節点・頂点、点）:
    - グラフの基本単位です。
    - グラフ内の各個別アイテムやオブジェクトを表します（例：都市、ネットワーク内のコンピュータ、人物など）。
- エッジ（Edge）（枝・辺、線）:
    - ノード同士を結ぶ線です。
    - 有向グラフでは、エッジには矢印が付き、一方向の関係を示します（例：AからBへの道、Webページ間のリンクなど）。
- リーフ（Leaf）:
    - 子を持たないノードのことで、特に木構造の文脈で使用されます。
    - 有向グラフのコンテキストでは、外部へのエッジがない（つまり、出力エッジがない）ノードと考えることができます。

## ノードの関係を表す要素

- ルートノード（Root Node）
    - 特に木構造の文脈で使用され、グラフの「開始点」を指します。
    - 有向グラフでは、他のすべてのノードへのパスが存在するようなノードがルートノードに相当します。

- サイクル（Cycle）
    - エッジをたどって元のノードに戻ることができる一連のノード。
    - 有向グラフにおいては、特定の方向に沿って閉じたループが形成されます。

- ウェイト（Weight）
    - エッジに割り当てられる数値で、エッジの「コスト」や「容量」などを表すことができます。
    - 有向グラフにおいては、エッジの重要度や移動コストなどを表現するために使用されます。


## 主要なライブラリの比較(javascript)

以下の観点で比較しています。D3.jsが最も一般的に使用されているようです。

- 柔軟性: データや描画方法をどれだけ自由に変更できるか
- カスタマイズ: グラフの外観や挙動をカスタマイズする容易さ
- パフォーマンス: 大量のデータや複雑なグラフを扱う際のパフォーマンス
- 使用の容易さ: ライブラリの学習曲線や設定の簡便さ
- 特化分野: 各ライブラリが特に力を入れている用途や分野

| ライブラリ名                                                            | 柔軟性 | カスタマイズ | パフォーマンス | 使用の容易さ | 特化分野                     |
|-----------------------------------------------------------------------|-------|------------|--------------|------------|-----------------------------|
| [**D3.js**](https://d3js.org/)                                        | 高   | 高      | 中〜高       | 中         | 汎用的なデータ可視化           |
| [**Cytoscape.js**](http://js.cytoscape.org/)                          | 中    | 中〜高     | 高           | 中         | 生物学、ソーシャルネットワーク |
| [**vis.js**](http://visjs.org/)                                       | 中    | 中         | 中           | 高         | ネットワーク、時系列データ       |
| [**Sigma.js**](http://sigmajs.org/)                                   | 中    | 中         | 高           | 中〜低      | 大規模ネットワーク             |
| [**GoJS**](https://gojs.net/)                                         | 高   | 高       | 高           | 中         | インタラクティブな図表作成      |
| [**cola.js**](https://ialab.it.monash.edu/webcola/)                   | 中〜高 | 中〜高     | 中〜高       | 中         | 自動レイアウトの最適化         |


## 描画上における諸要素

- ラベル（Label）
    - ノードやエッジに付けられるテキストで、識別情報や追加データを提供します。
    - ノードの名前、エッジの種類や強度などを示すことができます。

- カラーコード（Color Coding）
    - ノードやエッジに特定の色を割り当てることで、カテゴリー、状態、重要度などを視覚的に区別します。

- グループ/クラスター（Group/Cluster）
    - 類似または関連するノード群をグループ化します。
    - クラスタリングにより、大規模なグラフの中でパターンやサブグループをより明確に視覚化できます。

- サイズスケーリング（Size Scaling）
    - ノードやエッジのサイズを、重要度や量の多さなどの指標に基づいて調整します。
    - 例.より多くの接続を持つノードを大きく表示することができます。

- グリッド/配置（Grid/Layout）
    - ノードを整理的に配置するためのグリッドやレイアウトアルゴリズム。
    - グラフが読みやすく、情報が把握しやすいようにします


# まとめ

JavaScriptにおける、有向グラフ描画ライブラリについてまとめました。
Database構築にあたって設定すべきこと、気を使うべきこと

```
```
:::note info
１．vacuum analyzeの使用頻度
２．transaction_isolation のレベル
３．クライアント接続に関するlogを取得するか
    log_connections=on,log_min_messages=???,
４．listen_addresses,pg_hba.confの確認　クライアント接続
:::
wslで、最小のカーネルをコンパイル その15

# 概要
wslで、kernel.elfのコンパイル、やってみた。
cで、書いたカーネルで、俺言語を組み込んだ。
じゃんけんを、打ち込んで、実行した。

# 写真

![スクリーンショット 2024-03-17 110826.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/781e3b78-e08b-29c2-d484-24d38b5209a2.png)


以上。
Pythonで「パターンにマッチしたすべてのマッチオブジェクトを取得する(Pattern.finditer)」の動作を確認してみた

# 概要

Pythonで「パターンにマッチしたすべてのマッチオブジェクトを取得する(Pattern.finditer)」の動作を確認してみました。
以下のページを参考にしました。

https://www.javadrive.jp/python/regex/index8.html

# 実装

以下のファイルを作成しました。
```sample.py
import re

msg = 'MA-52, JO-72, PP-45'
pattern = re.compile(r'[A-Z]{2}-[0-9]{2}')

result = pattern.finditer(msg)

for m in result:
    print(m.group())

import re

msg = 'MA-52, JO-72, PP-45'
pattern = re.compile(r'([A-Z]{2})-([0-9]{2})')

result = pattern.finditer(msg)

for m in result:
    print('Match:' + m.group(0))
    print('Group1:' + m.group(1))
    print('Group2:' + m.group(2))

import re

msg = 'Sample'
pattern = re.compile(r'[A-Z]{2}-[0-9]{2}')

result = pattern.finditer(msg)
m = None

for m in result:
    print(m.group())

if m is None:
    print('Don\'t matched')
```

以下のコマンドを実行しました。
```
$ python3 sample.py 
MA-52
JO-72
PP-45
Match:MA-52
Group1:MA
Group2:52
Match:JO-72
Group1:JO
Group2:72
Match:PP-45
Group1:PP
Group2:45
Don't matched
```

# まとめ

何かの役に立てばと。
Visualforceページをタブレットで表示した時にCSSが効かない

# 事象
Visualforceページで作成したforce.com上のページをタブレット・スマホで表示したときにCSSが一部効いていない
# 実装内容
Force.com上にVisualforceページを使用してフォームを設置し、入力した内容から取引先・取引先責任者のレコードを作成する。
# 使用した機能
- Apexクラス
- Visualforceページ
- Force.com
# 原因
原因は単純でCSSをネストで記述していたことで、ブラウザがネストに対応していないバージョンだったため、正常に表示されていなかった。
# 解決方法
以下のどちらかの方法で解決できる。
- CSSをネストせずに記述する
- ネストに対応しているバージョンブラウザを更新する
# おわりに
CSSのネスト機能はリリースされてからそれほど時間が経っていないため、ネストせずに記述しておいた方が無難ですね。
# プログラミングコミュニティの紹介
Reactを１から実践レベルまで身につけることができるサービス「JISOU」では現在メンバーを募集中です。
気になる方は以下のHPのLINEからお問合せください。
https://projisou.jp

# 会社の紹介
この記事を最後まで読んでいただき、ありがとうございます！
私がエンジニアとして働いているViVO株式会社では、SalesforceやYextといったSaaSシステムに関わるエンジニアを募集しています。
経験者の方はもちろん、未経験者でもチャレンジしたいという熱意があれば大歓迎です。

技術的な経験がない方でも成長できるよう全面的にサポートする環境を提供しています。

もし少しでも興味を持っていただけたら、以下のURLまたは私にDMでご連絡ください。
https://vivojpn.com
英語の意味や例文をまとめた辞書系ウェブサイトを制作しました


最近、「[Let's English](https://letsenglish.jp/?trk=qt-aa)」という英語学習に特化したウェブサイトを制作しましたので、その概要をご紹介いたします。このウェブサイトは、英語や英熟語、フレーズ、言い回しに関する意味、語源、覚え方、使い方、例文などを一覧で分かりやすくまとめた、オンライン辞書のようなサービスです。

→ [https://letsenglish.jp/](https://letsenglish.jp/?trk=qt-ab)

## ウェブサイトの特徴

- **包括的な情報提供**: 英語学習に必要な様々な情報を網羅しています。単語やフレーズの意味だけでなく、語源や覚え方、使い方、例文なども詳細に解説しています。
  
- **分かりやすいデザイン**: 初心者から上級者まで、幅広いレベルの学習者にとって使いやすいデザインを心がけました。情報が整理されており、見やすいレイアウトを採用しています。

## 使用技術

ウェブサイトの制作には、以下の技術を使用しました。

- **Next.js**: サーバーサイドレンダリングとルーティングを簡単に行えるNext.jsを採用しました。これにより、ウェブサイトのパフォーマンスを向上させ、SEOにも配慮しています。
  
- **React**: ウェブサイトのフロントエンド部分はReactを使用し、動的なUIを実現しています。
  
- **Tailwind CSS**: シンプルで柔軟なデザインを実現するために、Tailwind CSSを利用しました。これにより、迅速なデザイン変更やカスタマイズが可能です。

## 今後の展望

今後は、さらに多くの英単語やフレーズを追加し、より多くの学習者に役立つコンテンツを提供していきます。また、ユーザーからのフィードバックを元に、ウェブサイトの改善を進めていく予定です。

「Let's English」は、英語学習をサポートする頼れるツールとなることを目指しています。ぜひ、お試しください。

以上が、「Let's English」のご紹介でした。ご興味がありましたら、ぜひご利用ください。
Azureサポートチケット関連APIを実行する

Azureのサポートチケット関連操作をAPIで実行する必要があり、いくつかAPIを試したので書き残します。

# アクセストークン取得

* Azure PortalにログインしてCloudShell(Bash)を開きます

* アクセストークンを取得します

```bash
token=`az account get-access-token | jq -r .accessToken`
```

# 各種API操作

## サポートチケット一覧取得

* 以下コマンドでサポートチケット一覧を取得できます

```bash
curl -X GET -L -H "Content-Type: application/json" -H "Authorization: Bearer $token" https://management.azure.com/subscriptions/[Subscription ID]/providers/Microsoft.Support/supportTickets?api-version=2020-04-01 | jq .
```

* 最も最近クローズになったサポートチケットのTicket Nameを取得します

```bash
curl -X GET -L -H "Content-Type: application/json" -H "Authorization: Bearer $token" https://management.azure.com/subscriptions/[Subscription ID]/providers/Microsoft.Support/supportTickets?api-version=2020-04-01 | jq -r '.value | map(select(.properties.status == "Closed")) | sort_by(.properties.modifiedDate) | reverse | .[0].name'
```

## サポートチケットの詳細取得

* 取得したTicket Nameを指定して、チケットの詳細を取得します

```bash
curl -X GET -L -H "Content-Type: application/json" -H "Authorization: Bearer $token" https://management.azure.com/subscriptions/[Subscription ID]/providers/Microsoft.Support/supportTickets/[Ticket Name]/communications?api-version=2020-04-01 | jq .
```

* やり取りが長い場合はnextLinkが出力されるので続きを取得できます

```bash
curl -X GET -L -H "Content-Type: application/json" -H "Authorization: Bearer $token" https://management.azure.com/subscriptions/[Subscription ID]/providers/Microsoft.Support/supportTickets/[Ticket Name]/communications?api-version=2020-04-01 | jq -r .nextLink

curl -X GET -L -H "Content-Type: application/json" -H "Authorization: Bearer $token" '[nextLink]' | jq .
```

以上です
Symbol Desktop Wallet の LevelDB データが残ってる場合のサルベージ

ログイン画面からプロファイルが消えてログイン出来ないけど、LevelDBファイルが残っている場合の秘密鍵サルベージ方法です。

流れは以下の通りです。

- LevelDBファイルから暗号化された秘密鍵を取得
- 復号のための生け贄になるプロファイルとアカウントをall版ウォレットで作成
- 生け贄アカウントデータに復元したいアカウントの暗号化秘密鍵を移植
- all版ウォレットのアカウントから秘密鍵表示


## ファイルが残っているか確認

プロファイルやアカウント情報は下記のフォルダのldbファイルまたはlogファイルに入ってます。ファイルがない場合は、残念ながら消えてしまっているので復元は不可能です。

`C:\Users\<ユーザー名>\.symbol-desktop-wallet\Local Storage\leveldb`


## データのバックアップ

間違って削除したり編集したりしても大丈夫なように、`.symbol-desktop-wallet`フォルダごとコピーしてバックアップしておきます。zipで圧縮しておくとアイコンも違うし間違って消したり編集したりすることが減ると思います。


## 秘密鍵のサルベージ

ldbファイルまたはlogファイルをテキストエディタで開きます。バイナリデータ(文字以外のデータ)も含まれるため、メモ帳ではなくサクラエディタなどが良いです。

ファイルを開いたら、復元したいアドレスを検索します。アドレスの少し後ろに`encryptedPrivateKey`があるので、その値をコピーします。最後が`=`の172文字です。

ここで、`encryptedPrivateKey`がない場合も復元は不可能です。

場合によっては、文字と文字の間にスペース(実際はヌル文字)が入っていることがあるので、よく探してください。

![スクリーンショット 2024-03-17 175021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622558/ba85a023-259d-a75f-ab9a-d1bf71e39e30.png)

ヌル文字は頑張って削除するか、サクラエディタを使用して置換する方法があります。
サクラエディタの方が簡単なのでそちらがお勧めです。
正規表現をオンにして、
置換前: `\x{00}`
置換後: (何も入力しない)
で置換すると綺麗になります。


## 秘密鍵の復号

ウォレットに復号する画面を追加しました。

https://github.com/ccHarvestasya/desktop-wallet-hv/releases/tag/symbol-desktop-wallet_1.0.13.hv24031701


ログイン画面の上部にある「Go to Tools」をクリック

![スクリーンショット 2024-03-17 185444.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622558/eabad430-0a01-be4e-829c-e1651a504970.png)

「Encrypted PrivateKey」に172文字の暗号化された秘密鍵を入力。
「Password」に暗号化された秘密鍵のあったプロファイルのパスワードを入力。
「Decrypt!!」ボタンを押すと復号されます。

![スクリーンショット 2024-03-17 185542.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622558/c1cc3598-4580-8609-e5c0-4e8919d93ada.png)


## 秘密鍵の復号(公式all版ウォレットを使用する場合)

ブラウザを使ってデータの編集が出来る、all版ウォレットで新しくプロファイルを作って、出来た新しいアカウントにさっきコピーした暗号化秘密鍵を移植して復号します。

https://github.com/symbol/desktop-wallet/releases

all版ウォレットをダウンロードし、***復号したいアカウントのプロファイルと同じパスワードで***プロファイルを作成します。

プロファイルが出来たら、一旦ログアウトして`F12`を押しデベロッパーツールを起動します。

アプリケーションを選択し、左ペインから`ローカルストレージ>http://localhost:8080`を選択します。

右ペインにキーと値が表示されるので、キーから`accounts`を探します。
その値の文字列の中にある`encryptedPrivateKey`を先ほどコピーした値に変更します。
(文字数が多いので、テキストエディタに貼り付けて編集したほうがやりやすいと思います)

![スクリーンショット 2024-03-17 101423.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622558/c1e3e020-6779-58d5-834a-bb1f2598891b.png)

`encryptedPrivateKey`の変更が終わったらログインします。

アカウントメニューを選択し、秘密鍵の表示ボタンを押してパスワードを入力すると、復元したいアドレスの秘密鍵が表示されるはずです。
(パスワードが異なるなどで失敗している場合は何も表示されないと思われます。)

![スクリーンショット 2024-03-17 103553.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3622558/5db0e500-dd4c-3da4-35f1-c593df8a3484.png)
ABC345回答メモ

# 0.はじめに
　最近調子を落としているので挽回したいところでしたが
 結果はC問題で大ブレーキがかかり、まぁなんとかACできましたが
 結果3問解けただけで、レートも-18の880となりました・・・。
 入茶が見えてきてしまった・・・。


# 1.A - Leftrightarrow
　1問目からなかなか歯ごたえのある問題。
 まぁ単純に実装しました。
 【考え方】
 　・状態遷移を記録する変数chk(初期値0)を用意する。
   ・先頭から文字列を見ていき、文字が<かつ、chkが0の時chkを1にする
   　<かつ、chkが0以外の時chkを9にする
   ・文字が=かつ、chkが1か2の時chkを2にする
   　=かつ、chkが1と2以外の時chkを9にする
   ・文字が>かつ、chkが2の時chkを3にする
   　>かつ、chkが3以外の時chkを9にする
   ・文字列を見終わった後、chkが3ならYesそれ以外ならNoを出力

　https://atcoder.jp/contests/abc345/submissions/51282024


# 2.B - Integer Division Returns
　打って変わってB問題にしては簡単・・・。かと思いつつ
 ちょっと工夫の必要な問題。
 まぁ、例題が罠ケースを網羅してたので罠にかからずに済みました。
 言語によっては実装方法変わるんだろうな・・・。

 Xが10で割り切れる場合は、Xを10で割った(//)値
 割り切れない場合はその値に1を加算した値を出力

 実装はXが正か負かで分けてましたが、今見直すとどちらのケースも同じ式に
 なってました・・・。
 
　https://atcoder.jp/contests/abc345/submissions/51289448


# 3.C - One Time Swap
　普通に考えたら、TLEになる問題。
 まぁ、交換すると考えると、自分と違う文字がどれだけあるかを
 保持して、それぞれと組み替えた分を合計して出力でAC!
 と思いきや、結構のエラーとなる。
 となって嵌りましたが、例題２のようなケースの時、横着して
 上のやり方で0になったら1を出力。というような適当な
 実装をしていたせいで、同一文字が2個ある場合はそれを入れ替えて
 元の文字列と同じになるパターンとして、1を加算しなければ
 いけなかったという点が漏れてました。
　実装時の問題を突き詰めずにいたために失敗してしまうという
 防げたミスが悔やまれます。 
 
　https://atcoder.jp/contests/abc345/submissions/51332263


以上
日本語のMoEモデル：Swallow-MX-8x7bが公開されました

先日、日本語のMoEモデル「Swallow-MX」（Mixtral-8x7Bの継続学習モデル）がHuggingFaceで公開されました。
精度は⇩の通りで、70Bモデル並みの性能を持っているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/5b6fb6c7-5264-19a9-530e-ad1ffd369e54.png)

私も試してみました。（Colabでは最大40GBのGPUしか使えないため、量子化されたggufバージョンを使用しました）

まず、いつも通りの最適化ユースケースについて聞いてみました。3つ指定したところ、なぜか8つの回答が返ってきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/ca973e2f-ad70-ec76-9aac-becb5461d37e.png)

次に、最近Claude3でほぼ完璧にできた最適化コードの生成も試しました。

制約条件までのコードは問題なく動作しましたが、制約条件に間違いがあったため、修正が必要だと感じました。
![屏幕截图 2024-03-16 180043.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/1c457b8b-b1aa-da74-5db9-73dc8c48e042.png)


興味ある方試してみてください：

Swallow-MX-8x7b:

https://zenn.dev/tokyotech_lm/articles/5f4211b9ed3197
while read を使用して、1行ずつ読み込み、一致する場合のみ出力させる

## 背景
既存のあるシェルスクリプトのSIテストをしていたところ、引数設定に漏れがあることを見つけた。そのため、その他のスクリプトにも同様の事象がないか確認する作業が必要となった。
数が多く検索をかけるのは時間がかかるため、シェルスクリプトを作成して作業時間の節約を行うことにした。

## 準備
検索対象の文字列が既にまとめられていたため、その対象文字列をサクラエディタに入力した。また、使用するtoolはlinuxであったため、改行コードはLFに変更し、保存した。

## 書式
```
while read line
 do 
     grep -r "$line" パス名
 done < ファイル名
```
### 処理の流れ
①"done < ファイル名"の部分で、ファイル名に記載されている文字列を読み込み、変数lineに格納する。
②grepにより、変数lineへ格納した文字列と指定したパス配下に存在するファイルの中に一致する文字列がある場合、出力される。
Apexで個人取引先レコードの作成

# はじめに
個人取引先は取引先・取引先責任者の両方の役割を持つため、レコード操作時にどのオブジェクトに対する操作なのか、その指定方法を調査しました。
# やりたかったこと
Visualforceページ上のinputフィールドで入力された情報から個人取引先レコードを作成する
# やり方
以下で指定で個人取引先レコードの作成が可能でした。
- オブジェクトは取引先
- レコードタイプは個人取引先レコードタイプ
```java:Apex
//変数を作成
Account newAccount = new Account();
//値を指定
newAccount.Name = '取引先名';
newAccount.RecordTypeId = 'ここに個人取引先レコードタイプID';

//取引先レコードを作成
insert newAccount;
```
レコードタイプIDは以下のように記述すると組織から自動的に取得可能
```java:Apex
private Id getPersonAccountRecordType() {
    List<RecordType> recordTypes = [
        SELECT Id
        FROM RecordType
        WHERE SobjectType = 'Account'
        AND DeveloperName = 'PersonAccount'
        LIMIT 1
    ];
    if (!recordTypes.isEmpty()) {
        return recordTypes[0].Id;
    }
    return null; // 適切なレコードタイプが見つからない場合
}
```
以下は個人取引先レコードタイプIDの取得→個人取引先レコードの作成のコード例
```java:Apex
// レコードタイプIDを取得するメソッド
private Id getPersonAccountRecordType() {
    List<RecordType> recordTypes = [
        SELECT Id
        FROM RecordType
        WHERE SobjectType = 'Account'
        AND DeveloperName = 'PersonAccount'
        LIMIT 1
    ];
    if (!recordTypes.isEmpty()) {
        return recordTypes[0].Id;
    }
    return null; // 適切なレコードタイプが見つからない場合
}

// 新しい取引先レコードを作成して挿入する
public void createPersonAccount() {
    Id recordTypeId = getPersonAccountRecordType(); // レコードタイプIDを取得
    if (recordTypeId != null) {
        Account newAccount = new Account();
        newAccount.Name = '新しい取引先';
        newAccount.RecordTypeId = recordTypeId; // レコードタイプIDを設定
        insert newAccount;
    } else {
        // レコードタイプIDが取得できなかった場合の処理
    }
}
```
取引先責任者の項目に対して値をセットしたい場合は、取引先オブジェクトでの項目名（取引先責任者の項目名__pc）を指定するとセットできます。
# おわりに
公式のドキュメントなど読んでみたが、クエリの操作などに関する内容しか書いてなかったため、上記方法が参考になればと思います！
# プログラミングコミュニティの紹介
Reactを１から実践レベルまで身につけることができるサービス「JISOU」では現在メンバーを募集中です。
気になる方は以下のHPのLINEからお問合せください。
https://projisou.jp
# 会社の紹介
この記事を最後まで読んでいただき、ありがとうございます！
私がエンジニアとして働いているViVO株式会社では、SalesforceやYextといったSaaSシステムに関わるエンジニアを募集しています。
経験者の方はもちろん、未経験者でもチャレンジしたいという熱意があれば大歓迎です。

技術的な経験がない方でも成長できるよう全面的にサポートする環境を提供しています。

もし少しでも興味を持っていただけたら、以下のURLまたは私にDMでご連絡ください。
https://vivojpn.com
【iOS】初心者が公式Sample AppをながらARKitとかMetalを理解する②

# はじめに

こんにちは、プログラミングを始めて約3年のエンジニアのkeitaMaxです。

今回はポイントクラウドのサンプルアプリと、公式を見ながらARKitとかMetalとか、ついでにSwift UIとかをふんわりと理解していこうの②です。

前回の記事

https://qiita.com/keitaMax/items/468afa789368eabe646a


下にあるサンプルアプリで色々学んでいきます。

https://developer.apple.com/documentation/arkit/arkit_in_ios/environmental_analysis/displaying_a_point_cloud_using_scene_depth


# ARDataProviderをみる

前回、点群情報をARDataProviderファイルの`onNewARData()`に渡しているところで終わったので、この続きからみていこうと思います。

```swift
func onNewARData(arData: ARData) {
    lastArData = arData
    processLastArData()
}
```
`lastArData`に取得した`arData`を入れていました。

そのあと`processLastArData`の関数をしています。

ここで`colorYContent.texture`と`colorCbCrContent.texture`に`arData`を入れています。

### processLastArData

`colorYContent`は`MetalTextureContent()`が初期の値として入っています。

>フォーマットされた画像データを保持するリソース。

どうやら、画像データを保持するクラスのようです。

### 色の保存

```swift
colorYContent.texture = lastArData?.colorImage?.texture(withFormat: .r8Unorm, planeIndex: 0, addToCache: textureCache!)!
colorCbCrContent.texture = lastArData?.colorImage?.texture(withFormat: .rg8Unorm, planeIndex: 1, addToCache: textureCache!)!
```

この処理の解説として、

>サンプル プロジェクトでは、GPU コードで各ポイントに色を付けているため、CPU 側は GPU で使用できるようにカメラ データをパッケージ化します。

と記載されています。

点群に色をつけるためのカメラデータを、GPUで使用できる形にして保存しているらしいです。

### 深度データの保存

```swift
if isUseSmoothedDepthForUpsampling {
    depthContent.texture = lastArData?.depthSmoothImage?.texture(withFormat: .r32Float, planeIndex: 0, addToCache: textureCache!)!
    confidenceContent.texture = lastArData?.confidenceSmoothImage?.texture(withFormat: .r8Unorm, planeIndex: 0, addToCache: textureCache!)!
} else {
    depthContent.texture = lastArData?.depthImage?.texture(withFormat: .r32Float, planeIndex: 0, addToCache: textureCache!)!
    confidenceContent.texture = lastArData?.confidenceImage?.texture(withFormat: .r8Unorm, planeIndex: 0, addToCache: textureCache!)!
}
```
この処理の解説として、

>サンプル プロジェクトでは、GPU コードで各ポイントを配置するため、CPU 側は GPU で使用するために深度データを Metal テクスチャにパッケージ化します。

となっています。

点群データの深度データを保存しています。

その後、`MTLCommandQueue`にいろいろな値を渡しています。

### MTLCommandQueue

>これらのバッファ内でコマンドを実行するために、特定のGPUデバイスにコマンドバッファを作成、送信、およびスケジュールするために使用するインスタンス。

GPU側に処理を渡すためのものらしいです。

`MTLCommandQueue`に画像データと深度データを渡しています。

そして、最初に見た画面を表示しているファイルの`MetalViewSample`の`var arProvider: ARProvider = ARProvider()`に戻ってくるのですが、そこで実際に点群を表示する処理に行っていそうです。



# おわりに

今回はここまでにします。次回以降はこの続きからいこうと思います。

結構難しくて、なかなか理解できないですが、諦めずに色々見ていこうと思います。

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。（公式みて自分なりに理解しているだけなので、少しでも「ん？」と思うことがあったら教えていただけると助かります。）

最後まで読んでいただきありがとうございました！


# 参考文献

https://developer.apple.com/documentation/arkit/arkit_in_ios/environmental_analysis/displaying_a_point_cloud_using_scene_depth

# 次の記事
Pythonで、lzhファイルを解凍する方法（Win版・7z利用）

## 背景
python上でlzhファイルを解凍する必要性が出てきたが、標準ライブラリで解凍する機能が備わっておらず、ググるとよく出てくるライブラリ（lhafile）もインポートできなくて困っていた。
いろいろ探って試した結果、以下のやり方が簡単かなと思った。

## 準備
7zのサイト上のhowtoページにあるexeファイルをダウンロードし、任意の場所に置いておく。コードの例では、実行ファイルと同じ階層においている。
https://7-zip.opensource.jp/howto/9.20/7z.exe

## コード
```python
import subprocess

# 解凍したい対象のファイルパスを変数に入れる
targetfile = r"C:\Temp\test.lzh"

# subprocessで7z.exeを呼び出し、引数にe(解凍の命令)とファイルパスを指定する
subprocess.run("7z.exe e " + targetfile)
```
Ansibleのconfigファイルの適応方法

# はじめに
Ansibleのconfigファイルの適応する際に，configファイルをどこに配置すれば適応できるか迷ったことはありませんか？この記事はそんな人のための記事です．


# Ansibleのインストール
venvとpipを用いてAnsibleをインストールします．venvはPythonの仮想環境で，venvを起動している間にライブラリをインストールすることで，もとのPythonにインストールされずに仮想的なPython環境を構築することができます．venvを起動している間はインストールしたライブラリやコマンドを使うことができるようになります．venvを停止している間はvenv起動中にインストールしたライブラリやコマンドを使うことができなくなります．

Ansibleはvenvでインストールすることで，Ansibleコマンドを実行することが簡単にできるので，venvを用いたインストール方法をしています．

Pythonの仮想環境venvの作成
```shell
python3 -m venv .vemv
```

Pythonの仮想環境のvenvの起動
```shell
. .venv/bin/activate
```


Ansibleのインストール
```shell
pip install ansible
```

Ansibleのバージョン確認
```shell
ansible --version
```

実行結果
```shell-session
ansible [core 2.15.0]
  config file = None
  configured module search path = ['/home/c0118050/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/c0118050/ansible/.venv/lib/python3.10/site-packages/ansible
  ansible collection location = /home/c0118050/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/c0118050/ansible/.venv/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/home/c0118050/ansible/.venv/bin/python3)
  jinja version = 3.1.2
  libyaml = True
```

注目して欲しいのは`config file = None`この部分です．今のままだとconfigファイルは適応されていません．そのため，`.venv`があるディレクトリと同じディレクトリに`ansible.cfg`を作成します．

`executable location = /home/c0118050/ansible/.venv/bin/ansible`とあるので，`/home/c0118050/ansible/`ディレクトリに`ansible.cfg`に作成しましょう！

# ansible.cfgの作成と適応

```shell
vim ansible.cfg 
```

今回は仮に`forks = 20`を設定します．これを設定することでAnsibleの並列実行数を20にできます．
```ansible.cfg
[defaults]
forks = 20
```

Ansibleのバージョンを確認するコマンドでconfgファイルが適応されたか確認しましょう．
```shell
ansible --version
```

```shell-session
ansible [core 2.15.0]
  config file = /home/c0118050/ansible/ansible.cfg
  configured module search path = ['/home/c0118050/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/c0118050/ansible/.venv/lib/python3.10/site-packages/ansible
  ansible collection location = /home/c0118050/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/c0118050/ansible/.venv/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/home/c0118050/ansible/.venv/bin/python3)
  jinja version = 3.1.2
  libyaml = True
```
`config file = /home/c0118050/ansible/ansible.cfg`となっていますね．config fileが適応されました！
【Excel】くじ引き、ルーレット、ランダムで人を決めたい時

何かの担当をランダムに決めたいこと、ありますよね。
オフラインならジャンケンすればいいんですが、オンラインだとタイムラグあるしジャンケンはやりづらい。
くじ引き、ルーレットのサイトなんかもありますが、Excelで30秒ぐらいで作れたりもします。

# Excel（スプレッドシート）でランダムに人を決める方法
RAND関数を使います。
最大値もしくは最小値の人が担当するルールにします。

Excelならなんかのセルに入って（F2キー）出るだけでランダム数が書き換えられます。
フィルターつけて降順に並び替えるとランダムな並び順を作れたりもします。

下半分は明示的に「この人です！」と表示するための関数ですが、別に不要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3736028/5657a4fe-5a30-012a-955a-2f1b633958a4.png)
【Android】起動したWorkerを停止させる方法

# はじめに
皆さん、Worker使っていますか？
Serviceへの風当たりがどんどん強くなる今日この頃ですが、公式でもできる限りWorkerへの置き換えを推奨しているご状況です。
以前にもWorkerの取り扱いについて触れましたが、仕様の変更や何らかの問題が発生した際にすでに起動中のWorkerを止めなければならないケースが発生した場合、単純に処理を消すだけではWorkerは止まりません。
明確に停止する必要がありますので、今回は備忘録的にWorkerの停止方法をまとめておこうと思います。

# Workerの停止方法
Workerの停止方法には3通りのやり方があります。

```main.kt
val workManager = WorkManager.getInstance(context)

// by id
workManager.cancelWorkById(syncWorker.id)

// by name
workManager.cancelUniqueWork("sync")

// by tag
workManager.cancelAllWorkByTag("syncTag")

```
以上になります。
注意点として、cancelAllWorkByTagは名前の通り同じタグ名を持つWorkerを全て停止させます。
もしキャンセルしたくないWorkerとタグ名が被ってしまっている場合は使えないのでご注意ください。

上記でキャンセルすることで、Workerの状態はCANCELLED状態となり、処理が実行されなくなるというわけです。
ご説明は以上になります。

# さいごに
ようやくDovlak配列を運用していく上での解が出ました、次回の記事はDovlak Loverへ捧げたいと思います！
wslで、最小のカーネルをコンパイル その14

# 概要
wslで、kernel.elfのコンパイル、やってみた。
cで、書いたカーネルで、俺言語を組み込んだ。
じゃんけんを実行させるため、拡張する。
構想編

# じゃんけんのソースコード

1 goo 2 choki 3 par

```


10 a=?
20 #=a<1*10
30 c=!
40 #=c=1*80
50 #=c=2*120
60 #=c=3*160
70 #=10
80 #=b=1*200
90 #=b=2*240
100 #=b=3*220
110 #=10
120 #=b=1*220
130 #=b=2*200
140 #=b=3*240
150 #=10
160 #=b=1*240
170 #=b=2*220
180 #=b=3*200
190 #=10
200 ?="aiko"
210 #=10
220 ?="kati"
230 #=10
240 ?="make"
250 #=10

```



# 必要な拡張。

- a=?
?で、キー入力
- c=!
!で、乱数

# キー入力

```
void facto() {
	unsigned char cc;
	char ch;
	char sc;
	if (RD(Ptr) == '\0')
	{
		Val = 0;
		return;
	}
	if (getnm2())
		return;
	cc = RD(Ptr++);
	if (cc == '?')
	{
		sleep(0x01FFFFFF);
		putstr("> ");
		sc = scan();
		ch = lower_ascii_codes[sc];
		if (ch == 0x31)
			Val = 1;
		else if (ch == 0x32)
			Val = 2;
		else if (ch == 0x33)
			Val = 3;
		else
			Val = 0;
	}
	else if (cc == '$')
	{
		Val = 55;
	}
	else if (cc == '!')
	{
		Val = 33;
	}
	else
	{
		Ptr--;
		getvr2();
		Val = RD(Adr2);
		Ptr++;
	}
}
```

# 乱数

```
char randseed = 123;
char rand(void) {
	return (randseed = randseed * 5 - 1);
}
```


以上。
AWS 全資格取得　未経験50才の挑戦

こんにちは

このたび、AWS全12資格に合格しましたので、その体験記を記載したいと思います。

【背景】
今年、52才となる中年男性。20数年営業を経験し、現在、コンサルタントとして活動。

【契機】
国産クラウドで、お客様との協業ビジネスを担当した2010年、AWSが徐々に台頭してくる中、なんとか、自社国産クラウドを死守。したものの、数年後、自身が担当から外れた後に、AWSにリプレイスされる。

負けた悔しさ、負けて当たり前だったか、負けたままでは、いられないとずっと思っていた。

【転機】
営業不要論、リスキリングブームの中、2023年、20数年勤務した会社を退社。本来、自分がやりたかった、ビジネスマン人生を振り返ったとき、後悔のないことを考えた時、AWSから逃げることはできなかった。クラウドが好きだった。”夢から逃げるな:baseball:”
そう思ったら、自ずとAWS12資格取得を目指していた。

【経緯】
・CLF 2021年11月
・SAA 2022年 8月
・DVA 2023年 2月　この時、20数年勤めた会社を退社。
・以降、2023年6月から2024年3月で残りの9資格を取得。（10ヶ月で9資格）

【勉強方法】
とにかく、問題集を解く。わからないことが前提なので、わからないことに立ち止まるのではなく、わからないことを問題集を解きながら、洗い出し、そこから、重要な仕組み、サービスを徹底的に調べる。

【利用した教材】
・Blackbelt
・CLoudtech
・CloudLicense
・Kindle 問題集
・Youtube

【まとめ】
未経験、営業出身、50歳　並んだ言葉からは、想像もし難いことであったが、諦めない気持ち、そんな気持ちがあれば、やり遂げることが出来る。と思いました。昨今、肩身が狭い境遇に立たされている方へのエールと少しの勇気になればと思い、投稿させて頂きました。:sunny:

![スクリーンショット 2024-03-17 7.29.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2050732/1f9d78ef-ab8b-de08-7511-8947074a9682.png)

https://www.credly.com/users/tetsuya-suzuki.8ae96aae/badges
ルートテーブルの設定ミスのせいでEC2インスタンスに接続出来なかった話

# 事象
私「初めてだけどudemyのハンズオンやってみよ！へ～～こんな感じなのか」
私「パブリックサブネットとプライベートサブネット作って……それぞれEC2インスタンスに紐づけて……**なんだ簡単じゃん！**」
私「Teratermで接続しましょ！」
Teratermくん **「繋がらんで笑」**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/32f27ad2-b2aa-50e3-58e1-344136ec6e66.png)
私「**ハンズオン通りにやった**やろがい！！！！」

# とりあえず設定を見返してみる
私「ssh接続できないってことはどうせネットワークの問題」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/9ef1bedb-284a-17bb-1ad5-dc3db95c841b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/b42a997a-301f-7a25-8edf-c04d52f4123e.png)
私「はいここ！」
私「VPCのルートテーブルで設定した値がおかしかったのか……」
私「じゃあここを**ハンズオン通りに**直して……」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/53099f99-3160-9768-0377-d4ced77e786e.png)

Teratermくん **「繋がったで！！！」**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/b42a677e-678c-bfb1-3d87-892675bffa6a.png)

# 原因
私「パブリックサブネットのルートテーブルがインターネットゲートウェイじゃなくてNATゲートウェイに向いてなかったのが良くなかったから、インターネットゲートウェイを向くように設定する必要があったのね（説明口調）」

# 学んだこと
1. 手順書見ても間違えることがあるのだからハンズオン動画通りにやっても間違える
1. 怪しいところへの目星を付ける力が多少ついてきた

# 【参考文献】
https://go-journey.club/archives/12101
CSSのtouch-actionプロパティでハマった話（画像版）


## タイトルのパクリ元

https://qiita.com/CafeOreco/items/2376a9bb5c9ef3f3b2a8

## 問題のコード

```css
body {
  touch-action: manipulation;
}
```
## 何が起こったか

imgタグの画像を長押ししても「画像をダウンロードする」のやつが出ない！
スマホのブラウザの仕様なのかな～。なんて馬鹿なことを考えて無駄にハマってしまった。

冷静に考えたらタッチアクションを制限してるんだから当たり前だろって話。

そんだけ。

## 修正方法

```diff_css
body {
  touch-action: manipulation;
}

+ img {
+   touch-action: auto;
+ }
```
競プロ用のチートシート（Python）

# はじめに
競プロで使う Python のチートシートを載せています。

# 標準入力
:::note warn
記号は次の意味で使い分けています。
整数：$N, M, A_i, B_i, H, W$
文字列：$S, T, S_i$
:::

> $N$
> ```py
> n = int(input())
> ```

> $N$ $M$
> ```py
> n, m = map(int, input().split())
> ```

> $N$
> $A_1$ $A_2$ $\dots$ $A_N$
> ```py
> n = int(input())
> a = list(map(int, input().split()))
> ```

> $N$
> $A_1$
> $A_2$
> $\vdots$
> $A_N$
> ```py
> n = int(input())
> a = [int(input()) for _ in range(n)]
> ```

> $N$
> $A_1$ $B_1$
> $A_2$ $B_2$
> $\vdots$
> $A_N$ $B_N$
> ```py
> n = int(input())
> ab = [list(map(int, input().split())) for _ in range(n)]
> ```

> $H$ $W$
> $A_{1,1}$ $A_{1,2}$ $\dots$ $A_{1,W}$
> $A_{2,1}$ $A_{2,2}$ $\dots$ $A_{2,W}$
> $\vdots$
> $A_{H,1}$ $A_{H,2}$ $\dots$ $A_{H,W}$
> ```py
> h, w = map(int, input().split())
> a = [list(map(int, input().split())) for _ in range(h)]
> ```

> $S$
> ```py
> s = input()
> ```

> $S$ $T$
> ```py
> s, t = input().split()
> ```

> $N$
> $S_1$
> $S_2$
> $\vdots$
> $S_N$
> ```py
> n = int(input())
> s = [input() for _ in range(n)]
> ```

# 型変換
:::note warn
記号は次の意味で使い分けています。
整数：$N$
文字列：$S$
整数のリスト：$L_N$
文字列のリスト：$L_S$
:::

:::note alert
型変換は期待通りの結果にならない場合があります。
例えば、$S$ $\rightarrow$ $N$ では、 $S$ がアルファベットや漢字などアラビア数字以外の文字を含む場合は期待通りの結果になりません。
:::

> $N$ $\rightarrow$ $S$
> 例：123 $\rightarrow$ "123"
> ```py
> s = str(n)
> ```

> $N$ $\rightarrow$ $L_N$
> 例：123 $\rightarrow$ [1, 2, 3]
> ```py
> l_n = list(map(int, str(n)))
> ```

> $N$ $\rightarrow$ $L_S$
> 例：123 $\rightarrow$ ["1", "2", "3"]
> ```py
> l_s = list(str(n))
> ```

> $S$ $\rightarrow$ $N$
> 例："123" $\rightarrow$ 123
> ```py
> n = int(s)
> ```

> $S$ $\rightarrow$ $L_N$
> 例："123" $\rightarrow$ [1, 2, 3]
> ```py
> l_n = list(map(int, str(s)))
> ```

> $S$ $\rightarrow$ $L_S$
> 例："123" $\rightarrow$ ["1", "2", "3"]
> ```py
> l_s = list(s)
> ```

> $L_N$ $\rightarrow$ $N$
> 例：[1, 2, 3] $\rightarrow$ 123
> ```py
> n = int("".join(map(str, l_n)))
> ```

> $L_N$ $\rightarrow$ $S$
> 例：[1, 2, 3] $\rightarrow$ "123"
> ```py
> s = "".join(map(str, l_n))
> ```

> $L_N$ $\rightarrow$ $L_S$
> 例：[1, 2, 3] $\rightarrow$ ["1", "2", "3"]
> ```py
> L_s = list(map(str, l_n))
> ```

> $L_S$ $\rightarrow$ $N$
> 例：["1", "2", "3"] $\rightarrow$ 123
> ```py
> n = int("".join(l_s))
> ```

> $L_S$ $\rightarrow$ $S$
> 例：["1", "2", "3"] $\rightarrow$ "123"
> ```py
> s = "".join(l_s)
> ```

> $L_S$ $\rightarrow$ $L_N$
> 例：["1", "2", "3"] $\rightarrow$ [1, 2, 3]
> ```py
> l_n = list(map(int, l_s))
> ```
出る確率を調整できるサイコロ

前の投稿で、サイコロを指定回数振るプログラムを書きました。今回はサイコロの確率を変更できるプログラムを作成します。

下記サイトを参考にしています。
[出る確率を調整できるランダムテキスト（インチキサイコロ）](http://alphasis.info/2014/03/javascript-sample-fakedice/)
元サイトのプログラムは変数定義されていなかったりして動かせなかったので動作するようにし、こちら側で確率を操作できように修正しました。
numberInputsの中に正の数値を入れて、その数が大きいほど、出やすくなります。何も入れない場合は全て同じ確率でサイコロが振られます。どのくらいの確率になるかはprobabilityTextに表示されます。


```html
<p>
  <button id="diceThrowButton">サイコロを振る</button>
</p>
<p>
  1<input type="number" class="numberInputs">
  2<input type="number" class="numberInputs">
  3<input type="number" class="numberInputs">
  4<input type="number" class="numberInputs">
  5<input type="number" class="numberInputs">
  6<input type="number" class="numberInputs">
</p>
<ol>
  <li class="probabilityText">0%</li>
  <li class="probabilityText">0%</li>
  <li class="probabilityText">0%</li>
  <li class="probabilityText">0%</li>
  <li class="probabilityText">0%</li>
  <li class="probabilityText">0%</li>
</ol>
```
```js
const diceThrowButton = document.querySelector("#diceThrowButton")
diceThrowButton.addEventListener('click', fakeDice)

function fakeDice() {
  const probability = new Array()
  const numberInputs = document.querySelectorAll(".numberInputs")

  numberInputs.forEach(function (numberInput, index) {
    probability[index] = Number(numberInput.value) || 1
  })

  const sumAll = probability.reduce((sum, num) => sum + num, 0)
  const probabilityText = document.querySelectorAll(".probabilityText")
  const $text = [1, 2, 3, 4, 5, 6]

  let randomSum = Math.floor(Math.random() * sumAll)
  let randomSumA = 0
  let randomSumB = 0

  randomSum++
  for (let i = 0; i <= probability.length - 1; i++) {
    const probabilityNumber = Math.round(probability[i] / sumAll * 1000) / 10
    probabilityText[i].textContent = probabilityNumber + '%'

    randomSumB = randomSumA
    randomSumA += probability[i]

    if (randomSumB < randomSum && randomSum <= randomSumA) {
      console.log($text[i])
    }
  }
}
```
Docker 学習記録

Dockerを利用する目的
----------------------------
* OSに依存せず、コードを実行できる
    * OS依存による弊害として、ライブラリはOSによって異なるため、OSの差異によって正常に動作しなくなる

解決策として、コードとライブラリをパッケージング化することで、別チームへパッケージングしたファイルを渡すことで、OSの依存関係を考慮せず、コードを実行できる

※コードとライブラリをパッケージングすることをコンテナ化と呼ぶ。コンテナ化の元にファイルは、docker imageと呼ぶ

※ライブラリとは
よく使われるアルゴリズムをまとめているのがライブラリ

OS仮想化とDockerの違い
----------------------------
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3146038/aa69ae3a-b9e9-07e5-c71b-a15da59b7292.png)

* 仮想マシン
1つのOS上に複数の仮想OSをインストールし、OSを実行する

* コンテナ
1つのOSにDocker engineを起動して複数のコンテナを起動する

メリット
----------------------------
* OSを利用しないため、リソースの使用量を抑えることができる
    * 仮想マシンを経由する必要がないため、オーバーヘッドとプロセッサやメモリの消費を減らすことでき
    * ストレージの使用量を減らすことできる
    * 起動時間が早い
* Dockerがインストールされていれば、OSに依存せずコンテナを起動することできる

Dockerを利用するフロー
----------------------------
1.docker imageをpullする
2.リポジトリにアップロードする
3.使用したい環境でdocker imageをダウンロードする
4.コンテナを起動する

今回は、1.docker imageをpullと4.imageの起動まで

```
# docker hubから最新のnginxのイメージを取得
docker pull nginx 

# 取得したイメージを確認
$ docker images
REPOSITORY     TAG       IMAGE ID       CREATED        SIZE
nginx          latest    92b11f67642b   4 weeks ago    187MB

# 取得したnginxのdocker imagesを起動する
docker run -p 80:80 --rm -d --name nginx nginx
e98d25e851821f4fb00c08be357d79e68e853b61d5d3cf4e5304becd3b870388

# 起動確認
docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED         STATUS         PORTS                  NAMES
e98d25e85182   nginx          "/docker-entrypoint.…"   5 seconds ago   Up 3 seconds   0.0.0.0:80->80/tcp   nginx

# 起動したコンテナにログインする
docker exec -it コンテナ名※1 bash
root@e98d25e85182:/# 

# ログアウトする
root@e98d25e85182:/# exit 
exit

# コンテナを停止する
docker stop nginx
nginx

# コンテナの状態確認
docker ps
CONTAINER ID   IMAGE          COMMAND                   CREATED        STATUS        PORTS                NAMES

# 停止したコンテナが削除されたことを確認
docker ps -a
CONTAINER ID   IMAGE          COMMAND                   CREATED        STATUS        PORTS                NAMES

```
* docker run コンテナを作成と起動するコマンド
    * -p ポートを指定する ホスト側:nginx側
    * -rm 終了したコンテナを削除する
※コンテナのログ情報など取得できなくなるため、用途に応じてオプションを付ける
終了したコンテナが残り続けるのが嫌なので、オプションを加える
    * -d デタッチ バックグラウンドでコンテナを起動する
    *  -name 起動するdocker image tag名

* docker exec コマンドは、コンテナ内で作業するコマンド
    * -it をつけることで、Terratermのように作業ができる
    * bash 使用するシェルを指定する、shでも可

* docker ps -a
    * -a すべてのコンテナを表示    

備考
初期のコンテナに一般的なコマンド等が使えない

docker cpコマンド
docker cp ./file1.txt hip:/tmp   ホストからコンテナにコピー
※hipはコンテナ名を指す
sed 
あまり、おすすめしないかも

3/20までにimagesの作成とレイヤー、ボリューム系を少しやりたい

https://www.tohoho-web.com/docker/docker_cp.html
https://tellingbook.com/docker-container-name/
VBAからサクラエディタのGrepを実行し、その結果をVBA上で扱う

サクラエディタはコマンドラインからGrepを実行し、その結果を標準出力に出力することができます。

https://qiita.com/neko_the_shadow/items/36dfefa4f824dbc5a966

この機能を利用すると、VBAからサクラエディタのGrepを実行し、その結果をVBA上で扱うことが可能です。

**サンプルコード**

対象のフォルダの配下にあるjavaファイルをGrepし、その結果をResultシートのA列に書き出す。

```vb
Sub Main()
    ' 必要な値を定義する
    Dim sakura As String
    Dim gkey As String
    Dim gfolder As String
    Dim gfile As String
    
    sakura = "C:\Program Files (x86)\sakura\sakura.exe"
    gkey = "検索ワード"
    gfolder = "C:\Path\To\Folder"
    gfile = "*.java"
    
    ' コマンドを組み立てる
    Dim command As String
    command = "{0} -GREPMODE -GCODE=99 -GOPT=SPHU -GKEY={1} -GFOLDER={2} -GFILE={3}"
    command = Replace(command, "{0}", """" & sakuraPath & """")
    command = Replace(command, "{1}", """" & gkey & """")
    command = Replace(command, "{2}", """" & gfolder & """")
    command = Replace(command, "{3}", """" & gfile & """")
    
    ' コマンドを実行する
    Dim ws, wse
    Set ws = CreateObject("WScript.Shell")
    Set wse = ws.Exec(command)
    
    ' 実行したコマンドの標準出力を1行づつ読み込み、配列に格納する。
    Dim lines As Collection
    Set lines = New Collection
    Do Until wse.StdOut.AtEndOfStream
        lines.Add wse.StdOut.ReadLine
    Loop
    
    ' コマンドの実行結果をResultシートのA列に書き出す
    Dim line As String
    Dim i As Long
    For i = 1 To lines.Count
        line = lines(i)
        ThisWorkbook.Worksheets("Result").Range("A" & i) = line
    Next i
End Sub
```

**環境情報**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/5ba63ffe-c038-5bd7-b5dc-a6b7d83ce166.png)
競プロにおけるオーバーフローのチートシート

# はじめに
競プロでオーバーフローしているか気づけないことがあるので、整数型の上限値を確認できるチートシートを作成しました。整数型の名称は Rust 言語で表記しています。他言語での int は i32 で、 long は i64 です。

# チートシート
|    |およそ           |上限値|
|:-  |:-              |:-                                       |
|i32 |$2\times10^9$   |$2147483647$                             |
|i64 |$9\times10^{18}$|$9223372036854775807$                    |
|i128|$1\times10^{38}$|$170141183460469231731687303715884105727$|
|u32 |$4\times10^9$   |$4294967295$                             |
|u64 |$1\times10^{19}$|$18446744073709551615$                   |
|u128|$3\times10^{38}$|$340282366920938463463374607431768211455$|
INとEXISTSの実行時間を比較:SQLチューニング#3

### INとEXISTSについて

どちらも複数の条件判定をまとめて行うために使用するものですが、以下のような違いがあります。

**IN** 条件に当てはまるデータをすべて抽出

**EXISTS** 条件に当てはまるデータが存在するかどうかをtrueまたはfalseで返す

### INとEXISTSを比較した結果

同じ検索条件で同じテーブルを検索しても、EXISTSを使用した時の方が若干ですがSQLの実行速度が速くなりました。

### INの実行時間を測ってみる
以下の画像のような構造の、addressテーブルのすべてのカラムのデータを、address2テーブルにlocal_goverment_cdが存在するものという検索条件で検索します。

![addressテーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/ce33b2a0-25c8-a45e-8e6d-1d4c77be02d8.png)

![address2テーブル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/8861500d-d783-0975-1e68-dbe4061f44c0.png)

![IN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/e34342f8-e6b2-8bb3-9df0-6e792594d81e.png)

### EXISTSの実行時間を測ってみる

INと同じ条件で今度はEXISTSを使用したSQLを実行し時間を測定します

![EXIST.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3533750/6efcd2b6-276b-afa5-2a2e-f8a8acb71de9.png)

画像の下部にある実行時間のように、IN使用時は4.257秒、EXISTS使用時は4.136秒となり
EXISTSの方が実行時間が速いことがわかりました。

以上です。ここまで読んで頂きありがとうございました。

### 参考文献

「達人に学ぶSQL徹底指南書」ミック著　翔泳社
PowerShellで送信メールを作成する

# きっかけ

毎日メールで日報を送信するのですが、テキストファイルに入力した
本文、件名、宛先を１つずつペタペタ張り付けて作るのが面倒になり、
少しでも自動化しようと考えました。

エクセルのマクロを使えれば、日付や記載内容等をもっと自動化したり、
他の管理につかえたり出来るのですが、環境的にマクロを使えない為、
PowerShellを使う事にしました。

# やりたかった事

- 実行するとOutlookのメールを作成してくれる
- テキストファイルに記載したものをメール本文に転記
- 件名には送信する日付を埋め込む(フォーマット指定あり)
- 宛先は固定
- メールは作成してポップアップまで　(自動送信はしない)　**←ここ大事**

## スクリプトとテキストファイルの配置構成
![スクリプトとテキストファイルの配置構成.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214030/e01e968d-6c7d-351f-dc8f-cfb6b43c917b.jpeg)


```PowerShell:MakeMail.ps1
# スクリプトを実行した年月日を取得
$currentDate = Get-Date
$year = $currentDate.Year
$month = $currentDate.Month
$day = $currentDate.Day

# フォルダとファイルのパスを構築
$folderPath = Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath $year) -ChildPath $month"月"
$filePath = Join-Path -Path $folderPath -ChildPath "日報_$($currentDate.ToString('yyyyMMdd')).txt"

# フォルダが存在しない場合は作成
if (-not (Test-Path -Path $folderPath)) {
    New-Item -Path $folderPath -ItemType Directory
}

# テキストファイルを読み込む
if (Test-Path -Path $filePath) {
    $mailContent = Get-Content -Path $filePath -Raw
} else {
    Write-Host "Error: テキストファイルが見つかりません。"
    exit 1
}

# メールの件名を作成
$mailSubject = "業務報告 $($currentDate.ToString('yyyy.MM.dd')) 〇〇〇〇"

# メールの宛先を指定
$mailTo = "test@example.com"

# メール本文にテキストファイルの内容を張り付ける
$mailBody = $mailContent

# Outlookでメールを新規作成
$outlook = New-Object -ComObject Outlook.Application
$mail = $outlook.CreateItem(0)
$mail.Subject = $mailSubject
$mail.To = $mailTo
$mail.Body = $mailBody

# メールを送信せずに終了
$mail.Display() | Out-Null
```
3値量子化パラメータを学習できるオプティマイザを作った【PyTorch】

# はじめに

2024年2月28日、Microsoft より BitNet b1.58 というモデルの論文[^1]が公開されました。
この論文は量子化されたモデルを学習する手法を提案しており、精度は落とさずに推論の速度やメモリ消費量を改善できるという内容です。

このモデルの中で重みは `{0, -1, 1}` の3値で表現されており、にも関わらず学習ができているという点に感銘を受け、以下に紹介するオプティマイザを作成しました。

(BitNet を実装するという話ではありません。オプティマイザでこんな事ができるよという話です)

# TernaryOpt

3値で量子化されたパラメータを学習できる pytorch のオプティマイザを作りました。これを *TernaryOpt* と呼ぶことにします。
このオプティマイザを使用して学習したすべての重みは `0`, `-γ`, `γ` のいずれか値をとります。ここで `γ` は分散を調整するための値です。

TernaryOpt を使用する利点として、パラメータの保存方法を工夫すればモデルファイルのサイズ軽量化が可能になります。

TernaryOpt は既存のオプティマイザを継承することで定義されます。基底クラスとなるオプティマイザは任意に差し替えることができます。

TernaryOpt はただのオプティマイザであるため、既存のモデルに適用することが容易です。

以下が TernaryOpt の全文です。

``` py
from torch import optim

class TernaryOpt(optim.Adam): # <- 基底クラスは任意に置き換え可能
    def __init__(self, *args, **kwargs):
        self.norm = kwargs.pop('norm', True)

        super(TernaryOpt, self).__init__(*args, **kwargs)

    def step(self, closure = None) -> None:
        for group in self.param_groups:
            for p in group['params']:
                if 'raw' in self.state[p]:
                    p.data = self.state[p]['raw']

        super(TernaryOpt, self).step(closure)

        for group in self.param_groups:
            for p in group['params']:
                self.state[p]['raw'] = p.data
                if self.norm:
                    gamma = p.data.abs().mean()
                    p.data = (p.data / gamma).round().clamp(-1, 1) * gamma
                else:
                    p.data = p.data.round().clamp(-1, 1)
```

# アルゴリズム

このオプティマイザは量子化された重みを直接最適化しません。量子化前の重みが `raw` として保持されていて、基底クラスのオプティマイザが `raw` を最適化します。そして TernaryOpt の最適化の結果として `raw` を量子化して返します。
量子化は単に `raw.round().clamp(-1, 1)` として定義されます。

## norm オプション

TernaryOpt は論文[^2]に従い、量子化前後にスケーリングを行います。これは学習を安定させる効果があります。
スケーリングをオフにしたい場合は、 `TernaryOpt(norm = False)` のように使用してください。

# 実験

PyTorch の Mnist の[サンプルコード](https://github.com/pytorch/examples/blob/main/mnist/main.py)をベースに TernaryOpt を適用している例です。

https://colab.research.google.com/drive/10C01N7KwY0KqkY4XuP2A4UhuQpngqD-V?usp=sharing

以下のように僅かな変更で元のコードと切替可能にできます。
(ここでは Adadelta を基底クラスとしているので `TernaryAdadelta` という名前にしています)

``` py
    if use_ternary:
        model = Net(bias = False).to(device)
        optimizer = TernaryAdadelta(model.parameters(), lr=args.lr)
    else:
        model = Net(bias = True).to(device)
        optimizer = optim.Adadelta(model.parameters(), lr=args.lr)
```

## 学習結果

オリジナル

```
Test set: Average loss: 0.0259, Accuracy: 9922/10000 (99%)
```

TernaryOpt

```
Test set: Average loss: 0.0331, Accuracy: 9895/10000 (99%)
```

# 使用時の注意

埋め込みベクトルやバイアスまで量子化されてしまうことに注意してください。
パラメータごとに違うオプティマイザを使用したい場合は[パラメータごとのオプション](https://pytorch.org/docs/stable/optim.html#per-parameter-options)を使ってください。
Tips: バイアスは削除しても問題ないかもしれません[^3]。


[^1]: The Era of 1-bit LLMs:
All Large Language Models are in 1.58 Bits https://arxiv.org/abs/2402.17764

[^2]: BitNet: Scaling 1-bit Transformers for
Large Language Models
 https://arxiv.org/abs/2310.11453

[^3]: [^1]に`removes all biases` と書いてある
AtCoderの復習

## 小数点切り上げ
```python
a = -(-a//x)
```
a が 10^16を超えると **math.ceil(a/x)** では失敗する

## 組み合わせ
```python
import math
a = math.comb(n, 2)
```

## collections
```python
from collections import Counter,defaultdict
S = 'abba'
ame = Counter(S)  #Counter({'a': 2, 'b': 2})
dic = defaultdict(int) #keyが無くてもエラーにならない
```