OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu18.04にVirtualBox6.1をインストールする際に依存関係に悩まされた話

#はじめに
業務で扱うUbuntuサーバ上にVMを構築する必要があり、VirtualBoxを利用することにしました。都合上、GUIは用いずにCLIのみでインストール＆環境構築を行う必要がありました。コマンド上でVirtualBoxをインストールするために、

```bash
sudo apt-get update
```
を取り敢えず実行してみると、大量のエラーを吐いたため

```bash
sudo apt-get install virtualbox-6.1
```
ではインストールできないな～と思い、別の方法でインストールしてみました。

#直接ダウンロードして実行
まずは、[公式サイト](https://www.virtualbox.org/wiki/Linux_Downloads)から自身の環境に合ったファイルをダウンロードします。今回は「Ubuntu 18.04」を想定しているので、画像の赤い矢印が指している文字列をクリックすることで、ダウンロードが開始されます。
![virtualbox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/300353/ffe040fd-13f5-068a-0060-1810e81041a9.png)

（上手くいかないので、実行する必要はありません）ダウンロードしたファイルを実行して、VirtualBoxをインストールします。

```bash
sudo dpkg -i virtualbox-6.1_6.1.30-148432_Ubuntu_bionic_amd64.deb
```
すると、途中でインストールが止まってしまいました。一旦、綺麗にしておきます。

```bash
sudo apt-get install -f
```
（次も上手くいかないので、実行する必要はありません）ならばと、aptでインストールしてみることにしました。

```bash
sudo apt install virtualbox-6.1_6.1.30-148432_Ubuntu_bionic_amd64.deb
```
すると、以下のようなエラーが出ました。

```bash
以下のパッケージには満たせない依存関係があります:
 virtualbox-6.1 : 依存: libsdl1.2debian (>= 1.2.11) しかし、インストールすることができません
                  推奨: libsdl-ttf2.0-0 しかし、インストールすることができません
E: 問題を解決することができません。壊れた変更禁止パッケージがあります。
```
これを解決するためには、「apt-get update」をしてから色々と個別にインストールしたりすることなどが考えられますが、はじめに書いた通り、それは出来ないので、別の手法でこのエラーを回避したいと思います。

#パッケージ依存関係の解消
エラーメッセージでは、「依存: libsdl1.2debian (>= 1.2.11) しかし、インストールすることができません」とあるので、「libsdl1.2debian (>= 1.2.11)」をインストールしてあげれば良さそうです。
これもコマンドを叩くのではなく、[公式サイト](https://packages.debian.org)から直接ダウンロードしてきます。今回は「Ubuntu 18.04」（＝buster、異なるバージョンのUbuntuを利用している場合は変更してください）かつ「amd64」アーキテクチャなので、「パッケージ＞buster＞libsdl1.2debian＞amd64」と検索していきました。（具体的なURL：https://packages.debian.org/buster/amd64/libsdl1.2debian/download）

ダウンロード後に「You might want to compare the checksums to verify the integrity of downloaded packages. The SHA256 checksums should be favored as the MD5 algorithm must be treated as insecure!」とあるので、パッケージの整合性を確認しておきます。

```bash
md5sum lib*

（実行結果）
dbe592539b2f41093bac7218c8969c92  libsdl1.2debian_1.2.15+dfsg2-4_amd64.deb
```
ダウンロードしたファイルを実行して、パッケージをインストールします。

```bash
sudo dpkg -i libsdl1.2debian_1.2.15+dfsg2-4_amd64.deb
```
これで、依存関係はクリアできているはずなので、VirtualBoxをインストールします。

```bash
sudo dpkg -i virtualbox-6.1_6.1.30-148432_Ubuntu_bionic_amd64.deb
```
無事にインストールすることができました！

#最後に
複数人でサーバを利用しているので、環境を破壊しないように慎重に作業する必要がありました。また、「apt-get update」が上手くいかないのは、前任者が色々としていたようで。。。

#参考文献
* [virtualbox.org](https://www.virtualbox.org/wiki/Linux_Downloads)
* [debian.org](https://packages.debian.org)
* [kali linux rolling edにvirtualboxを入れるときに躓いたこと](https://lapis-zero09.hatenablog.com/entry/2018/02/28/221845)
仮想モニター　を通しての　vnc over ssh　



![1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/3a8bc6b5-212a-1f72-d989-c2c441605bcd.jpeg)

を使います


## 雪でした
![20211205_092120.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/222f737b-eb36-c59b-f71a-49b89e2f8c57.gif)

https://www.youtube.com/watch?v=csPefrLxjpQ





![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211097/dc6c1dc6-6aec-5ddc-2eae-08eb9b35cdfc.jpeg)


|vnc されるパソコンAでは　監視カメラを動かしています|
|:---|
|Aには　仮想ビデオアダプターしか付いていません、つまりモニターは接続してません|
|遠く離れたパソコン B から SSH Over SSH で A に入って 撮影した監視カメラ画像を見ます|


```
$ ./comment-out.bat ./vnc-1-tunnel.bat 
ssh jaro@192.168.10.125 -L 5900:localhost:5900


$ ./comment-out.bat ./vnc-viewer.bat 
vncviewer localhost:5900


```



##動く姿は以下です

https://www.youtube.com/watch?v=xF7CoWIFy6w
勤怠管理の作成を目指す＋α：Day２

　早起きに失敗したけど、とりあえずやっていきます！

やったこと
----------
https://eng-entrance.com/java-get-time

・上記サイトを読み進めて実践する

勤怠に関係しそうな整理としては。。。
朝の時間が足りなくなり、Dateクラスの実践&理解（中途半端）で断念。

・Udemyの動画進める
めっちゃ駆け足だけど、理解追い付いてないけどなんとか



明日やること
-------------
仮想通貨ボット：BitMEXの板でスプーフィングを試みた話

# はじめに
[UKI](https://twitter.com/blog_uki)です。
今回は過去に検討したボット戦略について紹介します。

遡ること2018年6月、私はbitFlyerの高頻度ボットを使って原資1万円を2週間でどれくらい増やせるかチャレンジしていました。結果として、2週間で1万円を47万円に増やすことができ（利回り+4600%）、この結果を「[2週間で利回り4000%超を達成したトレーディングbot構築の考え方](https://note.com/uki_profit/n/n24a110c0a609)」というNoteにまとめました。

このNoteの影響かどうか断定はできませんが、私の稼働していたボットはNote公開後まもなくトレードの優位性を失い、利益が出なくなってしまいました。その裏で私はある戦略を検討していたのです。

# Order Flow Imbalance
この話に先立って、まずは板取引の指標である「Order Flow Imbalance」というものについて説明したいと思います。直訳すると「注文フローの偏り」となり、[杉原の論文](https://www.imes.boj.or.jp/research/papers/japanese/kk31-1-8.pdf)では以下のように紹介されています。

>最良買い気配上の注文量の時間変化から最良売り気配上の注文量の時間変化を差し引いた値を注文フローの偏り（order flow imbalance: OFI）と定義する。

要するに、板の差分（時間的な変化分をΔとすると、ΔbestBit－ΔbestAskの意）がその後の値動きに対して説明力を持つ、というものです。
この事象はそもそも米国株のティックデータで有効性が確認されており、その短期的な説明力はテクニカル指標などとは比べ物にならないほど強いものとなります。私はこの論文を元に、BitMEXの取引板からこの指標を計算して高頻度ボットの売買方向を決める基準としたのでした（下図はNoteからの引用。横軸はBitMEXのOFI）。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562749/71304fec-e0f3-e13b-4396-8e376f852fa6.png)


OFIの計算にBitMEXの板を使用した理由は以下の通りです。

- そもそもbitFlyerよりも海外取引所のほうが価格が先行する。
- bitFlyerはティック幅が1円となっており、1枚の板が薄くOFIの計算に適さない。
- その反面、BitMEXはその手数料体系から板が厚く力を溜める傾向にあった。

# スプーフィングできる可能性
さて上記の事象を乱暴に言い換えると、「BitMEXの板にデカイ注文が入ればbitFlyerの価格が動く」ということです。つまりスプーフィング（要するに見せ玉）によって相場操縦できる可能性を示唆するものでした。

BitMEXのOFIとbitFlyerの値動きを回帰して調べると、BitMEXの板に50万USDの変化があればbitFlyerの価格が100円程度動き、それなりの期待値が生じることが分かりました。BitMEXの最大レバレッジは100倍であり、この見せ板は約定させる気はないため、証拠金が5000USD（当時の1BTC程度）あればいったんこの戦略を実行できることになります。

ボットの優位性はいつまでも存在するとは限りません。思いついた戦略は粗削りでもよいので可能な限り早くリリースすべきです。私はさっそくこの戦略の実現可能性について検証を進めることにしました。

# 動かない価格
検証を進めてみましたが、結論としてBitMEXに大きな板を放り込んでも思ったようにbitFlyerの価格は動きません。ここに来て、私はある事実に気が付きました。

### Order Flow Imbalanceの分解
まずBid側（買い板側）を考えると、Bid板の変化分は以下の3つが合わさったものです。
　(1)新しい買い指値注文の流入
　(2)存在した買い指値注文のキャンセル
　(3)成行売り注文でのテイク

続いてAsk側（売り板側）を考えると、Ask板の変化分は、
　(4)新しい売り指値注文の流入
　(5)存在した売り指値注文のキャンセル
　(6)成行買い注文でのテイク

これらを全て正の数量とすると、Order Flow Imbalanceは、

　OFI　＝　ΔBid　－　ΔAsk
　OFI　＝　（1-2-3）－（4-5-6）


このうち説明力として支配的なものは(3)と(6)の成行注文なのでした。指値注文の変化分である(1)、(2)、(4)、(5)にも説明力は存在しており、(3)と(6)と併用することで全体の性能を向上させることはできます。しかし、あくまでも大事なのは成行注文だったのです。

これではbitFlyerの価格を動かすためにはBitMEXで大きな成行をかますしかありません。これは単純に海外取引所で大きな数量を買い上げるという普通の相場操縦と変わりないのです。
この方法に旨味はありません。BitMEXでの成行注文には大きな手数料が掛かりますし、取得したポジションは逆選択リスク（反対方向に動いて損失が発生するリスク）が残ります。

こうして、この戦略はお蔵入りしたのでした。


# おわりに
今回の戦略は未遂に終わったわけですが、そもそもこの戦略の考え方の発端は、**BitMEXの板を参照するボットを殺すボットを作る**、ということでした。市場がボットで飽和すると、必ずボットを食い物にするボットが現れるはずです。
皆さんのボットも常にこのような視点から対策・改良を進めていくとよいと思います。
UbuntuでAWS　CDK環境構築ではまった事。

Ubuntu 20.04
Node.js 16.13

WindowsでAWS CDKを構築したが、どうもCDKが上手くいかない。
情報がWindowsよりもMac Linuxが多いので、Ubuntuで再度構築。

nodejsのインストールでハマってしまったのでメモ。
npm install -g aws-cdkを実行したらエラーが・・

````
npm notice 
npm notice New minor version of npm available! 8.1.2 -> 8.3.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.3.0
npm notice Run npm install -g npm@8.3.0 to update!
npm notice 
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /usr/local/lib/node_modules/aws-cdk
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/aws-cdk'
npm ERR!  [Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/aws-cdk'] {
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'mkdir',
npm ERR!   path: '/usr/local/lib/node_modules/aws-cdk'
npm ERR! }
npm ERR! 
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR! 
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator.
npm ERR! A complete log of this run can be found in:
npm ERR!     /home/saito/.npm/_logs/2021-12-14T21_04_20_425Z-debug.log
```
そこで、調べたら、２つの有力な情報を発見しました。
[npmでpermission deniedになった時の対処法[mac]](https://qiita.com/okohs/items/ced3c3de30af1035242d)


この情報を参考に
 npm install -g npmを実行しましたが、エラー
```````

````
npm ERR! code EACCES
npm ERR! syscall rename
npm ERR! path /usr/local/lib/node_modules/npm
npm ERR! dest /usr/local/lib/node_modules/.npm-i9nnxROI
npm ERR! errno -13
npm ERR! Error: EACCES: permission denied, rename '/usr/local/lib/node_modules/npm' -> '/usr/local/lib/node_modules/.npm-i9nnxROI'
npm ERR!  [Error: EACCES: permission denied, rename '/usr/local/lib/node_modules/npm' -> '/usr/local/lib/node_modules/.npm-i9nnxROI'] {
npm ERR!   errno: -13,
...
````

[【備忘録】npm -g install に失敗する](https://qiita.com/NaokiIshimura/items/cc07441939b226e779c6)
この情報を参考に

````
s:~$ mkdir ~/.npm-global
s:~$ npm config set prefix '~/.npm-global'
s:~$ echo ' export PATH=~/.npm-global/bin:$PATH' >> ~/.bash_profile
s:~$ source ~/.bash_profile
s:~$ npm install -g npm
````
npm install -g npmを再度実行したら正常に実行されました。

AWS CDKインストール

````
sudo npm install -g aws-cdk
````
無事、正常にインストールできました。
XCTContext.runActivityを使ってユニットテストをわかりやすくする

#XCTContext.runActivityとは

公式のリンクはこちらです。
https://developer.apple.com/documentation/xctest/xctcontext/2923506-runactivity/

`Creates and runs an activity with the provided block of code.`
とのことで直訳すると
`提供されたコードのブロックを使ってアクティビティを作成及び実行します`
みたいな意味です。

簡単にいうと、**これを使うとテストが構造化できて何をしているのか名前もつけることができる**ということです。

runActivity自体はXcode９から追加されたものでそれまではSpec記法が使えるQuickを導入していることも多かったと思います。


#実際に使ってみる

```UnitTests.swift
        XCTContext.runActivity(named: "searchButtonDidPush") { _ in
            XCTContext.runActivity(named: "when before called") { _ in
                XCTContext.runActivity(named: "`fetchRepositories` is not called") { _ in
                    XCTAssertEqual(callCount, 0)
                }
            }
            
            XCTContext.runActivity(named: "when after called") { _ in
                XCTContext.runActivity(named: "`fetchRepositories` is called") { _ in
                    presenter.searchButtonDidPush(searchText: "Swift")
                    XCTAssertEqual(callCoount, 1)
                }
         }
```


テスト結果も構造化された状態を見ることができるので、とても便利です。
海外との多拠点開発の話 - 東京で開発のための通翻訳チームを立ち上げたことを振り返る

[海外との多拠点開発の話 - 上海でブリッジ開発をしていたときに感じていたことを振り返る - Qiita](https://qiita.com/e99h2121/items/6ec28c4ce991898503cc) の続編です。


## 上海拠点勤務時代の自慢

当時、上海拠点で、発足から関わったプロジェクトにおいて、チームメートが2015年の社内MVPにノミネートされた。プロジェクトについて自分は東京拠点および上海拠点のコミュニケーションブリッジ役だった。嬉しかった。

## 一方で「失敗」だと思っていたこと

上海にて。東京との関わり方についてどのようなマインドセットをもつかについて苦い思い出。例えば

- 何故東京が上海の状況をわかろうとしないのか分からない、そして何故コミュニケーション上、英語すら話そうとしないのか分からない
- 何故我々のメールを読まないのか全く分からない　等

[海外赴任者の心理的サイクル](http://www.jamh.gr.jp/kokoro/series8/series8-2-1.html) にはいくつかステップがある。少し抜粋して引用。
> - ステップ１：不安と期待の混在期。
- ステップ２：ハネムーン期。赴任直後はすべてが新鮮で日本と違う習慣や、街並み、家の広さ、人々が大らかであることなどがよいことに見え、興味を持って接することができます。ですが、このハネムーン期という時期は、あまり長くは続きません。
- ステップ３：カルチャー・ショック期。予約をしておいた水道屋さんが待てど暮らせど来ない、雨が降ると帰宅するまでが渋滞になり、45分のところが、２～３時間かかる、現地の社員は詰めが甘い、など習慣や文化の違いで不便を感じたり、不快な経験をしてショックをうけます。
- **ステップ４：怒り・幻滅の時期。現地の習慣のいやなところが気になり、また、日本の生活や親しい友人などが恋しくなります。場合によっては孤独になって落ち込んだりします。**
- ステップ５：適応期。その後、時間が経つにつれ、現実を受け入れ、現地の生活に適応していきます。
- ステップ６：現地文化の受容の時期。慣れてくると、住めば都というように、現地文化を受容し、仕事においても生活においても、快適な生活を送るようになります。
- ステップ７：帰国の不安と期待の時期。海外赴任の期間は３年から５年が多く、帰任が近づくと、帰国準備で忙しくなります。
- **ステップ８：逆カルチャーショックの時期。帰国後は慣れ親しんだ海外の友人や同僚から切り離されます。そして、生まれ育った日本に戻っても、浦島太郎になったように、孤独感を少し味わいます。**
- ステップ９：再適応の時期。その後、日本の生活にも再適応し、海外で培ったスキルや異文化適応力をうまく生かしていく時期がきます。


開発者としても「それぞれのチームにそれぞれのプロ意識と責任がありお互いにそれを尊重しなければならない」というHRTの原則というようなものが重要だと思うわけです。
[大事な言葉・HRT～「Humility（謙虚）」、「Respect（尊敬）」、「Trust（信頼）」。ああなんて難しい - Qiita](https://qiita.com/developer-kikikaikai/items/9e08fe0f8ee0eebaccab)

## なので立ち上げた

複数拠点開発には以下のような問題があると思っていた。上海でも各チームがそれぞれに格闘していたが、それを組織として解決したいと考えた。

### 問題1. 言語スキルの差により生じている問題
- 日本語、英語、中国語という異なる言語のスキル差に基づく問題
- フォーマルな場において
    - 各プロダクトのWikiやあらゆるドキュメント、情報差
    - 各会議体における議事録や対話の情報差
- インフォーマルな場において
    - 自由に会話できない、雑談できない
    - 経験値、知識、技術スキルに関わらず起こっている問題
- これについて以下のような取組みを行いたい！！
    - ドキュメントの翻訳
    - 会議における逐次訳
    - ボランティアワーク等含め社内のあらゆる人から組織的に通訳・翻訳の力を「借りたい時に借りられる」仕組み
    - 言語学習のあらゆる面からのサポート

### 問題2. 言語スキルの差と思われがちだがそうではない点により生じている問題

- **問題2-1. 論理思考、知識、理解、マネジメントの仕方の差**
    - 言語によらず基礎的なコミュニケーションスキルによって生じている問題
    - 例:
        - 冗長に書かれたドキュメント
        - 十分な準備のない会議
    - これについて以下のような取組みを行いたい！！
        - 日本では研修で行われているはずの文章講座、ロジカルシンキング、あるいは会議フォーマット等を海外事業所にも広めたい。
    - 海外事業所他各拠点で行われている取組を東京に吸い上げる仕組みを作りたい。
- **問題2-2. 拠点ごとの暗黙ルール、風土等の差**
    - 言語によらず基礎的な拠点の風土理解差によって生じている問題
    - 例:
        - スケジュール共有
        - 勤務時間
        - タイムゾーンや設備など所与の条件

等など。

## 大事にしたいと思ったこと

### 1. 聴く力
開発のあらゆるチームメイトの状況について理解すること。どう東京と上海間で相互に関わるべきかを考えさせられた。上海のあらゆるチームメートをサポートする経験は彼らと彼らのバックグラウンドに対する理解が必要だと思った。もちろん、それは所詮上海だけの話なので、今後上海だけでなくさらにあらゆる国に出自を置いた仲間と関わるには、同じように勉強し続ける必要があると思う。

### 2. 発信する力
同じく、開発のあらゆるチームメイトに対して考えて発信する力。考えられるリアクションを認識し、提案し改善していきたい、これも引き続き勉強が必要だと思った。1. 2. のいずれにおいても、重要なのはただの言語力ではなく、それを前提としたマインドと洞察、どうやってそれを相手に伝えるか、どうやって相手を理解するかだと思っていた。

### 3. 継続する力
また、最終的に、重要なのは継続して取り組むこと、取り組みを一過性でなく浸透させて健康的に続けられるようにまですることだと思っていた。


## 続く

はてさてそのような意気込みでどんな取り組みをしたのだろうか、続く。

以上です～。
明るい夜明けを迎えるためのスクラム前夜

# はじめに
こちらは[Makuake Advent Calendar 2021](https://adventar.org/calendars/6822)の14日目の記事です。

今日はスクラムについて書こうと思います。

# スクラム前にやって良かったこと
最近まで携わっていたプロジェクトではスクラムを採用しており、そのプロジェクトではスクラムマスターに賞賛されるほどかなり自己組織化された良いチームができました。

もちろんプロジェクト中の個々の取り組みが良かったからこそ良いチームになったことは間違いないのですが、(個人的に)振り返ってみると**プロジェクト開始前〜開始後すぐくらいの取り組みがプロジェクト期間全体に渡って良い結果をもたらす下地になっていたのではないか**、と感じられました。

というわけでスクラムを成功させるために、スクラムに取り組む前にやって良かったことをまとめていきたいと思います。

## スクラムについてチーム全体で共通の理解を持つ
スクラムを始めるにあたって、共通の理解を持つことでかなり議論を進めやすかったです。
私たちは全員で**スクラムブートキャンプ**を読み、その上でスクラムをやるか検討し、プロジェクトを開始しました。

https://www.amazon.co.jp/dp/4798163686/

同じ本に基づくことで各メンバーの頭の中にある**「あるべきスクラム像」**を概ね揃えることができ、そのおかげで議論が起きても大きく方向性がズレることもなく進められました。
また、進め方について何か疑問が出てきた時は都度スクラムブートキャンプに立ち返った上で進めることで、迅速に疑問を解決し進め方を修正していくことができました。

スクラム経験者と未経験者が混じったチームや、経験者同士であっても異なるチームでスクラムを進めてきたメンバーで構成されるチームでは、この点が結構大変なのではと思います。
もしそうしたチームの場合でも、何かチームの礎となる本を定めて理解・認識を揃えることですれ違いを防げるでしょう。

私たちが読んだスクラムブートキャンプは短時間で読めて、かつエッセンスを掴めるので共通認識を作るという点ではとても良かったかもしれません。

## スクラムを採用することについて納得する
きちんと会話した上でスクラムを採用することを決められたので、後からそもそも論が出てこなかったのが良かったです。

スクラムという手法は難しく感じられたり、ルールが多いように思われ抵抗を感じる方もいると思います。そういった抵抗・不安を完全に拭い去るのは難しい場合もあるので、そうした方は「不安はあるけどまずはやってみるか」と自分から思えたら良しとするのが良いと思います。

私たちは本を読んで認識を揃えた後、具体的には誰がどの役割で、どういうスケジュールで動くか検討してみることで納得感を高められるよう工夫していました。最終的には変化する状況に対処するにはスクラムが良いだろうというメリデメの点で決めたと思います。

## インセプションデッキは自分たちで手を動かして作る
**これが最もやって良かったことかもしれません。**インセプションデッキの作成に積極的にエンジニアが携わったことでプロジェクトへの理解もグンと高まり、チーム全体が自分ごととしてプロジェクトを捉えられるようになりました。

特に**「我々はなぜここにいるのか」**と**「エレベータピッチ」**はプロジェクトの根幹に関わるスライドなので、チーム全員(PO, SM, エンジニア, その他チームメンバー)で作り認識を揃える価値は非常に高かったです。

具体的には以下のような進め方で作っていきました

1. **全員でそれぞれ**インセプションデッキを書いてくる
1. 互いの内容をシェアして質疑応答やすり合わせをする
1. POとSMがまとめあげる
1. まとめられたものを全員で見て、**違和感がある場所はどう書いたほうが良いか案を出してくる**

**これを全員が一言一句納得がいくまでやりました。**時間はかかりますが、プロジェクトの根幹を担うものなので、その後の認識齟齬やそこから起こるミスコミュニケーションを減らせたと思えばやはりやって良かったと感じます。

事前に手を動かしてくるという方法も理解が深まって良かったです。読み合わせや説明を聞くだけではその場で浮かんできたフィードバックしか返せないですし、チームで話し合う前に個人作業を通して事前に考えを深めてくることで全員の理解度を揃えることができたと思います。

# まとめ
ざっくりとスクラム開始前にやって良かったことは以下の3つでした。

```
- スクラムそのものについてチームで共通認識・言語を持つ
- 納得感を持った上で始める
- プロジェクトやその目的についてチームで理解を深める
```

これら一つ一つが直接的に成果を出すというタイプの施策ではないです。ですがこれらの下地があるからこそいわゆる心理的安全性が確保され、成果を出すために良い相互作用を生み出せるチームが出来上がったのだと思います。

最初は拙いチームであっても、こうした下地を整えて、レトロスペクティブやデイリースクラムなどの機会を使って積極的に互いを成長させる環境が整っているならば、最終的には素晴らしいチームになることができるというのが私の実感でした。

これからスクラムを始めるチーム、スクラムが始まったチームはもちろん、今現在スクラムに取り組んでいるチームなど何かしらのシーンでこの記事の内容が役に立てたら嬉しいです。

## 最後に
[Makuake Advent Calendar 2021](https://adventar.org/calendars/6822)はまだまだ続くので明日以後もぜひ楽しみにしていてください。

また、Makuakeでは一緒に働いてくれるエンジニアを募集中です！この記事を通して少しでもMakuakeにも興味を持ってくれたら嬉しいです。

https://www.wantedly.com/companies/makuake
.NET 6 の C# 10 を今すぐ REPL で試す

この記事は、以下のアドベントカレンダーの 10日目 の記事だ。

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

カレンダーのタイトル長くない？
リンクカード見切れちゃってるじゃん。

この記事では、 『.NET 6? C# 10? 触ってもいいけど面倒なのは嫌！』 という諸兄に、今すぐ触って動かせる方法をお伝えする。

## .NET Interactive の C# REPL を使え

SDK のインストールすら面倒なあなたでも、 [.NET Interactive](https://github.com/dotnet/interactive) なら以下の手順で簡単に利用できる。

1. ブラウザで [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/dotnet/interactive/main?urlpath=lab) リンクをクリック
1. C# Console をクリック
1. C# を REPL で書く
![dotnet6-interactive-csharp-repl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308278/ab57fcb0-cf6b-aa32-143b-8fa14138b4fa.gif)

**たったこれだけ。**
実質 1 Step

C# 10 の新機能である、 [定数の補間文字列](https://docs.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-10#constant-interpolated-strings) も問題なく動いているとおり、 ちゃんと .NET 6 の環境で動作していることがわかるだろう。

## .NET Interactive とは？

……と、これで記事が終わってしまっては寂しすぎるので、もう少し .NET Interactive についての説明をば。

[.NET Interactive](https://github.com/dotnet/interactive) は、 .NET 機能のインタラクティブな体験を、様々なツールを介して提供するプロジェクトだ。

上記リンク先のページでは、 .NET Interactive によって提供された **C#, F#, PowerShell 各言語機能 (カーネル)** を、 **JupyterLab** に入れた環境を、 Binder というサービスで立ちあげている。

Jupyter 以外にも、 [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode) 等に言語機能を加える事も可能だ。

## Jupyter と Binder (mybinder.org)

Jupyter とは、 REPL 的に実行できるコード片やその実行結果などを「ノートブック」と呼ばれる形式で記録しながら、データの分析や可視化を行うためのツールを提供するプロジェクトだ。
もともと、 Python 向けに IPython Notebook という名前で開発されていたものが、 Python 以外の言語にも対応する機能 (カーネル) を追加するにあたって、 Jupyter Notebook → JupyterLab と改名されて今に至る。
![](https://raw.githubusercontent.com/jupyterlab/jupyterlab/v3.2.5/docs/source/images/jupyterlab.png)

Jupyter を語る上で外せないのが、この Binder (mybinder.org)。
これは、 GitHub 上にある Jupyter のリポジトリの情報をつかって、 自分専用の一時的な Jupyter サーバーを、無料でホストしてくれるサービスである。

つまり、 ほとんどの Jupyter の環境を、ブラウザを用意するだけで実行できる。

しばらく非アクティブにしていると、セッションが切断されてしまう問題はあるものの、 アクセスしたユーザー固有の環境を、会員登録もなしにブラウザで開くだけで使用できるのは大変ありがたい。

### Binder を起動するタグを変更して、 .NET のバージョンを使い分ける

Binder では、起動する Github リポジトリコードのブランチやタグを選択できるので、以下のように敢えて古いバージョンの .NET Interactive を指定することで、 古い .NET のランタイムを起動することもできる。

https://mybinder.org/v2/gh/dotnet/interactive/v1.0.246201?urlpath=lab

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308278/c7109c00-17ee-5633-513b-6abaea0b6269.png)

https://mybinder.org/v2/gh/dotnet/interactive/main?urlpath=lab

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308278/2f9b5b4b-56be-769a-32d1-e8b8ea5dfc4b.png)

## まとめ

.NET Interactive が提供する REPL 環境には簡単なコード補完 (IntelliSense) が働くため、単純な REPL 環境としてもなかなか優秀だ。

Binder 経由で Jupyter を起動することが煩わしければ、 

* [.NET Core 6.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
* Visual Studio Code 
* Visual Studio Code の [.NET Interactive Notebooks 拡張機能](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.dotnet-interactive-vscode)

を入れるだけで、ローカルで動く高速な REPL 環境も入れられる。

「ちょっと C# コードの実行を試したい！」という場合に、ブラウザひとつで優れた実行環境が手に入るのは魅力的なので、是非活用してみてはいかがだろう?
Twilio SMS で脱PPAP

この記事は[Twilio Advent Calendar 2021](https://qiita.com/advent-calendar/2021/twilio)と[株式会社シンプルウェイ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/simpleway)の10日の記事です。今日は15日ですが。

[Twilio Advent Calendar 2021](https://qiita.com/advent-calendar/2021/twilio) の空きがあったので過去にさかのぼってエントリーしてみました。

-----

PPAPやめたいですよね? ピコ太郎じゃないですよ。パスワードZIP・パスワードメール・暗号化・プロトコルです。

シンプルウェイでは以前プライバシーマークを持っていたのですが、その際に機密情報のやり取りをどうするかという問題に対してはPPAPでお茶を濁していました。最近ISMSの取得を目指しているのですが、セキュリティ周辺の運用を見直しているときにPPAPはどうにかしたいよねという話になり、これを機にPPAPを廃止する方針となりました。

廃止するのであれば代替手段が必要になりますが、幸いシンプルウェイではオンラインファイル共有システムを自社で開発して利用していましたので、これに機能追加することで解決することにしました。

このファイル共有システムの動作は、

![改修前シーケンス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/b5bb351d-dcd8-071d-5767-99664609270d.jpeg)


1. 自社スタッフがファイルと顧客のメールアドレスを登録
1. 送付が初回なら名前入力、2回目以降なら顧客名が表示される
1. 一意のURLが発行される
1. URLを顧客へ連絡
1. 顧客がURLにアクセス
1. 顧客がワンタイムパスワードを取得
1. ワンタイムパスワードがメールで送られてくる
1. パスワードを入力
1. ファイルにアクセス

という仕様になっています。

ところで、PPAPには

* 宛先間違いが起こりうる  
  (ファイルもパスワードもどちらもメールで送るという同じ作業なので、宛先を間違えたまま操作を繰り返す恐れあり)
* ファイルとパスワードが同じ通信経路を通る  
  (通信経路が盗聴されていたり顧客のメールアドレスが乗っ取られていたらファイルが漏洩する)

という問題があります。

これらの問題に対して上記システムでは

* 宛先間違いの問題については、(2)で顧客名とメールアドレスの組み合わせをチェックすることである程度緩和される
* 通信経路については、(4)のURLの連絡がチケットやチャット経由であれば解決になるのですが、ほとんどはメールになってしまうので、これはPPAPと大差なくなってしまいます

という状態です。

-----

さて、やっとこの投稿の本題です、上記システムのワンタイムパスワードの通信経路がメール以外になればPPAPの問題点を克服できますので、これをSMSにしてしまおうと思います。

ここ最近は窓口担当者は会社の携帯を持つのが当たり前になりつつありますので、概ねこれでカバーできるでしょう。(一応旧来の仕様も残しておいて、番号を入手しづらいようであればURLの送付経路を変えることで代替可能という運用ルールにすることにします)

改修後の動作は、

![改修後シーケンス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/f116bbd2-498e-49b7-60d0-0f4f6a040d26.jpeg)

1. 自社スタッフがファイルと顧客のメールアドレス・電話番号を登録
1. 送付が初回なら名前入力、2回目以降なら顧客名が表示される
1. 一意のURLが発行される
1. URLを顧客へ連絡
1. 顧客がURLにアクセス
1. 顧客がワンタイムパスワードを取得
1. ワンタイムパスワードが**SMS**で送られてくる
1. パスワードを入力して
1. ファイルにアクセス

という仕様になります。

今回上記のSMS送信部分をTwilioのサービスで実装しました。

実装してわかったのですが、Twilio の SMS 送信って本当にかんたんですね。

実は上記システムはFreePascalという言語でApacheのモジュールとして開発されているので、APIがOAuthとかだと実装が面倒なんですよ。しかしTwilioのAPIはBasic認証でステートレスでAPI実行できるので、レガシーなプログラミング言語でもササッと組み込みてることがラクですね。

SMSを送るならたったこれだけです

```
$ curl 'https://api.twilio.com/2010-04-01/Accounts/[アカウントSID]/Messages.json'　\
  -X POST \
  --data-urlencode 'To=+819012345678' \
  --data-urlencode 'MessagingServiceSid=[Messaging Service Sid]' \
  --data-urlencode 'Body=Your password: 87654321' \
  -u [アカウントSID]:[Authトークン]
```

改修されたあとのシステムの動作はこんな感じです。

![DEMO](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219010/c364d479-14ff-58e0-c849-0ed99933a3ed.gif)


結構理想的な動きになったのではないでしょうか。ITを扱う会社としてセキュリティには気をつけたいので、これで顧客にも示しが付きますね。

-----

なお、このシステムは商品として大々的に広報していませんが販売もしています。下記のような機能もありますのでご興味がある方は[お問い合わせ](https://www.simple-way.co.jp/contact/system/)ください。

* SaaSとしての提供または買い切り可
* オンプレ・VPS・クラウドいずれも利用可
* ファイルはサーバー内で暗号化保持
* クリーンアップ(ファイル有効期限)機能あり
* SSOは将来的機能として検討中
【2021年12月】GCP Professional Cloud Developer 合格体験記

2021年12月に [Professional Cloud Developer](https://cloud.google.com/certification/cloud-developer) 認定試験を受験し合格してきました。
この記事では、経験年数・資格、学習方法・学習時間をざっくり書いてます。

## 経験年数・資格
経験年数

- Android: 5年
- Golang: 1年
- Python: 2年
- React: 1年

資格

- AWS Cloud Practitioner 
- AWS Solution Associate Architect

本業ではクラウドを使用しておらず、副業や [ISUCON](https://isucon.net/) の練習で使ったぐらいです。
GCP に関しては CloudRun や Compute Engine、IAM の辺りを少し使ったことがあるという状態でした。Kubernetes に関してはコンテナをいい感じに制御してくれる何かという理解しかなかったです。

## 学習方法・学習時間
### Cousera
受講したコース
[Google Cloud Fundamentals: Core Infrastructure 日本語版](https://www.coursera.org/learn/gcp-fundamentals-jp): 20時間
[Developing Applications with Google Cloud 日本語版 Specialization](https://www.coursera.org/specializations/developing-apps-gcp-jp): 30時間
[Getting Started with Google Kubernetes Engine 日本語版](https://www.coursera.org/learn/google-kubernetes-engine-jp): 25時間

GCP の全体像や製品の特徴や使い所などをざっくり学びました。Qwiklabs という GCP のコンソールを動かしながら学べるハンズオンがあり実際に動かせる所が良い。
製品毎の細かい仕様については Cousera では詰めずに後述の模擬試験や問題集を解く際に詰めていきました。

### 公式の模擬試験
かなり本番に近い難易度の問題が20問あり、試験の雰囲気は掴めるかなと。
答え合わせやドキュメント読んだりで5時間程かかった。

https://cloud.google.com/certification/cloud-developer?hl=ja

### Udemy の問題集
25 × 3 + 17 = 92 問ありますが、問題が重複していたり、製品名が古いものが出てきたり、答えが間違っていたり、解説が時々なかったりなどかなりモヤモヤはしましたが、自分の調べた範囲内では他に問題集はなさそうだったので、問題があるだけでもありがたいのかなと…
全く同じ問題は出ませんでしたが、やった甲斐はありました。
かなり理解が深まった状態でやらないと正解が絞り込めないので試験直前にやるのが良さそう。
15時間程かかった。

https://www.udemy.com/course/gcp-google-professional-cloud-developer-exam-oct-2021

日本語版もあったが↑とほぼ同じ内容のはず

https://www.udemy.com/course/google-cloud-professional-cloud-developer-ja/

### 認定試験ガイド
出題範囲や事例紹介が載っている。時々見返して自分の理解度チェックに使いました。

https://cloud.google.com/certification/guides/cloud-developer?hl=ja

## 当日
2時間で50問あり、一つ一つの問題文が長いのである程度脳のスタミナを温存しておいた方が良いかなと思います。
筆者は直前まで問題を解き続けて割とへばった状態で試験会場に向かったら最初の10分ぐらい頭が回らずヒヤヒヤしていました。

## さいごに
読みづらい部分も多いと思いますが、役に立つ部分があると幸いです。
KrunkScriptの使い方

# krunker.ioについて
__krunker__とは_Sidney de Vries_と_Vincent de Vries_によって制作され、
_Yendis Entertainment_によって運営されているブラウザFPSゲームです。[^1]
モバイル版のアプリも出ています。[^2]
__krunker__はユーザーがゲームを作成して、ゲームを公開できるように設計されたオンラインプラットフォームです。自由にマップなどを作成し、手軽に公開できます。
#KrunkScript
ブラウザで[エディター](krunker.io/editor.html)を開く。
Quick Startをクリック。
scriptingをクリックすると、ウィンドウが開くので、そこにコードを記述していく。
マップの公開などは省略。

[^1]: [krunker.io利用規約](https://krunker.io/docs/terms.txt)
[^2]: [Krunker Client -Google Play-](https://play.google.com/store/apps/details?id=com.krunker.client&hl=ja&gl=AU)
# 参考
> [Map Editor Guide | Krunker.io Wiki | Fandom](https://krunkerio.fandom.com/wiki/Map_Editor_Guide)
graphQLでセッション情報をリクエストヘッダーに格納する方法【Apollo Client使用】

## 概要
突然ですが、皆さんはGraphQLをSPAなどで利用する際にセッション情報をリクエストURLのクエリ文字やGraphQLのinput部分に含んだりしていませんか？
実は、GraphQL使いたての頃の自分はリアルにセッション情報の一部をリクエストURLのクエリ文字に含んでバックエンドにログインしているか教えていました。

> ※ 今回は、NextAuthを利用しているので、セッション情報はバックエンドではなく**フロントエンド**が保持しています。
NextAuthにはsessionを管理してくるuseSessionというフックが存在します。これを利用することで、Redisの設定やCookie周りで非常に苦しめられた「バックエンドでセッションを管理する」から解放されるのです。

→ こちら[NextAuthの公式サイト](https://next-auth.js.org/getting-started/client#usesession)です。興味があればご覧になってみてください！

本題に戻りますが今回は、実際にApollo Clientの初期設定を行いながら解説していこうと思います。



## Apollo Clientをインストールする
```shell:ターミナル
$ npm install @apollo/client graphql
```
ここでは、1.**@apollo/client**と2.**graphql***という二つのパッケージのインストールを行っています。
一つ目のパッケージ（@apollo/client）はapollo clientを使う上で必要な基本的なものが大体まとまっているというものです。
例えば、Apollo Clientにおける代表的なキャッシュ機構であるInMemoryCacheやエラー処理、ローカルステート管理などが含まれているらしいです。

二つの目のパッケージ(graphql)は、GraphQLのクエリを解析するために必要なものです。


## Apollo Clientのインスタンスを初期化する

細かいヘッダーにセッション情報を追加する部分などもここに含まれていますが、切り分けるのが面倒だったので一挙に解説してしまいます。

```react:サンプコード
// 1. 必要なシンボルのimport
import {
  ApolloClient,
  InMemoryCache,
  createHttpLink,
  ApolloProvider,
} from "@apollo/client";

// 2. http linkの生成
const httpLink = createHttpLink({
  uri: `${server url}/graphql`,
});

// 3. headerをリクエストを送る前のコンテキストに追加する
const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem('token');
  return {
    headers: {
      ...headers,
      authorization: token && token !== 'undefined' ? token : "",
    }
  }
})

// 4. apollo clientのインスタンスの初期化
const apolloClient = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});
```

コードの中にコメントでざっくり「何してるか」を記述してみましたが、もう一度詳しく解説していこうと思います。

※1.の部分は単なるインポートですので割愛させていただきます。
### 2. http linkの生成
ここでは、バックエンドにリクエストを送る際のリクエストURLを作成しています。
今回のサンプルコードでは、「LocalStrageに保存してあるJWTトークンを取得し、それをheaderの中に追加する」という手順で行なっているためリクエストURLの生成部分とheaderの作成部分を分けていますが、どうやら下記のように、headerも一緒に渡すという方法もあるようです。

[コードの引用元: Apollo Clientを使ってGitHubクライアントを作成してみた](https://blog.engineer.adways.net/entry/2019/05/31/173000)

```react
const httpLink = createHttpLink({
  uri: "https://api.github.com/graphql",
  headers: {
    authorization: `Bearer ${process.env.REACT_APP_GITHUB_TOKEN}`
  }
});
```

### 3. header部分の作成
ここではsetContextという関数を使ってコンテキストの設定を行なっています。

どうやらこのsetContextという関数は、オブジェクトまたは、プロミスを返す関数を受け取り、リクエストの新しいコンテキスト（ここでは```header```）を設定するためのオブジェクトを返すそうです。

さらにsetContextの引数の関数は、基本的に二つの引数を受け取るそうで、一つ目が「**これから実行しようとするGraphQLのリクエスト**」で、二つ目が「**リクエスト前のコンテキスト**」です。

必ず二つの引数を受け取る必要があるっぽいので、第一引数を_（アンダースコア）でおいておき、第二引数からはheaderのみを受け取ることにします。（基本的に第一引数とheader以外は必要ないので）

あとは、上記でも少し触れましたが、今回はlocalStorageにJWTトークンを保存しているのでそれを取り出してheaderに追加しています。

## 4. apollo clientのインスタンスの初期化
最後の部分は、2.と3.で作ったリクエストURLとheaderをconcatさせたものを引数に渡してインスタンスを初期化させている。
これでapollo clientが作成できれば、ApolloProviderを使って下記のように、クライアント情報を他のコンポーネントで共有することができます。

```react
<ApolloProvider client={apolloClient}>
  <Component {...pageProps} />
</ApolloProvider>
```

## 最後に
何か間違っていたり、ツッコミどころがあればなんでもコメントください！🙇‍♀️

## 参考
- [Apollo Clientを使ってGitHubクライアントを作成してみた](https://blog.engineer.adways.net/entry/2019/05/31/173000)
- [Apollo client公式](https://www.apollographql.com/docs/react/api/link/apollo-link-context/)
Gtk3アプリ DateTimeピッカー

DateTimeピッカーがなかったので作ることにした。

<img width="400" alt="Screenshot from 2021-12-15 01-45-20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/8778ff36-d753-4855-850b-89a3c1eea2cc.png">

https://github.com/iotagtk1/GtkDateTimePicker

####使用するコントロールの使い方

Gtk.CalenderとGtk.SpinButtonを使います。

<img width="450" alt="Screenshot from 2021-12-15 02-01-54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/27d282fa-188f-9676-2210-e49c318e276e.png">

Gtk.SpinButtonのアジャストメントを作成します。
<img width="300" alt="Screenshot from 2021-12-14 22-59-37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/aac97180-20c6-31ba-755a-aa0644a62879.png">
<img width="300" alt="Screenshot from 2021-12-14 22-59-54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/76c34dad-dc30-040f-b267-8cba0a522993.png">

アジャストメント内で増減幅などを設定します。
<img width="550" alt="Screenshot from 2021-12-14 23-00-47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/16261e4a-7dbe-264f-f730-fa5343855210.png">

ボタンにイベントを作成します。Onを押すとインテリセンスが効きます。
<img width="400" alt="Screenshot from 2021-12-14 23-01-27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/4c322206-37ad-4cff-6cc7-e98dcefee7c0.png">

ラップにチェックを入れると数字が上限から下限へ、下限から上限へ移動できるようになります。
<img width="400" alt="Screenshot from 2021-12-14 23-01-14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/941542e1-e28f-6950-6665-3f4b1e0278c5.png">

OKボタンを押すと応答ID１が返ってくるようになっています。

```cs
 MainDialog MainDialog1 = new MainDialog();
            
 MainDialog1.DateTimeObj = DateTime.Now;
            
 var r = MainDialog1.Run();

 Console.WriteLine(r);
 if (r == 1) {
     Console.WriteLine(MainDialog1.DateTimeObj);
 }
```

[C#のバイナンスの仮想通貨のライブラリを使ってみる](https://qiita.com/iota_11/items/59564685acba166fb6a1)へ続く
iOS アプリで App Tracking Transparency (ATT) でリジェクトされた場合の対処方法

# Case 1
広告付きアプリを iOS 15 対応にしたら、ATT 関係でリジェクトされた。
iOS 13 の時に作成したアプリで、AppDelegate の _application(_:didFinishLaunchingWithOptions:)_ に _ATTrackingManager.requestTrackingAuthorization()_ を記述している場合、Xcode 13 でビルドしたバイナリは iOS 15 のデバイスでは期待通りに動作しない。
iOS 15 からアプリがアクティブ状態にならないと、ATT のプロンプト表示が行われなくなったのが原因である。この場合は、_UIApplication.didBecomeActiveNotifcation_ などの通知を UIViewController のサブクラスで受信する方法で対応できる。要は通知を受信して、_Not determined_ の場合は、_ATTrackingManager.requestTrackingAuthorization()_ を呼び出すコードを実装するだけ。
リジェクトされるまで全然問題に気づかなかった。

# Case 2
上記の実装方法で実機およびシミュレータで問題なく動作確認したのに、ATT プロンプトが表示されないという理由でリジェクトされる場合、原因はアプリではなく審査員の iOS 環境にある。設定アプリのプライバシーのトラッキング画面の「Allo Apps to Request to Track」がオフの状態で審査されると、アプリのインストール直後でも ATT プロンプトは表示されない。
App Store Connect の「メモ」に以下のようなスクリーンショットとコメントを記述して審査に提出すると良い。この現象に気づくまで、三回もリジェクトされた。アプリ側の実装に問題がないので、なかなか気づけなかった。スクリーンショットと動画のやりとりをして、ようやく原因にこぎつけた。

![ATT設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62583/a8c27690-b216-a29f-2baf-f6467047db56.png)


:::note
Please make sure that "Allow Apps to Request to Track" is on in Settings.app. If the switch is off, the App Tracking Transparency (ATT) prompt is not shown. The ATT prompt is shown at only "Not Determined" status. You should turn on the switch if you check the ATT prompt. You can also change the switch after the app is installed.
:::

# おわりに
ATT 関係は一度実装すると見直す機会がないので、リジェクトされるまで気づかない。おそらく今後は大きな仕様変更もないと思うので、今の実装方法でしばらく対応する必要はないと期待している。以上、備忘録も兼ねて、同じ状況に遭遇した誰かの参考まで。
フィーチャーで気にされる[戻る]ボタンについて

# はじめに
この記事ではGoogleゲームアプリのフィーチャーの審査においての、[戻る]ボタン(※)にフォーカスを絞ってお話しさせていただこうと思います。
[Developer向けガイドライン](https://developers-jp.googleblog.com/2017/07/standard-back-key-navigation-on-android.html)内でも記載されており、個人的に重要な要素として考えています。
実装的にというより、テストを依頼された際に観点を持っておく、期待値としての情報を持っておく目的で、参考になれば幸いです。

※バックキー、⇦ボタンなど呼称がありますが、この記事では[戻る]ボタンと記載いたします
####読了までの時間
・約5分
####ターゲット
・これから[戻る]ボタンのテストを行うが、明確な期待値をもっていない方

# [戻る]ボタンの動作について
Androidのナビゲーションバーにある[戻る]ボタンをタップした際の動作で好ましいものとしては、分かりやすく言うと下記のような動作が担保されていると指摘を受けにくいと感じます。

**①適切な箇所なら一つ手前の画面に移動する**
└例外としては、ストーリーなどの会話中、チュートリアル中、などの場面だと戻る動作が不適切な場合がある
**②タイトル画面やTOP画面（ホーム画面など戻れる階層がない場所）ではゲームを直接終了**
└直接ゲーム終了を行わず、確認のポップアップがある方が良い
**③タブ移動などの画面では前に戻らない（タブを戻ったり）**
└タブの表示されるお知らせ画面などでは、その画面が閉じるのが良い
# 実際の動作調査
1つ目に挙げた”適切な箇所”以外のところの動作について情報が少なく、期待値を出せませんでした。
解決方法として実際市場でフィーチャーされているアプリを少し調査しました。
その動作についていくつか紹介させていただきます。

|　　　　    | チュートリアル中等の<br>操作不能な箇所 | ADVパート<br>(ストーリーなどの会話中) | 補足 |
|:------|:------------------------|:-|:-|
|アプリA|アプリ終了モーダルが表示される  | 反応せず 　 |終了モーダルは専用にデザインされたのものが表示された|
| アプリB  | 特に反応せず  | ナビゲーションバー非表示  |ー|
| アプリC  | アプリ終了モーダルが表示される  | 特に反応しない  |ー|
| アプリD  | バックキーが使えない旨の表示  | オプションメニューが開く  |ー|
| アプリE  | アプリ終了モーダルが表示される  | アプリ終了モーダルが表示される  |ダウンロード中は強制終了が発生する|

上記の結果となり、アプリごとに動作はそれぞれ異なることがわかりました。
操作感が好ましかったのは以下のような動作でした。
・操作不能な箇所：アプリ終了モーダルの表示
・ゲーム中の戻ることが不適切な箇所：オプションメニューの表示


#テスト方針
ここまでに記載したような、明確に期待値が出しやすい動作については大きな方針が立てやすいのです。
しかし、実際のゲームアプリだと画面によって様々なシチュエーションがありテストケース作成もそうですが、テストする際に確認事項が多くなりテストしづらいものとなります。
以下のような方法を取ることで、そのやりづらさを無くしました。

###テストケース作成
・遷移図などでテストケースを作成し、そこでカバー仕切れない細かい遷移は実際テストしながら追加する
・無反応な箇所が多い場合などは、そのカラムを用意する

例えば、新規アプリの場合は、テストケースを用意してるうちに画面の仕様が絶え間なく変化することで、せっかく細かく作ったのにいざテストに臨むと、該当の画面がなかったり、新たな遷移が追加されてることが多いです。

###テスト実行
・下記の動作以外の場合はコメントに記載する
　・「戻る」「×」「キャンセル」ボタンが表示されている場合はそれに準拠した動作
　・それ以外の個所は1つ前の画面へ戻る
　　※強制終了など明確な不具合は報告

テスト実行者が「期待値としては良さそうだけど、この場面では適してなさそうだ。だけど期待値としてはいいんだけど...」と考える時間が多くなることが多い印象なので、ひとまず動作を記載してあとでまとめて判断する方が効率が良いと考えています。

###テスト報告
テスト後は、開発チーム側に展開して特筆した動作について想定通りなのかそうでないのかを判断してもらいます。
以下の画像はテスト報告用に各画面に対して確認した結果をまとめた例となります。
上述したとおり、[戻る]ボタンの動作で無反応となった場合にも注目するため、期待動作と無反応欄を分けています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542716/a3d764dc-a1f9-5977-e002-8080c1ec1b8c.png)

# 最後に
今回は自身が結構大変だなと感じた[戻る]ボタンについてのみお話しさせていただきましたが参考になりましたでしょうか。
フィーチャーを取るために必要なことは技術の進化と共に増えて行ったり、これまで気にされていたことが不要になっていたりとテストする身としては状況が追いにくいものだなと感じています。
新たにAndroidの機能が増えて、大規模なテストが必要なものが出てきたときには、色々試行錯誤していきたいと思います。
iOS15以降でNavigationBarの戻るボタンの文字をAppearanceの設定でまとめて消す方法

#実現したいこと
戻るボタンの文字は消しつつmenuを表示させたときには各画面のtitleが入っている状態にします。
**これをAppDelegateのAppearanceで一括で設定します。**

![Simulator Screen Recording - iPhone 13 - 2021-12-15 at 01.36.46.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/893593/60a50b56-34b9-e1f3-d5e7-28c0d19797fd.gif)


#iOS14以降のNavigationController
知っている方も多いと思いますが、iOS14から戻るボタンを長押しするとmenuが表示され、どの画面に戻るかユーザーが選択できるようになりました。

戻るの文字を消して、かつmenuを表示させたときには各画面のtitleが入っているようにするには

 - 各ViewControllerで **navigationItem.backButtonDisplayMode = .minimal** にする
 - AppDelegate内でappearanceを設定する際に**itemのtintColorを透明にする**
 
といった方法がありました。
この辺の解説やbackButtonDisplayModeの挙動はこちらの記事が詳しかったです。

https://spinners.work/posts/ios14_blank_back_button/

https://developer.apple.com/documentation/uikit/uinavigationitem/backbuttondisplaymode

#iOS15以降でどうなったのか

iOS15からの変更点として、UINavigationBarとUITabBarに
**scrollEdgeAppearance**が追加されました。
その他にも色々追加されているようですが全貌は把握していません。（どうせまたすぐ変わる）

https://developer.apple.com/documentation/uikit/uinavigationbar/3198027-scrolledgeappearance?language=objc

各ViewControllerでbackButtonDisplayModeをminimalにすることでも目標の動作にできますが、**めんどくさかった**ので色々調査してappearanceでbackButtonTitleをclearにする方法を見つけました。

#結論

AppDelegateに以下を書いて

```AppDelegate.swift
 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        let appearance = UINavigationBarAppearance()
        appearance.backButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear]
        UINavigationBar.appearance().standardAppearance = appearance
        UINavigationBar.appearance().scrollEdgeAppearance = appearance
        
        return true
  }
```
各ViewControllerのNavigationItemのtitleにmenuで表示させたいタイトルを入力します。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/893593/a9b23869-7867-6ebe-0e9e-a1ec7b7ac726.png" width=50%>

これで動画の通りの挙動になります。
もっといい方法を知っている方がいたら教えて下さい。
Node.js 複数インポート、エクスポートする方法

Node.jsの学習の備忘録と振り返りの記事です。
何かの参考になれば幸いです。
付け足しや訂正などある場合ご教授いただけると
大変嬉しく思います！！

##複数インポート、エクスポートする方法

```js

const name = "yuka";
const add = function (a,b){
  return a + b
}

module.export = {
  //定義名:値,
  name:name,
  add:add, //最後のカンマは無くてもあってもどっちでもいい
}

//===別ファイル===
const {name,add} = require("インポートしたいファイル名")
```
ゆめみとティール組織

この記事は [ゆめみ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/yumemi) の 15 日目の記事です。

# はじめに

ゆめみという組織を表現するときティール組織との共通点がいくつかあり、その内容を言語化してみる記事です。この記事では、ティール組織そのものについては解説しません。

ティール組織については、イラスト解説の書籍が簡潔な内容でわかりやすいです。

https://gihyo.jp/book/2018/978-4-297-10257-9

# ゆめみとティール組織の共通点

- 助言プロセス
- セルフマネジメント
- 自己組織化

1週間前の記事で、ゆめみでの一場面から自己組織化において必要な要素を取り上げているので、併せて参照してもらうと具体的なイメージがしやすくなると思います。

https://qiita.com/ykws/items/b404178669e62e9b4c05

## 助言プロセス

前述の記事でもあったように個々のメンバーからの提案が日常的に行われており、助言プロセスを通して実施されています。

1. 提案
2. 提案に対して助言
3. 提案の承認または改訂
4. 提案の実施または取り下げ
 
以下、書籍からの引用として、まさにこれと近い感覚があります。

> 私はこの助言プロセスの効率の良さに感動します。決定は24時間以内なのです。しかもおまけに、その決定が下されたときには、全組織にすでに支持されているのです！

ある決定に対して、決まるまで周知されないというのがこの逆の運用だと思います。
この場合、メンバーはその決定を周知されてから初めて知ります。ゆえに、その決定を受け止められずにうまくいかないケースが想定されます。決定の速度に対しても階層型の関係各所の承認を得るケースとの対比においては大きな差が生じます。決定まで時間がかかるのにメンバーに受け入れられないのでは、これは組織として大きな問題です。

助言プロセスでは、これを逆転させて、決まる前に内容を周知して助言を求め、改善していきます。ゆえに、決まった時にメンバーが受け止める準備ができている状態になっているのが大きな違いです。

GitHub での Pull Request も助言プロセスと言って良いと思います。
助言プロセスとは、組織に対して、プログラミングできない行為に対してもこの考えを拡張したとも言えます。

## セルフマネジメント

前述の記事で触れたように意思決定が個々に行われます。良くも悪くもマネジメントされません。

書籍では、セルフマネジメントを組織の形状と見る表現があります。
セルフマネジメントは自己管理と和訳されており、ミクロ視点とマクロ視点の側面があると思いました。

1. 自分自身をどのように管理するか（ミクロ視点）
2. 組織としての管理手法を個々に任せる（マクロ視点）

この記事では、一旦前者をセルフマネジメントとし、後者はセルフマネジメントの結果としての自己組織化という表現としています。

セルフマネジメントの光と闇については別の記事で取り上げたいと思います。

## 自己組織化

前述の通り、書籍では、組織としての管理手法を個々に任せた結果、自己組織化された組織をセルフマネジメントと呼ぶように見えました。

以下、書籍からの引用として、脳を例とした次のような表現があります。

> 人間の脳には850億の細胞があります。しかしそこには経営委員会も中間管理者もありません
>
> どんな重要な考えも、私が経営委員会として選んだ6つの細胞に承認されてから、私を通さなければなりません」と。脳は複雑過ぎ、ピラミッド状の組織で動かすことはできません。私たちがそれを試みても、すぐに機能不全に陥るでしょう。

鳥を例とした次のような表現もあります。

> 鳥は群れで飛んでいるとき、互いにぶつかりあいません
>
> ヒエラルキーのある集中化した意思決定方式では、このレベルの速度と複雑さをマスターすることはできません。

自己組織化を構成する要員においてセルフマネジメントは必須であり、そのものであるというのがわかったような気になりました。
ある一定の複雑さに対して速度を維持して対応するのに必要な形状であり、リアクティブプログラミングもこれに近いと感じました。

# おわりに

今回記事を書くにあたってティール組織のイラスト解説を改めて読み直しました。
助言プロセスにおいて重要な要素として以下があります。

- 言語化
- 非同期コミュニケーション
- フィードバック（助言）

言語化と非同期コミュニケーションはリモートワークにおいても必要でしたが、フィードバックはゆめみの助言プロセスに触れてから強く意識するようになりました。

また書籍ではティール組織を構成する要素として、この記事では触れていない項目もあります。

- ホールネス（全体性）
- 常に進化する目的

わかったようなわからないようなふわふわした感覚なので、別の機会で自分の言葉で言語化してみたいと思います。

# 参考

はじめに紹介したイラスト解説は、本書を基にしたものになります。
イラスト解説と比較すると分厚くて未だ積読した状態です。積読の効果もあってイラスト解説版と出会えたと思ってはいます。

http://www.eijipress.co.jp/book/book.php?epcode=2226

今ぱらっとめくったら、セルフマネジメントに自己管理ではなく、**自己経営**の和訳が当てられていたので、解釈が全く違う可能性もあるので、読んだ方が良いと感じたところです。

## 積読のススメ

https://www.youtube.com/watch?v=bV9SSN75swU
ラムダ式を用いて、拡張for文の可読性を上げる。

#問題
Listをループする際に便利な拡張for文ですが、どうしても冗長化してしまい
可読性に欠けることが多くある為、ラムダ式を用いて冗長化をなるべく防ぎたいと日々思っています。

例えばListを普通に拡張for文でループする場合は

```
List<String> list = new ArrayList<>();
list.add("赤");
list.add("青");
list.add("黄色");

for(String color: list){
 System.out.println(color);
}
```

これをラムダ式に置き換えると、、、

```
List<String> list = new ArrayList<>();
list.add("赤");
list.add("青");
list.add("黄色");

list.forEach(color -> System.out.println(color));
```

上記の場合
①：「color」の部分にループする際に代入する変数を定義
②：「System.out.println(color)」の部分にループ中に行う処理
※{}を次のように用いれば、ループ中に行う処理を増やすことも可能

```
list.forEach(color -> {System.out.println(color); System.out.println(color + "色");});
```
EKSアドオンが管理するリソース（2021/12/15時点）

注）この先のアップデートで変更あるかと思います

---

# EKSアドオン

EKSクラスタを作成するとネットワークに関するコンポーネントがデフォルトでdeployされています
これらは現在、EKSアドオンとして管理されるリソースとなっています

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eks-add-ons.html

これはそこまでガチガチに管理されたリソースというわけではなく、他のリソースと同じくk8sクラスタにdeployされているだけのものなので、変更が可能であり、それはドキュメントにもあるようにアドオンを使用する上で認められた運用です

このフィールドの変更について、 EKSアドオンが管理されているフィールドを変更した場合、その後のEKSアドオンの更新によって再度アドオンのデフォルトに戻されてしまいます
（アドオンの管理にk8sのserver-side applyを使っているそうなので、--force-conflictsオプションで上書きしているものと思われます）

どのフィールドをEKSアドオンが管理しているか、という点については、こちらのドキュメントにある通り

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/add-ons-configuration.html

kubectlコマンドで確認できますか、k8s v1.21の時点ではこれに加えて、--show-managed-fieldsオプションを付ける必要があります
例えばcorednsの場合は
`kubectl get deployment/coredns -n kube-system -o yaml　--show-managed-fields`
といった具合です

表示されたyamlの中の、`spec.managedFields` のうち、 `manager: eks` となっているフィールドがEKSアドオンの管理しているフィールドになります

# リソースは？

アドオンが管理しているフィールドを参照する方法はわかったのですが、管理しているリソースはどれなのかがわかっていません
現在の時点で、ドキュメント等は存在しないとのことでした（この先作られるかも？）
ので、現在リリースされている3種類のEKSアドオンが管理しているリソースを記しておきます

以下、namespacedなリソースのnamespaceは全て `kube-system` です

# vpc-cni

v1.10.1-eksbuild.1

- ClusterRole / aws-node
- ClusterRoleBinding / aws-node
- CustomResourceDefinition / eniconfigs.crd.k8s.amazonaws.com
- DaemonSet / aws-node
- ServiceAccount / aws-node

# coredns

v1.8.4-eksbuild.1

- ClusterRole / system:coredns
- ClusterRoleBinding / system:coredns
- ConfigMap / coredns
- Deployment / coredns
- ServiceAccount / coredns
- Services / kube-dns

# kube-proxy

v1.21.2-eksbuild.2

- ClusterRoleBinding / eks:kube-proxy
- ConfigMap / kube-proxy
- ConfigMap / kube-proxy-config
- DaemonSet / kube-proxy
- ServiceAccount / kube-proxy

# 繰り返しますが
これは記載のバージョン時点でのものです
この先のアップデートで変更がある可能性があります
【TypeScript】typeof, keyof, in の挙動に関する備忘録

## 前提

以下のような定義があるとする。

```ts
type User = {
  name: string
  age: number
}

const user: User = {
  name: 'example',
  age: 20
}
```

## typeof

### 型コンテキストでの使用

変数の型を取得することができる。

```ts
type User2 = typeof user // User2 は User型となる

console.log(typeof user)                   // object
console.log(typeof user.name)              // string
console.log(typeof user === 'object')      // true
console.log(typeof user.name === 'string') // true
```

## keyof

オブジェクトのプロパティ名を抽出し、文字列リテラルのユニオン型(String Literal Union) を取得することができる。

```ts
let keys: keyof User
keys = 'age'
keys = 'name'
keys = 'XXX' // 型 '"XXX"' を型 'keyof User' に割り当てることはできません。

// 例) GraphQL スキーマから TypeScript の型を生成するビルドツールを使っている場合
type APIResponse = {
  user: {
    id: string
    friendList: {
      count: number
      friends: {
        firstName: string
        lastName: string
      }[]
    }
  }
}

type ResponseKeys = keyof APIResponse    // 'user'
type UserKey = keyof APIResponse['user'] // 'id' | 'friendList'
```

### ルックアップ型 × keyof

型安全なゲッター関数を実装することができる。

```ts
function get<
  O extends object,
  K extends keyof O
>(
  o: O,
  k: K
): O[K] {
  return o[k]
}

const res: APIResponse = {
  user: {
    id: 'sample',
    friendList: {
      count: 1,
      friends: [
        {
          firstName: '',
          lastName: ''
        }
      ]
    }
  }
}

const user = get(res, 'user')
console.log(user) // { id: 'sample', friendList: { count: 1, friends: [ [Object] ] } }
```

ネストの深い階層を取得するために、複数の引数を取れるようにしてみる。

```ts
type Get = {
  <
    O extends object,
    K1 extends keyof O
  >(o: O, k1: K1): O[K1]
  <
    O extends object,
    K1 extends keyof O,
    K2 extends keyof O[K1]
  >(o: O, k1: K1, k2: K2): O[K1][K2]
  <
    O extends object,
    K1 extends keyof O,
    K2 extends keyof O[K1],
    K3 extends keyof O[K1][K2]
  >(o: O, k1: K1, k2: K2, k3: K3): O[K1][K2][K3]
}

const get: Get = (object: any, ...keys: string[]) => {
  let result = object
  keys.forEach((k) => {
    result = result[k]
  })
  return result
}

const abc = get(res, 'user', 'friendList', 'count')
console.log(abc) // 1
```

## in

### オブジェクトのプロパティ存在有無を判定する

```ts
console.log('name' in user); // true
console.log('xxx' in user); // false
```

### for で全プロパティを処理する

```ts
for (const key in user) {
  console.log(key) // name\n age
}
```

### Mapped types

```ts
type Weekday = 'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri'
type Day = Weekday | 'Sat' | 'Sun'

const nextDay: { [K in Day]: Day } = {
  Mon: 'Tue',
  Thu: 'Wed',
  Wed: 'Thu',
  Tue: 'Fri',
  Fri: 'Sat',
  Sat: 'Sun',
  Sun: 'Mon'
}
```

### keyof × in

mapped type は TypeScript 特有の言語機能で、それらは、リテラル型と同様に JavaScript を静的に型付けする試みにとって有用なユーティリティ機能である。これはとても強力である。なぜならオブジェクトのキーと値に型を与えるだけでなくルックアップ型とそれらを組み合わせると、どの値の型がどのキーの名前に対応するかを制約できるからである。

```ts
type Account = {
  id: number
  isEmployee: boolean
  notes: string[]
}

// 全てのフィールドを省略可能にする
type OptionalAccount = {
  [K in keyof Account]?: Account[K]
}

// 全てのフォールドをnull可能にする
type NullableAccount = {
  [K in keyof Account]: Account[K] | null
}
```
react-hook-formでフォームに入力されている値を参照する。

#概要
今日はreact-hook-formを用いてフォームの作成をする際に、watchを用いてフォームに現在入力されている値を取り出す方法説明します。

#具体的な方法
1. watchを宣言する
1. watchを使用する

##watchを宣言する
（例）

```typescript
const {
    register,
    handleSubmit,
    watch,
  } = useForm<ValuesType>({
    mode: 'onChange',
    reValidateMode: 'onChange',
 })
```

このようにregisterとhandleSubmitに加えて、watchも一緒に宣言します。
ここの書き方については[この記事](https://qiita.com/ykkamm/items/58454d5687f887fe67d6 "Qiita Home")で詳しく説明しているので参照してみてください！

##watchを使用する
（例）

```typescript
console.log(watch('user.first_name'))
```

ここでwatchの引数にはValuesTypeで指定した値を入れてください。
これによってuser.first_nameに対応したファームに書き込まれている値を取り出すことができます。

#余談
これはvalidationを自由に操作する際に用いました。
自分で用意されていないvalidationを記述する際に有用だと思います。
S3に格納されているテキストデータを読み込みブラウザ表示させる

#はじめに
・タイトル通りですが、S3に格納されているテキストデータを読み込み、JavaScriptでブラウザに表示させる方法です。


## S3とhtmlをつなぐ
・[AWS SDK for JavaScript](https://aws.amazon.com/jp/sdk-for-javascript/)というAPIを使用してs3から情報を取得します。
・これを使用するためにAmazon Cognito アイデンティティプールIDが必要なので、下記公式ドキュメントを参考に事前に作成します。
[Amazon Cognito アイデンティティを使用してユーザーを認証する](https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/loading-browser-credentials-cognito.html)

コードはこんな感じになります。

```html:index.html
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.991.0.min.js"></script>
<script>
var albumBucketName = '******'; //S3のbucket名
AWS.config.region = 'ap-northeast-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: '******', //事前に作成したAmazon CognitoのID
});
// Create a new service object
var s3 = new AWS.S3({
  apiVersion: '2006-03-01',
  params: {Bucket: albumBucketName}
});
</script>
```
これでSDKが使えるようになりました！

##バケット内の特定のファイルの中身を取得しブラウザ表示
file_nameの部分に「S3内に置いているファイル名」を定義してファイルの中身を取得します。
今回のファイルの中身は、「LINEから送られてきた情報が入っている」と想定しています。
具体的には、下記のようになっているとします。

```test.txt
テキスト内容**=**ユーザー名**=**ユーザーアイコンURL
```
ちなみに今回はこれ(\*\*=**)を区切り文字とします。イビツですが。

この情報を受け取り、ブラウザ表示させるまでの方法を書いていきます。

```html:index.html
<div class="text_contents text_container"></div>
<template id="new_text_template">
    <div class="text_content">
        <div class="faceicon">
            <img src="">
        </div>
        <p class="new_text text"></p>
    </div>
</template>

<script>

// 1. albumBucketName内のfile_nameにあるテキストを取得
function S3_getObject(bucket, key) {
    return new Promise( (resolve, reject) => {
    // getObject関数で必要なファイルの中身を取得！！！！！
        s3.getObject(
            {Bucket: albumBucketName, Key: file_name },
            (err, response) => {
                if(err) { reject(err); }
                else { resolve(response); }
            }
        );
    });
}


// 2. ブラウザに表示
// テキストデータには「LINEから送信された内容」「ユーザー名」「ユーザーアイコンURL」が入っており、それを表示させるという目的だったので、それらをテンプレートにいれて表示させていきます。
// テキスト内の**=**を区切り文字として活用します。
function displayNewText(text) {
    let $text_template = $("#new_text_template").html();
    let text_device = text.split('**=**');
    $('.text_contents').append($text_template);
    let $target_text = $('div .text_content:last');
    let word = text_device[0]; //LINEメッセージの内容
    let name = text_device[1]; //ユーザー名
    let new_pic_url = text_device[2]; //ユーザーアイコンURL
    $target_text.find('.new_text').text(word + name);
    $target_text.find('img').attr('src', new_pic_url);
}


(async ()=> {
    // ①S3_getObjectでalbumBucketName内のfile_nameにあるテキストを取得します。
    let response = await S3_getObject(albumBucketName, file_name);
    // ②テキストの内容をutf-8にします
    let text = response.Body.toString("utf-8");
    // ③ブラウザに表示します！
    displayNewText(text);
})()

</script>
```
S3からオブジェクトを取得し、テキストの内容をutf-8に変換し、ブラウザに表示する一連の流れになります。
詳しい内容はインラインで記載しています。

ちなみに、テキスト内容をutf-8にする際に参考にした記事は[こちら] (https://kz-works.blogspot.com/2018/05/aws-s3-get-object-body.html)。

# まとめ
・これで、S3に格納されているテキストデータを読み込みブラウザに表示されるはず、、！
・表示されなかったらAWSの権限あたりがあやしいかもしれない。
動画の音声から文字起こしする

# 目的
動画内で話している内容を文字列に変換してファイルに保存する。

# 背景
前回のNo.3記事により、shotcutのmltプロジェクトファイルに動画を追加出来た。次はテロップを追加するための文字列を、動画の音声から文字起こしして用意する。

- No.3記事「[shotcutのタイムラインに動画を追加する](https://qiita.com/igapon1/items/af5470b75eff1f140332)」
- No.2記事「[Pythonとffmpegで動画の無音部分をカットする](https://qiita.com/igapon1/items/3faa83fc8af1543bc672)」
- No.1記事「[shotcutで動画作ってyoutube投稿してみた](https://qiita.com/igapon1/items/5486f187d7751af2ddd5)」

# 環境
- Windows10 バージョン21H1(OSビルド19043.1348)
 - Python3.9.1
 - SpeechRecognition 3.8.1
- 動画撮影：iPhoneX

# セットアップ
これまでの記事のセットアップを実施して、追加で以下のライブラリをセットアップする。
- Windowsキーを押す
- 検索ボックスに「cmd」を入力して決定する
- 以下のコマンドを実行する

```commandline:cmd.exe
pip install SpeechRecognition
```

# 使い方
[Git](https://github.com/igapon50/training/releases/tag/1.4.0)からSource code(zip)をダウンロードして、展開する。
展開したパスを「c:\Git\traning\」として、加工前の動画ファイルが「c:\temp\test.mov」なら以下のコマンドを実行する。

```commandline:cmd.exe
cd c:\Git\traning\python\Movie
python movieHelper.py c:\temp\test.mov
```
動画と同じフォルダに、動画と同じファイル名で、文字起こしのテキストファイルが作成される。

自分のコードにimportして使うなら、movieHelper.pyファイルを取り込み、以下の通り記載する。

```commandline:python
from movieHelper import MovieHelper
mh = MovieHelper('c:/temp/test.mov')
mh.mov_to_text()
```

# おわりに
私は調べていませんが、SpeechRecognitionは最大で1分程度の音声ファイルしか変換できないそうです。
なるべく長く分割して変換しないと、文章が分かれてしまうので、良い変換がされないように思います。
そのうち、最適な区切り方も考えてみたいです。
次回は今回用意した文字列をテロップにする予定です。

# 関連リンク
## 参考サイト
以下の記事を参考にさせていただきました。ありがとうございました。

- hirasu1231@ハムレット型エンジニアさん「[pythonで長い音声・動画からの文字起こしを実装する](https://www.hamlet-engineer.com/posts/mojiokoshi_long.html)」
- yukara_13さん「[PythonでWAVファイルを読み込む](https://yukara-13.hatenablog.com/entry/2013/11/09/103848)」
- siddhantsomaniさん「[.wavファイルを複数の.wavファイルに分割する方法は？](https://www.webdevqa.jp.net/ja/python/wav%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E8%A4%87%E6%95%B0%E3%81%AEwav%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E5%88%86%E5%89%B2%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%81%AF%EF%BC%9F/825724990/)」

## ドキュメント

- [Git SpeechRecognition](https://github.com/Uberi/speech_recognition#readme)
- [FFmpeg](https://trac.ffmpeg.org/wiki/CompilationGuide)