OmniAICreator/Qiita-1.07M huggingface dataset:
SendGridでメールを受信する

# はじめに

急遽必要になりまして、SendGridでメール受信するのを試してみました。
ちなみにこんなことしなくてもAmazon WorkMailを使うのが一番簡単な手段だということに後から気づきました。

# 今回の構成

SendGridにはInboudParseWebhookという機能がありまして、メールが入ってきたら裏側にHTTPリクエスト投げてくれるようです。[SES→Lambda](https://docs.aws.amazon.com/ja_jp/ses/latest/dg/receiving-email.html)と同じですね。
HTTPリクエストを受ける部分をFunctionで構成してログを出力するところまでやってみたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/752148cf-f225-7e46-f4b7-c5ecfec853fe.png)

弾力性が足りないぞ。とお叱りを受ける場合はこんな感じの構成になるんじゃないでしょうか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/701a3464-9715-06ad-ff00-3f1e20e78d83.png)

SendGridから受けたらServiceBusでキューイングして、そのあと処理させます。
Functionの部分はAppServiceでも構わないですがOutputBindingやInputBinding使うと非常に楽に作れますし信頼性も上がります。

# メールを受け取るAPIを作ろう

こちらの記事を参考にFunctionの雛形を作ってデプロイまでやっていきましょう。なれると5分くらいでできます。
- [[初学者向け]AzureFunctions(TimerTrigger)＋nodejsをはじめてみよう](https://qiita.com/uzresk/items/c3b312c5df16026bbcc2)

Functionのコードはただ標準出力するだけのものです

```typescript
import {AzureFunction, Context, HttpRequest} from "@azure/functions"

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
  context.log('HTTP trigger function processed a request.');

  const body = Buffer.from(req.rawBody);
  context.log(body.toString())

  context.res = {
    status: 200,
    body: "success"
  };
};

export default httpTrigger;

```

# ドメインの設定

SendGrid側でドメインの認証を行います。私はAppServiceドメインを使ったのでGoDaddyを選択しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/e21a49fe-c85c-678e-56d5-e99518a541c4.png)


次の画面でドメインを設定するとDNSに以下のレコードを登録してくれ。って出てきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/5f224cce-8280-6a52-4bb8-a482b7a2d12d.png)

言われた通り登録していきます。ついでにMXレコードもSendGridに向けます（↓のキャプチャの一番下の行です）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/95860ba6-de38-3422-aae6-26a32e2a63fc.png)

# WebHookの設定

先ほどCNAMEで登録したサブドメインが実際にメールを受け取るドメインになりますのでそこだけ注意して登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/d0a52cff-9d54-9b4e-8689-dc40a3331b53.png)

# メールを投げて動作確認

info@xxx.hogehoge.comでもfoo@xxx.hogehoge.comでもなんでも大丈夫です。メール送信後、Functionsのモニターを確認してメールが受信できることを確認します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/57686/5858b448-de6b-ec80-45cd-d9ba77f34e9d.png)

あとはデータベースに保存するなりすればよいのですが、Bodyのパースはなかなかしんどいので以下のライブラリを使うことで幸せになれそうです。

- [sendgrid-nodejs(公式)](https://github.com/sendgrid/sendgrid-nodejs)
- [inbound-parse-multipart-parser v 1.0.0](https://npm.io/package/inbound-parse-multipart-parser)

# 参考

- [Setting Up The Inbound Parse Webhook](https://docs.sendgrid.com/for-developers/parsing-email/setting-up-the-inbound-parse-webhook)
JUnit5

テスティングフレームワーク「Junit」を統合開発環境（IDE）Eclipse※1で実行する手順を備忘録として記載させていただきます。
特徴であるラムダ式などのJava 8以降の機能を活用して実施したサンプルを記載しました。

※1 Eclipse Oxygen.1a (4.7.1a)から JUnit Platformサポートを提供

**junit5**
**https://junit.org/junit5/**

**ECLIPSE**
**https://www.eclipse.org/community/eclipse_newsletter/2017/october/article5.php**


:::note info
検証環境
**java Version: "13.0.1" 2019-10-15**
**Eclipse Version: 2021-09 (4.21.0)**
:::

## 1.Javaプロジェクトの新規作成
ファイル → 新規 → プロジェクト
![2022-07-13_00h43_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383237/e9ebafb2-3913-0b07-a541-10fec6ade336.png)

## 2.テストメソッド、テストクラス作成
ラムダ式を使用できることを確認して「src」フォルダに配置しました。
```java
import java.util.Arrays;
import java.util.List;

public class Filter {
	public String FilterFunction(String x, String y) throws Exception {
		List<String> stringList = Arrays.asList(x, y);
		stringList.stream().filter(string -> string.contains(x));
		return x;
	}
	
	public void Exception(String arg) {
		if (arg == null) {
			throw new IllegalArgumentException();
		}
	}
}
```
```java
import static org.junit.jupiter.api.Assertions.*;

import org.junit.jupiter.api.Test;

class FilterTest {

	@Test
	public void FilterTest_1() throws Exception {
		Filter Filter = new Filter();
		String expected = "Hello";
		String actual = Filter.FilterFunction("Hello", "World");
		assertEquals(expected, actual, () -> "Hello");
	}

	@Test
	void exception1() {
		Filter target = new Filter();
		assertThrows(IllegalArgumentException.class, () -> target.Exception(null));
	}
}

```
## 3.JUnit5をビルド・パスに追加
@Testアノテーションで発生しているエラーをクリック
![2022-07-09_15h52_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383237/f5724fbf-6e25-a6c1-4e72-cf3e902f5391.png)
## 4.テスト実行
テストクラスを右クリックして実行
![2022-07-09_16h04_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383237/fed5850e-8876-10f0-161c-97beb15be5eb.png)
## 5.テスト結果確認
![2022-07-09_16h03_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383237/d4ebd554-a1ab-05e8-2c12-b03f76b6a1ef.png)
【Vue.js】 デバック方法 基本の'キ'



こんにちはエンジニア1年目の小林です。

最近新しくVue.jsを勉強し始め、デバックの方法に困ったことがあったので備忘録として残したいと思います。
## 基本のキ

・随時console.log で処理が叩かれているかどうか確認する
・値が渡されているかどうか確認する

## 具体例

Vue.jsを勉強し初めてよくあるやつ。
入力値をリアクティブに描画する。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/e1f4f6d7-52b0-b28f-647f-38f4c61f81ba.png">



以下が当該コード

```html
  <div id="app">
    <my-input v-model:str="message"></my-input>
    <p>入力値：{{message}}</p>
  </div>
```

```js
Vue
.createApp({
  data(){
    return{
      message: ''
    }
  },
// デバックのために書いています
  watch: {
    message(newValue) {
      console.log("====watch", newValue)
    }
  }

})
.component('my-input', {
  props:['str'],
  emits: ['update:str'],
  template: `
  <label>名前：
  <input type="text" v-model="internalValue" />
  </label>
  `,
  computed: {
    internalValue: {
      get(){
        // デバックのために書いています
        console.log('======get', this.str)

        return this.str
      },
      set(new_value){
        // デバックのために書いています
        console.log("======set", new_value, this.str)

        if(this.modelValue != new_value){
          this.$emit('update:str', new_value)
        }
      }
    }
  }
})
.mount("#app")
```

jsファイルはもっっっと簡単に書ける（公式：[フォーム入力バインディング | Vue.js (vuejs.org)](https://v3.ja.vuejs.org/guide/forms.html#%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E5%85%A5%E5%8A%9B%E3%83%8F%E3%82%99%E3%82%A4%E3%83%B3%E3%83%86%E3%82%99%E3%82%A3%E3%83%B3%E3%82%AF%E3%82%99)）
のですが、ちょっと複雑に書いています。（というか参考書に書いてあった）

ただ、やってることは至ってシンプル。
入力値が入力前と変化した場合、その値を親に渡し、画面に描画している。
流れとして、子が親のプロパティを呼び出し、子の中で値を変更して親に返す、みたいな感じです。

※ 親  = 親コンポーネント
※ 子 = 子コンポーネント
※ getterとsetterの説明は以下で詳しく説明されており、参考にさせていただきました。
[【Vue】getterとsetterの使い方。大元の変数を間接的に変更する方法](https://qiita.com/shizen-shin/items/a48cfbe7c88cc9f42e30)

## 課題の切り分け方

### **console.log で処理が呼ばれているか確認する**

コンポーネントの親子関係、`props/emit`、テンプレートなど複数の概念が出てきているので
値の受け渡しが分かりにくくなっています。

そんな時は、下図のように
**console.log('どこで', '何が') というスタイルでログを追う**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2508607/cf4d2d5c-206d-7fe6-30c5-1216aca5a54c.png)

その結果、以下の動きが観測できます。

子の中で値が変更したので`set`が発火
↓
変更した値が親で反映されたので`watch`が発火
↓
`this.str`が変更したので、`getter`で要素を再取得
（`internalValue`の`getter`が子の`str`プロパティに依存している。そのため、子の`str`プロパティが変わると算出プロパティ`internalValue`に`bind`する要素は再描画される）

### **親に値が渡っているかwatchメソッドで確認**

`watch`で指定した値が変化したかを追跡できます。
つまり、**子で変化した値が親に渡ったかどうか**を追跡できます。

```ruby
watch: {
    message() {
      # 処理
    }
  }
```

## 最後に

ここまで読んでくださりありがとうございます。
今からvue.jsを勉強するという方の手助けになれば幸いです。
ESP32でセンサのログを出力する

# ESP32
ESP32はEspressif Systemsが開発したWi-FiとBluetoothを内蔵するマイクロコントローラである．ESP32は接続されているセンサと通信を行う方法としてI2C通信が挙げられる．今回はI2C通信が行えるセンサを対象とした実装を行った．

# 今回使用したセンサ
今回は温度センサを使用した．
温度センサはエイブリック株式会社が開発したS-5851Aを使用している．
詳しい情報は下記のデータシートを参照
[S-5851Aのデータシート](https://akizukidenshi.com/download/ds/ablic/S5851A_J.pdf)

# ログの使用目的
ログを閲覧することでセンサが通電しているかが分かる．通電しているのにセンサデータが取得できなかった場合は、センサではなくプログラムに異常があるのが分かる．

# 構築環境
- ESP32
    - マイクロコントローラ
- MicroPython(1.17.0)
    - 使用したプログラミング言語
- S-5851A
    - 温度センサ

# 出力するログ
- ログの出力日時(time stamp)
- センサのI2Cアドレス
- 使用している言語のバージョン
- 使用しているマイクロコントローラ名

# ログを出力するプログラム
```python
from machine import I2C, Pin, RTC
import utime
import ntptime
import sys

#ピンの設定
p21 = Pin(21,Pin.IN,Pin.PULL_UP)
p22 = Pin(22,Pin.IN,Pin.PULL_UP)
i2c =I2C(scl=Pin(22), sda=Pin(21))

#時間の設定
rtc = RTC()
ntptime.settime() 
tm = utime.localtime(utime.time()) # UTC now
datetime_jst = str(tm[0])+'/'+str(tm[1])+'/'+str(tm[2])+' '+str((tm[3]+9)%24)+':'+str(tm[4])+':'+str(tm[5])

#センサのI2Cアドレス取得
def SencerAd():
    ad = 0
    if i2c.scan():
        ad = i2c.scan()
        return ad
# センサのI2Cアドレスを取得できなかった場合
    else:
        ad = '[No sensor.]'
        return ad

#使用している言語のバージョンを取得
impl=sys.implementation
#使用している言語とバージョンを配列に格納
lang_version = str(impl[0])+","+str(impl[1])

#マイクロコントローラ名を取得
plat=sys.platform

#ログをまとめる
log = datetime_jst+"--"+str(SencerAd())+"--"+lang_version+"--"+plat
#ログを出力
print(log)
```


# ログの出力結果
ログを"--"でパース出来るようにした．
センサのI2Cアドレスが取得できた場合に出力されるログである．
[]の中にセンサのI2Cアドレス値が表示される．
```
2022/7/13 17:48:46--[72]--micropython,(1, 17, 0)--esp32
```
センサのアドレスが取得できなかった場合に出力されるログである．
[]の中に”No sensor”と表示される．
```
2022/7/13 17:50:4--[No sensor.]--micropython,(1, 17, 0)--esp32
```
[]の中に表示されている内容でセンサがESP32に接続されているかが判断できるため、センサデータが取得できなかった際に原因の判別が出来るようになる．
PowerAutomateで配列の差集合を求める

# 概要
PowerAutomateで集合を扱う場合、積集合はintersectionというコレクション関数があらかじめ用意されています。
差集合を求める場合は少し厄介で工夫が必要です。
差集合を求める方法をネットで調べてみると二重ループとアレイのフィルター処理を使う方法やOfficeScriptsを使う方法などがヒットします。
今回はシンプルにアレイのフィルター処理を使って差集合を求めてみます。

# 前提条件
差集合を求めるための配列型変数を２つ用意します。
ここでは配列Aと配列Bとします。
各配列には以下の値が入っています。

配列A
["test1","test2","test3","test4","test5"]

配列B
["test4","test5"]

そして今回求めたい値は以下の値です。
["test1","test2","test3"]

図にすると以下のような関係になります。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342210/f7417357-ced4-a885-e113-21c6c1039d2e.png)


青色の部分を求めます。


# 実装
配列Aと配列Bを実装します。
![配列.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342210/71054f2e-ae3d-b79f-483b-d02f39331e6f.png)

次に、今回の本題であるアレイのフィルター処理を実装します。
![アレイフィルター処理.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342210/be2caa96-cac1-0f0e-500e-4d4043393846.png)
差出人には配列Aを設定します。
値の選択の左辺には数式で以下の式をセットします。
```shell:数式
contains(variables('配列B'), item())
```
配列Aの要素を順番に配列Bの各要素と突き合わせ、配列Bの要素に存在しないものを取り出しています。

今回作成したフローの全体図は以下の通り。
![フロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342210/85a4f6c7-5949-5354-7aec-e50609a267c6.png)


# 実行結果
フローを実行し、アレイのフィルター処理の出力結果を確認します。
![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342210/af48d12d-971c-d543-0659-1fac19f2ce8f.png)

配列Aと配列Bの差集合として["test1","test2","test3"]が取得できていることが確認できました。

# まとめ
今回は差集合についてアレイのフィルター処理を活用してみました。
アレイのフィルター処理を使いこなせば、これ以外にもループ処理を用いずにデータの編集ができる場面も多いです。
アレイのフィルター処理をぜひ活用してみてください。
Python3エンジニア認定基礎模試試験6回目　-間違えた問題-

<H1>獲得点数　950/1000点</H1>
<H2>正答率: 95.0 % ( 38問 / 40問 正解 )</H2>

```python
対話モード時に、最後に表示した式を格納している変数を選びなさい。

A,変数：_ (アンダーバー)

>>> a="機械学習サイコー!!"
>>> a
'機械学習サイコー!!'
>>> _
'機械学習サイコー!!'
```
UNITYの3点照明技術

みなさん、こんにちは。私はミンです。現在、[OneTech会社](https://onetech.jp/)でVR / AR開発者（Unityチーム）として働いています。次の記事では、[Unityの3点照明技術](https://onetech.jp/blog/unity-3-point-lighting-technology-14973)について説明します。

3点照明技術は、映画館で長い間使用されてきた古典的な方法です。このあまり洗練されていないテクニックは、メインライト（キーライト）、セカンダリライト（フィルライト）、ボーダーライト（リム）/バックライトの3つの光源だけで芸術的に最も必要な詳細で被写体を完全に強調するのに役立ちます。

![3点照明技術（写真:pluralsight.com）](https://onetech.vn/wp-content/uploads/2022/06/Three-Point_Lighting.jpg)

上記のテクニックをUnityで再現した手順は次のとおりです。

**目次**:
1. 3点照明技術とは何ですか？
2. 環境設定
3. すべての外光を排除します
4. メイン光源を設定する（Key light）
5. フィルライト設定 (Fill Light)
6. エッジ光源（Rim/Back Light）
7. 結果
8. ライトデフォルトと3ポイントライティングの比較
9. エンディング

## 3点照明技術とは何ですか？
3点照明技術は、映画館で使用される標準的な照明方法であり、3つの光源のみを使用して合理的で芸術的な方法でオブジェクトを照明するためによく使用されます。

* **キーライト** （メイン光源）：カメラの右側に45度の角度で配置された明るい光
* **フィルライト** ：暗いスポットを含む被写体全体を照らすことができる、あまり明るくないライト。
* **リム/バックライト** ：オブジェクトのすぐ後ろに配置されたもう1つの弱い光源は、バックライトとも呼ばれます。

## 環境設定
ゲームオブジェクトを使用して空のシーンを作成します。この例では、ゲームオブジェクトは円です。4つの周囲の壁を設定し、オブジェクトの前面が見えるようにカメラを設定します。

![環境設定](https://onetech.jp/wp-content/uploads/2022/06/Hinh-1.png)

## すべての外光を排除します

デフォルトのライトや共有環境がないことを確認してください。最初のライトを追加すると、シーン内に他のライトはありません。[照明]->[環境]で、[スカイボックスマテリアル]を[なし]に設定して、すべての光源を削除します。また、UnityシーンのデフォルトのDirectionalLightをオフにします。

![Unityのすべての外部ライトとデフォルトライトを削除します](https://onetech.jp/wp-content/uploads/2022/06/Hinh-2.png)

## メイン光源を設定する（Key light）
キーライト は、被写体に最も強いメインライトを作成し、被写体の最も明るい領域と最も暗い領域を特定するのに役立ちます。キーライトは、太陽、窓、天井のライトなどの主要な光源を表します。メインの光源は通常、ターゲットの左側に45度の角度で配置され、最も強い光を提供し、注ぐことができます。シャドウと強調機能。この場合、キーライトは範囲が10のポイントライトになります。
![Key Light single](https://onetech.jp/wp-content/uploads/2022/06/Hinh-3.png)

## フィルライト設定 (Fill Light)
このフィルライトは、被写体をより見やすくしながら、メインライトによって提供される暗いコーナーの照明を柔らかくして拡大します。フィルライトは、空（太陽ではない）からの光、夜の月光、湖からの光、テーブルランプなどの二次光源、またはシーン内の反射光と反射光をシミュレートできます。二次光源は、カメラの反対側、主光源の反対側に配置され、主光が到達していない部分を明確にし、コントラストを和らげます。

![Fill light and Key Light](https://onetech.vn/wp-content/uploads/2022/06/Hinh-9.png)

## エッジ光源（Rim/Back Light）
リムライト （別名バックライト）このテクニックは、被写体を背景から視覚的に分離するのに役立つ、被写体のエッジの周りに光の線を作成します。リムライトは通常、オブジェクトのすぐ後ろに配置されます。このライトは、被写体を背景から際立たせます。この場合、上部の境界線を明るくするので、離れた場所からスポットライトを使用します 。

![3点照明：Key Light, Fill Light and Rim Light](https://onetech.vn/wp-content/uploads/2022/06/Hinh-8.png)

## 結果
異なる色を使用した3つの光源のイラスト
![結果の画像は3点光を示している](https://onetech.vn/wp-content/uploads/2022/06/Hinh-9.png)
結果の画像は3点光を示している

## エンディング
Unityの3点照明に関連することを理解したので、それは非常に簡単ですよね。このテクニックは、キャラクターへのインタビューやロゴを使ったエフェクトの作成など、主要なテーマで短編映画を作成する必要がある場合に特に便利です。

これは、Unityで再作成した後の私の結果です。この記事が3点照明技術の理解に役立つことを願っています。あなたはより完全なステップを持つことができるようにもっと研究して学ぶことができます。

幸運を！

**参照元：**
* [https://onetech.jp/blog/unity-3-point-lighting-technology-14973](https://onetech.jp/blog/unity-3-point-lighting-technology-14973)
* [https://www.pluralsight.com/blog/film-games/understanding-three-point-lighting](https://www.pluralsight.com/blog/film-games/understanding-three-point-lighting)
Ruby 練習問題４ ~特定条件のみに呼応するプログラムの作成~

こんにちは、プログラミング初学者"fujitacoma"です！

今回は、Ruby練習問題シリーズの4回目です。
Dateクラスを使用し、曜日を呼び出すプログラム問題です！

それでは早速始めます！

# 問題
今日の曜日を表示するコードをDateクラスを使用して記述してください。

ただし、金曜日だった場合だけ以下のように表示の内容を変えてください。

（出力内容）
「今日は月曜日」
「今日は金曜日だ ！！！」

## ヒント
### Dateクラス
DateクラスとはRubyの標準ライブラリの機能です。Dateクラスを使うには以下一文を記述します。
```ruby
require "date"
```
次に、Dateクラスを用いて「今日の曜日」を取得する場合は以下のように記述します。
```ruby
Date.today.wday
```
`wday`は曜日を0(日曜日)から6(土曜日)の整数で取得することができる
Dateクラスに用意されているメソッドです。

たとえば、以下のように使うことができます。
```ruby
require "date"

day = Date.today.wday

puts day
```
これを実行すると、曜日に合わせた数字が出力されます。
たとえば、木曜日だとすれば4が出力されることになります。

これを踏まえて、問題を解いてみましょう！

# 解答と解説

### 模範解答
```ruby
require "date"

day = Date.today.wday
days = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"]

if day == 5
  puts "今日は#{days[day]}だ！！！"
else
  puts "今日は#{days[day]}"
end
```
### 解説
今回はRubyで日付を扱うため、RubyのライブラリにあるDateクラスを使用します。

（1行目）Dateクラスをライブラリから呼び出します。

（3行目）wdayメソッドを用いて曜日を0（日曜日）から6（土曜日）の整数にしたときの「今日」の値を取得します。

（4行目）配列daysを定義し、日曜日（0番）〜土曜日（6番目）まで文字列を格納します。

（6〜10行目）dayの値が5（金曜日）か否かで条件分岐させます。たとえば、今日が金曜日だった場合は`day=5`となり、daysの5番目の値である`金曜日`が出力されるようになります。

# 最後に
いかがでしたでしょうか！

シンプルですが、曜日の呼び出し等細かいところにミスを誘うポイントがありますね。
しっかり引っかかりました。笑
精進します。

ここまでお読み頂き、有難うございました！
c#でlibyara その6

# 概要
c#でlibyaraやってみた。
練習問題やってみた。

# 練習問題
emotet、チェッカーを作れ。

# サンプルコード

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using YaraSharp;

namespace YaraSharp
{
	public class test {
		private static string BaseDirectory = Environment.CurrentDirectory;
		static void Main(string[] args) {
			if (args.Length == 0)
			{
				Console.WriteLine("emoc0 file");
				return;
			}
			string yaraRuleFile = Path.Combine(BaseDirectory, "emotet.rule.txt");
			string yaraInputFile = args[0];
			YSInstance yaraInstance = new YSInstance();
			using (YSContext context = new YSContext())
			{
				using (YSCompiler compiler = new YSCompiler(null))
				{
					compiler.AddFile(yaraRuleFile);
					YSReport compilerErrors = compiler.GetErrors();
					YSReport compilerWarnings = compiler.GetWarnings();
					YSScanner scanner = new YSScanner(compiler.GetRules(), null);
					List<YSMatches> Matches = scanner.ScanFile(yaraInputFile);
					foreach (var Match in Matches)
					{
						Console.WriteLine(Match.Rule.Identifier);
					}
					if (scanner.ScanFile(yaraInputFile).Any(r => r.Rule.Identifier != null))
					{
						Console.WriteLine("hit");
					}
					else
					{
						Console.WriteLine("pass");
					}
				}
			}
		}
	}
}





```

以上。
PIPEでのBlockingとNon Blockingでの挙動の違い調査メモ

# PIPEの概要
* プロセス間通信で使用できる単方向のデータチャンネル
  * PIPEには　`Write側` と　`Read側` がある
  * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169589/12137d43-fd56-fa3d-16d8-ad49f7e345b5.png)
* man page へのリンク→ [PIPE](http://linuxjm.osdn.jp/html/LDP_man-pages/man7/pipe.7.html)
* 名前付きPIPEを用いると、PIPEの識別にファイル名が用いれて便利

# Blocking/NonBlocking
* PIPE への Write/Read の挙動は Blocking と NonBlocking の 選択が行える
    * PIPE を open() する際の引数で `O_NONBLOCK` を指定すると NonBlocking になる
        * man page へのリンク→ [OPEN](http://linuxjm.osdn.jp/html/LDP_man-pages/man2/open.2.html)


### Blocking の特徴
* NonBlocking　に比べて扱いが容易
* open(), read(), write() の関数内から、条件が整うまで戻らない。（Blocking）

### NonBlocking の特徴
* open(), read(), write() の関数内で即時に実行が行えない場合には、関数から即時に抜けてくる。（NonBlocking）
    * 即時に実行が行えない時の処理を自前で実装することが可能

# Read 側での Blocking/NonBlocking での挙動の違い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169589/7774ca6d-8b21-417f-09a7-8346cbd19db7.png)

# Write 側での Blocking/NonBlocking での挙動の違い
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169589/749cf5ef-a96b-9232-61bc-f2b077443674.png)
* Write 側は、相手がCloseした場合に SYGPIPEを受ける
    * 終了するにしても継続するにしても、SYGPIPE時の処理を書くのが良さそう

# NonBlocking でのセオリー
* 名前つきPIPEを作成後、Read側が先にPIPEをopen()する。
    * Read側がPIPEをopen()したのを検知した後、Write側でPIPEをopen()させるのが好ましい。
        * この検知させる仕組みで凝りすぎてもバグの元。。

# 疑問からの調査
### Read側の継続性
* NonBlocking の場合に Write 側が close()　した後に再度　open()した場合には、Read側も 再度open()する必要があるか？
    * 不要だった、Read側は　open（）し直さなくても読み取れる
        * CentOS7で検証した
Well-Architected Frameworkについて（自分用メモ

・Well-Architected Framework
AWSが提唱するクラウド設計・運用のベストプラクティス集。AWSユーザーが、効率よく、コストパフォーマンスが高く、安全で信頼のおけるクラウドシステムを設計するためのサポートを目的としています。

Well-Architected Frameworkには「一般的な設計原則」と、
6本の柱である「信頼性」「セキュリティ」「パフォーマンス効率」「コスト最適化」「運用性上の優秀性」「持続可能性（2021年12月追加）」があります。

「一般的な設計原則」と「6本の柱の設計原則」には、クラウド環境におけるシステム設計のベストプラクティスが書かれており、実現したいシステムを設計原則に基づいて設計することで、AWSサービスをより最適に利用できます。
Well-Architected Frameworkは、技術の進化やAWSサービスの変化に応じて継続的に更新されているので、システムを実装した後も定期的にWell-Architected Frameworkと実装したシステムを見直すことが重要です。

【運用上の優秀性の設計原則】
・運用をコードとして実行する
運用手順をコード化しイベントに対応して自動実行することにより、人為的なミスを抑制できます。

・元に戻すことができる小規模な変更を定期的に実施する
変更作業を小規模かつ元に戻せる作業にすることで、変更に失敗した場合でもユーザーへの影響を極力抑えることができます。

・運用手順を定期的に改善する
定期的な運用手順の見直しと同時に、手順の改良や運用者への周知を行います。

・障害を予想する
障害シナリオをテストし原因を特定する演習を実施することにより、障害発生の原因を除去したり障害による影響を軽減できます。

・運用上のすべての障害から学ぶ
運用上のイベントや障害から教訓を学び、運用の改善を促進します。
Jupyterにおけるipynbとpyファイル。

## 初めに
どうもプログラミング歴3か月、jupyter歴1か月の者です。
今回Jupyret labにおけるipynbとpyファイルの使い分けについて簡単にまとめて行こうかと思います。
私自身よく理解せずに使用しておりましたので。


## 学習

### pyファイル

イメージとしては、VScode等で記入し実行するとターミナルに結果が出力されるものです。
画像は挿入できませんが、コメントとしてメモを残す事は可能です。

#### 特徴

flask等のアプリの中に入れ込むにはpyファイルが適しています。
少なくとも私が試みた結果、ipynbではflaskやコマンドプロンプトの動作が上手く行きませんでした。
webアプリの実装やコマンドプロンプトを組み合わせる際はこちらの方が良いと思います。


### ipynbファイル(IPython Notebook)
Jupyter notebook専用ファイル。フォーマットとしてはJSONで、markdown方式と組み合わせる事も可能。<font color="red">Google Colab</font>もこの形式でexportすると.ipynbで抽出されます。

#### 特徴
- セルが分かれている。
- markdown形式でメモができる。
- 変数を入力するだけで結果が出力される。

セルが分かれていると、ちょっとした値や型を確認したい時とかに気軽に実行できる事が強みです。
<font color="red">pandasやデータ分析､グラフ表示</font>の時には顕著でコツコツ実行して結果を確認しながら進む作業にはピッタリです。


markdownで記入できることも大きな強みです。私は良く勉強やノートにて愛用しております。
セル等の収納機能や画像を挿入する事もできるのでお勧めです。

![2022-07-13_12h22_15.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2719278/c6fe71c1-708f-8e21-32f5-2354db2018d7.gif)

また、変数を入力するだけで結果が表示されるのでその機能も慣れると凄く便利です。

![2022-07-13_12h23_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2719278/5f49374f-d8b9-55aa-27cf-5172a2604450.png)




### 両方表示させる。

両方Jupyterで表示させることもできます。
追記：VSコードでも同様に表示させることが可能です。
pyファイルとcmdをJupyterで表示できる事を知っていれば、普段Jupyter lab派のような私でもwebアプリ開発に対してのハードルが多少なりとも下がるのではないでしょうか。私はlabでアプリ開発を実装できました。

![2022-07-13_12h56_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2719278/41724cbb-bb6f-9467-79c8-5cab6c906e99.png)


![2022-07-13_12h44_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2719278/2112f497-47d2-7964-5a30-ba2845b43420.png)



## 終わりに。

この度ウェブアプリ開発にてpyファイルを扱う事をきっかけに記事を書きました。
比較してみるとpyファイルの特徴がいまいち掴み切れていない嫌いがあります。そこを少しづつ改善できればと。

### まとめ

ipynbは確かに勉強やpandas,データ分析には最適だが、webアプリ開発にはpyファイルの方が適している。おそらくpyファイルでないと出来ないと思われる。
そしてJupyter labはipynbとpy&cmdを作成かつ表示できるのでやはり便利である。



### 参考サイト

- https://python.atelierkobato.com/py/#:~:text=ipynb%20%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AF%20Jupyter%20notebook,Python%20%E5%AE%9F%E8%A1%8C%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%A7%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82
- https://blog.tsurubee.tech/entry/2016/05/11/201337#%E3%83%8E%E3%83%BC%E3%83%88%E3%83%96%E3%83%83%E3%82%AF%E3%82%92%E5%85%B1%E6%9C%89%E3%81%A7%E3%81%8D%E3%82%8B
- https://whatext.com/ja/ipynb
Cypy のFFTでOut of memory errorになる件はcacheが原因だった

# 環境
Winpython
WPy64-31040

# 現象
CupyでFFTを使用すると、del で変数を消してメモリーを確保したはずなのにメモリーエラーが発生する。

# 原因
chacheが残っているためだった。
https://docs.cupy.dev/en/stable/user_guide/fft.html

# 解決方法
**キャッシュの確認** 

import cupy as cp

cache = cp.fft.config.get_plan_cache()
cache.show_info()
------------------- cuFFT plan cache (device 0) -------------------
cache enabled? True
current / max size   : 1 / 16 (counts)
current / max memsize: 8564793344 / (unlimited) (bytes)
hits / misses: 0 / 1 (counts)

cached plans (most recently used first):
key: ((1023, 1023, 1023), (1023, 1023, 1023), 1, 1, (1023, 1023, 1023), 1, 1, 41, 1, 'C', 2, None), plan type: PlanNd, memory usage: 8564793344


chached plans になにやら残っている

**キャッシュの削除** 

cache.clear()


cache = cp.fft.config.get_plan_cache()
cache.show_info()
------------------- cuFFT plan cache (device 0) -------------------
cache enabled? True
current / max size   : 0 / 16 (counts)
current / max memsize: 0 / (unlimited) (bytes)
hits / misses: 0 / 0 (counts)

cached plans (most recently used first):
PCの周辺知識まとめ（備忘録）

こんにちは、プログラミング初学者"fujitacoma"です！

前回更新から数日空いてしまいました、、
3日坊主にならないように気合を入れ直して投稿します！
何事も継続が大事！！

先日、PCの周辺知識について学ぶ機会がありましたので、
今回はそのまとめを備忘録として書き残しておきたいと思います。

それでは早速参りましょう！

## 1.  OS
 「Operating System（オペレーティングシステム）」の頭文字を取ったもので、 ユーザーとハードウェアの間や、アプリケーションとハードウェアの間をつなぐ役割を持つ。 PCにおけるOSで代表的なものはWindowsとMac OS、スマートフォンではiOSとAndroidがある。 

## 2.  CPU
 「Central Processing Unit（セントラルプロセッシングユニット）」の頭文字を取ったもの。別名、プロセッサー。 コンピューターでは制御と演算を担当し、周辺機器からのデータの受け取りや、メモリやHDD(SSD)などに命令を出す役割を持つ。 

## 3.  HDD 
「Hard Disk Drive（ハードディスクドライブ）」の頭文字を取ったもの。 コンピューターでは補助記憶を担当し、データを保存する役割を持つ。 PCでは主に、OSやアプリケーションがインストールされたシステムドライブや、作成したデータなどを保存する データドライブとして使われている。 

## 4.  SSD 
「Solid State Drive（ソリッド・ステート・ドライブ）」の頭文字を取ったもの。 コンピューターではHDDと同様に補助記憶を担当し、データを保存する役割を持つ。 PCでは主に、OSやアプリケーションがインストールされたシステムドライブや、作成したデータなどを保存するデータドライブとして使われている。 

## 5.  メモリ
 データやプログラムを一時的に記憶する部品を指し、コンピューターでは主記憶を担当する。 HDDやSSDを本棚とすると、メモリは作業台(テーブル)の役割を持つ。 

## 6.  マザーボード　
 PCの中に必ず入っている基盤のこと。メインボードやシステムボードとも呼ばれる。 CPUやメモリ等の様々なパーツが複雑な回路によって接続されており、パーツ間の橋渡しをする役割を持つ。 

## 7.  BIOS
 「Basic Input Output System（ベーシックインプットアウトプットシステム）」の頭文字を取ったもの。 PCに搭載されたハードウェア（キーボード、マウス、HDD、メモリ、CPU等）の管理と制御をする役割を持つ。 

## 8. ドライバ
 内蔵機器やデバイス、周辺機器等を使用できるようにするソフトウェアのこと。別名、デバイスドライバ。 OSと機器をそれぞれ歯車とすると、ドライバは潤滑油として橋渡しをする役割を持つ。 

## 9.  GUI
 「Graphic User Interface（グラフィックユーザーインターフェース）」の頭文字を取ったもの。 グラフィックや図表（graphic）により、ユーザーとコンピューター間での情報のやり取りの仲立ちをする役割を持ち、 ほとんどのデジタル機器や各種アプリケーションはGUIに該当する。 

## 10.  CUI 
「Character User Interface（キャラクターユーザーインターフェース）」の頭文字を取ったもの。 文字（Character）により、ユーザーとコンピューター間での情報のやり取りの仲立ちをする役割を持つ。 代表的なものとして、WindowsのコマンドプロンプトやMac OSのターミナルが挙げられる。 

## 11.  拡張子 
ファイルの種類を識別するために使われるファイルの末尾にある「ドットで区切られた右側の英数字1～4文字」のこと。 代表的なものとして、”.jpg” , ”.pdf” , ”.txt” , ”.html” , ”.css” 等が挙げられる。 

## 12.  ミドルウェア
 OSとアプリケーションの橋渡しとして、サーバやデータベースとのやり取りなど複雑な処理を行うソフトウェアのこと。 WEBサーバ、アプリケーションサーバ、データベース管理サーバの3種類がある。

# 最後に

いかがでしたでしょうか！

聞いたことはあるけど知らない、
知っていたようで知らなかった、
といったことばかりで、とても勉強になりました！


このまとめが誰かの学習の手助けになると幸いです。
とか、ちょっとしおらしく締めてみる。笑

ここまでお読み頂き、有難うございました！
【Rails】テーブルの作成手順

Railsでテーブルを作成する機会があったので、自分でやったやり方をまとめる。

## ①コマンドを実行

```
$ rails g model Test(任意のモデル名)
```
※`g`はgenerateの略。
間違えた場合は
```
rails d model user(任意のモデル名)
```

で削除できる。

コマンドを実行すると、以下ファイルが自動で作られる。
①モデルのクラスファイル（app/models配下に作られる）
②マイグレーションファイル(db/migrate配下に作られる）
③テスト系のファイル（この辺は導入しているテストツールで異なる？）

## ②マイグレーションファイルを編集

生成されたマイグレーションファイルを修正し、テーブルの中身のカラムを作成するため設定をしていきます。
マイグレーションのファイル名は、生成日時が自動でつき、コマンドで実行したモデル名の複数形で名前がつきます。
例：`20220711090757_create_tests.rb`

```Ruby
class CreateTests < ActiveRecord::Migration[6.1]
  def change
    create_table :tests do |t|
      # ここから下に設定したい内容を記載していく
      t.string :name, null: false
      t.integer :status, null: false
    end
  end
end
```
カラムには、id、created_at(作成日時)、update_at(更新日時)は自動で設定されるため
改めてここで設定する必要はない。

基本的にはこの後マイグレーションを実行して、この内容でマイグレーションされるので
その後にカラムを追加したい場合などは、下記コマンドを実行することになる。
```
$ rails g migration AddImageToTests name:string
```
`Add Image`で追加したいカラム名、`ToTests`でカラムを追加したいテーブル名を指定します。
※テーブル名の指定は複数形で。


削除したい場合はAddをRemoveに変える。
```
$ rails g migration RemoveImageToTests name:string
```

## ③モデルファイルを編集

生成されたモデルファイルを編集して制約などを設定します。

```Ruby
class Test < ApplicationRecord
  # ここから下に設定したい内容を記載していく
  has_one :profile

  has_many :tweets

  belongs_to :user

  with_options presence: true do
    validates :name
    validates :status
  end
end
```
`has_one`などの設定は、作成したテーブルを他テーブルと関連付けたい時に設定する。

`has_one`・・・他テーブルとの関連の対象が１つ（単数形で記述）
`has_many`・・・他テーブルとの関連の対象が複数（複数形で記述）
`belongs_to`・・・このテーブルが他テーブルに所属している（単数形で記述）

あとはvalidateなどの設定があれば記述する。

## ④マイグレーションを実行
```
$ rails db:migrate
```
マイグレーションを実行するコマンドを入力。
これでマイグレーションファイルに設定した内容で、テーブルとそれに付随するカラムが作成された。



## 補足
マイグレーション実行後にカラムなどの内容を変更したい場合。
（※マイグレーションファイルの削除は絶対にやってはいけない！）

```
$ rails db:migrate:status
```
コレで現状のマイグレーションの状況が確認できるので、バージョンを確認する。
```:実行結果
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20220711042708  Create users
   up     20220711051028  Add email to users
   up     20220711055028  Create tweets
   up     20220711090757  Create tests
```

下記のコマンドを実行すると、データベースの状態が最新のmigrationファイルを実行する前に戻る。
`STEP=1`は、１つ前のバージョンに戻す。もしくは戻したいバージョンのMigration　IDを指定する。
```
$ rails db:rollback STEP=1

もしくは

$ rails db:migrate VERSION=20220711055028
```
```:実行結果
== 20220711090757 CreateTests: reverting ==============================
-- drop_table(:tests)
   -> 0.0160s
== 20220711090757 CreateTests: reverted (0.0288s) =====================
```

これで再度`rails db:migrate:status`すると、マイグレーションしたファイルがdownになっていることがわかる。

```:実行結果
$ db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20220711042708  Create users
   up     20220711051028  Add email to users
   up     20220711055028  Create tweets
  down    20220711090757  Create tests
```

この状態でマイグレーションファイルを編集し、再度`rails db:migrate`すれば、
変更した内容でマイグレーションが実行される。
**基本的にこの方法はデータベースに反映済みの場合はやってはいけない。**
【Next.js】@types/reactが認識されない場合の対応方法

# 概要


`@types/react 18.0.2` をインストールしたが認識されない事象があったので対処方法をまとめる


https://github.com/vercel/next.js/issues/36085

```bash
It looks like you're trying to use TypeScript but do not have the required package(s) installed.

Please install @types/react by running:

        yarn add --dev @types/react

If you are not trying to use TypeScript, please remove the tsconfig.json file from your package root (and any TypeScript files in your pages directory).
```

# `@types/react`をダウングレードする

`issues`の通りだが`18.0.2`にバグがあるらしくダウングレードすることで正常化するとのこと


```bash
npm install --save-dev @types/react@18.0.1
```
macOSで `ctype.h` が無いと言われた時

個人的なメモ。

# 具体的な症状
- とあるpythonパッケージを `pip` を通しインストールしようとした際に、下のように、 `ctype.h` が無いと言われた。
    - インストールしようとしたパッケージは、`smt` というパッケージ。
    - pythonは、`homebrew` を通し `Miniforge` でインストールした。

```
/opt/homebrew/Caskroom/miniforge/base/bin/../include/c++/v1/ctype.h:38:15: fatal error: 'ctype.h' file not found
      #include_next <ctype.h>
                    ^~~~~~~~~
      1 error generated.
      error: command '/opt/homebrew/Caskroom/miniforge/base/bin/clang' failed with exit code 1
      [end of output]
```

# 解決策
https://qiita.com/Rascal/items/b92d94631adfbd19522a

上記記事の様に、`export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"` とすればよい。
論理演算とベン図

# コンピュータの回路を知る
コンピュータの中は論理回路の組み合わせでできている。
これらを組み合わせで複雑な処理を行なっている。
電気を流がすとリレーの磁力で鉄編が引き寄せられて全体に電気が流れる。
リレーはオン、オフがあり、１、０もこれで表現できる。

## 気づき
リレーが１、０の役目を果たすのか。
つまり論理式について学んでいくのかな。

# 論理演算とベン図
論理演算というのは1と０の２つの値だけで行う演算。
```1```が真(True)
```0```が偽(False)

論理演算は```AND```,```OR```、```NOT```が使われる演算のこと。

# 論理演算はベン図を使う
図で表して集合同士の関係を、図として視覚的に表したものです。

# 論理積(AND):かつ
２つある条件の、両方が合致するのものを真とみなす。
AかつB

# 論理和(OR):または
２つある条件の、いずれかが合致するのもを真とみなす。
AまたはB

# 否定(NOT):ではない
ある条件の「合致しない」ものを真とみなす。
Aではない

出典 キタミ式イラストIT塾　基本情報技術者令和０３年
Zoom Meeting SDKをつかって会議にアバターで参加する

# はじめに
ZoomがSDKを提供しはじめたということで盛り上がりを見せている昨今ですが、Qiitaでも盛り上げイベントが開催されています。SDKでいろいろ遊ばせてもらえる上に、アイテムもゲットできるかも、ということで参加するしかないですね。

ということで、これを機にいろいろ実験してみたのですが、面白そうなことがたくさんできそうだったので、いくつか連投する予定です。ご興味を持たれましたら、後続の投稿もご覧ください。


第１回の記事はこちら⇒[Zoom Meeting SDKでタイムキーパーちゃんを作る](https://qiita.com/wok/items/205c086f19a7ff73718d)
第２回の記事はこちら⇒[Zoom Meeting SDKでアバターにいろいろしゃべらせる](https://qiita.com/wok/items/0450c8620f11a371bd8b)
第３回の記事はこちら⇒[Zoom Meeting SDKをつかって会議にアバターで参加する](https://qiita.com/wok/items/1bccd567e844ac4e8979)　**←本記事**
第４回の記事はこちら⇒[Zoom Meeting SDKでなんちゃってボイスチェンジャー](https://qiita.com/wok/items/08c9505d5c3c95d8956d)
番外編の記事はこちら⇒[Zoom Meetingにアバターで参加するぞ。番外編](https://qiita.com/wok/items/4f51e1a72d735b75f73f)
第５回の記事はこちら⇒[Zoom Meeting SDKとVosk browserでZoom会議のリアルタイム文字起こし](https://qiita.com/wok/items/e83c49c530354a7b8b42)


前回までは時報ちゃんはボットとして会議に参加していたのですが、今回はユーザの表情をキャプチャして時報ちゃんの動きに同期させるようにします。これで、アバターを使って会議に参加できますね。
完成品は↓こんな感じです。今回は音声を使わずハウリングの心配がないので、参加者の画面を横に並べてみました。
（ここでは、カメラ映像の代わりに動画を用いてます。カメラ映像と動画の両方サポートしています）。

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

AIで表情やポーズを認識しているのでアラはありますが、それなりによく動いていると思います。特に顔の表情の読み取りはかなりよくできているので、顔だけキャプチャするようにしてもいいかもしれません。

とりあえず、Dockerイメージにしているので、ダウンロードして使ってみてください。
なお、音声を使いたい場合は引き続き、[VoiceVox](https://voicevox.hiroshiba.jp/)と[OpenTTS](https://github.com/synesthesiam/opentts)も起動してください。詳細は前回の記事を参照ください。

```
$ docker run -p 8888:8888 dannadori/zoom-meeting-plus:v03
# ↓オプション
$ docker run --rm -it -p '127.0.0.1:50021:50021' voicevox/voicevox_engine:cpu-ubuntu20.04-latest
$ docker run -it -p 5500:5500 synesthesiam/opentts:en
```

http://localhost:8888/ にアクセスすれば使えるようになります。
なお、httpで起動しているのでローカルで使用する必要があります。

操作は次の通りです。

![image](https://user-images.githubusercontent.com/48346627/178626982-de2abdd3-ac55-46c0-beae-0e7ee616b0fb.png)


![image](https://user-images.githubusercontent.com/48346627/178627226-5fce6d7c-fd1e-4980-8e4e-5a283b74219e.png)


# 構成
前回までにご紹介してきた構成に画像処理機能を追加しました。画像処理の結果をAvatarに反映させています。画像処理ではMediapipeのモデルを使用しています。ただし、公式のMediapipe JavaScript Solutionsは現時点ではWebWorkerでは動きません([参考](https://github.com/google/mediapipe/issues/2506))。このため、独自にWebWorkerで動かす部分を作成しています。(この処理については、[こちらのリポジトリ](https://github.com/w-okada/image-analyze-workers)をご参照ください。)実装は公式からは公開されていないため、一部推測で実装しているところがあります。これが少し画像認識の結果がぶれる原因の一つかと考えています。要改善ですね。（というか、公式で出してほしい。）

![image](https://user-images.githubusercontent.com/48346627/178627869-89789c3d-4a06-470d-bcfe-4497b153e977.png)


# デモ
記事の冒頭で示した通りです。

# リポジトリ
ここで紹介したデモは次のリポジトリで公開しています。
https://github.com/w-okada/zoom-meeting-plus

どんどんアップデートしていくので最新版は安定しない可能性があります。
次のタグでcloneして使ってください。
```
$ git clone https://github.com/w-okada/zoom-meeting-plus -b v03
```

# 宣伝
弊社 FLECT は、Salesforce を中心に AWS, GCP, Azure を用いたマルチクラウドシステムの提案、開発を行っております。 また、ビデオ会議システムについては、Zoom SDK, Amazon Chime SDK, Twillio など各種ビデオ会議用 SDK を用いたシステムの開発しており、サービス化の実績も多数あります。 ご興味をお持ちいただけたら是非ご相談ください。
Teamsをリンク（Web）で開こうとしたら白い画面になったときの解決方法（2022.7/13）

リンクを使用してTeamsに参加しようとしたら白い画面になり、Teamsに参加できなくて焦りました。

◆解決方法
Cromeの設定＞リセットとクリーンアップ＞設定を元の既定値に戻す＞（確認）設定のリセット

◆リセット内容
• Chrome の設定と Chrome のショートカットがリセットされます
• 拡張機能が無効になります
• Cookie や他の一時的なサイトデータが削除されます
ブックマーク、履歴、保存したパスワードへの影響はありません。


入れなくなった切っ掛けは、たぶんZoomだと思いますが、原因は不明です。
OpenSSLに脆弱性が見つかったので自分でコンパイルした

yumでしかパッケージをインストールしたことがなかったので、かなり苦労しました。

# 1. ソースをダウンロード
https://www.openssl.org/source/

真ん中あたりにtarファイルのリンクがあるので、ダウンロードする。
今回は最新の「openssl-3.0.5.tar.gz」を使用した。

# 2. 解凍
任意の場所にtarファイルを配置し、解凍する。

```shell
tar xzf openssl-3.0.0.tar.gz
```

# 3. ディレクトリに入ってconfig

```shell
cd openssl-3.0.0

./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl -static zlib
```

# 4. make install
```shell
make 

make install
```

## エラーが起きた場合
自分はこんなエラーが出ました。
```
/bin/ld: cannot find -lz
/bin/ld: cannot find -ldl
/bin/ld: cannot find -lpthread
/bin/ld: cannot find -lc
```
コンパイルで使用するライブラリが不足しているもよう。
色々インストールしました。
```shell
yum install zlib-devel

yum install glibc-devel

yum install glibc-static 
```

コンパイルに成功すると、configで指定した「/usr/local/ssl/bin/openssl」にファイルが出来上がります。

# 5. バージョン確認
```shell
/usr/local/ssl/bin/openssl version
```
3.0.5 と表示されれば成功。
Python tkinterで作業記録用のタイマーを作成

## 背景<br>
PCで複数の作業を行う際に各作業に何時間かかっているかを計測したくて
Tknterを使用してタイマーアプリを作成してみた。

## デモ画面
![デモ画面.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/158871/af9badd6-aefa-dc44-fd83-f8e7bfd1ff87.gif)

誤操作防止の為、ResetボタンはStopボタンがクリックされるまで無効化している。
また、Startボタンはクリック後、無効化しStopボタンクリック後に有効化されるように
している。

## コード内容
GitHubのリポジトリはこちらになります。
https://github.com/yuuta-git12/TimeManagement_App
heroku デプロイ方法（Spring）

# 事前準備
- [Herokuアカウントの作成](https://signup.heroku.com/)
- [Heroku CLIのインストール](https://devcenter.heroku.com/ja/articles/heroku-cli)
- [Gitのインストール方法](https://qiita.com/ryome/items/44a274d6eb4ef78f6344)

事前準備として、上記リンクの内容が必要です。

# heroku デプロイ方法（Spring）

1. コマンドプロンプトを開く
2. herokuにログインを行う
    ```
    heroku login
    ```
3. 資材をフォルダに配置する
    ※ サンプルプロジェクトはGitHubに公開されています。
    ```
    git clone https://github.com/heroku/java-getting-started
    cd java-getting-started
    ```
4. Gitリポジトリを新規作成する
    ```
    git init
    ```
5. `.git/config` を開き、以下を追加
    ```
    [remote "heroku"]
      url = https://git.heroku.com/[app名].git
      fetch = +refs/heads/*:refs/remotes/heroku/*
    ```
6. 資材をインデックスに追加する（コミットの対象にする）
    ```
    git add .
    ```
7. インデックスに追加した変更をリポジトリに記録する
    ```
    git commit -m "コメント"
    ```
8. Herokuアプリを作成する
    ```
    heroku create
    ```
9. ローカルリポジトリの変更内容をリモートリポジトリに送信する（デプロイ）
    ※エラー時は [エラー対処](#エラー対処) へ
    ```
    git push heroku master
    ```
10. アプリにアクセスする
    ※エラー時は [エラー対処](#エラー対処) へ
    ```
    heroku open
    ```
11. ログの監視を行う
    ```
    heroku logs --tail
    ```

---

# エラー対処

## failed to push some refs to 'https\://git.heroku.com/[app名].git'

```
error: failed to push some refs to 'https://git.heroku.com/[app名].git'
```

上記エラーが出た場合、最新でない可能性があるため、以下コマンドを実行

```
git pull origin
```


## Multiple apps in git remotes

```
 »   Warning: heroku update available from 7.53.0 to 7.59.0.
 »   Error: Multiple apps in git remotes
 »     Usage: --remote origin
 »        or: --app [app名]
 »     Your local git repository has more than 1 app referenced in git remotes.
 »     Because of this, we can't determine which app you want to run this command against.
 »     Specify the app you want with --app or --remote.
 »     Heroku remotes in repo:
 »     [app名] (heroku)
 »   [app名] (origin)
 »
 »     https://devcenter.heroku.com/articles/multiple-environments
```

上記エラーが出た場合、以下コマンドでorigin以外は削除

```
git remote -v
git remote rm <名前>
```

---

# その他コマンド

- postgresql追加
```
heroku addons:create heroku-postgresql
```

- 環境変数を確認
```
heroku config
```

- 環境変数を設定
```
heroku config:set 環境変数名=値
```
```
heroku config:set 環境変数名1=値1 環境変数名2=値2
```

- 詳細情報を確認
```
heroku pg
```

# 参考文献

https://devcenter.heroku.com/ja/articles/deploying-spring-boot-apps-to-heroku#preparing-a-spring-boot-app-for-heroku

https://devcenter.heroku.com/ja/articles/connecting-to-relational-databases-on-heroku-with-java

https://devcenter.heroku.com/articles/build-docker-images-heroku-yml#run-defining-the-processes-to-run

https://devcenter.heroku.com/ja/articles/getting-started-with-java#-3

https://github.com/heroku/java-getting-started

https://qiita.com/mzmz__02/items/64db94b8fc67ee0a9068
野良PWAを生成するサイトを作りました

# これはなに？

[野良PWA](https://nora-pwa.laser5.net/)
このサイトについて説明していきます。

# 前回のあらすじ

https://qiita.com/m-m-n/items/504f10c147e800f436cd

https://qiita.com/m-m-n/items/8c3a6385627284fa9ee0

前々回、前回とPWAでインストールしたアプリをコマンドラインで立ち上げる方法と、PWAに対応していないサイトをPWAにするアイデアを紹介しました。

# 今回やったこと

野良PWAを簡単に作れるサイトを作りました！

さっそく使い方を見ていきましょう。

# 使い方

## トップページ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/9ef4b42d-a86d-8e66-544c-8440f5eedd59.png)
殺風景ですね。
サンプルとしてGoogleを登録してあります。

## カードをクリックする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/28fe89bc-3c3a-c6f8-966a-dfd79a375e7f.png)
さらに殺風景なページに遷移しましたね。

このページをPWAとしてインストールします。

## インストールする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/3588fc08-e180-fe0b-c6d7-2f5aae21658d.png)
Google Chromeの場合、アドレスバーの右側がこんな感じになっているかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/5ef0113f-49e9-e54c-725e-fe14b18151bd.png)
PCに落とすような雰囲気を感じるアイコンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/f8a0bbfe-5a57-d3a5-de2d-cd0582f109e4.png)
するとインストールするか聞かれますので、「インストール」をクリックしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/5f227bab-eac6-f647-0921-9dfa8297485c.png)
いや、まぁこうなりますよね。
一旦閉じましょう。

## アプリを開く

Google Chromeの場合、アドレスバーに `chrome://apps/` と入力するとアプリ一覧が表示されます。
この中に先程インストールしたPWAのアプリがあるのでクリックすると以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/2575215f-9616-af94-c73a-2e257492d3f1.png)
グーグルが開きました。
どうしてこうなるかについては前回の記事を参照。

ちなみにスマホでインストールするとホーム画面やドロワー内にアプリストアからインストールしたアプリと同様にアイコンが並ぶと思います。
ブラウザのショートカットを作るとホームには置けるがドロワーには存在しないと思いますが、これがスマホでPWAインストールするかなりのメリットになるかと思います。
ショートカットから起動するとブラウザの新規タブで開きますしね……

## サイトを追加する方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/8de44458-2a5f-28a8-7719-c0d2e163f70e.png)
右下にあるフローティングアクションボタンをクリックします。

### 追加ページ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/f7d2a9f6-eda6-6f8c-c785-644b31de2d94.png)
必要な項目を埋めていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/426191/cc97e18f-2625-b4ad-9f73-e628529c8449.png)
こんな感じにPWA化して開きたいURLを「リダイレクト先」に指定します。
アプリ名、テーマカラーはご自由に。

### 保存する

あとは保存ボタンを押して無事に保存されればトップページにカードが追加されます。
カードが追加されましたら、先述の方法でインストールして完了です。

# システムについて
- OS
    - Linux (Ubuntu)
- Webサーバー
    - Nginx
- フロントエンド
    - Flutter
- バックエンド
    - Node.js
    - PHP

# 雑感
Flutter初めて触りましたが簡単にマテリアルデザイン作れて良いですね。
Dartは最近良く触ってますがDartという感じがなく、もうFlutterだよねこれ……という感じがします。

NginxでPHP動かすのが面倒だったのでサーバーサイドはNodeで待ち受けてPHPのプロセス立ち上げる手抜き仕様です。
野良PWAのアイデア自体は大分前からあったので、その時にPHPで作ったスクリプトがあり流用した結果となります。
新規で作るならサーバーサイドもDartで書くかもしれない。

あとは大分雑に作ってるので色々おかしい部分があるかもしれません。

PWAに対応していないサイトもスマホにインストールできるようになるし、PCからは前々回の記事のやり方でターミナルからコマンド叩いてPWAのサイトが起動するようにできるし、色々と捗ります。
公式がPWAに対応してる場合はこのシステムを使う理由が皆無ですので素直に公式を入れましょう。
また、スマホでアプリ版が存在する場合も素直にアプリを使う方が良いでしょう。

---

それでは良いPWAライフを。

# 採用PR

株式会社viviONでは一緒に働く仲間を募集しております。
オタク文化を盛り上げたいWebエンジニアのご応募お待ちしております！

https://hrmos.co/pages/vivion/jobs/0000191

Devトークもあります！

https://plus.jobs.qiita.com/dev-talk-company-pickup-vivion/
Salesforceの手動共有を確認しよう

こんにちは。

Salesforceではレコードを「誰に見せるor見せない」設定がいくつかございます。
今回はその中でLightning環境の「手動共有」のボタンの表示について見ていきましょう。


## 前提　手動共有ってなに?
手動共有とはページレイアウト上に「共有」ボタンを配置することにより、ユーザが特定のレコードを誰に見せるか。を設定できる共有方法です。
なお、SalesforceのClassic環境では昔からあった設定ですが、Lightning環境で導入されたのは意外と最近（Spring '21 リリース）です。

手動共有ができるオブジェクトは限られていて、取引先、商談、ケース、取引先責任者、リード、カスタムオブジェクトでのみ設定可能です。
![手動共有１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/5b534bf3-444c-7300-399d-361a75e4c84b.png)


※参考ヘルプ
手動共有を使用したレコードの共有
https://help.salesforce.com/s/articleView?id=release-notes.rn_forcecom_manual_sharing_lex.htm&type=5&release=230


## 前提　手動共有の設定方法

まずは使用しているページレイアウトに「共有」を設定します

Lightning環境の場合
・Salesforce モバイルおよび Lightning Experience のアクション
に「共有」を設定します
![共有テスト１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/493e0a29-a1e9-1482-c017-bb9fd3857d7b.png)

もしもシステム管理者の場合、上記のようにページレイアウトに「共有」が設定されていれば、ページから「共有」を確認することが可能です。
![共有ボタン２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/65ceb487-5e4c-4e53-6728-5633ef56517f.png)

もしもシステム管理者ではない場合、ページレイレイアウトに「共有」が設定されていてもページから「共有」を確認できない場合があります。

それは、対象オブジェクトのレコードまたは関連レコードの共有モデルが「非公開」または「公開/参照のみ」ではない場合です。
一例をあげれば、共有設定で
取引先および契約が「公開/参照・更新可能」な場合、（商談も「公開/参照・更新可能」な場合）
取引先のレコードまたは関連レコードの共有モデルが「非公開」または「公開/参照のみ」ではないのでシステム管理者以外のユーザは取引先で「共有」ボタンを確認することはできません。
その場合、例えば取引先を「非公開」に設定すればシステム管理者以外のユーザにも「共有」ボタンが確認できます。

![共有設定について確認２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/876775c2-4ba2-f42d-8349-d3e87dfe140f.png)

もしもシステム管理者以外のユーザで「共有」ボタンが確認できない場合は、共有設定の確認をおこないましょう


※参考ヘルプ
Salesforce Classic でレコードの [共有] ボタンが表示されないのはなぜですか?
https://help.salesforce.com/s/articleView?id=sf.faq_general_why_cant_i_see_the_sharing.htm&type=5

（上記ヘルプについて、ヘルプのタイトルが「Salesforce Classicで～」と記載ありますが、Lightning環境でも見る価値のあるヘルプ差と思います。）
OpenCV で (-212:Parsing error) Failed to open NetParameter file: xxx.cfg in function 'readNetFromDarknet' が発生したときに確認すること

## はじめに

OpenCV は画像処理ライブラリです

簡単に画像加工が行え、画像データを行列（numpy array）として扱えるため、機械学習でもよく使います

https://opencv.org/

バージョン 3.3 からは DNN (Deep Neural Network) モジュールが追加され、
OpenCV で機械学習モデルを使った推論が実行できるようになりました

readNetFromDarknet や readNetFromTensorflow などによって、
他の機械学習ライブラリで学習したモデルを読み込んで使うことがきます

## エラー内容

先日、以下の記事でやったのと同じように、Docker コンテナで AWS の Lambda 関数を作っていた時のこと

https://qiita.com/RyoWakabayashi/items/0734f7f0a76a5dad3770

今回は Darknet で学習したモデルを OpenCV で動かそうとしていました

https://pjreddie.com/darknet/

以下のようなコードでロードするようにしていました

```python
self._net = cv2.dnn.readNetFromDarknet(cfg_path, weights_path)
```

しかし、デプロイした Lambda 関数を実行すると、以下のようなエラーが返ってきました

```
error: OpenCV(4.6.0) /io/opencv/modules/dnn/src/darknet/darknet_importer.cpp:210: error: (-212:Parsing error) Failed to open NetParameter file: xxx.cfg in function 'readNetFromDarknet'
```

## 調査

とりあえず、エラーメッセージで検索すると OpenCV の GitHub Issue が引っ掛かりました

https://github.com/opencv/opencv/issues/10160

読んでいくと、エラーの原因はどちらかのようです

- `.cfg` ファイルのパスが間違っている
- `.cfg` ファイルが破損している

ローカルで動作することは確認済なので、 `.cfg` ファイルは問題ないはずです

パスも確認しましたが、何回確認しても間違っていません

Docker で配置した場所に確かにファイルは存在しているし、パスの指定も一字一句相違ありません

ローカルの Docker 上で動かしてもエラーは発生しません

エラーになるのは Lambda で実行したときだけです

一体なぜ、、、？

## 原因

勘の良い方、 Lambda に詳しい方はすでに原因がわかったと思いますが、、、

原因確認のため、コードで当該パスに `ls -al` をかけると、、、

```
-rw------- 1 root root      8347 Jul  7 02:44 xxx.cfg
-rw------- 1 root root 246326928 Jul  7 02:48 xxx.weights
```

はい、所有者（root）には `rx` で読み書きの権限が与えられていますが、
それ以外には一切権限がありません

Lambda 関数では、 root ではない特別なユーザー `sbx_userNNNN` が使用されます

そのため、 root にしか権限のないファイルを読み込めなかったわけです

ローカル実行では所有者=自分だったためエラーが発生せず、
ローカルの Docker では root ユーザーで実行していたためにエラーが発生しませんでした

## 解決方法

確実にコンテナ内で権限を与えたいので、 Dockerfile に以下の一文を加えます

```Dockerfile
RUN chmod -R +r <.cfg や .wrights の配置されたディレクトリー>
```

`-R` でディレクトリー配下のすべてのファイルを対象として、 `+r` で全員に読み取り権限を与えています

## おわりに

権限不足という超基本中の基本が原因でした:sweat_smile:

エラーメッセージに `Permission denied` くらい出してほしいけど、、、

結論として、 OpenCV で `Failed to open NetParameter` エラーが出た場合は、
以下の点を確認してください

- ファイルのパスは正しいか = 指定した場所にファイルがあるか
- ファイルの権限は正しいか = 実行ユーザーに読み取り権限があるか
- ファイルは破損していないか = ファイルの形式、内容が正しいか
「Dataiku」のExecution Engines機能について

## 膨大なデータの処理に困ったことありませんか？

はじめに、この度は本ブログを読んでいただき誠にありがとうございます。
よろしければ最後まで読んでみてください。

現在ではデータという存在は必要不可欠な存在になっています。その存在は１日経つ度に大量に生まれてきます。
そんな中、データを扱っている業務の中で以下のような問題に遭遇したことはありませんでしょうか？

・膨大なデータを高速に処理したい
・データ量の加工に時間がかかる
・データ量が多く処理が重い

上記の課題以外にもデータの加工や処理速度の問題に遭遇したことがあると思います。

本ブログは「ある機械学習ツール」を使うと、上記の問題を解決できる方法を紹介したいと思います。
最後までよろしくお願いいたします。

## 機械学習ツール「Dataiku」

前章を読んでいただいて、ふと疑問が思い浮かんだ方や「あれ？おかしくない？」と思った方もいらっしゃるのではないでしょうか？

・普通、データ加工するならデータベースを使用するのに、どうして機械学習ツールを使うの？
・機械学習ツールで本当に解決できるの？

そう思った方もいると思います。
安心してください！私も最初は思いました👍

ですが、ある機械学習ツールを使用すると上記の問題を解決することができるのです。


ある機械学習ツール、その名は……Dataiku（データイク）です！！！！

聞いたことない人もいると思いますので、簡単に説明したいと思います。

Dataikuとは、データ準備からデータ加工、AutoML（機械学習）、デプロイまでの一連の流れを1つのプラットフォームで行うことができるツールとなります。（Dataikuについて詳しい説明は本ブログ最後にリンクを貼りますので、そちらをクリックしてください。）

今回はDataikuの機能にありますExecution Engines機能、こちらが前章の問題を解決してくれる機能となりますので、次章から説明したいと思います。

## Execution Engines機能

まずDataikuは機械学習ツールです。このDataikuは多種多様なデータベース（DB）に接続することができます。
![dataiku DB connection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2610573/f86fa445-aaa9-076b-e059-f4a58d5c2793.png)

上の図には、一部抜粋してますが、有名なところで言いますとPostgreSQLやMySQL、Oracle、snowflakeにも接続することができます。それ以外にも接続できますが、本目的から離れてしまうので、気になる方はコメント欄で質問してください。

では、この章の題名にも書いてありますExecution Engines機能について説明してきたいと思います。

一言でいうと、接続先のデータベース（DB）側のエンジンでデータ加工を処理してくれる機能となっています。

説明下手すぎない！？！？！？（自分にツッコミ！）

茶番に付き合っていただきありがとうございます。
さてもう少し具体的な例を挙げながら、Execution Engines機能について説明していきたいと思います。

以下の図をご覧ください。今回はデータベースの接続先をsnowflakeに設定しています。
![Jobs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2610573/b6f0359a-dccf-b731-ff61-cf5e37e70d67.png)

こちらはDataikuのあるプロジェクトのフローの一部を抜粋してあります。Dataikuでは水色の四角がデータセット、黄色い丸はデータセットを加工する処理を表してあります。今回はデータベースの接続先をsnowflakeに設定してありますので、snowflake側にあるデータを読み込んでいます。

今回のフローは2つのデータセットを結合（join）する処理を表しています。結合するデータセットは左上のデータセット「customers_db」と中央のデータセット「orders_by_customer_db」です。２つのデータセットを結合し、データセット「customers_orders_joined_db」を作成しています。

本来の処理は、まずDataikuが処理するために必要なデータセットをsnowflake側から読み込み、Dataiku側のエンジンで加工したい（例：結合、グループ化etc...）処理を行い、処理を終えたらsnowflake側にデータを転送する処理が一般的な流れになります。この流れの場合、膨大なデータ量になるとDataikuとデータベース間の転送する処理が重くなり、多くの時間を要してしまいます。

ここでExecution Engines機能が活躍します。Execution Engines機能は、加工したいデータが同じデータベースだった場合、Dataikuはデータベースにあるデータを読み込みません。データベース(今回だとsnowflake)側のエンジンで加工処理を行い、作成したデータセットをDataikuが読み込みます。
つまり、データ加工するデータセット（上記の図でいうとデータセット「customers_db」、「orders_by_customer_db」）を読み込む処理が不要になります。

このようにデータベース側で処理することでデータベースとDataiku間のデータ転送が発生しないため、膨大なデータを高速に処理することができ、更にDataikuサーバへの負荷を分散することができるため、本ブログの冒頭に書きました問題も解決することができます。

## まとめ

今回はDataikuのExecution Engines機能について書きました。このような機能があるため、膨大なデータでも処理速度をあげることができます。
またDataikuはGUI操作でクリックのみで簡単にAutoMLまで作成できる機械学習ツールとなっています。
ご興味を持たれた方・ご質問がある方は、コメント等にて、お気軽にお問い合わせください。
また以下のリンクにDataikuについての内容が記載されてますので興味持った方はクリックしてみてください。

https://www.air.co.jp/dtk/

大変長くなりましたが、本ブログを読んでいただき誠にありがとうございました。
Have a good life!!!

過去のブログ
https://qiita.com/KawanoMunekazu/items/5c79fb6942629719c578
Unityで対象を中心に縦横二方向に回るカメラ回転[Unity備忘録]

# はじめに
Unityで対象を中心にした回転、単純にRotateAroundすると、一方向だけならいいんですが、縦横二方向になるときもいことになります。
じゃあどうすんねんってなった時の僕の回答です。多分公式リファレンスとか調べたらもっと賢い方法あるんだろうなあ。

# _transformを_centerを中心に、centerを向きながら回転させる関数。カメラの距離も決めちゃってるよ。
```
    public float cameraDistance = 1f;

    #region MyRotateAround関数のローカルパラメータ。他のとこからいじっちゃダメ。
    Vector3 _pos;
    float _ypos = 0f;
    const float _yLimit = 0.9f;
    #endregion

    void MyRotateAround(Transform _transform, Vector3 _center, Vector2 angle)
    {
        //カメラの上下はy座標の移動+LookAt,左右はRotateAroundで行う
        //左右
        _transform.RotateAround(_center, Vector3.up, angle.x);
        //上下のパラメータの計算
        _ypos += angle.y * 0.02f;
        if (_ypos > _yLimit * cameraDistance) _ypos = _yLimit * cameraDistance;
        else if (_ypos < -_yLimit * cameraDistance) _ypos = -_yLimit * cameraDistance;
        //位置を代入用変数に入れて、上下のパラメータを適用し、距離の調整をする
        _pos = _transform.position;
        _pos.y = _center.y + _ypos;
        _pos =(_pos-_center).normalized * cameraDistance+_center;
        //代入用変数を代入する。
        _transform.position = _pos;
        //対象に向かせる
        _transform.LookAt(_center);
    }
```
# 中心を動かす場合のスクリプト
```
    public void ChangeCenter(Vector3 newPosition)
    {
        newPosition = newPosition - center;
        center += newPosition;
        transform.position += newPosition;
    }
```
# 余談
メモリが少しでも増えないように、ローカル変数を外に出してます。多分最適化で何とかしてくれるのかもしれないけれど？
テストスクリプトは、テスト内容を日本語で書くようにしてるんですよねえ。プロジェクトの中に「Test_Camer...」(...以降は折りたたまれて見えない)みたいなスクリプトがあっても二度と開きませんしね。重要な組み込み用のプログラムと見分けがつきやすいしいいですよ？