OmniAICreator/Qiita-1.07M huggingface dataset:
FreeBSD をメインのデスクトップ環境として使う

# FreeBSD がメイン環境
もうかれこれ 15 年くらい FreeBSD がメイン環境です。
自作機がメインマシンですが、これに FreeBSD と Windows を入れてデュアルブートになっています。
Windows は何ヶ月に 1 回か Windows Update のために起動するか、どうしても FreeBSD ではできない時だけ起動しています。
仮想環境とか SBC (≠ Raspberry Pi) に Ubuntu とか Debian を入れて Linux 環境も別途持っています。

# ノート PC の FreeBSD はしんどい
ノート PC はプリインストールの Windows を消して FreeBSD 専用環境で使用していましたが、 6 年くらい前から Mac にしました。どうしても WiFi 等の無線系のサポートと ACPI まわりが弱くて追いかけるのを断念してしまいました。今はサポートされるようになったのでしょうか。
ただ、いまだに MacBook Air 2015 モデルを使っていて、月に何回かくらいしか使いませんがそろそろ買い換えたいです... 

# FreeBSD をメインで使う
私のデスクトップ環境です。
普段は 4K + FullHD のデュアルモニタを使っていますが、このスクリーンショットは FullHD モニタだけの片側の時に取っています。
![desktop_snapshot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913528/c6be15df-932b-3c4a-6959-80a684cd8a70.png)
何が入っているか紹介したいと思います。
- Window Manager
これを入れないとメインの環境で使うのはしんどいです。
FreeBSD を使い始めてから [WindowMaker](https://www.windowmaker.org/) で変えていません。このシンプルさが気に入っています。一瞬 Xfce にしようとしましたが結局変えませんでした。今は Ubuntu や Debian でデスクトップ環境を作ると [LXDE](http://www.lxde.org/) にしているので、それに合わせようかちょっと悩んでいます。

- ターミナル
LXTermial を使っています。
ちょっと前まで mlterm だったのですが、どうしてもホイールクリックでコピペできない時があって不便なので変えました。

- ブラウザ
Firefox と Chrome を併用していますが、普段は Firefox です。
Flash や Silverlight が幅を利かせていた時代はしんどい部分がありましたが、 HTML5 な世の中になってから不自由を感じなくなりました。

- Office Suite
[LibreOffice](https://ja.libreoffice.org/) を使っているというか、これしかないと思います。
時々パッケージから無くなってみたり日本語入力できなくなったりしますが、何とかなっています。
MS Office とはだいぶ異なるので慣れは必要ですが、一通り困らないくらいの作業はできます。
ただ、お役所の申請書とか紙で提出の書類を PDF じゃなくて MS Office で置いてある時は殺意を覚えます:-)。
PDF は xpdf が入っていますがブラウザで開くことも多いです。

- 画像編集
[GIMP](https://www.kicad.org/) があれば困らないです。
スクリーンショットを撮って少しいじるくらいがメインなので充分です。

- 動画編集
[OpenShot](https://www.kicad.org/) があります。
インストールしてありますがほとんど使わないです。

- 開発系
    - コード
一応 VSCode は動きますが Linux や Windows で使える Plug-in が動かなかったりするので注意は必要です。私はがっつりコーディングするわけじゃないので、面倒なので vi で済ますことが多いです。
    - 回路設計
[KiCad](https://www.kicad.org/) を使っています。ガーバーデータを出せて基板屋さんに作ってもらうまではできますので、特に不自由は感じて無いです。これも自動配線のような Windows で使えるけど FreeBSD では使えない Plug-in があります。
回路シミュレーションは [Qucs](https://qucs.sourceforge.net) がありますが、 [www.falstad.com](http://www.falstad.com/circuit/circuitjs.html) の方がブラウザで動いて視覚的に分かりやすいです。作った回路を保存して再度読み込ませることができるので専ら [www.falstad.com](http://www.falstad.com/circuit/circuitjs.html) を使っています
    - IoT 関連
Arduino がありますが 1.8.5 からバージョンアップされていません。 PlatformIO も使っていますが、これは不便なので Ubuntu の Desktop 環境で作業していることがあります。

# FreeBSD をメインのデスクトップ環境で使うことについて
一通りやりたいことができているので問題ないと思っています。
動作が軽いですし、必要なリソースも少なくて済んでいます。某 OS のようにバージョンアップすると UI が変わって使いづらくなったりしません。
それでも、 jail だったり bhyve も動かすのでメモリは人権が保たれる 16GB 積んでいます。
アップデートは freebsd-update と pkg upgrade で済んでしまうので、 make world と ports の時代から比べると非常に楽になりました。
ですが、どうしてもできないこともあるので、そんな時は Linux だったり Windows も併用して使っています。FreeBSD に固執はしていません。

# おしまい
というわけで、FreeBSD をメインの環境で使っても問題ないというお話でした。
この記事はもちろん FreeBSD で動いている Firefox で書いています。
![desktop_browser.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/913528/d128e659-33a2-32a5-7137-7166bc6015bc.png)
【Alpine.js】Maskを使ってinputの入力値を統一していくぞ

# コイツを解説していく
https://alpinejs.dev/plugins/mask

MaskはAlpine.jsの拡張機能です。

# Maskでできること
<b><font color="red">inputに入力する値の形式を統一することができます。</font></b>

# 導入方法
CDNの方が楽な気がします。
## CDN
HTMLファイルに張り付けるだけです。
```html
<!-- Maskプラグイン -->
<script defer src="https://unpkg.com/@alpinejs/mask@3.x.x/dist/cdn.min.js"></script>
```
## npm
まずnpmでインストール
```
npm install @alpinejs/mask
```
その後、バンドルするjsファイルにこう書きます。
```js
import Alpine from 'alpinejs'
import mask from '@alpinejs/mask'
 
Alpine.plugin(mask)
```
これで使えます。

# 使用例
実際の公式ページで挙動を確認できるので確認してみてください。
（リンクのURLの表示が同じですが、それぞれ違うMaskへのリンクになっています。）
### 例①　日付の入力

https://alpinejs.dev/plugins/mask#x-mask

input内の日付を「MM/DD/YYYY」に統一することができます。
<b>しかも数字以外の入力を受け付けません。</b>
設定すれば色々な日付表示にできるようです。


### 例②　電話番号の入力

https://alpinejs.dev/plugins/mask#mask-functions

電話番号は国や地域で入力値が違いますよね。
（東京の03-xxxx-xxxxや福岡の092-xxxx-xxxx、携帯電話の080-xxxx-xxxx、フリーダイヤルの0120-xxx-xxxなど）
Maskを使えば「0120の時はxxx-xxxの3桁区切り」「03の時はxxxx-xxxxの4桁区切り」といった具合で動的にinputの値を制限できます。

### 例③　金額の入力

https://alpinejs.dev/plugins/mask#money-inputs

金額を入力する時に自動的に3桁区切りで表示してくれます。
(123,567円みたいな感じ)


Alpine.jsが既に$moneyという関数を用意しているので、公式ページをコピペで使えてしまいます。


# まとめ
ユーザーの入力の仕方に頼らずに入力値を統一できる！
便利すぎンゴ。
C言語の記憶領域

# C言語の記憶領域　
## 動機
現在、大規模数値計算プログラムをC言語で書いており非常に大きな配列を使うのだが、記憶領域(下記のようなコードの書き方)によって配列にどのような違いが出てくるのか気になったため、色々調べてみた。　

```c 
/* 配列の宣言方法 */


/* 1.ローカル変数的な配列 */
int array[5];

/* 2.static変数的な配列 */
static int array[5];

/* 3.ポインタ変数的な配列(動的確保) */
int *pntr;
int num_elements;

printf("配列のサイズを入力：");
scanf("%d", &num_elemtns);

array = calloc(num_elements, sizeof(int));


```


## 4つ(5つ)の記憶領域　
メモリは大きく4つの領域に分けられる。1番の方が低位のアドレスで、4番の方が高位のアドレスである。
1.テキスト領域
プログラムのコードが保存されるメモリ領域。

2.静的領域
**グローバル変数**や**静的変数**が保存されるメモリ領域。
上記の配列の宣言例での2番に該当。

3.ヒープ領域
malloc系で**プログラム実行中に確保**できるメモリ領域。
上記の配列の宣言例での3番に該当。

4.スタック領域
**ローカル変数**などが保存されるメモリ領域。
上記の配列の宣言例での1番に該当。

ローカル変数の保存されるスタック領域は**数MB程度のメモリしか持ち合わせていない**ので、それ以上のサイズの配列を使う際には配列をヒープ領域、もしくは静的領域に保存してあげる必要がある。ちなみに、参考サイトによると、どちらを使った場合も処理速度に大きな変化はないらしい。


http://netsu-n.mep.titech.ac.jp/~Kawaguchi/cpp/dyn_alloc.html

https://www.cns.s.u-tokyo.ac.jp/~masuoka/post/calc_speed/

さらに詳しく分けることもできるらしいが、今回は省略する。
詳しくは以下のサイトを参考　


https://www.momoyama-usagi.com/entry/info-calc-sys13



## 静的と動的
静的　
プログラムコンパイル時に決定されるもの。　
ローカル変数やstatic変数は静的変数であり、あらかじめ決めたサイズしか持たず、必要なサイズがわかっている時にはこちらでも問題ない。

動的　
プログラム実行時に決定されるもの。　
ポインタ型の配列は動的であり、プログラム実行中にそのサイズを決定することができ、必要なサイズが不明なときでも対応できる柔軟性をもつ。

## 結論
少なくとも最初にあげた3種類の配列の宣言方法は、メモリの大きさという観点から2つに分けられる。数MB以下程度の比較的**小さい配列を扱う場合はローカル変数としてスタック領域に保存されても問題ない**が、数値計算など非常に**大きな配列を扱う場合は、静的領域やヒープ領域に保存するべき**ある。





## 疑問
1. static宣言時の配列と、ポインタ変数型の配列は、どちらも数MB以上の配列を扱うことができるらしいが、どちらの方がメモリ容量的には大きいのだろうか？また、どちらの方が数値計算には適しているのだろうか？
というのも、先日static宣言で配列を使おうとしたがエラーが出た。詳しい内容は今手元にないので、今度記述しておくが、両者の間に動的、静的以外の違うがあるかどうかも確認しておきたい。　


## 参考サイト　　

https://www.cns.s.u-tokyo.ac.jp/~masuoka/post/calc_speed/

http://netsu-n.mep.titech.ac.jp/~Kawaguchi/cpp/dyn_alloc.html

https://www.momoyama-usagi.com/entry/info-calc-sys13

https://yu-nix.com/archives/c-static-dynamic/
【20日目】discord.jsで受け取ったメッセージをすべてLINEに転送する

# はじめに
こんにちは、なりかくんです。
今回は、discord.jsを使って受け取ったメッセージをすべてLINEに転送するプログラムを作ってみようと思います。

# LINEでメッセージを送信する
まず、LINEにメッセージを送る方法ですがLINE Notifyというシステムを使いたいと思います。
LINE上でまず一人のグループを作ります。作れたらLINE Notifyのサイトにログインします。
https://notify-bot.line.me/ja/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/488a3db9-8a2c-c1ae-709b-c3bf95703afe.png)

ログインしたらマイページに移動して、開発者向けのアクセストークンを発行してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/fca16ad8-fbfa-4efb-585b-ae8fd19f022b.png)

なお、送信するトークルームは先ほど作成したグループを選びます。トークン名はなんでもいいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/f2dd15fd-dc5b-3bea-0631-77ca7079069c.png)

発行したらトークンをメモしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/afe0447e-d781-953b-135f-9fe12beb43b1.png)

また、作ったグループにLINE Notifyを追加してあげます。

これでLINEの設定は終わりです。

次にLINE Notifyに送信するコードです。今回は受け取ったメッセージをすべて送信するというクソみたいなコードを作りました。そのコードが以下のコードです。
```js:linenotify.js
const request = require("request");
const { Client, GatewayIntentBits, IntentsBitField } = require('discord.js');
const { token } = require('./config.json');

const client = new Client({ intents: [GatewayIntentBits.Guilds, IntentsBitField.Flags.GuildMessages, IntentsBitField.Flags.MessageContent] });

client.on('ready', () => {
	console.log(`${client.user.tag}でログインしました。`);
});

client.login(token);

client.on('messageCreate', async message => {
	try {
        if (message.author.bot) return;
        await sendLineNotify(message.content);
	} catch (error) {
		console.error(error);
	}
});

function sendLineNotify(msg) {
    return new Promise((resolve, reject) => {
        request({
            url: "https://notify-api.line.me/api/notify",
            method: "POST",
            json: true,
            form: {
                message: msg
            },
            headers: {
                'Authorization': "Bearer <Token>",
                'Content-Type': 'application/x-www-form-urlencoded',
            }
        }, function (error, response, body) {
            if (error) {
                reject(error);
            } else {
                resolve(body);
            }
        });
    });
}
```

内容としては、messageCreateで受け取ったイベントのメッセージをすべてリクエストにかけているだけです。
なお、LINE Notifyには以下のURLにPOSTして送信します。
```
https://notify-api.line.me/api/notify
```
詳細の仕様は以下のドキュメントをご覧ください。

https://notify-bot.line.me/doc/ja/

# 実際に動かしてみる
実際にメッセージを送ってみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/be1652b8-53ac-f5f9-9395-01f0ae985ec7.png)
LINE側にも送信されることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549951/b9cdd7a8-2a2c-50d8-b9ca-1d3691b771b9.png)

# 注意点
最後に注意点です。LINE Notifyにはレートリミットという1時間に何回APIを叩けるかを制限システムが導入されています。詳しくは、ドキュメントをご覧ください。

https://notify-bot.line.me/doc/ja/

以上です、最後までお読みいただきありがとうございました。
AWSのVPNサービスについて

# 本記事について
この記事では３回目のANS-C01を受けるにあたって勉強した内容を整理するための記事です。
詳しくは[こちら](https://qiita.com/the13-HK/items/349cdf5f38e0ce1e47b1)をご覧ください。
今回はAWSで良く使用されるVPNサービスの比較記事となります。

# VPNについて
AWSで使用されるVPNサービスは主に以下の二つです
- site-to-site VPN
- client VPN

今回はそれぞれのVPNの特徴について整理します

## site-to-site VPN
- AWSのVPCとオンプレのデータセンターネットワークをIPsecでつなげる。
    - VPCにはVirtual Gateway(or Transit Gateway)
    - オンプレ側にはCustomer Gateway
を設置する。

### 注意点
- Virtual GatewayはVPCにつき一個のみ設置可能
- プライベートASN番号を採番可能で、ルーティングの優先順位付けに使用可
- 各ゲートウェイにパブリックIPが必要 
- 冗長化を行う場合
    1. CGWとVGWそれぞれ一つに対してVPN接続を二つ設置
        - CGW、VGWが１つ、VPNが2つ
        - VGWは内部的に冗長化しているが、CGWは冗長化できていない
    1. CGW２つに対してVPN接続を１つずつ設置VGWは１つのみ
        -  CGW、VPN接続が２つ、VGWが１つ
    1. CGW２つでCGW1つに対してVPN接続を2つずつ設置、VGWは１つ
        - CGWは2つ、VGWは1つ、VPN接続は4つ

- 経路選択方法について
    - LPを選択
        - 値が低い方が優先度高い
    - TGWにおけるルートテーブル
        - ロンゲストマッチが適用される
        - マッチの長さが同じ場合は優先度はDirect Connect > VPN

- ECMP（Equal Cost Multi Path）について
    - 同じ帯域のVPNを束ねて高帯域化させる仕組み
        - Transit Gatewayでの接続の時に有効化できる


## Customer Gateway
- AWSのVPCと自身のクライアント端末を直接VPN接続でつなげる。
    - VPCのサブネットにはENI
    - オンプレ側にはクライアントＶＰＮエンドポイント（Open VPN Client等）
を設置する。   
 
### 注意点
- ENIにはセキュリティグループを設置可能
- クライアントはプライベートIPアドレスのみで設定可能
- ただし、クライアントとAWSのサブネットのCIDRの範囲は重複してはならない
- VOC内のEC2と同じような振る舞いをすることが出来る
    - VPCピアリング先と通信できる、等


## まとめ
基本的にエンタープライズで使用するVPNとなるとsite-to-siteになりそう。
site-to-siteはネットワーク間の延長、client VPNはオンプレのパソコンをあたかもEC2かのように使用するための接続ｍという印象を受けた。
HSP3のstart.axを編集してみた

# なぜ編集する必要があるのか
HSP3の実行ファイルのデコンパイルは簡単で、公開されているデコンパイラ
https://github.com/YSRKEN/HSP-Decompiler
に実行ファイルを投げるだけで完了します。
ですが、場合によってはデコンパイルに失敗したり、内容が難読化されていて部分的な処理に手を加えるだけなのにそれが出来ない、という事態に陥ります。
(`/*09 20 004E*/`とかになる場合はhttps://github.com/onitama/OpenHSP/blob/master/src/hspcmp/hspcmd.cpp を参考にしながらDictionary.csvを編集するだけで動きますが)
それなら必要な部分だけ編集しよう、ということです。
また、axファイルを編集することでデコンパイルの対策にもなります。

# axファイルの構造
https://wiki.hsp.moe/OpenHSP%E3%81%AE%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%EF%BC%8FAX%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E6%A7%8B%E9%80%A0.html
ここの読めば分かります。

# 編集する
## if文の条件式を変える
こんなプログラムを用意します
```c
#module
#defcfunc check int p1, int p2
    return p1 - p2
#global

if check(30, 29) == 1{
    mes "Oops!"
}else{
    mes "flag{cool}"
}
```
これからaxファイルを生成すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984781/b749a216-1bd2-fadd-4d2c-51fb0357866d.png)
こんな感じになります。
このままだとOops!が表示されてしまうので条件式を変えます。
=の命令コードは08なのでこれを!である09に変更します。
場所は0xB8ですね。
axファイルを編集したらレガシーツールからPACKFILEを編集してstart.axファイルを入れます。
そしてレガシーツールから実行ファイルを生成すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984781/1b782626-22f0-127e-bc9d-ba0815e386bc.png)
無事にflagが入手できました。
(axファイルが編集できる時点で中の文字列が全部見えるけど)
## 関数名を変更する(主にデコンパイル対策)
つぎにaxファイルを編集してデコンパイラを使った場合に出力される関数名を変更してみます。
上と同じプログラムを利用します。
元のaxファイルはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984781/c4acfd2d-f88c-345c-03e1-341bc2afd3b4.png)
この"check"という文字列を同じ長さの"color"に変更して、実行ファイルを生成してみます。
このファイルを実行すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984781/770d0a0b-4b5e-f036-3859-692f0c55ba4f.png)
結果は変わりませんが
```c
	goto *label_1
#defcfunc color int prm_0, int prm_1
	return prm_0 - prm_1
*label_1
	if ( color(30, 29) == 1 ) {
		mes "Oops!"
	}
	else {
		mes "flag{cool}"
	}

```
デコンパイルすると関数名がcolorになっていることが分かります。
勿論、"color"という名前の色を指定する命令が既にあるので、コンパイルしようとしてもエラーが発生します。
【Linux】Docker上のUbuntuに任意バージョンのPythonをインストールする【Ubuntu 20.04】

# はじめに
この記事は、Docker上で動かしているUbuntuに好きなバージョンのPythonをインストールする方法を備忘録的にまとめたものです。


Ubuntuに複数バージョン、任意のバージョンのPythonをインストールする方法として`software-properties-common`を使う方法がありますが、社有資産ではプロキシなどの問題でリポジトリにアクセスできないなどの問題がありました。
そこで、Git clone経由でpyenvを使った方法であればうまくインストールできたのでこれを紹介します。

:::note info
こんな方に参考になればと思います。
- DockerでPythonを使いたいが、特定のバージョンを使いたい
- `software-properties-common`がうまく機能しない
- 社有資産でプロキシ、SSLの問題がよく発生している
:::

:::note warn
**ポイント**
社有デバイスで作業する場合、あらかじめ企業に指定されているプロキシサーバを通してください。
:::


こちらの記事を参考にさせていただきました。大変わかりやすく解説されています。

ubuntu 20.04 / 18.04 に pyenv をインストールする話／@neruoneru

https://qiita.com/neruoneru/items/1107bcdca7fa43de673d


## 動作確認環境

| 項目 |  |
|:-:|:--|
| OS  | Ubuntu 20.04 |
| Shell  | Bash  |




# インストール方法

## コンテナに入る
```bash
docker attach xxxxxxxxxxxx
```

## パッケージ更新
```bash
apt update
apt upgrade
```

## pyenv実行用パッケージをインストール

```bash
apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \
    curl llvm libncursesw5-dev tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \
    libopencv-dev git
```

## pyenvをclone
```bash
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```
## カレントディレクトリを移動
```bash
cd ~/.pyenv/plugins/python-build
```

:::note info
私の環境ではなぜか`~/.pyenv/plugins/python-build`に一度に移動できず、`cd ~/`、`cd .pyenv/`とディレクトリごとに指定すれば移動できました。
:::

## pyenvインストール実行
```bash
./install.sh
```
:::note info
**ポイント**
インストールには時間がかかるので少し待ちましょう。
:::

これでpyenvが動くようになりました。それでは好きなバージョンのpythonをインストールします。

## バージョン指定してpythonをインストール
```bash
python-build -v 3.8.6 ~/local/python-3.8.6
```

これでPython 3.8.6をインストールできましたが、環境変数に通してすぐに呼べるようにします。


## 環境変数にインストールしたPythonのディレクトリを追加
```bash
echo 'export PATH="$HOME/local/python-3.8.6/bin:$PATH"' >> ~/.bashrc
```


## エイリアスを追加
今の時点ではこのPythonを起動するには`python3`と打つ必要があります。単純な`python`でも起動できるようにエイリアスを設定しておきます。
```bash
echo 'alias python="$HOME/local/python-3.8.6/bin/python3"' >> ~/.bashrc
```

## 起動確認

念のためコンテナを停止し再度起動させ、pythonを呼び出してみます。
```bash
python -V
# Python 3.8.6
```


# おわりに

こちらの方法でPythonをインストールしたところ、pipなどパッケージ管理もうまくインストールでき快適な開発環境を構築できました。同じ悩みがある方の参考になれば幸いです。

# 参考

こちらの記事を参考に記事を作成しました。ありがとうございます。

https://qiita.com/neruoneru/items/1107bcdca7fa43de673d

pyenvのリポジトリ

https://github.com/pyenv/pyenv
【GMC-4】エニグマもどき

学研の4ビットマイコン GMC-4 でエニグマのようなものを作ってみた。

# エニグマ

* [エニグマ (暗号機) - Wikipedia](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%8B%E3%82%B0%E3%83%9E_(%E6%9A%97%E5%8F%B7%E6%A9%9F))
* [エニグマを実装してみた - Qiita](https://qiita.com/opengl-8080/items/995778d1cce43ed5babc)

エニグマは、変換する文字をキーボードで打ち込むと変換結果の文字のランプが光る、換字式暗号の暗号化および復号を行う装置である。
同じ設定を用いて平文を変換すると暗号文になり、暗号文を変換すると平文になる。

エニグマは、以下の順番に変換を行う。

1. プラグボード
2. ローター1 (正方向)
3. ローター2 (正方向)
4. ローター3 (正方向)
5. リフレクター
6. ローター3 (逆方向)
7. ローター2 (逆方向)
8. ローター1 (逆方向)
9. プラグボード

それぞれのパーツは電気的な配線により変換を行い、以下の性質を持つ。

* プラグボードは、設定された2個の文字を入れ替える。(例えば、「AとB」のペアを設定したら、AをBに、BをAに変換する)
* ローターは、逆方向の変換が正方向の変換の逆変換になっている。(例えば、正方向でAがBに変換される場合、逆方向ではBがAに変換される)
* リフレクターは、入力の文字を必ず別の文字に変換する。

ローター1は、1文字変換するごとに1文字分回転し、変換の仕方が変わる。
ローター2は、ローター1の回転が一周すると1文字分回転する。
ローター3は、ローター2の回転が一周すると1文字分回転する。
これにより、文字の位置によって様々な変換が行われる。

# 今回の仕様

プラグボードは省略し、データメモリで表現するローター1枚だけを用いたエニグマもどきによる暗号処理を行う。
キーにより文字を入力すると、7セグメントLEDに変換結果の文字が出力される。
本来のエニグマはアルファベット26文字を対象とするが、今回は0～Fの16文字を対象とする。

# プログラム

以下のプログラムは、[MikeAssembler](https://mikecat.github.io/mike_assembler/) でアセンブルできる。

```
target gmc4

	org 0x00

main_loop:
	CAL RSTO
	; キー読み込み
key_wait:
	KA
	JUMP key_wait
	; ローター (順方向)
	CY
	MA
	; リフレクター
	CAL CMPL
	; ローター (逆方向)
	TIY 0
	JUMP reverse_search_initial
reverse_search:
	M-
	AIY 1
reverse_search_initial:
	M-
	CIA 0
	JUMP reverse_search
	CY
	; 暗号化/復号結果を出力
	AO
	; ローターを回転させる
	TIY 0
	MA
	CH
	TIY 1
rotate_loop:
	MA
	AIY -1
	AM
	AIY 2
	JUMP rotate_loop_end
	JUMP rotate_loop
rotate_loop_end:
	CH
	TIY 0xF
	AM
	; キーが離されるのを待つ
key_release_wait:
	KA
	JUMP main_loop
	JUMP key_release_wait

	; ローターの設定
	org 0x50
	datan 0x8, 0x6, 0xd, 0x9, 0x1, 0x4, 0xe, 0x7
	datan 0xf, 0x2, 0x3, 0x0, 0xc, 0xa, 0xb, 0x5
```

以下は、このプログラムの機械語表現である。

```
  | 0 1 2 3  4 5 6 7  8 9 A B  C D E F
--+-----------------------------------
0 | E 0 0 F  0 2 3 5  E 4 A 0  F 1 2 7
1 | B 1 7 C  0 F 0 F  3 1 A 0  5 2 A 1
2 | 5 B F 4  B 2 F 2  C F 2 0  2 A F 4
3 | 0 F 0 0  F 3 0
```

さらに、データメモリを0～Fの順列 (0～Fをそれぞれちょうど1回ずつ使った列)で初期化しておく。
この列がローター (変換表および回転位置) を表す。
データメモリの内容が0～Fの順列でない状態でプログラムを実行した場合、結果は保証しない。(変換時に無限ループとなる可能性がある)

```
  | 0 1 2 3  4 5 6 7  8 9 A B  C D E F
--+-----------------------------------
5 | 8 6 D 9  1 4 E 7  F 2 3 0  C A B 5
```

# 実行結果

<iframe width="560" height="315" src="https://www.youtube.com/embed/ZJdSViEJA-M" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

上記のローターの設定を用いて「DEADBEEF01234567」を暗号化すると、「FC849C0D330ABC85」となった。
本来は暗号化/復号を開始する際にローターの再設定が必要であるが、動画では16文字変換するとローターが一周して元に戻ることを利用し、再設定を省略した。
RubyKaigi 2022 セッション紹介「Method-based JIT compilation by transpiling to Julia」

## はじめに

RubyKaigi2022に初参加してきましたので、そのセッションの中で面白かった内容を紹介しようと思います。

今回紹介するのは、KentaMurata氏のメソッドベースのJust-In-Timeコンパイルへの新しいアプローチとして、RubyのインフラストラクチャにJulia言語を使用した背景と仕組み、特徴についてになります。

## スライドリンク

https://speakerdeck.com/mrkn/method-based-jit-compilation-by-transpiling-to-julia

## 本題

現在Rubyでは数値計算が高速ではなく、Numo::NArrayやRed Arrowを使えば大きな数値計算が出来つつありますが、MJITやYJITが利用できてもあまり高速ではないという問題があるとのことでした。

理由として、これらのJITコンパイラがRubyの全てのセマンティクスを保持するためです。Rubyでは全てのメソッドが再定義可能で、再定義されたメソッドは直ちにコード実行に影響を与えます。例えば、以下のようなループの途中でも、injectメソッドや+演算子（メソッド）が再定義されていないかの確認が毎回行われます。

```Ruby
s = (1..10).inject { |a, x| a + x }
```

以上の特徴によって高速性が失われていましたが、数値計算の場合このRubyの動的性は数値計算アルゴリズムでは殆ど無意味なので、これを無視して計算を最適化できるほうが良いのでは？　というのがこのセッションの議題になります。

しかし、現在ではこのような最適化を行うためには、アルゴリズムをCの拡張ライブラリに書き換える必要があります。これをせずに、高速化を行う手段として挙げられたのがJuliaでした。Juliaはデータ処理や数値計算に向いていて高速な言語という特徴があります。

ここで、比較としてPythonの世界での解決策であるNumbaというライブラリの紹介がありました。NumbaはCPython用のJITコンパイラであり、PythonとNumPyのコードの一部を高速な機械語に変換します。もう少し具体的にコンパイルの流れを書きます。

- CPythonのバイトコードを解析
- NumbaIRを生成して書き換え
- 型を推論
- 型付IRに書き換え
- 自動並列化の実行
- LLVM IRの生成
- ネイティブコードにコンパイル

という流れで、CPythonを型付の中間表現に変換してネイティブコードを生成しています。

またNumbaには2つのモードがあります。オブジェクトモードというCPythonインタプリタのC APIを使用しCPythonの完全なセマンティクスを保持するモード。もう1つはnopythonモードというfloat64やnumpy配列などの特定のネイティブデータ型に特化した小さくて効率の良いネイティブコードを生成するモードです。ざっくり言うと処理をPython経由で行うか、CPUに直接命令するかの違いになります。

このNumbaのnopythonモードのようなものをRubyのJITコンパイラでも実現する手段として登場するのが、今回のセッションの本題であるJuliaでした。まず、RubyでNumbaライクなJITコンパイラを表現すると以下のようになります。

- Rubyメソッド
  - ASTの生成
  - 最適化
  - バイトコードの生成
- CRubyのバイトコード
  - IRの生成
  - タイプ推論
  - 最適化
- 型付けされたIR
- LLVM IRの生成
- ネイティブコードにコンパイル

これと同じようなことをやっているのが、Juliaになります（JuliaはNumbaともだいたい同じ機構が動いています）

- Juliaコード
  - ASTの生成
- Julia AST
  - タイプ推論
  - IRの生成
- Julia typed IR
- LLVM IRの生成
- ネイティブコードにコンパイル

そこで、RubyをJuliaへトランスパイルし、それ以降をJuliaのJITコンパイラに実行してもらって高速化します。

- Rubyメソッド
- Juliaコード
- Julia AST
- Julia typed IR
- LLVM IRの生成
- ネイティブコードにコンパイル

Juliaは最適化されたネイティブコードを生成してくれるため、高速です。この辺りの解説はセッションのスライド図と発表が大変分かりやすく、面白かったので是非資料や動画をご覧ください。

次に、RubyからJuliaへのトランスパイル方法についての紹介がありました。トランスパイルには、yadriggyというRubyメソッドのASTを構築し、構文と型をチェックするgemを使用しているとのことでした。セッションでは具体的なコードを紹介していましたが、大雑把にいうとRubyコードからASTを構築し、それを使ってJuliaコードを生成しているようでした。

Rubyコード → Ruby AST → 型チェッカーでノードに対して型付け → Juliaコード

これによって、Rubyの機械への命令を最適化させています。

またRubyとJuliaで実装の違うものがいくつかあり（例ではRangeを挙げていました）これらの対応をするには自分で変換コードを書く必要があるとのことでした。

これらの高速化の実験比較として、以下の計算を行っていました。

- マンデルブロ集合
- モンテカルロ法によるπの近似
- クイックソート
- 畳み込み
- ドット積

それぞれの結果は以下のようになっていました。RubyはおそらくYJITが有効。

- マンデルブロ集合
  - Ruby：平均3.326ms
  - Ruby to julia：平均171.667μs
- モンテカルロ法によるπの近似
  - Ruby：平均106.368ms
  - Ruby to julia：平均8.851ms
- クイックソート
  - Ruby：平均7.551ms
  - Ruby to julia：平均1.937ms
- 畳み込み（結果が複雑なので省略）
- ドット積
  - Ruby (N=10000)
    - 平均468.608μs
    - Ruby to julia (N=10000)
    - 平均3.759ms
  - Ruby to julia (N=10000, T=Float64)
    - 平均10.651μs

これらのように、一部の結果を除いて超高速に計算することが可能になるようでした。

紹介は以上になります。発表が分かりやすく、深掘りしたくなるような興味深い内容でした！Rubyの高速化についてこういう方法もあるんだなと、とても学びが多かったです。RubyKaigiではこのような発表がいくつもあり、すごくワクワクしました。
XSSについて

# はじめに

この記事は[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)の記事です。
このカレンダーでは、なんとなくわかった気になっている、Webの知識をおさらいします。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

今回はXSS(クロスサイトスクリプティング)について説明します！  

## XSS(クロスサイトスクリプティング)とは
悪意のあるクライアントサイドのコードをWebサイトに挿入させ、スクリプトを実行させるセキュリティ攻撃のこと。
CrossSiteScriptingで、CSSと略称がかぶってしまうので、XSSと表記されている。

### 種類
攻撃手法に応じた種別名称があります。
* 反射型 XSS
* 格納型 XSS
* DOM Based XSS

#### 反射型XSS(Reflected XSS)
攻撃者が用意したURLを叩いた際に、リクエストにスクリプトに相当する文字列が含まれ、そのスクリプトをそのままレスポンスとして返して出力してしまうタイプのもの。

例えば、クエリパラメータにスクリプトを入力してユーザーにアクセスさせる例がある。
`?search_word=<script>cookie取得などの攻撃スクリプト</script>`

結果として
URLを叩いてしまうだけで、ユーザーのcookie情報を取得して、攻撃者のサーバーに送信するというようなことが可能になってしまう。

スクリプトがそのまま送信者の元に返って、実行されることから反射型XSSと呼ばれる。

#### 格納型 XSS(Stored XSS)
掲示板やQiitaのような投稿サイトなど、ユーザーがコンテンツを投稿できる仕組みがある時に、
そのコンテンツの中に直接悪意のあるデータを書き込んで格納しておくことで、ユーザーに悪意あるスクリプトを実行させる手法。

ユーザーが該当の格納データを表示するたびに、その悪意あるスクリプトが実行されてしまうことから格納型 XSSという。

#### DOM Based XSS
サーバー側ではなく、クライアント側で動的にDOM操作を行う際に、悪意あるスクリプトが埋め込まれてしまうことで発生する。

`insertAdjacentHTML や innerHTML`などのHTMLを操作するjavascriptのメソッドを使う際はよく注意して使用する必要がある。

クライアントサイドで実行されるため、検知が難しいケースがある。

DOM操作を起点に悪意あるスクリプトを実行させることからDOM Based XSSという。

### 被害
* セッションハイジャック
    * 例: cookieからセッション情報などを取得され、本人に成り代わってアプリケーションの操作をされてしまう。
* 機密情報漏洩
    * 例: フォームに入力したデータなどを送信され、盗まれてしまう。
* 不正な操作
    * 例: 投稿サイトなどに自動スクリプトによって意図せぬ投稿をさせられてしまう。
* ページの偽造
    * 例: ページの内容を書き換えて、偽物のログイン画面を表示したりすることで不正にIDやパスワードを盗まれてしまう。


## 対策
* サニタイジング
* 入力値の制限
* WAFでの防御

### サニタイジング
`<`や`>`などスクリプトを構成する文字列を検知して、無害化すること。
例えば`<script>`は`&lt;script&gt;`のように置換される。
基本的に、ユーザーが入力した内容やユーザーに表示される内容にはサニタイジング処理をしよう。

### 入力値の制限
数値のみや文字数制限、記号の不許可など入力フォーム自体に制限をかける方法。
予めユーザーからは該当の文字列を入力できないようにすることで対策をする。

### WAFでの防御
WAF(Web Application Firewall)は、ユーザーの不正な通信を監視するためのセキュリティシステムのことです。
ユーザーのリクエスト内容などを確認して、不正なものがあった場合はブロックをしてくれます。  
予期せぬ対応漏れがあったとしても、問題がないようにWAFで防御をしておくと安心です。

## 終わりに
以上、簡単にXSSについてまとめてみました。
一口にXSSといってもいろんな攻撃パターンがあるので、内容を正しく理解し、対策をしっかり行いましょう！

[Webの基礎をおさらいカレンダー Advent Calendar 2022](https://qiita.com/advent-calendar/2022/basic_review)でした。
興味をもし持ってくださった方は、購読いただけると嬉しいです！

## 参考文献
[とほほのWWW入門 クロスサイトスクリプティング(XSS)](https://www.tohoho-web.com/ex/xss.html)
APIの負荷試験でNew RelicのAPMを活用する

## はじめに
この記事は[New Relic Advent Calendar 2022](https://qiita.com/advent-calendar/2022/newrelic)の20日目の記事となります。

Rubyで構築されたAPIのパフォーマンスチューニングに挑んでいる者です。
先日負荷試験を実施し、試験結果の分析にNew RelicのAPMを活用するためにNew Relicさんと面会させていただきました。
そこで教えていただいたことや学んだことをこの記事にて共有します。

### 対象者
- これからNew Relicを使い始めようと思っている人
- New Relicを使ってサーバーサイドの処理を見たい人
- サーバーサイドのパフォーマンスチューニングにNew Relicを活用したい人

## Distributed Tracing
各項目を説明していきます。
### Trace groups
- trace_duration
  - レスポンスタイム
- span
  - DBへのクエリ実行・他サービスの呼び出し・関数の呼び出しをおこなった回数
  - 多すぎる場合は何かしらの改善をすべき(N+1の検出等に役立てることができる)
- traces
  - Group similar tracesがオンの場合に表示される、グループにまとめられているトレースの数

### グラフになっている項目

-  Trace count
    - リクエストがあった回数
-  Trace duration(ms)
    - レスポンスタイム
-  Trace with errors
    - エラーの数

### [Tips]全てのデータをトレースしたい場合
- APMのページ上部にあるGroup similar tracesのトグルをOFFにするとサンプリングが解除されて全てのデータが一覧で見れます
  - デフォルトの設定だと、全体の10%サンプリングしたものが表示
![APM_distributed_traces_toggle_off.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983261/242f3128-e6a6-7d8b-8c76-eb530dd25363.png)

## Databases
### Slow SQL traces
時間がかかったクエリがサンプリングされ、一覧に並べられています。
レスポンスタイム(Duration)で照準・降順にして見ることができます。

### [Tips]クエリの数値を難読化解除
デフォルトだとクエリの数値が難読化されています。
↓こんな感じ
```sql
SELECT * FROM users WHERE id = ?
```

このままだと検証やチューニングなど色々とやりづらかったりするので、難読化を解除します。
(今回、RubyのシステムをトレースしているためRuby Agentでのやり方のみ紹介します)

Ruby(Rails)アプリケーションのconfig配下にある`newrelic.yml`を編集します。
`transaction_tracer.record_sql`の値を`raw`に設定します。(デフォルトだと`obfuscated`になっている)
```yml
common:
~~~

staging:
  transaction_tracer:
    record_sql: raw

production:
~~~
```

今回、検証で使うStaging環境のみ難読化を解除します。

## その他
### 時間の指定
ページ上部で表示するトレースの時間帯を指定することができます。
![スクリーンショット 2022-12-19 22.51.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2983261/8572667c-3244-fc85-8d01-4dc27471df49.png)
デフォルトだと過去30分の指定になっていますが、Set customで任意の時間にできます。
(ただし、次の項目で説明するifinite traceをしていない場合は8日より前のトレースを遡って見ることはできません)

### infinite trace
デフォルトの設定だとトレースされたものが8日で消去されるようになっているが、消えないように設定することもできます。
ただし、料金モデルによってはできないこともあるので、要確認です。([公式のリンク](https://docs.newrelic.com/jp/docs/distributed-tracing/infinite-tracing/introduction-infinite-tracing/))

## まとめ
今回、初めての負荷試験でNew Relicを活用し効率よく結果を見て分析することができました。
また知見が溜まったら記事にしようと思います。
DenoでNotionのAPIを触ってみる


DenoでもNotionのAPI触ってみたいなーと調べたら、Node.jsのSDKと同じような使い勝手で利用できる非公式SDKがあったので触ってみました。

## 環境

```bash
$ deno --version
deno 1.29.1 (release, x86_64-apple-darwin)
v8 10.9.194.5
typescript 4.9.4
```

## notion_sdk_deno

執筆次点だと0.3.9が最新の模様です。

- https://deno.land/x/notion_sdk_deno@v0.3.9
- https://github.com/yeukfei02/notion-sdk-deno

```app.ts
import { Notion } from "https://deno.land/x/notion_sdk_deno@v0.3.9/mod.ts";

const notion = new Notion({
    token: "APIトークン",
  });

const userList = await notion.getUsers();
console.log("userList = ", userList);
```

実行には`--allow-net`と`--allow-env`のフラグが必要です。

```bash
$deno run --allow-net --allow-env app.ts

urlSearchParams =  URLSearchParams {
  [Symbol(list)]: [],
  [Symbol("url object")]: null,
  [Symbol("[[webidl.brand]]")]: Symbol("[[webidl.brand]]")
}
userList =  [
  {
    object: "user",
    id: "xxxxxxxxxxxxxxxxxxxxxx",
    name: "のびすけ",

省略

 },
  {
    object: "user",
    id: "23feb307-xxxxxxxxxxx",
    name: "ほげほげ",
    avatar_url: null,
    type: "bot",
    bot: { owner: { type: "workspace", workspace: true }, workspace_name: "Hogehoge" }
  }
```

サンプル通りで動いてよかった


## notion_sdk

- https://github.com/cloudydeno/deno-notion_sdk
- https://deno.land/x/notion_sdk@v1.0.4
 
サンプルを動かす

```app.ts
import { Client } from "https://deno.land/x/notion_sdk/src/mod.ts";

// Initializing a client
const notion = new Client({
  auth: 'APIトークン',
})

const listUsersResponse = await notion.users.list({})

console.log(listUsersResponse)
```

実行は先ほど同様

### 少しハマった

サンプルページのサンプルだと↓の書き方になっていてこちらだと、`Deno.env.get()`を使ってNOTION_TOKENの環境変数を取得するコードになってました。 Node.jsで`process.env`を使うイメージですね

```app.ts
import { Client } from "https://deno.land/x/notion_sdk/src/mod.ts";

// Initializing a client
const notion = new Client({
  auth: Deno.env.get("NOTION_TOKEN"),
})

const listUsersResponse = await notion.users.list({})

console.log(listUsersResponse)

```

こんな感じで実行すればOKです。

```bash
$ NOTION_TOKEN=APIトークン deno run --allow-net --allow-env app.ts
```


## どっちを使うか

このくらいの利用だとどちらでも良さそうって感じでしたが、なんとなく最終更新が比較的最近。v1としている。の2点から

https://deno.land/x/notion_sdk@v1.0.4

こっちの方がいいのかも？くらいな印象です。
kotlinでbuild.gradleにimplementationを追加しているのにUnresolved referenceになる

# はじめに

kotlinを書くのに依存関係を追加することは多くありますが、そこで発生するエラーについてあまり私が検索したやり方では解決方法が見つからなかったのでまとめます

(検索方法が悪い可能性もありますが、、)

# 問題

`build.gradle`に新しく`implementation`を追加して、`import`したのに何故か`Unresolved reference`でIntelliJ上で赤線が引かれてしまうことがあります

もちろん実行もエラーになってしまいます

こんな感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/810513/3e66c4d8-20a6-0819-0e6e-ad35405e8fe1.png)

(実際にtestはないです)

# 解決方法

依存関係がうまく反映されていないので、今ダウンロードしている依存ファイルをすべて削除してもう一度入れ直すと治ります

```
$ rm -rf ~/.gradle/caches
$ rm -rf ~/.gradle/daemon
```

このコマンドを叩くとIntelliJが再ダウンロードを始めます
少し長いですが待つとエラーが消えていると思います

# おわりに

これを知らずに何度も苦しめられました
理解すれば簡単に対処できるようになりましたが、初心者にはいきつくまで時間がかかりました
[SwiftUI] まだ `NavigationLink(...) { EmptyView() }` で消耗してるの？

## Tl;Dr

```diff
+ EmptyLink(isActive: $isActive) {
+     ChildView()
+ }
- NavigationLink(isActive: $isActive, destination: { ChildView() }) {
-     EmptyView()
- }
```

## How to use

```swift
struct ContentView: View {
    @State var isActive: Bool = false

    var body: some View {
        NavigationView {
            VStack {
                Button("画面遷移") { isActive = true }

                // 🎄 Readable 🎁
                EmptyLink(isActive: $isActive) {
                    ChildView()
                }

                // NavigationLink(isActive: $isActive, destination: { ChildView() }) {
                //     EmptyView()
                // }
            }
            .navigationTitle("18日目")
        }
    }
}

struct ChildView: View {
    var body: some View {
        Text("Child")
            .navigationTitle("Child")
    }
}
```

## Source code

```swift
struct EmptyLink<Destination: View>: View {
    private var navigationLink: () -> NavigationLink<EmptyView, Destination>

    init(
        isActive: Binding<Bool>,
        @ViewBuilder destination: @escaping () -> Destination
    ) {
        navigationLink = {
            NavigationLink(
                destination: destination(),
                isActive: isActive,
                label: { EmptyView() }
            )
        }
    }

    init<V: Hashable>(
        tag: V,
        selection: Binding<V?>,
        @ViewBuilder destination: @escaping () -> Destination
    ) {
        navigationLink = {
            NavigationLink(
                tag: tag,
                selection: selection,
                destination: destination,
                label: { EmptyView() }
            )
        }
    }

    var body: some View {
        navigationLink()
    }
}
```

## おわりに

[SwiftUI Advent Calendar 2022](https://qiita.com/advent-calendar/2022/swiftui) の19日目の記事でした 🎁

*- Merry Christmas, SwiftUI Lovers -*

## 他のアドベントカレンダー記事

https://qiita.com/YusukeHosonuma/items/dc986c408e14106caf29

https://medium.com/kauche/swiftui-group-chat-812cd6636e49
Bufferについての初歩的な知識

# ジャンル
ソーシャルメディア・マーケッティン(SMM)グツール

# プラットホーム
 1. ウエブ版
 1. モバイル版
     1. iOS
     1. Android

# 価格 (USD)

1. Free
    - 登録チャンネル　最大3つ
    - チャンネル当たりの投稿予約 10
    - 共同作業 1
    - ユーザー招待 0
    - 基本的な発行ツール
    - ランディングページビルダー
1. Essentials
    - 1チャンネルにつき$6/月
    - チャンネルあたりの投稿予約 2,000
    - 共同作業 1
    - ユーザー招待 0
    - 設計・発行ツール
    - 分析ツール
    - エンゲージメントツール
    - ランディングページビルダー
    - レポート機能
    - bit.lyを利用したリンク短縮
1. Team
    - 1チャンネル当たり $12/月
    - チャンネルあたりの投稿予約 2,000
    - 共同作業 無制限
    - ユーザー招待 無制限
    - チームメンバー、クライアント数無制限
    - 設計・発行ツール
    - 分析ツール
    - エンゲージメントツール
    - ランディングページビルダー
    - レポート機能
    - bit.lyを利用したリンク短縮
    - ドラフトコラボレーションツール
1. Agency
    - 10チャンネル当たり $120/月)
    - チャンネルあたりの投稿予約 2,000
    - 共同作業 無制限
    - ユーザー招待 無制限
    - 設計・発行ツール
    - 分析ツール
    - エンゲージメントツール
    - ランディングページビルダー
    - レポート機能
    - bit.lyを利用したリンク短縮
    - ドラフトコラボレーションツール
    - カスタムアクセス＆パーミッション
  
https://buffer.com/pricing

# 概要
　Bufferは一番古いソーシャル・メディア・ツールです。競合するサービスには、[HootSuite](https://www.hootsuite.com/en-gb), [SproutSocial](https://sproutsocial.com/),  [AgoraPulse](https://www.agorapulse.com/), [ZOHO　Social](https://www.zoho.com/social/), [Publer](https://publer.io/plans)などがあり、無料のアカウントが作成できるのは Buufer と Publer です。

　2010年、ジョエル・ガスコイン(Joel Gascoigne)はBufferを立ち上げ、リモートファーストの会社を作るという非常にユニークな目標を掲げました。現在、世界21カ国で82人のチームメイトが完全分散型チームとして週4日勤務し、14万人以上のユーザーをサポートしています。

　ソーシャルメディは、企業にとって必要不可欠なツールとマーケッティング・ツールとなっています。そして、発信する情報をきちんとコントロールする必要性が高まっています。ソーシャルメディア・マーケッティン(SMM)グツールは、そのような企業の要望から生まれました。

　現在接続できるソーシャルメディアは、Facebook、TikTok、Instagram、Twitter、LinkedIn、Pinterest、YouTube、Shopifyです。

# 機能

　使い方は非常に簡単で、SNSの種類を選んで接続するだけです。

<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/0137959c-b8f0-03d8-d19c-c754217ced94.png"/>

　私は、TwitterとFacebookとLinkedinをつなげてみました。Twitterは簡単につながったのですが、FacebookとLinkedinはページを作る必要があったりと、ちょっと手間取りました。Facebookの使い方がよくわかっていないということがわかったのでした。

　繋がったらカレンダーの発信したい日時をクリックして、登録していきます。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/0cafe65c-f443-0e6a-fd4e-b980766ce94d.png"/>
　発行先は、最初はすべてのチャンネルが対象になってますので、外したいチャンネルのアイコンをクリックすれば対象から外れます。対照を外していく操作になります。
<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/7636ab18-fb03-50ca-323a-241a5852ee51.png"/>
　Customize for each networkボタンを押した後、個別にSNSごとの修正を行って Schedule Postsを押します。一旦保留にする場合は Schedule Draft を押します。

　そんな簡単な操作で、発信予約や一斉発信ができます。無料枠だとチャンネル3つで予約10件までですが、個人利用なら十分だと思いますので、SNSを多用している場合は使ってみてはいかがでしょうか。

　ちなみに、最初はお試しで有料版の機能も使えるのですが、以下のような分析がグラフ化されて見えるのは面白いですね。

<img width="800" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/864075/9ad4ebb1-3be9-e43f-d812-92e9adfd3d2c.png"/>
[Day23] ドキュメント part3

本記事は一人アドベントカレンダー企画の一つです。
[30代未経験エンジニアが25日後にJavaScriptをマスターするカレンダー](https://qiita.com/advent-calendar/2022)

[JAVASCRIPT.INFO](https://ja.javascript.info/)を元にJavaScriptを勉強していき、そこで学んだ知識をアウトプットしていきます。
２５日でJAVASCRIPT.INFOをやりきり、未経験エンジニアがJavaScriptをマスターする過程を投稿していきます。



## 2.1.9 要素サイズとスクローリング
### 知らない単語
- ジオメトリとは
  - コンピュータグラフィックスにおける描画対象の形状や、形状を定義づける頂点の座標や線分、面などの図形を表す式の係数といったデータの組み合わせを意味する

### 学んだこと
要素の幅、高さや他のジオメトリの特徴を関する情報を読み取ることのできるプロパティについて

- ジオメトリ

幅、高さや他のジオメトリを提供する要素プロパティは常に数値で、ピクセルと仮定される





![スクリーンショット 2022-12-20 0.27.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2612204/112d3e09-141a-7df9-5348-52d8b3a09bf5.png)

画像は全体像だが、1つの図でそれらすべてを表現するのは難しい事である

- 要素が持つジオメトリプロパティ

offsetParent は最も近い position 指定された祖先である
offsetLeft/offsetTop は offsetParent の左上端を基準とする座標
offsetWidth/offsetHeight はボーダーを含む要素の 外部の 幅/高さ
clientLeft/clientTop は左上の外側の角から左上の内側の角までの距離である
左から右の OS では、常に左/上のボーダー幅で、 右から左へのOSの場合、縦スクロールバーは左にある
clientWidth/clientHeight はコンテンツの幅/高さだが、スクロールバーは含まない
scrollWidth/scrollHeight はスクロールアウト部分を含むコンテンツの幅/高さ
scrollLeft/scrollTop は要素のスクロールアウトされた部分の幅/高さ

scrollLeft/scrollTop 以外のすべてのプロパティは読み取り専用である

### 感想
要素が持つジオメトリプロパティは種類が多いので、関連付けて覚えていきたい。



## 2.1.10 ウィンドウサイズとスクローリング
### 知らない単語
- 無し

### 学んだこと
- ジオメトリ
ドキュメントの可視部分の幅/高さ
document.documentElement.clientWidth/Heightを使う

スクロールアウト部分も含むドキュメント全体の幅/高さ
```javascript
let scrollHeight = Math.max(
  document.body.scrollHeight, document.documentElement.scrollHeight,
  document.body.offsetHeight, document.documentElement.offsetHeight,
  document.body.clientHeight, document.documentElement.clientHeight
);
```

- スクローリング

現在のスクロールを読むのはwindow.pageYOffset/pageXOffset.

現在のスクロールを変更するのは
window.scrollTo(pageX,pageY) – 絶対座標
window.scrollBy(x,y) – 現在の場所を基準にスクロール
elem.scrollIntoView(top) – elem が見えるようにスクロール
というように使える

### 感想
ジオメトリなど、前の章と被っている所もあるので、振り返りながら理解を深めていく必要がある。


## 2.1.11 座標
### 知らない単語
- 無し

### 学んだこと
- ウィンドウ座標: getBoundingClientRect

ウィンドウ座標はウィンドウの左上端から始まる
メソッド elem.getBoundingClientRect() はelem に対する座標を返す

top – 要素の上端の Y-座標,
left – 要素の左端の X-座標,
right – 要素の右端の X-座標,
bottom – 要素の下端の Y-座標.
図で表すと





![スクリーンショット 2022-12-20 0.27.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2612204/1658a958-ff8c-9818-67a8-b2b0342bbd9a.png)

のようになる


- elementFromPoint(x, y)

document.elementFromPoint(x, y)は、ウィンドウ座標 (x, y) で最もネストされた要素を返す

構文
```javascript
let elem = document.elementFromPoint(x, y);
```

- ドキュメント座標

ドキュメント相対座標は、ウィンドウではなくドキュメントの左上端から始める

CSS では、ウィンドウ座標は position:fixed で記述するが、ドキュメント座標は position:absolute に近い
position:absolute と top/left を使うことで、ドキュメント上の特定の場所に何かを置くことができる


- ドキュメント座標の取得

要素のドキュメント座標を取得するための標準メソッドは無いが、書き方は以下である

pageY = clientY + ドキュメントのスクロールアウトした垂直部分の高さ
pageX = clientX + ドキュメントのスクロールアウトした水平部分の幅
関数 getCoords(elem) は elem.getBoundingClientRect() からウィンドウ座標を取り、それらに現在のスクロールを加える
```javascript
// 要素のドキュメント座標を取得
function getCoords(elem) {
  let box = elem.getBoundingClientRect();

  return {
    top: box.top + pageYOffset,
    left: box.left + pageXOffset
  };
}
```
のように書く

### 感想
ウィンドウ座標はfixed、ドキュメント座標はabsoluteと覚えて、同じ座標でも、違うので混同しないようにする。


# 最後に
ドキュメントについてはかなり理解が深まったと思うが、とにかく覚える事が多いので、間違えないように、忘れないようにしたい。
Next.js tailwind css での備忘録 (レスポンシブ)

# Next.js tailwind css での備忘録をメモしていきたいと思います。

今まで、見様見真似でtailwind cssを使っていましたが、あらあためてレスポンシブの設定や、display flex の使い方を確認したので、自分の復習のためにもこちらにメモしていきたいと思います。
開発未経験者のため、訂正箇所などありましたら、ご指摘いただけますと幸いです!

```css
/* display: flex; */
className="flex"

/* flex-direction: column; */
className="flex-col"

/* align-items: center; */
className="items-center"

/* justify-content: center; */
className="justify-center"

/* かんたんにレスポンシブを設定してくれる */
className="container"

/* containerの中身 */
.container {
    width: 100%;
}
@media (min-width: 640px) {
    .container {
        max-width: 640px;
    }
}
@media (min-width: 768px) {
    .container {
        max-width: 768px;
    }
}
@media (min-width: 1024px) {
    .container {
        max-width: 1024px;
    }
}
@media (min-width: 1280px) {
    .container {
        max-width: 1280px;
    }
}
@media (min-width: 1536px) {
    .container {
        max-width: 1536px;
    }
}
```

また、上記の container を活用するためには

```css
className="md:flex-row"

/* width 50% などを設定する際には */
className="md:w-1/2"
```

などとして設定するだけでかんたんにレスポンシブの変更を記述することができる。
最初はとっつきづらかったですが改めて tailwind の便利さを実感しました。


参考

https://www.youtube.com/watch?v=82cN8zwDhbY&t=2768s
Google Compute Engine SSH command login

# 公開鍵と秘密鍵を生成
```bash
ssh-keygen -q -P "" -f ~/.ssh/id_rsa
```
<details><summary>PowerShell</summary>

```bash
ssh-keygen -q -P '""' -f $HOME/.ssh/id_rsa
```
</details>


# 公開鍵を追加
公開鍵をコピーし、インスタンス編集画面から項目を追加し保存します。
```
cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgAEMvjTl6roZOC0mLFDzo18eGYr/SkoyS8rV8= user@DESKTOP-PC
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/00da723d-eb0f-ba21-3354-10e169228850.png)

# ログイン
外部IPでログインできます
```bash
ssh 34.97.61.120
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/e1ea8403-e30d-a6f8-5984-3a4e9000c25a.png)

公開鍵のユーザー名だけを変えることもできます
```bash
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDgAEMvjTl6roZOC0mLFDzo18eGYr/SkoyS8rV8= user2@DESKTOP-PC

ssh user2@34.97.61.120
```
[Flutter] チャートを作る


こんにちわ　いせきです。

今回はチャートを作ってみました。


# レッツトライ

１、ファイルを追加してください

```yaml
dependencies:
  syncfusion_flutter_charts: ^20.3.59
```



```dart:chart.dart
import 'dart:ui';

class ChartData {
  ChartData(this.x, this.y, this.color);
  final String x;
  final double y;
  final Color color;
}
```

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:money_records_app/model/chart_data.dart';
import 'package:syncfusion_flutter_charts/charts.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: GraphScreen(),
    );
  }
}

class GraphScreen extends StatefulWidget {
  const GraphScreen({Key? key}) : super(key: key);

  @override
  State<GraphScreen> createState() => _GraphScreenState();
}

class _GraphScreenState extends State<GraphScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        backgroundColor: const Color(0xFF4A67AD),
        elevation: 0,
      ),
      body: Column(
        children: [
          SizedBox(
            width: MediaQuery.of(context).size.width,
            height: 200,
            child: SfCircularChart(
              series: <CircularSeries>[
                PieSeries<ChartData, String>(
                  dataLabelSettings: const DataLabelSettings(isVisible: true),
                  dataSource: [
                    // Bind data source
                    ChartData('Jan', 35, Colors.red),
                    ChartData('Feb', 28, Colors.white),
                    ChartData('Mar', 34, Colors.blue),
                    ChartData('Apr', 32, Colors.yellowAccent),
                    ChartData('May', 40, Colors.greenAccent),
                  ],
                  xValueMapper: (ChartData data, _) => data.x,
                  yValueMapper: (ChartData data, _) => data.y,
                )
              ],
            ),
          ),
        ],
      ),
    );
  }
}

```

# 画像

![Simulator Screen Shot - iPhone SE (3rd generation) - 2022-12-19 at 22.42.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/28ea722c-10cc-8db6-c6e5-1e790e144078.png)






# 最後に
![Frame 9 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/87f2a488-c5cd-549d-f07f-01b44a1317b8.png)
<b>Veroo</b>は、Blockchain技術を活用した「想いの巡るグルメSNSアプリ」です。食に対する熱量、例えばラーメンがめちゃくちゃ好きで年間400杯食べているとか、変態的に具材にこだわった中華料理を作っているなどのような、今まで直接お金にはならなかった食に対する情熱や熱量、その裏側にある想いがトークンを使うことで巡る世界。自分のラーメンに費やす熱量がコミュニティに承認される。自分がほんとにいいと思って作った食べ物がコミュニティで広まる。Verooは単なるSNSアプリではなく、クリエイターたちの想いが紡がれるソーシャルグルメアプリです。

##### Homepage: https://veroo.xyz/
##### Discord URL：https://t.co/VoT0gpsflA
【Git】リポジトリのルートを取得する方法

## リポジトリルート

リポジトリルートの絶対パスを取得するには次のコマンドを実行します。  

```terminal
git rev-parse --show-toplevel
```

## `.git`

また次のコマンドを実行すると`.git`のパスを取得できます。  

```terminal
git rev-parse --git-dir
```

環境変数`GIT_DIR`が設定されている場合には`GIT_DIR`の値が出力されます。  
リポジトリルートで実行すると`.git`のみが出力されそれ以外の場合には`.git`の絶対パスが出力されます。  

## `.git/*`

また次のコマンドを実行すると`.git`内のファイルやディレクトリのパスを取得できます。

```terminal
git rev-parse --git-path 取得したいファイルなどのパス
```

以下のように実行すると`.git/info/exclude`のカレントディレクトリからの相対パスを取得できます。  

```terminal
$ git rev-parse --git-path info/exclude
../.git/info/exclude
```
コマンドプロンプトを使用してVirtualBoxのゲストOSにSSH接続してみた

### はじめに
Windows端末を使用した際は、よくTeraTermでサーバーにSSH接続していますが、
コマンドプロンプトでTeraTermの様にサーバーにSSH接続できるか試しました。

### 対応手順

**コマンドプロンプトで鍵を生成**
以下のYoutubeを参考にコマンドプロンプトに鍵を生成して、サーバーに公開鍵は登録済みです。
https://www.youtube.com/watch?v=Fz2Kj4q2MrE 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/dbaf1db3-ff01-09ec-eff1-64ffea4b55d9.png)



**SSH接続をしてみました**
SSH接続が上手く行きました。
linuxサーバーにSSH接続出来ているため、問題なくlinuxのコマンドも使用出来ることが分かりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/6f1829ec-1240-2c11-6308-69d03d1c092f.png)

Dockerのサービスのステータスも表示出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/44202722-c8f3-098b-ecb6-e8d26e05be83.png)


**ファイル転送を試しました**
scpコマンドは非推奨のため、sftpコマンドでゲストOSに接続してみました。
ゲストOSの/tmp配下のtestファイルもダウンロード出来ました。

scpコマンドが非推奨な理由は、以下のサイトが勉強になりました。
https://gigazine.net/news/20201111-deprecating-scp/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/6aa82ea8-bf64-8a60-03de-79b2eb5768ff.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/df049af7-5866-ed79-748a-bbfbf88a42bc.png)

**コマンドプロンプトのコマンドの在処を確認した**
C:¥windows¥system32の配下にコマンドプロンプトのコマンドがありました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/b48de272-a4e5-c018-bfa5-de44f2dd1632.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599002/64a04c14-4653-a72f-bf2a-8603bc6166c9.png)

### まとめ


**コマンドプロンプトもWSLもターミナルソフトのため、機能としては同等だという事を知りました。**
知見がある方に伺いましたが、linuxのコマンドは/bin配下ですが、コマンドプロンプトのコマンドは
C:¥windows¥system32の下にssh.exeの様に、実行可能なexeファイルで実行しています。
私の周りでは、あまりコマンドプロンプトでサーバーに接続して作業するというのは、聞いたことがないですが、
今回の検証で意外に使えそうだと思いました。

WSLについては以下のサイトを参考にしてください
https://qiita.com/gama1234/items/5828b2b2e4e9e1365711
Big O 記法について

# はじめに

+ コンピューターサイエンス初学者の初投稿です。
+ Big O 記法について学んだのでそのまとめです。
+ 間違っている場所もあるかもしれません。

## O(1)

配列の添字でアクセスを行う
計算が最も少ない

```java
  public void func1() {
    int[] ints = new int[]{1, 2, 3, 4, 5};

    System.out.println(ints[0]);
  }
```

出力結果
```
1
```

## O(n)

配列の個数分処理を行う
そのため、配列が長くなれば長くなるほど処理時間が増えていく

```java  
  public void func2() {
    int[] ints = new int[]{1, 2, 3, 4, 5};

    for (int i : ints) {
      System.out.print(i + " ");
    }
  }
```

出力結果
```
1 2 3 4 5
```

## O(n * n)

配列の個数２乗分の処理を行う
O(n)と同様に、配列の長さで処理が変わるがnの２乗のため、大幅に計算量が変わる

```java
  public void func3() {
    int[] ints = new int[]{1, 2, 3, 4, 5};

    for (int i : ints) {
      for (int j : ints) {
        System.out.print(i + "-" + j + " ");
      }
      System.out.println();
    }
  }
```

出力結果
```
1-1 1-2 1-3 1-4 1-5 
2-1 2-2 2-3 2-4 2-5 
3-1 3-2 3-3 3-4 3-5 
4-1 4-2 4-3 4-4 4-5 
5-1 5-2 5-3 5-4 5-5 
```

## O(log(n))

分割を行った後に処理を行う
O(1)へと収束が発生するのでO(n)ほど処理回数は多くない

```java
  func4(10);

  public static void func4(int number) {
    if (number <= 1) {
      return;
    }

    System.out.println(number);

    func4(number / 2);
  }
```

出力結果

```
10
5
2
```

## 最後に

まだまだ奥が深そうだが、ひとまず自分の理解したところまで

参考資料

現役シリコンバレーエンジニアが教えるアルゴリズム・データ構造・コーディングテスト入門

https://www.udemy.com/course/python-algo/
larave バリデーション

```
blade
@for($i=0;$i<2;$i++)

<p><td><input type="text" id="i[{{$i}}]" name="n[{{$i}}]" value="{{ old('n.'.$i) }}" ></td></p>

@endfor


validate
public function rules()
{
    return [
        'n'.'.*'  => 'required|max:1',
    ];
}
Canvas2D マスク処理によるはみ出さないブラシ塗りの実装実験

この記事は [Web グラフィックス Advent Calendar 2022](https://qiita.com/advent-calendar/2022/webgraphics) の17目の記事です。（二日遅れ・・・）

# 自作ドローツールで線をはみ出さない塗りがしたい

筆者が個人で作っているElectronベースのドロー系ツールで線をはみ出さない塗りがしたいということで、[前回](https://qiita.com/warotarock/items/66dedd96b6e2056ef58b)まで色々とやってきました。

今回は、ついに最終回といいますか、現状の最終案をご紹介したいと思います。課題もありますが、いちおう自作ツールにも組み込んでみた方法です。

# 処理の概要

一口にはみ出さないといっても色々ですが、今回の方法では、ブラシの中心から見て線分によって遮蔽される部分をはみ出すと考えます。

ブラシは複数の線分で遮蔽される場合がありますので、どこが遮蔽されるのかを「遮蔽マップ」に書き込みます。遮蔽マップは、ブラシ中心を中心として、角度ごとに一番近い線分との距離を記録したものです。遮蔽されない角度はブラシ半径と等しい距離を書き込んでおきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/ec3792ef-931f-1fe0-a8b9-db781b4c131a.png)
なお角度の決め方もいろいろありますが、ここでは右方向をゼロとして反時計回りとしました。

遮蔽マップを作ったら、次にマスク画像を作成します。

色を塗るところを自前でコーディングすれば遮蔽マップだけでいいのですが、Canvas2Dの機能を活用したいのでマスクを使うことにしました。

ブラシのサイズの範囲について、遮蔽マップを参照しながらマスクを塗りつぶしていきます。たとえばブラシ中心からの相対位置が (x, y) だった場合、atan2(y, x) で角度を求めれば、遮蔽マップからその角度の一番近い線分までの距離が取得できます。(x, y)の位置がその距離よりも近ければ遮蔽されていないのでマスクを 1 にし、遠ければ 0 にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59191/4f9ef370-84e1-1a57-394f-4b380b089664.png)

マスク画像ができたら、あとは普通にCanvas2Dでブラシを描画したあとglobalCompositeOperation = 'destination-in' でマスク画像を描画すれば、マスクが1の部分だけを残すことができます。これではみ出した部分が消えるので、はみ出さない塗りが実現できます。

# 実装したもの

<p class="codepen" data-height="720" data-default-tab="result" data-slug-hash="zYLYzKM" data-user="warotarock" 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/warotarock/pen/zYLYzKM">
  Canvas2D マスク処理によるはみ出さないブラシ塗りの実装実験</a> by 柏崎ワロタロ (<a href="https://codepen.io/warotarock">@warotarock</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

# 考察

この実験では１回の描画で１回だけ処理をすればよいのでそれほど重くないのですが、ツールではけっこう膨大な量のブラシの点があるので、現実的な処理時間で実現できるのか問題でした。

それは実際にツールに組み込んでみないと分からないところがあったのでツールで実装してみました。

結果、どうだったかというと・・・

すごく重い。

・ﾟ(゜´Д｀゜)ﾟ・。

線分が1000くらいあって、遮蔽マップで計算する角度が300あって、ブラシの点が1000くらいあるということが今作っているツールでは普通にあるので、ベタに実装すると1000×300×1000の繰り返し回数になってしまいます。そのため、ちょっとした絵でもものすごく重たくなります。

ま、まあでも、高速化というか必要なところだけを計算するような作りにはしていけると思いますので、しばらくこれでツールを作ってくことにしました。

# まとめ

- 遮蔽マップとマスクによる線をはみ出さないブラシ塗りを実装してみた
- マスクを利用することでCanvas2Dの機能を活用できる
- そのままツールに組み込むと激重いので工夫が必要
- 動いたときは嬉しかった

ひとまず、今年のアドベントカレンダーでテーマだったブラシ塗りはこれで完結です。あとは残りの日のどこかで作成中のツールの紹介をできたらと思っております。