OmniAICreator/Qiita-1.07M huggingface dataset:
pandas.json_normalize の逆

ネストされた dict の list をいい感じにフラットにしてくれる `pandas.json_normalize` っていうのがあるんだけど、
https://pandas.pydata.org/pandas-docs/version/1.2.0/reference/api/pandas.json_normalize.html

元に戻す方法がないので書いた。

ちなみに数値はだいたい float64 になっちゃうので基本元の型には戻せないです。

```py
import functools
import pandas as pd

def denormalize_json(df, sep="."):
    def _denormalize_series(sr):
        result = dict()

        def _default_dict(acc, x):
            if x not in acc:
                acc[x] = dict()
            return acc[x]

        for k, v in sr.items():
            p = k.split(sep)
            d = functools.reduce(_default_dict, p[:-1], result)
            
            if not pd.isna(v):
                d[p[-1]] = v

        return result
    
    return [ _denormalize_series(sr) for _, sr in df.iterrows() ]
```

```python
In [2]: l_nested = [{'name': 'Alice', 'age': 25, 'id': {'x': 2, 'y': 8}},
   ...:             {'name': 'Bob', 'id': {'x': 10, 'y': 4}}]
   ...: l_nested
Out[2]:
[{'name': 'Alice', 'age': 25, 'id': {'x': 2, 'y': 8}},
 {'name': 'Bob', 'id': {'x': 10, 'y': 4}}]

In [3]: pd.json_normalize(l_nested)
Out[3]:
    name   age  id.x  id.y
0  Alice  25.0     2     8
1    Bob   NaN    10     4

In [4]: denormalize_json(pd.json_normalize(l_nested))
Out[4]:
[{'name': 'Alice', 'age': 25.0, 'id': {'x': 2, 'y': 8}},
 {'name': 'Bob', 'id': {'x': 10, 'y': 4}}]
```
Bitfield を使った json.Marshal/Unmarshal の例

[2021年Goアドベントカレンダー](https://qiita.com/advent-calendar/2021/go) 4日目の記事です。


`encoding/json` パッケージには Marshaler/Unmarshaler インターフェイスがあります。
インターフェイスの実装を満たす構造体であれば、jsonをGoのデータへマッピングすることや、jsonデータをシリアライズして出力することが出来ます。

```go
type Unmarshaler interface {
	UnmarshalJSON([]byte) error
}
```

```go
type Marshaler interface {
	MarshalJSON() ([]byte, error)
}
```

https://pkg.go.dev/encoding/json

`UnmarshalJSON` は、インプットの json データをハンドルして Go の型へ変換したい時、</br>
`MarshalJSON` は、Goの構造体などを json データへシリアライズして出力する際などに利用できます。

## MarshalJSON / UnmarshalJSON の実装例

下記のような型を定義して、実装例を示してみたいと思います。

```go
type Bitfield uint8

const (
	x uint8 = 1 << iota
	w
	r
)
```

`Bitfield` に以下のようなメソッドを実装すれば、json配列として表現することが出来ます。

- `UnmarshalJSON` では、論理和を行いインプットを処理する
- `MarshalJSON` では、論理積により判定を行う

```go
func (b *Bitfield) UnmarshalJSON(byt []byte) error {
	var items []string
	if err := json.Unmarshal(byt, &items); err != nil {
		return err
	}
	for _, s := range items {
		switch strings.ToLower(s) {
		case "x":
			*b |= Bitfield(x)
		case "w":
			*b |= Bitfield(w)
		case "r":
			*b |= Bitfield(r)
		default:
		}
	}
	return nil
}

func (b Bitfield) MarshalJSON() ([]byte, error) {
	arr := []string{}
	if uint8(b)&x != 0 {
		arr = append(arr, "x")
	}
	if uint8(b)&w != 0 {
		arr = append(arr, "w")
	}
	if uint8(b)&r != 0 {
		arr = append(arr, "r")
	}
	return json.Marshal(arr)
}
```

出力例
https://go.dev/play/p/w-dIYugBrO9

```go
func main() {
	blobs := []string{`["x", "w","r"]`, `["x","r"]`, `["r"]`, `[]`}
	for _, blob := range blobs {
		var b Bitfield
		if err := json.Unmarshal([]byte(blob), &b); err != nil {
			log.Fatal(err)
		}
		byte, err := json.Marshal(b)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%d: %s\n", b, byte)
	}
}
```

```shell
7: ["x","x", "w","r"]
5: ["x","r"]
4: ["r"]
0: []
```
proxy環境下でのdocker build

## TL; DR

dockerfileに書いてしまうと、そのレイヤが保持されてコンテナが作られる。
すると何が起きるかというと、containerをbuildした後にunsetできなくなる。
その回避策。

## 問題の詳細

以下が、実際に問題となってしまうdockerfileの例です。

```dockerfile
# FROM OSの名前:バージョン
FROM centos:7

####### 問題となる部分:ここから
ENV HTTP_PROXY http://user:pass@host:port
ENV HTTPS_PROXY http://user:pass@host:port
ENV FTP_PROXY http://user:pass@host:port
####### 問題となる部分:ここまで

RUN echo "now building..."
RUN yum update -y && yum upgrade && yum -y install httpd
RUN sed -i '/#ServerName/a ServerName www.example.com:80' /etc/httpd/conf/httpd.conf

ADD ./index.html /var/www/html/

EXPOSE 80
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
```

こういうdockerfileを書いてしまうと、環境変数HTTP_PROXYに、http://user:pass@host:port がセットされます。
そして、ご存知のようにbuildの過程で1つのレイヤとしてfixしてしまいます。
つまり、環境変数HTTP_PROXYは、あとから***変更不可となります*** 。

例えば、社内でContainerをbuildしてそれを配布したい場合、自分の**proxyの認証情報を埋め込んだまま配布**してしまいます。
これは問題ですよね。。。。。


## 回避策
buildする際に、build-arg引数として、proxyの情報を与えてあげましょう。

```bash
docker-compose build ^
  --build-arg HTTP_PROXY=http://%LDAP%:%PASS%@host:port ^
  --build-arg HTTPS_PROXY=http://%LDAP%:%PASS%@host:port ^
  --build-arg http_proxy=http://%LDAP%:%PASS%@host:port ^
  --build-arg https_proxy=http://%LDAP%:%PASS%@host:port ^
  service名
```

もちろん、この時のdockerfileには、上記のダメサンプルの「問題となる部分」は記載はしません。
【Rails】ルーティングまとめ

### 背景
学び始めでのルーティングをする際、getを使わなきゃだとか、resource、ヘルパーメソッドって何だったか…？となり毎回検索しては忘れてしまうのでここにまとめを。

### ルーティングのやり方
**◆個別設定**
1行ずつ設定する方法。１行１行手入力しないといけないので少し面倒。
一括設定する方法もある。

```
get 'URLに追加', to: 'コントローラのアクション'

例：　get 'index', to: 'posts#index'
これをURLにすると→ http://localhost:3000/index
```

**◆一括設定**
resourcesを使う。
これらのメソッドは、railsで定義されている7つのアクションを自動で生成してれる。
　▼７つのアクションとは

| アクション名 | 役割 |
|:-:|:-:|
|  index |   リソースの一覧を表示させる|
|   show|   リソースの詳細を表示させる|
|   new|   投稿フォームを表示させる|
|   create|   リソースを追加させる|
|   edit|   更新フォームを表示させる|
|   update|   リソースを更新させる|
|   destroy|   リソースを削除する|

```
resources :コントローラー名,:コントローラー名...

コンソールにてrails routesコマンドで、ルーティングを確認できる。
また、アクションを指定したいときには下記のように記述。

resources :コントローラー名,only:[:index, :new]

```

**resouce(最後に"s"が無い)メソッドでも出来るが、コントローラの７つのアクションに対して、indexとid付きのパスが生成され無いため、show, editアクションの実行に、idが必要ない場合に有効。**

### HTTPメソッドについて
**◆HTTPメソッドとは**
HTTPメソッドとは、「クライアントがサーバーにしてほしいことを依頼するための手段。
　▼比較的多く使われるメソッド

| メソッド| 役割 |
|:-:|:-:|
|  get |  データの取得 |
|   post|   データの送信(主に新規作成)|
|   put|   データの送信(主に既存データの更新)|
|   delete|   データの削除|

### getとpostの違い
##### get
主にサーバーからブラウザに情報を返す時に使われる。単にウェブページを参照する際にはこのメソッドが利用される。

##### post
ブラウザからサーバーに情報を送信するときに使うメソッドで、入力フォームのデータをブラウザからサーバーに送信するときなどに使われている。
getメソッドとは異なり、リクエスト内容をHTTP通信のbody部に含めることで、**URLにその内容が表れない通信方式**。
代わりに、リクエストボディ内に内容が含まれているため、URLを直接入力するだけでは同じ通信を再現することはできない。

### _pathと_urlの違い
#### _path
・相対パス
・redirect_to以外で使用

#### _url
・絶対パス
・redirect_toの時にセットで使用する。(HTTPの仕様上、リダイレクトのときに完全なURLが求められるため

#### 相対パスと絶対パスの違い
**相対パス**
URLでページを指定して、目的地（情報）がどこにあるのかを確実に伝える。
たとえば実際に道案内をするときに、目的地の住所（URL）を教えるのが絶対パスの伝え方。

**絶対パス**
今いる場所（階層）を基準にして、目的地（情報）がどこにあるのかを伝える。
ある地点から道を曲がって道路沿いのつきあたりを右…というように、今いる場所から目的地までの経路を案内するのが相対パスの伝え方。



### 参考記事
[【Rails入門】ルーティング （config/routes.rb）の書き方を説明！](https://www.sejuku.net/blog/13078)
[【Rails】 resourcesメソッドを使ってルーティングを定義しよう！](https://pikawaka.com/rails/resources)
[resourcesとresourceの違いについて！](https://qiita.com/wacker8818/items/1ba526fcbc73e065a511)
[Web開発でよく使う4つのHTTPメソッド【REST API】](https://tsuyopon.xyz/2019/01/31/understand-4-http-methods/)
[GETメソッドとPOSTメソッドの違いとSEO面からの使い分け](https://www.sakurasaku-labo.jp/blogs/seo-get-post#POST%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%A8%E3%81%AF)
[_pathと_urlの違いについて調べてみた](https://qiita.com/bSRATulen2N90kL/items/a183c501f56c4068584c)
[これだけは覚えておきたい！絶対パスと相対パスの違いとは【初心者向け】
](https://techacademy.jp/magazine/5801)
OSSライセンスが怖かったので、GPL系のライセンスを調べてみた

# 背景
JPHACKS2021に出場した際に、最初から作業・提出リポジトリにMITライセンスなるものが設置されていた。
ライセンスよくわからないで使わされるのも怖いし、コピーレフト性のあるものは「改変の開示」が必要で怖いし、知っておかないとやばいよなーとなった。

# この記事のゴール
コピーレフト性のあるGPL系ライセンスで、どのケースでコードを開示する必要があるのか理解する。

# GPLライセンスのまとめ
## コピーレフト（Copyleft）
著作物の自由な利用・改変・再配布する権利を人々に提供し、その派生物についてもこれら行為の制限をしてはならないとする考え。
OSSライセンスが持つことのある概念。

## GPLライセンスとは
GPL(GNU General Public License)はコピーレフト性を持つライセンスとして有名。
GPLライセンスは他のライセンスよりも、制限が強く、厳格にコピーレフトの概念を具現化したライセンスと言える。

## GPL2.0ライセンスを持つソースの主な利用条件
GPLはいくつかのバージョンが存在するが、ここでは特にGPL2.0について調査を行った。

- 著作権表示とライセンス条文、無保証などをソフトウェアの重要部に記載する必要がある
  - ヘッダへの埋め込みでも良い
- **頒布時にソースコードの公開義務**
- GPLライセンス以上の条件を課すことはできない

また、商用利用も可能なようです。

## どんなときにソースコードを開示しないといけないのか？
**頒布時のソースコードの公開義務**は、一定の場合、一定の範囲で発生するようです。

「一定の場合、一定の範囲」は主にOSSを第三者に提供する場合に当てはまります。
### 「OSSを第三者に提供すること」のケース

- 機器の組み込みソフトウェアの一部に存在
- サーバからダウンロードさせて利用させる

などが該当します。

### ソースコード公開義務が通常は及ばないケース
- 社内利用に留まる
- 社外ユーザにネットワークを介してアクセス、利用に供する

などが該当します。


# 最後に
__「頒布」__というワードは「不特定多数の相手に広く配る行為」であり、多くのケースで該当するようです。
MITライセンスなど非コピーレフト性のライセンスなどは頒布時の公開の義務はありませんが、GPLのようなOSSでは、「どこでその処理が行われるのか？」という処理形態に注意が必要そうですね。。。

詳しくは参考文献をご参照ください。

# 参考文献
[1]https://yamory.io/blog/about-gpl-license/
[2]http://www.it-houmu.com/archives/1902
[3]https://blog.y-yuki.net/entry/2018/09/02/214000
Wigner 3nj記号の実装

# Wigner 3nj記号について雑な説明

Wigner 6j記号から定義できる一連の関数で、量子力学まわりでたまに出てきます。6j, 9j, 12j, ...と続きます。
まず3j記号を定義します。リンク先にあるようにClebsch–Gordan係数の対称性をちょっといい感じにした量です。
https://en.wikipedia.org/wiki/3-j_symbol
6j記号は3j記号を用いてリンク先のように定義できます。
https://en.wikipedia.org/wiki/6-j_symbol
9j記号以降は6j記号を用いて以下のように定義されます。

第一種3nj記号

```math
\begin{Bmatrix} j_1 & j_2 & \ldots & j_n \\ l_1 & l_2 & \ldots & l_n  \\ k_1 & k_2 & \ldots & k_n \end{Bmatrix} = \sum_x(-1)^{R_n + (n-1)x} \begin{Bmatrix} j_1 & k_1 & x \\ k_2 & j_2 & l_1 \end{Bmatrix} \begin{Bmatrix} j_2 & k_2 & x \\ k_3 & j_3 & l_2 \end{Bmatrix} \cdots \begin{Bmatrix} j_{n-1} & k_{n-1} & x \\ k_n & j_n & l_{n-1} \end{Bmatrix} \begin{Bmatrix} j_n & k_n & x \\ j_1 & k_1 & l_n \end{Bmatrix}
```

第二種3nj記号

```math
\begin{bmatrix} j_1 & j_2 & \ldots & j_n \\ l_1 & l_2 & \ldots & l_n  \\ k_1 & k_2 & \ldots & k_n \end{bmatrix} = \sum_x(-1)^{R_n + nx} \begin{Bmatrix} j_1 & k_1 & x \\ k_2 & j_2 & l_1 \end{Bmatrix} \begin{Bmatrix} j_2 & k_2 & x \\ k_3 & j_3 & l_2 \end{Bmatrix} \cdots \begin{Bmatrix} j_{n-1} & k_{n-1} & x \\ k_n & j_n & l_{n-1} \end{Bmatrix} \begin{Bmatrix} j_n & k_n & x \\ k_1 & j_1 & l_n \end{Bmatrix}
```

$x$ は三角不等式を満たす全ての値です。また

```math
R_n = \sum_{i=1}^n(j_i + k_i + l_i)
```

ここでは以下の文献の(17.1)および(17.2)式の定義を引用しました。どうやら文献によって定義がまちまちらしいです。
A. P. Yutsis, I. B. Levinson, and V. V. Vanagas, Mathematical Apparatus of the Theory of Angular Momentum (Israel Program for Scientific Translations, Jerusalem, 1962).

ご覧の通りどちらも6j記号をくるっと一周する形となっています。一種と二種は位相と、一周するときにひねりを入れるか（最後の6j記号のところ）の違いです。

# 実装

Rustでの実装を探してみると、すでにこの方が9j記号までは多倍長演算のライブラリを作っていました。

https://github.com/Rufflewind/wigner-symbols-rs

もともとWigner15j記号が必要だったので、このライブラリに追加するかどうか迷ったのですが、
多倍長演算でなければ一般のnに簡単に拡張できそうだったので、最初から作り直して雑に公開しました。
（READMEとかはサボって書いていない）

https://crates.io/crates/wigner-3nj-symbols

今回Rustが最初だったのもあり、とりあえず全部f64とかになっています。

# 大変だったこと

テストのために正しい値が必要だったのですが、12j記号以降はWolfram Alphaにも実装されていないようだったので、
簡単な場合に手計算などで地道に求めた値を使いました。なので一般のときには正しい値とのずれがあるかもしれません。
このあたり数値計算している人たちはどうしているのだろう。。。
Figmaのコメント一覧をさっと取得したいなあ……

## これは何

Qiitaのデザイナーをしています。綿貫といいます。
中の人としてもアドベントカレンダーを盛り上げるべくFigma Advent Calendarを作成し、3日目の記事を書きました！

https://qiita.com/advent-calendar/2021/figma

今回はFigmaのコメント機能についてとりあげます。
なお、ほぼネタみたいな記事なので実用性はそんなにありません。

## コメントがたくさんつくと確認が大変

Figmaのコメント機能はコミュニケーションをとる上で非常に便利ですが、あまりにもたくさんのコメントがつくと追うのが大変です。
特に複数のPageにまたがっているとあっちを開いてこっちを開いて……。

単にコメントを一覧したいだけなのになあってときは若干不便です。

## ターミナルで全件取得してみましょう

https://www.figma.com/developers/api#comments

Figma APIを見るとcommentsのエンドポイントがありますので、利用しましょう。

### access tokenの取得

`Settings > Account > Personal access tokens`で取得できます。
適当な名前をテキストフィールドに入れてエンターを押せば発行されるのでどこかにメモしておいてください。

### file keyの取得

コメントを取得したいFileを開いて`Share > Copy link`。
ブラウザで開くとURLの形式が`https://www.figma.com/file/:file_key/:title?node-id=XXXX`といった具合になっているので`file_key`をメモしておいてください。

### コマンドを叩く

後は簡単です

```shell:ターミナル
curl -H 'X-FIGMA-TOKEN: YOUR_TOKEN' 'https://api.figma.com/v1/files/YOUR_FILE_KEY/comments' | python3 -c 'import sys,json;print(json.dumps(json.loads(sys.stdin.read()),indent=4,ensure_ascii=False))' | grep "message"
```

結果はこんな感じで見れます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/3add5168-a7b3-8e81-97d7-001a165d5381.png)

なお、詳細に見たい場合は`| grep "message"`を削るだけでOKです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/926e9791-9e59-163e-91c8-dad856b20227.png)

整形のコードはこちらのブログを参考にさせていただきました :pray:

https://kotapontan.hatenablog.com/entry/2021/01/04/curl%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AE%E7%B5%90%E6%9E%9C%E3%82%92%E6%95%B4%E5%BD%A2%E3%81%99%E3%82%8B

## まとめ

- Figma APIでコメントを全件取得できる
- ただただ全てのコメントを見たい場面があれば使えるテクニック
- ネタです
UnityのLightAnchorコンポーネント

![LightAnchor3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98727/c6da7663-7b3c-b2e4-edc6-70747bbec250.gif)
この記事は[PONOS Advent Calendar2021](https://qiita.com/advent-calendar/2021/ponos)の6日目の記事です。

昨日は私(@block)の[CLIから使えるC#のフォーマッターdotnet-formatの紹介](https://qiita.com/block/items/3d2a2680d7c6cfbb5890)でした。

---

`LightAnchor`というものが面白かったので簡単な紹介です。

公式からは[Unity 2021.2 のアーティスト・デザイナー向け新機能](https://blog.unity.com/ja/technology/whats-new-for-artists-and-designers-in-unity-20212-0)や[New Lighting Features in Unity 2021.2- Volumetric Clouds, Lens Flare and Light Anchor](https://resources.unity.com/vidyard-all-players-8/new-lighting-features-in-unity-2021-2-volumetric-clouds?_ga=2.116202562.55191132.1638673008-352072205.1512542016)(動画の24:20あたり)で紹介されています。
[マニュアル](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@12.0/manual/light-anchor.html)もありますがパラメーターの説明だけなので直感的に分かりづらいと思います。

---


## `Light Anchor`コンポーネントとは
Unity2021.2から追加されたLight用のコンポーネントです。
今までライトでどこを照らすかの設定はLightをアタッチしたオブジェクトのTransformを編集するしかなかったですが`LightAnchor`を使用することで、照らしたい場所と方向を基準にライトを設定できるようになりました。


下記のgifはSpotLightをCubeの位置を基準に照らしているものです。
![LightAnchor1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98727/34404c3c-c52d-4851-646a-14da76da781d.gif)

## 設定方法
`Light`がアタッチされているオブジェクトに`LightAnchor`をアタッチして`Anchor Position Override`に照らしたいオブジェクトの`Transform`を参照させるだけです。

![LightAnchor2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98727/259d8bdc-4263-9ad9-6736-caa1422f7959.gif)

そのまま角度を設定したり距離を設定することもできます。
![LightAnchor3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98727/02d5d721-7cca-5ad4-09a0-ddb1f306006c.gif)

ちなみにそのまま`Anchor Position Override`に設定しているオブジェクトを動かすとLightのオブジェクトも同時に移動します。
![LightAnchor4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/98727/d31596bc-86d1-2868-89cf-a6c0994fea08.gif)

他にもいろんな機能があるのでぜひ試してみてください！

---
Lightの位置を固定したまま対象のオブジェクトの向きに向けたい場合は`Look At Constraint`というコンポーネントが使えると思います。

---

明日は@nissy_gpさんです
Lookerで日付フィルタを複数条件指定する方法



※ 本投稿はLooker Advent Caledar 2021 4日目の記事となります。

Lookerで時系列表示するグラフの日時範囲を複数条件の組合わせで表現する小技の紹介になります。

## どんな時に使うのか？

例えば

- **当日の２年前から、１週間前までの範囲でデータを見たい。**
- **当日の午前10時から現時刻の30分前までの範囲でデータを見たい。**

など、`ある一定期間のデータを現時点から相対的に表示したい。`
という可視化が必要な場合に利用することになります。


## どうやって実現するのか？

Lookerでは複雑な日付範囲を指定する場合は、
**１つの日時項目のフィルタを複数組合わせる**ことで実現する必要があります。

具体的には、

- **当日の２年前から、１週間前までの範囲でデータを見たい。**

という場合には、以下のような複数のフィルタを指定します


```json:フィルタ１
## 当日の１週間前までの範囲を指定
　Date: is before relative 1 weeks ago
```

```json:フィルタ2
## 当日の2年前までの範囲を指定
Week: is on or after relative 2 years ago
```

:arrow_lower_right: Looker上では以下のようにします。
![Lookerで複数条件フィルタをAND指定する方法1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/9a739851-7bca-659b-0232-3cbfc25a27ee.png)

これで無事

- **当日の２年前から、１週間前までの範囲でデータを見たい。**

の要望を満たすことができるフィルタを設定することができました。


## まとめ

一つの日付項目を複数指定することで、複数条件のAND指定ができる。という結構マニアックな内容でした。
自身もLooker歴３年目に突入しましたが、この方法を知ったのはつい最近でしたので、なかなか実務で使うことがない内容かもしれません。ただしそういう情報も日本語ではまだ見つけるのが難しい為、この場を借りて紹介させていただきました。どなたかの役に立てれば幸いです。
[6行メモ] ActiveRecordのeagar_load後のwhere条件をControllerのParam値で動的に変更したい時

これは「[「はじめに」の Advent Calendar 2021](https://adventar.org/calendars/7037)」3日目の記事です。

Active Record 初心者が今日学んだこと。

```ruby
result = Foo.where(name: params[:name])
            .eager_load(:bars)
if params[:bar_name].present?
  result.where(bars: { name: params[:bar_name] })
end

render :json => result
```

※もっと良い方法があったら教えて下さい。
【Python】BeautifulSoupを使ってスクレイピングで気象データを取得

## 概要
**スクレイピング**とはWebサイトからデータを取得すること。
Webスクレイピングとも呼ばれます。
サイトによっては禁止されている場合やマナーなどがあるので、使うときは注意が必要です。

今回は**BeautifulSoup**と**urllib.request**いうモジュールを使って気象データを取得します。

最終的にこのようなCSVファイルを作成しました。

```csv:sample.csv
日時,現地気圧,海面気圧,降水量,平均気温,最高気温,最低気温,湿度,平均風速,最大風速,最大風向,日照時間
2020-01-01,1018.0,1021.0,--,5.5,10.2,3.2,49,2.6,6.1,337.5,7.4
...
```

## Pythonで実装

今回は[気象庁HP](https://www.data.jma.go.jp/obd/stats/etrn/index.php)より、表になったデータを取得しました。

**BeautifulSoup**と**urllib.request**がない場合はpipなどで入れてください。
[pip公式](https://pypi.org)では下記のように書かれていました。

```bash:bash
pip install beautifulsoup4
pip install pycopy-urllib.request
```

それでは実装していきます。

```python:scraping.py
import urllib.request
from bs4 import BeautifulSoup

url = "https://..."
html = urllib.request.urlopen(url).read()
soup = BeautifulSoup(html, "lxml")
tbl = soup.find("table", { "class" : "data2_s" })

for tr in tbl.findAll('tr'):
    tdList = tr.findAll('td')
    print(tdList[0].string)
```

**urllib.request**でhtmlコードを取得し、**BeautifulSoup**で解析していきます。
第二引数には下記があります。必要なライブラリがない場合はエラーを吐きます。

- lxml
- html.parser
- xml
- html5lib

変数**soup**にはBeautifulSoupによって綺麗なコードが格納されています。
これを加工してデータを取得できます。

今回は表なので、htmlから表の部分を取り出し、**tr**の中にある**td**を取得します。
findAllにはリスト型で入っているので、欲しい要素番号を指定しましょう。
stringをつけることで文字列になります。

これをCSVモジュール等でファイルに書き出せば、冒頭のようなCSVファイルを作成することができます。
詳しい説明は[こちら](https://atchicken.com/fileread/)でしています。

## まとめ
PythonのBeautifulSoupを使って超簡単にスクレイピングを実現できました。
データ取得が自動化できるのはかなりありがたいですね。

## その他
今回実装したソースコードはGitHubに置いてあります。

https://github.com/khfkd/scraping

作成にあたり、下記サイトを参考にさせていただきました。
この場を借りて感謝申し上げます。

https://www.gis-py.com/entry/scraping-weather-data
Power Virtual Agents: 変数についてのまとめ

# 背景
会社で以下質問を受けたので試してみた記録

> ボット変数のリセット方法が分かりますか？　トピックA⇒C、トピックB⇒C　で動かすと、トピックA⇒Cで動かしたときの結果が残ってるんです。

https://powerva.microsoft.com/

# 分かったこと
## 「質問する」を追加することで作成する。
逆に言うと・・これでしか、作成出来ない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d8bfb85f-a236-4b44-42f0-1ff3dbd32896.png)

[Create a variable](https://docs.microsoft.com/en-us/power-virtual-agents/authoring-variables#create-a-variable) によると、
> In the bot authoring canvas, add a question node by choosing Ask a question. **A variable will be automatically created** within the node.

他に生成方法が無いかと探したけど、現状見つからず・・。上記マニュアルの通りかな、と

## 変数の設定
- トピック：対象トピック内だけで利用可能。<br>「別のトピックにリダイレクトする」を利用することで、以下が効いてくる
    - 他のトピックから・・：他のトピックから受け取ることが可能。と言いつつ、質問で上書きされるので意味不明
    - 値を元のトピックに・・：Return して結果を返すことが可能
- ボット：トピック間で利用可能
    - 外部ソース・・：外部（Power Automate とか）で設定することが可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/8172ca6f-c9ef-9500-5dc9-45bcaf37b331.png)

### 他のトピックから・・・
渡す値が、変数と整合取れていれば普通に渡せるが、不整合の場合はエラー
※以下の場合、選択肢外の変数を入れているからエラーが出てると認識
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/d3eb557b-638d-0dd0-4286-4e81a5c9b7df.png)

で、参照元から渡されてる場合、質問が省略される。
故に、複数のトピックからリダイレクトした場合、Call元の値をそのまま利用することが可能そう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/e3cd2824-c085-0149-f317-a450af20974d.png)

しかしながら、同一トピックへの複数リダイレクトの場合は、二回目以降では、引数は利用されず質問されることになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/444cd36a-61a5-6b93-a373-4ccd14bd0a1c.png)


### 値を元のトピックに・・・
こんな感じで使うことでトピックの結果を受け取り可能
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/8ded202e-def4-6062-c90c-623d425c7ccf.png)

## 変数の初期化タイミング
[Life Cycle](https://docs.microsoft.com/en-us/power-virtual-agents/authoring-variables-bot#bot-variables-lifecycle-and-resetting-its-value) によると、最初からやり直す場合と、変数の生成トピックを呼び出された時。
> The value is only cleared when the bot user is redirected to the Start over system topic, or when the user triggers this topic directly (for example, by typing Start over). In this case, all bot variables will be reset and won't have any values.

## 変数が初期化されてなかった場合の動作
[initialization](https://docs.microsoft.com/en-us/power-virtual-agents/authoring-variables-bot#bot-variable-initialization) によると、参照トピックが呼び出された際に未初期化だった場合、変数の生成トピックが事前に呼び出されることになる。
> If a bot variable is triggered before it has been initialized (or "filled in"), the bot will automatically trigger the part of the topic where the bot variable is first defined—even when it's in a different topic—before returning to the original topic. This allows the bot to have all the variables filled in without interrupting the conversation.

実例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120072/5827f6b3-96e0-85e0-4ec8-46be5d3cea2c.png)

# 考察
- 変数のリセット方法は無い
- 複数のトピックの結果を共通して利用することは可能。
    - 同一トピックを複数回リダイレクトすることがあると問題はあるけどそんな使い方はたぶんしない筈
- Bot変数を利用すると、必須質問をトピックにまとめておくことで、必要な時に勝手に呼ばれるように出来そう
- Automateからの受取もまた便利そうね

いい感じで使えそうなことが見えてきた。
あとは、もうちょいメンテしやすい仕組みにしてくれるとありがたいなぁ
プログラミング学習Ⅱ　Day1(クラスとは)

# クラス
- オブジェクトを定義する機能をクラスという
- クラスから作成されたオブジェクトをインスタンスという
- クラス内で関数を定義するとそれはメソッド。"."で表現する
- l.append()もメソッド
- クラスとインスタンスは別
- クラスは定義をするだけ
- 中身ができたものがインスタンス

```python
class クラス名:
    ブロック
```
アイコン作成等のツールリンク集


たまたまどこかで知り、便利じゃん！と思ってブックマークに入れたは良いが、
本当に必要なときに結局どこにしまったか忘れているので、
個人的にたまに使ったりするツール系のリンクを備忘録としてまとめてみました。

# Android/iOS

- AndroidAssetStudio(各種アイコン作成)

https://romannurik.github.io/AndroidAssetStudio/

- MakeAppIcon(アイコン作成)

https://makeappicon.com/

- resizeappicon(アイコン作成)

https://resizeappicon.com/

- (Android用)BundleToolを使用してaabファイルを実機にインストール

https://apuridasuo.hatenablog.com/entry/2019/09/25/144546


# 画像系

- RemoveBackground(透過画像作成)

https://www.remove.bg/

- MethodDraw(SVGエディタ)

https://editor.method.ac/

- SvgPathEditor(SVGエディタ)

https://yqnn.github.io/svg-path-editor/


# フォント系

- Google Fonts

https://fonts.google.com/

- MaterialDesignIcons

https://materialdesignicons.com/


# その他

- Regexper(正規表現の可視化)

https://regexper.com/

- .NET Foundation Store(.NET系のノベルティストア)

https://stores.kotisdesign.com/dotnetfoundation
同一アカウント内でのS3のレプリケーション手順



#目的
シンプルな設定でS3のレプリケーションを実施することです。
そのため、細かな設定の説明は省略します。
あくまでレプリケーションという技術を実施することを念頭に置いてます。

#準備
S3
・レプリケート元バケットを作成
・レプリケート先バケットの作成
※どちらも設定でバージョニングを有効化しないとレプリケーションができないので注意してください

IAM
・EC2でS３バケットの中身をコピーするためのIAMロールの作成

#手順
S3のナビゲーションペインから「バケット」をクリック
レプリケーション元バケットを選択
「管理」タブの「レプリケーションルール」の項目から「レプリケーションルールを作成」をクリック

こんな画面が出てたらOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/969819/4082ff01-e70c-42ce-f483-d4fe641815ca.png)

##設定項目
・レプリケーションルール名→任意
・ステータス→有効
・ルールスコープを選択→「バケット内のすべてのオブジェクトに適用」を選択します（どちらでも構いません）
・送信先→このアカウントのバケットを選択する（別のアカウントの選択をするとクロスアカウントアクセスを別途する必要があります。
・IAMロール→新しいIAMロールを作成
・「保存」をクリック

##データのコピー
IAMロールアタッチされたEC2で以下のコマンドを参考にS3バケットの中身コピーする
※レプリケーションはルールを作成される以前のオブジェクトはレプリケーションされないためこれをしないとデータの不整合が生じます。


#実験
やってみましょう
①GuardDutyの検出結果保存用バケットを作成します。
②レプリケート先のバケットを作成します
③上のようにレプリケーションのための設定を完了させます
④guarddutyのナビゲーションペインの「設定」をクリック
⑤「結果のサンプル」より「結果サンプルの生成」をクリックして検出結果のサンプルを生成
⑥時間をおいてそれぞれのバケットに入っているか確認する
blenderで縦書きテキストを作るアドオンを書いたよ

# 
![](https://imgur.com/6FyfMbh.png)


## まえがき
この記事は、
[QiitaのBlender Advent Calendar 2021](https://qiita.com/advent-calendar/2021/blender) の6日目と、
[BLUGjpさん主催のBlender Advent Calendar 2021](https://adventar.org/calendars/6384) の4日目の記事です。

さて今年のアドベントカレンダーが始まって少し立ちましたね。
あんまりエントリーが集まらない事に時代の流れを感じます。
かつて「俺だけが良さを知っているんだ…」という気分で使っていたblenderもどんどんメジャーになっていって日々話題に事欠かなくなったのであんまりアドベントカレンダーのお祭り感がなくなったのかなと思っているblender厄介オタクです。

## 記事概要
この記事では私が実装したtategaki text toolsアドオンを紹介します。

このアドオン何ができるかというと、blender上で縦書きテキストの作成が出来ます。

まず、blenderのテキストオブジェクトって縦書きに対応してませんよね。

これが地味に不便だなーと思っていて、無理やり素のblenderで縦書きテキストを作ろうと思うと1文字ずつ改行する必要があるので面倒だし、複数行にしようとするとレイアウトが汚くてイマイチになる…

これらを解決してblender上で縦書きテキストオブジェクトの作成、レイアウトの調整、メッシュなどへ変換する機能を実装しました


## 出来上がったもの
https://github.com/nepia11/tategaki-text

## 機能紹介

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

以下機能は縦書きテキストのコンテナ(エンプティオブジェクト)を選択状態で使えます

### 縦書きテキストに変換

- 選択テキストオブジェクトから縦書きテキストを生成

テキストオブジェクトのフォントやマテリアルを引き継いだ状態で生成することができます

分割解像度だけ、縦書きテキスト生成時に重くなるので下げて生成します

### 縦書きテキストを複製

- 選択された縦書きテキストから新規に縦書きテキストを生成

単純にコレクションとか、選択して複製するとIDかぶりするので同じ状態のオブジェクトをIDを変えて再生成します

### 行間調整

- 行間を調整する

### 字間調整

- 字間、自動カーニングの有無を調整する

固定値での文字配置と、グリフの大きさを基準にした文字配置の調整ができます

グリフの大きさ(というか高さ)をいちいち計算すると重かったのでキャッシュするようになっています

### 行文字数調整

- 縦書きテキストの 1 行あたりの文字数制限を調整する

作文用紙みたいに一定の文字数で改行したいときに調整します

内部データの行を分割して改行表示しているので一応非破壊に調整できます

### 変換

縦書きテキストを単一のオブジェクトにそれぞれ変換する

- メッシュ
- カーブ
- gpencil

縦書きテキストオブジェクトは大量のテキストオブジェクトで構成されているので、作りっぱなしにしているとオブジェクトの参照などが遅くなっていきます。

なので必要に応じてメッシュやカーブに変換しておくと良いです。

gpencilへの変換は、例えばgpencilで漫画を描いたときに文字入れするのに使えないかなと思って実装してみました。


## あとがき
そんな難しくないだろうと思って実装し始めたら結構たいへんでした

縦書き時に回転する文字とか位置の調整が必要な句読点など細かい工夫があります

愚直に実装すると動作が重くなりすぎるので細かい軽量化や最適化をしてあります（bpy.opsで処理すると重い部分をbpy.dataで代替する処理を色々実装）

コア部分で1200行を越えててでか過ぎるなーと思いつつファイルを分割するとアドオン開発時にリロードがうまく行かなくなったりそもそも分割する領域が定かじゃないので手が付けられない…

本文編集機能も実装したいなーと思いつつめんどくささが勝っているのでしばらくはやらないと思います

この記事とは別に、つい最近rename toolというアドオンを書いたのでちょっと紹介
https://github.com/nepia11/rename_tool
ざっくり紹介すると、非ascii文字を含む語句を含むアイテム名(オブジェクトとかモディファイアとか色々)を一括置換するツールです
blendファイル内のマルチバイト文字を一層したいときに使えます


それでは
Gitコマンド　備忘録

#はじめに
Gitのコマンドをすぐに忘れるのでメモしておきます。
自分用備忘録です。


####・リポジトリの作成

```
git init
```

####・共有対象の指定

```
git add [ファイル名]
# カレントディレクトリ以下の、すべてのファイル(変更があったもの)をaddする場合は
git add .
```

####・addされたファイルのコミット

```
git commit -m "メッセージ"
```





####・コミット履歴の確認

```
git log
```

####・コミットメッセージのみ確認
```
git log --oneline
```

####・指定の数だけコミット履歴の確認(最後に数字を指定)

```
git log -1
```

####・差分の表示

```
git diff
```

今後編集して追加していきます。
ブラウザーで録音、再生

こちらのページを参考にしました。
[JavaScriptだけ！ブラウザで録音＆ファイル保存する方法](https://blog.capilano-fw.com/?p=5351)

録音
![sound_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/0374e8d7-be80-030e-34b6-f3ff624eafc1.png)

再生
![sound_bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/7d5c5c62-57f5-ca0a-b70a-80ef849ae810.png)

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body class="p-3">
<h1 class="mb-3">JavaScriptで録音するサンプル</h1>
<div id="app">
        <!-- ③ 録音の開始／終了ボタンを設置する部分 -->
<button class="btn btn-danger" type="button" v-if="status=='ready'" @click="startRecording">録音を開始する</button>
<button class="btn btn-primary" type="button" v-if="status=='recording'" @click="stopRecording">録音を終了する</button>

</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script src="sound_record.js"></script>
<hr />
Dec/03/2021<br />
</body>
</html>
```

```js:sound_record.js

        new Vue({
            el: '#app',
            data: {

                // ① 変数を宣言する部分
status: 'init',     // 状況
recorder: null,     // 音声にアクセスする "MediaRecorder" のインスタンス
audioData: [],      // 入力された音声データ
audioExtension: ''  // 音声ファイルの拡張子
            },
            methods: {

                // ② 録音を開始／ストップする部分
startRecording() {

    this.status = 'recording';
    this.audioData = [];
    this.recorder.start();

},
stopRecording() {

    this.recorder.stop();
    this.status = 'ready';

},

                // ④ 音声ファイルの拡張子を取得する部分

getExtension(audioType) {

    let extension = 'wav';
    const matches = audioType.match(/audio\/([^;]+)/);

    if(matches) {

        extension = matches[1];
    }

    return '.'+ extension;

}

            },
            mounted() {

                // ⑤ マイクにアクセス
navigator.mediaDevices.getUserMedia({ audio: true })
    .then(stream => {

        this.recorder = new MediaRecorder(stream);
        this.recorder.addEventListener('dataavailable', e => {

            this.audioData.push(e.data);
            this.audioExtension = this.getExtension(e.data.type);

        });
        this.recorder.addEventListener('stop', () => {

            const audioBlob = new Blob(this.audioData);
            const url = URL.createObjectURL(audioBlob);
            let a = document.createElement('a');
            a.href = url;
            a.download = Math.floor(Date.now() / 1000) + this.audioExtension;
            document.body.appendChild(a);
            a.click();

        });
        this.status = 'ready';

    });

            }
        });
```

http://localhost/tmp/sound_record/
にアクセス
https でなくても大丈夫です。

Chrome では、 *.webm が作成され
Firefox では、 *.ogg が作成されます。
Self-hosted runnerの`--ephemeral`オプションを試す


Self-hosted runnerとして登録する際に、`--ephemeral`オプションを付ける。

```
./config.sh --url (リポジトリのURL) --token (トークン) --ephemeral
```

登録できたら、起動する。

```
./run.sh
```

そしたら動かしてみる。

割り当てられたジョブが完了すると、Self-hosted runnerは自動的にRemoveされます。work folderなどは残る。
NextAuth.js+API Routes+Prisma...。Firebase不要!?のフルスタックアプリケーション。

# はじめに
フロントエンドをメインで学習している僕にとって、Firebaseは欠かせない相棒です。
(いや、"でした"と言うべきでしょうか。今回、「NextAuth.js」と「Next API Routes」にトライするまでは、、)

下記のような技術スタックを用いて簡単なアプリを作成したので、その感想をFirebaseと比較しつつ、書いていきます。

>前提として、、
ここでは個人開発等の比較的小規模なアプリケーションを想定して、色々書いております。


<div align="center">
<h1 align="center"> :book: 技術</h1>
<p align="center">
  <a href="https://nextjs.org/"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1766904/26eb5fa5-2494-44ac-dacd-18e645344730.png" width="100px" /></a>
    <a href="https://vercel.com/"><img width="100px;" alt="prisma" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1766904/3b5a7eb1-3253-fdd5-e482-5dff9e930274.png">
</a>
  <a href="https://prisma.io/"><img width="100px;" alt="prisma" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1766904/cdc7a81e-94ea-a98e-6228-32b8d026692f.png">
</a>
  <a href="https://www.postgresql.org/"><img width="100px;" alt="tailwindcss" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1766904/eadf278a-eb24-77b5-05ed-615af6fa0b8d.png"></a>
  <a href="https://mui.com/"><img width="100px;" alt="daisyUI" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1766904/40dde297-86cb-33b0-20f2-b3d8da7ff0f0.jpeg"></a>
</p>
</div>

## :octocat: Github
実装甘い部分はありますが、、

https://github.com/kondo97/deep-memo

## :apple: 作成したアプリのURL
ゲストログインもあるので、覗いてみて下さい　:bow:

https://deep-app.vercel.app/login

# :white_check_mark: NextAuth.js　～お手軽認証機能～
「Firebase Authentication」に迫るレベルで簡単に認証機能が実装できてしまいます。
SNSログイン認証であれば、ほぼ遜色ないです。
ただ、メールアドレス認証に関してはFIrebaseには敵わなそうです。
UIをカスタマイズしたり、認証メールを送るのがやや面倒でしょうか。

一方、NextAuthの良い点として、sessinを用いてログインしているかどうかを管理するのが容易であるように感じました。FirebaseはonAuthStateChangedメソッドを用いると思うのですが、このメソッドをどこで呼び出すか、データをどこで保持しておくか悩んだ記憶があります。

メールアドレス認証が不要ならば、NextAuth.jsを推奨したいです。

[[...NextAuth.ts]をご確認下さい。](https://github.com/kondo97/deep-memo/blob/master/src/pages/api/auth/%5B...nextauth%5D.ts)

# :white_check_mark: API Routes　～Expressも不要だ！～
``create-next-app``を実行すると、pagesディレクトリ配下にapiディレクトリがデフォルトで作成されます。このapiディレクトリ配下に作成したファイルで、クライアントから呼び出せるAPI を定義することができます。

Expressを導入する必要も無いのです。:open_mouth:

ただ個人的に微妙だったのが、pages配下にapiディレクトリを置くと、フロント側と視覚的に混ざってしまう点です。今回の小規模な開発でさえ、やりにくさを感じました。出来ればAPI側は、フロント側と明確に分別したいところです。

# :white_check_mark: Vercel　～push毎にデプロイ&URL発行～
Githubにプッシュすれば、自動でビルド・デプロイされるので非常にカンタン。
以前、SSRで実装したNuxt.jsのアプリケーションを、「Firebase Hosting」でデプロイしたのですが、「Cloud Functions」の設定が必要で苦労しました。

push毎にデプロイしてくれる点もvercelの良いところです。
ビルドに失敗していたら、プルリクを作成したタイミングで教えてくれます。

# :white_check_mark: テスト　～とりあえずJestを使っておく！～
今回一番躓いたのが、テストの実装です。
「NextAuth.js」や「API routes」の公式では、Cypressが推奨されております。他にも、next-test-api-route-handlerというモジュールなどが選択肢としてあります。
[詳しくは公式ドキュメントでご確認下さい。](https://nextjs.org/docs/testing)

githubで色々な実装例は確認したものの、結局Jestを採用しました。
node-mocks-httpを使うと、比較的スッキリ記述出来ました。

ただ、正直APIのテストはかなりサボっております。
ベストプラクティスと言える自信はありませんが、個人的にはJestで落ち着きました。

[テストディレクトリをご確認下さい。](https://github.com/kondo97/deep-memo/tree/master/src/__test__)

# まとめ　
今後の個人開発は、上記の技術スタックを使用していきたいです。
もちろんFirebaseの方が、開発の全体的なスピードは早いと思います。
しかし、Firebaseに関してのキャッチアップ自体にもそれなりに時間的コストがかかります。
(NoSQLなFirestoreは面白いですが、、）

というわけで、しばらくはVue.js(Nuxt.js)からは離れることになりそうです。
Next.jsが素晴らしすぎる、、、
greple #5 複数キーワード検索 NOT

# 複数キーワード検索 NOT 編

これまでに、複数キーワードを使った AND と OR の組み合わせを紹介しました。AND、OR とくれば、当然次は NOT です。

## 実行例

また寿司セットを使って考えてみます。

```sushi.txt
サービスセット      熟成まぐろ えび たまご いか サーモン いなり ねぎまぐろ サラダ
お子様セット        熟成まぐろ えび たまご いなり ツナサラダ
特上セット          中とろ 熟成まぐろ 熟成真鯛 はまち 赤えび ほたて うなぎ かに いくら
特上極旨セット      中とろ はまち かに いくら 赤えび サーモン うなぎ うに
うどんセット        熟成まぐろ サーモン たまご えび うどん
サラダ軍艦セット    えびマヨ ツナサラダ サラダ シーフードサラダ
人気セット          熟成まぐろ 漬けまぐろ サーモン びんちょう いか えび えびアボカド たまご
まぐろづくしセット  中とろ 熟成まぐろ ねぎまぐろ
プレミアムセット    中とろ まぐろ サーモン 赤えび はまち うなぎ かに いくら
```

**まぐろ**は必ず食べたくて、**はまち**か**えび**のどちらかが入ったセットは、次のようにして探すことができました。

```
greple -n 'まぐろ はまち|えび' sushi.txt 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/8f8ea7ce-3418-c0bf-d1bf-e87a2db26202.png)

でも、実は**いくら**はアレルギーで食べられないことを思い出しました。

```
greple -n 'まぐろ はまち|えび いくら' sushi.txt 
```

とすれば、候補の中から**いくら**を含む食べられないセットを表示することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/0d8e93bb-6c50-02cd-551d-6745e96c6d40.png)

でも、本当に探したいのは**いくらを含まない**セットです。そのような場合には、やはり検索エンジンと同じように、キーワードの先頭にマイナス記号 `-` を付けます。

```
greple -n 'まぐろ はまち|えび -いくら' sushi.txt 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/0fc07065-b9c7-25ea-feb9-250b6f232e1e.png)

これで、望みの結果を得ることができました。

## grep -v との違い

grep の `-v` オプションは、全体から指定したパターンを含まない行を選び出すためのものです。それに対して、greple の NOT キーワードは、他のキーワードによって選ばれた選択肢から、指定したパターンを含むものを削除するためのものです。ですから NOT キーワードだけのパターンはエラーになります。

grep と同様に動作して欲しければ、どの行にも必ずマッチするパターン、たとえば行頭にマッチする `^` を指定することで実現は可能です。ただ、そのために greple を使う必要性は、あまり感じられません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36551/77853d57-05b9-347f-59b4-773b8c2aaa70.png)

## まとめ

今回は、複数キーワードを使った検索について AND と OR に続いて NOT の使い方を紹介しました。使い方は簡単で、検索エンジンと同じように、除外したいパターンの先頭に `-` を付けるだけです。

寿司セットの例は、数が少ないので**目grep**でも望む情報は得られますが、もし数千行の情報から選び出すとすれば、ツールの力を借りた方が得策です。AND、OR、NOT を組み合わせて情報を絞り込んでいくことで、望みの結果に近づくことができます。

## SEE ALSO

https://qiita.com/advent-calendar/2021/greple

1. https://qiita.com/kaz-utashiro/items/5b6bcbe54891b3bd9db5
2. https://qiita.com/kaz-utashiro/items/eb8c7067e6de34842fe3
3. https://qiita.com/kaz-utashiro/items/165e744d4250adedc4c1
4. https://qiita.com/kaz-utashiro/items/439e6abcecf36c520703
5. https://qiita.com/kaz-utashiro/items/24ac0b8fdd30b598e069 ←イマココ
6. https://qiita.com/kaz-utashiro/items/a1ba4e3d07cf37dc25e3
7. https://qiita.com/kaz-utashiro/items/0c8c944c17a72724b771
8. https://qiita.com/kaz-utashiro/items/8783c2fd0cc4315b9a3d
9. https://qiita.com/kaz-utashiro/items/84f5a6be6bf996076c64
10. https://qiita.com/kaz-utashiro/items/ebc7ea99f800cfc8c90c
11. https://qiita.com/kaz-utashiro/items/25a14e75380c39b5e0af
12. https://qiita.com/kaz-utashiro/items/ebbeb8a5538a15ff04fc
13. https://qiita.com/kaz-utashiro/items/b265deef9c9b1953a414
14. https://qiita.com/kaz-utashiro/items/2b20e0226cffde213ce0
15. https://qiita.com/kaz-utashiro/items/16b5142ef7a89aa35380
16. https://qiita.com/kaz-utashiro/items/d19fe5ee859f31ce172c
17. https://qiita.com/kaz-utashiro/items/09a5f5cf08ce314e2add
18. https://qiita.com/kaz-utashiro/items/6e4b1f51455e587ef743

- https://github.com/kaz-utashiro/greple
- https://metacpan.org/dist/App-Greple
EclipseをMacにインストールする方法


今回はJava開発環境のEclipseをMacにインストールする手順を教えます✨

まずは下記のサイトからインストーラを入手します。
　:point_right: https://mergedoc.osdn.jp/
![スクリーンショット 2021-12-02 21.38.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2346709/873fdd15-cd52-cd58-09fb-17f7aa55632a.png)

「Eclipse 2021 最新版」をクリック👆
容量があるのであればMac版のJavaで「Full Edition」をダウンロードしましょう。
![スクリーンショット 2021-12-02 21.42.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2346709/778e93af-f8be-af15-4422-40e37e34207f.png)

ダウンロードができたらファイル実行し、表示された画面に従って「Eclipse_2021-12」を「Applications」フォルダにコピーします。
![スクリーンショット 2021-12-03 20.14.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2346709/c7d9819b-9436-6c2e-0a36-e8547622bd1d.png)

先ほど「Applications」フォルダに移動した「Eclipse」を起動してみましょう。

![スクリーンショット 2021-12-03 20.26.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2346709/5452ab76-9cbf-9b52-a232-91435a55e826.png)

:warning:このようなエラーが表示された場合は、
　システム環境設定 > セキュリティとプライバシー > このまま開く
これでアプリを開くことができました:white_flower:

![スクリーンショット 2021-12-03 20.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2346709/c820ef8e-e81b-b680-3e63-e566e22acca3.png)

続きは別の記事で紹介しようと思います:smile::wave:
OutSystems Aggregate で動的SQL

先日、検索画面から動的にクエリを構成したいんだけど、Aggregate だと検索条件が決め打ちになるので、検索条件が設定されていたら検索条件に加える、ということができないと相談をうけることがありました。

スキャッフォールディングで作成すると、自動的にこの対応がなされるのですが、複数の検索条件を想定して一から検索画面を作る際に思いつかなかったりと、意外に盲点になっている方がいらっしゃるのかなと思い、今回記事にしてみました。

#パラメータは Aggregate のなかで評価できる

単純な入力有無チェックを行う場合は、次のようなフィルタを追加することで、AdvancedSQL にすることなく、実現できます。

```
<入力パラメータ> = "" or <入力パラメータ> = Entity.Field
```

パラメータチェックは、最初（左側）にします。これで、入力があったら、検索条件に加えるという動作になります。

例えば、アカウントテーブルを定義して、名前、タイプ、開設日のフィールドを定義したとします。アカウント検索画面を作成して、入力されていたら条件に加える、という標準的な仕様があったとします。その場合は、このような感じになります。

![OutSystemsAggregate1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348467/b332ba10-0e19-17c7-d27e-3961c9011cdd.png)

SearchXXXというのは、各検索入力値です。

#入力有無以外のロジックは埋め込めるか

式を評価できる仕様にはなっていますが、シンプルな入力有無チェック以外の要件は、なかなかフィルタの中に記述しきれないと思います。

その場合は、Aggregate を呼び出す前に、呼び出し元で要・不要判定だけしておいて、Aggregate では、

```
<要・不要判定結果フラグパラメータ> and <入力パラメータ> = Entity.Field
```

のようにすることもできます。こちらは、もちろん **and** です。

パラメータではなく、関数に差し替えることもできますが、複雑な処理であれば、パラメータを使って外で計算するほうが、トラブルシューティングしやすいでしょう。
2021-12-03 RAD Studio 10.2 Tokyo > エディタのスクロールが遅い症状 > とりあえずの対処


### 動作環境

- Windows 10 Pro (v21H1)
- RAD Studio  10.2 Tokyo

### 症状

エディタのスクロールに5秒くらいかかる。
コーディングしている時のストレスになる。

### 気づいたこと

1. ツール > オプション > エディタ設定 > 色 > 強調表示
1. 「構造強調表示を有効にする」にチェック
    - 普段はチェックしてない
1. OKを押す
    - => スクロールが遅いのが解消される (ただし、コードの最後の行あたりは遅いまま)
1. ツール > オプション > エディタ設定 > 色 > 強調表示
1. 「構造強調表示を有効にする」にチェックをはずす
1. OKを押す
    - => スクロールが遅いのが解消されたまま (コードの最後の行あたりの遅い症状も消える)

<img width="955" alt="image.png (36.7 kB)" src="https://img.esa.io/uploads/production/attachments/6206/2021/12/03/21741/71d7ef40-2eb4-4ab5-83ee-18e8ffde5e23.png">

### ファイルを開き直すと再発する

ファイルを開き直すと再発してしまう。

 「構造強調表示を有効にする」のチェックをつけたままだとファイルを開き直してもスクロール速度は速いままである(コード最後の行あたりのスクロールが遅い症状は解消しない)。

   個人的には構造強調表示は邪魔なので表示はしたくないところではあるが、スクロールが遅いストレスとどちらを取るか。

### とりあえずの対処

  以下のようにすることにした (強調表示を白で表示しない)。

<img width="944" alt="image.png (34.7 kB)" src="https://img.esa.io/uploads/production/attachments/6206/2021/12/03/21741/39ea0bb6-f752-4a62-b3e3-bd45ec67dd01.png">

10.2 Tokyo使用開始してからずっと抱えていたストレスが解消されただろうか。


### 関連

- Delphi 10.3.3/10.4 IDE Editor on VMware speed issue
    - https://en.delphipraxis.net/topic/3209-delphi-1033104-ide-editor-on-vmware-speed-issue/
    - こちらでもスクロールの遅い症状について議論されている
    - 症状がある人とない人がいる
    - はっきりとした解消法は見つかってないようだ
ラズパイをあきらめてMESHでUSB制御してみた

# この記事について
[前回](https://qiita.com/Hiroki1928/private/695318d05397b28f2ee2)ラズパイでのUSB制御に失敗したのでMESHでやってみました。

# 明るさが変わったらライトを光らせる
 ![無題 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502127/4d58b502-c4fb-be1f-4cc8-3fb4e5daea5a.png)

## いい感じに光りました

![iOS の画像 (4).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502127/52ee4913-275d-d040-119a-00aa73eaf8ba.jpeg)

![iOS の画像 (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502127/7fbf39fa-2ff7-1616-a235-8edeeb42f664.jpeg)

# チカチカさせてみた
暗くなったら、自動的にチカチカするようにしてみました
![無題 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502127/ca73b845-ce94-2735-7ded-d934d42e823f.png)

## いい感じにチカチカしています

[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/sW2BFTZa3oE/0.jpg)](https://www.youtube.com/watch?v=sW2BFTZa3oE)
【Rails】redirect_toとrenderの処理の違いについて【初学者の疑問点を簡潔に解説】

## はじめに
　本記事は、プログラミングの学習を始めて1ヶ月の初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。
　そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。
　間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。

## 今回の疑問点
　今回の疑問点は、

　　_`redirect_to`と`render`の処理の違い_
　
　です。　

 　以前、バリデーションの設定を行った際に上記について疑問を抱きました。
　また、処理の違いをしっかりと理解しておかないとエラーの発生につながるので今回まとめていきます。

## 疑問点についての解説

###結論
結論から記載しますと`redirect_to`と`render`の処理はそれぞれ以下のようになります。

####redirect_toの処理の流れ

`①controller（redirect_to）　→ ②HTTPリクエスト　→　③ルーティング　→　④controller　→　⑤view`

①controllerの処理で`redirect_to`を実行
②`redirect_to`の引数で指定したURLにHTTPリクエストを実行
③HTTPリクエストされたURLに対応するルーティング処理を実行
④ルーティング処理に対応したcontroller、アクションが呼び出され処理を実行
⑤処理に応じたviewのレンダリングを実行

####renderの処理の流れ

`①controller　→　②view`

①controllerの処理で`render`を実行
②renderのオプションで指定したviewファイルを表示する


###特に注意を要するポイント
**redirect_toとrenderの処理の違いの中でも、`render`を使用してviewファイルを表示したときにはアクションを呼び出し処理をしているわけではないことに注意しましょう。**

以下で具体例を用いて説明します。

```ruby:app/controllers/books_contllore.rb
class BooksController < ApplicationController


  def index
    @books = Book.all
    @book = Book.new
  end

  def create
    @book = Book.new(book_params)
    @book.user_id = current_user.id
    if @book.save
      redirect_to book_path(@book), notice: "You have created book successfully."
    else
      render 'index'
    end
  end

end
```

上記の記述で、`render`の処理の際にindexアクションは呼び出されず、createアクションから直接index.html.erbを表示しするためエラーが発生します。
indexアクションをご確認ください。
`@books = Book.all`
`@book = Book.new`
２つのインスタンス変数が定義されております。
次にcreateアクションをご確認ください。
`@book = Book.new(book_params)`
`@book.user_id = current_user.id`
のみでindexアクションで定義されていた
`@books = Book.all`
が定義されていません。
先ほども申し上げた通り、`render`処理の際にはindexアクションは実行されないので、上記の記述のまま、処理をしてもcreateアクション内では`@books = Book.all`が定義されていないため、Viewがデータを取得できずにエラーとなります。

以下のように記載することでエラーを解消することができます。

```ruby:app/controllers/books_contllore.rb
class BooksController < ApplicationController


  def index
    @books = Book.all
    @book = Book.new
  end

  def create
    @book = Book.new(book_params)
    @book.user_id = current_user.id
    if @book.save
      redirect_to book_path(@book), notice: "You have created book successfully."
    else
      @books = Book.all  #追記  
      render 'index'
    end
  end

end
```

また、`render`処理の際にはindexアクションが実行されないことから、`@book = Book.new`も実行されず、フォームの中に入力した内容がそのまま表示されます。


## まとめ
最後にポイントをまとめます。

- render処理の場合にはアクションが実行されない。
- 上記のことから、render処理を行う際には、呼び出すViewファイルに渡す変数が全てrender処理を行うアクションに定義されているか注意する必要がある。
【Java】Caffeineでお手軽にローディングキャッシュ 

## まえがき
・[Caffeine Cache](https://github.com/ben-manes/caffeine) をもう一段深堀り
・通常版は [【Java】Caffeineでお手軽にローカルキャッシュ](https://qiita.com/a__i__r/items/44e9b0aa934de26ba5bd)をご参考下さい。
・**ローディングキャッシュ（LoadingCache）**とは…
　　・**リクエストの際は既存のキャッシュにあるものを返し、裏側で新しいデータを読み込み格納しておく**キャッシュの事

#### 長所
・重い処理の影響をリクエストの際に受けない
・初回を起動時に読み込んでおけば、あとは良しなにしてくれる
#### 短所
・リクエストを返すと古い（現状の値ではない）値が取得される
　　・↑これを対処するにはScheduledExecutorServiceとかで定期的にロードするとかでしょうか
　　・定期的にロードするとリソース使うので一長一短な気がします
　　・バッチ等でテーブルにデータを入れるとか、起点となる処理が実行された際に裏で読み込むとか、色々と方法はありそうです

## 環境
spring framework
java 8

## 使い方
・ここではランキングのキャッシュを想定
#### 宣言

```java
private static @NonNull LoadingCache<String, Ranking> rankingCache = null;
```

#### 初期化
・通常のキャッシュと異なるのは build の際にキャッシュローダーを渡すこと
　　・ローダーを起動することでキャッシュのリフレッシュをしています
　　・refreshAfterWrite を指定することで書き込み後の時間経過後にリフレッシュするようになります
　　・expireAfterWrite も別に指定することが可能

```java
	@PostConstruct
	public void init() {
		rankingCache =
				Caffeine.newBuilder()
				.maximumSize(64)
				.refreshAfterWrite(10, TimeUnit.MINUTES)
				.build(rankingCacheLoader());
	}
```

#### 読み出し関数
・引数は String: param1, String: startDate, String: endDate を想定（この引数からキーを作ります）

```java
	public Ranking getCachedRankingDto(String param1, String startDate, String endDate) {

		Ranking result = new Ranking();
		if (param1 == null || startDate == null || endDate == null) return result;

		final String[] params = { param1, startDate, endDate };
		final String cacheKey = String.join("-", params);
		try {
			result = rankingCache.get(cacheKey, key -> {
				try {
					return getRankingDto(param1, startDate, endDate);
				} catch (Exception e) {
					throw new RuntimeException(e);
				}
			});
		} catch (Exception e) {
			rankingCache.invalidate(cacheKey);
			StringWriter sw = new StringWriter();
			e.printStackTrace(new PrintWriter(sw));
			logger.error(sw.toString());
		}
		return result;
	}
```

#### キャッシュローダー
・読み出し関数とは逆に、キーを分割してパラメータにしています

```java
	public CacheLoader<String, Ranking> rankingCacheLoader() {
		
		CacheLoader<String, Ranking> loader = new CacheLoader<String, Ranking>() {
			@Override
			public @Nullable Ranking load(@NonNull String key) throws Exception {
				
				final String[] params = key.split("-");
				if (params.length != 3) { return null; }
				return getRankingDto(params[0], params[1], params[2]);
			}
			
		};
		return loader;
	}
```

#### 実読み込み関数（キャッシュしたい重い処理）
```java
	public Ranking getRankingDto(String param1, String startDate, String endDate) {
		if (param1 == null || startDate == null || endDate == null) {
			return null;
		}
		// データ取得など重い処理
		Ranking dto = ...

		return dto;
	}
```

手軽に良きキャッシュライフ（？）が手に入ります。
以上、お疲れさまでした！
夏は海に潜り冬は山に登りそしてたまに滑るエンジニアの生活

断捨離の天才です、こんにちは。YouTubeチャンネルは100k subscriberに達していないですが、なんとかメソッドとは次元が違う天才でありたいと考えながら、今日も粛々とCatallaxyでフルスタックなエンジニアリングに注力しています。

こちらの記事は金属加工プラットフォームを開発・運用するCatallaxyの[Catallaxy Advent Calendar 2021](https://qiita.com/advent-calendar/2021/catallaxy)の第2日目の記事となります。1日目は[エンジニア1号](https://qiita.com/catallaxy)さんによる[Ruby biz Grand prix 2021のファイナリストに選ばれた](https://qiita.com/catallaxy/items/4a4e57c10f39bd86532e)でした。

断捨離が好きすぎて、不要なSlackや孤立してしまい放置されたNotion記事はついつい削除してしまう、断捨離の天才が、夏は海に潜り冬は山に登りそしてたまに滑るエンジニアの生活を実現するために努力していることを共有しようと思います。

## 夏は海に潜る

私がダイビングのことを知ったのは大学生のときだったと思います。学部4年の年でした。その時は地味な練習ばかりさせられ特に楽しいと思わなかったのですが、たまたまモルディブというリゾートに連れて行かれてそこで潜った海に魅せられてまた潜りたいなと思ったのでした。
帰国後、多忙を極めていたので、なかなか海に潜るチャンスは到来しなかったのですが、2021年Catallaxyにジョインしたところ、ダイビング経験者が複数名いたので、そこで意気投合していました。しかし、時は2021年。まだ新型コロナウイルスの感染拡大は続いており、ダイビングを含むワーケーション合宿は実現していませんでした。

2022年はさらに別の離島へのワーケーションを標榜しているところですが、本記事末尾に書く通り、その実現には、コーポレイトイベントマネジメント業務を担当してくださる人材が必要不可欠です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345141/d8a0cf0b-1403-4f85-cf72-fcaebba9eb1d.jpeg)


## 冬は山に登る

そうこうしているうちに、新型コロナウイルス第5波が峠を越して、ワーケーションをするチャンスが到来したのです。コーポレイトイベントマネージャーとソフトウェアエンジニアを兼務する断捨離の天才は急いでワーケーションの計画をすることにしました。

ファウンダーCEOが離島に行きたいと予々言っていたのを思い出した私たちコーポレイトイベントチームは国内数多あるワーケーションスペースより都内から行きやすい離島を探し出し、一度の失敗ののちブッキングに成功しました。

コロナウイルス感染症拡大および需要の減少から減便もあったり、地方在住者の参加もあり乗り継ぎを考慮する必要がありましたが、飛行機の手配もなんとか完了することができました。これは創業時から現在に至るまで普段、開発・運用業務で活用しているSlackのチャットを用いた即レスや[Slack Apps](https://api.slack.com/apps)の活用により円滑にできました。

離島ということで、積雪が見込めない中、CatallaxyのMitsuri開発軍（エンジニアを多く含むが他のロールの人たちもいます）は島の一番高い頂上を目指すことにしました。早朝起床からの久々の飛行機で到着して海の幸で腹ごしらえをすると、軽い登山をすることにしました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345141/246a5a18-65f1-b79f-0178-98d9b59d1361.jpeg)

頂上ではチーム一丸となり記念撮影をしたので、別の媒体などで掲載されるかと思います。フルリモート時代のチームビルディングに登山はもってこいだと感じました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345141/18a281df-bca5-7573-88b1-6e685feff51c.jpeg)

## たまに滑る

断捨離の天才なのでギャグを発することはなくそもそも私のギャグが滑ることはないのですが、目の前に雪があれば雪の上を滑ることになります。
今シーズンの初雪の報告も各地で見られるようになってきました。現時点で、雪山のワーケーションを兼ねた開発合宿の企画はないのですが、1月以降で企画をしていこうと検討しているところです。

本ワーケーションを支えてくださった外部の協力者の方々、ワーケーションに参加できなかったが本ワーケーションにより通常業務が出てしまった同僚には、感謝の気持ちしかないのですが、こんなCatallaxyのオペレーションを継続する、コーポレイトイベントマネジメント業務を兼務したい、あるいはダイビング部を結成させたい、人事またはソフトウェアエンジニアの方はぜひご応募ください：

- 人事: https://open.talentio.com/r/1/c/catallaxy/pages/36857
- フロントエンド: https://open.talentio.com/r/1/c/catallaxy/pages/25990
- バックエンド: https://open.talentio.com/r/1/c/catallaxy/pages/25989

ポジションは記事執筆時点のものであり充足状況によっては今後クローズする可能性があります。表示されない場合やその他のポジションにご興味のある方は https://open.talentio.com/r/1/c/catallaxy/homes/2947 もご確認ください。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345141/f33a16e7-815c-579c-fd95-fa4c0b53100b.jpeg)

明日はGitHub大好きなあの方によるCloud IDE 2021が公開される見込みですので、楽しみですね。

注意：決して全てがバケーションではなくちゃんと登山以外では通常の開発業務を行っていましたし、通常とは異なるチームビルディングの取り組みも実施していました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2345141/5b0e2a85-8e5b-f5a0-66e7-0fb28ec8d354.jpeg)

（夜は火を囲みコーヒーを飲みながら仕事をしていました）
AWS CLIとLinuxコマンドでSNSトピックやSQSキューのみを抽出する

# 抽出コマンド
AWSリソースの整理中、SNSトピックやSQSキューのみを抽出するためのコマンドが必要になったので、備忘録として残しておきます。以下のコマンドのプロファイルのみ修正することで、トピックやキューのみを抽出することが出来ます。

```
aws sns list-topics --profile XXX | jq -r '.Topics[].TopicArn' | cut -f 6 -d ":"
```

```
aws sqs list-queues --profile XXX | jq -r '.QueueUrls[]' | cut -f 5 -d "/"
```

# コマンド解説
解説するまでもないようなコマンドですが、インプットも兼ねて。
### aws sns list-topics (--profile XXX)


```
# SNSトピックを取得
aws sns list-topics --profile XXX 
```

出力結果

```
{
    "Topics": [
        {
            "TopicArn": "arn:aws:sns:ap-northeast-1:${AccountId}:${トピック名1}"
        },
        {
            "TopicArn": "arn:aws:sns:ap-northeast-1:${AccountId}:${トピック名2}"
        },
        // 以下省略
    ]
}
```
このままだと上記のようにトピックがjson形式で出力されるため、jqコマンドを利用して整形を行う。


### jq -r '.Topics[].TopicArn'
"Topics"配列内の"TopicArn"の内容を取得する。更に、-rオプションによりダブルクウォーテーションを取り除く。

```
# SNSトピックを取得し、jqコマンドでTopicArnのみを抽出
aws sns list-topics --profile XXX | jq -r '.Topics[].TopicArn'
```

出力結果

```
arn:aws:sns:ap-northeast-1:${AccountId}:${トピック名1}
arn:aws:sns:ap-northeast-1:${AccountId}:${トピック名2}
//　以下省略
```

この時点でTopicArnのみを抽出することが出来たので、最後にcutコマンドを用いて${トピック名}のみを取得する。
### cut -f 6 -d ":"
-dオプションで区切り文字に「:」を指定し、-fオプションで6つ目のフィールドのみを抽出する。

```
# SNSトピックを取得し、jqコマンドでTopicArnのみを抽出し、cutコマンドでトピック名のみを取得
aws sns list-topics --profile XXX | jq -r '.Topics[].TopicArn' | cut -f 6 -d ":"
```

出力結果

```
${トピック名1}
${トピック名2}
//　以下省略
```

# おわりに
SQSキューの取得に関してもやってることはほぼ同じなのでコマンド解説は省略します。これくらいのワンライナーのシェルは何も見ないでスラスラ書けるようになりたいものです。