OmniAICreator/Qiita-1.07M huggingface dataset:
初歩の初歩から学び直し-記憶域と変数について-

#なぜ学び直したか
専門学校に入り3年目、プログラムについて学んできたけれど知らないことがまだ多かった......
まずはキーワード (static, const) とかについて勉強をし直していたところ
**staticとは、静的記憶クラスを使用し、静的に存在する領域にデータを保持することができる。**
こう書いてありました。

はい、静的領域について詳しく知りませんでした。
効果は知っているけれど、初歩のここで躓いてしまったので最初のところから学び直そうとしたわけです。
それでは記憶域と変数についての説明をしていきましょう
##記憶領域
**記憶領域**とは……プログラムやデータを格納する場所のこと(メモリ領域とも言う)
記憶領域にはいくつかの領域が存在します。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1580138/108ad85f-d755-f688-2617-b2dec77d8d15.png)

**「テキスト領域」**
**「静的領域」**
**「ヒープ領域」**
**「スタック領域」**


各領域の呼称や、メモリの使われ方は処理系により異なるようですが、大まかな点は同じらしいです。
**コード領域**は**「コードテキスト領域」****「プログラム領域」**と読んだり
**静的領域**と**ヒープ領域**を合わせて**「データ領域」**と呼んだりもします

###各領域の説明
**「テキスト領域」**
機械語に変換されたプログラムが格納される場所。

C言語、C++、Javaなどは**高水準言語**と呼ばれており、この機械語を人間に分かりやすくした形になります。
逆に**低水準言語**と呼ばれるものにはアセンブリ言語と呼ばれるものがあり、こちらは機械語に対して１対１と機械語に近い言語です。 

**「静的領域」**
**外部変数(グローバル変数)**や**静的変数(static変数)**などを格納する場所。
この二つの変数の特徴は、プログラム開始処理の前に**1度だけ初期化**を行う点。
1度しか初期化をしないため、後の処理で値が変わることはありません。

ほかの特徴は、実行中は常に同じ場所に値が配置される点。
アドレスなどが変更されないということですね。

**「ヒープ領域」**
new演算子やmalloc関数のように、プログラマー側がメモリを確保する時に格納される領域
こちらの領域は格納時には若いアドレスから情報を持つようになっています。
(若いアドレスとは、0x0000のような小さい数値のほうです)

**「スタック領域」**
自動変数(intやfloat)や、引数・戻り値など一時的に保存する変数などが格納される領域
スタック領域はヒープ領域とは逆な点が多いです。

保存される場合、アドレスは大きい値から格納されていきます(0xFFFFのように)


それでは次は変数について一部を説明していきましょう。

###変数とスコープ
変数には**自動変数**,**外部変数**,**静的変数**があります。
それぞれのスコープの違いについて話していきます。

まずは下の画像を見てください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1580138/5ebcbda9-759c-f0a5-9e01-9601fc709cc4.png)
こちらには**システム**,**ファイル**,**関数**の3つのスコープがあります。

自動変数と呼ばれるものは、関数スコープ
外部変数(グローバル変数)はシステムスコープ
静的変数(スタティック変数)はファイルスコープに分けられます。

・それぞれの挙動は、自動変数は{ブロック}に囲まれた範囲でしか値を保持できません。
・グローバル変数は、ファイルの範囲内で使用でき、別のファイルではextrunを使用すると、他ファイルで定義したグローバル変数を使用することができます。
・スタティック変数は、宣言した場所にスコープを限定することができます。
関数で宣言したならば関数内までにしかスコープが設定されません。


私が調べたことはここまでです。
参考資料として私が勉強したものを
C言語 extern宣言とグローバル変数
https://monozukuri-c.com/langc-funclist-extern/
記憶クラスとスコープについての資料
http://www9.plala.or.jp/sgwr-t/c/sec12.html
http://www.ibe.kagoshima-u.ac.jp/edu/gengo0/p11.html
ヒープ領域とスタック領域の違いの解説
https://proglife.net/heap-stack/
画像を全部Lennaにして異常検知を行った話

初投稿です。

今年の2月頃に画像に対する異常検知の手法を発表しました。
その手法の宣伝のために記事を書いています。



もしこの記事を参考にする場合は論文を引用してください。よろしくお願いいたします


<h1>背景</h1>
教師あり学習には学習データにあるものしか予測できないという弱点があります。例えば学習データにリンゴしかない場合、モデルはあらゆるものをリンゴと予測してしまいます。この問題を解決するために、学習データにある既知のデータ(リンゴ)と、それ以外の未知のデータ(リンゴ以外)を分類する必要があります。

<h1>関連研究</h1>
この問題はOne-class classificationと呼ばれており、通常の機械学習からDeep Learningまで幅広くアルゴリズムが提案されています。画像の場合、畳み込みによって特徴抽出ができるためDeep Learningが有効とされています。その中でも既知と未知のデータに共通のタスクを与えるSelf-Supervisionという考え方が流行しています。これは既知のデータを学習したモデルの誤差によって既知と未知を分類する考え方です。未知のデータは学習には利用されないため、既知のデータに比べてエラーが大きくなると仮定されています。つまり、エラーが小さければ既知、大きければ未知と考えることができます。

<b>タスク例:Auto-encoder</b>
モデルとしてAuto-encoderを使った手法です。Auto-encoderは入力と出力を同じにしようとするネットワークです。入力と出力の比較によってモデルのエラーを求めます。
![PictureAE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590427/d4c32620-eef0-8c23-ad2a-68b4c0159976.png)
この手法は高速ですが精度が悪いという弱点があります。モデルが入力に応じて多様な出力を学習するため、既知と未知でエラーの差が出ないと考えられます。


<b>タスク例:Classification</b>
学習データ中の画像に対して何らかの形で追加の画像を生成し、生成方法をラベルとして与えます。
図の場合はリンゴを回転させて、回転した角度をラベルとして与えています。
できあがったモデルはリンゴの回転を予測できますが、バナナの回転を予測できません。
![Classification.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590427/6b36e155-d662-fa83-810e-681157b3da81.png)

この考え方を使った論文として、「Deep Anomaly Detection Using Geometric Transformations」が有名です。
その論文では、各画像に対して72個の画像を生成して分類し、高精度な予測を行っています。
しかし、1つのテスト画像に対して72個の画像を追加で生成する必要があるため、処理が遅いです。

<h1>提案手法</h1>
高速で高精度な手法を考えた結果、辿り着いたのがすべての画像を同じ画像に変換することです。
Auto-encoderから出力の多様性を排除するという考え方によって高精度を実現しました。
また、テストデータにモデルを適用してエラーを求めるだけなので、高速な処理が可能です。
変換後の画像をGoal imageと呼び、何か適当な画像を与えます。図の場合はLennaを使っています。
まず学習データ(リンゴ)をLennaにする方法を学習します。できあがったモデルは<b>あらゆる画像をLennaにしようとします</b>。
学習データにあるのはリンゴだけなので、リンゴ→Lennaの変換はうまくいきますが、バナナ→Lennaはうまくいきません。
つまり、うまくLennaになれば既知(リンゴ)、Lennaにならなければ未知(リンゴ以外)と考えることができます。

![Picture12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590427/0eef8ffc-5fc6-5b16-ed67-cac762079093.png)

<h1>実験</h1>
図は実験に使用したGoal imageです。画像のEntropyを基に選択しました

![PictureGoal-images.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590427/bdcda832-a4fa-b041-cb60-874e759e254b.png)
実験の結果Goal imageによって、精度が大きく変化することがわかりました。
たとえば、Lennaを使ったときにMNISTのAUCが97.3、白い画像だとAUCが62.4といった感じです。
また、Lennaに変換したとき、MNISTとFashion MNISTでSOTAを達成し、CIFAR10に対しても3番目に良い結果でした。上位2つの手法に速度や実用性の面で問題があるためOCITNは有力な選択肢と考えられます。他の画像を使うとどうなるんだろう？というのが今後の課題です。

<h1>まとめ</h1>
画像を全部Lennaにして異常検知を行った話でした。
詳しくは以下の論文に書いてあります。よろしくお願いします。

Toshitaka Hayashi, Hamido Fujita, Andres Hernandez-Matamoros, Less complexity one-class classification approach using construction error of convolutional image transformation network, Information Sciences, Volume 560, 2021, Pages 217-234, https://doi.org/10.1016/j.ins.2021.01.069
Flutter on the Webでタイトル属性を設定

この記事は、[「Flutter Advent Calendar 2021」](https://qiita.com/advent-calendar/2021/flutter)に投稿した「Flutter on the WebをFirebase Hostingで公開した」の一部となります。

# タイトルの設定

Flutter on the Webで、HTMLの`<title>`属性を設定するだけであれば、`web/index.html`の`<title></title>`を直接設定すればよいだけです。
アプリ内で統一されているならこれで終わりです。

# タイトルの動的変更

Titleウィジットで設定することができます。

https://api.flutter.dev/flutter/widgets/Title-class.html

```dart:main.dart
Widget build(BuildContext context) {
    final mytitle = '$house | $subTitle';
    return Title(
        color: Colors.white,
        title: mytitle,
        child: Scaffold(
                appBar: AdaptiveAppBar(pagepath: pagepath, title: mytitle),
                drawer: Drawer(
                    child: HorsesWidget()),
                body: Column(children: [
                  Expanded(flex: 1, child: body),
                  SizedBox(height: adHeight)
                ])));
}
```

![Qiita](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4668/512a1709-c4ac-b352-006b-edda57005378.png "Qiita")

以上です。
お金の歴史を学び直しました

#はじめに
こんにちは。オブジェクティブコードの東端です。

今回は**「お金の歴史を学び直しました」**ということで、最近歴史を学ぶことに夢中になっている私ですが、改めて「お金」の歴史を学んでとても面白かったので、その面白かった部分を搔い摘んでシェアさせて頂きます。

普段お財布に入っている

1000円札、5000円札、1万円札

これらがなぜそれぞれ、その価値があるのか。

これって皆さん考えたことあります？
たまに疑問に思ったりしませんか？
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2100940/9acdad14-cdc1-6692-d106-2277cacd9972.png" width=60%>
実際に調べると出てくるんですが1万円札1枚当たりの原価は22円程度だそうです。

どうして1枚22円で製造されるこの紙っぺら1枚で、1万円分の取引ができるのか。

あまり考えたりしないですよね。

当たり前になり過ぎていて考えない事だと思います。自分自身もそんな当たり前なこと考えてこなかったです。

ですが改めて、どうして今の様式が確立されているのか、歴史を紐解いて学び直してみました。

学び直した結果、めちゃくちゃ面白かったですよ。学んだことをアウトプットする事は凄く大切です。


自身の知識定着の為にも、この場を借りて現在に至るまでの経緯を本当にざっくりと説明させてください。

#貴金属から紙幣へ変遷したのはなぜ？？
昔は、実際に価値のある金や銀などの貴金属の重さを測って取引をしていたそうなんです。

この金や銀は当時も価値のあるものであるとどの国も認めていました。なので他の国との取引や外交にも使用できるツールだったようです。

しかしそれでは他国に金銀などの財産が流出してしまいます。

**勝手に海外との取引が発生してしまう事を危機を覚えた時の国家権力者**が、海外との勝手な取引を抑制する為に他の国では使う事の出来ないツールが必要になりました。

それで、コインが生まれたり…

なんやかんやあって、その末に、紙幣が生まれたとされています。

この紙幣やコインなどがなぜ今この瞬間も含めてそのもの自体の価値以上、原価以上の取引に使えるかがとても重要ですよね。

これがなぜ行えるか、それは・・・

中央集権型の強大な権力が**「価値を証明」「価値を担保」**してくれているからという結論に至ります。

今の日本で使用されている1万円札の原価はおよそ22円程度です。

しかしその物(原価22円で発行された1万円札)を

**「1万円相当の価値がありますよ」**

って事を国が保証しているから1万円札1枚の価値は1万円なのです。

だいぶ端折って説明していますが、何となくお判りいただけましたかね？


#価値のコントロールって超大切

**スパークリングワイン**と**シャンパン**の違いって皆さん、ご存じですか？

価格的にはシャンパンに比較してスパークリングワインは安価で楽しむことができます。

内容物の違いという意味では素人には殆ど判別不可能なスパークリングワインとシャンパンですが、この2つ何が違うのか。

**シャンパン**
＝フランスのシャンパーニュ地方で作られたお酒であり、フランスのワインに関する法律に規定された条件を満たしたもの

**スパークリングワイン**
＝それ以外の発泡性ワイン

これも先程の原価22円の1万円札の価値を1万円と定義している国家権力と価値のコントロールと同様の構造です。

他にも身の回りにある価値がコントロール、もしくは定義されているモノを発見するのも面白いかも知れませんね。


#価値のコントロールを理解できなかったスペインの悲劇

ちなみに16世紀に当時のスペインである出来事が起きました。

「価値のある銀をたくさん国に持ち込めば国が豊かになる！」

って考えた当時のスペインの皆さんは、

およそ**15,000トン**という桁違いの銀を新大陸から持ち込んだそうです。

しかしこれによって何が起きたか・・・

皆さん、想像できますか？？

国内に大量の銀が流入したために

銀の価値が相対的に**ガクンと下がってしまって・・・**

**超超超インフレ**に陥ってしまったのです…！！！！

（お寿司も、たまに食べるから有難みがあって特別な食べ物として認識できます。）


#おわりに
今日現在の日本の経済市場もそうですが、価値のコントロールが適切に行われているっていうのはとても大変で、大切なことなんだなぁという事を歴史を通して学ぶことができました。

日常当たり前に感じているモノやコトに関するルーツを学ぶ事って凄く興味深いですし、とても面白かったです

皆さんも是非一緒に歴を学んでみませんか？

という事でオブジェクティブグループではstandFMによる音声配信も行っており、会社に関係ある話やない話まで様々配信しています。
https://stand.fm/episodes/611ed920f4ef5e0007208add
良かったらこちらも聴いてみて下さいね～

（私、イケボと評判なんです ）♪

最後までお読みいただきありがとうございました。
アロー関数の（）や｛｝について

アロー関数の書き方で（）省略したりすることができる。
しかし、条件が複数あって頭が混乱してきたので、自分のメモとしてまとめておく。

```
アロー関数
const func1 = (val) => {return val}
```
■ 引数が１つの場合()を省略できる
■ ｛｝の中の処理が単一行であれば、｛｝とreturnが省略出来る

● {}を書いたら return がいる






```
アロー関数
const func1 = (val, val2) => (
{
 name: val1,
 email: val2
}
)

実行
console.log(func1(hoge, moge))

///出力
{name: hoge , email: moge}
```

返却値が複数行になる場合は（）を用いることで単一行として扱える
AtCoder Beginner Contest 007をやった(Java)

AtCoder Beginner Contest 007をやった。
C問題は幅優先探索なのであとから追記予定です。。。
BFSとかなんか競プロって感じやな・・・


##[A](https://atcoder.jp/contests/abc007/tasks/abc007_1)
法則を見つけてあげてください。
ソース見たらわかるか。。。

```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Scanner scan = new Scanner(System.in);
        ArrayList<String> list = new ArrayList<String>();
        
        int num = scan.nextInt();
        if(num == 0){
            System.out.println(num);
        } else {
            System.out.println(num-1);
        }
    }
}
```

##[B](https://atcoder.jp/contests/abc007/tasks/abc007_2)
入力文字に応じて、出力文字を選定していると面倒なので、"a"か"-1"の出力に絞った。

```Java
import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Scanner scan = new Scanner(System.in);
        
        boolean flg = true;
        String str = scan.nextLine();

        if(str.length() == 1 && str.split("")[0].equals("a")){
            flg = true;    
        } else {
            flg = false;
        }

        if(flg == true){
            System.out.println(-1);
        } else {
            System.out.println("a");
        }
    }
}
```

いつかC問題もJavaで解きたいな(n回目)。
Nginx default.confの設定反映方法

# 目的

- Nginxのdefault.confの設定を反映するコマンドをメモ的に記載する。

# 方法

- 下記コマンドを実行してリロードする。

    ```terminal
    $ sudo service nginx reload
    ```

- もしくは下記コマンドを実行してNginxそのものを再起動する。

    ```terminal
    $ sudo service nginx restart
    ```
【え、簡単すぎ...!?】pythonで簡単にスクレイピング をしてみたメモ

#環境構築

https://qiita.com/yutoun/items/788fac08bf73f173d447

いつも通りこれで環境構築完了する。

#requests
htmlを取得する目的

```
pip install requests
```
でrequests使えるようにする

```python
import requests
url="https://qiita.com/1000ch/items/93841f76ea52551b6a97"
r = requests.get(url)
```
こんな感じでrequest.getの引数に取得するurlをいれる

#BeautifulSoup
requestsで取得したhtmlを加工して扱えるようにする目的

###一つ目の要素を取得する

```python
import requests 
from bs4 import BeautifulSoup　#追加
url="https://qiita.com/1000ch/items/93841f76ea52551b6a97"
r = requests.get(url)
#print(r.text)
soup = BeautifulSoup(r.text, "html.parser")　#追加 
result = soup.find("h2").text　#追加
print(result)
```
6行目の"html.parser"を抜くと

```python
scraping.py:6: GuessedAtParserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("html.parser"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.
```
て言われます。簡単に言うと
「htmlパーサを選択してないから私が一番合ってそうな"html.parser"にしておいたよ。私だからいいけど他の環境だったら違うの選んでおかしいことになるかもだょ.....」
なので念のため"html.parser"はいれておく

r.text→html取得
soup.h2.text→h2だけだとタグとかも含まれるのでtextにする。allないから最初だけ

###任意の要素の取得
find_all('h2').text→✖︎
見てみるとリストなので

```python
result = soup.find_all("h2")[0]
```
このように.textだった部分にインデックス番号を表記することで任意の要素が取得できる

これではタグも含まれているため.textを書きたいがエラーになるから

```python
for i, h2_tag in enumerate(soup.find_all('h2')): 
    print(i,h2_tag.text)
```
これで任意の要素のテキストのみを出力できる

###クラスを指定して要素を取得する

class_でクラスを指定することでそのクラス(fragment)の要素のみ取得できる

```python
result = soup.find_all("span", class_="fragment")
print(result)
```

###記事本文からのみ取得する

```python
body = soup.find["必要な範囲のタグ"] 
body.find_all(["h2","h3"])
```
のようにfindを二回使うことで限られた範囲内から検索することができる

#困ったエラー

```
AttributeError: 'NoneType' object has no attribute 'find_all'
```

https://teratail.com/questions/168481
curlとAdvanced REST clientでAPIの動作確認する

# 目的
APIを開発して動作確認したいです。エンジニアだけならcurlを使えば問題無いですが、エンジニア以外の方に確認してもらうのにはGUIが無いとつらいのでAdvanced REST client(ARC)を使います。

# 使い方
## curl
curlは良く使う簡単な例だけあげておきます。

### GET

```
curl "http://api.example.com/users"
```
### ヘッダー付きGET

```
curl -H "aaa=bbb" "http://api.example.com/users"
```

### POST

```
curl -X POST -d "aaa=bbb" "http://api.example.com/users"
```

### POST(JSONファイル)

```
curl -X POST -H "Content-Type: application/json" -d @data.json "http://api.example.com/users"
```

### おまけ(ファイルダウンロード)
```
curl -OL "http://api.example.com/users.zip"
```

## ARC
Google Chromeの拡張機能(アプリ)です。インストール先は[こちら](https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo/details?hl=ja-JP)です。

![スクリーンショット 2021-12-20 095146.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148247/d11eaaf8-1fcd-fe98-1f5e-9239808fb68e.png)


## おまけ
[https://httpbin.org](https://httpbin.org)は様々なAPIが用意されていてクライアントの確認やテストなどに便利です。
5分でVPN接続完了なZeroTier

![ZeroTier-768x427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484973/bd4431b0-6d9c-35eb-5523-d3a9258c5bcb.png)
VPN(Virtual Private Network)は非常に便利ですね．仮想的にプライベートネットワークを構築することで，例えば自宅ネットワークに繋がっているパソコンと学内ネットワークに繋がっているパソコンがあたかも同じネットワークに接続されているかのように扱うことができます．


ですが，VPNの構築には知識が必要な上に，作業も非常に面倒です．とりあえず何も気にせず今すぐにVPN接続がしたいという人におすすめできるのがZeroTierというOSSです．

ZeroTierを使えば長く見積もっても5分でVPN接続ができてしまいます．Windows･Mac･Linux･iOS･Android･Rasbianなどあらゆる端末をあっという間に暗号化された状態で接続できるのです．

では肝心の使い方ですが，たったの4ステップです．


#### 【ステップ1】<a href="https://my.zerotier.com/" target="_blank" rel="noreferrer noopener">ZeroTier</a>のアカウントを作成
リンクに飛んで，[Log In to ZeroTier]→[Register]

#### 【ステップ2】<a rel="noreferrer noopener" href="https://my.zerotier.com/" target="_blank">Network</a>を作成

リンクに飛んで，[+Create a Network]

#### 【ステップ3】接続したい端末にZeroTierを<a href="https://www.zerotier.com/download/" target="_blank" rel="noreferrer noopener">ダウンロード</a>

LinuxやDebianにダウンロードする方法を以下に記載しています．それ以外のOSをお使いの方はリンクに飛んで確認して下さい．

```
# 標準のLinuxならこれだけ実行すれば大丈夫
$ curl -s 'https://raw.githubusercontent.com/zerotier/ZeroTierOne/master/doc/contact%40zerotier.com.gpg' | gpg --import && \
if z=$(curl -s 'https://install.zerotier.com/' | gpg); then echo "$z" | sudo bash; fi

# GPG(Gnu Private Guard)が入ってない場合はこっち
$ curl -s https://install.zerotier.com | sudo bash
```

#### 【ステップ4】Networkに接続

```
# zerotierを起動させます
$ sudo systemctl enable zerotier-one

# zerotierの状態を確認します(200番が返ってくるはず)
$ sudo zerotier-cli status

# いよいよネットワークに接続します
$ sudo zerotier-cli join [network_id]
```

---

2024/07/06 追記

Tailscale も無料で 100台まで接続できて便利らしいです

https://tailscale.com/solutions/devo
より簡単に，より美しくボード線図を描く方法

![block-diagram-890x500.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/484973/20552ff7-ebea-e886-e8c7-885c9fe345d6.png)
人生のあらゆる場面においてボード線図を描く必要がでてきます．もちろんボード線図を描く方法はいっぱいあります．例えばパワポ芸が1つの方法です．しかし，あらゆる方法の中でdraw.ioというツールを使うことが最適です．(最適というのは何らかの評価関数を最大化もしくは最小...)
上の図はそこそこ割と結構キレイで美しいブロック線図ですが，これが5分程度で描けてしまいます．ブロック内にtex形式で数式を簡単に書けるのも魅力的です．
Selenium Python　IDもnameもない場合

IDもnameもわからない場合はxpathを使います。
日記がてら実際の写真も交えてメモします。キャプチャみただけで懐かしくなります。

一番よく使うのが
##タグ名+クラス名
###例：divタグのクラス名がp-booking-calendar__calendar-navi

もちろん divタグでクラス名がp-booking-calendar__calendar-naviの要素が一つしかないものとします。

```python
driver.find_element_by_xpath("//div[@class='p-booking-calendar__calendar-navi']")
```


実際の画面はこちら
カレンダーの次へボタンを押したかったのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/d14758fd-2814-24b5-328b-eaf95caebfd5.png)

実際のソースはこち
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/49b6585b-e9e6-c4de-17ce-66c83b69a785.png)


## 特定の文字列の次にある要素
### containsとfollowing-siblingを使う
###例：h4文字列の次にあるテーブル。そのテーブルのtdタグの値をすべてほしい
〇番目のtdタグかわかるようにforでループしています。
h4の文字列は特徴・関連情報

```python
#まずh4で文字列が特徴・関連情報
#その次にある（兄弟要素)tableを取得
tabletag = driver.find_element_by_xpath("//h4[contains(text(),'特徴・関連情報')]/following-sibling::table[1]")

#tabletagの中からtdタグを全部取得
tdtags = tabletag.find_elements_by_tag_name("td")
#tdタグの中身を全部出力してみる
for i in range(0,len(tdtags)):
    print(tdtags[i].text)

```




・実際の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/e070d811-d77b-cf44-e900-df0919a40e71.png)




・実際のソース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/f25029ab-e35f-c334-f5f1-519ddf791dd9.png)


##th見出しの次にあるtdの文字列
### containsとfollowing-sibling
例：tdタグにあるオープン日だけを取得したい

```python
hpurl = tabletag.find_element_by_xpath("//th[contains(text(),'オープン日')]/following-sibling::td[1]").text

```

・実際の画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/edc46a36-9a36-b2f8-bbb4-3c3a0c8439a6.png)


・実際のソース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/325cf4a5-81a5-6abc-5d78-cc2f6dbd879c.png)

##複数のtableに同じthタグが複数ある(thタグの文字列だけで取得できない)
###Xpathの//と/を使い分ける
例：これが一番困る。上の例だと thタグのオープン日が複数のテーブルにある場合
この場合まずテーブルを指定して、そのテーブルからthタグにあるオープン日をみつける
具体的には
・特徴・関連情報を含むh4タグを見つける
・その次にあるテーブルを見つける
・テーブルの中から文字列が「オープン日」を含むthタグを見つける
・その次にあるtdタグを指定する

<font color="red">※ポイント
・table[1]の次は//です。table→tbody→trの記述を省略するため</font>



```python

aaa = driver.find_element_by_xpath("//h4[contains(text(),'特徴・関連情報')]/following-sibling::table[1]//th[contains(text(),'コース')]/following-sibling::td[1]")
print(aaa.text)


```

・実際の画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/edc46a36-9a36-b2f8-bbb4-3c3a0c8439a6.png)


・実際のソース
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369082/325cf4a5-81a5-6abc-5d78-cc2f6dbd879c.png)



##その他順次追記予定
ブラウザの拡張機能からxpathを取得すればその時は速攻ですが、
数日後に「動きません」と悲しい結果になるので。
なるべく自分でxpathを作成するように勉強中です。
iframe loding="lazy"で画像がうまく読み込まれない時

<p>wordpressでiframe lazy-loadingが使えるようになりましたね。でも動画によってはlazy-loadingが効かなくて、「youtube.comから接続を拒否されました」が出てしまう。その問題点を探った感じです。結果としてpluginを入れることになりましたが、満足いく結果が得られてホッとしています。

<h2>Nativeにiframe lazy-loadingする方法
<p>最初に考えたのはwordpress5.5から公式に対応したそのままlazy-loadingする方法。これができれば苦労しないのだね。

```
<iframe src="nasnigasi.you.tubebe"></iframe>
```
<p>これでは上手くいかないね。wordpressではlazy-loadingを使うにはwidthとheightを指定する必要がある。初期設定のwordpressはブラウザ？なのか、最初からwidthとheightが決まっていたような気もするが、これはしっかりと決めよう。

```
<iframe src="nasnigashi.you.tubebe" width="600" height="450"></iframe>
```
<p>これで動けば万歳だ。自分も一応、このコードで動くことは確認したのだが、一部の(自分の場合は50個中/45個)動画が「youtube.comから接続拒否されました」と出る。nanigashiの動画を直接埋め込みURLだけ貼り付ける方法なら上手く動くが、ページの負担は半端ない。

<h2>pluginを使う
<p>自分では有効な手立てが見つけられなかったので、仕方ないのでpluginを入れることにした。2021/12現在でそこそこ更新履歴のあるlazy-loadingのpluginを探したところ、「a3 Lazy Load」が良さそうだなと思った。単純に高評価が多いだけだけど。
<p>普通に素の設定で動画のlazy-loadingがONの設定になっているので使ってみると、全ての動画がうまいこと遅延読み込みされたので、文句は無くなった。加えて、iframeを全てのページにこれから埋め込むと言った愚行を行わずに済んだのは素晴らしい。

<h2>まとめ
<p>wordpressは手を抜くためにあるので、とことんpluginに頼りたくなる師走だった。
HACCPが制度化されたので、温度を定期的に取得して記録するデバイスを作成

詳細は後ほど追記します。

#HACCP制度化
食品事業者は温度記録しないと法律違反になります。

#温度ロガーに金払うのがちょっと・・・
自作します。
多少慣れていないところがあったので２時間ちょっとかかりました。

https://zenn.dev/shuyin02/scraps/491f348774f38c

リンクでごめんなさい。
単三電池1本で１年持つらしいので、結構経済的
冒頭にも書きましたが、後で詳細は書き直します。
SalesforceテストデータのTypeID書き換えを自動化した

## はじめに
本記事はSalesforceを利用したアプリ開発をしている方向けです。
パッケージ開発組織へ任意の初期データを投入するスクリプトを作成したので、その内容について解説します。
以下のコマンド、ツールが利用できることを前提としています。
- sfdx-cli(v7.120.0) 
- awkコマンド
- sedコマンド
- trコマンド
※MacOSのターミナル上で実行しています。一部コマンドのオプション等は他環境と異なる可能性があります。

## 解決したい課題
Salesforceでは`sfdx:data:tree:import`を利用したデータのインポートが可能です。しかし、一部項目はアプリ上で自動採番されるため、テストデータ(json)を投入する際に該当箇所を手動で書き換えていました。めんどうですね。
以下のフローを自動化することが本記事の目的となります。
1. 自動採番されるデータをアプリから取得する
2. テストデータ用jsonの該当箇所を書き換える

## 解決方法
### 最終的なスクリプト
※npmで利用していたためpackage.jsonからの転記になります。

```package.json
"scripts" {
  "setRecordType": "s=$(sfdx force:data:soql:query -q \"SELECT DeveloperName, Id, Name FROM RecordType WHERE sObjectType='[オブジェクト名]'\" 2>/dev/null | grep -E 'RecordType1|RecordType2' | awk '{print \"s/___\"$1\"___/\"$2\"/\"}' | tr '\\n' ';'); sed -i -e $s test-data/test-data.json;"
}
```

### コマンドごとに分解した解説
１コマンドずつ値がどのようになっているかを追っていきます。

```
sfdx force:data:soql:query -q \"SELECT DeveloperName, Id, Name FROM RecordType WHERE sObjectType='[オブジェクト名]'\" 2>/dev/null
```
アプリ側にクエリを投げてレコードタイプを取得します。

***実行後***

```
DEVELOPERNAME  ID                  NAME
─────────────  ─────────────────   ────
RecordType1    0121m000000xxxxxxx  事業会社
RecordType2    0121m000000xxxxxxx  支払先
```
---

```
grep -E 'RecordType1|RecordType2'
```
grepコマンドで対象行のみ抽出します

***実行後***

```
RecordType1    0121m000000xxxxxxx  事業会社
RecordType2    0121m000000xxxxxxx  支払先
```
---

```
awk '{print \"s/___\"$1\"___/\"$2\"/\"}'
```
awkコマンドを用いてスペースごとにテキストを分割します。
分割したテキストは先頭から\$1、\$2…という風に番号が振られ、printアクションでそれらを利用してテキストを再構築できます。

***実行後***

```
s/___RecordType1___/0121m000000xxxxxxx/
s/___RecordType2___/0121m000001xxxxxxx/
```
---

```
tr '\\n' ';'
```
trコマンドで改行コードを;に置き換えます

***実行後***

```sample
s/___RecordType1___/0121m000000xxxxxxx/;s/___RecordType2___/0121m000001xxxxxxx/;
```
---

```
sed -i -e $s test-data/test-data.json
```
sedコマンドを利用してファイル内の文字列を置き換えます。
`s/abc/ABC`はabcをABCに置き換えるという意味になります。
test-data.json内で変更する箇所に"\_\_\_RecordType1___"という文字を仕込んでおくことで取得した値に置き換えてくれます。

```json:test-data.json(実行前)
    "records": [
        {
            "Name": "株式会社ダイアログ",
            "RecordTypeId": "___RecordType1___",
        }
    ]
```

```json:test-data.json(実行後)
    "records": [
        {
            "Name": "株式会社ダイアログ",
            "RecordTypeId": "0121m000000xxxxxxx",
        }
    ]
```

## 最後に
awkやsed、trなど普段使わないコマンドを利用したため勉強になりました。
面倒な作業はどんどん自動化できるようにしていきたいですね。

---
### 株式会社ダイアログについて
『物流業界をテクノロジーの力でHAPPYに』
弊社は「物流xITx経営」をキーワードに、W3、Tariffeeといった自社サービスを中心に、他サービス連携やデータプラットフォーム化を通してよりHAPPYな物流を目指して活動しています。
ただいま一緒に働くエンジニアを募集中です。
物流、ロジテック、サービス連携、データプラットフォーム等に興味のある方、カジュアル面談で一度お話しませんか。
詳しい採用情報は[Wantedly](https://www.dialog-inc.com/top/recruit_top/) にて。
BigQueryでGIS関数を使う時は下準備が大事

## はじめに
LBMA Japan Advent Calendar 2021 の記事です。

こんにちは、unerryでプロダクトマネージャをしている鶴見です。

2021年は、モビリティ、スマートシティ、ポイ活など、位置情報マーケティング・サービスの領域が飛躍的に拡大しました。
領域の拡大に伴って位置情報データのボリュームも飛躍的に増加し、データが増えたことによってまた新しい領域が拡がるという、非常に良い循環が業界全体に生まれた素晴らしい1年だったと思います。

一方、データが増えたことにより集計や分析の処理に時間がかかるようになってしまったため、常に時間と戦い続けた年でもありました。
今日はそんな時間との戦いの中で生まれたBigQueryで位置情報データを集計する際の効率化に関するちょっとしたTIPSをご紹介いたします。

## 一般的なGIS関数の使い方

### ケース

日本全国のPOI情報が入っているマスタがあり、各POIの中心点から任意の半径を指定し、周囲の位置情報ログを一括で抽出するケースを想定します。
マスタは下記のようなイメージになります。radiusはデータを取得したい半径（メートル）です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2383746/f3674c1d-4df3-b841-4c1a-d7cd48ad6ba2.png)

### シンプルにクエリを書いてみる

中心点＋半径でデータを抽出する場合は、GIS関数のST_DWITHINを使います。
user_id、time_stamp、latitude、longitudeのある位置情報のログテーブルがあると想定し、シンプルにクエリを書いてみると以下のような感じになります。
※addressは不要なのでSELECTから落としました。

```sql
WITH
mst AS (
  SELECT
    place_name,
    place_latitude,
    place_longitude,
    radius
  FROM
    poi_mst),
log AS (
  SELECT
    user_id,
    time_stamp,
    latitude,
    longitude
  FROM
    log_table)
 
  SELECT DISTINCT
    user_id,
    time_stamp
    latitude,
    longitude,
    place_name
  FROM
    mst JOIN log
  ON
    ST_DWITHIN(ST_GEOGPOINT(place_longitude, place_latitude),ST_GEOGPOINT(longitude, latitude),radius)
```


### 結果

サンプルで作成した5万のPOI数、2,000万レコードのログを対象に実行してみたところ、30分経過してもクエリが完了しなかったので敢え無く断念。
これだと日が暮れてしまうので次はちょっとした工夫をしてみます。


## 緯度経度に対し数値処理を入れてみる

### アプローチ方法

先ほどのクエリだと、5万のPOIそれぞれに対して2,000万レコードのログが半径の中におさまっているかどうかを判定してしまっているせいで処理に時間がかかったようです。
この問題を解決するために緯度経度を数値処理してGIS関数で判定するログを絞り込んでみます。

### アレンジしたクエリを書いてみる

各POI中心点の緯度経度から、取得したい半径の分だけそれぞれプラスマイナスをした緯度経度の数値をカラムに追加します。
lat_min,lat_max,lon_min,lon_maxが該当のカラムで、「30.8184 * 0.000277778」と「25.2450 * 0.000277778」はそれぞれメートルを緯度経度に変換するときの係数です。
イメージとしては、円に外接する正方形の各頂点の緯度経度を取得する感じですね（実際は10メートルほどバッファを持たせているので外接はしていません）。

JOINする際に緯度経度をlat_min,lat_max,lon_min,lon_maxで数値として絞り込む処理をした後にGIS関数を使って円の形でログを抽出します。

```sql
WITH
mst AS (
  SELECT
    place_name,
    place_latitude,
    place_longitude,
    radius,
    place_latitude  - ((radius + 10) / 30.8184 * 0.000277778) AS lat_min,
    place_latitude  + ((radius + 10) / 30.8184 * 0.000277778) AS lat_max,
    place_longitude - ((radius + 10) / 25.2450 * 0.000277778) AS lon_min,
    place_longitude + ((radius + 10) / 25.2450 * 0.000277778) AS lon_max,
  FROM
    poi_mst),
log AS (
  SELECT
    user_id,
    time_stamp,
    latitude,
    longitude
  FROM
    log_table)
    
  SELECT DISTINCT
    user_id,
    time_stamp
    latitude,
    longitude,
    place_name
  FROM
    mst JOIN log ON latitude BETWEEN lat_min AND lat_max AND longitude BETWEEN lon_min AND lon_max
  WHERE
    ST_DWITHIN(ST_GEOGPOINT(place_longitude, place_latitude),ST_GEOGPOINT(longitude, latitude),radius)
```

### 結果

5分ほどで集計結果が出力されました。これぐらいの時間でクエリが回ってくれればサクサクと分析が進められそうです！

## 最後に

今回は、緯度経度を数値処理してGIS関数の集計を効率化するやり方をご紹介しました。
この記事では中心点＋半径でデータを取得する方法で書きましたが、ポリゴンによる取得においてもポリゴンデータの各頂点の緯度経度の最小値、最大値を取得することで同様の処理が可能です。

また、数値処理以外にもgeohashを使ったりすることによってスキャン量を抑えたり処理を高速化したりすることもできます。GIS関数は奥が深いですね。
左上・左下で原点の違う UV 座標系を変換する（座標・Scale・Offset）

# はじめに
3DCG ソフトウェアにおいて、UV 座標系は統一性が無い。
多くの環境は原点が左上か左下に位置しており、バラバラである。
したがってソフトウェア間で 3DCG データを移動するには、UV 座標の変換が必要になることがある。

ここでは UV 座標そのもの、そしてそれに関連するパラメタ Scale と Offset の変換方法について述べる。

# 結論
- 左上原点と左下原点の UV 座標系の間で変換する場合
  - U 座標は無変換で良い
  - V 座標は $1 - v$ で求まる
  - Scale パラメタは無変換で良い
  - U 軸に関する Offset パラメタは無変換で良い
  - V 軸に関する Offset パラメタは $1 - \mbox{scale}_v - \mbox{offset}_v $ で求まる

# UV 座標の変換
左上原点の UV 座標系の UV 座標を $(U_{t}, V_{t})$ としたときに
それに対応する左下原点の UV 座標系の UV 座標を $(U_{b}, V_{b})$ とする。
このとき、UV 座標変換はこのように行えばよい。

```math
\begin{eqnarray}
U_{b} &=& U_{t} \\
V_{b} &=& 1 - V_{t}
\end{eqnarray}
```

つまりまず、U 座標に関しては無変換でよい。
そして V 座標に関しては、反転させて 1 を加算すればよい。
また逆に、左下原点から左上原点に変換するときも同様の式で求まる。

# UV Scale/Offset パラメータの変換
ではここで、一般に UV 座標に付随して定義される Scale および Offset の値はどう変換すればいいだろうか？
Scale と Offset は次のように定義される。

ある頂点の UV 座標を $(U_{m}, V_{m})$ とする。
また Scale $(S_u, S_v)$ および Offset $(O_u, O_v)$ とする。

このとき最終的に求められる UV 座標 $(U, V)$ は以下のように定義できる。

```math
\begin{eqnarray}
U &=& U_m S_u + O_u \\
V &=& V_m S_v + O_v
\end{eqnarray}
```

ここで前節から、U 座標に関しては無変換でよい。
では V 座標はどうだろうか？

まず入力となる左上原点の UV 座標系を持つソフトウェア上での値を次のように定義する。
最終的に求まる UV 座標系の V 座標を $V_t$ とする。
メッシュ頂点 UV の V 座標を $M_t$ とする。
スケールの V 軸パラメタを $S_t$ とする。
オフセットの V 軸パラメタを $O_t$ とする。

同様に返還後の出力となる左下原点の UV 座標系を持つソフトウェア上での値を次のように定義する。
最終的に求まる UV 座標系の V 座標を $V_b$ とする。
メッシュ頂点 UV の V 座標を $M_b$ とする。
スケールの V 軸パラメタを $S_b$ とする。
オフセットの V 軸パラメタを $O_b$ とする。

このとき、これらのパラメタは以下を満たせばよい。

```math
\begin{cases}
V_b &= 1 - V_t \\
M_b &= 1 - M_t \\
S_b &= S_t \\
V_t &= M_t S_t + O_t \\
V_b &= M_b S_b + O_b \\
\end{cases}
```

これらを代入して式変形していくと以下のように計算できる。

```math
\begin{align}
V_b &= 1 - V_t \\
M_b S_b + O_b &= 1 - (M_t S_t + O_t) \\
M_b S_t + O_b &= 1 - (M_t S_t + O_t) \\
M_b S_t + O_b &= 1 - ((1 - M_b) S_t + O_t) \\
M_b S_t + O_b &= 1 - (1 - M_b) S_t - O_t \\
M_b S_t + O_b &= 1 - S_b + M_b S_t - O_t \\
O_b &= 1 - S_t - O_t \\
\end{align}
```

したがってオフセットの V 軸パラメタは $1 - S_t - O_t$ で求まる。
Coursier + ammonite + Scala3 で簡単なスクリプト作成


Coursier + ammonite + Scala3 で簡単なスクリプトを作成してみました。


# Coursier のインストール

Coursier = Scala のインストーラツール
インストールが必要なものすべてを自動でインストールできる。便利。

### 参考サイト

GETTING STARTED WITH SCALA 3:
https://docs.scala-lang.org/ja/scala3/getting-started.html

### インストール手順

ほぼ参考サイトの手順通りに進めました。
今回は brew でインストールしました。

#### Coursier のインストール

```
brew install coursier/formulas/coursier && cs setup
```

#### coursier に Scala3 をインストール

デフォルトでは coursier に Scala2 しか入らないので、 
Scala3 を coursier でインストールします。

```
cs install scala3-compiler
cs install scala3
```

これで Scala3 でのコンパイル・実行ができます。

# coursier を使って素振り

#### cs launch scala3 で実行

```HelloScala3.scala
enum Color:
    case Red, Blue, Green

@main
def main() =
    println(s"Hello ${Color.Red} ${Color.Blue} ${Color.Green}")
```

実行

```
$ cs launch scala3 -- HelloScala3.scala
Hello Red Blue Green
```


#### cs launch ammonite で実行

```HelloAmmScala3.sc
enum Color:
    case Red, Blue, Green

println(s"Hello Amm Scala3 ${Color.Red} ${Color.Blue} ${Color.Green}")
```

実行

```
$ cs launch ammonite --scala 3.0.2 -- HelloAmmScala3.sc
Hello Amm Scala3 Red Blue Green
```


# 簡単なスクリプト作成

とりあえず素振りできたので、
APIを叩いてレスポンスを取得する簡単なスクリプトを作ってみます。

今回は以下のライブラリとAPIを使わせていただき、
書籍のISBNと一致する書籍タイトルを取得するスクリプトを作ってみます。

#### ライブラリ
sttp : https://github.com/softwaremill/sttp
circe : https://circe.github.io/circe/

#### API
Google Books API : https://developers.google.com/books/docs/v1/using#WorkingVolumes

以下のようなリクエストで書籍情報を取得できます。
https://www.googleapis.com/books/v1/volumes?q=${クエリ}

## 作ったスクリプト

作ったもの。
(※ISBN をプロパティで渡している箇所はもっと良い方法がありそう・・・)

```GetBook.sc
import $ivy.`com.softwaremill.sttp.client3::core:3.3.14`
import $ivy.`io.circe::circe-core:0.14.0`
import $ivy.`io.circe::circe-generic:0.14.0`
import $ivy.`io.circe::circe-parser:0.14.0`

import sttp.client3._
import io.circe.generic.auto._
import io.circe.parser._

// TODO 引数をシステム・プロパティで渡しているが、 ammonite の仕組みで渡せると良さそう。
Option(sys.props("isbnArg")) match 
    case Some(isbn) => request(isbn)
    case None => println("isbnArg is required")

def request(isbn:String) =
    val url = s"https://www.googleapis.com/books/v1/volumes?q=isbn:$isbn"
    val request =basicRequest.get(uri"${url}")
    val backend = HttpURLConnectionBackend()
    val response = request.send(backend)
    for {
        body <- response.body
        result <- parse(body)
        item <- result.items
    } println(s"${item.volumeInfo}")

// APIのレスポンスから取得したい要素を case class のフィールドで定義
case class Result(items:List[Book])
case class Book(volumeInfo:VolumeInfo)
case class VolumeInfo(title:String)
def parse(responseBody:String) = decode[Result](responseBody)
```

実行コマンドと結果

```
$ cs launch ammonite --java-opt -DisbnArg=429501155X --scala 3.0.2 -- GetBook.sc
VolumeInfo(Scalaスケーラブルプログラミング 第4版)
```

無事書籍タイトルが取得できました。
APIからのレスポンスにはもっと豊富な情報があるので、case class のフィールドを拡張すればもっと出力結果を充実させることも可能です。
AWS CLIで Web サイトを構築、管理、運用する(21日目)

21 日目！

予告通り、コンテンツ周り、特に管理やデプロイについて設定をいれていきます。

# 21日目の要約
コンテンツをリポジトリで管理するよ！

# AWS CLI の準備
このあたりをみて、好きなバージョンとお使いのOSにあった環境設定をしてくださいね。
なんなら、 AWS CloudShell で実行するのも楽でよいと思います。
この記事シリーズは、AWS CloudShell で実行し、実行例を載せています。

バージョン１
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv1.html

バージョン２
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/install-cliv2.html

# 概要
CodeCommit を使ってコンテンツを管理するよ！

# さあ、やってみよう！
## リポジトリを作る
CodeCommit のリポジトリを作成して、コンテンツを管理できるようにします。

```sh
aws codecommit create-repository --repository-name <任意のリポジトリ名>
```

リポジトリが作れると以下の json が返ってきます。

```json
{
    "repositoryMetadata": {
        "accountId": "************",
        "repositoryId": "********-****-****-****-************",
        "repositoryName": "<指定したリポジトリ名>",
        "lastModifiedDate": "2021-12-20T16:53:42.654000+00:00",
        "creationDate": "2021-12-20T16:53:42.654000+00:00",
        "cloneUrlHttp": "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/<指定したリポジトリ名>",
        "cloneUrlSsh": "ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/<指定したリポジトリ名>",
        "Arn": "arn:aws:codecommit:ap-northeast-1:************:<指定したリポジトリ名>"
    }
}
```

## git のセットアップを行う
以下の例は AWS CloudShell での実施したものです。

ローカルリポジトリを作成します。
合わせて、 S3 に格納した index.html の元ファイルをコピーしておきます。

```sh
mkdir <リポジトリ名>
cp -p index.html <リポジトリ名>/index.html
cd <リポジトリ名>
git init
```


以下が出力されました。

```sh
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint:   git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint:   git branch -m <name>
Initialized empty Git repository in /home/cloudshell-user/<リポジトリ名>/.git/
```

git コマンドで CodeCommit 上のリポジトリが扱えるように設定します。

```sh
git config --local credential.helper '!aws codecommit --region ap-northeast-1  credential-helper $@'
git config --local credential.UseHttpPath true
git remote add origin https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/<リポジトリ名>
git config --global user.email "<メールアドレス>"
git config --global user.name "<ユーザー名>"
```

設定が終わったら、index.html ファイルをリポジトリにプッシュします。

```sh
git add index.html 
git commit -m "First Commit"
git push origin master
```

正常にプッシュできると以下のように表示されます。
※以下の例は2回目のプッシュのため、一回目とは若干異なる

```sh
[master *******] test
 1 file changed, 1 insertion(+), 1 deletion(-)
git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 284 bytes | 284.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
To https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/<リポジトリ名>
   23*****..a6*****  master -> master
```

これで CodeCommit を使ったコンテンツ管理ができるようになりました。

# まとめ
今までは ローカルのみでコンテンツを管理していましたが、 CodeCommit を使うことで変更履歴管理を行えるようになりました。

明日は、コンテンツがプッシュされたら S3 へデプロイされるように設定していきます。
MUI-v5の2つのstyled()の違いについて

mui-v5において、以下2つの挙動についてドキュメントを読んてもあまり理解できなかったのでソースコードを追ってみました。

```jsx
import { styled } from '@mui/material/styles';
import { styled } from '@mui/system';
```

公式の見解はこうです。

> You can use the utility coming from the `@mui/system` package, or if you are using `@mui/material`, you can import it from `@mui/material/styles`. The difference is in the default `theme` that is used (if no theme is available in the React context).
> 

Reactコンテキストでテーマが利用できない場合に使用されるデフォルトのテーマが違うみたい。

```jsx
const StyledButton = styled(Button)(
  ({ theme }) => `
  color: ${theme.palette.primary.main};
  `
);
```

上記のコードで試しに、_app.tsxの以下の部分をコメントアウトしてみた

```jsx
{/* <ThemeProvider theme={theme}> */}
 <CssBaseline />
 <Component {...pageProps} />
{/* </ThemeProvider> */}
```

import { styled } from '@mui/material/styles';

ではmuiのデフォルトのテーマが適用された。

しかし、import { styled } from '@mui/system';では

```jsx
TypeError: Cannot read property 'main' of undefined
```

エラーとなり表示されなかった。

つまりここで言うReactコンテキストとはReactを使える状況なのかそうではないのかの違いなのか？

一応コードを追ってみた。

確かに**@mui/system**ではpaletteにはmodeはない。

[https://github.com/mui-org/material-ui/blob/master/packages/mui-system/src/createTheme/createTheme.js#L23](https://github.com/mui-org/material-ui/blob/master/packages/mui-system/src/createTheme/createTheme.js#L23)

そして、それを呼び出している箇所でもthemeがなければ上記のデフォルトテーマを使ってるっぽい。

[https://github.com/mui-org/material-ui/blob/master/packages/mui-system/src/createStyled.js#L122](https://github.com/mui-org/material-ui/blob/master/packages/mui-system/src/createStyled.js#L122)

**import { styled } from '@mui/material/styles';**

も調べてみた。

createStyleするときに何やらdefaultThemeを使ってる。

[https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/styles/styled.js#L9](https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/styles/styled.js#L9)

.defaultThemeは.createThemeをimportしてるのでcreateTheme.jsを見てみる。

[https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/styles/createTheme.js#L11](https://github.com/mui-org/material-ui/blob/master/packages/mui-material/src/styles/createTheme.js#L11)

createPaletteがあったり、createTypographyがあったり何やらデフォルトのテーマを作成してるっぽいですね。

createPaletteを見てみます。

[https://github.com/mui-org/material-ui/blob/f8697de9c250dbc6b446bcc08566f50fb4070aab/packages/mui-material/src/styles/createPalette.js](https://github.com/mui-org/material-ui/blob/f8697de9c250dbc6b446bcc08566f50fb4070aab/packages/mui-material/src/styles/createPalette.js)

おー。

ちゃんとデフォルトのテーマが設定されていましたね。

つまり公式の

> You can use the utility coming from the `@mui/system` package, or if you are using `@mui/material`, you can import it from `@mui/material/styles`. The difference is in the default `theme` that is used (if no theme is available in the React context).
> 

上記の文章に記載されているReactコンテキストとは、何かしら自分でテーマをカスタマイズして使用していない場合にthemeの挙動が変わるよということなのでしょう。

## まとめ

恥ずかしながら初めてOSSをここまで読むことができました。

OSSを読むのには時間がかかりますが、もっと読んで自分の知見にしていこうと思います。
バッチ処理の自動テストを書こう

# バッチ処理の自動テストを書こう


## はじめに
こんにちは。webエンジニアの [ningenMe](https://twitter.com/ningenMe) です。  
この記事は [ソフトウェアテスト Advent Calendar 2021](https://qiita.com/advent-calendar/2021/softwaretesting) の 21日目の記事です。


## バッチ処理とは
バッチ処理の定義がちょっと曖昧なので、本文中におけるバッチ処理を定義しておきます。  
ここでは あるデータソース `A` から データを取得し、なんらかの処理をした後、あるデータソース `B` に永続化するような作業、とします。

もちろんデータソースというのは、mysqlでもいいし、はたまた外部APIでもいいですし、s3などのオブジェクトストレージでも構いません。  
インプットとアウトプットが外部にあって、それをやりとりするイメージです。

## 前提
ここで実装に関しては spring-batch と呼ばれるフレームワークで実装されたバッチ処理に対するテストを想定します。  
テストのフレームワークは Junit5 です。

## まず
テストを書きましょう。  
テストのアドカレなのに何を言ってるんだと思われるかもですが、自分が見てきた限りだとバッチ処理に対してテストが薄かったり書かないみたいなチームや開発スタイルにしばしば遭遇します。

テストを書きましょう。

## integrationテストを書こう
バッチ処理でよく見かけるのが、かなりの項目を結合テストで対処するパターンです。  
もちろん結合テスト自体は大事なのですが、ビジネスロジックの細かい挙動や、IOのエラー時の挙動など、ありうるパターンを全部手作業でやろうとするとかなり大変です。  
ましてやコード凍結した後にバグが見つかったら修正が入って結合テストが全部やり直し、なんてこともしばしば......。  
なので、まずはソース内で完結させることができる部分だけでも極力自動テストを書いて、結合テストの負担を減らしましょう。

`integrationテストで出来ることは極力、結合テストでやろうとしないこと` です。

## integrationテストって何？
ここではアプリケーションを一気通貫で動かす自動テストを指しています。1クラスだけなどの単体テストではなく、バッチの実行単位(あるいは内部の1step)ごとのテストをイメージします。

## 結合じゃないとテストできない？
バッチでよく言われるのが、この話なのかなと思ったりしています。 
DBを用意できないとか、データを用意できないとか。そういう理由で開発環境で手動テストをたくさんやるみたいな流れが生まれたり。

これは本当に良くない。

近年だと一般的なdbとかが大体dockerで手軽に立てることができます。 
apiに関してもnginxなどをdockerで立ててしまえば、mockとしては十分です。
なのでテストの実行のたびにスタンドアローンなテスト環境(DBや外部のAPIのmock)を整えることができるはずです。

開発環境に立ってるdbなどを前提としたテストは、テストが状態を持ってしまうことや、冪等性、並列性を考えても本当によくないです。  
スタンドアローンなテスト環境を作り、結合テストをやめて極力integrationテストを書きましょう。



例として spring-bootでのスタンドアローンなテストの作り方を載せておきます。

- [spring-boot + dbunit + dockerでdbのテストを行う](https://qiita.com/ningenMe/items/045620965bf73555d0a7)

## 状態のassert
テストって基本的には、なんらかのインプットに対して、適切なアウトプットになっているかを確認する部分が大きいと思います。  
バッチ処理のテストでも、なんらかのデータソースをインプットとし、最終的に永続化されるデータに対して assert が行われるべきです。


dbunitなどのツールを用いてdbのテーブルをassertしたりしましょう。
静的なファイルとのデータの突合を意識するべきです。  
なんとなく正常終了したらok、ではダメです。


## 冪等性
バッチ処理において、冪等性はかなり大事です。
もちろん結合テストでも確認したいですが、これこそ自動テストでもある程度確認できるので、自動化しましょう。

以下にソースのイメージを載せます。

```java

void test() {
        //inputを準備する
        setupInput()

        //バッチを動かす
        execBatch()
        //outputをassertする
        assertOutput()

        //冪等確認のために再度バッチを動かす
        execBatch()
        //outputをassertする
        assertOutput()
        }

```
おそらくある程度ソースが書けていれば、上記のように手軽に確認できるはずなのでintegrationテストを自動化する際は入れたほうが安心感が増します。

## コードフリーズ
リリースが近づいたら、コミットをこれ以上加えない、という日付を設けてコードをフリーズさせましょう。 

上記でも話しましたが、開発途中で結合テストをするのは良くないです。 
もちろん結合テストでバグが見つかって修正コミットをするのは普通のことです。 
ただその時は、手動でやってるような結合テストは全部やり直すべきです。 
最終的なソースの状態に対して、結合テストが行われるべきです。

実際のところ、コストとの兼ね合いもありなかなか上記が守られないことが多いです。 
なので1ケースでも多く自動テストに組み込み、結合テストを減らし、CIが毎回チェックしてくれるような仕組みを作りましょう。  
人間は疲れてくるとテストしなくなります。

## 個人的な話
自分の業務では、最初は手動の結合テストが多め、自動のintegrationテストはほぼない状態でプロジェクトを進めていました。
その時はバグがかなり多く出たり、後から改修が増えた結果、工数も大きくなりました。

途中でプロセス改善を行い、
手動の結合テストを少なく、自動のintegrationテストを多くしたところかなりバグが少なくなり、品質が大きく上がりました。
また結果的に工数も少なくなりました。


やっぱり自動テストに寄せる方が、全体としては品質も工数も担保されると思います。


## さいごに
具体的なテクニックというよりは、プロセス改善に近い気はします。  
Javaに関わらず、どの言語で書くにしてもある程度意識することは同じだと思います。

チーム内で誰かが(あるいは自分が)手作業でたくさんテストしてたら違和感を持ちましょう！
快適な自動テストライフを。

ではでは。
どうしても1990年代のプチレトロPCゲーが遊びたくなったので環境構築した件

　はじめまして。技術力がないので文章力でIT業界にしがみついているへっぽこインフラエンジニアです。

※この記事は元々「Qrunch」というここよりちょっぴり敷居の低い技術ブログサービスが運営されていた頃に投稿した文章
　……をQrunchサービス終了に伴いnoteへ再掲載した文章です。
　Qiita Advent Calendar 2021向けの「改稿版」的な扱いです。




# Windows10だけど昔のPCゲーで遊びたくなったきっかけ
2018/07　サザンオールスターズのデビュー40thをきっかけにどちゃくそハマる
2018/09　関口和之(Bass)🤠推しになる
2019/03　推しが1996年にPCゲーム「砂金Ⅱ」をリリースした事を知る

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">砂金IIは何故CD-ROM→ゲームかよ→毛ガニさんも別のゲームに関わってた→やってみたい→1996年発売！？その頃何やってたっけ→PCならサンリオタイニーパークとかうるうるとかパンツァードラグーン→殆ど家に無い→プレイしたくなってきた→せめてプレイ動画→何故この頃のゲーム動画無いの　←今ここ</p>&mdash; RYUSEKI,Akane🐲🌽💉💉 (@kan8lovers) <a href="https://twitter.com/kan8lovers/status/1107975805370417153?ref_src=twsrc%5Etfw">March 19, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この頃Windows95やOld Macについて調べてましたが、ADSL普及以前の情報ってかなり現存率が下がってしまうのですよね。
最後の砦だったYahoo!ジオシティーズも遂にサービス終了し、現代史や民俗学的に後年価値が発生するであろう「ガチでアングラだった頃のインターネット文化」を形成するテキスト情報達が電子の海へ散骨されてしまったのは仕方ない事と理解しつつも悲しいですね。

その後Old Mac環境再現の為のBasiliskⅡ(Old Macのエミュレーター、詳しくはググってください)に寄り道しつつ、最終的には下記に記載する環境でどうにかゲームプレイ環境を用意する事が出来ました。
「砂金Ⅱ」の起動が確認出来た頃にはGWが終了して翌朝から仕事でしたね……(汗)
この記事は今後私がプレイ環境再構築の必要が出た場合に間違えない為の備忘録も兼ねています。

# Windows10で1990年代のプチレトロPCゲーを遊ぶ為に構築した環境
基盤OS:Windows10 Pro(64bit)
仮想化技術:Hyper-V
仮想マシンのOS:Windows7 Enterprise(32bit)
　※大学時代に入手したDVD-ROMを使いました
メモリ:RAM 2048MB/動的メモリ有効(最小512MB、最大1048756MB、メモリバッファー20%、、メモリの重み:中)
仮想プロセッサ:1個(特に設定は編集なし)
DVDドライブ:Hyper-V起動前にソフトのディスクを投入した上でUSB接続し、Hyper-Vマネージャー>設定タブ>ハードウェア>DVDドライブのメディア欄で「物理CD/DVDドライブ」にチェックを入れる
もしくは、基盤OSに指定のISOファイルを保存し、Hyper-Vマネージャー>設定タブ>ハードウェア>DVDドライブのメディア欄で「イメージファイル」にチェックを入れ、「参照」ボタンをクリックして指定のISOファイルを選択して「開く」をクリック
ネットワークアダプター:Default Switch(セキュリティが気になる人はInternal Switchを指定すること

Windws7でも64bitだと駄目でした。bit数が高すぎてもゲームが動かせなくなるみたいです。
また、Windows8系及び10の32bitは現在未所持の為検証できておりません。お持ちの方は是非上記を参考に試してみてください。

# 音を出しながらゲームをするのに必要な準備
Hyper-Vから出す小窓でも仮想マシン上のPCゲームは遊べますが、**音が出ない**のでリモートデスクトップ接続によって音を出しながらプレイ出来る様に設定します。
リモートデスクトップを起動したら、**「オプションの表示」>ローカル リソース> リモートオーディオの「設定」**を開きます。
リモート オーディオ再生画面から**「このコンピューターで再生する」**のチェックを忘れずに





ここまで設定したら、あとはHyper-V仮想マシンとリモートデスクトップを起動してプチレトロPCゲーを仮想マシン上で遊べる……筈です。
ソフトによってはQuickTimeやゲーム動作に必要な当時のソフト等を別途インストールさせられる事もありますが、仮想マシンなので問題ありません。
あと、ひとつ大事な事書き忘れてました。インストールしてもWindows7は通常クリックだとエラーが出てしまうので、原則**管理者として実行**をおすすめしておきます。モニタの色を256色にするとかの操作はいらないので。　

#(参考)今までに遊んだor遊んでみたいいにしえのPCゲーム
クリア済みもしくはプレイ途中
・砂金Ⅱ
　[プレイ動画前編をニコニコ動画にアップしました](https://www.nicovideo.jp/series/81793?ref=pc_watch_description_series)
・眠れぬ夜の小さなお話
　[初回お試しプレイのみニコニコ動画にアップ済](https://www.nicovideo.jp/watch/sm39741796)
・ALeX-WORLD
　分岐があるらしいので二周目プレイ予定)

プレイしたい
・DARK FIBER
・THE SABOTENMAN
・うるうるⅢ(ⅠとⅡもディスクを入手次第……)
・ぼのいぢり
・パラダイスレスキュー
・じょうじなまはげ(実はサザンオールスターズの「毛ガニ」ことパーカッショニストの野沢秀行さん😘がBGMを作成されたそうです)

他にもおすすめのプチレトロPCゲーがありましたら教えてください。あかん方法も含めて駆使してソフトを探します。
是非プレイ動画をうｐして、オンライン上にアーカイブする事でそのソフトがあった事・インタラクティブ期のクリエイターの業績を歴史に残していきたいと思っています。


#最後に
推し、お誕生日おめでとうございました！(1955/12/21生まれ)
CloudFlare&Let's Encryptで証明書がrenewできなかった

# はじめに

突然サービスのSSL証明書が切れまして
定期的にrenewするようにcronを設定してたのですが、何が起きたのか。。。

とりあえず解決ができたので、共有をば

# 要点

まずはcertbotの更新

```
yum install -y --enablerepo=epel certbot
```

そして認証局の証明書群のインストール

```
yum install -y ca-certificates
```

最後にCloudFlareの設定画面にてフレキシブルを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35462/d8b5178e-2e7a-9811-01a5-09fd2ff00828.png)

↑これは気づけなかった...

# 問題発生

夜中に、いきなりさ、証明書の有効期限切れてるよってLINE〜♪

**怖**

certbotをcrontabで動かしていて、今まで動いてたんだけどな。。。
切れたのが夜でよかった。。。

確認してみると、以下のように設定しているcrontabがうまく動作していないということが判明

```
vi /etc/cron.d/certbot
0 0 18 * * root /bin/certbot renew --force-renew --post-hook "systemctl reload httpd"
```

というわけで、上記を `--dry-run` つけて実行してみると

```
/bin/certbot renew --force-renew --dry-run
```

```
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Failed to renew certificate foo.bar with error: __str__ returned non-string (type Error)
```

というエラーが発生しているせいで、 `fullchain.pem` が更新できていない様子

ログを見てみると

```
less /var/log/letsencrypt/letsencrypt.log
```

なんか要するにAPIアクセスが失敗してて、stringに入るべきところに何も入ってない的なことがわかった

- [Connection error on "acme\-v02\.api\.letsencrypt\.org" \- Help \- Let's Encrypt Community Support](https://community.letsencrypt.org/t/connection-error-on-acme-v02-api-letsencrypt-org/162393/8)


こことか見てて、ライブラリの問題があるっぽかったんだけど、なんと残念ながらこちらの環境はpipでライブラリをインストールしているわけじゃない様子だったので、バージョン変更できず。。。

ならば問題の箇所である `urllib3` の方でエラー文調べてみると

- [Need to update error handling for pyOpenSSL · Issue \#556 · urllib3/urllib3](https://github.com/urllib3/urllib3/issues/556#issuecomment-986554930)

認証局の証明書群をインストールすると良さそうということが判明

```
yum install ca-certificates
```

で、再度 `--dry-run` で実施


```
/bin/certbot renew --force-renew --dry-run
```

するとうまくいった。

というわけでrenew実行。

```
/bin/certbot renew --force-renew --post-hook "systemctl reload httpd"
```

cloudflareまでアクセスが進んだが、エラーが変わって、今度は524エラーだった。

```
Starting new HTTPS connection (1): api.cloudflare.com
Failed to renew certificate foo.bar with error: 524 Server Error:
```

どうやら、foo.barにアクセスした際に、timeoutしているみたい

- [Troubleshooting Cloudflare 5XX errors – Cloudflare Help Center](https://support.cloudflare.com/hc/en-us/articles/115003011431-Troubleshooting-Cloudflare-5XX-errors#524error)

問題を発見するまでに調べていた内容で
certbotは証明書発行の際、サービスのURLにアクセスする際にhttpsではなくhttpでアクセスしてくるらしく
http→httpsのリダイレクトを設定しているとうまく証明書更新ができないらしいよ、という記事を見かけていたので、それかな？と推測

推測したはいいものの、リダイレクトの設定なんかWebサーバーのconfでやってなかった(Apache)

ということは、CloufFlare側の設定かな？と思い、コンソールにログインしてみると、SSLの設定項目の中に以下があった

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35462/d8b5178e-2e7a-9811-01a5-09fd2ff00828.png)

元々「フル」が選択されており、オリジンサーバーに証明書月リクエストを行なっていたようだったので、今回は「フレキシブル」に変更。

ここでcertbotのrenewを再実行。

```
/bin/certbot renew --force-renew --post-hook "systemctl reload httpd"
```

正常に実行されて、サーバーも再起動され、正しくSSLアクセスができることが確認できました。

# 感想

なんだかんだ1時間半くらいで解決できてよかったけど、夜のLINEは怖いですな。

最近は問題発生したらすぐにQiitaに書いておくようにしているので、この投稿時間が問題の発生時間とほぼ等しいです。

同じことで困っている人がいれば、この記事が助けになっていると嬉しいです。

おやすみなさいー。
plantumlでtheme

# 見た目が微妙なplantuml

今まで、微妙だと思いつつ、いろいろ置き換えていたが、デフォルトで色々使えるようになっていたのね。
「!theme テーマ名」でテーマを指定する。

詳細は以下。
[https://plantuml.com/ja/theme]
[https://bschwarz.github.io/puml-themes/gallery.html]

## default

```plantuml
@startuml
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml
```

## aws-orange

```plantuml
@startuml
!theme aws-orange
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml
```

## sketchy

```plantuml
@startuml
!theme sketchy
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml
```

## stechy + aws-orange

単純に足されていくので、「!theme」を複数行記載する。

```plantuml
@startuml
!theme sketchy
!theme aws-orange
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response

Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml
```
【UE5】MetaSoundで癒しの周波数を使った曲を奏でる

この投稿はUnreal Engine Advent Calendar 2021 22日目の記事です
###自己紹介
こんにちは　kabgoyaこと かぶ です
音楽活動をしながらUnreal Engineや3DCGをたしなむ者です。

###今年の記事を書こうとした経緯
私事ですが、今年は自分がらみのTwitter動画が2回プチバズりました。
ひとつは自分が作詞作曲した歌
もうひとつがMetaSoundのチュートリアルをやってみた記事です。

https://twitter.com/liusei/status/1398307327292284931?s=20

これに味を占めて？**今年はMetaSound記事をTwitterにたくさんUPすればUnrealEngineつかいらしくなれるのでは？**
と思い次はMetaSoundで童謡を演奏させようと思いチャレンジしましたがあえなく挫折…
音を出すまでは至ったのですが一気に音が鳴るので不協和音が出るだけ
という結果を修正する作業に耳が耐えられず
その上夏に体調を崩したこともありしばらくUE5から遠ざかっていました。

参考にした記事

https://zenn.dev/tan_y/articles/e3c561a44aec24

体調がよくなった頃、ふたたびMetaSoundを使う機会があったので改めて上記の記事を読んで気づいたことがありました

**あれ？周波数が設定できるぞ**

もしかしたらこれでこの前の仕事の時調べた知見が応用できるかも！
と思いこの記事を書きました。

###癒しの周波数をMetaSoundで出してみよう！
ソルフェジオ周波数ってご存じですか？

グレゴリオ聖歌で使われた失われた古代の音階を周波数化したもので
近年癒しの世界(いわゆるスピリチュアル系)で注目されています。

今年の秋ごろ、スピリチュアル系の方から瞑想曲の依頼が来たのですが
ヒヤリングの結果、ソルフェジオ周波数を入れてほしいとのこと。
？？？と思いながらも周波数を織り交ぜた楽曲に興味はあったのでいろんな資料をかき集めたりYouTubeなどでヒーリングミュージックを聴いて研究しました。
話し出すと今回のテーマと大きく外れてしまいますので興味のある方は以下のリンクをご覧ください。

https://www.miki.co.jp/culture/bizdev/miki_music_lab/1343/

瞑想曲の仕事自体はスピリチュアルな理由で流れてしまいましたが
その時調べた知識を無駄にしたくない！と思いました。

まずはMetaSoundで基本のソルフェジオ周波数・528Hzを正弦波で鳴らしてみました。

https://youtu.be/rOQndWTJywQ

ここはポジTAさんのnoteを参考にしました

https://note.com/posi_ta/n/nb1375f24c558?magazine_key=m2876a7aaad2a

……癒しというより無機質な単音ですよね:droplet:
いくらDNAを修復してくれる(かもしれない)とはいえこの音を聞き続けるのは苦痛かと思います。

そこで公式のリファレンスを見直しながらソルフェジオ周波数でプロシージャルな音楽を作れないか考えてみました。

###チューニングを考える
最初に引っかかったのは<b>チューニングをどうするか</b>
デフォルトでは基準の音が440Hzです。
これはポップスのチューニングの基準の音になります
音階名はA4、つまりラの音です。

先ほどのソルフェジオ周波数の基準音は528Hz
音階名C5(523.251Hz)より4.749Hz高い音になります。

MetaSoundでプロシージャルな音楽を作ろうとすると440HzでチューニングされたMIDI音階ナンバーを使うので基準音を4.749Hz底上げしたチューニングをすればよいのではないかと考えました。
![ScreenShot01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541757/bd673d8a-df30-85bc-bfef-3e0fc0bb1f8a.png)

###癒しの周波数を使ったプロシージャルな曲を作ってみた

チューニングを変更する方法がわかったので[MetaSoundクイックスタートガイド](https://docs.unrealengine.com/5.0/ja/AudioFeatures/MetaSounds/QuickStart/)をベースにプロシージャルな曲を作ってみることに。

MetaSoundのノードの全体図はクイックスタートガイドを見ていただくことにして主な変更点だけ抜き出します。

まずはMIDI鍵盤ナンバーを設定し(5Cは72なんだけどなぜかRandomGetノードが2を吐き出しているので70に設定)
MIDIから周波数(Float)ノードで周波数に変換し
ここに528Hzとの差分4.749を足して正弦波ノードに周波数の数値を送ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541757/e30e5f10-1270-f043-7cdf-2f0940205fda.png)

そのままの数値では癒しの曲っぽくなかったのでテンポやパラメータを変更して聴く、の繰り返しでここまで仕上げました。

正弦波の設定　Typeを 7世紀に発見されたという Bhaskara にしています
![ScreenShot03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541757/79a15d5c-730e-48d2-fb82-3800c2c47508.png)

のこぎり波を三角波に変更　Typeをトリアブルに設定しています
![ScreenShot04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541757/cd6c4a42-76c0-03ab-3197-8e7036deb1d6.png)

テンポは72 スケールはリディアンオーグメント
その他の設定はクイックスタートガイドとほぼ同じです。

で、完成したサウンドがこちら！

https://youtu.be/OkzddNuFRgY

ヒーリングミュージックというより現代音楽のようになってますが
調整している間に眠くなってきたのである程度の効果はあるようです(?)

###作ってみた感想など
MetaSoundを触っているとDTMなんて言葉がなかった時代のコンピューターミュージックを思い出しました。
音階を番号で表記するのが役に立ったのって数十年ぶりじゃないでしょうか？

MetaSoundはどちらかというとシンセサイザーとしての機能寄りなのでアナログシンセで音作りしてた人が触ると使いこなせるんじゃないかという印象を持ちました。
あとは和音の出し方がもっと簡単だといいなと思いました。


冬至なのでかぼちゃを食べてゆず湯につかって来年はもっといい年であるように祈ります。
それでは良き冬至とクリスマスと年末年始をお過ごしください！