OmniAICreator/Qiita-1.07M huggingface dataset:
react-trackedを使ってreduxのような機能を作ってみる

# はじめに
多くの方が既にuseContextやuseReducerを使い、Reduxのようなprops-drillingを回避するようなHooksを作っています。そこで今回はreact-trackedを使いReduxが解決した機能の一つであるpropsdrilling回避を実現したいと思います。
react-trackedの利点については@daishiさんの[react-trackedの紹介](https://qiita.com/daishi/items/72e5ef3a46c83897af06)という記事をご参照ください。

# react-trackedを使ってみる
今回はカウンターアプリを作っていきたいと思います。

### ファイル構成

今回のファイル構成は以下です。store.jsにglobalに置きたい変数、reducerを置きます。

```
src
 |-- index.js
 |-- App.js
 |-- store.js
 |-- Components
   |-- Counter.js
   |-- Display.js
```

### store.jsに初期値を設定&Reducerを置き、Providerを定義する

今回はカウンターアプリなので、以下のように設定します。

```React:src/store.js
import { useReducer } from "react";
import { createContainer } from "react-tracked";

const initialState = { count: 0 };

const reducer = (state, action) => {
  switch (action.type) {
    case "INCREMENT_COUNT":
      return { ...state, count: state.count + 1 };
    case "DECREMENT_COUNT":
      return { ...state, count: state.count - 1 };
    default:
      throw new Error();
  }
};

const useValue = () => useReducer(reducer, initialState);

export const {
  Provider,
  useTrackedState,
  useUpdate: useDispatch
} = createContainer(useValue);
```

### ProviderをApp.jsに適用し、変数、reducerにアクセスできるようにする

Providerでコンポーネント全体をラップします。各コンポーネントに関しては下で説明します。

```React:src/App.js
import React from "react";
import Display from "./Components/Display";
import Counter from "./Components/Counter";
import { Provider } from "./store";

const App = () => {
  return (
    <Provider>
      <Display />
      <hr />
      <Counter />
    </Provider>
  );
};

export default App;
```

### Count機能を作るCounterコンポーネントとCountの値表示機能を作るDisplayコンポーネントを作成。

今回の作ったコンポーネントはComponentsディレクトリにまとめておきます。
まずはCount機能

```React:src/Components/Counter.js
import React from "react";
import { useDispatch } from "../store";

const Counter = () => {
  const dispatch = useDispatch();

  return (
    <div>
      <button onClick={() => dispatch({ type: "INCREMENT_COUNT" })}>
        Plus
      </button>
      <button onClick={() => dispatch({ type: "DECREMENT_COUNT" })}>
        Minus
      </button>
    </div>
  );
};

export default Counter;
```

次に値表示機能

```React:src/Components/Display.js
import React from "react";
import { useTrackedState } from "../store";

const Display = () => {
  const state = useTrackedState();
  return <div>count : {state.count}</div>;
};

export default Display;
```

### 完成品

完成品については[このCodeSandboxのリンク](https://codesandbox.io/s/wild-flower-1c2ln)から見ることができるので、動作を確認してみてください。

# 最後に
カウンターアプリだと結構簡単に作ることができましたが、正直これだけだとreact-truckedの「不要なrenderがパフォーマンス低下を引き起こすのを防ぐ」という面は紹介できなかったかなと思います。
詳細については上で紹介した@daishiさんの[react-trackedの紹介](https://qiita.com/daishi/items/72e5ef3a46c83897af06)という記事や[react-trackedのチュートリアル](https://react-tracked.js.org/docs/tutorial-01)を見るとよくわかると思います。

## 参考文献
今回カウンターアプリを作るにあたり以下の記事を参考にさせていただきました。ありがとうございました。

[Reduxから Context API with Hooks へ](https://qiita.com/GenkiAma/items/f2e3a48b480a89df7734)
Javascriptレシピ④

Javascriptの簡単なメモです。
アプリ制作に応用できる基本レシピですので、参考にされたい方はどうぞ。

###for文

繰り返しが決まっている時はfor文
繰り返しが決まってない場合はwhile文



for(初期値;条件式;増減式){
    繰り返し処理
｝

```js

for(i=0;i<100;i++){
    documen.write(i);
}

const list=['toypoo','pome','siba'];
for(const i=0;i<list.length;i
++){
    document.write(list[i]);
}
```
このように配列と繰り返し処理はよく使います。

```js

for(const i=o;i<10;i++){
    if(i===5){
        break;
    }
    document.write(i);
}
```
breakを使うことで処理を終了できます。

```js

for(const i=o;i<10;i++){
    if(i===5){
        continue;
    }
    document.write(i);
}
```

iが5の時は処理がスキップされます。

continueを使うと実行中の処理を中断し次の処理へ進みます。


###while文

繰り返し回数が決まってない場合はwhile文です。
無限ループは避けましょう。

```
while(条件式){
    繰り返し処理
}
```
条件式がtrueである限りずっと繰り返しますので制限をつけましょう。

```
do{
    繰り返し処理
}while(条件式)
```
こちらのdo whileはとりあえず先に処理を行います。その後条件式が真であれば処理を続けるというものです。

```js

const count = 0;
while(count<100){
    document.write(count);
    count++;
}

do{
    document.write(count);
    count++;
}while(count<10);
```

一旦処理を行いたい場合はdo whileです。

###Dateオブジェクト

DateオブのジェクトはJSの組み込み関数の一つです。
他の組み込み関数には
String,Number,Booleann,Array,Date,Mathなどがあります。

```js

//年を取得します。
const day = new Date();
console.log(day.getFullYear());

//付きを取得します
console.log(day.getMonth()+1);
//+1することを忘れずに。

//日付です。
console.log(day.getDate());

//曜日です。
console.log()day.getDay());

//年月日曜日を一気に取得してみます。
console.log(day.getFullYear()+'/'+day.getMonth()+1+'/'+day.getDate()+'/'+day.getDay());

//ゼロパディング処理をして日時を取得します。
const day = new Date();
day.getHours()+'時'+today.getMinutes()+'分'+('0'+today.getSeconds()).slice(-2)+'秒';
```
「ImportError: DLL load failed: 指定されたモジュールが見つかりません。」が出たの時の対処

## はじめに
書籍「Kaggleで勝つデータ分析の技術」を読んで
サンプルコードを入手したので早速試してみたら
しょっぱなで環境的な問題でハマったのでそのときの対処を記録する。
いまだに原因はよくわかっていない

## 発生した事象
ch01/ch01-01-titanic.py実行時
　24行目：from sklearn.preprocessing import LabelEncoder
を読み込んだところで、
「ImportError: DLL load failed: 指定されたモジュールが見つかりません。」
を出力してエラー終了する。


## 実行環境
OS:Windows10
anaconda3環境で実行
　- Python 3.7.3
　- pip 19.1.1
　- numpy 1.17.2
　- scipy-1.2.1
　- scikit-learn-0.21.2:

## やったこと
参考：https://teratail.com/questions/102949

```
>pip uninstall numpy
```
実行したところnumpyのuninstallはできたっぽいがその直後
　「PermissionError: [WinError 5] アクセスが拒否されました。: 'c:\\users\\watya\\anaconda3\\lib\\site-packages\\~umpy\\.libs\\libopenblas.TXA6YQSD3GCQQC22GEQ54J2UDCXDXHWN.gfortran-win_amd64.dll'」
というエラーメッセージを吐いて異常終了

しかしその後もメゲず

```
>pip install -U numpy scipy scikit-learn
```
したところ、こちらは正常終了。
結果、↓↓のようにnumpy, scipy, scikit-learnのバージョンが上がり
この状態で、コード[ch01-01-titanic.py]を実行したところ、エラーは発生しなくなった。

## 実行後の環境
OS:Windows10
anaconda3環境で実行
　- Python 3.7.3
　- pip 19.1.1
　- numpy 1.17.4 ←バージョンあがった
　- scipy-1.4.1　←バージョンあがった
　- scikit-learn-0.22　←バージョンあがった

## とはいえ、直ったので原因を深堀する
落ち着いエラー発生時のスタックとレースをおいかけると
"C:\Users\watya\Anaconda3\Lib\site-packages\scipy\sparse\linalg\isolve\iterative.py"
の
10行目：from . import _iterative
を読み込んだ時に「モジュール見つかりません」というエラーがでていたようだ。

このキーワードでぐぐったところ
参考：https://teratail.com/questions/93662
によると、
＞恐らく、根本原因は先の回答にもありますが、MKL関連のライブラリがないことでしょう。
とのこと。
で、結論としてはnumpy含めたライブラリの再インストールということらしい。

詳細はURLに譲るとしてMKLという言葉も初耳だし、condaとpipの混合は危険とか
これも初耳だし、なんで危険なんだろう？という疑問すらわかないくらい自分はまだまだ無知だ
ということだけはわかった。

勉強になりました。
Unityでゲームつくりてえ：マウス関連

# マウスカーソルの座標を得る
`Input.mousePosition`

# 座標をワールド座標に変換
transform.position に収まってるやつがワールド座標。
`Camera.main.ScreenToWorldPoint(Input.mousePosition)`

# ボタン押したかどうか取る
`Input.GetMouseButtonDown(0)`
`Input.GetMouseButtonUp(1)`
0は左クリック、1で右クリック、2でホイールクリック。

# 参考
http://negi-lab.blog.jp/MouseFollow2D
[Flutter] Sign in with Apple を Cloud Functions 無しで実装する

(過去枠が空いてたので登録しちゃいました。)

flutter の [firebase_auth plugin](https://pub.dev/packages/firebase_auth) に、[Sign in with Apple](https://developer.apple.com/jp/sign-in-with-apple/) の対応が入りました!
早速これを取り入れたので、簡単にまとめておきます。

ドキュメントとしては、以下2つを見てください。

* **[firebase auth plugin の該当 PR](https://github.com/FirebaseExtended/flutterfire/pull/1526)**
  * [PR 作者による sample code](https://github.com/FirebaseExtended/flutterfire/pull/1526#issuecomment-562193260)
* **[Firebase 公式ドキュメント | Authenticate Using Apple on iOS](https://firebase.google.com/docs/auth/ios/apple)**

## Sign in with Apple を有効に
[Apple Developer Console | Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list) からやってもいいですが、Xcode からが手っ取り早いかと思います。
Signing は Automatically manage signing をオンにしているとします。

1. `Signing & Capabilities` から `+Capability` をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159680/9b950886-d583-531b-28b1-d15adc746278.png)
2. Sign in with Apple を追加
3. entitlements に `Sign in with Apple` の項目が追加されたことを確認

## Firebase Authentication
1. Apple を有効にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159680/649d06b1-88e5-723f-f888-e011473fe0a0.png)
2. Android でも使いたいなら、諸々追加の設定項目があるので設定します。iOS だけなら、基本的にはこれだけ。
3. もしメールを送りたいとかがあれば、[Apple Developer Console | More](https://developer.apple.com/account/resources/services/list) から追加で設定を行う。

## Flutter
あとはクライアント実装するのみ。
簡単に書いておきます。

### Sign in 処理

```pubspec.yaml
firebase_auth: ^0.15.3
apple_sign_in: ^0.1.0
```

```authentication.dart
Future<AuthResult> _signInWithApple() async {
  final result = await AppleSignIn.performRequests([
    AppleIdRequest(
      requestedScopes: [Scope.fullName],
      requestedOperation: OpenIdOperation.operationLogin,
    )
  ]);
  // TODO: result.status を見てエラーハンドリング

  const oAuthProvider = OAuthProvider(providerId: 'apple.com');
  final credential = oAuthProvider.getCredential(
    idToken: String.fromCharCodes(result.credential.identityToken),
    accessToken: String.fromCharCodes(result.credential.authorizationCode),
  );
  return await FirebaseAuth.instance.signInWithCredential(credential);
}
```

ちなみに、Cloud Functions を使って Authentication の onCreate に Trigger して Firestore に User の Dcoument を作るようにしている場合は、後続の処理で Document を timeout 付き `firstWhere` で Listen する感じです。

### ボタン
あとは、[Apple のガイドライン](https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/) に従ってボタンを配置すればおしまいだと思います。
package で済ませたい場合は、例えば [flutter_auth_buttons](https://pub.dev/packages/flutter_auth_buttons) とかがあります。

あ、あとは iOS 13 以上で使える機能なので、[device_info](https://pub.dev/packages/device_info) を使って分岐を入れるくらいでしょうか。

```pubspec.yaml
device_info: ^0.4.1+4
```

```dart
Future<bool> _canSignInWithApple() async {
  if (!Platform.isIOS) return false; // Android ではこの機能を提供しない方針の場合。
  final iosInfo = await DeviceInfoPlugin().iosInfo;
  final version = iosInfo.systemVersion;
  // 13 以上なら〜
}
```
OSSと動物たち

# はじめに

動物が好きなのでOSSのロゴで動物園を作ることにしました。以降はOSSのロゴを動物と表現します。

# 前提条件
## 配置

ひとまず北海道にあるあの動物園を題材にさせていただきました。

## 受け入れる動物
受け入れる動物の条件は以下の通りです。

* その動物と分かるシルエットを含んでいる
* 〇〇フクロウとか〇〇ガエルとかの〇〇は無視する
* 名を名乗っている
* なるべくかわいくておしゃれ
* なるべく有名

# 動物園

![OSSZoo_20191226.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253933/38959a36-1a07-6cd0-d4ba-d295fc533af9.png)

動物が足らないのでフレームーワークとかOSSコミュニティのロゴもねじ込み始めました。

# おわりに

個人的にはmoloch, wolfSSL, FreePBXあたり好きです。まだ全然動物が足りないのでこれから必死で探します。
動物園変えたり水族館にしたりした方がいいのかも。。
(著作権問題等ありましたらご指摘ください。）
サンプリング定理と画像処理における補間

# 目的
画像処理100本ノックに挑戦中です。Q.27はバイキュービック補間ですが、どうもサンプリング定理の応用らしいです。ここらへんをちゃんと理解するためにサンプリング定理を復習します。

# サンプリング定理
観測対象は連続実関数$f(x)$です。離散サンプリングは、コム関数で表現されます。

```math
s(x) = \sum_n \delta(x-nL)
```

$L$はサンプリング間隔です。サンプリング後の信号は

```math
\tilde f(x) = f(x)\sum_n \delta(x-nL)
```

とあらわされます。

これをフーリエ変換します。畳み込みの定理より

```math
\mathcal F[\tilde f](\nu) = \mathcal F[f] \otimes \mathcal F[\sum_n\delta(x-nL)]
```

となります。コム関数のフーリエ変換は

```math
\mathcal F[\sum_n\delta(x-nL)] = \frac{1}{L}\sum_n\delta(\nu- n/L)
```

です。これから、

```math
\mathcal F[\tilde f](\nu) = \frac{1}{L}\sum_n F(\nu- n/L)
```

となります。元の連続信号$f$のフーリエ変換$F(\nu)$を$1/L$周期で並べたものになるわけです。サンプリング間隔を小さくすれば、この周期は長くなります。つまり、十分に小さなサンプリング間隔をとれば、隣り合った$F(\nu)$同士が重なり合わなくなります。実関数のフーリエ変換が偶関数となることに注意すれば、

```math
\nu_{\rm max} < \frac{1}{2L}
```

を満たすようにサンプリングすればよいわけです。これがサンプリング定理です。信号が含む最大周波数の2倍以上のサンプリング周波数が必要ということです。2倍なのは実関数のフーリエ変換が偶関数であることに由来するわけです。

さて、この条件を満たしている場合、隣り合う$F$同士は重なり合っていないわけですから、周波数空間上で幅$1/L$の矩形関数($\times L$)をかけてやれば元の$F(\nu)$が得られるわけです。実空間で言えば、

```math
\mathcal F[L\times {\rm rect}_{1/L}] = L\times \frac{\sin(\pi x/L)}{\pi x}
```

より、sinc関数を離散サンプリングされた信号$\tilde f$に畳み込んでやれば元の連続信号$f$が復元出来ることになります。このsinc関数の周期は$2L$ですから、畳み込んでも、サンプリングした点において寄与するのはその点のみであり値が変わらないことがわかります。うまく出来ています。

電気信号などであれば、サンプリングされた離散パルス列$\tilde f$に理想ローパスフィルタをかけてやれば連続信号$f$が生成出来るわけです。
画像処理のように計算機上でデジタル的な計算をする場合は、実空間での畳み込みによって任意の位置$x$におけるアナログ信号値が得られます。

# 離散信号から連続信号を復元してみる
元の信号を$f(x) = \exp(-\frac{x^2}{2\sigma^2})$とします。サンプリング間隔は$L=1$とします。

```c++
#include <iostream>
#include <vector>
const double pi = 3.14159265358979323846;

int main()
{
	int N = 1024;
	auto gauss = [&](double x)
	{
		double m = N / 2;
		double s = 100;
		return exp(-(x - m) * (x - m)/2./s/s);
	};
	std::vector<double> data;
	for (int i = 0; i < N; i++)
	{
		data.push_back(gauss(i));
	}

	auto f = [&](double x)
	{
		double ret = 0;
		for (int i = 0; i < N; i++)
		{
			double d = x - i;
			if (std::abs(d) > 1e-5)ret += data[i] * sin(pi * d) / pi / d;
			else ret += data[i];
		}
		return ret;
	};

	for (double x = N/2-10; x < N/2+10; x += 0.2)
	{
		std::cout << x << " " << f(x) << " " << gauss(x) << std::endl;
	}


	return 0;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/35ba0014-ffcd-6bc8-abb1-cd19b597ac1f.png)
実線が真の値、点が復元した値です。整数点しか測定していないのにちゃんと復元出来ています。

# バイキュービック補間との関係
バイキュービック補間はsinc関数を3次近似した式を用いるらしいです。補間というよりは"回復"と言った方がしっくりきます。もちろん、単一画素内での急激な変化がない前提でないと正しく回復出来るわけではないのですが。
詳しい計算は今後書く予定の【画像処理100本ノックに挑戦】記事中でしてみるつもりです。
Hello! After World!! - 初心者がelixirでオンラインゲーム製作に挑戦してみた　デモ公開編


この記事は、[「fukuoka.ex Elixir／Phoenix Advent Calendar 2019」](https://qiita.com/advent-calendar/2019/fukuokaex)21日目の記事です。

# ・目次

昨年のfukuoka.exアドベントカレンダ([Hello! After World!! - 初心者がelixirでオンラインゲーム製作に挑戦してみた](https://qiita.com/GKBR/items/653c8f56f5ac86ab81b0))から1年が経ちました。本日は「2019年12月21日にゲーム公開」の公約？を実行に移したいと思います。



# ・参考文献 
|No.|書籍名|著者|出版年|
|:--|:--|:--|:--|
|1|MMORPGゲームサーバープログラミング|ナム ジェウク|2005|
|2|オンラインゲームを支える技術　壮大なプレイ空間の舞台裏|中嶋 謙互|2011|
|3|クラウドゲームを作る技術　マルチプレイゲーム開発の新戦力|中嶋 謙互|2018|
|4|ドラゴンクエストXを支える技術　大規模オンラインRPGの舞台裏|青山 公士|2018|
|5|プログラミングElixir|Dave Thomas|2016|

# ・開発環境

|PC|Mac Book Pro (Retina, 13-inch, Late 2013) |
|:--|:--|
|OS|Mojave|
|Memory|8GB|
|言語|elixir v1.7|


# ・デモ動画

[<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256958/9bcea53d-4b88-4fb8-1cb3-3e8914e6c95e.png">](https://youtu.be/nwxHhOcTHBw)
画像クリックで動画ページに遷移します。



# ・まとめ
- elixirで作成したmmoのデモ動画を公開しました。
- 2020年1月or2月からαテストを行います。
- テストにご協力いただけると助かります。


最後まで読んでいただきありがとうございました。

elixirのお仕事探してます。
SwiftUIでgit-blame-pr.plをMacアプリにしてみた

この記事は、[ZOZOテクノロジーズ #4 AdventCalendar2019](https://qiita.com/advent-calendar/2019/zozo_tech4)の記事です。
昨日は@satto_sannさんの[「FastAPIの負荷実験環境を作ってみる」](https://qiita.com/satto_sann/items/27c1f3712dded0e8ac85)でした。


さて、あるコードが、どういった背景や意図で変更されたのかを知りたいことは、よくあることだと思います。そういった場合に[git-blame-pr.pl](http://blog.kazuhooku.com/2017/12/git-blame.html)を使うと、そのコードがどのプルリクエストで変更されたかを簡単に知ることができます。

これはCLIでそのまま使うだけでも十分便利です。
ただ使用頻度が高いこともあり、ユースケースに沿ったGUIが欲しくなりました。
そこで、git-blame-pr.plが出力した結果の行をクリックするだけで、該当のWebページに遷移できるMacアプリを作ってみました。

出来上がったものは下記のリポジトリで公開しています。
https://github.com/maoyama/GitBlamePR
![Dec-20-2019 23-50-30](https://user-images.githubusercontent.com/1035994/71262771-d46fb500-2383-11ea-9646-f0b991248c44.gif)

GitHubの[リリース](https://github.com/maoyama/GitBlamePR/releases)から最新のGitBlamePR.app.zipをダウンロード、解凍するだけで使えます。ぜひ試してみてください。
※macOS Catalinaが必要です。

## 実装内容の紹介
UIはAppKitではなくSwiftUIで実装しています。
以下のコードがUIにおいては全てです。SwiftUIを使っているので、Storyboardやxibファイルもありません。

```swift

struct GitBlamePRView: View {
    var model: GitBlamePRViewModel
    var textOnCommit: (String) -> Void

    @State private(set) var fullPath: String = ""

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            TextField(
                "Enter full path",
                text: $fullPath,
                onEditingChanged: {_ in },
                onCommit: {
                    self.textOnCommit(self.fullPath)
                }
            ).lineLimit(1)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
            Divider()
            ScrollView(.vertical, showsIndicators: true) {
                VStack(alignment: .leading) {
                    if !model.error.isEmpty {
                        Text(model.error)
                    }
                    ForEach(model.lines, id: \.id) { line in
                        HStack(alignment: .top, spacing: 12) {
                            Text(line.message)
                                .font(Font.system(.caption, design: .monospaced))
                                .foregroundColor(.accentColor)
                                .frame(width: 80, height: nil, alignment: .trailing)
                                .onTapGesture {
                                    NSWorkspace.shared.open(line.url)
                                }
                            Text(line.code)
                                .font(Font.system(.caption, design: .monospaced))
                                .frame(width: nil, height: nil, alignment: .leading)
                        }
                    }
                    HStack {
                        Spacer()
                        EmptyView()
                    }
                }.padding()
            }.background(Color(NSColor.textBackgroundColor))
        }
    }
}

```

「Better apps. Less code.」とAppleが謳っている通り、とても少ないコードで実現できています。
またSwiftUIは、全てのAppleプラットフォームで使えます。そのため、僕のような普段はiOSアプリの開発をしているプログラマでも、macOSで動くアプリを作る敷居がとても低くなりました。


この記事は以上です。
明日は@alpha_gotoさんです。お楽しみに！
Scrach for FX RnDTASK

**このトピックはHoudiniAp_User向けに作成しています**



**FX RnDについて**

RnDについてFXSupervisorの立ち位置、シニアArtistの立ち位置から
それぞれの観点から得た知見をみなさんに共有しようと思います。

**そもそもRnDってなに?**
-RnD-
Research & Development(リサーチ＆デベロップメント)の略
コンピューター用語のひとつで主に**研究開発**の事を指します。

例えば
Procedual Modeling/Animationの設定
DestructionSimulationのSetup開発であったり
Constraintの新規パターンの設定
FX Elementの表現開発及び技法提案とRnD
とかなり幅が広い。

プロダクションやStudioによっても
RnDの認識が違うのも押さえておきたいポイントです。

**FX工程から見るRnDについて**
僕が
FX工程でRnDを依頼/受注する際に気をつけている事を共有します。

**:GOALを設定**
RnDの目的が何なのかをきちんと明確にします。
(Lookdev込みのFX要素開発なのか,チーム内共有のFXAssetなのかとか...)
**TASK managementが下手くそだと無駄なコストを湯水のごとく
消費しがちなので気をつけるべし！**

**:誰に共有(見せる)するのか**
RnDの結果を**誰に向けて**共有するのかを明確にする。
**Dirや監督にルックの方向性を提示するのか?**
**FXSVにチーム内共有を目的としたAssetを提示/プレゼンするのか？**

**結果のプロセスを残して共有する**
具体的な進捗を目に見える形で共有しておく事で管理しやすくなる。

以上が私の中でPJや開発する際に気をつけている事です。
![gif_A.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179218/f57ebd0c-c153-5855-c5d9-efc41c25f37c.gif)
---

さてさて....
せっかくHoudini関連のtipsなどを共有する場所なので

Houdiniを使用したRnDの紹介をします。

:**Bubble(泡)**
:目的と課題
ルック... フォトリアルでもなく作画チックなものでもない中間的な印象を出したい。
オーガニックさをどこかに入れたい。
量産できるようにしたい。

**FXコンセプト**
![fx_B.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179218/7761b136-af71-0fcc-f9ea-01e894ed738f.gif)

![fx_ref_A.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179218/8ca9fa7c-c93a-b77f-4819-33db1be06458.gif)
---
Sample hip_file
https://drive.google.com/open?id=1W2FCVTNuQLm_Y7_kw7NobMJElJIIHIOj

諸事情の関係で
途中経過までしか共有できません....悲

通常の泡表現に関しては
おそらくcopyやflipSimulationを使用して
アプローチをとると思いますが....

Sampleは収束表現とdeformingにフォーカスした
アプローチです。


暇な時にでもだらだらと見てやってください。


以上です


今年は非常にラフな内容にしました。(ちーぷ？)

近いうちにまたデカめの内容を公開できる？
と思います〜

それでは〜


ps
マレーシアは暑いです
屋台のアイスティーでお腹壊しました笑
年末に帰国しますので
日本食だべにいきたいですねー
windows上でubuntuしたいならhyper-Vじゃね

# ある日の俺氏
- 最近までバリバリプログラム組んでたmacの調子が悪い
- pythonでパパっとプログラム組むくらいならわざわざmacじゃなくてメインの自作PC(dual display)を使いたい
- でも仮想環境をvmとかvirtualboxで組むと調子も悪いし,なんかマシン性能最大限まで活用されていない感すごい
- [Windows Subsystem for Linux](https://www.atmarkit.co.jp/ait/articles/1903/18/news031.html)はいい感じだけどに日本語表示でバグったりmatplotlibとか使ったら表示できない(ホントはできるけど設定面倒)
- WSL2が来るまでまてないなぁ

# hyper-vがあるじゃないか
- hyper-Vとは
  - windowsが標準で持ってる仮想化技術
  - メモリを無駄なく使えるらしい
  - 詳しくは[いまさら聞けない！Hyper-V入門](http://www.itstaffing.jp/engineer/entry/20170726_1)をチェック!

# さあ導入だ!
- まずは前提条件として`windows10 PRO`以上のOSグレードを使っているかがポイント
- それ以外の人は,まずはOSバーションをアップしましょう

1. hyper-Vを有効化
  - [ここら辺を見ながら](https://docs.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v)hyper-Vを有効化

2. hyper-Vクイック作成を起動
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243429/ad8898d2-6853-b372-afb6-8e92b870c2f9.png)

3. 画面指示に従って環境作るンゴ
4. hyper-Vマネージャーから起動
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243429/9463d258-bfcc-ea8a-3407-54a3343573eb.png)

# 完成
- あとは使ってみるだけ,かなり簡単に作れるし動作もいい感じだと思います.
- windowsとの共有ディレクトリも案外簡単に作れるそうなんでやって見ます.
- [Hyper-V 仮想マシンの ゲストUbuntu から ホストWindows の共有フォルダをマウントして利用](http://hxn.blog.jp/archives/19151985.html)
Pythonの変数とオブジェクトID

# はじめに

[いなたつアドカレ](https://qiita.com/advent-calendar/2019/allinatatsu)の二十一日目の記事です。

今日はちょっとPythonのオブジェクトIDと ~~参照渡し~~ 変数のお話を

普段Pythonをあまり使わない人間なので間違ってる部分勘違いしてる部分ありましたら優しく訂正をお願いします。。。。。。

# Python's Tips

- Pythonは全てがオブジェクト
- オブジェクトにはそれぞれオブジェクトIDがふられている
- 変数にはオブジェクトIDが代入される
- 関数呼出し時の引数（変数）にもオブジェクトIDが渡される

# オブジェクトのIDを確認する

```test.py
num1 = 1
num2 = 2
print(id(1)) # 1
print(id(num1)) # 1

print(id(1 + 1)) # 2
print(id(num1 + 1)) # 2
print(id(num2)) # 2
```

1と2のIDをいろんな方法でだしてみました。

```
$ python test.py
140280906740832
140280906740832
140280906740864
140280906740864
140280906740864
```

こんな感じの出力になりました。
もう一度実行してみます。

```
$ python test.py

140040431375456
140040431375456
140040431375488
140040431375488
140040431375488
```

順番的には上から1,1,2,2,2のIDが出力されていますが、1回目と2回目で出力されている値はちがいますね。
そして1とnum1のオブジェクトIDが同じですね。
ここからPythonのオブジェクトIDは動的に決まっており、1と1を入れた変数のオブジェクトIDが共通であることがみて取れます。

では次の実験です。

```test2.py
num1 = 1
num2 = 2
print(id(1))
print(id(num1))

num1 += 1

print(id(num1))
print(id(num2))
```

実行結果

```
$ python test2.py
140413757891680
140413757891680
140413757891712
140413757891712
```

2つめと3つめの間でnum1が1から2に変わってますね、ここでオブジェクトIDも変わってます。

次の実験

```test3.py
num = 1
list = [1]

print(num)
print(id(num))

num = 2
print(num)
print(id(num))

print(list)
print(id(list))

list[0] = 2

print(list)
print(id(list))
```
実行結果

```
$ python test3.py
1
140609807909984
2
140609807910016
[1]
140609798595120
[2]
140609798595120
```

はい、数字は1から2に変わるとオブジェクトIDが変わってますが、リストは中の値が変わってもオブジェクトIDが変わりません。

# 関数に渡す

```test4.py
number_list = [1,2,3,4,5,6,7,8,9,10]

def show (arg):
    print(arg)
    print(id(arg))


def update_list (arg):
    arg[0] = 0

print(id(number_list))
show(number_list)
update_list(number_list)
show(number_list)
```
実行結果

```
$ python test4.py
140048610816560
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
140048610816560
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10]
140048610816560
```
関数に渡しても中身を書き換えてもオブジェクトIDが変わってないことがわかりますね。

# まとめ

Pythonは ~~参照渡し~~ オブジェクトIDを渡しており、数字などのイミュータブルな値は ~~それぞれ固有のオブジェクトIDが存在するため、関数内部で値を書き換えると参照しているオブジェクトIDが変わるため、参照を渡してはいるものの実質値渡しのような挙動をする。~~ 変数に代入することしかできず、変数の代入は別のオブジェクトIDを代入することになり、呼び出し元のオブジェクトには影響を与えない。
リストなどのミュータブルなオブジェクトの内部状態を変更すると、リストそのもののオブジェクトIDが変化するわけではないので、関数内部での変更は同一オブジェクトIDを持つ変数やオブジェクトに影響を与える。もちろん、変数に別のリストを代入すれば別のオブジェクトIDになり、外部のオブジェクトには影響を与えない。
CentOS8のDockerイメージで送信専用SMTPサーバー

#はじめに
以前投稿した「[Dockerで送信専用メールサーバーなうに使っていいよ。](https://qiita.com/takeyamajp/items/be4ccc61862de3b121bf)」はCentOS7ベースのDockerイメージでした。

今回、CentOS8ベースに対応させたので記念投稿です。
https://hub.docker.com/r/takeyamajp/postfix

#CentOS7版からの変更点

- Microsoftなどビッグネームのトレンドに追従して証明書の暗号化レベルを引き上げました。
- postfixのバージョン変更に伴ってnewaliasesの整合性チェックが厳しくなっているので、警告が出ないように設定方法を変更しました。
- rsyslogのバージョン変更に伴って、docker向けの設定を変更しました。
- supervisorのバージョン変更に伴って、docker向けの設定を変更しました。

#その他
今後centos8ベースのDockerfileを作る人に、rsyslogやsupervisorを使う場合の参考になればと思います。
知らない人は、必ずハマりますからね。

Docker hubで星を付けて頂けると励みになります。
LINEWORKSと連携して音声メッセージのやりとりをする

## 概要
こんにちは。株式会社ネインというヒアラブルデバイスを開発している会社でアプリエンジニアをしているmiyataです。
まずはタイトルに書ききれなかったので「LINEWORKSと連携して音声メッセージのやりとりをする」とは一体どういうことかを説明します。
**LINE WORKSのBotとGCPを使い、LINE WORKSのトークルームにイヤフォンで録音した音声と、その音声をGoogle音声認識したテキストを投稿するBotを作りました。**
LINE WORKSで音声メッセージをテキストとメッセージを送ることができれば、トランシーバーのように利用することができ、チャットを利用しているデスクワーカーと、フィールドワーカーがシームレスにやり取りできる！と考えて機能を実装しました。
## 全体像
![lineworks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541471/c023528e-2d59-141b-9ed1-e0692a48a110.png)

## GCPサーバー
今回サーバーはGoogle Cloud Platformを使い、アプリとLINE WORKSサービスのブリッジ機能を開発しました。
### User Managementサーバー
LINEでログインした情報を元にTokenサーバーで管理します。これにより、LINE WORKSログインでアプリからサービスを利用できます。
### Botサーバー
録音した音声ファイルを受け取り、保存してURLを取得します。
その後その音声をGoogle Cloud Speechによりテキスト化します。
さらに、テキストと、URLをLINE WORKSのルームに投稿します。
## LINEWORKS管理機能
現在、公式BOTとしては登録していないため、導入時に管理者がサーバーとやりとりするためのキーを使って都度BOTを登録する形にしています。（今後、もっと簡単にBOT導入できるようにする予定です。）
## アプリ利用
今回、弊社の「Zeeny」アプリの追加サービスという形で実装しました。（※ 開発者用機能で、正式公開していません。）
<img width="375" alt="IMG_1408.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59087/b7462454-b5fb-0def-8656-ac6de538251b.png">
主に以下の機能を実装してあります。
1. LINE WORKSにログインして音声をアップロードする機能
2. 届いた他の人が投稿したLINE WORKSの音声投稿を再生する機能
### 1. 音声アップロード
LINE WORKSログイン画面を用意してアクセストークンを取得する。
イヤフォンから音声録音を開始し、録音した音声データをアプリ内に保存。
音声データをサーバーにアップロード
### 2. 音声再生
LINE WORKSから届く通知に音声認識されたテキストと、音声データダウンロードURLを仕込む。
通知が来た際に、そのURLから音声データを取ってきて、イヤフォン経由で再生する。
## 動作
(※こんな感じでLINE WORKS上に投稿されます。ネイン代表の山本がテストしている画面キャプチャーです！)
<img width="375" alt="IMG_1407.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59087/4fca6b9a-ddc6-785e-00d8-301b63ea6fc7.png">
## 苦労したところ
一度音声データをアップロードすることになるので、メッセージ送信から受信までのタイムロスが気になるところです。今後ストリーミングも併用するなどして、パフォーマンスを上げられたら、と考えています。
最初はLINE WORKSログインまで作り込んでいませんでしたが、実際に運用する際には利用者が簡単に利用できた方がいいだろう！ということで、Token管理を考えて設計し直したので、サービス利用設計を考える上でいい勉強になりました。
## おわり
本格的に展開していく際には、Botの設定をあまり技術的に詳しくない各グループの管理者が行う必要があります。もっと簡単に登録できるようにしていきたです。
さらに、音声データなので、増えていくと肥大化してサーバー利用料金がかさんでいく問題があります。実際には一定期間経ったら消したり、現実的な運用や料金体系を探っていくことになると思います！
お読みいただきありがとうございました！:fist:
mySQLから取得した文字列を改行したまま画面に出力する方法【PHP】

PHPとmySQLを使って、SNS風のメッセージ掲示板を作成しました。

今回作成にあたり苦労した機能の実装方法をアップします。

【実装機能】

メッセージエリアに入力した「改行あり」の文字列をmySQLでDBから取得し、メッセージボードに出力する際に、改行の場所を維持したまま出力するという機能。

完成画像にあるように、メッセージ文がしっかりと改行されている事が分かると思います。

【完成画像】
<img width="1379" alt="スクリーンショット 2019-12-21 15.19.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518144/36fbed91-58f4-f64f-b4b6-4630996bd1ee.png">


私と同じように、未経験からエンジニア転職を目指しWEBサービスを作成している方にむけて、参考になれば嬉しいです。


【今回の実装した機能の流れ】

・textareaに「改行あり」のメッセージを入力
・POST送信でDBへメッセージを格納
・格納したメッセージをSELECT文で取得
・改行の位置はそのままに画面へ表示

※今回の記事ではPOST送信やSQLのSELECT文は問題ない前提です。
       
【コード】

<pre><code>
function sanitize_br($str){
  
    return nl2br(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));

}
</code></pre>

上記コードで、SQLから取得した文字列を、改行の位置はそのままに表示出来るように入力文字列を変換しています。

今回のように、ユーザーがtextareaに入力した文字を一度DBへ格納した後、画面へ入力文字を出力する場合、入力文字にHTMLダグやスクリプト言語を含めた不正なデータを入力される恐れがあります。

そのような不正入力を防止するため、textareaに入力される文字のうち、HTMLタグやスクリプト言語をコードではなくそのまま文字列として認識し出力してあげる必要があります（サニタイズ）。

そこで今回はサニタイズの機能に

①HTMLタグ「　< , > 」や「　"　」「　'　」「 ｀ 」は文字列として表示

②改行（\r , \n ,\r\n )を&lt;br /&gt;に置換

以上の2つの機能を持つサニタイズを検討したところ、PHPで準備されている標準関数で解決が出来ました。

※記事投稿後にご指摘いただき「標準関数」へコード修正しました。

今回の標準関数により、不正入力によるページ遷移は不正画面の表示を防止した上で、<br>タグを挿入したことにより、改行位置はそのままに出力する事が可能です。


【本コードによるサニタイズ効果】
<img width="1024" alt="スクリーンショット 2019-11-19 0.47.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518144/c3d02271-b876-2657-07ed-6d5042ec1409.png">

通常、&lt;br&gt;タグは、サニタイズしていなければHTMLタグと判断され、&lt;br&gt;が記入された場所で改行されます。
&lt;div&gt;もタグと判断され、本来はメッセージ画面には表示されません。
しかし今回の機能で、HTMLタグは全て文字列として扱われているため全て画面に表示されています。

逆に改行の文字コードである「　\r , \n ,\r\n 」はHTML上で入力されても画面表示の際に改行されないため&lt;br&gt;タグに変換しています。
そうする事で今回実現したかった「改行位置はそのまま文字列を画面に表示する」という機能を実現出来ました。

ちなみに何度も使う可能性があったため関数にしています。

是非、同じように改行ありのメッセージ連絡画面を実装したいと思っている方は是非参考にしていただければと思います。

もし、もっといい方法がある！という方は、是非教えていただけると嬉しいです！！


最後まで読んでいただきありがとうございました。
v-onでイベント情報を取得する ❏Vue.js❏

今回はある場所にマウスが乗ったら、そこのイベント情報を取得してX軸とY軸を表示させます。

[![Screenshot from Gyazo](https://gyazo.com/a307065021cc29bcdde0f229b89fdb4b/raw)](https://gyazo.com/a307065021cc29bcdde0f229b89fdb4b)

<br>
開発環境はJSFiddle
https://qiita.com/ITmanbow/items/9ae48d37aa5b847f1b3b

```html:html
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<div id="app">
  <p @mousemove="changeMousePosition">マウスを乗せる</p>
  <p>x:{{ x }}</p>
  <p>y:{{ y }}</p>
</div>
```

```javascript:javascript
new Vue({
  el: "#app",
  data: {
    x:0,
    y:0
  },
  methods: {
    changeMousePosition(event) {
      this.x = event.clientX;
      this.y = event.clientY;
    }
  }
})
```

v-onは@に省略
`mousemove`イベントに`changeMousePosition`メソッド
メソッドの引数に`event`を取るとイベントの情報が取得できます。

`console.log(event)`イベント情報を確認してみると...
<img width="131" alt="798bf01fc6466b9f3b5da03bac08044d.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529651/33fb6add-acb0-887c-e47f-06788f7efdcd.png">
この下にもズラーッと情報がありますが、今回は`clientX`と`clientY`を使いました。

<br>
ではまた！
色覚特性とUCのお話

ちゃお！この記事は[NCC Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ncc)の20日目の記事です！

この記事では多くのユーザに使ってもらうために、デザインにUC(ユニバーサルカラー)を取り入れようね！という記事です！

1大学生が書いているので、間違っている点がありましたらご指摘ください…:sob:

#####色覚特性とは
目には色を識別する錐体細胞という細胞があります。これには3種類あり、反応する波長領域が短い順にS錐体・M錐体・L錐体と呼ばれます。これらのいずれかが機能しておらず、多数派の人と色の認識・識別が違う人がいます。
こういった人たちはかつて、色覚異常・色盲・色弱と呼ばれていました。
しかし、錐体細胞が正常でも色の見え方には個人差があります。異常の有無に関わらず、こういった**見え方の個人差を色覚特性**と呼びます。

###錐体細胞による色覚特性
錐体細胞が先天的に、あるいは事故や病気で、感度が落ちたり働かなくなったりすることで起こります。

錐体細胞に関する遺伝子は性染色体のX染色体に存在しています。
つまりは女性より男性の方が先天的な異常が出やすいということです。実際に、日本人では男性の約5%、女性の約0.2%がこれに該当すると言われています。

###加齢による色覚特性
年をとると以下のような変化がおきます。

角膜が黄ばむ (**黄変**)
→コントラストに対する感度の低下
→黄色や青色に対する感度の低下

水晶体が白濁する (**白内障**)
→彩度の感度の低下

###デザインで考えておくべきこと
#####明度コントラストを強めにする
色相が大きく違っていても明度が近い場合、色覚特性によっては識別できない場合があります。
#####色の組み合わせを工夫する
識別しにくい色相を把握し、使用を控える。
と言っても把握は難しいので[カラーユニバーサルガイドライン](https://jfly.uni-koeln.de/colorset/CUD_color_set_GuideBook_2018.pdf)を参考にすると良いです。
#####色以外で区別をする
そもそも色に頼らない。形や文字でわかるように。
このとき、文字の色と背景色のコントラストを強くして読めるようには…しましょう…

###参考
- [色彩検定1級 公式テキスト](https://www.amazon.co.jp/%E3%83%BBF%E3%83%BBT%E8%89%B2%E5%BD%A9%E6%A4%9C%E5%AE%9A-%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%881%E7%B4%9A%E7%B7%A8-%E3%83%BBF%E3%83%BBT%E5%85%AC%E5%BC%8F%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E7%B7%A8%E9%9B%86%E5%A7%94%E5%93%A1%E4%BC%9A/dp/490125720X)
- [色覚異常は遺伝なの?](https://www.gankaikai.or.jp/health/50/06.html)
ガンツ7回クリアの岡八郎をJavaを使って一般化しました

## はじめに
初投稿です。ITエンジニア１年目です。ご容赦ください。
この記事は超初歩的なJavaの文法しか使いません。
## GANTZとは
いきなりですが、みなさん**GANTZ（ガンツ）**って漫画知ってますか？
詳細はここでは述べませんが、強化スーツみたいのを着た主人公たちがめちゃくちゃ強い化け物と戦う、みたいな漫画です。面白いです。
ガンツの世界では敵がめちゃくちゃ強くて気をぬくとすぐに死んでしまうハラハラした世界なのですが、大阪編という話ですごい登場人物が出てきます。それが**岡八郎**です。
## 岡八郎とは
GANTZの世界で戦闘に勝って特典を貯めると、GANTZをクリアすることができます。
一回クリアすると
「元の世界に帰る」「誰かを生き返らせる」「強い武器を手に入れる」
の３つから１つを選択することができます。
普通に考えたら全クリしたら元の世界に帰りたいですよね。死にたくないし。
でも岡八郎はすごいです。
なんとあのGANTZを７回もクリアしているのです。すごすぎる。
そして毎回クリアするごとに新しい武器を手に入れているので**岡八郎**はめちゃくちゃごつい装備を手に入れているんですよね。
それまで登場したキャラと比べても異常に強キャラ感がある、インパクトのあるキャラでした
「ガンツ７回クリアの岡八郎！」
このパワーワード感はすごいです。
## エンジニアとして思うこと
さて、僕はQiitaに投稿するのは初めてですが、Qiitaはガンツについて語るところではなく、プログラミングについて語るところだと聞いています。そこでITエンジニアとしてこの
「ガンツ７回クリアの岡八郎」
について考えてみたいと思います。
まずこの文を見て、少し感のいい人ならある法則性に気づくと思います。
```7+1=8```
7はガンツをクリアした回数、8は岡の下の名前です。
これを一般化すると
「ガンツn回クリアの岡(n+1)郎」
とすることができますね。
このように```7```や```8```をベタ打ちするよりも任意の数```n```を使った方がスケーラビリティに優れており、可読性も増すような気がします。
## Javaで書いてみる
- まずは```Oka.java```という名前のファイルを作ります
- 中身に以下のコードを打ちます

```java

public class Oka{
   public static void main(String[] args){
     System.out.println("ガンツ7回クリアの岡八郎");
   }
}
```
これで準備ができました。ターミナルで以下のように打ち込んでみましょう。
わくわくしますね。

```bash

javac Oka.java 
java Oka
```
以下のように出力されれば成功です。

```bash

ガンツ7回クリアの岡八郎
```
無事岡八郎がガンツを7回クリアすることができました。
しかし、この状態だと6回クリアしたい場合や8回クリアしたい場合に対応できません
## 一般化する
さきほどのコードを少し改良して岡八郎を一般化しましょう。

```java

public class Oka{
   public static void main(String[] args){
     //岡がガンツをクリアした回数
     int n = 7; 
     //岡を表示する
     System.out.println("ガンツ"+ n +"回クリアの岡"+ (n+1) +"郎");
   }
}
```
以下のように出力されます。

```bash

ガンツ7回クリアの岡8郎
```
上のコードで```n=8```としてみると、出力結果は以下のように変化します。

```bash

ガンツ8回クリアの岡9郎
```
やりましたね。岡の一般化に成功しました。
## for分で岡を繰り返してみる
せっかくなので岡を繰り返してみましょう。先ほどのOka.javaを次のように編集します。

```java

public class Oka{
   public static void main(String[] args){
     //岡の繰り返し回数
     final int oka_itr = 10;
     //岡を繰り返す
     for(int n=0; n<oka_itr; n++){
       System.out.println("ガンツ"+ n +"回クリアの岡"+ (n+1) +"郎");
     }
   }
}
```
以下のように出力されれば成功です。

```bash

ガンツ0回クリアの岡1郎
ガンツ1回クリアの岡2郎
ガンツ2回クリアの岡3郎
ガンツ3回クリアの岡4郎
ガンツ4回クリアの岡5郎
ガンツ5回クリアの岡6郎
ガンツ6回クリアの岡7郎
ガンツ7回クリアの岡8郎
ガンツ8回クリアの岡9郎
ガンツ9回クリアの岡10郎
```
やりましたね！無事岡を繰り返すことができました。
## まとめ今後の課題
今後の課題をしては

- 岡がガンツをクリアする回数を実行時に引数として指定する
- 岡をモジュール化して外部から利用する

などが考えられますが、今回はとりあえず岡の一般化に成功したのでここまでとしておきます。
ガンツを読んでて「この岡八郎、拡張性ないな〜」と思った方がいたら、是非試してみてください。
## 余談〜岡八郎のその後〜
初登場時にものすごいインパクトを残した岡八郎ですが、そのあとすぐめちゃくちゃ強い敵にやられて死にます。完全にかませキャラとして使われてしまったのです。ガンツ7回もクリアしたのに。。
俺は忘れない。岡八郎がガンツを7回もクリアしたことを。
ラズパイで画像をGoogleDriveにアップロードするならrclone一択じゃね？という話

※この記事は大変ちんたらしています。
ダルい方は、この記事の見出し「rcloneって知ってる？（神）」からお読みください。
https://qiita.com/ElecCPinAAII/items/19f1757e89bc06535d98#rclone%E3%81%A3%E3%81%A6%E7%9F%A5%E3%81%A3%E3%81%A6%E3%82%8B%E7%A5%9E

この記事は、まっじっでっLinux、RaspberryPiを初めて:beginner:触った、
そして普段プログラミングなどは一切やらないド素人:baby:が書いたものですので、
用語の使い方が変、とか、間違ってるとか、いろいろお察し＆ご容赦ください。
完全なる素人ですが、まわりにはちらほらと神:zap:がいて、
たくさん助けていただきましたこと、改めてこちらでお礼を申し上げます。
さて。
####やりたかったこと：ラズパイでtimelapse動画を作るための写真を自動でとって、GoogleDriveに自動でアップロードする
なんでど素人がいきなりそんなことをやるんだよ、
と突っ込まれると説明が長くなるので割愛いたしますが、
とにかくやることになったのです :frowning2:
それでもカメラの操作自体はわりとあっさりできるようになりました。
でも、そこから
=>GoogleDriveの認証（OAuth2）が自動でできずにドツボにハマる
=>もうできない、無理、と死にそうになる
=>神:zap:からrcloneの存在を教わる
=>あまりにあっさりと解決
という流れでしたので、自分のメモと記念のために記事にしておきます。
##RaspberryPiで写真をとる
これもいろんな方法があって、いろんなサイトでお知恵を借りました。
一番簡単なのはシェルスクリプトでrapstillを使うことなのですが、
今回は写真をとったら、GoogleDriveに画像をアップしたいので、
pythonのpicameraを利用して写真を撮りました。

-【picamera】ラズパイで写真を撮るコードを書いてみた
https://ymgsapo.com/2019/03/25/picamera-raspi/

↑こちらを参考に。
このpythonをcronに実装すれば、写真を自動で撮るのはわりと簡単（！？）です。
（とはいえ、環境設定や謎のエラーなどで、十分もう大変だったのですが、
ここでもまわりの神:zap:に助けられました）

##画像をGoogleDriveのマイドライブにアップする
しかしながら、ここからおそろしくハマりました。
まずラズパイの画像を自動アップロードする方法としては
OAuth2とGoogleDriveAPIを利用する方法が多くのウェブページに紹介されています。
日本語だけでなく英語のページも随分見ました。
情報が古いのかもと思って、2019年内に書かれた記事も読みました。
しかし結果からいうと、どれも上手くいきませんでした。
どの記事でも、一度手動でコンソールから認証すると、
次回からは自動認証できると書いてあるのに、
毎回毎回毎回毎回、手動で認証しないと動かない :sob: :sob: :sob:
認証情報がちゃんとセーブできていないのだと思って、
かなりいろいろやってみたのですが、どの方法でも上手くいきませんでした。
いろんな人にも見てもらいましたが、結局理由はわかりませんでした。
もしかしたら職場で提供されているGoogleアカウントなので、
そもそも何か制約があったのかも？？？
##rcloneって知ってる？（神）
もう諦めかけて、手動でアップロードするしかないかと思っていたところ、
また別の神:zap:が降臨して、以下のWebページに関する啓示を与えてくれたのです。

-いるかのボックスーRaspberry PiのファイルをGoogleドライブにバックアップする
https://irukanobox.blogspot.com/2019/07/raspberry-pigoogle.html

rcloneという、これは何？プログラム？アプリ？を
こちらの記事通りにインストールして設定するだけ。
一点だけ違うのは、rcloneも日々進化しているらしく、

```
$ rclone config
```

でサービスを設定する際は、こちらの記事では

```
（12 / Google Drive）
Storage> 12
```

と書いてありますが、2019年12月現在では
13 がGoogle Driveになっていましたので、

```
Storage> 13
```

で利用設定をしました。
また変わるかもしれませんが、そこは普通にリストで表示されるので、
冷静にGoogleDriveの番号を選んでください。
全部設定が終われば、これで

```
$ rclone copy XXXX gdrive:YYYY
```

とするだけで、ファイルXXXXをGoogleDriveのマイドライブの中のYYYYフォルダーに
アップロードできるようになりました:tada:
クライアントIDやクライアントシークレットなどの情報は、
rcloneの設定の段階で手動認証する時に取得してしまうようです。
こうなるとpythonじゃなくていいので、
シェルスクリプトでrapstillを使うのが一番シンプルです。

-パソコン工房NEXMAG 定点観測カメラをRaspberry Piで作る
https://www.pc-koubou.jp/magazine/25538

↑こちらの情報をもとに、シェルスクリプトにしました。
結果としてなんと:sunny:
たった4行のシェルスクリプト↓をcronで１０分おきに走らせることで
解決してしまいました :joy: :joy: :joy:

```shell
#!/bin/sh
fn=$(date +%Y%m%d%H%M%S)
raspistill -o /home/pi/timelapse/${fn}.jpg
rclone copy /home/pi/timelapse/${fn}.jpg gdrive:timelapse-pic
rm -f /home/pi/timelapse/${fn}.jpg
```

仕事の合間にちらちらやっていただけとはいえ、
一ヶ月以上もOAuth２の認証に悩まされていたのに、
このあっさり感。
私は探し方が下手なのか、どこにもこの簡単な方法を見つけられなかったので、
こちらにポストしておきます。
ぜひ同じようなOAuth２の呪いにハマる人がいませんように :angel:

このrclone、GoogleDriveだけでなく、
いろんなcloudサービスに対応しているらしいので、
他にも使いでがありそうですね。
（私はもう使う予定は全くないけれど・・・）

このプロジェクト、いろいろ大変だったけど、まあ楽しかったです。
最後まで読んでいただき、ありがとうございました！！！
deno v0.27.0の変更点

# 概要

https://github.com/denoland/deno/releases/tag/v0.27.0

deno v0.27.0がリリースされました。

新機能に絞って変更点をまとめます。

## ファイルサーバ([std/http/file_server.ts](https://deno.land/std/http/file_server.ts))がutf8をサポート

https://github.com/denoland/deno/pull/3495

ファイルにUnicode Emoji等が含まれていると、文字化けが発生してしまう問題があったため、修正されました。

## ファイルサーバ([std/http/file_server.ts](https://deno.land/std/http/file_server.ts))がヘルプ表示に対応

https://github.com/denoland/deno/pull/3489

`--helpオプション`を指定することでヘルプが表示されるようになりました。

```sh
$ deno https://deno.land/std@v0.27.0/http/file_server.ts --help
```

## fetchがURLオブジェクトに対応

https://github.com/denoland/deno/pull/3496

下記のように、文字列だけでなく、URLオブジェクトも渡せるようになりました。

```javascript
fetch(new URL('http://www.example.com'))
```

## `Deno.dir`関数が追加

https://github.com/denoland/deno/pull/3518

引数にディレクトリの種別を渡すと、プラットフォームに応じて適切なパスを返却してくれます。

```typescript
Deno.dir('home') // ホームディレクトリ
Deno.dir('cache') // キャッシュディレクトリ
```

`Deno.dir`に渡せる引数は、下記のいずれかの文字列です。

- `"home"`
- `"cache"`
- `"config"`
- `"data"`
- `"data_local"`
- `"audio"`
- `"desktop"`
- `"document"`
- `"download"`
- `"font"`
- `"picture"`
- `"public"`
- `"template"`
- `"video"`

## `deno --version`でv8とTypeScriptのバージョンが表示されるようになった

https://github.com/denoland/deno/pull/3507

v0.26.0ではdenoのバージョンしか表示されませんでした。

v0.27.0ではv8とTypeScriptのバージョンも表示されます。
チームファシリテーションというファシリテーション像

# はじめに

この記事では、「チームファシリテーター」「チームファシリテーション」というファシリテーションの姿について、お話ししていこうと思います。

# チームファシリテーションとは

私、森は、「チームファシリテーター」と名乗って活動しています。チームを活性化したり、組織を改革する、所謂働き方改革でイメージされる活動が一般的には近いかもしれません。

私は「ふりかえり」「チームビルディング」を軸に、いろんなチームの状態を改善する、「チームをよりよい方向に導く」ことがチームファシリテーションだと考え、実践しています。チームファシリテーションの結果、チームひいては組織が、より大きなROIを生み出せるようにするのがゴールです。

# よいチームの備える5つの要素

それでは、何がチームファシリテーションなのでしょうか。
私なりの定義をここに書いて残しておきます。

私の経験上、「よいチーム」が持つ要素として、以下の5つが優れていることがわかりました。

1. 目的・目標が揃っている
2. 多様性に富んでいる
3. 関係性が密である（関係の質が高い）
4. 文化を自分たちで作り上げている
5. 自立・自律している

それぞれについて説明していきます。

# 目的・目標が揃っている

目的や目標について、チームで共通認識は取られているでしょうか？
「なぜそのチームがそのチームであるのか」というミッション・ビジョン・ゴールがチームの中で共通認識となっており、そのゴールに向かって日々の仕事ができているでしょうか。
また、そのゴールを達成するための中間目標やKPIが、チームにとって納得感のあるものでしょうか。

これらの問いに、チーム一人一人が「自分の言葉で」返答ができたとき、目的・目標が合致し、同じ方向を向くことができていると判断します。

チームファシリテーションの最初の一歩としては、チームメンバーそれぞれが思い思いの方向性を持っていて、方向性が違うということを認知するところから始まります。
全員が同じ思想を持つ必要はありません。多様性があるということを認知した上で、「個人として」のゴールではなく、「チームとして」のゴールを検討して、チームが全員で全力で前に進むことのできる環境を整えます。

このためのアクティビティとして、インセプションデッキを作ったり、チーム名を決めたり、というものがありめす。

# 多様性に富んでいる

推進力のあるチームは、チームメンバーそれぞれが別々のスキルを持っており、それが相互補完的である必要があります。
全員が画一的なスキルを持っている必要はありません。多様なスキルや考え方を持つからこそ、イノベーションは生まれますし、コラボレーションしたときのチームメンバー同士で相互に与える刺激が高まります。

チームファシリテーションの2つ目の要素は、この多様性があることを全員で知覚することです。スキルマップを作ったり、互いの価値観を共有するようなワークを行い、互いのことを深く知っていき、互いが互いを補完できるような環境を作り上げます。

# 関係性が密である

コミュニケーションが活発に行われており、チーム内でのコラボレーションが強力に行われているチームでは、問題は自然と解消されていきます。

普段のふりかえりや、内面開示のワーク、Kudoなど、様々な方法で関係の質を高めていきます。

# 文化を自分たちで作り上げている

チームのルールやリズムなど、様々な「チームを運営するために必要な活動」や「考え方」などが、固定の人間（例えばリーダーやファシリテーター）により誘発されて行われたのではなく、自分たちが自発的に作るような動きができているチームです。

次の「自立・自律」にもつながりますが、このようなチームは何か問題があったとしても、自分たちで何とかでこる、解決できる能力を持ちます。

# 自立・自律している

自分たちで改善を自発的に行い、変化や問題へも自分たちでなんとかできる。所謂自己組織化されたチームの状態です。

この状態を目指すためには、ふりかえりを自分たちで行い、改善する癖をつけるのが最初の第一歩になるでしょう。

# 5つの要素を伸ばし続ける

この5つの要素は、どんな素晴らしいチームメンバーを集めたとしても、最初から備わっているものではありません。普段の仕事を通じて、これらの要素を高め続ける必要があります。

継続したチームビルディングの活動によって、この要素を高め続けます。

多くのチームでは、チームが結成された初期段階ではこうしたチームビルディングの活動が行われるものの、チームが活況になるにつれ、行われなくなってしまいます。
そうならないようにするための効果的な活動が、定期的に行う「ふりかえり」です。ふりかえりの時間をこれらの5要素を高めるための活動に使い、強いチームを生み出していきます。

この5つの要素のどこに着目し、伸ばしていくのか、というのを、チーム自身が自走できるまで伴走し、促すのが「チームファシリテーター」だと考えています。

# さいごに

あなたのチームでは、これらの5要素はどのような状態でしょうか。
読んでいただいたあなたが「チームファシリテーター」として、チームの成長に寄与してみようと思えたなら、是非小さい1歩からでもいいので始めてみてください。

チームにとってピタリと当てはまる活動は、色々と試してみないとわかりません。
何から始めたらものかと迷う方は、ふりかえりの中で毎回1つの要素を高めることから始めてみてみるとよいでしょう。
virshでnfsのstorage poolを作る


# 環境
- debian10(buster)

# nfs serverを立てる
## nfs-serverのinstall
```
# apt-get -y install nfs-kernel-server
```

# nfsの設定
## 公開するディレクトリを設定する
nfsのテストでHostOSからmountする場合、127.0.0.1でアクセスする。192.168.1.0/24だけであると、127.0.0.1と一致しないためmount失敗してしまう
``` :/etc/exports
/home/data        192.168.1.0/24(rw,sync,fsid=0,no_subtree_check,crossmnt,no_root_squash) 127.0.0.1(rw,sync,fsid=0,no_subtree_check,crossmnt,no_root_squash)
```

## nfsv4のみを有効にする
``` :/etc/defaults/nfs-kernel-server
s/RPCMOUNTDOPTS=\" --manage-gids"/RPCMOUNTDOPTS=\" --manage-gids --no-nfs-version 2 --no-nfs-version 3\"/
```
## nfs serverの再起動

```
# systemctl restart nfs-kernel-server
```

# mount pointの作成
virshはstorage poolを`/var/lib/libvirt/images`に保存する(デフォルト)
nfs(netfs)のstorage poolを使用する場合、nfs mount pointのデクレクトリ(e.g. /var/lib/libvirt/images/nfs-pool)を作成しておく

```
# mkdir /var/lib/libvirt/images/nfs-pool
```

## nfs mountの動作確認
```
# exportfs
/home/data      127.0.0.1
/home/data      192.168.16.0/24
```

```
# apt-get -y install nfs-utils
# mount -t nfs example.com:/ /var/lib/libvirt/images/nfs-pool
# df -h
# touch /var/lib/libvirt/images/nfs-pool/aaa
# rm /var/lib/libvirt/images/nfs-pool/aaa
# umount /var/lib/libvirt/images/nfs-pool
```

# storage-poolの作成
まずpool-create-asでxmlファイルを作成しないでpoolの作成ができるかどうか確認する
成功した場合HostOS起動時に自動mountにしたいためautostartを設定する。
そのためにはxmlファイルが必要である。
そこで`pool-define-as --print-xml`を使ってxmlファイルを生成する。

### storage-pool作成の確認
```
# virsh pool-create-as nfs-pool netfs \
    --source-host=example.com \
    --source-path=/ \
    --target=/var/lib/libvirt/images/nfs-pool
```
### storage-poolの削除

```
# virsh pool-destroy nfs-pool
```

### xmlファイルの生成
```
# virsh pool-create-as nfs-pool netfs \
    --source-host=example.com \
    --source-path=/ \
    --target=/var/lib/libvirt/images/nfs-pool \
    --print-xml > /etc/libvirt/storage/nfs-pool.xml

# cat /etc/libvirt/storage/nfs-pool.xml
<pool type='netfs'>
  <name>nfs-pool</name>
  <uuid>abcd-efgh-4b16-aa0f-63f8bfa291c7</uuid>
  <capacity unit='bytes'>0</capacity>
  <allocation unit='bytes'>0</allocation>
  <available unit='bytes'>0</available>
  <source>
    <host name='example.com'/>
    <dir path='/'/>
    <format type='auto'/>
  </source>
  <target>
    <path>/var/lib/libvirt/images/nfs-pool</path>
  </target>
</pool>
```

### storage-poolのdefine

```
# virsh pool-define etc/libvirt/storage/nfs-pool.xml
```

### autostart

```
# virsh pool-autostart nfs-pool
```

### pool作成
```
# virsh pool-create etc/libvirt/storage/nfs-pool.xml
```

### 確認
```
# virsh pool-list
 Name        State    Autostart
---------------------------------
 default     active   yes
 nfs-pool    active   yes
```
しまうまプリントからEPSON Photo+への住所録の移行

# 背景
* これまでプリンタを自宅に持ってなかった[^1]が、今年嫁がどうしても欲しいとのことでEPSONのプリンタ [Colorio EP-881AB](https://www.epson.jp/products/colorio/ep881a/index.htm) を購入した
* これまで年賀状はSaaSの [しまうまプリント](https://www.n-pri.jp/) を利用していたが、せっかくプリンタを購入したので今年からは自分で印刷してみようと思った
* EPSONプリンタ用の無料アプリとして [EPSON Photo+](https://www.epson.jp/products/colorio/guide/software/) というものがあり、これを使えば年賀状が簡単に作成/印刷できる

ということで、しまうまプリントからEPSON Photo+へ住所録を移行する必要があり、format変換用のruby scriptも書いたので記録しておく。
(やる前はまー普通にできるやろと思ってたが、 **EPSON Photo+の住所録用CSVフォーマット仕様が開示されておらず** 、ヘルプデスクと何往復かのメールのやり取りが必要だった。。。)

[^1]: そもそも自宅では殆どプリンタなんて使わなかった(電子ファイルで事足りる)し、必要であればコンビニ等のネットプリントを利用していた

# Software version
## Windows
* Windows 8.1 Enterprise
* EPSON Photo+: Version 3.1.0.0

## Mac
* macOS Catalina(version 10.15.1)
* ruby 2.3.5p376 (2017-09-14 revision 59905) [x86_64-darwin18]

# やり方
## しまうまプリントからの住所録ダウンロード
* [ここ](https://order.n-pri.jp/mypage/postcard_address/list) の 「宛名データのダウンロード」ボタンをクリックすることで xlsx ファイルをダウンロードできる (address_data.xlsx)
* 手持ちのExcel等でダウンロードしたファイルを開き、CSVファイル形式で保存する (ここではaddress_data.csvという名前で保存されたと仮定する)

### (参考) しまうまプリントのCSVフォーマット
headerの各カラムを列挙したのが以下。

```
印刷(する・しない)
グループ※必須(全角30文字まで)
送付先※必須(自宅・会社)
姓※送付先自宅の場合必須 (全角10文字まで)
名※送付先自宅の場合必須 (全角10文字まで)
姓カナ(全角10文字まで)
名カナ(全角10文字まで)
会社名※送付先会社の場合必須(30文字まで)
会社名カナ(全角30文字まで)
部署名(全角20文字まで)
役職名(全角20文字まで)
敬称※必須※送付先自宅の場合(様・殿・先生・君・ちゃん・さん・御中)※送付先会社の場合(御中・様・殿・先生・御一同様)
郵便番号※必須(7桁)
都道府県※必須
住所1※必須(全角20文字まで)
住所2(全角20文字まで)
住所3(全角20文字まで)
連名1姓※送付先自宅の場合のみご利用可能(10文字まで)
連名1名※送付先自宅の場合のみご利用可能(10文字まで)
連名1敬称※送付先自宅の場合のみご利用可能(様・殿・先生・君・ちゃん・さん・御中)
連名2姓※送付先自宅の場合のみご利用可能(10文字まで)
連名2名※送付先自宅の場合のみご利用可能(10文字まで)
連名2敬称※送付先自宅の場合のみご利用可能(様・殿・先生・君・ちゃん・さん・御中)
連名3姓※送付先自宅の場合のみご利用可能(10文字まで)
連名3名※送付先自宅の場合のみご利用可能(10文字まで)
連名3敬称※送付先自宅の場合のみご利用可能(様・殿・先生・君・ちゃん・さん・御中)
その他連名※送付先自宅の場合(ご家族御一同様)※送付先会社の場合(スタッフ御一同様、従業員御一同様、職員御一同様、の皆様へ)
```

マルチバイト文字(日本語)が入っているかつ一行が長いのでプログラムとしては扱いづらい。
以下script内では列数をハードコードしているため、もし上記フォーマットが変更されていたら、合わせて以下scriptのハードコード部分の列数を変更する必要がある

## 住所録のformat変換

1. [script](https://github.com/shoutm/convert-shimauma-to-epson/blob/master/convert_shimauma_to_epson.rb) をローカルにcopy
2. 以下を実行

```shell
$ chmod +x convert_shimauma_to_epson.rb
$ ./convert_shimauma_to_epson.rb address_data.csv
```

これで `output.csv` というファイルが同じディレクトリに生成されます。

## EPSON Photo+にインポート

[ここ](http://support.epson.net/appinfo/photoplus/3.0/ja/GUID-12D9F750-7CBB-4DC9-AB0A-CFB481AB024C.htm) にインポート手順が記載されています。

# 既知の問題
* 連名1については敬称1で指定した値がちゃんと反映されるが、連名2以降の敬称が反映されない。
  * 私の場合連名2以降が殆どなかったためimportしてから手入力してしまった。
  * もしここも変換したい方は是非EPSONのヘルプデスクに問い合わせて頂きたい。わかったらこちらにもコメントつけてもらえれば本記事も更新します。

# (2019-12-22 更新)
うおー、outputの `住所１` は30文字制限なのかよ！
CSV importするときはエラー等出ず無条件で後ろが切られる模様。30文字超える場合はちゃんと `住所２` (マンション名等入力する欄)に入れてあげるようにせねば・・・。めんどくさい。
すでに印刷してしまったんだが。。。。

# (2019-12-22 更新2)
* とりあえず住所1 or 2が30文字超えてたら例外上げて落とすようにした。元データを修正して収まるようにしてね。
* コードをgithubにあげた。 https://github.com/shoutm/convert-shimauma-to-epson
Firebase StorageでMetadataを使う

# はじめに

こんにちは。
沖縄でエンジニアをしている [@yuji_azama](https://twitter.com/yuji_azama) です。

Firebase Storage、いろんなデータを手軽に保存できて便利ですよね。

Firebase Storage にデータをアップロードするとき、Metadata を指定できることをご存知ですか？
この記事では、ちゃんと使うと便利な Firebase Storage の Metadata について説明します。

※サンプルコードは Swift で記述します。

# Firebase Storage Metadata とは

Firebase Storage で扱うデータには、Metadata と呼ばれるそのデータに関する付加的な情報（ファイルサイズや contentType など）を含めることができます。

メタデータを設定することで、検索性が良くなったり、Firebase console 上での可視性(イメージプレビュー)が良くなったりします。

実際に使ってみるのがわかりやすいので、さっそく解説していきます。

# Metadata を使わないとどうなるか

まずは Metadata を使用せずに JPEG 画像を保存してみます。

```swift
let storage = Storage.storage()
let storageRef = storage.reference()
let ref = storageRef.child("image.jpg")
let uploadImage = imageView.image!.jpegData(compressionQuality: 1.0)! as NSData

ref.putData(uploadImage as Data, metadata: nil) { _, error in
    if (error != nil) {
        print("upload error!")
    } else {
        print("upload successful!")
    }
}
```

上記を実行すると、Firebase console 上では以下のように確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79499/6c76e999-6175-29bd-3955-55549fa31769.png)

ファイル名を選択することで、画面右側にファイルの詳細が表示できます。
先ほどアップロードした image.jpg のタイプが `application/octet-stream` となっており、JPEGのファイルとして認識されていないことがわかります。

ファイルを保存する目的だけであればこれでも問題はありませんが、ファイルの数が増えてくると console 上で一目で何のファイルなのか確認できないのは何かと不便です。

# Metadata を使ってみる

それでは、Metadata を用いてファイルのタイプを指定してみます。
Metadata を使うには、StorageMetadata クラスを使用します。
StorageMetadata をインスタンス化したら、`contentType` に`image/jpeg` を設定し、putData メソッドの引数に指定します。

```swift
let storage = Storage.storage()
let storageRef = storage.reference()
let ref = storageRef.child("image.jpg")
let uploadImage = imageView.image!.jpegData(compressionQuality: 1.0)! as NSData

let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"

ref.putData(uploadImage as Data, metadata: metadata) { _, error in
    if (error != nil) {
        print("upload error!")
    } else {
        print("upload successful!")
    }
}
```

上記を実行し、Firebase console 上で確認してみましょう。
以下の様に、ファイルの詳細を表示するとタイプに `image/jpeg` が設定されていることがわかります。
それにともなって、画像ファイルのプレビューも表示されているため、ファイルの可視性が向上したと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79499/568c05bd-4b0b-2e6c-f77c-b0ea72af7901.png)

# おわりに

この様に、metadata を適切に設定することで Firebase Storage が少し使いやすくなります。
他にも様々な metadata があったり、カスタムメタデータを設定したりできます。
メタデータ利用についてはまだあまり情報がないので、効果的な使い方がどんどん出てくると良いですね。

# 参考

- [iOS でファイル メタデータを使用する](https://firebase.google.com/docs/storage/ios/file-metadata?hl=ja)
[ffmpeg]Pythonのsubprocessを使ってffmpegしたらThe system cannot find the path specified.

## 環境
windows 10
python 3.7
ffmpeg 不明

## やろうとしたこと

```python
command = f'ffmpeg -i "{file_path}" -vf crop={Xl}:{Yl}:{Xs}:{Ys} "{out_path}"'
subprocess.call([command], shell=True)
```

動画ファイルのクロップをするコマンドを実行しようとしています。
しかし、エラーメッセージが...

```
The system cannot find the path specified.
```

しかし、ファイルもちゃんと存在しているし、`print(command)`してそれをコマンドプロンプトで実行すると成功する。

## 結論

```python
command = f'ffmpeg -i "{file_path}" -vf crop={Xl}:{Yl}:{Xs}:{Ys} "{out_path}"'
subprocess.call(command, shell=True)
```
で直りました

これに2時間ほどハマっていたので...
メインアカウントがbot誤判定され凍結されたときにDiscordBOTが削除されないようにする方法

## ユーザーが誤ってbot判定されて凍結されると...
- メインアカウント名が変わってしまう... (ユーザー名#1111 → Deleted User xxxxx#yyyy → Deleted User#0000)
- メインアカウントの作ったサーバーが消される...
 - 回避方法: 100人を超えているサーバーなら所有権の移動して回避できる。
- メインアカウントが入っていたサーバーから退出させられる...
- **メインアカウントのアプリケーション(DiscordBOT)がDiscordにログインできなくなる... → アプリケーション(DiscordBOT)削除...**
 - **回避方法: 事前に準備をしていれば、回避できる方法があります。(しかし、注意点があります。)**

# DiscordBOTを削除されないようにする方法
1. Discordチーム作成
2. My アプリケーションをチームに転送


## Discordチーム作成方法
1. https://discordapp.com/developers/teams にアクセスします。

![Discord Developer Portal — My Teams - discordapp.com](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/52ab2360-5f0f-cf68-5d00-9c1aa7dd50fe.png)
2. `New Team`をクリックします。

![Discord Developer Portal — My Teams - discordapp.com](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/c4d4a57e-a229-0d4d-3f46-3857edcb2006.png)
3. `チーム名`を入力して、`Confirm`をクリックします。

![FireShot Capture 160 - Discord Developer Portal — My Teams - discordapp.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/c789e16d-6c40-e9d8-58f5-8fcb259c9f64.png)
4. `INVITE TEAM MEMBERS`に招待するユーザー名とタグ(サブアカウント)を入力して、`invite`をクリックします。
5. 招待したユーザー(サブアカウント)にメールが届きます。

![Discordチーム招待](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/acf5b100-0fd5-9a15-11c5-42e9f64a0f8e.png)
6. `招待を受け入れる`をクリックします。

![Discord Developer Portal — My Teams - discordapp.com](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/f9f60ca3-7e8a-5eac-5802-b7662306bb16.png)
7. チームに追加されます。
8. 完了

## My アプリケーションをチームに転送方法
1. My アプリケーションでチームに転送したいアプリケーションをクリック。
1. `Transfer App to Team`をクリック。**(チームに転送したら、元に戻すことはできません。自己責任でお願いします。~~Discord運営に、元に戻してくださいとリクエストを送信すればなんとかなるかもしれない。~~ ~~もし、共同開発する予定がある方は、チームグループに分かれて管理することをおすすめします。~~ チーム作成制限がわからない... )**

![Discord Developer Portal — My Applications - discordapp.com](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/7ea64004-8996-e7f1-38ac-d219f4c936d1.png)
3. 完了

## こんな感じ
![Discord Developer Portal — My Applications - discordapp.com](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480250/d86f90e0-b8d0-7aa1-155f-595122066599.png)

## 終わりに
メインアカウントがbot誤判定されて凍結されても**サブアカウントが凍結されていなかったら**、DiscordBOTが削除されません。
2019年フレームワークのトレンドが見れるサイトの紹介

# hotframeworks.com
URLはこちらになります。
http://hotframeworks.com/
![a.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282788/1b52681e-2325-a75b-d2cb-214d3c23e526.jpeg)