OmniAICreator/Qiita-1.07M huggingface dataset:
TypeScriptを使うと、emotionを使うためにbabel pluginがいらなくなる理由を調べてみた

TypeScript 4.1以上だと、emotion/reactを動かすために必要な設定はこれだけになります。

```tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react"
  }
}
```

https://emotion.sh/docs/typescript

旧JSXランタイムで使っていた時は、`@emotion/babel-preset-css-prop`を別途インストールして使っていたのですが、これが不要になりました。
このライブラリは内部でbabel pluginを使っているようです。

冒頭の設定をするだけでemotionが使えるということで、tsconfigがどう関係しているのか？というところから分かっていなかったので調べてみました。

## 旧ランタイムの場合

React 17から新ランタイムが導入されました。

https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

以前は、以下のように

**In**
```jsx
import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}
```

**Out**
```js
import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}
```

`import React`を書いておいて、babelによってReact.createElementに変換していました。

しかし、emotionを使っている場合は旧ランタイムのときから、emotionで定義されている`jsx`を使ってJSXをコンパイルしていました。

https://github.com/emotion-js/emotion/tree/v10.0.6/packages/babel-preset-css-prop

**In**
```jsx
const Link = props => (
  <a
    css={{略}}
    {...props}
  />
)
```

**Out**

```js
import { jsx as ___EmotionJSX } from '@emotion/react'

(一部略)

const Link = props =>
  ___EmotionJSX(
    'a',
    _extends(
      {
        css: _ref
      },
      props
    )
  )
```

## TypeScript 4.1 以降

TypeScript 4.1で`compilerOptions`の`jsx`に`react-jsx`が追加されました。

https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#jsx-factories

https://www.typescriptlang.org/tsconfig#jsx

これは、新ランタイムを使えるようにするための機能で、以下のように変換されるようになります。
これにより、`import React`を手で書く必要がなくなっています。

**In**
```jsx
export const HelloWorld = () => <h1>Hello world</h1>;
```
**Out**
```js
import { jsx as _jsx } from "react/jsx-runtime";
import React from 'react';
export const HelloWorld = () => _jsx("h1", { children: "Hello world" });
```

さらに、`jsxImportSource`で、`jsx`の関数を呼び出すモジュールを指定することができるようになりました。

https://www.typescriptlang.org/tsconfig#jsxImportSource

先程、

```js
import { jsx as _jsx } from "react/jsx-runtime";
```

と出力されていたところが、tsconfigに以下のように設定することで、`jsx`の関数を`@emotion/react`から呼び出すことができるようになりました。


```tsconfig.json
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@emotion/react"
  }
}
```

これによって、babel pluginが不要になったようです。

## jsx pragmaについて

https://emotion.sh/docs/css-prop#babel-preset

ちなみにbabelの設定ができないような環境では、元々、以下のようにjsx pragmaを使う方法もあります。

```ts
/** @jsx jsx */
import { jsx } from '@emotion/react'
```

このjsx pragmaもJSX fragmentsをコンパイルする時に使う関数を選択しているようです。

https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#pragma

## 参考

- [Emotion – TypeScript](https://emotion.sh/docs/typescript)
- [Introducing the New JSX Transform – React Blog](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html)
- [Announcing TypeScript 4.1](https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#jsx-factories)
- [TypeScript: TSConfig Reference - Docs on every TSConfig option](https://www.typescriptlang.org/tsconfig#jsx)
- [@babel/plugin-transform-react-jsx · Babel](https://babeljs.io/docs/en/babel-plugin-transform-react-jsx)
Switchbot APIの使い方～デバイスIDの取得～

GoogleAppsScriptでSwitchbot機器のデバイスIDを取得する方法を解説します。

# トークンとシークレットの入手
まずはAPI認証に用いるトークンとシークレットを入手します。
SwitchBotアプリの[設定] > [開発者向けオプション]から入手可能です。手順は以下の通り。

1. [プロフィール]タブから[設定]を開きます。
![S__5054472.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451285/d74861be-242e-8653-bc4a-9ac41a7a36f8.jpeg)

2. [アプリバージョン]を連打すると出てくる[開発者向けオプション]を開きます。
![S__5054470.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451285/8393d32e-6f6d-f13a-28a8-5e3801ad12f5.jpeg)

3. トークンとシークレットをメモしておきましょう。
![S__5054471.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/451285/fa150ad5-e58d-1deb-d6bf-a27d8e3403ab.jpeg)

これが漏洩すると他社が自分の家の家電の情報を入手したり操作できたりしてしまうので注意しましょう。

# デバイス情報一覧の取得
当記事では [Switchbot API v1.1](https://github.com/OpenWonderLabs/SwitchBotAPI)を利用していきます。GoogleAppsScriptで以下のコードを実行しましょう。

```javascript:getDeviceInfo.gs
// // SwichBotAPIのサービスURL、認証情報
const url = 'https://api.switch-bot.com'
const token = "xxxxxxxxxxxxxxx"//Swichbotのトークン（アプリの開発者オプションから取得）
const secret = "xxxxxxxxxxxxxxx"//Swichbotのクライアントシークレット（アプリの開発者オプションから取得）

//SwitchBotに登録されているデバイスの一覧を表示する。
function getDeviceInfo() {
  const path = '/v1.1/devices'
  const nonce = Utilities.getUuid() // 任意の文字列で可 

  let timestamp = new Date()
  timestamp = timestamp.getTime().toString()

  let sign = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256, token + timestamp + nonce, secret)
  sign = Utilities.base64Encode(sign).toUpperCase()

  headers = {
    'Authorization': token,
    'sign': sign,
    't': timestamp,
    'nonce': nonce
  }
  const options = {
    'method': 'GET',
    'headers': headers,
  }
  Logger.log(UrlFetchApp.fetch(url + path, options).getContentText())
}
```
すると以下のようなレスポンスがあると思います。（内容は登録されている機器により異なります。）
```
{
	"statusCode": 100,
	"body": {
		"deviceList": [
			{
				"deviceId": "XXXXXXXXXXXXXXX",
				"deviceName": "ロック",
				"deviceType": "Smart Lock",
				"enableCloudService": true,
				"hubDeviceId": "F47E42F891A4",
				"master": true
			},
			{
				"deviceId": "XXXXXXXXXXXXXXX",
				"deviceName": "Hub Mini A4",
				"deviceType": "Hub Mini",
				"enableCloudService": false,
				"hubDeviceId": "000000000000"
			}
		],
		"infraredRemoteList": [
			{
				"deviceId": "XX-XXXXXXXXXXXXXXX-XXXXXXXX",
				"deviceName": "エアコン",
				"remoteType": "Air Conditioner",
				"hubDeviceId": "XXXXXXXXXXXX"
			},
			{
				"deviceId": "XX-XXXXXXXXXXXXXXX-XXXXXXXX",
				"deviceName": "照明",
				"remoteType": "Light",
				"hubDeviceId": "XXXXXXXXXXXX"
			}
		]
	},
	"message": "success"
}
```

デバイスID等のデバイス情報を取得することができました。デバイスIDは個々の機器の操作をするAPIを呼ぶときに用います。
SoftEther VPNをパフォーマンスが出るようにビルドしてセットアップした

# SoftEther vpnのビルド

https://jp.softether-download.com/ja.aspx のSoftEther VPN Server/Bridgeアプリケーションは、Linuxサーバにおいては、CPUリソースをフルに使ってくれないので、ソースコードからビルドし、これを解決するため、いちからビルドしてインストールするようにしたい。

## 必須パッケージのインストール

RHEL系
```shell:RHEL系OSの場合
$ sudo dnf install wget make gcc readline-devel ncurses-devel openssl-devel zlib-devel
```
Debian系
```shell:Debian系OSの場合
$ sudo apt install build-essential libz-dev
```

## ビルド

### 最新版を拾ってくる

https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/releases/ から、最新バージョンのソースコードをDLしてくる。

v4.39-9772-betaだと、https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/releases/download/v4.39-9772-beta/softether-src-v4.39-9772-beta.tar.gz となる。

```
$ wget https://github.com/SoftEtherVPN/SoftEtherVPN_Stable/releases/download/v4.39-9772-beta/softether-src-v4.39-9772-beta.tar.gz
```

### 展開

```
$ tar xzvf softether-src-v4.39-9772-beta.tar.gz
$ cd v4.39-9772
$ ./configure
---------------------------------------------------------------------
SoftEther VPN for Unix

Copyright (c) Daiyuu Nobori.
Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan.
Copyright (c) SoftEther Corporation.
Copyright (c) all contributors on SoftEther VPN project in GitHub.

License: The Apache License, Version 2.0

Read and understand README.TXT, LICENSE.TXT and WARNING.TXT before use.
---------------------------------------------------------------------

Welcome to the corner-cutting configure script !

The Makefile is generated. Run 'make' to build SoftEther VPN.
$ make -j$(nproc)
```
## インストール

以下はVPN bridgeをインストールする場合。VPN Serverなどの場合は、適宜置き換える。

```systemd:vpnbridge.service
$ sudo cp -r bin/vpnbridge /usr/local/bin/
$ sudo cp -r bin/vpncmd/* /usr/local/bin/
$ sudo chown `whoami`: /usr/local/bin/hamcore.se2
$ sudo cat << 'EOT' | sudo tee /etc/systemd/system/softether-vpnbridge.service
[Unit]
Description=SoftEther VPN Bridge
After=network.target auditd.service
ConditionPathExists=!/usr/local/bin/do_not_run

[Service]
Type=forking
EnvironmentFile=-/usr/local/bin/vpnbridge/vpnbridge
ExecStart=/usr/local/bin/vpnbridge/vpnbridge start
ExecStop=/usr/local/bin/vpnbridge/vpnbridge stop
KillMode=process
Restart=on-failure

# Hardening
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full
ReadOnlyDirectories=/
ReadWriteDirectories=-/usr/local
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SYS_NICE CAP_SYS_ADMIN CAP_SETUID

[Install]
WantedBy=multi-user.target

EOT

$ sudo systemctl daemon-reload
$ sudo systemctl enable --now softether-vpnbridge
```

### 設定を構成する

あとは適宜設定をする。

## 最後に

正直めんどくさいのでこんなことするならtailscaleとか使ったりしてよしなにしたほうが良い。どうしてもVPN使うならpritunlとかでもいいし。
一時的なswapのつくりかたおさらい

# 概要
GCE e2-microみたいなメモリが少ない環境でswapを作成する。
Ansible流してって言われたときにあまりにスペックが低すぎてメモリが足りずに踏み台サーバが壊れたのでやむ無しにswapを作って流した。
最近swapなんて使うことがないので、すっかり忘れていた。

参考: https://centos.bungu-do.jp/archives/65

# 作業
```
# dd if=/dev/zero of=/mnt/swapfile bs=1M count=2048
2048+0 records in
2048+0 records out
# mkswap /mnt/swapfile
mkswap: /mnt/swapfile: insecure permissions 0644, 0600 suggested.
Setting up swapspace version 1, size = 2 GiB (2147479552 bytes)
no label, UUID=7d4c9699-a66c-4d84-9cac-d38b71cb4f5c
# chmod 600 /mnt/swapfile
# swapon /mnt/swapfile
# swapon -s
Filename				Type		Size	Used	Priority
/mnt/swapfile                          	file    	2097148	0	-2
# echo '/mnt/swapfile swap swap defaults,nofail 0 0' >> /etc/fstab
$ sudo reboot
$ free -mh
              total        used        free      shared  buff/cache   available
Mem:          708Mi       252Mi       198Mi       4.0Mi       257Mi       347Mi
Swap:         2.0Gi          0B       2.0Gi
```

# 最後に
素直に一時的にサーバスペックを高いものにして流すとかしましょう。
APT/DNFのパッケージ自動アップデート設定

## APT
https://www.mk-mode.com/blog/2019/10/14/debian-10-automation-security-update 参考
```
$ sudo apt install unattended-upgrades apt-listchanges
$ echo 'APT::Periodic::Update-Package-Lists "1";' | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades
$ echo 'APT::Periodic::Unattended-Upgrade "1";' | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades
$ sudo tee /etc/apt/apt.conf.d/02periodic <<EOF >/dev/null
// Control parameters for cron jobs by /etc/cron.daily/apt //

// Enable the update/upgrade script (0=disable)
APT::Periodic::Enable "1";

// Do "apt update" automatically every n-days (0=disable)
APT::Periodic::Update-Package-Lists "1";

// Do "apt upgrade --download-only" every n-days (0=disable)
APT::Periodic::Download-Upgradeable-Packages "1";

// Run the "unattended-upgrade" security upgrade script
// every n-days (0=disabled)
// Requires the package "unattended-upgrades" and will write
// a log in /var/log/unattended-upgrades
APT::Periodic::Unattended-Upgrade "1";

// Do "apt autoclean" every n-days (0=disable)
APT::Periodic::AutocleanInterval "21";

// Send report mail to root
//     0:  no report             (or null string)
//     1:  progress report       (actually any string)
//     2:  + command outputs     (remove -qq, remove 2>/dev/null, add -d)
//     3:  + trace on
APT::Periodic::Verbose "2";

EOF

$ sudo systemctl restart unattended-upgrades
```

## DNF
https://ex1.m-yabe.com/archives/6276 参考
```
$ sudo dnf install dnf-automatic

sudo tee /etc/dnf/automatic.conf <<EOF >/dev/null
[commands]
upgrade_type = default
random_sleep = 0
network_online_timeout = 60
download_updates = yes
# 「no」から「yes」に変更
apply_updates = yes
[emitters]
# 「stdio」から「command_email」に変更します
emit_via = command_email 
[command_email] # dnf-automatic の結果をメール通知します設定
# コメントアウトを外す
command_format = "mail -Ssendwait -s {subject} -r {email_from} {email_to}"
# コメントアウトを外す
stdin_format = "{body}"
# 送信元のメールアドレスを設定
email_from = info@example.com
# 送信先のメールアドレスを設定
email_to = admin@example.jp
[base]
debuglevel = 1

EOF

$ sudo systemctl enable --now dnf-automatic.timer
```
フラッシュメモリの本物/偽物判定をmacOSでおこなう

# 概要
s3write/s3readを使ったフラッシュメモリ等ストレージデバイスのパチモノ判定

参考: https://blog.katsubemakito.net/macos/check-microsd

# インストール方法

Mac:

`$ brew install f3`

```
$ f3write --version
F3 Write 7.1

$ f3read --version
F3 Read 7.1
```

# 使い方

書き込みと読み込みをテストし、偽物なら途中でエラーが出るはずなので、テストする。

## 書き込みテスト

例えば、`/path/to/mountdir`にマウントされたストレージがある場合、
```
$ f3write /Volumes/＜mountDir＞
```
で、大量のファイルを作成し、書き込みができるかを確認する。

## 読み込みテスト

例えば、`/path/to/mountdir`にマウントされたストレージがある場合、
```
$ f3read /Volumes/＜mounntDir＞
```
で、読み込みができるかを確認する。
ラズパイで仮想化基盤をつくってみた。

# Proxmox on Raspberry Pi

ラズパイを使って仮想化基盤OSSのProxmox VEを用い、省電力な仮想化基盤を構築する。

## 実行環境

- Raspberry Pi4 B+ (4GB)
- Raspberry Pi OS 64bit ver (Bookworm)

## 構築方法

### (前提)
Raspberry Pi imagerを利用して、ユーザ作成等が済んでいる前提。
### いつもの
```
$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt autoremove -y
$ sudo apt install curl wget vim -y
```
### ラズパイの設定(あれば)
`$ sudo raspi-config`

### Proxmox VE化
https://github.com/pimox/pimox7 を利用する。
```
$ sudo -s
# curl https://raw.githubusercontent.com/pimox/pimox7/master/RPiOS64-IA-Install.sh > RPiOS64-IA-Install.sh
# chmod +x RPiOS64-IA-Install.sh
# ./RPiOS64-IA-Install.sh
```
終わったら案内に従い再起動する。
`$ sudo reboot`
ラッパークラスJava.lang.IntegerをArrayListに格納して出力してみた

コレクションのArrayListの練習をしてみた。

今回はラッパークラスJava.lang.IntegerをArrayListに格納して出力してみる。


```javascript:HerroRamen.js
import java.util.ArrayList;

public class HelloRamen {
	public static void main(String[] args) {
		ArrayList<Integer> numbers = new ArrayList<Integer>();
		
		
		numbers.add(17);
		numbers.add(43);
		numbers.add(65);
		
		
		for (int number : numbers) {
			System.out.println(number);
		}
 		
	}
}

```


ArrayListはjava.utilパッケージに属し、コレクションフレームワークである。
ジェネリクスと呼ばれる「<>」記号を使った表現が特徴だ。
配列とは違い、データを追加する際に入れ物が不足して入れば、自動的に追加されるため「addメソッド」で要素の追加が可能だ。
インスタンスでないものを格納できないため基本データ型をラッパークラス型にしなければいけない。
Javaには、オートボクシングとオートアンボクシングがあるため基本データ型とラッパークラス型を自動変換してくれる。

今回の結果は、下記のようになる。


```diff_javascript
17
43
65
```
【csh】for文の代替方法(foreach + seq)

# まえおき
cshにはforeach文はあるけど、for文がありません。
感覚的にはforeach文の方が任意の配列をクロールしたりでfor文よりややこしそうなのに・・・(素人小並感)

というわけで、当記事ではcshでスクリプトを書く際にfor文の代替となる方法をご案内します。
たぶん知ってる人はやってるだろうし、すでに記事もあると思うんだけど、見つからなかったので投稿します。

# 結論から言おうッ！
例えば、１－３１のループをしたいときは以下のように記載します。

```sh:csh.for
foreach i(`seq 1 31`)
    echo $i
end
```

# 解説
ザ・シンプルなので必要ないかもしれんけど一応説明します。

## foreach
foreachは言わずと知れたループ文の一種です。
指定した配列の要素数分だけループするので、無限ループに陥る心配が少ないこと、結果が想像しやすいので、非常に使いやすいループ文ですね。

## seq
次にseqは、連続した数字を出力するコマンドです。
ここだけ抽出します。

```sh:csh.seq
seq 1 31
```
今回の記載方法だと、第一引数が開始数、第二引数が終了数です。
ただ、開始数を省略した場合1スタートになるので
`seq 31`
でも全く問題ありません。
あくまでfor文らしく書くために開始数を記載しました。

### 普通に打ったらどうなるの
こうなります。
```sh:csh.seq
seq 31
1
2
3
..(中略)
29
30
31
```
cshは配列に代入した文字列をスペースかタブ、改行で区切る仕様となっています。
なのでseqコマンドとは非常に相性がいいです。使い勝手がほぼfor文です。

### もっとfor文らしく
seqコマンドには以下のような機能もあります。

```sh:csh.for
seq 1 2 31
1
3
5
...(以下略)

```
開始数と終了数の間に数字を入れると、ステップ数を変更できます。
いやマジfor文に必要な機能じゃないすか。
迅悠一と風刃と中村悠一くらい相性いい。

中村悠一と杉田智和ほどには相性よくない。

# オマケ
わかる人にはわかると思う用途例です。
利用してるソフトもわかるんじゃないでしょうか。

### 先月のログには、一日当たり何レコード記録されていたか、知りたい

```sh:csh
#!/bin/csh

set LogFile = `ログのフルパス`
set TargetDate = `date -d'1 month ago' + %Y/%m`
set LastDay = `date -d"$TargetDate/1 + 1 months + 1 days ago" +%d`

foreach i(`seq 1 $LastDay`)
    set SearchDay = `date -d"TargetDate/$i" "+$d $b"`
    cat $LogFile | grep "$SearchDay" | wc -l
end

```

# おわりに
いろんなサイトみたけど、たいてい「cshでfor文書きたきゃwhile使え」って説明ばっかりだったんですよ。
なんか理由あるのかもしれないけど、while文は条件式ミスると無限ループに陥るし、インクリメントを別途明記しなきゃいかんしでいいことないので、これにしました。
可読性は間違いなくこちらのほうが高いと思うので、特別な理由がなければこれを使おうと思います。
お役立ていただければ幸いです。
【Bash】シェルの終了時にコマンドを実行する方法

## 方法
次のように記述することでシェルが終了した際に設定したコマンドが実行されます。

```shell
trap 'some command' EXIT 
```

## `trap`コマンドとは

`trap`コマンドはシグナルを受け取った際の動作を設定するコマンドです。

以下のように記述します。  

```terminal
trap 'コマンド' シグナル
```

上記の「シグナル」にはシグナル名またはシグナル番号を記述します。  

## シグナル

使用できるシグナルの一覧は`trap -l`を実行することで確認できます。  

```terminal
$ trap -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
```

| シグナル名 | シグナル番号 |                        説明                        |
| :--------: | :----------: | :------------------------------------------------: |
|   SIGHUP   |      1       |     制御端末を切断するか、制御プロセスを終了     |
|   SIGINT   |      2       |  ユーザーが`Ctrl + C`（割り込みシグナル）を入力  |
|  SIGQUIT   |      3       |    ユーザーが`Ctrl + \`（終了シグナル）を入力    |
|  SIGTERM   |      15      | 終了シグナル。`kill)コマンドのデフォルトシグナル |
|    EXIT    |      0       |                  シェルの終了時                  |

## 設定されているコマンドの確認

現在設定されているコマンドを確認するには`trap -p`を実行します。  

```terminal
$ trap 'echo trap-exit' EXIT 
$ trap 'echo trap-sigint-sigquit' SIGINT 3
$ trap -p
trap -- 'echo trap-exit' EXIT
trap -- 'echo trap-sigint-sigquit' SIGINT
trap -- 'echo trap-sigint-sigquit' SIGQUIT
```

`trap -p シグナル`とすることで特定のシグナルの設定を確認できます。  

```terminal
$ trap -p EXIT
trap -- 'echo trap-exit' EXIT
```

## 設定の上書き

同じシグナルに対して複数回設定すると上書きされます。  

```terminal
$ trap 'echo trap-exit' EXIT
$ trap 'echo trap-sample' EXIT
$ trap -p EXIT
trap -- 'echo trap-sample' EXIT
```

また設定をリセットする場合にはコマンド部分を記述せずに実行します。  

```terminal
$ trap EXIT
$ trap -p EXIT
<!-- 何も出力されない -->
```
Ubuntu？Linux？そもそもなに？

## A : 両方、広義のOS（Operating System）である
OSとはソフトウェアの種類の一つで、機器の基本的な管理や制御のための機能や多くのソフトウェアが共通して利用する基本的な機能などを実装したシステム全体を管理するソフトウェア。
LinuxはUNIX系OSの一種で、プログラムが公開されており、だれでも自由に入手や使用、改変再配布ができる。

狭義のLinuxはコンピュータハードウェアの管理やプログラムの実行制御などを行う中核部分の<font color=red>**Linuxカーネル**</font>のことを指す。
カーネルだけでは利用者が操作しやすい状態にはならない。
そこで、LinuxカーネルがOSとして機能するために、必要なプログラム群をまとめたパッケージのことを<font color=red>**Linuxディストリビューション**</font>という
UbuntuはLinuxディストリビューションの一つ。

ちなみに”Ubuntu”は「他社への思いやり」などを表す単語らしい

.....<font color=pink>Ubuntu好きになっちゃいそう。
windowsのdocker上にgo言語の環境を作りたい(dockerチュートリアルまで)

# はじめに
Go言語やりたい
↓
[WSL上に環境構築はできた](https://qiita.com/KoHey94/items/5abf60e612cfb6ec263e)
↓
今時ならdockerで環境作るべきか？
↓
なんもわからんからとりあえずやろう←いまここ

~~自分用備忘録ってことにすればQiitaの肥やしを増やしてもいいと思いました~~

# 前提
Windows11です。

# Dockerって有料になったのでは？
https://www.itmedia.co.jp/news/articles/2201/31/news096.html
正確にはDocker Desktopが有料になったが、個人利用もしくはスモールビジネス（従業員数250人未満かつ年間売上高1000万ドル未満（訳注：1ドル110円換算で11億円））、教育機関、非商用のオープンソースプロジェクトでは引き続き無料で利用できるという条件がついているそうです。
今回は学習用の個人利用なので問題なさそう。

# docker hubのアカウント作成とDocker Desktopのインストール
imageのアップロード等に必要になるのでアカウントを作成する。
右上のRegisterをクリック。
![2023-02-01 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/75b681c1-18a9-be1f-4e5d-7f8b43d0e697.png)

必要事項を記入してSign upをクリック。
![2023-02-01 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/09762513-2b00-a2fc-0af1-e842f8f112d0.png)

Continue with Freeをクリック。
![2023-02-01 (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/55bc9206-b3d1-6fad-d916-96115492491d.png)

Download for Windowsをクリック。
![2023-02-01 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/35ec9f9a-b3f9-bd88-1e59-9df20e53ba84.png)

インストーラーの指示に従いインストールする。
![2023-02-01 (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/5f98b52a-6db5-bebd-9b8a-d96bd23c2bf3.png)
![2023-02-01 (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/d08b2897-7817-0f18-05aa-53719c2673e6.png)
Close and log outをクリックしてPC再起動する。
![2023-02-01 (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/b42446b7-b4d1-a47a-7b77-2ed95ebde772.png)

再起動後、Docker Desktopを起動するとDocker Subscription Service Agreementの画面が出るのでAcceptをクリック（スクショ忘れた...）。

Decker Desktopが起動した。
![2023-02-01 (8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/c6d2d9e3-323f-3a88-fb74-c516bd25bcf9.png)

# チュートリアルやる
チュートリアルやろう的な画面になるので画面の指示に従って操作をするとdockerのチュートリアルができる。
![2023-02-01 (9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/e7469056-3476-d9e5-a97d-b42a0eee7d87.png)

正直なにをやっているのか100%理解していないですが、ローカル環境で作ったdockerのimageをdocker hub上にアップロードしたっていうことまでは理解した。
チュートリアルはこれでおわり。
![2023-02-01 (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/a23515af-7783-8020-8abc-f153380f82ab.png)
![2023-02-01 (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157491/ee7fa632-cc26-8cf5-1280-acdb010fd0c2.png)

# おわりに
go言語の環境を作りたいので、次にやることはgo言語を動かすために必要な設定等を記述してdocker imageを作成する、またはすでに公開されているimageを使って自分の環境で動かす、のどちらかになると思います。
業務でなんとなく使っている現状がだいぶまずいことに気づいたので頑張ります。

# 参考(感謝します)
https://zenn.dev/aymaymaym/articles/a29fe4272e3880
【基本シリーズ】タブメニューの実装

<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="oNMQOPQ" data-user="wataruNakai" 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/wataruNakai/pen/oNMQOPQ">
  tab UI(js)</a> by wataruNakai (<a href="https://codepen.io/wataruNakai">@wataruNakai</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

jsを使って情報量が多いサイトなどによくみられる、タブメニューの実装を行います。基本動作としてはsectionにactiveクラスを付与する機能になります。

jsのコードを上から解説していきます。
まず.menu li aタグをmenuItemsに格納。
次に.contentとクラスをcontentsに格納します。

aタグをクリックした時の処理をforEach文を使って実装していきます。

a要素ですが、リンク先にページ遷移するという規定の動作があるのですが、それをキャンセルしたいので、こちらにイベントオブジェクトを渡して preventDefault()をよんであげます。

次にクリックされていない要素にはactiveクラスを外す様に、forEach文を使ってremoveメソッドを呼んできてあげます。
今回引数は、clickedItemとitem2種類あります。
それぞれ引数にわたってくる要素はクリックされたa要素(clickedItem)とクリックされていないa要素(item)です。

その下にはクリックしたらactiveクラスを付与するメソッドを記述します。

次はクリックしたメニューに応じて content のほうも変えていきます。

全てのcontentに対してactiveクラスを削除したあとにクリックしたメニュー項目に応じて、対応したcontentにだけactiveクラスを付けてあげます。

data-id というカスタムデータ属性を使って、値を紐付けてあげます。
htmlにそれぞれdata-id="about"のようにidを振ります。
そしてjsで以下のようにDOMの取得を行います。

 document.getElementById(clickedItem.dataset.id).classList.add('active')

日本語に直すとクリックされたa要素(menuItems)のデータセット属性IDとそれぞれのセクションのIDが一致するところにactiveクラスを付与するといった意味になります。

・JS
![js.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118505/1076d7f4-1d5b-b145-43db-7570cdb3e8bb.png)

・HTML
![code.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118505/fce26c8f-b14f-3564-189f-c1fc42f96e1e.png)

・CSS![css.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118505/9ab5438f-d8df-a1b8-3d5b-4685683e9481.png)
ローカルでgit pull main originをしたのにリモートのmainのような挙動をしない時の対処法

1.git statusで差分を見る
編集した覚えのない変更がたくさん入ってることがある(事前に行ったgit feachの後にmergeしていないなどが原因)

2.git checkout .

3.git pull origin main

解決！！
WSL2 でホットリロードが効かない問題の解決方法

# WSL2 でホットリロードが効かない問題の解決方法

先日から、WSL2 でホットリロードが効かない問題が発生していました。
主にフロントエンドの開発時に、結構困っていて、解決方法を探していました。
WSL2 側の google-chrome GUI を使えば、問題なくホットリロードできるのですが、Windows 側のブラウザで確認したい場合に、ホットリロードができずに困っていました。

## 問題原因

問題の原因は、WSL2 で Windows の環境変数を読みに行っていたことが問題でした。
たまたま、Flutter 関連の環境構築でエラーが出ていて、その時に、WSL2 側の環境変数を確認したところ、Windows 側の環境変数が読み込まれていました。

`flutter doctor` でエラーが出ていたので、WSL2 側の環境変数を確認してみました。

```
/usr/bin/env: ‘bash\r’: No such file or directory
```

これをみて、そんなはずないのになぁと環境変数を確認していた時に発覚しました。

## 解決方法

Windows の環境変数を読みに行かないようにすることで、解決できました。

WSL2 側の、`/etc/wsl.conf` に以下の設定を追加することで、Windows の環境変数を読みに行かないようにできます。

```
[interop]
appendWindowsPath = false
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/905557/d401132f-6060-2121-0fd3-95f555400579.png)


↑ 解決する前は、Windowsの環境変数を優先していた。
Ruby11

# 概要
対象の文字列の中に特定の値が含まれているかどうかを検知するプログラムを実装します。

# 問題
以下の要件を満たすcheck_nameメソッドを実装しましょう。

・名前を入力すると「登録が完了しました」という文字列を出力すること
・名前の中にピリオド(.)がある場合は、「 "!エラー!記号は登録できません"」という文字列を出力すること
・名前の中に空白（半角のみ）がある場合は、「 "!エラー!空白は登録できません"」という文字列を出力すること
※今回空白に関しては、半角スペースのみを考えることとします。

```Ruby:雛形
def check_name(str) 
  # 処理を記述
end

puts "登録したい名前を入力してください(例)YamadaTaro"
str = gets
check_name(str) 
```
```Ruby:ターミナル
YamadaTaro → 登録が完了しました
Yamada.Taro→!エラー!記号は登録できません
Yamada Taro → !エラー!空白は登録できません
```

### 💡ヒント💡
<b>include?メソッド</b>
include?メソッドは、指定した値が配列や文字列内に含まれているかを判定するメソッドです。指定した値が含まれている場合はtrueを、含まれていない場合はfalseを返り値として返します。

```Ruby:例
array = ["foo", "bar"]
puts array.include?("bar")
# => true
puts array.include?("hoge")
# => false
```

<br>
<br>
<br>

# 模範解答
```Ruby:模範解答
def check_name(str) 
  if str.include?(".")
    puts "!エラー!記号は登録できません"
  elsif str.include?(" ")
    puts "!エラー!空白は登録できません"
  else
    puts "登録が完了しました"
  end
end
puts "登録したい名前を入力してください(例)YamadaTaro"
str = gets
check_name(str)
```

# 【解説】
1行目から9行目
check_nameメソッドを定義しています。

1２行目
その定義したcheck_nameメソッドを呼び出しています。
この際、引数にはgetsメソッドで入力された文字列を渡しています。

2行目から8行目にわたるif文による条件分岐では、1行目の仮引数strで受け取った文字列に対してinclude?メソッドを使用し、”.”(ピリオド)と” ”(半角スペース)がないかを順に判断しています。

注意点として、if文は条件が当てはまった時点で処理が終了します。
そのため、「ピリオドや空白があるかどうか」という条件式を先に記述すること。
※if文を使用する時は処理したい順序を考えてから記述することが大切です。

出力例を参考にそれぞれの場合で出力させる値を、putsメソッドを用いて記述する。
比較的大きな穴でも修復できる inpaintingモデルRecurrent Feature Reasoning for Image Inpainting

正解→マスクした画像→推論結果
![paris.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/4d636d27-5c5a-253f-ae5c-38d1c955b0b7.jpeg)
![ca1356f1-2eb0-419d-b2b3-8027a75c0256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/0c8349d4-878d-4b65-d418-1595df148db9.png)
![97cb67cb-8870-4e36-80e2-497faf0d7002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/89cf1852-6f8e-daa2-7adf-11b69bfb9274.png)


https://github.com/jingyuanli001/RFR-Inpainting

# 使い方

インストール

```shell
git clone https://github.com/jingyuanli001/RFR-Inpainting.git
cd RFR-Inpainting
pip install --upgrade gdown 
gdown https://drive.google.com/u/0/uc?id=1jnUb-EvBw9DcwyWUQyWDdN9o42BPH7uT
```

実行

```shell
python run.py --data_root images --mask_root masks --model_path checkpoint_paris.pth --test --mask_mode 2
```

mask_mode 1　にするとランダムマスクを生成して適用してくれる。
その場合、model.pyの87行目をコメントアウトする必要がある。

```python
            # masks = torch.cat([masks]*3, dim = 1)
```

🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
rockyshikoku@gmail.com

機械学習、ARアプリ（Web/iOS）を作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)
【基本シリーズ】アコーディオンUI実装


<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="ZEjmBvm" data-user="wataruNakai" 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/wataruNakai/pen/ZEjmBvm">
  Untitled</a> by wataruNakai (<a href="https://codepen.io/wataruNakai">@wataruNakai</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>今回はjsを使って基本的なアコーディオンUIを実装してました。
jsで記述する機能としては、

・トグルメソッドでクラスのつけ外し
・dt要素は複数あるのでforEach文で繰り返し処理
・トグルでクラスを付けれるのは一つの要素のみとする

3番目に記述した中身は、クリックした要素の親要素にappearクラスを付けたあとで、
いったんすべての dt 要素を調べてあげて、クリックされた dt 要素以外のappearクラスを削除する流れになります。

js記述の内容
1行目:クエリーセレクターオールでdtの要素を全て取得。
2行目:取得したdt要素（変数dts）の繰り返し処理(forEach)
3行目:引数dtの要素がクリックされたら以下の処理をします。
4行目:引数dtの親要素(div)にtoggleメソッドでappearクラスを付け外しする。
5行目:上記で取得したdiv .appear dt要素(el)を繰り返し処理(forEach)で使います。
6行目:if文のtrueの中身は初めに取得したdt要素とクリックによってクラス付与されたdt要素を真偽値で比較します。
今回はイコールでなければ7行目を実装するといった形になります。
7行目:'div.appear dt'(el)の親要素のクラス.appearを削除する。
以上となります。
新米PMがMTGのファシリで意識したこと

# はじめに

PMになってからというもの、いろんなMTGでファシリをやることが増えました。
ファシリをやることが人生でほぼ無いに等しかったので、最初は大苦戦しましたが本を読んだり先輩から指摘を受けたりする中で、少しは慣れてきた感じがするので、学びをまとめたいと思います。

## 参考書籍

https://www.amazon.co.jp/%E8%B6%85%E3%83%95%E3%82%A1%E3%82%B7%E3%83%AA%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E5%8A%9B-%E5%B9%B3%E7%9F%B3-%E7%9B%B4%E4%B9%8B/dp/4776211734

会社の先輩に紹介していただいた書籍です。わかりやすくて、すぐに試せるテクニックも載っていたのでおすすめです。

# 明るい声で話す

経験の有無関係なしに、すぐに変えられることだと思っています。

ファシリが暗い雰囲気で話していると、MTGの雰囲気も悪くなって意見が出づらくなるということにも繋がりかねないので、とにかく明るい雰囲気にするように心がけています。

# 参加者全員を1回は打席に立たせる

ファシリをやり始めた頃は、意見を話した人以外に話を振るということが全くできていませんでした。

**他の人は議論に参加できてる？** という先輩からの指摘があり、議論の進め方を見直しました。

**参加者全員を1回は打席に立たせる**という表現が書籍の中でされており、以降のMTGでは、他の参加者にも見せ場を用意するという意識が強くなりました。

とはいえ、話の振り方はまだまだ勉強中です。。

# なるべく沈黙を作らない

参加者に話を振ったけど、すぐに回答が出ずに沈黙が生まれることがあります。沈黙が続くのは、他の参加者にとってもそうですが、話を振られた側からすると地獄の空気が流れてしまいます。

そんな時は自分の振り方が悪かったと思い、質問の仕方を変えて沈黙を埋めるようにしています。心理的安全性を高めるためにも、沈黙はなるべく作らないようにしています。

# 発言に対して感謝を伝える

意見を出しやすい環境にするには、どんな意見もまずは受け止める姿勢が必要かなと思っています。

出してくれた意見に対して、ありがとうございますと伝えるだけでも**自分はあなたの意見を受け止めました**というメッセージになるのかなと思っているので、感謝の気持ちは忘れずに進めていきたいです。

# わからないことはわからないと言う

ファシリたるもの、わからないことがあると進行に支障が出ると思っていた時がありました。
不明点を抱えたままなんとなくで進めていると、**そんなフワフワした状態で進めても良い議論ができますか？** と指摘を頂きました。

もちろん最低限の準備は必要です。ただ、完璧を目指して準備をしてもキリがないですし、何より時間が足りません。自分より知見がある方がMTGに同席していたら質問しましょう。

# まとめ

ファシリは本当に慣れが必要だなと感じました。今抱えている課題としては、話を振って意見をもらったのは良いものの、どこに着地させれば良いかを見失ってしまうことですね…。

開発のスキルとは関係ないかもしれませんが、ビジネススキルも１社会人として必要なので、これからも精進します！
【備忘録】Excelのボタンを押しても反応しないときのチェック項目

[1. 2枚以上のディスプレイ作業している時](#1-2枚以上のディスプレイ作業している時)だけでも見ていってください。
# 背景・動機
業務で使ってたExcelでマクロを実行しようとボタンを押しても何も起こらない、という時のための備忘録です。
今まで、何故か急に動かない→何もしてないのに治った、となっていてつい最近対処法が分かったので。

※Windows10、Excel2019の環境です。他の環境はわかりません（ビルド番号等は会社のPC上なので許して）。


# チェック項目
- [1. 2枚以上のディスプレイ作業している時](#1-2枚以上のディスプレイ作業している時)
- [2. windowsのアップデートの影響があるか調査する](#2-windowsのアップデートの影響があるか調査する)
- [3. キャッシュを削除してみる](#3-キャッシュを削除してみる)
- [4. Officeを修復してみる](#4-officeを修復してみる)
- [5. ここまでやって動かなければ](#5-ここまでやって動かなければ)


## 1. 2枚以上のディスプレイ作業している時
2枚以上のディスプレイを使っていませんか？（デスクトップPC+モニタ2枚 or ノートパソコン＋モニター1枚、etc...）
ボタンを押しても反応しないExcelを、メインのディスプレイに移動させて（※）もう1回ボタンを押してみてください。

……反応しました？

（※）以下のようにして、どれがメインディスプレイかを判別できます。
1. windowsのデスクトップで右クリック
1. ポップアップメニューから「ディスプレイの設定(D)」をクリック
1. 「ディスプレイの選択と整理」でどれがメインかを確認する
    -  図の右下にある「識別」をクリックして「1」が表示されたディスプレイがメイン

こうなる原因は……わかりません。何故かActive Xのボタンはメインディスプレイ以外では正常に動作しないようです。

stackoverflowにて解決方法が2019年5月に投稿されている[1.1]のを見るにこの不具合は今後も解消されないと思います。

![20230201_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2519179/db035873-9c8c-dfe6-9162-cafbcdcd151a.png)


#### 参考
- 1.1: stackoverflow: [Excel Active-X button cannot be clicked](https://stackoverflow.com/questions/56265391/excel-active-x-button-cannot-be-clicked)
- 1.2: URK実験室とフォルテ君&サイクリング: [Excel ActiveXのボタンが拡張画面で動かない](https://ameblo.jp/urklabo/entry-12498651762.html)

---

以下の内容は検索するとわりと出てくる内容なので、優先度順で書き直しておきます。


## 2. windowsのアップデートの影響があるか調査する
ググるなりtwitterで検索するなりして、windows updateの影響がないか確認してみる。

ちなみにググると出てくる2021年とか2022年とかの内容は関係ないものとして無視してよい。

特にそこらの年のMicrosoftコミュニティの投稿はまず役立たない（回答があってもそれで解決したかのレスが無くて正しい方法かもわからない……）。


## 3. キャッシュを削除してみる
1. Excelをいったん閉じる（押せないファイルだけでなく、すべてのファイルを閉じる）
1. 以下のファイルを除去する（※無いこともある）：
    - `%USERPROFILE%\AppData\Local\Temp\Excel8.0\MSForms.exd`
    - `%USERPROFILE%\AppData\Local\Temp\VBE\MSForms.exd`
1. Excelを開きなおして押せるようになるか確認する

#### 参考
- 3.1: シスデイズ技術ブログ: [Excelマクロのボタンが押せなくなった](https://www.sysdays.co.jp/blog/article/4/)


## 4. Officeを修復してみる
1. 「プログラムと機能」を開く
    - windowsキー+R > `appwiz.cpl`と入力してエンター
1. 表示されたリストから「Microsoft Office ~」を右クリック > 「変更(C)」
1. 「クイック修復」を実行して完了したら確認
1. ダメならOfficeを入れなおす（たぶんオンライン修復をするより楽）


## 5. ここまでやって動かなければ
まだ未知の不具合かもしれません。情報系の詳しい人に泣きつくか今日は諦めましょう。


# 最後に
実は1.の内容が日本語のサイトで全然出なかった（参考リンク1.2のみ？）のでこの内容だけ残したくて記事にしました。

原因がわかる方はご教示願います。
FFmpegでshowvolumeする際にグラデーションじゃなくて単色で音量を表示させたい

### 解決したいこと
以下のコマンドを実行しました。

```bash
ffmpeg -i l.ogg -shortest -filter_complex "
   [0] showvolume=ds=log
                 :t=false
                 :v=false
                 :f=0
" l.webm
```

ただし、`ds=log`で対数目盛にし、`t=false`と`v=false`でそれぞれチャンネル名と具体的な音量の値を非表示にしています。`f=0`でフェードをゼロ秒としています。

その結果以下のような映像を含む動画が得られました。

![Screenshot from 2023-02-01 22-27-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3082964/5ec5232d-d762-0a8e-7783-c416c963808c.png)

`showvolume`は恐らくデフォルトでは上記のようにグラデーションで表示されますが、これを単色のみで表示させるにはどうしたらよろしいのでしょうか。

### 試したこと
`c='Lime'`は上手くいかなかったが、`c='0x00FF00'`を追加したら何故かできた。

### FFmpegのバージョン
```
ffmpeg version n5.1.2 Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 12.2.0 (GCC)
```

### 参照したもの
- [FFmpegのフィルタのドキュメンテーションから、`showvolume`節](http://www.ffmpeg.org/ffmpeg-filters.html#showvolume)
- [FFmpegのユーティリティのドキュメンテーションから、`Color`節](https://ffmpeg.org/ffmpeg-utils.html#Color)

**元々質問予定でしたが自己解決しました**
Vue.js の要素順序について

## はじめに

`Vue.js` で多くのコンポーネントを使って実装すると各コンポーネント毎に属性の順序がバラバラになることはないでしょうか。そのため、統一感がなく読みにくいコードになってしまうことがあります。そこで、`Vue.js` の公式サイトのスタイルガイドを見ていたところ、属性順序に明記していたので紹介します。

## 対象者

- `Vue.js` のコンポーネントの属性順序について悩んでいる人

## 結論

[Vue.js のスタイルガイド](https://jp.vuejs.org/v2/style-guide/) の [要素の属性の順序](https://jp.vuejs.org/v2/style-guide/index.html#%E8%A6%81%E7%B4%A0%E3%81%AE%E5%B1%9E%E6%80%A7%E3%81%AE%E9%A0%86%E5%BA%8F-%E6%8E%A8%E5%A5%A8) に明記していました。

## VS Code について

`VS Code` には、コードを自動整形する便利な拡張機能は多くありますが、属性順序を自動で整形するモノはなかったです。

## 参考サイト
配列の操作一覧

### 配列について

初めて配列を操作するにあたり、どの様な操作が出来るか・動きをするかまとめていきます。

## 空の配列xを作成
```
x = []
=>[]
```
空の配列xを作成しました。
このxに要素(文字列や数字)を入れていきます。

## 空の配列xに0,0,1,2,2,3,4を入れる
```
x.push(0,0,1,2,2,3,4)
=>[0,0,1,2,2,3,4]
```

これで配列に要素を入れることが出来ました。
入れたばかりではありますが、さっそく削除していきます。


## 要素の削除

```
x.delete(0)
=>[1,2,2,3,4]
```
削除が出来ましたが、指定した"0"に該当する要素がすべて消えてしましました。


## 場所を指定して要素を削除

```
x.delete_at(3)
=>[1,2,3,4]
```
delete_at()で指定した、前から数えた数字の要素が削除されます。
ですので、今回は(3)を指定した為、前から3番目の"2"が削除されました。


## 指定範囲の要素を削除する

```
x.slice!(1,3)
=>[1]
```
sliceでは(削除開始位置 , 削除する長さ)を指定します。
要素を数えるのは左から0番目である事を注意してください。
<br>
```
x.slice!(1..3)
=>[1]
```
引数に範囲を指定すると、その範囲分の要素を削除します。

ちなみに、slice! ではなく slice にすると、削除された要素が戻り値として出力されます。
Ruby10

# 概要
任意の数字が配列の中の何番目に格納されているかを確認できるプログラムを実装します。

# 問題
以下の配列から任意の数字を探して何番目に含まれているかという結果を返すsearchメソッドを、each_with_indexを用いて作成しましょう。

```Ruby
input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
```

以下の雛形のコードを参考に解答しましょう。

```Ruby:雛形
def search(target_num, input)
  # 処理を記述
end

input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
# 呼び出し例
search(11, input)
```

### 出力例
search(5, input) → 2番目にあります
search(12, input) → 4番目にあります
search(7, input) → その数は含まれていません

### 💡ヒント💡
<b>each_with_index</b>
each_with_indexは、Rubyに標準で組み込まれているメソッドの1つです。要素の繰り返し処理と同時に、その要素が何番目に処理されたのかも表すことができます。

```Ruby:記述例
配列名.each_with_index  do |item, i|

end
```
```Ruby:使用例
fruits = ["メロン", "バナナ", "アップル"]

fruits.each_with_index do |item, i|
 puts "#{i}番目のフルーツは、#{item}です。"
end
```
```Ruby:ターミナル
0番目のフルーツは、メロンです。
1番目のフルーツは、バナナです。
2番目のフルーツは、アップルです。
```

<br>
<br>
<br>

# 模範解答
```Ruby:模範解答
def search(target_num, input)

  input.each_with_index do |num, index|
    if num == target_num
      puts "#{index + 1}番目にあります"
      return
    end
  end
  puts "その数は含まれていません"
end

input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
search(11, input)
```

# 【解説】
searchメソッドを呼び出す際の処理とsearchメソッド内の処理、それぞれを分けて解説していきます。

### searchメソッドを呼び出す際の処理

配列inputを定義します。

次に、searchメソッドを呼び出す際に、11とinputという変数を実引数としてセットします。
そして、呼び出されたsearchメソッドでは、実引数でセットした値を仮引数target_numとinputとして受け取ります。

### searchメソッド内の処理
まず、input.each_with_indexでは、inputに格納されている要素を1つひとつnumとして取り出すと同時に、要素毎に割り当てられている添字をindexとして取得します。
※わかりやすい変数名であればindexじゃなくても大丈夫です。

次に、if文でnum == target_numという条件式を設定します。
ここでは、inputから取り出された要素numと、target_numが等しいかを判別しています。

そして、numとtarget_numが等しければ、numがinputの中の何番目に含まれているかが出力されます。
#{index + 1}としているのは、配列が0番目から始まることを考慮するためです。

反対に、numとtarget_numが等くなければ、「その数は含まれていません」と出力されます。

今回は、引数で渡した「11」は配列inputには含まれていないので、条件には当てはまりません。
よって、「その数は含まれていません」と出力されます。
perplexity.ai を検索エンジンとして日本語でも回答を得られるように設定して ChatGpt と使い分け

# 背景
ChatGPT と違って、

https://www.perplexity.ai

は出展がきちんと出てくるので正確な調査がしたい場合には便利です。

でもって日本人なら、日本語で回答欲しかったりしますよね。
たとえ英語で質問したとしても。

そんな時用の、検索エンジン設定です。

## 本人談
> Perplexity.aiは、ウェブクローリングした情報を要約する生成系AIで、出典ソースを明記するとともに、時事性のある質問にも正しく回答してくれます。Perplexity Askは日本語の質問にも対応していますが、回答が英語になることがあるので、その場合は、ブラウザの自動翻訳機能などを利用してください。
![本人談.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645569/97f4304a-9d39-8528-4ce8-155cba6c10fb.png)

# 設定内容

検索エンジン、ショートカットはお好みで。
クエリの代わりに～ってところを、以下のように設定

```text: クエリの代わりに %s を使用した URL
https://www.perplexity.ai/?s=o&q=%s 日本語で回答して
```
## 日本語で回答貰う用の設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/af48d10f-535c-d157-2c8d-df49bf7fdf07.png)

## 英語検索用の設定も
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/e1081fb1-7d90-ae26-8a3c-f693c98d6f13.png)


# 利用例
- 日本語で探したい時は、"per" + Tab で、質問を
- 英語で制度重視の際は、"pere" + Tab で、質問を
![Perplexity.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/9321cc1c-e158-3bb0-2a26-612759454407.gif)

# あとがき
今後は色んな AI サービスを用途に応じて切り替えて使えるようになっていく必要がありそうですね。

なんにせよ、新しいものへの挑戦意欲は必須ですね。
ファイル名一括変更


例
xxx_320kbps.mp3から 「_320kbps」トル
```
rename 's/_320kbps//' *.mp3
```

ファイル名先頭3文字トル
```
for f in *; do mv "$f" "${f:3}"; done
```

参考
https://qiita.com/shuhei/items/cf1ddf373d1f83d5d667
https://ja.stackoverflow.com/questions/14569/%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%A7%E5%90%84%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E5%90%8D%E3%81%AE%E9%A0%AD%E6%96%87%E5%AD%97%E3%82%92%E4%B8%80%E6%96%87%E5%AD%97%E6%B6%88%E3%81%99%E3%81%AB%E3%81%AF
No.3（ちょっと一息）作成したビジュアルを組み合わせてみる

# はじめに
ここまでのセッションで何種類かのビジュアルを追加する方法を紹介しましたが、いざそれを一度に追加するとなると、どのようにまとめる事ができるのでしょうか？

## レポートのたたき台
幾つか1ページ以内にビジュアルをまとめてみました。
ザ・並べてみただけですが、これだとちょっと見辛いと思います。
![スクリーンショット 2023-02-01 21.49.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/e839713f-573f-d90c-5d6c-0ec3a3ca8f56.png)
こちらを少し、手直ししてみたいと思います。

## レポートの改善例
こちらが改善してみた結果です。先程のレポートよりそれっぽくなっていると思います。
大きく2つ、変更を加えたのでこれから説明します。
![スクリーンショット 2023-02-01 21.50.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/1d818bb1-4747-7edc-46c4-7297b49dda22.png)


## 変更点①：効果（境界線）を使う
**1．ビジュアルの書式設定を選択**
**2．全般から効果を選択**
**3．視覚的な境界のトグルをONにする**
![作成1ezgif-1-da56ccca1a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/cc061bdd-a4a5-f025-50e0-6c338e1bab6a.gif)

こうする事で、ビジュアルと別のビジュアルとの境界線がわかりやすくなり、それぞれ区別がつきやすくなるかと思います。
![スクリーンショット 2023-02-01 21.57.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/6490b7a3-fd03-a39e-a595-72ed200d792f.png)

## 変更点②：タイトルを使う
続いてビジュアルのタイトルの話です。タイトルは自動的に作ってくれるので便利ではあるのですが、初見の人にはわからないタイトルになっている事がたまにあります。
**作成した本人はどのデータを使っているのかわかっているのですが、本人以外は伝わらないのが落とし穴です。**
これ↓とか全然わからないですよね。。なんとなく推移を示しているのはわかるのですが。
![スクリーンショット 2023-02-01 22.00.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/901c29ae-11d0-d8a8-ccbf-b7314e35fe48.png)
という事で誰が見てもわかるようなタイトルに変更しましょう。

**1．ビジュアルの書式設定を選択**
**2．全般からタイトルを選択**
**3．テキスト欄に「わかりやすいタイトル」を記入する**
**4．フォントサイズや太さ、配置を適宜変更**
![作成2ezgif-1-635301af1f.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/c0084f1c-56cd-d984-d470-2127b9e50200.gif)

このような感じでひと目で理解できるような言葉になりました。
![スクリーンショット 2023-02-01 22.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/38b03159-ee6a-0973-9c8e-667711de202b.png)


## 【参考】ページを追加する
無理に一枚にまとめようとするとビジュアルのサイズが小さくなってしまうので、その場合は下の「＋」ボタンを押して新たにページを追加しましょう（Excelのシートのイメージです）
![ezgif-1-304dafbc50.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/2c389f08-990c-c1e0-d1f6-e5eb700d5b7c.gif)


## 【参考】ダッシュボードにまとめる
デザイン的にはダッシュボードにまとめて見やすくする事もできますが、こちらはダッシュボードのそもそもの説明も必要となってくるので、別の記事でまとめたいと思います。

**・ダッシュボードの画面**
![スクリーンショット 2023-02-01 21.46.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2943951/5a8f26c2-05a7-9ab4-a0b1-f388983580fe.png)


こちらのセッションは以上です。
[→ Power BI サービス練習帳に戻る](https://qiita.com/shinyasasaki/items/391d50c2508794e8fcfd)
【Laravel】SQLSTATE[HY000]: 1005 エラーの解消

## エラー内容
### マイグレーションファイルを用意
* 2023_02_01_153621_create_items_table.php
* 2023_02_01_153622_create_categories_table.php
![マイグレーションファイル.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483743/2e54687e-b3e3-4723-dc3b-ac4d22873e88.png)

### マイグレーションファイルを編集
:::note warn
ポイント
「items」の「category_id」を「categories」の「id」に対して外部キーの設定をしている
:::

```php
Schema::create('items', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('user_id');
            $table->string('name', 255);
            $table->string('description', 1000);
            $table->unsignedBigInteger('category_id');
            $table->integer('price');
            $table->string('image', 100);
            $table->timestamps();
            
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            // ↓　外部キー設定
            $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
        });
```

### マイグレーション実行
```
php artisan migrate
```

### エラー出力
>SQLSTATE[HY000]: General error: 1005 Can't create table プロジェクト名.items(errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter table items add constraint items_category_id_foreign foreign key (category_id) references categories (id) on delete cascade)

翻訳すると
>SQLSTATE[HY000]: 一般エラー: 1005 テーブル プロジェクト名.items を作成できません (errno: 150 "外部キー制約の形式が正しくありません") (SQL: テーブル items を変更すると、制約 items_category_id_foreign 外部キーが追加されます ( category_id) はカスケード削除で categories (id) を参照します)

とのこと。

## 原因
### 前提
```
php artisan migrate
```
マイグレーションは上から実行される。

### 現象

マイグレーションファイルを確認すると、
* 2023_02_01_153621_create_items_table.php
* 2023_02_01_153622_create_categories_table.php
![マイグレーションファイル.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483743/2e54687e-b3e3-4723-dc3b-ac4d22873e88.png)

「items_table」が上
「categories_table」が下になっている。

先に「items_table」を生成しようとすると、
参照先のテーブル「categories_table」はないですよ。
というエラー。

## 解決方法
マイグレーションファイルの日付を変更（153621→153623）し
参照先のテーブル「categories_table」を先に生成させる

* 2023_02_01_153622_create_categories_table.php
* 2023_02_01_1536**23**_create_items_table.php

![マイグレーションファイル.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483743/a86e326b-b547-aab3-928d-70db3eb7810a.png)

マイグレーション実行
```
php artisan migrate
```
![マイグレーションファイル.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1483743/4dd132a6-780a-3b4b-0bb1-8b04c10ba892.png)

成功。

## まとめ
マイグレーションを実行すると上のファイルから実行されていく。
変更するには日付を変更し、順番を変える。

## その他

1005 エラーの原因は他にもあるみたい。

https://qiita.com/kidach1/items/1060e094a0b0f9b9eaaa
【Xcode】シュミレーターの位置情報を変更する

# はじめに
シュミレーターの位置情報をいじれるらしいのでやってみた。

位置情報を表示するまではここをコピーします。

https://qiita.com/chi_soft_dev/items/045ec9d91917dc3a7226

# やりかた
① 「Features」を選択します
② 「Location」を選択します
③ 「Custom Location...」を選択します

![スクリーンショット 2023-02-01 21.58.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1fd6c9b5-0af4-7f47-a7bf-a2f5a5a77a57.png)

④ 座標を入力します
⑤ 「OK」を選択します
![スクリーンショット 2023-02-01 21.55.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1bbf81f6-9749-6a4b-126d-a507a1dc61f3.png)

# おわり
こんなに簡単に変えられるとは！！！
AWS Amplifyホスティングのセキュリティに関するissueを確認したら残念だった

前回の投稿では、Amplifyホスティングのセキュリティに関して評価しました。
その結果わかった課題は以下の通りです。
セキュリティヘッダについては、Amplifyホスティングの機能でも実装できるため、
それ以外について、GitHubのissueを確認してみました。

- セキュリティヘッダが不十分
- [DV証明書のみであり、OV/EV証明書の導入ができない](#dv証明書のみでありovev証明書の導入ができない)
- [暗号強度が低い](#暗号強度が低い)
- [IPアドレス制限ができない](#ipアドレス制限ができない)
- [WAFの設定ができない](#wafの設定ができない)

https://qiita.com/dorcus-rectus/items/617839d8fe65f6db215b

# DV証明書のみであり、OV/EV証明書の導入ができない

こちらのissueは以下の内容となります。
以前から要望が上がっているようですが、現在もopenのステータスになっています。
内容はかなりネガティブな印象です。2023年も厳しそうなコメントです。

https://github.com/aws-amplify/amplify-hosting/issues/56

話はそれますが、issueを読んでいて、Amazon CodeCatalystというものがあることを知りました。
まだ、プレビュー版ですが、今後ウォッチしてみようと思います。

https://aws.amazon.com/jp/codecatalyst/

# 暗号強度が低い

以下のissueは、前回の診断で検知した以下の暗号化方式に関するものです。
ステータスはclosedになっていますが、直っていないように見えます。

- ECDHE-ECDSA-AES256-SHA384
- ECDHE-RSA-AES256-SHA384

https://github.com/aws-amplify/amplify-hosting/issues/2007

Amplifyホスティングは、内部的にCloudFrontが使用されているようですが、最新の「TLSv1.2_2021」ではなく、「TLSv1.2_2019」が利用されているように見えます。

https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html

# IPアドレス制限ができない

以下のissueにありますが、対応はまだのようです。
CloudFront + S3を使って回避している人が目立ちます。

https://github.com/aws-amplify/amplify-hosting/issues/12

# WAFの設定ができない

こちらも要望があるようですが、なかなか実装されないように見えます。
CloudFrontを使って回避することを試みるもうまくいかないようです。

https://github.com/aws-amplify/amplify-hosting/issues/36

# 感想

Amplifyホスティングはすごく便利そうですが、プロジェクトがうまくいってなさそうな感じがしました。
issueにもあった、Amazon CodeCatalystに今後はシフトしていくのでしょうか。

CloudFormationやSAMを使った昔ながらのやり方をした方が無難なような気がしてきました。
[IDMC]Google Big Queryへデータを投入する

## はじめに
Informatica Intelligent Data Management Cloud(IDMC/旧称IICS)でのちょっとしたTipsを纏めていきます。日々の活動の中で検証した結果記録であり、忘れやすい自分のためのメモですが、少しでも皆様のお役に立てればと思い公開していきます。記述方法など試行錯誤しており随時更新するかもしれません。

## この記事のゴール：IDMC データ統合における Google Big Query への接続と連携が作成出来るようになる
この記事ではGoogle Big Queryへの接続設定とマッピング作成時の設定において、マニュアルだけでは判りづらい所をメモしています。

- Google Big Query への接続の設定
- マッピング作成時のターゲット設定

尚この記事の内容は、R41 で検証しています。

### 参照情報
マニュアル：
Data Integreation Connectors:[Google BigQuery Connectors](https://docs.informatica.com/integration-cloud/data-integration-connectors/current-version/google-bigquery-connectors/preface.html)


### Google Big Query 接続の設定
:::note info
Googleアカウントが有り、Google側にプロジェクトが作成されており、且つ、Google Cloud Storage 及び Google Big Queryが利用できるようになっている前提とさせて頂いています。
:::
コネクタは ”Google Big Query V2”タイプを選択します。

基本的にマニュアルの記載の通り設定することで接続は作成出来ます。が、接続が作成出来ても実行時にエラーが起こる場合があるのがやっかいなところですね。ということで設定を公開します。今回は以下の部分を埋めたことでマッピングが正常に実行できました。最低限以下の所を設定すればOKかとおもいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/4700471c-686e-72ed-dae0-5a35f8047fd1.png)

何処の情報を使えば良いのか判りづらい為、画面ショットを元に説明します。
- Storage Path:  これは "Google Cloud Storage"のbucket名(＋フォルダ名)を記述します。記述フォーマットはマニュアルにある通り、
```
gs://<bucket name>
gs://<bucket name>/<folder_name>
```
とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/4434a493-ba39-4738-6812-d851207ef588.png)


- Dataset Name for Custom Query:  これは "Google Big Query"のData Set名を記述します。
- Region Id: 自分が最後まで填まってしまったのがココ。BigQueryのデータセットのロケーションを入力しますが、例えばus-east1等のこまかいRegion名では実行時にエラーとなってしまいます。ここは下記のとおり「データのロケーション」の文字 ここでは US と入力するのが正解です。要注意ポイント。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/3c5064c9-31af-5ac9-5108-cda44114925e.png)

## マッピング作成：ターゲット設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/17db5755-6380-3a6b-ea9e-da232210a083.png)

CSVファイルをソースとして、Google Big Queryにデータを投入する簡単なマッピングです。ターゲットとしてBigQueryを指定し、データ投入時にテーブルを新規作成しています。

ターゲット プロパティの設定画面です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/4daa24c5-5902-9128-6e4f-c400289e6e51.png)
ここでオブジェクトの設定は以下の通り。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2985453/e6ce2e44-ab79-b539-592b-06fed49dd999.png)

- オブジェクト名 : 必須項目。任意の文字列を入力すればOKで、この名称でGBQにテーブルが作成されデータ投入されます。
- パス : 冒頭にスラッシュ(/)を記述し、続けてデータセット名を入力します。

これで実行可能となりました。

以上、自分が填まったところを記述してみました。何かのお役に立てば幸いです。
【Solidity】abi.encodePacked()の働きを見てみよう。

### 前書き

Solidityについて勉強しているうちに気になることが出てきました。それは「よくわかんないで使っていたabi.encodePacked()って実際なんなん？」ということでした。私は初心者プログラマーで、abi.encodePacked()をググって、ヒットしたものを読んでみてもちんぷんかんぷんだったので、実際に自分でコードを書いて（簡単にですが）検証してみました。
* * *

### 検証
```solidity:TestAbiEncodePacked.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract TestAbiEncodePacked {
    //試しに一回
    function testAbiEncodePacked1() public pure returns (bytes memory) {
        return abi.encodePacked("AAA", "BBB", "CCC");
        // -> bytes: 0x414141424242434343
    }

    //違う文字列たちでもう一回
    function testAbiEncodePacked2() public pure returns(bytes memory) {
        return abi.encodePacked("DDD", "EEE", "FFF");
        // -> bytes: 0x444444454545464646
    }

    //引数の個数を変えてもう一回
    function testAbiEncodePacked3() public pure returns(bytes memory) {
        return abi.encodePacked("DDD", "EEE");
        // -> bytes: 0x444444454545
    }

    //引数の個数をもう一度変えてみる
    function testAbiEncodePacked4() public pure returns(bytes memory) {
        return abi.encodePacked("DDD");
        // -> bytes: 0x444444
    }

    //何となく
    function testAbiEncodePacked5() public pure returns(bytes memory) {
        return abi.encodePacked("DDDEEE");
        // -> bytes: 0x444444454545
    }

    //string型にキャスト
    function testAbiEncodePackedWithStringCasting() public pure returns (string memory) {
        return string(abi.encodePacked("AAA", "BBB", "CCC"));
        // -> string: AAABBBCCC
    }

    //あらかじめ結合した文字列をBytesにしてみる。
    function testStringToBytes() public pure returns (bytes memory) {
        return bytes("AAABBBCCC");
        // -> bytes: 0x414141424242434343
    }

    //こっちでも代用可能
    function stringLine() public pure returns (string memory) {
        return "AAA" "BBB" "CCC";
    }

    // 文字列→Bytes, Bytes→文字列は当然内容の変化はない。

}
```
#### わかったこと１
abi.encodePacked()の戻り値はbytes型
testAbiEncodePacked1/2関数を定義するときreturnsの型を設定しますが、bytesでコンパイルが通り、実行できました。
* * *
#### わかったこと2
引数の文字列を結合したものをBytes型に変換する。
結合した文字列の長さによりBytesの長さが変わる。（当たり前）
* * *
#### わかったこと３
戻り値をstring型にキャストすると、引数の文字列を結合しただけの文字列が返ってくる。
* * *
### わかったこと４
わかったこと３の機能は下のようにして代用可能。それぞれの文字列が結合される。
```
return "AAA" "BBB" "CCC";
```

### まとめ
abi.encodePacked()はstring型にキャストすることで引数の文字列を結合する働きを持っているようです。意外と単純な機能でした。