OmniAICreator/Qiita-1.07M huggingface dataset:
ssh先でクソ長いビルドを走らせてしまったのにもう寝たい時にすること

# 状況

sshしたラズパイとか結構非力なマシンにsshしてあれこれビルドしようかなーと思って始めた`make`や `make install`とかが終わらなくて泣きたいときにするワークアラウンド。

# 方法

アプローチとしては実行中のコマンドのバックグラウンド化と非所有化(?)。

# 下準備(というか前提)
実行したいコマンド群はあらかじめシェルスクリプトに書いておき、実行するようにしましょう。
`;`で区切って1行にまとめたコマンドはそれぞれが別のジョブになってしまうためです。

## tmuxやscreen使え (2021/12/3追記)
ご指摘ありがとうございます。そうですね。tmuxなどを使うととても良いのですが、お恥ずかしながら使った事がありませんでした。勉強になります。
これらツールの使い方は本題では無いため各自ググって使って下さい。

# 手順

## 1. クソ長いジョブの走っているターミナルで `Ctrl + Z`をし、ジョブ(コマンド)を停止させる。

```
[1]+  Stopped                 make
```

## 2. `jobs`でジョブを確認、`bg` コマンドでバックグラウンドで再開させる。

```
root@ubuntu:~# jobs
[1]-  Stopped                 make
root@ubuntu:~# bg 1
[1]- make &
```

## 3.  `jobs`で走っていることを確認。

```
root@ubuntu:~/repos/snort_src/ragel-6.10# jobs
[1]-  Running                 make &
```
## 4.  `disown`で手放す。

```
root@ubuntu:~# disown -h %1
root@ubuntu:~# jobs
[1]-  Running                 make &
root@ubuntu:~# logout
Connection to xxx.xxx.xxx.xxx closed.
```

おしまい。走っているジョブのPPID(親PID)は1になります。
UiPathのXamlファイルに特定のコメントや表示名のアクティビティがあるか調べる

PowerShellで万全

```
$TargetXaml = "C:\work\sample\Main.xaml" # 検索するXamlファイル

$Xaml = [Xml](("<?xml version=""1.0"" encoding=""utf-8"" ?>`n") + (Get-Content -Encoding UTF8 $TargetXaml))
$XmlNsMgr = New-Object -TypeName System.Xml.XmlNamespaceManager -ArgumentList $Xaml.NameTable

$XmlNsMgr.AddNamespace("sap2010", "http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation")

$ConditionXPath = [String] "//*[contains(@DisplayName , 'はが')]" # アクティビティ表示名に「はが」を含むアクティビティがあるか
# $ConditionXPath = [String] "//*[contains(@sap2010:Annotation.AnnotationText , 'ほげ')]" # 注釈に「ほげ」を含むアクティビティがあるか


if($Xaml.DocumentElement.SelectNodes($ConditionXPath, $XmlNsMgr).Count -gt 0)
{
    Write-Output ("該当ありました: " + $TargetXaml)
}
```

実際にはファイル一覧をGet-ChildItemあたりでごっそり持ってきて順次処理するような使い方になると思います！
WAS設計その13 IHSとWASのトポロジー

まずはWASのトポロジー

水平クラスタ
サーバ毎にアプリケーションサーバを配置する。
※耐障害性に優れる。

垂直クラスタ
サーバ1台にアプリケーションサーバを2台以上構成する。
※たくさんの処理が可能

一般的によく見られるのは
水平クラスタにして垂直クラスタにする。
複数のサーバでアプリケーションサーバを2台以上動作させる。
※障害性もGOOD
※負荷も権限される。

IHSとWASのトポロジー

IHS2台構成　アプリケーションサーバ2個の構成
たすき掛け構成

または
IHS2台構成　アプリケーションサーバ2個の構成
たすき掛けなし構成
※明示的にGenPluginCfgで-webserver.nameを指定する。
※P.102 WAS V8.0 によるWebシステム基盤設計ワークショップ　トポロジー設計
クラスター構成の場合、IHS:WAS=1:1構成にするためplugin-cfg.xmlをGenPluginCfgコ
マンドで生成するか、直接編集する必要がある
xargsと| (パイプ)の違いって？

Linuxコマンドを学習すると、コマンドの実行結果を次のコマンドの引数としてくれるxargsというものが出てきます。

例えば、以下のようなフォルダとファイルがあるとします。
(雑な図ですみません)
![スクリーンショット 2021-11-23 20.43.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1865635/1d4dec62-56ee-6279-c4f7-c10d8829b0e9.png)
以下のコマンドを打ってみます。

```
$ ls test*.txt | xargs cat
>>>
log1
log2
```

lsコマンドで出てくる「test1.txt, test2.txt」をcat（ファイルの中身の表示）の引数としてxargsが架け橋のようにして持ってきてくれて、`cat test1.txt`, `cat test2.txt`を一気に反映してくれます。

ふむふむ。。

ここで自分が気になったのが、「でも、Linuxコマンドには『|』がそもそもあるけど、わざわざxargs使うのってどういうの？」って感じました。

試しに 上記のコマンドをxargs抜きで実行してみました

```
$ ls test*.txt | cat

>>>
test1.txt
test2.txt
```

ファイル名がconcatenateされて出てきました。
摩訶不思議。。

ここで、自分なりに色々調べてみると、
Linuxには「標準出力」と「引数」という区別があるということに行きつきました。
踏み込んだ話になりそうでしたが、Linux初学者（私）が色々調べてみました。

# xargsは何をしているのか？
xargsは「標準入力やファイルからリストを読み込み、コマンドラインを作成して実行する」というコマンドだそうです
（引用元: https://atmarkit.itmedia.co.jp/ait/articles/1801/19/news014.html）

`ls test*.txt | xargs cat`は最初に解説した通り。

# |（パイプ）は何をしているのか？
`パイプとは、Linuxコマンドを使って標準出力された内容を次のコマンドへ橋渡しするために使われるコマンド`
だそうです（引用元: https://academy.gmocloud.com/know/20210630/12090）
つまり、「標準出力」が次のコマンドに引き渡されます。

<hr>

パイプラインと親和性が高いコマンドの一つにgrepコマンドを思い浮かべる方も多いと思いますが、試しにgrepのパターンで見てみましょう

```
ls | grep *st1.txt 
>>> test1.txt

ls | xargs grep *st1.txt 
>>> (何もなし)
```

`ls | grep *st1.txt`はlsコマンドで出力された結果
「test1.txt, test2.txt, hoge.txt」の中から、[*st1.txt]に合致するファイルを検索しているため、
最終的な出力は「test1.txt」になります。

では、`ls | xargs grep *st1.txt `はlsコマンドで出力されたものを「<B>引数</B>」としてgrepに渡している結果、ファイル名として認識せず何も出力されずに終わった、と考えました
（この辺、自分の仮説に近い段階のため、正確な理解をしたらまた書き直します。）

## 終わり
一応、ここで終わるんですが、個人的に使い分けは、利用したいlinuxコマンドをちゃんと理解しなければ使い分けるタイミングは難しいと感じています。

暗記する必要はもちろんないなくて、不具合が出たらその度に調べる必要でいいのかなと思います。


# 今回参考にさせていただいた記事
[xargsとパイプの違いについて](https://teratail.com/questions/63845#:~:text=%E3%83%91%E3%82%A4%E3%83%97%20%EF%BC%9A%20%EF%BC%92%E3%81%A4%E3%81%AE%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE,%3C%EF%BC%89%E3%82%92%E5%90%8C%E6%99%82%E3%81%AB%E3%81%97%E3%81%9F%E7%89%A9%E3%80%82&text=xargs%20%EF%BC%9A%20%E3%81%9D%E3%81%AE%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B%E3%82%92,%E3%81%A8%E3%81%97%E3%81%9F%E3%81%AE%E3%81%A8%E4%B8%80%E7%B7%92%E3%80%82)
[Linuxコマンドで使われるパイプ（|）の使い方を詳しくご紹介！](https://academy.gmocloud.com/know/20210630/12090)
[【 xargs 】コマンド――コマンドラインを作成して実行する](https://atmarkit.itmedia.co.jp/ait/articles/1801/19/news014.html)
Linuxで生成したCSVをVBA(Excelマクロ)で読み込むときの注意点

タイトルに関して結論から言っちゃうと「改行コードに気をつけて」で終わっちゃう話なんですが、
そんな凡ミスで延々と悩み続けてしまったので、備忘録としてきちんと書いときます。

※解決方法はLinux寄り(ShellScriptで解決する方法)で、最下部に書いてます。急いでいるかたはそちらをどうぞ。

## したかったこと
(1) Linuxでカンマ区切りのCSVファイルを生成
↓
(2) PSCPでWindowsへファイル転送
↓
(3) 任意のExcelへCSVをインポート

...というのを、VBA(Excelマクロ)を使ってやりたかったわけです。
※(1) だけはLinuxのShellScriptでやってますが。

## ハマった
やりたいことはすごく簡単なはずなのに、(3) のCSVインポートが下記エラーで引っかかる！
※やり方(コード)はググった結果を試しただけなので、ここでは割愛します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/66078/aa9aa436-9ab5-3090-c909-d3916a5cc3c0.png)
(アプリケーション定義またはオブジェクト定義のエラーです。)

デバッグしてみると、どうやら最初の変数に格納されるデータ量が多すぎるように思えたので、
(2) で転送してきたCSVファイルを編集して行・列を減らしてみると、うまくいく… やっぱりデータ量？

## もしかして...？
行・列をたった１行・１列減らしただけでうまくいくということは、データ量の問題ではない？
もしかして、**Linux/Windowsの文字コードの違い**が原因か！？

と思い、コード変換してからインポートしてみる。(ちなみにコードは下記のような感じ)

```
 # iconv -f utf-8 -t sjis test.pl -o test.csv
```

...が、うまくいかない。状況変わらず。

## あぁ、、そうか
(最初に結論を書いちゃってるので、読み物としては面白くないですが)
そうです、**Linux/Windowsの改行コードの違い**が原因でした...。

言われてみれば当たり前、誰でも知ってる(？)ことなんですが、
> Linux(UNIX/Mac)環境では LF
> Windows環境では CR+LF

これです、これを考慮しておかないとダメなんです。
違いは知ってました。知ってましたけど、なかなか気づけなかったんですよ…。

## で、どうやって解決したか
VBA側で改行コードを変換(置換)するか、[LFコードで改行したファイルを読み込む](https://www.moug.net/tech/exvba/0060089.html) 方法もあるようですが、
~~VBAのコードを書き換えるのが面倒なので~~ 簡潔に、Linux側で改行コードを変換する方法で対応しました。

```
# 変換前 ($はLF)
[user@testsv ~]$ cat -e test.csv
head1,head2,head3$
test1,test2,test3$

# 改行コード変換
[user@testsv ~]$ sed -i -e 's/$/\r/g' test.csv

# 変換後 (^M$がCR+LFです)
[user@testsv ~]$ cat -e test.csv
head1,head2,head3^M$
test1,test2,test3^M$
```
(1) のCSVファイルの生成Scriptに、sed ... の一行を加えるだけで解決！

めでたしめでたし。
Django Gitアップ前のシークレット情報設定

#はじめに
Gitへアップする前のシークレット情報の設定方法を手順化しました。

Pythonのバージョン:3.8.2
djangoのバージョン:3.2.9
gitのバージョン:2.30.2

#目次
1.django-environのインストール
2.「.env」の作成
3.settings.pyの修正
4.「.gitignore」の確認

##インストール
django-environをインストールします。

```
pip install django-environ
```

##フォルダとファイルの作成
BASE_DIR（manage.pyがあるディレクトリ)にsecretsフォルダを作成します。
作成後、secretsフォルダ内に「.env」を作成します。
.envにproject/settings.pyの下記の情報を記載します。

・SECRET_KEY
・DEBUG
・ALLOWED_HOSTS

```python:secrets/.env
SECRET_KEY=secret_key #ここにsecret_keyを貼り付ける ※ダブルクォーテーションは取り除く
DEBUG=True
ALLOWED_HOSTS=*
DATABASE_URL=sqlite:///db.sqlite3
```


##settings.pyの修正
projectのsettings.pyの中を修正していく

```python:project/settings.py
#追記---
import environ

env = environ.Env()
root = environ.Path(BASE_DIR / "secrets")
env.read_env(root(".env"))

#修正---
SECRET_KEY = env.str("SECRET_KEY")
DEBUG = env.bool("DEBUG")
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")

DATABASES = {
    'default':env.db(),
}
```

##.gitignoreの確認
.gitignoreに.envの記載があることを確認
ない場合は追記

```python:.gitignore
# Environments
.env
```
設定は以上
AtCoder C - Back and Forth 解法メモ


2回目の行きの際にはL、Dは必ず一回発生し、U、Rは1回目よりも値が差分+1大きくなる。
同様に2回目帰りの際にはR,Uが必ず一回発生し、D、Rは1回目よりも値が差分+1大きくなる。

上記には気がつけたが、コーディングに落とし込む能力がなかった。

```python

sx,sy,tx,ty = list(map(int, input().split()))
 
x = tx - sx # x座標間の差分を出す
y = ty - sy # y座標間の差分を出す
ans = "R"*x + "U"*y + "L"*x + "D"*y # 1回目の行きと帰り
ans += "D" + "R"*(x+1) + "U"*(y+1) + "L" + "U" + "L"*(x+1) + "D"*(y+1) + "R" # 2回目の行きと帰り
print(ans)



```



参考
https://atcoder.jp/contests/abc051/submissions/27297543
Podmanの環境構築メモ【Mac】

# はじめに

仕事でPodmanを触る機会があったので、[このページ](https://rheb.hatenablog.com/entry/podman-machine)を参考に環境構築をしたところ、
`podman machine init` で __permission denied__ が発生して詰まったのでメモに残します。
同じ様に詰まった方の助けになれば幸いです。

## 環境

macOS : Monterey 12.0.1(Big Surでも同じ現象が起きていたので、アップグレードしました)
Homebrew : 3.3.5
podman : 3.4.2

## 事象

```cmd
$ brew install podman # 特にエラーもなくインストール完了
$ podman machine init
Downloading VM image: fedora-coreos-35.20211029.2.0-qemu.x86_64.qcow2.xz: done  
Extracting compressed file
Error: open /Users/XXX/.config/containers/containers.conf: permission denied
```

permission denied？アクセス権見てみるか…と containersフォルダ の中を見てみると
そもそも containers.conf がいらっしゃらない。

## 対処

とりあえず空のファイルを作ってみるも、特に改善の兆しが見えない。

```conf:/Users/XXX/.config/containers/containers.conf
[containers]

[engine]

[machine]

[network]

[secrets]

```

```cmd
$ podman machine init
Extracting compressed file
Error: open /Users/XXX/.config/containers/containers.conf: permission denied
```

ナンデ？？ファイルツクッタノニ！！
冷静にアクセス権をじっくりと確認すると、 __/Users/XXX/.config に自分のユーザー(XXX)がいない__ 事に気づき
そのままFinderで __.configフォルダに読み/書きの権限を付与__ し
さらに念の為containersフォルダをリネームして退避した後、再度initを実行すると…

```cmd
$ podman machine init
Extracting compressed file
```

お！？エラーにならない！！
containers.confもinitコマンドでしっかり作成されている！
さらに

```cmd
$ podman machine start
INFO[0000] waiting for clients...                       
INFO[0000] listening tcp://0.0.0.0:7777                 
INFO[0000] new connection from  to /var/folders/81/1zq3g5b54zq2yycgpn8z398r0000gn/T/podman/qemu_podman-machine-default.sock 
Waiting for VM ...
Machine "podman-machine-default" started successfully
$ podman machine stop
```

start も stop もできた！とこれで無事にスタートラインに立つことができました。

## アクセス権がなかった原因は何だったのか？

心当たりと言えば、以前Macの[ユーザ名・ホームフォルダ名を変更](https://support.apple.com/ja-jp/HT201548)したのでその弊害だったのか？
明確な原因がわからず少しモヤモヤしますが、私の場合は
__.configフォルダのアクセス権がなく`podman machine init`が実行できなかった__
ので、もし同じ状況の方がいらっしゃいましたらお試しください。

> ぼやき < 時間のない時に限って構築に躓く気がします…
WebAPIをたたく with Python

PythonでWebAPIを叩く方法を簡潔に紹介します。

# 使用するAPI

ここでは[News API](https://newsapi.org/)を扱います。News APIでは世界中のニュースを取得することができます。また、個人で利用する分には十分無料で使えます。

今回はAPIを叩くことだけが目的なので、News APIの使い方には言及していません。

# 実際のコード

```python
import requests

# News APIに登録した際に発行される自分用のAPI KEY
API_KEY = 'Your API KEY'

# APIを叩く!!
res = requests.get(f'https://newsapi.org/v2/everything?q=bitcoin&apiKey={API_KEY}')
res_obj = res.json() # json形式に変換
print(res.status_code) # 200が返ればOK
print(res_obj)
```

#### エンドポイント

特定のリソースに対して与えられた固有の一意なURLのことです。今回の例でいうと、以下に示すように `?` の手前までのURLです。

`https://newsapi.org/v2/everything`

#### パラメータ

ほしい情報を取得するための条件のようなもののことです。今回の例でいうと、2つのパラメータ（q, apiKey）が与えられています。パラメータどうしは `&` でつなげます。

`q=bitcoin&apiKey={API_KEY}`

## 出力例

以下のような出力が得られれば大丈夫です。

```shell
200
{
    "status": "ok",
    "totalResults": 8069,
    "articles": [
        {
            "source": {
            "id": "the-verge",
            "name": "The Verge"
            },
            "author": "Richard Lawler",
            "title": "A fake press release claiming Kroger accepts crypto reached the retailer’s own webpage",
            "description": "A crypto hoax claimed Kroger is accepting Bitcoin Cash. The fake press release was similar to one targeting Walmart earlier this year. The retailer quickly confirmed it’s fake, but not before the cryptocurrency’s price spiked by $30.",
            "url": "https://www.theverge.com/2021/11/5/22765098/kroger-bitcoin-cash-cryptocurrency-hoax-pump-dump",
            "urlToImage": "https://cdn.vox-cdn.com/thumbor/CKp0YjnwF88--mWg1kfPmspvfzY=/0x358:5000x2976/fit-in/1200x630/cdn.vox-cdn.com/uploads/chorus_asset/file/22988084/1234440443.jpg",
            "publishedAt": "2021-11-05T13:32:14Z",
            "content": "A similar hoax earlier this year tied Walmart to Litecoin\r\nIf you buy something from a Verge link, Vox Media may earn a commission. See our ethics statement.\r\nPhoto Illustration by Thiago Prudencio/S… [+1900 chars]"
        },
        {
            "source": {
            # 省略
```

# さいごに

以上がWebAPIをPythonで叩く方法になります。

APIに関してはもっと深く掘り下げて説明しようとすると、HTTP、ステータスコード、REST APIなど取り上げるべき話がたくさんあります。ただし今回はあくまでもWebAPIをどうやって叩くのかだけに注力したかった（~~ダラダラと長い記事を書きたくない~~）のでここで締めます。

それではよい1日を！！
LINEのテキストファイルを分析しやすそうに整形する

# 背景
データ分析のインターン先で、個人タスクとしてFlaskでWebアプリケーションを作成したのですが、LINEのトークスクリプトが結構汚かったので、自分の整形方法を書いてみようと思います。

ちなみに今回の続編記事も書いておりますので、よかったらそちらもご覧ください！

https://qiita.com/ishidao/private/f5efc3b302413d8614bb

# お願い
かなり泥臭くデータ整形していると思います。
そんなことをしなくても「こうすれば良くない？」的なご指摘コメント等いただけたら幸いです。

また、LINEのトークを利用します。
他人とのトークは個人情報の宝庫なので、利用する際はちゃんと相手の許可を取り、扱いには十分気をつけましょう。

# データの取り込み
LINEはtxt形式でトークスクリプトをダウンロードすることができます。
LINEアプリから取得したテキストファイルを、分析環境に持ってきます。
ちなみに僕はローカルのanacondaで分析します。

```
[LINE] {{user名}}とのトーク.txt
```

こんな感じのtxtファイルを触っていきます。python側では、

```python
import pandas
df = pandas.read_csv("[LINE] {{user}}とのトーク.txt", sep='\n') 
```

とすれば読み込むことができます。タブ形式で読み込むとかなり汚いデータフレームが出来上がるので、行ごとに読み込みます。

# データの整形

ここからは皆さんが取得したテキストファイルの中身にもよりますが、LINEのテキストファイルの中身はこんな感じになっていますね。

```
[LINE] {{user}}とのトーク履歴
保存日時：yyyy/mm/dd hh:mm

2021/02/22(月)
11:19	me	こんにちは！

2021/02/23(火)
15:00	user	"ごめんなさい！
全然気づきませんでした！笑"
15:00	user	[スタンプ]

```

me：筆者
user：話者

で会話を一部抜粋した形で掲載してみました。

この生データを見る限り、最初の3行を除けば、
行の形式種類は4パターンありそうです。

- yyyy/mm/dd(day)
- hh:mm    話者    context
- context
- 空白

分析し辛いったらありゃしないですが、これが生データです。笑
あるあるですが、コンペ用のデータではないのでしょうがないですねー。

上記の4パターン別で、データフレームを1行ずつ作成していこうと思います。

## 日付の取得
行によっては日付がない行もあるので、各行に日付を追加していきます。
アルゴリズムはコードをみていただけるとありがたいです。。。

```python
import re

# 正規表現でトークから日付を取得し新しいカラムとして結合する
date_list = []
date_pattern = '(\d+)/(\d+)/\d+\(.?\)'
for talk in df['talks']:
    result = re.match(date_pattern, talk)
    if result:
        date_t = result.group()
        date_list.append(date_t)
    else:
        date_list.append(date_t)
df['date'] = date_list

# talksにおいて日付のカラムはもう必要ないので、そこがTrueのものをisin関数で消す
flag = df['talks'].isin(df['date'])
df = df[~flag]
df.dropna(inplace=True)
```

## トークスクリプトの分割

「時間　話者 context」が1行でミックスされているので分解していきます。

```python
# talks内を、時間、話者、トーク内容で分ける
time_l = []
user_l = []
talk_l = []
date_l = []
count = 0
for date, talk in zip(df['date'], df['talks']):
    # もし正規表現で時間が取れたらスプリットして3つに分ける
    if(re.match('(\d+):(\d+)', talk)):
        try:
            if(len(talk.split('\t')[0]) == 5):
                date_l.append(date)
                time_l.append(talk.split('\t')[0])
                user_l.append(talk.split('\t')[1])
                talk_l.append(talk.split('\t')[2])
                count = count + 1
            else:
                continue
        except:
            talk_l.append("メッセージの送信取り消し")
            count = count + 1
    else:
        talk_l[count-1] = talk_l[count-1] + talk

df = pandas.DataFrame({"date" : date_l,
                        "time" : time_l,
                        "user" : user_l,
                        "talk" : talk_l})
```

コードはこんな感じで、データフレームの上の方を見てみるとこんな感じになります。

![スクリーンショット 2021-11-23 21.13.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/845778/b8bc045b-edf2-1ae7-2a09-fbdddc8de0c0.png)

曜日データは今回使わないので、消してしまいます。

```python
date_l = []
for date in df['date']:
    date_l.append(date[:-3])
df['date'] = date_l
```


# 最後に
これでデータ分析の準備は終了です！
ここから自然言語処理をかけていくわけですね。

個人情報の流出等は十分に気をつけてください。
CXL (Compute Express Link) その1 - CXLで定義されるデバイスと従来技術との違い

私は、メモリデバイスの不揮発性メモリ制御やホストIFなどを扱うソフト屋です。
仕事でCXL(Compute Express Link)まわりの技術に関わっています。
CXL技術に関連するメモ書きを残していこうと思います。
ホストまわりのこと経験・知識共に乏しいので、詳しい親切な方は教えて下さると幸いです。現在、まずはQEMUで、CXLが接続された環境を立ち上げようとしているので、教えて頂けると非常に有難いです。
また、間違い、アドバイス、その他、ご意見やご要望ありましたらお気軽にどうぞ。

#1. CXLとは
CPUとAccelerator間、CPUとMemory間のIFを定義した仕様です。
CXL1.1/2.0の物理層はPCIe Gen.5を使用しており、CXL3.0の物理層はPCIe Gen.6を使用する見込みです。
PCIeで定義されている仕様と、CXLで定義される仕様では、Link Layer/Transaction Layerに違いがあるため、CXLで使用されるBusは、PCIe Busに対してFlex Busと呼ばれます。

#2. CXLで扱うデバイス
CXLの仕様で定義されているデバイスは、下図に示すType1 - Type3のデバイスです。
図中のCXL.mem、CXL.cache、CXL.ioはCXLの仕様で定義されているプロトコルです。

![CXL_DeviceType.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2292852/68d73750-35d4-6bb0-0b09-9bfaecaad368.png "デバイスタイプ")

- Type1デバイス
Root Complexとコヒレンシをとるキャッシュを持つが、Root Complexと共有するメモリ空間を持たないPGAS NICなどのデバイス。

- Type2デバイス
Root Complexとコヒレンシをとるキャッシュを持つが、Root Complexと共有するメモリ空間を持つGPU、FPGAなどのデバイス。デバイスとRoot Complexが共有するメモリ空間は、デバイスとRoot ComplexによりLoad/Storeのアクセスがされる。

- Type3デバイス
Root ComplexがLoad/Storeのアクセスをするメモリ空間を持つデバイス。基本的に、Type3のデバイスは、自発的にメモリ空間上のデータを書き換えることはない。

自分の興味は、Type3デバイスなので、メモではType3デバイスのみを扱います。

#3. 従来技術の問題点

- PCIe
CPUは、PCIeで接続されたデバイスのメモリ空間に対してLoad/Storeはできるが、Uncacheableなアクセスとなる。CPUは、PCIeのメモリ空間のデータを、自身のキャッシュに入れず、読み書きの都度、デバイスにアクセスすることになる。そのため、CPUはデータが必要になる度に、PCIeデバイスアクセスのレイテンシが発生するため、PCIe接続されたメモリは高速な演算をするためのメモリとして使用できない。
余談ですが、従来のシステムにおいて、OSのkernel等のソフトに手を入れて、PCIeで接続されたデバイスのメモリ空間のデータに対して、Cacheableなアクセスを実現しようとしましたが、できませんでした。64bit CPUは、PCIeのメモリ空間のデータに対して、64Bのキャッシュライン単位でのアクセスは行わず、8B単位のアクセスで、読み書きの都度、毎回デバイスにアクセスをしてしまう結果となりました。

- DDR
CPUとDIMM間の信号の品質を確保するために、DDRで接続されたDRAMをCPUから離れた位置に置くことができない。加えて、DRAMの微細化の技術的な限界が見えているため、今後の1枚のDIMMの高容量化には期待できない。
マザーボードのスペースとしての問題と、微細化の技術的な問題で、DDRで接続されるDRAMの容量が頭打ちになる一方でCPUのマルチコア化が進むと、コア当たり使えるメモリ空間が小さくなり、結果として、スワップの頻度増とストレージとメモリのデータの入れ替え頻度増が引き起こされて、データアクセスのレイテンシが増えることになり、CPUは高速な演算をすることができなくなる。

以上、従来技術で将来問題となる、もしくは現在問題となっていることをクリアするために、CXLの仕様が策定されています。

DDRでの接続では、CPUからの指示に対して、定時間で応答するDeterministicな応答がデバイスに求められていますが、CXLではデバイスにDeterministicな応答は求められていません。これにより、DDRのバスでは接続できなかった、不揮発性メモリ(PM: Persistent Memory)を記録メディアとしたデバイスを接続することができるようになっています。
(何故、PMを記録メディアとするデバイスが、Deterministicな応答ができないかは、そのうち書こうと思います)

---
以上、CXLの基礎の基礎な感じのメモでした。
iOS シミュレーターに写真をドラッグ&ドロップすると PHPhotosErrorDomain エラーが発生する

## 概要

macOS に保存されている写真を iOS のシミュレーターで使う際に、mac から シミュレーターにドラッグ&ドロップすればコピーできるとあったため、実施したところエラーが発生した。

## エラー内容

```text
One or more media items failed to import:
ファイルパス: The operation couldn’t be completed. (PHPhotosErrorDomain error -1.)
```

## 解決方法

コピー元のディレクトリー（`xxx`）がダウンロードディレクトリー（`~/Downloads/xxx`）だったため、ホームディレクトリー（`~/xxx`）へ移動したところ解決した。

## 参照 URL

https://developer.apple.com/forums/thread/126307
React Nativeでのstyled-componentsの使用方法

#はじめに
React Nativeでのstyled-componentsの使い方についての記事があまり無かったので備忘録として書いておきます。何か気づき次第追加するかもしれません。

#前提
TypeScriptの使用
yarnの使用
styled-componentsが書ける

#インストール
styled-componentsをReact Nativeで使用するためには専用のパッケージも追加する必要があります。

```
yarn add styled-components
yarn add -D @types/styled-components @types/styled-components-react-native
```

#最小構成で動作確認
expo initで作成されるテンプレートを使ってstyled-componetsでHello,Worldしてみました。

```react:App.tsx
import { StatusBar } from "expo-status-bar";
import { Text } from "react-native";
import React from "react";
import styled from "styled-components/native";

export default function App() {
  return (
    <SComponentView>
      <StatusBar style="auto" />
      <Text>Hello,World</Text>
    </SComponentView>
  );
}

const SComponentView = styled.View`
  flex: 1;
  background-color: #fff;
  align-items: center;
  justify-content: center;
`;
```
注意点はstyledはreactnative専用のものをimportしないといけない点くらいです。ほかはだいたい一緒かなと思います。

#おわりに
簡単ですね。ReactとReact Nativeで開発するならstyled-componentsがいいかなと思います。

#参考文献
[1]:https://suzukalight.com/snippet/posts/2021-04-06-react-native-styled-components

[[1]]:React Native で styled-components を使う
[VyOS] dhcp-serverのリース期間の最大値(備忘録)

#はじめに
公式ドキュメントにも載ってなくて、なんとなく気になったので実験してみました。

コマンドは、

```
set service dhcp-server shared-network-name <name> subnet <subnet> lease '<秒数>'
```

でリース期間を設定することができます。
VyOSのバージョン: vyos-1.3.0-rc5
#リース期間の最大値
実験した結果、**4294967295** 秒 (約136年)でした。
#最小値
実験した結果、**1** 秒でした。
JavaScriptでもっと効率的に記述するfor文

##for文の書き方３選！

###扱うリスト


~~~Javascript
const todos = [
    {
        id: 1,
        title: 'by some strawberries',
        completed: true
    },
    {
        id: 2,
        title: 'buy a fresh cream',
        completed: true
    },
    {
        id: 3,
        title: 'make a birthday cake',
        completed: false,
    },
]
~~~

###出力したい結果
1 'by some strawberries'
2 'buy a fresh cream'

###一般的なfor文

~~~javascript
for(let i = 0; i < todos.length; i ++){
    let todo = todos[i];
    if(todo.completed == true){
        console.log(todo.id, todo.title)
    }
}
~~~
変数iの宣言/変数iの範囲/変数iの増加量とするごくごく一般的な、progateとかでよく扱われる方法。

###inを使ったfor文

~~~javascript
for(let i in todos){
    todo = todos[i]
    if(todo.completed == true){
        console.log(todo.id, todo.title)
    }
}
~~~

宣言した変数iを扱うのではなく、リストのアイテムごとに割り振られた添字扱ってリストを扱う。


###ofを使ったfor文

~~~javascript
for(let v of todos){
    if(v.completed == true){
        console.log(v.id, v.title)
    }
}
~~~
ofを使うとリストの中身でリストを扱うことができる。
【GitHub】スクリーンショットからURLを発行する方法

#はじめに
こんにちは。
こちらの記事では、スクリーンショットからURLを発行する方法を記しています。
誤っている点がございましたらコメントいただけると幸いです。

##手順
READMEの作成をするときに、PC（Mac）で撮ったスクリーンショットを使用したいことがあると思いますが、URLが発行されないので`![テキスト](URL)`この記法では、画像やGIFを表示できません。
そんなときは、**GitHubのIssues** を活用することで解決できます。

###GitHubのIssuesを活用

![GIF](https://i.gyazo.com/0e405d7bf081da6051a6d922eae0aeea.gif)

使用したいスクーンショットをコピーして、Issuesのコメント欄にペーストします。するとURLが発行されます。

###Gyazoを利用する

URLを発行する方法は他にもあり、`Gyazo`というアプリを活用する方法があります。
`Gyazo`は、スクリーンショットで撮った画像やGIFを共有するためのツールで、自動でURLが生成されます。無料で利用できるプランもあるので、興味がある方は使ってみてください！

詳しくは下記のサイトを参照してください。
[Gyazoの使い方をインストールから丁寧に解説！オススメです](https://loop-bitter.com/gyazo/)

<br>


#おわりに
ここまでスクリーンショットからURLを発行する方法についてまとめました。
視覚的にわかりやすくするのに画像やGIFはよく使うと思うので、参考にしていただければと思います！

以上、最後まで読んでいただきありがとうございました！
よければLGTMを押してくれると嬉しいです！
シンプルな オブジェクトの項目一覧取得 サンプル (Salesforce CLI で Anonymous Apex Code 版)

ちょっと Salesforce オブジェクトの項目一覧取得を Salesforce CLI (sfdx) で動作させてみたい時のサンプルをメモしておきます。
この記事は `Salesforce Developer Edition` を利用して記載しています。

# Annonymous Apex Code の記述

`Schema.DescribeSObjectResult` を含む `Annonymous Apex Code` をファイルに記述します。ファイルの拡張子は `.apex` とします。

## myapex.apex

```apex
System.debug('シンプルな オブジェクトのスキーマ表示: Begin.');
Schema.DescribeSObjectResult dsr = Account.sObjectType.getDescribe();
Map<String, Schema.sObjectField> fieldMap = dsr.fields.getMap();

// 項目名の一覧を取得
List<String> fieldNameList = new List<String>();
for (String look : fieldMap.keySet()) {
    fieldNameList.add(look);
}
fieldNameList.sort();

// 項目名の一覧をもとに、全項目取得SOQLを生成
String soql = 'SELECT';
boolean isFirst = true;
for (String look : fieldNameList) {
    if (isFirst) {
        isFirst = false;
        soql += '\n    ';
    } else {
        soql += '\n    , ';
    }
    soql += look;
    System.debug('field: ' + look + ' (' + fieldMap.get(look).getDescribe().getType() + ')');
}
soql += '\n';
soql += '  FROM ' + dsr.getName() + '\n';
soql += '  WHERE IsDeleted = false\n';
soql += '  ORDER BY Name\n';
soql += '  LIMIT 1000';
System.debug('soql: ' + soql);
System.debug('シンプルな オブジェクトのスキーマ表示: End.');
```

## 簡易な解説

* `Account` の情報を取得
* 各項目の情報を簡易に Debug 表示
* 項目名を用いた SOQL 検索テキストを参考出力

# Annonymous Apex Code の実行

## Salesforce CLI (sfdx) ログイン

Salesforce CLI (sfdx) でログインします。

```sh
sfdx auth:web:login -a myorg1
```

## Salesforce CLI (sfdx) で Annonymous Apex Code の実行

先ほど作成した Annonymous Apex Code ファイルを指定して実行します。

```sh
sfdx force:apex:execute -u myorg1 -f myapex.apex
```

## 実行結果

* 実行結果は割愛します。

# 文書情報

* 初出: 2021-11-23

## 関連情報

* [シンプルな オブジェクトからレコード検索 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/a600a1176d18655fcda7)
* [シンプルな オブジェクトへレコード追加 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/f5b37ab6554a6aa67d1f)
* [シンプルな オブジェクトのレコード更新 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/97bd88aa61b77bf5c834)
* [シンプルな オブジェクトのレコード削除 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/baf2f533968176e6e55f)
* [シンプルな オブジェクトの項目一覧取得 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/1bedba5dc9d12bdaa34c)
Colaboratory にて for 文の進捗を可視化する

調べれば無限に出てくるよくある進捗の可視化方法についてメモする。

まずは以下のコードの通りに `tqdm` を import しておく。

```python
from tqdm.notebook import tqdm
```

あとは for 文のところに tqdm をかませると、進捗が可視化できる。
`time` は特に処理がないけれど処理時間の代わりに待機時間として経過してプログレスバーが進んでいく様子を観察するために使った。

```python
import time

for i in tqdm(range(100)):
    time.sleep(0.1)
```
【Amplify】federatedSignInのTypescriptエラーの解消方法

# はじめに
[この動画](https://youtu.be/eqDUSY9KHYE)を参考にAmplify Authを使用してGoogleサインインを追加しようとしたら、以下の記述でTypescriptエラー`「'provider' は型 'FederatedSignInOptionsCustom' に存在しません。」`が発生したので解決策をまとめます。

```js
Auth.federatedSignIn({ provider: "Google" })
```

# 結論
```js
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth/lib/types";
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google }
```
or

```js
Auth.federatedSignIn({ customProvider: "Google" })
```
のどちらかでTypescriptエラーを回避してGoogleサインインが出来ます。

# 型定義ファイルを確認してみる
@aws-amplify/authの型定義ファイルを確認すると3つのオーバーロードが存在します。

```js
federatedSignIn(options?: FederatedSignInOptions): Promise<ICredentials>;
federatedSignIn(provider: LegacyProvider, response: FederatedResponse, user: FederatedUser): Promise<ICredentials>;
federatedSignIn(options?: FederatedSignInOptionsCustom): Promise<ICredentials>;
```
今回直接関係がありそうな、FederatedSignInOptionsとFederatedSignInOptionsCustomの中身を見てみようと思います。

# FederatedSignInOptions
FederatedSignInOptionsにはproviderとcustomStateが存在し、CognitoHostedUIIdentityProviderはenumで各providerが定数で定義されています。

```js
export declare type FederatedSignInOptions = {
   provider: CognitoHostedUIIdentityProvider;
   customState?: string;
};
 
export declare enum CognitoHostedUIIdentityProvider {
   Cognito = "COGNITO",
   Google = "Google",
   Facebook = "Facebook",
   Amazon = "LoginWithAmazon",
   Apple = "SignInWithApple"
}
```
そのため、providerを指定する場合はCognitoHostedUIIdentityProviderをimportし、enumの定数(Google)を指定する必要があります。

```js
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth/lib/types";
Auth.federatedSignIn({ provider: CognitoHostedUIIdentityProvider.Google }
```

やっていることは、

```js
Auth.federatedSignIn({ provider: "Google" })
```
と何ら変わりないが、Typescriptのエラーを回避するためには上記の書き方をしなければいけないらしい。

# FederatedSignInOptionsCustom
FederatedSignInOptionsCustomには、customProviderとcustomStateが存在します。
単純にproviderをcustomProviderに変更すればTypescriptエラーを回避できるみたいです。

```js
Auth.federatedSignIn({ customProvider: "Google" })
```

# おまけ
記事作成時時点(2021/11/23)で[Amplify Docs](https://docs.amplify.aws/lib/auth/advanced/q/platform/js/)には上から2つ目のオーバーロードのみ説明されています。
引数には、provider, response, userが必要です。

```js
federatedSignIn(provider: LegacyProvider, response: FederatedResponse, user: FederatedUser)
```

LegacyProvider

```js
'google' | 'facebook' | 'amazon' | 'developer' | string;
```

FederatedResponse

```js
token: string; // providerから取得したtoken
identity_id?: string; // (任意) providerで指定されたidentity id
expires_at: number; // 有効期限
```

FederatedUser

```js
name: string;
email?: string;
picture?: string;
```
興味がある人はドキュメントを読んで見て下さい。
【PIXI.js】Graphicsのtintで塗りつぶしを設定する方法

beginFillで塗りつぶしたPIXI.Graphicsの色をtintで指定しようとしたら、上書きされずに色がブレンドされたので、その解決策についてまとめる。

PIXI.Graphicsで作成したグラフィックシェイプを塗りつぶす方法はbeginFillとtintの2通りある。

- [beginFill](https://pixijs.download/dev/docs/PIXI.Graphics.html#beginFill)・・・他のグラフィックスメソッド（lineToやdrawCircleなど）から​​endFillが呼び出されるまでの描画を単色で塗りつぶす

```js
const circle = new PIXI.Graphics()
     .beginFill(0xff00ff)
     .drawCircle(0, 0, 100)
     .endFill()
```

- [tint](https://pixijs.download/dev/docs/PIXI.Graphics.html#tint)・・・グラフィックシェイプの色合いを指定する

```js
circle.tint = 0xff00ff
```

後からグラフィックシェイプの色を変更したい場合は、tintで色合いを指定する方がおすすめです。


## グラフィックシェイプの色合いがブレンドされる

ただし、beginFillで塗りつぶした色をtintで上書き指定すると、色合いがブレンドされてしまう。
tintは「塗りつぶし」ではなくあくまで「色合い指定」のプロパティであるため。

例として、beginFillで青色に塗りつぶした色を2秒後にtintで緑色に指定する。
そうすると、グラフィックシェイプは緑ではなく、黒色に変色してしまう。

```js
const circle = new PIXI.Graphics()
     .beginFill(0x0000ff)
     .drawCircle(0, 0, 100)
     .endFill()
 
setTimeout(() => {
  circle.tint = 0x00ff00
}, 2000)
```

![gif1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704193/cc5785d0-28b7-dd8e-f4f1-d4fba4d4bf8f.gif)


## beginFillでは0xffffffを指定する

PIXI.Graphicsで作成するグラフィックシェイプのbeginFillは無条件で0xffffff(白)を使用し、塗りつぶしたい色はtintで指定する。
つまり、beginFillでは無彩色の白を指定し、その後の色指定は全てtintを使うことでブレンドを防ぐことができる。

以下のコードはbeginFillで0xffffff、tintで青色に塗りつぶし、2秒後にtintで緑色に指定している。
GIFを見ての通りブレンドされることなく、2秒後に緑色に変更されていることが分かる。


```js
const circle = new PIXI.Graphics()
     .beginFill(0xffffff)
     .drawCircle(0, 0, 100)
     .endFill()
circle.tint = 0x0000ff
 
setTimeout(() => {
  circle.tint = 0x00ff00
}, 2000)
```

![gif2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704193/4aeb9fcf-8eed-afea-6696-4f5d11f379b7.gif)
なぜ地図に関わり続けるのか

これは、[ベクトルタイル・アドベントカレンダー 2021](https://qiita.com/advent-calendar/2021/vt)の記事です。

tmcw が　[Maps, a decade later](https://www.placemark.io/post/maps-a-decade-later) という記事を書いています。かつて [ベクトルタイルの必然性について](https://qiita.com/hfu/items/6d1a07c56b48f1441535) 書いたときと同様、 Maps, a decade later をなぞって日本語で書き直すスタイルで、なぜ地図に関わり続けるのかを整理してみたいと思います。

## 概要
1. リミックスだから
1. オープンだから
1. 困難だから
1. 人文があるから
1. 複雑だから

## 1. リミックスだから
地図レイヤというのは、任意に組み合わせることができる、視覚的でもあるデータコンポーネントです。地図レイヤというコンセプトのおかげで、この業界は再結合と相互運用を深く考えています。ウェブ地図は、技術的にも法的にも、実時間リミックスです。

## 2. オープンだから
空間に関する共有知はあまりにも大切なため、政府・デジタルプラットフォーマー・スタートアップが対等に参加する状況のもと、オープンソースソフトウェアと規格が優勢になっています。

## 3. 困難だから
地図のラベル配置に例示されるような困難な問題について、速度・美しさ・単純さといった異なる側面からアプローチ可能になっています。開発競争は今でも進んでいます。地図を作るあらゆるステップはチャレンジであり、すべてのステップは改善可能です。

## 4. 人文があるから
地図は人文を取り込み、また人文と接続していて、複雑さや矛盾を具えています。

## 5. 複雑だから
地図は常に難しいです。地図でちょっとしたことを行うのはやりやすくなってきましたが、地図を設計したり、データを扱ったりといった難しいことは、まだ難しいままです。こういった複雑なことは、そもそも今後簡単になり得るのでしょうか。どれだけの「真の複雑さ」がそこにはあるのでしょうか。

## まとめ
地図が好きである、というよりは、地図をめぐってはいろいろなことがある、ということが、地図に関わり続ける理由です。
シンプルな オブジェクトのレコード削除 サンプル (Salesforce CLI で Anonymous Apex Code 版)

ちょっと Salesforce オブジェクトのレコード削除を Salesforce CLI (sfdx) で動作させてみたい時のサンプルをメモしておきます。
この記事は `Salesforce Developer Edition` を利用して記載しています。

# Annonymous Apex Code の記述

`Annonymous Apex Code` をファイルに記述します。ファイルの拡張子は `.apex` とします。

## myapex.apex

```apex
System.debug('シンプルな オブジェクトのレコード削除: Begin.');
List<Account> result = [
    SELECT Id, Name
    FROM Account
    WHERE Name = 'Updated YamadaTanakaHanako Corp' AND IsDeleted = false
    ORDER BY Name LIMIT 1
];
if (result.size() == 0) {
    System.debug('シンプルな オブジェクトのレコード削除: 失敗.');
} else {
    Account delAcct = result.get(0);
    delAcct.Name = 'Updated YamadaTanakaHanako Corp';
    delete delAcct;
    System.debug('シンプルな オブジェクトのレコード削除: 成功.');
}
System.debug('シンプルな オブジェクトのレコード削除: End.');
```

## 簡易な解説

* `Account` から Account レコードを検索
* Account レコードを UPDATE

# Annonymous Apex Code の実行

## Salesforce CLI (sfdx) ログイン

Salesforce CLI (sfdx) でログインします。

```sh
sfdx auth:web:login -a myorg1
```

## Salesforce CLI (sfdx) で Annonymous Apex Code の実行

先ほど作成した Annonymous Apex Code ファイルを指定して実行します。

```sh
sfdx force:apex:execute -u myorg1 -f myapex.apex
```

## 実行結果

* 実行結果は割愛します。

# 文書情報

* 初出: 2021-11-23

## 関連情報

* [シンプルな オブジェクトからレコード検索 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/a600a1176d18655fcda7)
* [シンプルな オブジェクトへレコード追加 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/f5b37ab6554a6aa67d1f)
* [シンプルな オブジェクトのレコード更新 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/97bd88aa61b77bf5c834)
* [シンプルな オブジェクトのレコード削除 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/baf2f533968176e6e55f)
* [シンプルな オブジェクトの項目一覧取得 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/1bedba5dc9d12bdaa34c)
ラズパイ起動時にSORACOMへ自動接続、リモートで黒電話ユニットを起動

知人との作品作りでインフラ部分を担当しましたので、SORACOMの部分を中心に解説します
ラズパイ起動時にSORACOMへ自動接続
-------------------------------------
![2IMG_4840.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/79821386-73a7-41e1-8522-e0c9a7cd89b7.jpeg)



L-02CをUSBモデムとして利用できるように設定します

```
sudo apt-get install wvdial eject
sudo modprobe usbserial vendor=0x1004 product=0x618f
sudo eject sr0
sudo chmod 666 /dev/ttyUSB*
```

soracomへの接続設定をwvdial.confに書き込みます

```
sudo nano /etc/wvdial.conf
```

以下の内容に変更します

```
[Dialer Defaults]
Init1 = ATZ
Init2 = ATH
Init3 = AT+CGDCONT=1,"IP","soracom.io"
Init4 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Dial Attempts = 3
Stupid Mode = 1
Modem Type = Analog Modem
Dial Command = ATD
New PPPD = yes
APN = soracom.io
Modem = /dev/ttyUSB2
Baud = 460800
ISDN = 0
Phone = *99***1#
Username = sora
Password = sora
Carrier Check = no
```

ラズパイ起動の90秒後にwvdialを実行する内容をrc.localに追加します

```
sudo nano /etc/rc.local
```
```
sleep 90
sudo wvdial &
```

PC（自宅のネット回線）からRaspberry Pi（SORACOM回線）にVNCリモート接続
-------------------------------------

SORACOMユーザーコンソールにログインしオンデマンドリモートアクセスを有効にします
VNCなので5900を指定しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/60ebba19-a36a-b234-6ae5-2dabffbb61a7.png)
![vnc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/0d70d76e-f70b-71ca-3215-aa696b4f5910.jpeg)
構成されたアドレスおよびポートをVCNで指定、ラズパイにアクセスできます

リモートで黒電話ユニットを起動
------------------------------------------
![タイトルなし.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/6ad4f568-1b88-7227-a7a5-996d867346af.jpeg)
１）ngrokを起動しURLを取得しコピー
２）pythonスクリプト起動時にパラメーラーとしてURLをペースト
３）TwilioのwebコンソールでWebhookのパラメーターにURLをペースト
４）SIPクライアント（linphone）の起動
黒電話ユニットが起動し、受発信の待機状態になります
組み込み系の知人が、黒電話の信号などをガッツリ解析し
プログラムしている様子はこちらをご覧ください

https://protopedia.net/prototype/2376


背負子をDIY！！
---------------------------------------------
背負子：竹棒、麻紐、シュロ紐、（結束バンドできつく固定！）
![kessoku.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/195e93e8-335e-2787-8c79-9a78dd644eed.jpeg)

肩ひも：麻紐と古タオル（編みました！）
![himo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/e49d8374-e87c-f7d7-3c24-dc48094dcf31.jpeg)

基板固定：木の板、木ねじ（アイロンビーズをスペーサーに！）
![iron.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/2dc74824-da4b-3532-09fa-400db7582ac1.jpeg)

電話機：ネオジム磁石、金属プレート（黒電話が脱着可能に！）
![neo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228252/687f20e1-12e9-2104-f849-4c6d75fc3326.jpeg)

電源：ＵＰＳの使用済みバッテリー（ショルダーバッグに収納！）
小道具：麦わら帽子、スーパーカブ（昭和感の演出にはこれ必須！）

まとめ
----------------------------------------
知人に誘われ作品作りに加わりました。
ほとんどがZoomでのやり取りで
Webカメラを複数同時使用、初めてのオシロスコープ測定、
コマンドの実行画面や、黒電話の操作映像を、OBSで1つの画面に取り込んで録画、
などなど初めての作業で大変でしたが、楽しい時間を過ごせました。


参考にさせていただきました
----------------------
https://uepon.hatenadiary.com/entry/2017/04/08/115936

https://iroridanro.net/?p=24715

スーパーカブc70dx（通称カモメカブ）について

http://www.mr-bike.jp/feature/cub/cub_ca-02.html
シンプルな オブジェクトのレコード更新 サンプル (Salesforce CLI で Anonymous Apex Code 版)

ちょっと Salesforce オブジェクトのレコード更新を Salesforce CLI (sfdx) で動作させてみたい時のサンプルをメモしておきます。
この記事は `Salesforce Developer Edition` を利用して記載しています。

# Annonymous Apex Code の記述

`Annonymous Apex Code` をファイルに記述します。ファイルの拡張子は `.apex` とします。

## myapex.apex

```apex
System.debug('シンプルな オブジェクトのレコード更新: Begin.');
List<Account> result = [
    SELECT Id, Name
    FROM Account
    WHERE Name = 'YamadaTanakaHanako Corp' AND IsDeleted = false
    ORDER BY Name LIMIT 1
];
if (result.size() == 0) {
    System.debug('シンプルな オブジェクトのレコード更新: 失敗.');
} else {
    Account updAcct = result.get(0);
    updAcct.Name = 'Updated YamadaTanakaHanako Corp';
    update updAcct;
    System.debug('シンプルな オブジェクトのレコード更新: 成功.');
}
System.debug('シンプルな オブジェクトのレコード更新: End.');
```

## 簡易な解説

* `Account` から Account レコードを検索
* Account レコードを UPDATE

# Annonymous Apex Code の実行

## Salesforce CLI (sfdx) ログイン

Salesforce CLI (sfdx) でログインします。

```sh
sfdx auth:web:login -a myorg1
```

## Salesforce CLI (sfdx) で Annonymous Apex Code の実行

先ほど作成した Annonymous Apex Code ファイルを指定して実行します。

```sh
sfdx force:apex:execute -u myorg1 -f myapex.apex
```

## 実行結果

* 実行結果は割愛します。

# 文書情報

* 初出: 2021-11-23

## 関連情報

* [シンプルな オブジェクトからレコード検索 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/a600a1176d18655fcda7)
* [シンプルな オブジェクトへレコード追加 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/f5b37ab6554a6aa67d1f)
* [シンプルな オブジェクトのレコード更新 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/97bd88aa61b77bf5c834)
* [シンプルな オブジェクトのレコード削除 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/baf2f533968176e6e55f)
* [シンプルな オブジェクトの項目一覧取得 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/1bedba5dc9d12bdaa34c)
Nodejs: multerでファイルアップロードし、sharpでファイルをリサイズして、S3へファイルをアップロード


###背景

写真アプリを作っていて、一覧画面を作ったが、ファイルサイズが大きくて表示に時間がかかってしまう。そのため、オリジナルファイルの表示ではなく、サムネールを表示し、選択したもののみをダウンロード表示するような仕組みに変更することにした。そこで、サムネールの作る必要があったため、そのメモとなる。

仕組み的には、Multerでファイルをアップロードし、アップロードしたファイルをSharpでリサイズして、私が利用しているS3へオリジナルファイルとサムネールの両方をアップロードする仕組み。

###Multer

https://qiita.com/tadnakam/items/d21d014e09cfa98437a8

Multer自体は上記の説明が詳しいですが、私は単一ファイルのアップロードを利用して、特にStorageなども使ってはない。
RoutesでMulterを定義した。

```route.js
// ファイルをアップロードし、一時保管するフォルダを定義
var multer  = require('multer');
var upload = multer({ 
    dest: 'uploads/', 
    limits: {
        fieldSize: 25 * 1024 * 1024 
    }

})

// Multerをミドルウェアとして利用しているコードの部分だけ抜粋。
router.post('/:albumid/upload', authenticateJWT, upload.single('formtest'), PicturesController.uploadNewPicture);


```

上記のように定義して、実際私とControllerにてアップロードしたファイルを参照したかったですが、
少し上記の文章と異なる部分があった。
req.fileでは、undefinedになっている。
そのため、req.fileではなく、req.body.fileを利用した。

```Controller.js
  // 上記の参照した文章では、下記のコードでファイルを参照していたが、私はUndefinedになっている。
  file = req.file 
  // 私は下記のようにreqのbodyからファイルを取得することができた。
  file = req.body.file
  
```

###Sharp

https://sharp.pixelplumbing.com/api-resize#resize

上記はSharpの公式ドキュメントである。
私が直面したエラーが一つあり、下記である。

Error: Input file contains unsupported image format

私はフロントエンドでFileReaderを利用して、ファイルを取得している。
最初は全然気にしていなかったが、下記のサイトで下記のようなコメントがある。

>The blob's result cannot be directly decoded as Base64 without first removing the Data-URL declaration preceding the Base64-encoded data. To retrieve only the Base64 encoded string, first remove data:*/*;base64, from the result.

https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL

Data-URL宣言を削除してから、base64でエンコードしたファイルになるようです。
そのため下記のような変換が必要となる。


```Conntroller.js

   // req.body.fileをそのままSharpのinputとして入力するとエラーになる。
   // Error: Input file contains unsupported image format 
   imagefile = Buffer.from(req.body.file.replace(/^data:image\/\w+;base64,/, ""),'base64');

   sharp(imagefile)
      .resize(200,200, {
        // リサイズする時のオプション設定、詳しくは上記の公式サイトへ
        // アスペクト比を維持しながら、画像のサイズをできるだけ大きくする
        fit: sharp.fit.inside,
        // ファイルサイズが指定のサイズより低ければ変更しない
        withoutEnlargement: true
       })
       .toFormat('jpeg')
       .toBuffer()
       .then(function(outputBuffer){
            // Upload image file to S3
            // 実際、オリジナルファイルとサムネールを両方S3へアップロードしている。
            // imagefile と outputbufferをs3.putObjectを利用してアップロードすれば良い。
       }

```

###S3

次いでにS3へファイルをアップロードするコードも添付。

```s3method.js

    // Setting up S3 upload parameters
    const params = {
        Bucket: process.env.MyPhotoBucket,
        Key: s3key,
        ContentType: 'image/jpeg',
        ContentEncoding: 'base64', 
        Body: bufferfile
    };

    // Uploading files to the bucket
    var s3response = await s3.putObject(params, function(err, data) {
        if (err) {
            console.log("error happend when upload file to s3");
            console.log(err);
            throw err;
        }
        console.log(`File uploaded successfully. ${data}`);
    }).promise();


```

以上です。
シンプルな オブジェクトへレコード追加 サンプル (Salesforce CLI で Anonymous Apex Code 版)

ちょっと Salesforce オブジェクトへのレコード追加を Salesforce CLI (sfdx) で動作させてみたい時のサンプルをメモしておきます。
この記事は `Salesforce Developer Edition` を利用して記載しています。

# Annonymous Apex Code の記述

オブジェクトの insert を含む `Annonymous Apex Code` をファイルに記述します。ファイルの拡張子は `.apex` とします。

## myapex.apex

```apex
System.debug('シンプルな オブジェクトへレコード追加: Begin.');
Account newAcct = new Account(
    Name = 'YamadaTanakaHanako Corp'
);
insert newAcct;
System.debug('シンプルな オブジェクトへレコード追加: End.');
```

## 簡易な解説

* `Account` を作成して Account オブジェクトに INSERT

# Annonymous Apex Code の実行

## Salesforce CLI (sfdx) ログイン

Salesforce CLI (sfdx) でログインします。

```sh
sfdx auth:web:login -a myorg1
```

## Salesforce CLI (sfdx) で Annonymous Apex Code の実行

先ほど作成した Annonymous Apex Code ファイルを指定して実行します。

```sh
sfdx force:apex:execute -u myorg1 -f myapex.apex
```

## 実行結果

* 実行結果は割愛します。

# 文書情報

* 初出: 2021-11-23

## 関連情報

* [シンプルな オブジェクトからレコード検索 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/a600a1176d18655fcda7)
* [シンプルな オブジェクトへレコード追加 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/f5b37ab6554a6aa67d1f)
* [シンプルな オブジェクトのレコード更新 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/97bd88aa61b77bf5c834)
* [シンプルな オブジェクトのレコード削除 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/baf2f533968176e6e55f)
* [シンプルな オブジェクトの項目一覧取得 サンプル (Salesforce CLI で Anonymous Apex Code 版)](https://qiita.com/igapyon/items/1bedba5dc9d12bdaa34c)
* [Salesforce の Userレコードを Anonymous Apex Code で追加するメモ](https://qiita.com/igapyon/items/3bca5c1a12cfac26d43f)
2018年に公開したAlexaスキルでもAWSプロモをもらい続けている件

本記事はスマートスピーカーアドベントカレンダー2021の21日目の記事です。

記事そのものは11月23日の勤労感謝の日に書いています。
ミュートにしているのに記事を見てしまった方はお疲れさまです。



https://qiita.com/advent-calendar/2021/smart-speaker

さて、最近になってこんなことを耳にしました。
「AlexaスキルでのAWS利用クーポンがこなくなった」

たしかに、以前は1つでもスキル公開していると月間100ドル分の利用クーポンが自動発行されていたと記憶しています。

私は業務上、Alexaスキルをリリースしているアカウントはいくつかあります。
さすがに依頼されたスキルをすべて自分のアカウントで公開というわけにもいきません。

その中で2018年中にしかリリースしていないアカウントがあります。
けれども、AWSの利用クーポンは未だに頂いているのが現状です。　
※少なくともここ数ヶ月は。

で、そのアカウントのメールを漁っていたら
2021/07/14 8:30
に以下のメールがきてました。
※本件のメールの公開は禁止事項に入ってない

![Alexaクーポン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67398/054fe7a5-8194-ce70-ed22-c6d830f4bfb5.png)

へぇ。
メール内のリンク先に以下のサイトへのリンクがありました。

https://developer.amazon.com/ja-JP/alexa/alexa-skills-kit/new/aws-promotional-credits

ただ、、、私は申し込んだ記憶が一切ないです。
むしろこのアカウントはAlexa-hostedのスキル公開すらしてない気がします。

それでも以下のようなメールが毎月きています。
金額が異なる場合があるので、規約通り利用頻度に応じてこの金額が変動するのでしょう。

![50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67398/4f678c1b-dc8d-d30d-4399-c64712677c4e.png)

2018年にリリースしたスキルで未だに毎月50ドル相当がもらえるのなら開発環境として試せる幅が増えて良いですね。
おそらく最低金額は25ドルと思われるので、何か1つリリースしておけばもらえるでしょう。

以上
「WSL2 + Docker」が遅いなら、速くすればいい

# はじめに

自分はよく、「WSL2 + Docker + Laravel + React(or Vue)」環境で開発していて、動作が遅すぎて毎度イライラし、作業効率を大幅に下げていました。
シンプルにメモリのせいだと思い、メモリを増築・・・
しかし、それでも大差のない遅さ。

なんでだろうと思って色々調べたときに、対策したメモです。（Windows環境です。）

Mac環境であれば、@ucan-labさんの
https://qiita.com/ucan-lab/items/a88e2e5c2a79f2426163
をご参照ください。大変わかりやすいです。いつも大変お世話になっております・・・

ちなみに、ReactやVueとかの環境を作っている場合にもかなり効果的でした。
（npm run devとかするときですね。）

# 結論

```
「\\wsl$\Ubuntu-20.04\mnt\」配下に、プロジェクトを配置するのではなく、
「\\wsl$\Ubuntu-20.04\home\」配下に、プロジェクトを配置。
※Ubuntuのバージョンは、良しなに・・・
```

つまり、

```
「¥¥wsl$\Ubuntu-20.04¥home¥」配下に、
Dockerfileとかdocker-componse.ymlがある場所で
「docker-compose up -d --build」とかをしてみる。
```

ということです。

# 内容


動作が遅くなっている理由として、

```
WindowsとLinuxのOSファイルシステム間でのファイル読み込みが遅くなっていることが原因です。
```

WSLがどういう構造で、どういうフォーマット形式で動作しているのかなどの確認をしたい場合には、
参考のリンクを参照ください。めちゃくちゃわかりやすいです、どちらも。

# 所感

ほんと、とんでもなく速くなっているので、なんでもっと早く気付かなかったのだろうと・・・
とにかく、「WSL2 + Docker + Laravel + React(or Vue)」などの環境で動作が遅いことを気にされている方は一読を。

# 参考
https://www.aska-ltd.jp/jp/blog/197
https://snyt45.com/posts/20210806/wsl2-multiple-linux-distribution/
CData Connectを活用してデータを全社員に利用してもらうための取り組み

この記事は、CData Connectの入門記事のつもりで書いています。

企業活動を行っていれば、日々たくさんのデータが会社に溜まります。
それらのデータは蓄積される場所も様々であることが多く、あるものはMySQLなどのRDBMS、またあるものはパブリッククラウドのDWHであったりするでしょう。
これらのデータベースは、エンジニアにとっては容易にデータをクエリできる一方で、非エンジニアのメンバーにはSQLの習得といったハードルがあるのも事実だと思います。
そのような状況ではデータのサイロ化が発生しやすいですし、非エンジニア部門がエンジニアにデータの取得を依頼するような本来不要な業務が発生することもあります。

ほぼ全ての社員がSQLを活用できるのが理想であると思いますが、そのためには多大なコストを払う必要があり、実現が困難である場合のほうが多いと考えています。
そこで、私が注目しているのはExcelやGoogle Sheetsなどの表計算ソフトです。
表計算ソフトの素晴らしい点は、コンピュータを利用する人であれば大体誰でも使えることだと思います。

どんなデータでも表計算ソフトに入れてしまえば、データにアクセスできる社員を増やすことができます。
問題は、どのようにそれを実現するかです。
様々なサービスがこの問題にアプローチしている認識を持っていますが、今回はCData Connectを利用してみます。

## 目的

今回検証することは、**CData Connectに接続したデータを、Google Sheetsで閲覧できること**です。
データソースは問いませんが、検証用に公開範囲を気にせずに利用できるデータとしてGCPの[公開データセット](https://cloud.google.com/solutions/datasets)しか当てが無かったので、BigQueryをデータソースを利用します。

:::note info
Google SheetsにはBigQueryのデータを取り込む機能があるので、CData Connectを利用する必要は無いのですが、CData Connectを抽象層と捉え、データの接続元を気にしなくて済む点に価値を感じています
:::

## BigQueryとの接続

まずはBigQueryをCData Connectに接続します。
CData ConnectのConnectionsメニューから、BigQueryを選択し、Project IdとDataset Idを入力します。
この時のProject Idは、クエリを実行するProject Idである必要があります。
そのため、公開データセットを利用する場合は、1度自分のGCPプロジェクトへデータをインポートしてから利用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283590/16038d45-bd85-6e66-2650-974b4ea15c55.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283590/5968b76f-d3e2-8b02-7d89-1ea65b6e314b.png)

ここからはほとんど画面の指示に従うだけで、非常に簡単にCData ConnectにBigQueryのデータを接続できました。
CData ConnectのUIからデータをクエリすることもできるのですが、データのスキャン容量は表示されないので、高額課金の事故を防ぐため避けることにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283590/708e6f24-bbbd-3450-58b7-d0fb0d852735.png)

## Google Sheetsとの接続

CData Connectに接続したデータは、BIツールやGoogle Sheetsで表示することができます。
記事執筆時点で対応しているのは、Data Studio(データポータル)とGoogle Sheetsだけのようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283590/71677236-4046-02da-4163-24ce153b0719.png)

GCPを利用している私には非常に都合が良いのも、CData Connectを選択した理由です。
今後様々なツールに対応すれば、より利用範囲が増やせそうです。

ここでGoogle Sheetsを選択すると、アドオンのインストールを促されるので従います。
インストールすると、Sheetsのアドオンメニューに`CData Connect Cloud`が表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283590/4e1ad1be-8d30-2c62-a23f-74cd1860c9fb.png)

あとはTableやカラムを選択すると、次のようにSheetsでデータを表示できます。
1度追加したデータを更新することも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283590/18b9afb0-ee6b-fcf3-f741-4bf3d24964e3.png)

## まとめ

ここまで読んでいただけると、何も難しいことがないことをお察しいただけると思います。
私はこの**何も難しいことがない**という点にCData Connectの価値を感じました。
SQLやプログラムの知識も不要で、多種多様なデータソースを利用することができて、下手にデータを移行して同じことをやるくらいなら、CData Connectを利用した方が話が早い場面もありそうです。
[UE4]NiagaraのModuleScriptを触ってみる

#はじめに
この記事は「[Advent Calendar 2021](https://qiita.com/advent-calendar/2021/ue)」その2の24日目の投稿記事です。

ぷちコンで応募した作品のナイアガラモジュールのスクリプトがあるのでそちらの紹介をしたいと思います。
#####できあがったもの
グレーマンが動いたときに周辺にあるエフェクトを動かすものができました。
<iframe width="1904" height="711" src="https://www.youtube.com/embed/RjWuDFlKitI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

バージョンはUE5.0で作成しています。

#プロジェクトの解説
下記フォルダに今回主に追加したアセットを追加しています。
Contents/Game/Niagara/
NE_Snow ： 雪を降らせるナイアガラエミッタ
NS_Snow ： 雪を降らせるナイアガラシステム
NM_Wind ： グレーマンが近くを走った時にノイズ値を計算するナイアガラモジュールスクリプト

###各アセットの解説
####NE_Snow
SPHERE LOCATIONの範囲にエフェクトを発生させて、GRAVITY FORCEで少しずつ落下させるエフェクトになります。
グレーマンが動いたときに近くのエフェクトを動かすためにモジュールのNM_WINDとCURL NOISE FORCEを追加しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536845/b9a8719a-6646-1590-2ad3-46d302b4cf49.png)
グレーマンの位置、移動速度はレベルBPでエフェクトに設定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536845/0c4b040a-6c52-e718-2acf-c1d5a928ed97.png)


####NS_Snow
上記NE_Snowを持っており、レベル上に配置しているアセットです。

####NM_Wind
エフェクトの位置からグレーマンの位置(入力 Location)の距離、速度(入力 VelocitySize)に応じてノイズの数値を計算しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536845/5e103fbc-599e-5d06-6461-8e3461ef67a2.png)
引数の説明
Location：グレーマンの位置
Position：パーティクルの位置
WindDistance：風(ノイズ)を発生させる距離
NoiseRate：VelocitySizeの倍率
VelocitySize：グレーマンの速度

上記モジュールで計算した結果をWindNoiseに渡しており、CURL NOISE FORCEのNoise Strengthに渡してグレーマンの周辺だけエフェクトのノイズを発生させています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536845/2ca83e75-d055-5e18-664b-3e4c5efb1b82.png)

#応用して、桜の花びらを舞わせる
上記を応用して桜のメッシュをNiagaraに設定等をすることにより、下記動画のようなこともできましたが、
CurlNoiseの値が大きすぎると違和感が出るのでいい感じに調整する必要がありました
<iframe width="1904" height="711" src="https://www.youtube.com/embed/_XAh_3LizKk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

#おわりに

ナイアガラのモジュールスクリプトを使用して自前でエフェクトの動きを実装してみました。
どんなエフェクトの動きを実装したいかのイメージがついていれば手探りの実装でも何とかなりそうでしたので、これから触る方などの参考になれば幸いです。