OmniAICreator/Qiita-1.07M huggingface dataset:
Salesforceの共有について（よく間違える部分を）解説してみた

こんにちは。
本橋孝昭です。
皆さんはSalesfroceの共有について学ぶ際に色々と悩む部分や気になる点があるかと思います。

今回は特に皆様が気になる部分や間違えそうな部分をまとめました。

※もっと多く深く学びたい人はこちらの記事も参考にしてください※

https://qiita.com/Takaa/items/dae3107d096510af1f74


今日は仮にこんな業務が発生したとしましょう
（あなたはSalesforceシステム管理者で上司から下記の指示があったと思ってください）

「業務内容」
Salesforceに新しいデータ「採用情報」を管理するようになり、管理することになった。
「採用情報」は秘密情報なので、特定のユーザにしか見せたくない。
閲覧できるユーザはプロファイル「人事部」「総務部」「システム管理者」のみである。
なお、プロファイル「人事部」はすべての「採用情報」の閲覧もできるし編集もできる。しかしプロファイル「総務部」はすべての「採用情報」の閲覧しかできない（編集はできない）

どうでしょうか？
おそらく皆さんの会社でも採用情報（面談者の住所や経歴など）は秘密事項なので、営業部などは閲覧不可となっているはずです。なので、「人事部」や「総務部」など特定の人たちのみにみれているはずです。（そんなイメージだと思ってください）

さあ、まずはSalesforceで「採用情報」の管理を考えましょう。
Salesforceには顧客情報管理の標準オブジェクトや商談管理の標準オブジェクトはありますが、採用情報の管理ができる標準オブジェクトはないはずなので、カスタムオブジェクト「採用情報」を作成します。

そして、作成したカスタムオブジェクトについて「誰を閲覧可能にするか？誰を編集可能にするか？」の権限を付与します。

今回はプロファイル「人事部」には「閲覧権限、参照権限」を。
プロファイル「総務部」には「閲覧権限」のみを付与します
（なお、標準プロファイル「システム管理者」はすべてのカスタムオブジェクトのレコードの閲覧、編集ができて、その権限を絞り込むことはできない　というルールがあります）

さて、これでこの業務は完了ですが、ここでもしかしたら「あれ？いつものあの画像の話はどうなった？
？」と疑問に思うかもしれません。。

そうです。この画像の話が一切ないですね
画像はこちらから引用
https://successjp.salesforce.com/article/NAI-000106
![アクセス権.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/a06c0936-0dbe-21e9-77c4-e533e1511519.png)

実は、組織共有設定、ロール階層、共有ルール、手動共有などの話については今回の業務内容で考える必要がない設定です
（しいていえば組織の共有設定を公開にしておいてください）

そもそもの話として
・オブジェクト内のレコード閲覧や編集権限は、プロファイル（権限セット）に依存する
というルールがあります。
今回の場合、
・プロファイル「人事部」「総務部」「システム管理者」のみすべてのレコード閲覧をさせたい
・そのほかのプロファイル（営業部やマーケティング部など）は絶対レコード閲覧させてはいけない

と、プロファイルごとに見せるor見せない　は明確です。
なので、プロフェイルのオブジェクト閲覧制限の設定で今回の設定は可能でした。

こちらは「総務部」プロファイルです。採用オブジェクトが閲覧のみになっていますよね
![採用オブジェクト例.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/2e2f343c-5bda-6d51-8888-189f9112d3b4.png)

次に「人事部」プロファイルです。採用オブジェクトが閲覧や編集が可能になっていますよね
![採用その２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/11f6c370-3ed1-0441-4fd4-90992a1743d7.png)

最後に「営業部」プロファイルです。採用オブジェクトの閲覧や編集が全くできない設定ですね
![採用みえない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531631/9c1508b8-23af-930c-9616-523e92ee295c.png)



さあ、もう一度業務内容をみていきましょう

＞プロファイル「人事部」はすべての「採用情報」の閲覧もできるし編集もできる。しかしプロファイル「総務部」はすべての「採用情報」の閲覧しかできない（編集はできない）

この中で「すべての」という言葉に注目です。

もしもこれが「人事部の中でも一部の採用情報を見せなくしたい」の場合であれば、組織共有設定、ロール階層、共有ルール、手動共有などの話が必要です

例として、例えば
「アルバイト佐藤さんがインターンとして入社した。アルバイト佐藤さんは人事部に配属されましたが、特定の採用情報（例えば海外の採用者）などは見せる必要がないので協議の結果、人事部に配属されながら一部の採用情報レコードのみ閲覧可能にしたい」
というような要望がある場合、組織共有設定、ロール階層、共有ルール、手動共有などの話が出てきます。

しかし、今回は人事部は（採用情報オブジェクトの）「すべての」レコード閲覧がしたい。ということなので、今回の組織共有設定、ロール階層、共有ルール、手動共有などの話については今回の業務内容で考える必要がない設定です。

つまりオブジェクトの閲覧権限について、最初はプロファイル（もしくは権限セット）をベースに権限付与します。
（ここでそのオブジェクトが見れるユーザがすべてのレコードが見たい。という場合、この話はこれでおしまい）
もしも、そのオブジェクトが見れるユーザがすべてのレコードが見たい。ではなく。特定のレコード見せたくない。という場合、組織共有設定、ロール階層、共有ルール、手動共有などの話がでてきます。


いかがでしたでしょうか。
なお、詳細についてはこちらのTrailheadで学習してみてください
https://trailhead.salesforce.com/ja/content/learn/modules/data_security/data_security_overview
iOS 15でSwiftUIビューを定期的にリロードします

iOS 15のSwiftUI 3では、新しいビュー構造`TimeLineView`があります。このビュータイプを使って、(あなたが定義した)一定期間ごとにビューをリロードすることができます。

例えば、アニメーションのロード画面を作ることができます。

![ezgif-2-554a1eb56133.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/f2be0d9e-a512-e20b-67ea-4f33d580f6a5.gif)

## Thoughts

SwiftUIビューはデータの変更時にだけリロードされるのがベストだと思います。

TimelineViewは、既定のリロード時間が設定されたビューを表示するように設計されているのではないかと思います（例えば、WidgetKitは所定のスケジュールに従ってリロードされます）

## 実装

```swift
public init(_ schedule: Schedule, @ViewBuilder content: @escaping (TimelineView<Schedule, Content>.Context) -> Content)
```

コードクロージャに渡された変数`Context`があります。この変数を使って、ビューがリロードされた時間にアクセスすることができます。

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        TimelineView(.periodic(from: Date(), by: 1)) { context in
            Text("\(context.date)")
        }
    }
}
```

## アニメーション付きローディング画面の作成

1秒ごとに画面をリロードできるため、日付から現在の秒の値を読み取り、その値を使用して別の画面を表示することができます。

0、1、2を繰り返すシーケンス番号を生成することができ、その値を使用して別の画面を表示することができます。

```swift
let sequenceNo = Calendar.current.component(.second, from: context.date) % 3
```

```swift
struct ContentView: View {
    
    var body: some View {
        Form {
            
            TimelineView(.periodic(from: Date(), by: 1)) { context in
                
                // A number that's in range 0, 1, 2
                let sequenceNo = Calendar.current.component(.second, from: context.date) % 3
                
                HStack {
                    
                    Image(systemName: "gamecontroller")
                        .font(.largeTitle)
                    
                    Image(systemName: "chevron.right")
                        .font(.largeTitle)
                        .foregroundColor((sequenceNo >= 0) ? .green : .init(UIColor.label))
                    
                    Image(systemName: "chevron.right")
                        .font(.largeTitle)
                        .foregroundColor((sequenceNo >= 1) ? .green : .init(UIColor.label))
                    
                    Image(systemName: "chevron.right")
                        .font(.largeTitle)
                        .foregroundColor((sequenceNo >= 2) ? .green : .init(UIColor.label))
                    
                    Image(systemName: "network")
                        .font(.largeTitle)
                        .symbolRenderingMode(.multicolor)
                    
                }
                
            }
            
            Text("Connecting your console to the Internet...")
            
        }
    }
    
}
```

## 関連記事

SwiftUIのビューは自動的に再描画され、通常は特定の関数をコールして再読み込みさせることはできません。どの変数を監視させるかをSwiftUIのビューに知らせるには、次の変数型を使用できます。

[変数が変更されたときにSwiftUIのViewがリロードされるようにする](https://qiita.com/MaShunzhe/items/cb45b5607fa586f6c442)

---

:relaxed: [Twitter @MszPro](https://twitter.com/MszPro)

:newspaper: [iOS開発に関するニュースレター iOS Dev Letter](https://ios-dev-letter.com)

:sunny: [私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。](http://mszpro.com/ioskiji/)
<img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">
Pythonでビット操作してみる

# スクリプト

```python
#!/usr/bin/env python3

import sys


def format_bit_image(value):
  bit_str = format(value, "b").zfill(32)
  return " ".join([bit_str[0:8], bit_str[8:16], bit_str[16:24], bit_str[24:32]])


def get_4octets(str):
  int_list = [int(x) for x in str.split(".")]  # using list comprehension
  return int_list[0] << 24 | int_list[1] << 16 | int_list[2] << 8 | int_list[3]


def get_str_expression(value):
  p = []
  p.append(value >> 24 & 0xFF)
  p.append(value >> 16 & 0xFF)
  p.append(value >> 8 & 0xFF)
  p.append(value & 0xFF)
  str_p = [str(x) for x in p]

  return ".".join(str_p)


def show_info(label, value):
  print(
      "%-14s = %d {%s} %s [%s]"
      % (label, value, format_bit_image(value), hex(value), get_str_expression(value))
  )


if len(sys.argv) != 3:
  print("Usage: %s [IP address] [Netmask]" % sys.argv[0])
  exit(1)

ip_addr = get_4octets(sys.argv[1])
netmask = get_4octets(sys.argv[2])
show_info("ip_addr", ip_addr)
show_info("netmask", netmask)
network_addr = ip_addr & netmask
show_info("network_addr", network_addr)
broadcast_addr = ip_addr | (~netmask & 0xFFFFFFFF)
show_info("broadcast_addr", broadcast_addr)
```

# 実行結果

```
% printf "%d\n" 0xf0         
240
% ./network_address.py 192.168.125.130 255.255.255.240
ip_addr        = 3232267650 {11000000 10101000 01111101 10000010} 0xc0a87d82 [192.168.125.130]
netmask        = 4294967280 {11111111 11111111 11111111 11110000} 0xfffffff0 [255.255.255.240]
network_addr   = 3232267648 {11000000 10101000 01111101 10000000} 0xc0a87d80 [192.168.125.128]
broadcast_addr = 3232267663 {11000000 10101000 01111101 10001111} 0xc0a87d8f [192.168.125.143]
% 
```
事業フェーズごとにiOS/Androidアプリ開発で気をつけるべき観点

色々な事業フェーズに携わる中で、事業フェーズ別のアプリ開発に関する観点に対して思う所があったので個人的な見解をまとめます。

# 前段
事業状況は0→1、1→10、10→100などの局面によって変化していくものです。
その事業の局面ごとに最適なアプリの設計や重視すべき観点というのは変化していくのではないかと私は思います。
もちろん、アプリの特性と組織状況によっても最適なアプリの設計は変わるものですが、そこはサブ要因として今回は踏み込まずに思うところを記載していこうと思います。

# 0→1フェーズ
0→1フェーズは仮説検証を繰り返し行い、ビジネスが成立するコアサイクルを見つけ出すフェーズです。
この局面ではアプリに必要とされる機能やUXもどんどん変化するため、そもそもネイティブアプリとして作るべきかどうかも含めて検討すべきフェーズです。
可能であれば、NoCodeによるアプリ開発で簡素な仮説検証を繰り返して一定の方向性を見つけてからアプリ開発を開始すべきでしょう。
この段階で実際にアプリを開発する場合、仕様変更が頻発するとともに0→1に興味を持つ少数のエンジニアでどんどん開発を進めていく形になると思われます。
この局面では、アプリ開発において以下の観点を重視すべきでしょう。

* 安定性よりも作りやすさを優先（スクラップ＆ビルド）
* 学習コストが小さく、参入障壁が低い設計
* テストよりも動くものを優先
* 仮説検証の状況の可視化（定性・定量調査とその可視化）

# 1→10フェーズ
1→10フェーズはビジネスのコアバリューが形成され、売り上げを拡大していくフェーズです。
この局面ではコアの機能しかないアプリに色々な機能追加やUX改善が求められます。
また、0→1にこだわるエンジニアが抜けたりすることで人の入れ替えが激しくなってくる時期でもあります。
この段階におけるアプリ開発においては以下の観点を重視すべきでしょう。

* コア機能に対するテストの実装
* 開発ドキュメントの整備（暗黙知から形式知への変換）
* リファクタリング（あるいはリニューアル）の検討と実施

# 10→100フェーズ
10→100フェーズは事業が安定した状態に入り、運用に重きを置くフェーズです。
この局面ではユーザ数が一定存在することもあり、細かいUI/UXの改善や不具合修正、外部（他アプリや他企業のAPIなど）との連携といった開発がメインとなってきます。
この時期には人員が十分な数配置され、技術主導の開発が進んでいる組織も存在するでしょう。
この段階におけるアプリ開発においては以下の観点を重視すべきだと思われます。

* 組織体制に応じた設計ルールの制定（人員が十分なら細かく責務を分けて厳密な設計ルールにするなど組織状況に応じた判断が必要）
* テストの拡充
* 運用周りの自動化推進

# 雑感
具体的な設計という意味では、初期フェーズではiOSならMVC、AndroidならMVVMで構成するにとどめておき、Clean Archなどを適用するとしても厳密なルールを適用しない方が小回りが利くと思います。
1→10フェーズではアプリの特性に合わせて設計を考え、場合によってはリニューアルする感じになるでしょう。
1→10でリファクタリングもしてないケースでは、10→100フェーズになってから大掛かりなリニューアルなどを行う羽目になり苦労している現場もあると思います。
逆に、0→1フェーズで作り込みをやりすぎて、1→10になってから作った人が抜けて誰も触れない設計になっているというのも聞いたことがあるので、事業フェーズと人員体制によってアプリに適した設計というのは変化していくことを意識してほしいと思う所です。
AWSのssmのポートフォワードを並列稼動で起動する。

AWSのEC2を開発機として利用しているが、ssmで接続に慣れてくると、鍵をできるだけ使いたくない。できるだけIPを考えたくない。ポートフォワードで、接続できると良いとなってきた。

asis

```
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=22,localPortNumber=50022
ssh  -i ~/.ssh/key/tanigawa-rei-development.pem ec2-user@127.0.0.1 -p 50022 -N -L 8000:localhost:8000 -L 33306:localhost:33306 -L 9000:localhost:9000 -L 9090:localhost:9090  -L 15808:localhost:15808
``
ssmのポートフォワードでは、複数ポートの指定ができなかったので、ssmでsshポートだけあけて、sshコマンドでやっていた。ひとつひとつウインドウ開いて、セッション貼るのが面倒だった。鍵を使うのも面倒だった。
```
 

tobe

スクリプトを作ることにした。非同期で、ssmのポートフォワードコマンドを叩く

```
reita@antares:/mnt/c/Users/tanigawa.rei$ cat ./port-forward.sh
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=22,localPortNumber=50022" &
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=8000,localPortNumber=8000" &
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=33306,localPortNumber=33306" &
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=9000,localPortNumber=9000" &
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=9090,localPortNumber=9090" &
aws ssm start-session --target i-0dhogehogec26 --profile tanigawa.rei  --document-name  AWS-StartPortForwardingSession --parameters "portNumber=15808,localPortNumber=15808" &

reita@antares:/mnt/c/Users/tanigawa.rei$ ./port-forward.sh

Starting session with SessionId: tanigawa.rei-029810fec20da552d

Starting session with SessionId: tanigawa.rei-06a4566ef1b1a7ade

Starting session with SessionId: tanigawa.rei-0dd66dce67dc95395

Starting session with SessionId: tanigawa.rei-07f0a13ce927c9c42

Starting session with SessionId: tanigawa.rei-001ef0b6bbd275e15

Starting session with SessionId: tanigawa.rei-07917d08a0f0a05e6
Port 33306 opened for sessionId tanigawa.rei-029810fec20da552d.
Waiting for connections...
Port 50022 opened for sessionId tanigawa.rei-0dd66dce67dc95395.
Waiting for connections...
Port 9090 opened for sessionId tanigawa.rei-06a4566ef1b1a7ade.
Waiting for connections...
Port 9000 opened for sessionId tanigawa.rei-07f0a13ce927c9c42.
Waiting for connections...
Port 8000 opened for sessionId tanigawa.rei-001ef0b6bbd275e15.
Waiting for connections...
Port 15808 opened for sessionId tanigawa.rei-07917d08a0f0a05e6.
Waiting for connections...
```
メモ〜DockerとOverlayFSについて

今回のお題
-
今回はファイルを保存する際の方法の一つである`OverlayFS`の仕組み、およびDockerとの関わりについて取り上げます。

普段の開発ではあまり意識することのない部分かもしれませんが、個人的には非常に興味深い内容だったので1人でも多くの方に同じように感じていただけると幸いです。

なお、本記事で触れるのはあくまでも定性的かつ基本的な原理にとどめます。

実際にコードを打ってファイルを作って・・・とやっていると非常に長くなってしまうので、その点についてはご了承ください。

目次
-

- OverlayFSとは
- OverlayFSファイル作成時の動き
- OverlayFSファイル編集時の動き
- OverlayFSとDockerイメージ

OverlayFSとは
-
OverlayFSとは`Overlay FileSystem`の略であり、Overlay、すなわち重ね合わせによってファイルの出力を管理するという方法です。

より具体的にいうと、OverlayFSで管理されているファイルはmergedir, workdir, upperdir, lowerdirという4つのディレクトリに分かれておりlowerdirとupperdirに存在するファイルを重ね合わせた内容がmergedir内に出力されて我々の目に触れることになります(workdirは作業に必要なリソースを保管するファイル）。

これだけでは分かりにくいと思うので、具体例を見てみましょう。

OverlayFSファイル作成時の動き
-
例として、`hoge`と`fuga`を出力するファイルを考えてみます。

このときのディレクトリ構成は以下のようになっています（あくまで一例です）。

````shell
|-- mergedir
|-- workdir
|-- upperdir
|-- lowerdir
      |-- hoge.txt # hogeと出力
      |-- fuga.txt # fugaと出力
```

hoge.txtとfuga.txtが実際に存在するのはlowerdirですが、見かけ上はmergedirに存在するように見えます。

```shell
% ls mergedir
>> hoge.txt fuga.txt
```

OverlayFSファイル編集時の動き
-
先程はファイル作成時の動きを説明しました。

では、このファイルに変更を加えた場合にはどのようになるでしょうか。

実は、この際にはlowerdir内のファイルが直接編集されることはありません。

編集前と編集後の差分だけが先述のupperdirに保存され、それがmergedirに読み取られることによって変更内容が反映されます。

例えば先程作成したファイルは`hoge fuga`と出力するようになっていますが、ここに`hogefuga`を追加する場合、以下のようになります。

```shell
|-- mergedir
|-- workdir
|-- upperdir
      |-- hogefuga.txt # hogefugaと出力
|-- lowerdir
      |-- hoge.txt # hogeと出力
      |-- fuga.txt # fugaと出力
```
編集前はhoge.txtとfuga.txtのみを重ね合わせて表示していたのが、hogefuga.txtも含めた3つのファイルをmergeするように変わっています。

```shell
% ls mergedir
>> hoge.txt fuga.txt hogefuga.txt
```

また、今の例ではhogefugaという出力を追加しましたが、逆に出力を削除したり変更したりするとファイル構成は以下のように変わります。

今回は例として`hoge`の削除と`fuga`から`fugafuga`への変更をおこなっています。

```shell
|-- mergedir
|-- workdir
|-- upperdir
      |-- hoge.txt # 何も出力しない
      |------------------------- fuga.txt # fugafugaと出力
|-- lowerdir
      |-- hoge.txt # hogeと出力
      |------------------------- fuga.txt # fugaと出力
```
upperdirにhoge.txtとfuga.txtが出現していますね。

そしてlowerdirのhoge.txtとfuga.txt自体に変化はありません。

lowerdirのhoge.txtとfuga.txtの代わりにupperdirのそれらが読み取られることで、mergedirの中身が変わったように見せているというわけです。

### ファイルの読み取りの優先度について
今回のようにupperdirとlowerdirで同名のファイルが存在する場合にはupperdirが優先されます。

また、lowerdir内には複数のディレクトリを作成することも可能なのですが、その場合にもファイル名の衝突があれば上位のlowerdirが優先されます。

### ファイルを削除した場合の挙動について
OverlayFSにおいては、既存のファイルの上から何も出力しないファイルを上書きすることで元のファイルが消えたように見せています。

上記例ではhoge.txtを削除しましたが、この時に作成されたupperdir/hoge.txtはただのブランクファイルではなくホワイトアウトファイルと呼ばれる特別なファイルのようです。

OverlayFSとDockerイメージ
-
最後に、このOverlayFSがどのような場面で活かされているのかを解説します。

今回は例としてDockerイメージを取り上げます。

Dockerイメージを新しく作る場合、基本的にはベースイメージとそこに追加する内容をDockerfileに記述するかと思います。

この際にDockerイメージ内部ではベースイメージの情報をlowerdirに、追加した内容をupperdirに保存します。

このように部品ごとに分けておくと何が良いのかというと、ファイル容量の節約になるということです。

例えばcentos:centos7をベースイメージに、`/var/www/html`に`hoge.html`を追加した`centos_hoge`というDockerイメージを作成し、DockerHubにpushしたとします。

同じようにfuga.htmlを追加した`centos_fuga`も作成してpushしたとします。

もしDcokerイメージが部品ごとに分かれていない場合にはcentos_hogeとcentos_fugaの内容を丸々記録しておかなければなりませんが、ベースイメージはどちらもcentos:centos7なのでここが重複しているのはかなりの無駄です。

しかしパーツに分けて管理しておくことで、重複する部品は一つずつ保存すれば十分ということになります。

あとは誰かがイメージをpullした際には必要な部品をコピーしてOverlayFSファイルを作り、それを送信してあげればOKというわけです。
laravel クエリビルダ where句にて「〇〇以外」で絞り込む方法

# 目的

- クエリビルダのwhere句にて〇〇以外で絞り込む方法をまとめる

# 概要

- usersテーブルにflagカラムがあったとする。
- flagカラムにはintの0、intの1、intの2いずれか格納されている。
- flagカラムが1以外のレコードを取得したい場合のwhere句の書き方をまとめる

# ご注意

- 「　〇〇以外」にNULLを含みたい場合は本方法では無理である。
- where句ではnullを判定することができない。
- orWhereNull句やグループ化などを用いて記載する必要がある。
    - 参考 [https://qiita.com/miriwo/items/59450b116213665e9b62](https://qiita.com/miriwo/items/59450b116213665e9b62)

# 方法

- 下記の様にwhere句を記載することでflagカラムが1以外のレコードを取得することができる。

    ```php
    $users = DB::table('users')
        ->where('flag', '!=', 1)
        ->get();
    ```

# 関連記事

- [https://qiita.com/miriwo/items/59450b116213665e9b62](https://qiita.com/miriwo/items/59450b116213665e9b62)
トスリンクコネクタ

SPDIFでは光ケーブルが使われています。このコネクタの仕様は東芝が作ったものでトスリンクという商標になっているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/0269a55f-a6c3-e671-d6eb-bdfd4d08f85c.png)

東芝の製品はTOTX147などで、シャープではGP1FAV30TK0Fなどがあったようです。

初期のものはキャップでしたが、最近のものはシャッターで保護しています。

シャッタータイプのモジュールは東芝は下側が中に入る仕様で、シャープは右側が中に入る仕様にです。

送信側(TX)が発光して受信側(RX)が受光します。

東芝ではディスコンになっているようですが、互換品を作ってるメーカーはまだあり、また部品取りでも手に入ります。

最大転送レートは15MBit/secくらいです。

48Kの16Bitデータを送信する場合は32Bitフレームに入れられるので、48*32*2で3.072MBit/secになります。

SPDIFのMAXは96Kのようです。

電圧仕様は三種類です。

* 5V
* 3V
* 3V-5V

5Vの仕様でも信号線のHiレベルのMINが3V以下であれば3.3V系の信号でも使えるかもしれません。

CSチューナから取ったトスリンクコネクタはシャープ製でした。このモジュールは1pinがVIN(SPDIF)で2pinがVCCで3pinがGNDのようです。

ジャンク基板から取り外すのは結構難しくて、かなりの確立で足をおってしまう。本体がプラスチックなので、ヒートガンも使えない。

秋月にどっかから出てきたシャープの5V TXなモジュールがある。かなりの在庫があるから、当面なくならないと思う。(2022/2)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4ab6d98e-a4af-4bd3-b9d8-86704c33c277.png)

東芝の製品には型番が入っていました。

![写真（2022-04-18 16.44）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/4f3da824-8fe5-d43c-e397-29770bcb6a36.jpeg)

おそらくこれはシャープのものだと思われます。

![写真（2022-04-17 14.55）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d98d3351-5322-e099-d651-242e2571b3b7.jpeg)

これは海外製かもしれません。

![写真（2022-04-18 16.52）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/1d02ee63-fbb8-5683-f069-79b40ef22dc4.jpeg)

ASUSの基板についてたコネクタです。

![写真（2022-04-18 18.41） #3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/da1b8f1c-1fb4-0a90-481a-fe63749f6f77.jpeg)

このコネクタはケーブルを差し込むときに結構な力が加わるので、しっかり固定しないとダメです。

金属のフリスクのケースを加工して入れてみました。ドリルで穴を開けて、ヤスリで四角にしました。

![写真（2022-04-29 16.54）.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/dc3906d7-acac-4374-c4ab-51ad72cb51a6.jpeg)


やっぱ国産のほうが音が良さそうな気もするが、オカルトかな。
EKSのバージョンの「サポート終了」についてちゃんと調べてみた

# 背景
業務でEKSを扱っていて、ふと生じた疑問について調べてみました。
[今回参考にしたドキュメント](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/kubernetes-versions.html)

# EKSの「サポート終了」とは？
K8sは成長途中の技術であるためバージョンのアップデートが早く、約3ヶ月に1度のペースで新しいマイナーバージョンがリリースされています。
それに伴いAWS上のEKSクラスターもデプロイしたらしっぱなしではなく、運用しながら手動アップグレードし続ける必要があります。ドキュメントでは、
> 各マイナーバージョンは、最初にリリースされてから約 12 か月間サポートされます

と書かれており、これ以降で下記の終了日を超えるとそのバージョンは「サポート終了」となります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577028/1e9ddc5c-0e6e-653c-95e6-62306395cdb9.png)
ここで、以下の疑問がわきました。
**EKSの「サポート終了」ってどういう意味なんだろう？🤔**

OSやソフトではの「サポート終了」 = 「それ以降も使い続けることはできるけど、セキュリティアップデートや不具合時の問い合わせが提供されなくなり、自己責任での運用になる」
とざっくり理解しています。

EKSでも、同じようにAWSサポートへの問い合わせができなくなるって意味なのか？
まさかサポート終了日過ぎたらPodが一気に停止してサービス停止に陥ったりしないよな…

そこでこの疑問を晴らすべく、ちゃんと調べてみることにしました。
ただ**大前提として、EKSクラスターはきちんと手動バージョンアップしてサポート終了日までほったらかしってことは無いようにしましょう**。笑
セキュリティのためにもですし、便利なツールがどんどん導入されています。

# サポート終了日が過ぎた時の挙動
EKSクラスターをデプロイした時のバージョンがサポート終了日を過ぎた場合の挙動は、コントロールプレーンとデータプレーンで違います。
###1. コントロールプレーン
こっちはドキュメントに明確に書かれています。


> サポート終了日には、終了の対象となっているバージョンで新しい Amazon EKS クラスターを作成できなくなります。既存のコントロールプレーンは、Amazon EKS の段階的なデプロイプロセスを通じて、サポートされている最も古いバージョンに自動的に更新されます。

つまり、バージョン1.20でEKSクラスターを運用中の場合、1.20のサポート終了したらコントロールプレーンは自動的に（サポートされている最も古い）1.21にアップグレードされます。この自動バージョンアップのタイミングははっきり決まっておらず、AWS側で任意のタイミングで行われるようです。

###2. データプレーン
コントロールプレーンと違い、データプレーンは自動でアップグレードされないようです。
ただ、データプレーンの構築方法として、EC2/Fargateの2種類があります。ドキュメントにも分けて書かれていたので、ここでも以下で分けて説明します。


# データプレーンの挙動を詳しく
### 1. データプレーンがEC2のとき
EC2を使用した時は、マネージドノード型グループでも、セルフマネージド型ノードグループでもEC2は自動バージョンアップされないようです。
ドキュメント中の以下2項目で詳しく書かれています。
> Q: Amazon EKS のマネージド型ノードグループは、クラスターのコントロールプレーンのバージョンとともに自動的に更新されますか?
> Q: セルフマネージド型ノードグループは、クラスタコントーロールプレーンのバージョンとともに自動的に更新されますか?

「だったらコントロールプレーンとバージョン差異が出たら互換性なくなって障害が起きるのか？」と一瞬不安になりましたが、マイナーバージョン2世代まではコントロールプレーンとデータプレーン間の互換性がサポートされているらしいです。なので、ある程度バッファはあります。（ずっと差異がある状態は推奨されていませんが）
> 最大 2 つ前のマイナーバージョンに対して、コントロールプレーンとノード間の互換性が確認されています。

実際にAWSサポートに問い合わせたところ、**プレーン間で２世代以上の差異が出た場合はKubernetes自体の各コンポーネントが正常に動作しなくなり、EKS上で運用しているアプリケーションは意図せず中断する可能性はある。**という旨の回答をもらいました。

結論として、
**「EC2データプレーンはずっと手動バージョンアップせず放置すると、サービス中断のリスクがある。そのためデプロイ後もK8sのリリースに追随してアップデートを続ける必要がある。」**
ということになります。

### 2. データプレーンがFargateのとき
じゃあEKS on Fargateを使用した場合はどうなるのか？これもドキュメントに書かれています。
> Q: クラスターコントロールプレーンのバージョンに対する自動アップグレードによって、Fargate で実行中のポッドも自動的にアップグレードされますか?

ただ、これに対するAnswerが分かりづらく、自分の読解力では理解できませんでした…。
「自動でPod削除されて再スケジュールされる的に読めるから、自動バージョンアップされるのか？よくわからん…」

そこで、これもAWSサポートに問い合わせたところ、**結局EC2のときと同様に自動バージョンアップはされず、手動バージョンアップが必要、**という回答もらいました。
具体的な手順としては、Fargateノードで実行されているPodを再デプロイして、手動でワーカーノードのバージョンを更新します。


#　まとめ
○EKSクラスタを手動バージョンアップせず放置した場合
 ・コントロールプレーンはAWS側で自動でバージョンアップされる。
 ・データプレーンはEC2/Fargateいずれを使った場合でも、自動バージョンアップされない。
なので、データプレーンは手動バージョンアップが必ず必要

○データプレーンをバージョンアップしなかった場合、最悪サービス中断に陥る恐れがある。（コントロールプレーンと２世代以上差異が出た場合）

○EKSクラスターはデプロイ後も放置せず、ちゃんと手動バージョンアップしてメンテナンスするようにしましょう。


[今回参考にしたドキュメント](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/kubernetes-versions.html)
[Mac]getconfで参照できる構成変数と結果の全一覧TSVの作成

- LinuxあるいはMacでシステム構成変数を参照するためには`getconf`コマンドがしばしば用いられる。
- ビット数や最大値等の参照に便利だが、指定する構成変数を調べる必要がある。
- 簡単に全ての変数を知るためにはaオプションが必要だが、Macでは利用できない。
- そのため今回はMacのgetconfで参照できる構成変数及び結果の全一覧TSVリスト作成のコマンドを記録する。

## 環境
- Mac 20.3.0

## 結果
- 結果の記述は以下の通り。

```sh
strings $(command -v getconf) |
grep -E '^_?[0-9A-Z_]+$' |
awk '{printf($1"\t");system("getconf "$1"")}'

*******************
LONG_BIT        64
LONG_MAX        9223372036854775807
LONG_MIN        -9223372036854775808
MB_LEN_MAX      6
SCHAR_MAX       127
SCHAR_MIN       -128
********************
```

- 結果をファイルにTSV形式で格納しておけば、検索や抽出が便利。
  - **※定義されているがエラーとなる構成変数もあるため、エラー出力も一緒にファイルへ格納する。**

```bash
# ファイルへ格納
strings $(command -v getconf) |
grep -E '^_?[0-9A-Z_]+$' |
awk '{printf($1"\t");system("getconf "$1"")}' &> all_getconf_data.tsv

# 検索
grep 'DARWIN' all_getconf_data.tsv

DARWIN_USER_DIR /var/folders/76/*****
DARWIN_USER_TEMP_DIR    /var/folders/76/****
DARWIN_USER_CACHE_DIR   /var/folders/76/****

# 抽出
grep 'LONG_BIT' all_getconf_data.tsv | cut -f 2

64
```

## 内容

### 変数一覧取得
- まずgetconfのプログラムを確認するために`command -v`でファイル名を出力。
- 名前が`/usr/bin/getconf`のバイナリファイルのため、`strings`コマンドで中身を可視化する。
- 中身は「簡単な説明・利用方法・構成変数一覧」とまとめらている。
- 構成変数一覧は大文字でまとめられているため、grepで正規表現で取り出すと以下のような一覧の出力が可能。
  - **※Linuxではより多くの情報で記述されているため、更に絞り込む必要がある。**

```
PATH
POSIX_V6_ILP32_OFF32_CFLAGS
POSIX_V6_ILP32_OFF32_LDFLAGS
POSIX_V6_ILP32_OFF32_LIBS
*******
*******
```

### 実行及び整理
- 参照できる構成変数一覧が出力されたため、一つ一つにawkでgetconfコマンドを実行。
- その際に出力が以下のような対応表のTSVになるようにawkで整理。

```
構成変数名  値
＊＊＊＊＊  ＊
＊＊＊＊＊  ＊
＊＊＊＊＊  ＊
```

## 参考
- https://docs.oracle.com/cd/E62101_01/html/E62874/getconf-1.html
ヒープソートの理解

ソートアルゴリズムには、選択ソート、挿入ソート、マージソート、バブルソート、ヒープソートなどがあるが、その中で最も理解に苦しんだヒープソートをPythonで整理していく。


## ヒープとは
ヒープソートに用いられるヒープは木構造であり、子ノードの値は、親ノードの値以上である性質を持つ。この場合、ルートの値は最小値になり、最小値の探索が簡単になる。逆に、子ノードの値が親ノードの値以下の場合もあり、ルートの値は最大値になる。親ノードが最大２つの子ノードを持つ構成を二分ヒープ木という。

##ヒープソートの実装
子ノードの値が親ノードの値以上の場合で実装していく。
二分ヒープ木をリストで構成する時、ある位置のインデックス番号が`0`の場合、左の子ノードのインデックス番号は`1`、右の子ノードのインデックス番号は`2`になる。つまり、ある位置のインデックス番号が`n`の場合、左の子ノードのインデックス番号は`2n + 1`、右の子ノードのインデックス番号は`2n + 2`になる。また、親ノードは`(n - 1) // 2`になる。
<img src="https://i.gyazo.com/2ebf18936972e40a42a59013667c851e.png" width=700>

### ヒープを構成
数字がまばらに格納されるリストを昇順にソートしていく。
リスト（`[3,6,1,4,8,2]`）があり、そのリストでヒープを構成する。現在の位置がルートでない、または値が親より大きい間は、親と交換し、位置を親の位置に移動する。

```python:Python
data = [3, 6, 1, 4, 8, 2]

# ヒープを構成
for i in range(len(data)):
    pos = i
    # 現在の位置がルートでない、または値が親より大きい間は、親と交換し、位置を親の位置に移動
    while (pos > 0) and (data[(pos - 1) // 2] < data[pos]):
        data[(pos - 1) // 2], data[pos] = data[pos], data[(pos - 1) // 2]
        pos = (pos - 1) // 2
        print(data)
```

```python:実行結果
[6, 3, 1, 4, 8, 2]
[6, 4, 1, 3, 8, 2]
[6, 8, 1, 3, 4, 2]
[8, 6, 1, 3, 4, 2]
[8, 6, 2, 3, 4, 1]
[8, 6, 2, 3, 4, 1]
```

### ヒープソートを実行
現在の位置の値をヒープの先頭と交換する。左下の値の方が大きい場合、左下と交換し、右下の値の方が大きい場合、右下と交換する。これを繰り返していくとリストの値が昇順にソートされる。

```python:Python
for i in range(len(data), 0, -1):
    data[i - 1], data[0], = data[0], data[i - 1]
    # ヒープの先頭から開始
    pos = 0
    while ((pos * 2 + 1 < i - 1) and (data[pos] < data[pos * 2 + 1])) or (
        (pos * 2 + 2 < i - 1) and (data[pos] < data[pos * 2 + 2])):
        # 左下の値の方が大きい場合、左下と交換
        if (pos * 2 + 2 == i - 1) or (data[pos * 2 + 1] > data[pos * 2 + 2]):
            data[pos], data[pos * 2 + 1] = data[pos * 2 + 1], data[pos]
            pos = pos * 2 + 1
        # 右下の値の方が大きい場合、右下と交換
        else:
            data[pos], data[pos * 2 + 2] = data[pos * 2 + 2], data[pos]
            pos = pos * 2 + 2
        print(data)

print(data)
```

```python:実行結果
[6, 1, 2, 3, 4, 8]
[6, 4, 2, 3, 1, 8]
[4, 1, 2, 3, 6, 8]
[4, 3, 2, 1, 6, 8]
[3, 1, 2, 4, 6, 8]
[1, 2, 3, 4, 6, 8]
```

## 最後に
ヒープソートには`upheap`や`downheap`も存在するが、今回は省略。
まだあやふやなところがあるので、何度も見直して理解を深めたい。
間違い等があればご指摘お願いいたします。


## 参考

増井 敏克「Pythonではじめるアルゴリズム入門 伝統的なアルゴリズムで学ぶ定石と計算量」 翔泳社 ２０２０年１月２４日
macOSアップデート後、『xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun』というエラーが出た時の対処法

【エラー内容】
macOSアップデート後にgitコマンドを入力したら以下のようなエラーが出ました。

```
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
```

【対処法】
下記のコマンドを実行し、xcodeをインストールすることでエラー解消できました。

```
xcode-select --install
```

参考になりましたら幸いです。
STM32G031とACM1602K(キャラクター液晶)で「HELLO ...」を表示(VSCのcubeide)3


x 原因は、わからないが液晶がちらつく場合は、ウェートを調整してね!!


x 74hc164使用

x cubeideは、初心者ころしである。
x MXは、動ないと思っていた　初心者にトラブルの自己解決は、不可能?
x VSCでnecleo-g031を選択
x 動けば正義、細かい事を気にするな
x STM32G031J6M6との違い、ピン数
x いつも、動くと思うなよ(バクや頻繁なアップデートの為)

目的
GPIOのテスト





![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/00540fb4-1625-12fc-6bea-9a489fe20012.png)





主なプログラム(後は、めんどいので省略、各自、自習の事)(main)




```c++



    //GPIOの初期化
    DW(en,GPIO_PIN_RESET);     //ビットが0 
    DW(swdclk,GPIO_PIN_RESET); //ビットが0 

    //液晶の初期化
    for(int ii=0;ii<8;ii++){ 
        seg1( lcd_int[ii] , 0);HAL_Delay(2);
    }//for

    //画面クリア
    seg1(   0x01  , 0  ); 
    HAL_Delay(1000);

    seg1( 0x80+0x00 , 0  ); //1ライン目にカーソルを移動
    ns_printf("Hello World !");HAL_Delay(500); //debug




```


mainの外


```c++





#define swdclk GPIO_PIN_5   //A4
#define swdio  GPIO_PIN_7   //A6
#define en     GPIO_PIN_4   //A3

#define DW(AAA,BBB)  HAL_GPIO_WritePin(GPIOA,AAA,BBB)

GPIO_PinState bi1[]={GPIO_PIN_RESET,GPIO_PIN_SET};

//1文字送信
void seg1(char v,int rs)
{
    for(int jj=0;jj<8;jj++){
        if( (v<<jj) & 0x80 ){
                DW(swdio,GPIO_PIN_SET);   //ビットが1 
        } else {
                DW(swdio,GPIO_PIN_RESET); //ビットが0
        }//endif
        DW(swdclk,GPIO_PIN_SET);DW(swdclk,GPIO_PIN_RESET); //clk
    }//for
    DW(swdio, bi1[rs] );
    DW(en,GPIO_PIN_SET);   HAL_Delay(1); //ビットが1 
    DW(en,GPIO_PIN_RESET);               //ビットが0      
}//seg1

//文字列の表示 nana_seg
int ns_printf(char *str1) {

    //文字の中身がゼロか
    while(*str1){

        //一文字出力
        seg1( *str1 ++ , 1  );

    } //while

    //戻り値
    return(0);
}//ns_printf

//液晶初期化配列
int lcd_int[]={
  0x30,0x30,0x30,0x38,0x08,0x01,0x06,0x08+0x04
};//lcd_init






```



stm32g031_lcd_adc_1内をいろいろ適当にコピー




https://os.mbed.com/users/caa45040/code/f303_h_p1/
【ツール】UFOSAをCSVではな<マウスと連動[専用無線アダプタ不要】

初めまして、スケベなシステム開発をしたいmi2と申します。

[@yotto_さま](https://qiita.com/yotto_/items/80236c0d209fcb4b3518 "Web BluetoothによるU.F.O. SAの制御")が開発してくださったWebBluetoothでUFOSAを制御する仕組みを使わせて頂いて、マウスと直感的に連動するウェブページつくりました。
専用無線アダプタも不要で、ササっとつくれてしまったので、webBluetoothすげええという話です。

操作方法などはブログで解説しているので、技術的に有益な情報だけメモ書きいたします。
[https://mi2no.com/xwp/sa_msu/](https://mi2no.com/xwp/sa_msu/ "【ツール】UFOSAをブラウザで操作【専用無線アダプタは不要】")

##BLE接続するとデバイスのオブジェクトが得られる
ブラウザの機能として備わっているrequestDeviceをawaitで実行してやるとdeviceが返ってきます。

```javascript
  async function selectSa() {
    const device = await navigator.bluetooth.requestDevice({
      filters: [
        { services: [SA_SERVICE_UUID] }
      ]
    });
    return device;
  }
```

その得たオブジェクトに機器に設定されているルールに乗っ取って、バイトを書き込むと動きます。
※1バイト=8桁の2進数(例:0000 0010)=2桁の16進数(例:0x02)
UFOSAはNLS独自の企画で、
1バイト目
　・機器コード(UFOSAは、0x02)
2バイト目
　・固定（0x01）
　3バイト目
　・1桁が回転の向き、残り7桁がスピード（スピードは1～100）

```javascript
const idByte = 0x02;
const directionAndSpeed = (direction << 7) | speed;
const value = new Uint8Array([idByte, 0x01, directionAndSpeed]);
```

仕組みの根本は、とにかく「このオブジェクトに3バイトを送り込むと動く」ということです。今回はマウスと連動させましたが、色々できそうですね。例えば、ブラウザゲームで、ナニが刺激されるのに合わせて３バイト書き込めば、それだけで連動になるので可能性無限大・・・！


##遅延を防ぐ仕組みがついたsetSpeedSaが偉大
連続で命令がきて、キューに溜まると遅延してしまうので、溜めずに破棄されて最後にした命令が実行されます。
詳しくは、[@yotto_さま](https://qiita.com/yotto_/items/80236c0d209fcb4b3518 "Web BluetoothによるU.F.O. SAの制御")の記事へ。

##今回はマウスの動きに合わせてsetCsvが走るようにした
onmousemoveのたびに、座標に応じたスピードでsetSpeedSaをするだけ。
マウスの位置のX,Y座標を、操作範囲内の上から何％の位置にあるかという情報に置き換えて、setSpeedSaにぶち込みます

```javascript
//マウス移動時
  document.onmousemove = onmousemove;
  onmousemove = function(e) {
    // マウスの位置のXY
    h_mouseXY.innerHTML = `マウス：x:` + e.pageX + `　y:` + e.pageY;
    // この瞬間の画面サイズ
    h_mouseXYSize.innerHTML = `（表示領域：x:` +  window.innerWidth + `　y:` + window.innerHeight+`）`;
    // 位置の％
    h_mouseXYPer.innerHTML = `位置の％：x:` + e.pageX/window.innerWidth*100 + `％　y:` + e.pageY/window.innerHeight*100　+　`％`;
    //paraをオブジェクトにする、これを渡せば動く
    let para=makeMauseXYPara(e.pageX,e.pageY);
    h_mouseXYPara.innerHTML = `位置パラ：x:` + para.direction + `　y:` +  para.speed;

    syncSetSpeedSa(para);
  }

  function makeMauseXYPara(x,y){
    const xPer=x/window.innerWidth*100;
    const yPer=y/window.innerHeight*100;
　　（略）
 }
```

簡単だったのに、およそ思った通りの挙動をしてくれてイイ感じ!

##今後：動画を見ながらランダム操作できるようにする
一定の動きだと刺激になれやすいので、ランダムなんだけどリアルタイムで操作するっていうのをつくる、かもしれない。
UFOSAを使っている方々がどういった機能を欲しがっているのか調査中です。

本記事のアプリはこちら
[https://mi2no.com/xwp/sa_msu/](https://mi2no.com/xwp/sa_msu/ "【ツール】UFOSAをブラウザで操作【専用無線アダプタは不要】")

それでは、また。
普段話しにくい人々とリモートワークで話せる機会を活かすアイディア

## 雑談スキル

飲み会に頼らなくても、特にリモートワークの状態で上下関係気にせず気持ちを吐き出せる、吐き出させることができるスキルは結構すごい。それは次世代[エレベーターピッチ](https://en.wikipedia.org/wiki/Elevator_pitch)的な何かだとおもっている。

https://qiita.com/viva_tweet_x/items/dd9d3353d1b961fd1c71

[コミュ障のための大体これだけ話せば良い1on1 テンプレート付 - Qiita](https://qiita.com/e99h2121/items/aeb93f0bd911ad604a02)
ということでそのためのアイディアのようなものをまとめておく。ポイントは上のテンプレート記事にもまとめているが基本的には「話者自身が得をする」ためのものであるというマインドセット。

## Tips

- リモート会議開始5分前には入室して世間話をする（雑談からのチェックインを行う）。
- ツッコミどころの多い背景を設定する。
- 直前にSlackで小話のネタを送っておく あるいは相手からも拾っておく。
- 音質、デバイスを高品質に保つ。
- 会議中もチャットを組み合わせる。
- リアルタイムで議事録を取る。取れと言われてなくても勝手にとって、「これこういう意味であってました？」とか言って後から偉い人と接触するのもいいぞ。
- あとそもそも会議の参加人数も大事ではある。せいぜい一桁... 



## 「チェックイン」の話題

- 昼飯なにたべました？
- 最近飲んでます？
- 最近朝何時に起きています？
- 最近お子ちゃん何覚えましたか？
- 最近料理してますか？
- 最近アフター5何してますか、休日何してますか？
- 今お住まいはどのへんなんですか？
- もう○月ですね
- 最近のニュースや話題のこと
- 事前に拾った小話のネタ。なんでもよい。
- このトラブルは大丈夫ですかなどでも相手を気にかけるのが良い。



## 温まってきた頃もう少し突っ込む仕事観

- 働かなくてもいいとしたら何をしたいですか？
- あと3年後5年後どうなってたいとかありますか？
- 現役開発（コード書いてる）時代の一番の失敗談と一番うれしかったエピソードってなんですか？
- もし自分が今開発の現場に居たら or 新人だったら何したいですか？


## ちょっと懐に入る話

- むしろネガティブな話聞いてもよいですか？
- これについてどう考えますか？
- 上長として仕事で大事にしていることはなんですか？
- ストレス解消してますか？
- ほか、昔話
- 次回に続くテレフォンショッキング式も良さそう。


## 参考

<script async class="speakerdeck-embed" data-id="c342766130794979930ffa955f9fe32d" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

https://nttcom.github.io/remote-work-handbook/

https://twitter.com/crema/status/1444220497395257349?t=3O28x0oJFmiAlGBs3sYSXw&s=19




いずれも「飲み会」という手段に頼らないでもこれから意識できたら良いことかもしれないななど。
参考になればさいわいです。
analogReadの値の変換を誤解していた話(1023、1024問題)

# analogReadの最大値が1023なのに1024で割るときがあるんですか！？
**あるんです。**

# それはanalogWriteのとき
では皆さん、アナログ入力の電圧によってLEDの明るさを変えるスケッチを書いてください。

```cpp:dame.ino
int lv = 0;

void setup() {
  pinMode(11, OUTPUT);
}

void loop() {
  lv = analogRead(A0);
  analogWrite(11, lv * 255 / 1023);
}
```

上みたいなスケッチを書いたあなた。ダメです！

どこがマズいのか。`* 255 / 1023`のところがマズい。

「え、だってanalogReadは10bitで最大値は1023、analogWriteは8bitで最大値は255じゃん。何が間違ってるの？」って大半の人がなっていると思う。僕も最初はそうだった。

こう考える人はこの1023だとか255って数字を連続値だと考えてしまっている。**量子化してるのに連続値で考えていいのか。いや、よくない。**

# 簡略化して考える
ぶっちゃけ、1023とか255とかでかい数字だから考えにくい。4bitから2bitへの変換(最大値15から最大値3への変換)を考えてみよう。

次の図を見て欲しい(手書きの図のままになっていたら力尽きて図の更新ができなかったということなので暖かく見守ってください)。
![IMG_9E7878304EBC-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629180/e51d492f-c484-406c-003d-7e0407335333.jpeg)

そんなに複雑な図じゃない。0-5Vの区間を2bit・4bitで量子化したときの対応を表している。
これを見て何かに気づいた方はいるだろうか？

…ふんふん？なるほど。
そう！2bit側と4bit側で上位2bitが一致している！たとえば2bitの10のところ。4bitの方は**10**11、**10**10、**10**01、**10**00と上位2bitが**10**になっている。

じゃあ2bitの方と4bitの方の桁を揃えてみよう。2bitの方の頭に00をつけて桁を揃える。たとえば10は0010になる。
こんな感じになる。
![IMG_34F40C219C0E-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629180/bdef7b5d-e818-c1e2-6ab4-b10dd96ad571.jpeg)

また、何か気づいた人はいるだろうか？

そう、4bit側から2bit側へで**2桁分の論理右シフト演算**になっている。
10進数で言えば$\div 2^2$の計算、これは`* 256 / 1024`に他ならない。

# じゃあいつ1023は出てくるの？
△bitから□bitへの変換、要は量子化とかの細かさの変換には1024とかのキリ番が出てきた。
裏を返せば量子化とかまったく関係ないときに1023は出てくる。

例えば、入力電圧をシリアルモニタに表示するときとか。

```cpp:sample_1023.ino
int lv = 0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  lv = analogRead(A0);
  Serial.println(lv * 5 / 1023);
}
```

# 最後に
~~長々と書いたが、ぶっちゃけ、`255/1023`と`256/1024`の違いなんて微々たる差(1%にも満たない)で考慮する必要ないだろと思う。~~**こういうことは言ってはいけない**

僕自身、あーだこーだ考えて理解したものだったので共有したくなった。
特に、論理シフトの考え方が出てきたあたりとか、基本情報でやるようなことでも実際のプログラミングで役に立つという話でとてもおもしろかった。

Arduinoプログラミングにも慣れてきた方々、僕と一緒にこういう細かいところにも気を使いつつ楽しんでいきましょう。
~~初心者はこんなクソ細かいことを気にするより色々作ってみたほうがいい。~~**こういうことも言ってはいけない**
【Unity】Assembly Definition にヘッダ的クラスを用意してコンパイルを速くしたかった

# 背景
Assembly-CSharp から Addressable Definition（以下、asmdef）に定義されたクラスを扱うには、asmdef の Auto Referenced を有効にして、毎回コンパイルする必要があります。
私は、多くのコードが書かれたクラスを毎回コンパイルするのは無駄だと思い、C のヘッダーのようなクラス（以下、ヘッダ的クラス）を作る事を考えました。多くのコードが書かれたクラスの Auto Referenced を無効にして、代わりにヘッダ的クラスの Auto Referenced を有効にする事で、コンパイルするコードの量を減らし、コンパイル時間を短くできないかという案です。
ヘッダ的クラスの実装が有効か判断するため、ヘッダ的クラスの有無がコンパイル時間に影響するか検証することにしました。

### ヘッダ的クラスとは
他のクラスの関数を呼び出すだけのクラスを指します（このようなクラスには名前があるかもしれません）。実装がないのでコード量も少ないです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/7f0fd4f4-57d9-55ac-f355-5f097110d76d.png)
# 計測方法
コンパイル時間の測定には、[baba-s](https://twitter.com/intent/follow?original_referer=https%3A%2F%2Fbaba-s.hatenablog.com%2F&ref_src=twsrc%5Etfw%7Ctwcamp%5Ebuttonembed%7Ctwterm%5Efollow%7Ctwgr%5Ebaba_s_&screen_name=baba_s_) さんの [CompileTimeMeasurer](https://baba-s.hatenablog.com/entry/2017/12/04/173417) を使わせていただきました（使うにあたり、ログ表示を改造しました）。

多くのコードが書かれたクラスを再現するために、適当な関数を1000個入れたクラス Body を用意しました（Google スプレッドシートで作りました）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/dc981d26-309f-a04f-60d3-60fe6e3be002.png)
コンパイルを走らせるために CompileTest というクラスを作りました。Body の関数である Function1() と Function2() を交互に書き換えて保存し、コンパイルを実行します（スクリプトが Editor に反映されるまでの時間は多少前後するので、手動で Refresh して誤差を減らしました）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/48911421-f6f7-2396-9ae6-2461eaf75dd7.png)
まずは、asmdef なしで20回計測しました（左から、回数,コンパイル時間,累計コンパイル時間）。
![noAsmdef.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/8ab436df-964b-846a-ae95-a8512df54ea9.png)
次に、Body の asmdef を作成し、Auto Referenced を有効にして20回計測しました。
![bodyOnly.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/8ea55c17-d081-3e40-e778-8ca35e4fde4b.png)
Body を asmdef に入れて、変更を加えなかったので、コンパイル時間が短くなりました。

最後に、Header を作り Body の代わりに Auto Referenced を有効にして20回計測しました。
<FONT COLOR=white><SUB>（どうでもいいですが、CompileTest の Body.Function を Header.Function に変えたり、Header.asmdef の asmdef References に Body.asmdef を追加したりもしました）</SUB></FONT COLOR>
![useHeader.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/d4517aff-d005-3497-f437-7c5acf8274f6.png)
逆に遅くなってしまいました😇

# 計測結果
左から、asmdefなし、Bodyのみ、Header利用の測定結果です。ヘッダ的クラスの利用は逆効果だと分かりました。
![noAsmdef.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/8ab436df-964b-846a-ae95-a8512df54ea9.png)![bodyOnly.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/8ea55c17-d081-3e40-e778-8ca35e4fde4b.png)![useHeader.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/d4517aff-d005-3497-f437-7c5acf8274f6.png)

# まとめ
ヘッダ的クラスはダメでしたが、スクリプトを asmdef で定義すればコンパイルが速くなると実感できました（当然）。
私のような発想に至った人がこの記事を見て、ヘッダ的クラスは無意味だと知ってくれれば幸いです。
BCM57780のドライバーでつまずいた話

#**はじめに**

初のブログデビューです。お手柔らかに。
先日Gentoo LinuxnのKernel Buildに勤しんでいたら、当方所有のノートパソコンに入っている有線LANモジュールであるBCM57780を認識していないことに気が付きました。そこから戦いは始まったのです…（小並感）

##一連の流れ
ある日Gentooを入れて再起動すると
BCM57780
というBroadcom製のイーサネットデバイスが認識されていないことに気づく。
「デバイスが認識してないってことはドライバーが当たってないってことだよね。」
そう早合点し、おもむろに以下を実行した。

```
# modprobe broadcom
```
しかし、「そんなモジュールねぇよ！」と怒られた。うーん、こりゃ困った。これじゃパッケージがなんも入れられないじゃないか…。
もしかしたらinitramfsを作った際にモジュールを入れ損ねたかもと思い、以下を実行してみる。

```
# dracut --host-only --no-kernel
```
だが効果なし。こいつ、ゴーストタイプか…？

取り敢えずKernelのコンフィグの際（make menuconfig）のBroadcom関連のnetwork driverを含むようにしビルドを行った。
しかし結果は変わらず。どうゆうこっちゃ。


そんなこんなでネットを徘徊していると、

>_"This Broadcom chipset sometimes does not behave well unless you specify the order of the modules to be loaded. The modules are broadcom and tg3, the former needing to be loaded first."_
(訳：ドライバーとしてtg3とbroadcomがいるんやけど、先にboroadcomを読み込ましてな。)
参照
 
 https://wiki.archlinux.org/title/Network_configuration/Ethernet#Broadcom_BCM57780


なるほど、tg3っていうドライバーがいるのね。ってかドライバーの順番が大事ってのもどういうことやねん。
ただそうも言ってられないので、上記を参考に以下を実行してみる。

```
# modprobe -r tg3
# modprobe broadcom
# modprobe tg3
```
結果は...

**やっぱり有効にならないやん(´；ω；`)ｳｩｩ**

ん？なにやらエラーコードに「tg3はkernelに含まれてるからオフにできないゾ」と書かれてる。

カーネル内蔵…？

モジュール化…？

**…わかったぞ！**

この時に該当ドライバーをモジュールとして（menu configで言う<M>）ではなくカーネル内蔵（menuconfigで言う<*>）でconfigを行ったことを思い出した。そこで該当ドライバーを全てモジュール化しビルドを実行。
ビルド後、上記dracatとmodprobe三行を実行。
すると…

**ちゃんと認識してる！！Σ(ﾟДﾟ)**

無事に有線LANを使えるようになりました。
（ここまでたどり着くのに半日かかったのは内緒）

###今回の気づき###
・デバイスのドライバーについてはネットで調べるのが一番。
・カーネルビルド時のドライバーの設定はモジュールにしとくといいらしい。


以上、初のブログでした。ご拝読ありがとうございました～。



###追伸###
どなたかエラーコードをQiitaに載せる方法がわかる方教えて下さい。ssshで実行してコピペしたらいいんだろうけど、ちょっと面倒くさいんですよね…。
OCRは愚行な気がするしなぁ。
コメントにて回答お待ちしてます。
RPiPlayを使ってラズパイをAirPlay化してみる

# そもそも RPiPlay って？

RPiPlayは、Raspberry PiでAirPlayを行うためのOSSです。
ラズパイといっても、実はUbuntuや他のLinux環境にもインストールすることができます。

理論上はCLI環境でも動作するはずなのですが、私が試した限り、GUI環境がインストールされてないと正常に動かないことが多いです。
CLIのUbuntu Serverとかだったら `apt install ubuntu-desktop` とかすれば、GUI環境を入れてくれます。
個人的に重くなるからイヤなんだけど。


# インストール作業

インストール作業といっても、実はコマンドひとつでインストールできちゃいます。

```bash
~$ curl https://yuzukichi.jp/rpiplay-inst.sh | bash
```

https://yuzukichi.jp は私が所有するドメインで、rpiplay-inst.sh は、RPiPlayの実行に必要になる作業をひと通り行ってくれるスクリプトになってます。
実体は[コチラ](https://yuzukichi.jp/rpiplay-inst.sh)。


> やる人いないと思いますが、dockerコンテナや一部のタイムゾーンが設定されていない環境では、インストール作業中に、タイムゾーンを選択する画面が出るかもしれません。そこは手動でお願いします...。
話が脱線しますが、そういう環境では、PID1がデーモンではなく、`date set` コマンドが使えないため、シェル上でタイムゾーンの設定に失敗してます。解決法はあると思いますが、そこまでは調べてません。。

インストールが完了したら、

```bash
~$ rpiplay -n AirPlayTest -b auto
```

のように実行してあげましょう。
待ち受け状態になったら、AirPlayレシーバ化完了です。
同じネットワーク内にあるiPhoneやMac、iPadからミラーリングしてみましょう。

個人的には、ラズパイ2では少しモッサリした感じでした。
（初代は論外、10秒以上のラグが発生した）

公式は3以降を推奨していたり、YouTubeとかで試している人たちは動きがかなり滑らかなので、それくらいのスペックがあれば間違い無いです。

# 参考資料

- [FD-/RPiPlay](https://github.com/FD-/RPiPlay)
- [RPiPlay試してみた](https://qiita.com/dyamaguc/items/f01e1f5e758b7245047b)
ffmepgで画像1枚と音声で動画を作ってみよう

#説明
ffmepgで画像1枚と音声で動画を作ってみよう
#まずインストールしてください
以下のサイトを参照してください

https://jp.videoproc.com/edit-convert/how-to-download-and-install-ffmpeg.htm

#手順

1.画像1枚から無音の動画をつくる(muteoutput.mp4)
2.muteoutput.mp4に音を足した動画(output.mp4)をつくる
この二つの手順で行います。
そして何でもいいのでsample.jpgとsound.mp3を用意しましょう。


あとから気づいたのですが一気に画像と音声をくっつけるべきでした。
#画像1枚の無音動画をつくろう
以下のサイトを参考にしました。

http://tecsingularity.com/ffmpeg/make-movie/

コピペしてもらうと三秒の動画がつくられます

```
$ffmpeg -loop 1 -i sample.jpg -vcodec libx264 -pix_fmt yuv420p -t 3 -r 30 muteoutput.mp4
```

#無音動画に音を足そう
以下のサイトを参考にしました。

http://pineplanter.moo.jp/non-it-salaryman/2019/04/21/ffmpeg-join/


```
$ffmpeg -i muteoutput.mp4 -i sound.mp3 output.mp4
```

これをすると動画が完成しました。
#動画をみてみる
output.mp4を見てみてください。
【Python】Mediapipeを使って口紅を塗ってみた

# TL;DR

ノートブックは[こちら](https://github.com/YomamaBanana/Mediapipe-python/blob/main/notebooks/lip_filter.ipynb)！

## はじめに

WEB会議を行う際に自分の顔をカスタマイズしたい（いわゆる顔フィルター）。
そのため、まずはローカルで顔のフィルターを作成して、その第一歩として、
今回は簡単な「唇フィルター」を作ってみよう！

## 手順

「唇フィルター」の作成には下記の手順で行う。

1. 画像を読み込む。
1. 顔認識を行う。
1. 認識した顔データから「唇」に合わせてマスクを作成する。
1. 抽出した「唇マスク」に対して画像処理を行う。
1. 元画像と新しい「唇マスク」を融合させる。


## 使用するツール
* python 3.8
* [OpenCV](https://opencv.org/)
* [Mediapipe](https://google.github.io/mediapipe/)
* [Numpy](https://numpy.org/)

## インストール

まずは必要なライブラリーをインストールしよう！
pipenvやvirtualenvなどの仮想環境をおすすめします！

```shell
$ pip install numpy opencv-python mediapipe 
```
## コード

#### ①必要なモジュールをimportする
```python
import cv2
import numpy as np
import mediapipe as mp
import matplotlib.pyplot as plt
```

#### ②画像データをと読み込む

今回使った画像データはGAN（敵対的生成ネットワーク）によって生成されたものである。
(https://thispersondoesnotexist.com/)

```python
img_path = "../input/image.jpg"

src = cv2.imread(img_path)
src = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
img = src.copy()
```
![before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/71aabd44-32bc-b253-274a-0310e7a235c3.png)

#### ②Mediapipeを用いて顔認識を行う

```python
# 検知器のインスタンス化
drawing = mp.solutions.drawing_utils
drawing_spec = drawing.DrawingSpec(thickness=1, circle_radius=1, color=(0, 255, 0))
drawing_styles = mp.solutions.drawing_styles
face_mesh = mp.solutions.face_mesh
face_detector = face_mesh.FaceMesh(min_detection_confidence=0.5, min_tracking_confidence=0.5)

# 検知処理
results = face_detector.process(img)
face_landmarks = results.multi_face_landmarks

# 可視化
drawing.draw_landmarks(
    image=img,
    landmark_list=face_landmarks[0],
    connections=face_mesh.FACEMESH_TESSELATION,
    connection_drawing_spec=drawing_styles.get_default_face_mesh_tesselation_style())
```

![detection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/bd99bc2a-ea28-0008-0aae-46462ec8bc1c.png)

#### ③「唇マスク」を作成する

```python
# 入力画像と同じサイズの黒マスクを作成
gray = np.zeros((src.shape[0], src.shape[1], 3), dtype=np.uint8)

# 検知した顔における「唇」に関するINDEXを抽出する
lips_idx = list(face_mesh.FACEMESH_LIPS)
lips = np.ravel(lips_idx)

# 唇のINDEXを用いてピクセル座標に戻し、リストを作成する
empty_lip = []
for i in lips:
    pt1 = face_landmarks[0].landmark[i]
    x = int(pt1.x * img.shape[1])
    y = int(pt1.y * img.shape[0])
    empty_lip.append((x, y))
```

#### ④「唇マスク」に対して画像処理を行う

```python
# ピクセル座標をもとに唇の凸包を作成
convexhull  = cv2.convexHull(np.array(empty_lip))

# 作成した凸包に対して色を塗る
mask = cv2.fillConvexPoly(gray, convexhull, ((100, 30, 100)))

# 見た目をより円滑化するため、ガウシアンブラーをかける
mask = cv2.GaussianBlur(mask, (7, 7), 20)
```

![mask.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/927971ee-6006-37a3-164e-3d5937aaf372.png)



#### ⑤入力画像と「唇マスク」の融合

```python
resulting_image = cv2.addWeighted(mask, 0.5, src, 1, 0.)
```

![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2290515/29f093ee-8bdf-d85a-71ea-b2563e35251a.png)

## あと書き
Mediapipeの使いやすさを感じた！さすがGoogleさん！
唇だけではなく、顔の他のパーツのINDEXさえ分かれば自由にフィルターをかけられる。
さらにフィルターをかけた結果をWEB会議などで活用できるのではないかと！
window環境でimagemagickで簡単な画像を作ってみよう

#説明
windowsの環境で
imagemagickをインストールしてみたけど
何に使おうか迷っている人にやってもらえれば幸いです。




#こんな画像を作ります
使い道がすくないですけど作ってみてください
![sample.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2273205/c94a0014-7375-1b70-631b-43ba410109a3.jpeg)


#やる前に
https://code-examples.net/ja/q/2eb1ed
このサイトを見てもらえればわかるのですが
windowsの環境だとconvertだけだとうまくいかないようです。


#やってみよう
以下のサイトを参考にしました。
https://tech.mktime.com/entry/145


```
$"C:\Program Files\ImageMagick-7.1.0-Q16-HDRI\convert.exe" -size 1920x1080 -gravity center -font C:\Windows\Fonts\msgothic.ttc -fill white -background black -pointsize 1000 label:あ  sample.jpg
```
ImageMagick-7.1.0-Q16-HDRIとなっているのですが、
ここは自分のダウンロードしたバージョンに変えてください。

#結果はどうでしょうか
sample.jpgを見ると、いい感じになっていると思います。
これでImageMagickが使えるようになれたらうれしいです。
Railsのセットアップの時、mysql2というgemのせいでbundle installができない時に見る記事

## 概要
Rails + MySQLで開発環境を構築する際に発生しうるそこそこややこしいエラーについて、自分なりにまとめてみました。
**※Railsの中で、mysql2というgemを使用してます。**

## 発生したエラーについて
Railsのプロジェクトを```rails new```コマンドで作成後、bundle installした際に下記のエラーが発生することがある。

```Bash
...省略

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

...省略

linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /var/folders/mj/93db0vd975799gg9w3nnr3_r0000gn/T/bundler20190503-14531-xlyd6cmysql2-0.5.2/gems/mysql2-0.5.2 for inspection.
Results logged to /var/folders/mj/93db0vd975799gg9w3nnr3_r0000gn/T/bundler20190503-14531-xlyd6cmysql2-0.5.2/extensions/universal-darwin-18/2.3.0/mysql2-0.5.2/gem_make.out


An error occurred while installing mysql2 (0.5.2), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.2'` succeeds before bundling.

In Gemfile:
  mysql2
```

このエラーメッセージで着目したいのは、この一行である。

```Bash
ld: library not found for -lssl
```
これはどうやら```openssl```というライブラリに起因するエラーのようです。
(※厳密には```libssl```だそうです、、、)

このlibsslは、どうやらGCC(GNU Compiler Collectionの略称)のopensslへのリンクオプションらしいです。([参照元](https://qiita.com/tatama/items/5e6c7c0ba1a2ba7ff9d3))

いろんな記事にて、

```
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"
```

このコマンドを実行すると解決する！！！みたいなことがよく書かれていると思いますが、これは上記のopensslのライブラリの場所を```--with-ldflags```というオプションに渡してあげるとopensslというライブラリ自体を参照するようにしてくれるみたいです。

ですが残念ながら、これでもまだ解決できないケースがあります。

[引用元](https://qiita.com/moroi/items/53d60d1d6885795a0f6f)
> MacのHigh Sierraから、デフォルトのOpenSSLがOpenSSLからLibreSSLになっているそうで、OpenSSLの諸々の問題を鑑みれば英断らしいのですが、そうはいっても開発環境の様々なツールがOpenSSLに依存しておりアレコレと新たな問題を引き起こすため、様々なツールのほうがLibreSSLに対応するまでさくっとOpenSSLに出戻る方法が下記です。

要するに、どうやらHigh Sierra以降はデフォルトがopensslになっていないそうです。
故に、冒頭にあったopensslというライブラリへの参照が見つからないみたいなエラーが発生してしまいます。

実際にOpenSSLのバージョンを覗いてみると、、、

```
$ openssl version
LibreSSL 3.0.0 7
```

このようにLibreSSLになってしまっているそうですね、、、、、

この問題の解決方法として、opensslでデフォルトのLibreSSLからOpenSSLに変更する必要があります。
このやり方に関してはシンプルにパスを通すだけで良いそうです。

```
$ echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.zsh_profile
```

ターミナルを再起動すると下記のように、OpenSSLに変更することができました。

```
$ openssl version
OpenSSL 3.0.0 7 sep 2021
```

ここまでできたらbundle installコマンドが正常に動作すると重います！！！

## まとめ
MySQLのセッティング周りはわりかしややこしいところが多くて、脳死しながらエラー解決しがちになってしまいますが、そこは堪えてエラーメッセージを一つづつ丁寧に読んでみましょう。

なんだかんだ、それがエラー解決の近道だったりしますよね　（自戒の意味も込めて）。



## 参考記事一覧
- [bundle installでmysql2がエラーになる件 (Qiita)](https://qiita.com/SAYJOY/items/dd7c8fc7a3647e7ff969)
- [macでmysql2がbundle installできない時 (Qiita)](https://qiita.com/tatama/items/5e6c7c0ba1a2ba7ff9d3)
- [macOS High Sierra（OSX）のOpenSSLをデフォルトのLibreSSLからOpenSSLに変更する (Qiita)](https://qiita.com/moroi/items/53d60d1d6885795a0f6f)
iOSアプリのユニバーサルリンクの設定方法

# はじめに
調べると古い情報が出てきがちなのでまとめました
iOS14,iOS15時代のものです

# 目次
1. [ユニバーサルリンクにしたいURLを決める](#ユニバーサルリンクにしたいurlを決める)
1. [apple-app-site-associationを作成する](#apple-app-site-associationを作成する)
1. [apple-app-site-associationを置く](#apple-app-site-associationを置く)
1. [アプリ側の設定](#アプリ側の設定)
1. [確認](#確認)

# ユニバーサルリンクにしたいURLを決める

↓これにします
`https://sampleApp/app`

# apple-app-site-associationを作成する
apple-app-site-associationを**自分**で作成します
自分で作らないと大変なことになります

```
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "{teamId}.{bundleIdentifier}",
                "paths": [ "/app/*" ]
            }
        ]
    }
}
```

# apple-app-site-associationを置く
apple-app-site-associationを
`https://sampleApp/.well-known/apple-app-site-association`
に配置します

正しく配置できているか
https://branch.io/resources/aasa-validator/
で確認できます



# アプリ側の設定
対象のアプリのIdentifiersから下記を設定
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237483/fab4195b-0027-d4a6-ac16-adc20a2714bc.png">

Xcodeから下記を設定
<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1237483/33d91966-8df0-3a64-1377-5f1090c94ff5.png">

コピペ用
`applinks:sampleApp`


# 確認
iPhoneから[https://sampleApp/app](https://sampleApp/app)にアクセスしてアプリに遷移すれば完了