OmniAICreator/Qiita-1.07M huggingface dataset:
VCIコンテストで使用したVCIの操作方法の紹介


# はじめに
12/5 にVCIを使ってものを運ぶ時間を競うVCIコンテストというものが開催されました。
　詳細はこちら：https://twitter.com/karasumayun/status/1322821429700653057
今回は上記イベント用に作成したVCI(ホイールローダ)で使用した内容を紹介します。


# 全体的な構成
基本的には手元のキューブの座標情報を用いてホイールローダを操るという形式をとっています。
今回は勉強がてら以下3つの機能をそれぞれ異なる方法で操作できるようにしました。
　・回転同期
　・加減速
　・アームの上げ下げ

以下の内容もコード内でおこなっていますがそちらは説明を割愛します
　・操作用のキューブの手への自動装着
　・「回転操作&加減速」と「アーム上げ下げ」のモードの切り替え
　・GetTransFormの処理(初期化時にITEMという名前のtableに全部入れてます)

# 回転同期
![rotate.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/ff4e4a95-57a9-9058-3996-2e8fcc8a5f9c.gif)


こちらは至って簡単で回転用コントローラーのQuaternionをホイールローダ(MACHINE)のQuaternionに入れてあげるだけです。

``` lua
function update()
  ITEM.MACHINE.SetRotation(ITEM.ROTATE.GetRotation())
end
```
ただし、Y軸以外の回転はさせたくないためUnityの設定で回転用コントローラーの回転軸を以下のように固定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/b7ded50f-2d44-a630-12bf-d6a36af9551a.png)


## 加減速
![speed.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/a76a3035-63cc-40f2-1399-bfd7a8fbbb03.gif)

こちらはGrabした位置をダミーオブジェクトに保存しておき、速度用コントローラーとダミーオブジェクトのy座標の距離に応じて加減速しています。(ダミーオブジェクトはgif画像の半透明の球の部分です)
Grabしていないときは動かないようになっています。

``` lua
local isGrabSpeed = false

function update()
  if isGrabSpeed then
    move()
  end
end

function move()
  --コントローラーとダミーオブジェクトの位置から移動量の計算(上限下限あり)
  local distY = (ITEM.CONTROLLER_SPEED.GetPosition().y - ITEM.DUMMY_SPEED.GetPosition().y)
  local distPerSec = math.max(math.min(distY*15,5),-5)*0.02
  local addVector = ITEM.MACHINE.GetForward().normalized*distPerSec

  --MACHINEの位置更新
  local machinePos = ITEM.MACHINE.GetPosition()
  ITEM.MACHINE.SetPosition(machinePos+addVector)
end

function onGrab(target)
  if target == ITEM.CONTROLLER_SPEED.GetName() then
    --Grabした位置をダミーオブジェクトに保存
    ITEM.DUMMY_SPEED.SetPosition(ITEM.CONTROLLER_SPEED.GetPosition())
    isGrabSpeed = true
  end
end


function onUngrab(target)
  if target == ITEM.CONTROLLER_SPEED.GetName() then
    --放した時に位置を同期させる必要はないがなんとなく実施
    ITEM.DUMMY_SPEED.SetPosition(ITEM.CONTROLLER_SPEED.GetPosition())
    isGrabSpeed = false
  end
end
```


## アーム上げ下げ
![arm.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64877/7ed10028-3d66-bd1b-8870-59cda2abe64a.gif)

左右のコントローラーのY座標の位置関係によってアームの角度を変えるようにしています。


``` lua
function updateAll()
  local x = (ITEM.CONTROLLER_ARM_LEFT.GetPosition().y - ITEM.CONTROLLER_ARM_RIGHT.GetPosition().y)*100
  x = math.max(math.min(x,10),-60)
  ITEM.ARM.SetLocalRotation(Quaternion.Euler(x,0,0))
end
```



# 終わりに 
今回はVCIコンテスト用のマシーンの操作方法について考えた方法をいくつか紹介しました。
別でuseしたい処理があったため今回はCubeを用いましたが、手の座標を取得して同様のこともできると思います。
Flutterでタグ検索やフィルターを実装する(FilterChip)

#はじめに
こちらの記事は[ユアマイスターアドベントカレンダー2020](https://adventar.org/calendars/5455 "ユアマイスター Advent Calendar 2020
")、13日目の記事です。

#動作イメージ
今回実装したのは、下記のように、都道府県を複数選択できるものです。
最初は、どのwidgetを使えばいいのかも分かりませんでした。
![スクリーンショット 2020-12-12 17.51.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817871/17c66e94-50f7-7a9b-e3d9-d69335189eea.png)

#実装
調べたところ、FilterChipを使えばよさそうでした。
https://api.flutter.dev/flutter/material/FilterChip-class.html

上記の公式ドキュメントにもある通り、Wrapを使うことで、自動で折り返しをしてくれるようです。
https://api.flutter.dev/flutter/widgets/Wrap-class.html

また、各地方ごとにListViewのItemとなるようにしています。

Region(地方モデル)は、nameとPrefecture(都道府県モデル)の配列を持っています。

```
class TestItem extends StatefulWidget {
  /// constructors
  const TestItem({
    @required this.region,
    Key key,
  })  : assert(region != null, 'a must not be null'),
        super(key: key);

  final Region region;

  @override
  State<StatefulWidget> createState() => _TestItemState();
}
```

下記でFilterChipを作成します。
選択時の背景やテキスト、外枠の色や、チェックマーク非表示の設定もしています。

```
class _TestItemState extends State<TestItem> {
  final List<int> _filters = <int>[];

  Iterable<Widget> get prefectureWidgets sync* {
    for (final prefecture in widget.region.prefectures) {
      yield Padding(
        padding: const EdgeInsets.all(4),
        child: FilterChip(
          label: Text(prefecture.name,
              style: TextStyle(
                  color: _filters.contains(prefecture.prefectureCode)
                      ? Colors.pink
                      : Colors.white)),
          shape: RoundedRectangleBorder(
              side: BorderSide(
                  color: _filters.contains(prefecture.prefectureCode)
                      ? Colors.pink
                      : Colors.grey),
              borderRadius: BorderRadius.circular(4)),
          backgroundColor: Colors.white,
          selectedColor: Colors.pink[50],
          showCheckmark: false,
          selected: _filters.contains(prefecture.prefectureCode),
          onSelected: (value) {
            setState(() {
              if (value) {
                _filters.add(prefecture.prefectureCode);
              } else {
                _filters.removeWhere((prefectureCode) =>
                    prefectureCode == prefecture.prefectureCode);
              }
            });
          },
        ),
      );
    }
  }
}
```

あとは表示をするだけです。

```
  @override
  Widget build(BuildContext context) => Ink(
        color: Colors.white,
        child: SafeArea(
          top: false,
          bottom: false,
          minimum: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text(widget.region.name),
              Wrap(
                children: prefectureWidgets.toList(),
              ),
            ],
          ),
        ),
      );
```
ARM64のAmazon Linux2で docker-compose を動かす

## 本記事執筆時の環境

>  4.14.203-156.332.amzn2.aarch64 #1 SMP Fri Oct 30 19:19:46 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux

## できなかった…

現時点で以下のドキュメントを確認すると、

Install Docker Compose | Docker Documentation 
https://docs.docker.com/compose/install/

以下から環境のバイナリイメージをダウンロードする配置か、もしくは以下GitHubのページに記載されているように pip を用いてインストールするかのようだった。

https://github.com/docker/compose/releases


ところが、現時点でARM64版のバイナリは無く、残念ながら pip でのインストールも上手くいかなかった。

## できた★

色々と検索したところ、以下のIssueコメントの内容/コンテナイメージで動作させることができた。

[Release docker/compose image for armv7 / arm64v8](https://github.com/docker/compose/issues/6831#issuecomment-683797087)
https://hub.docker.com/r/linuxserver/docker-compose

やはりパッケージ類を直接インストールするのは上手くいかないぽいので、要は docker-compose コマンド内で docker-compose 自体を Dockerコンテナとして実行させる感じのよう。

```
sudo curl -L --fail https://raw.githubusercontent.com/linuxserver/docker-docker-compose/master/run.sh -o /usr/local/bin/docker-compose
sudo chmod + x /usr/local/bin/docker-compose
```
mac に zunda をインストールする

# はじめに

日本語拡張モダリティ解析器ZundaをMacにインストールしたときのメモです。

https://jmizuno.github.io/zunda/

Zundaのバージョンは1.6、MacOSはBig Surです。

# 手順

### ファイルをダウンロード

とりあえずZundaをダウンロードして適当なフォルダに置きます。
私は`~/zunda-release-1.6`に置きました。

### ./configureする

手順としてはzundaのフォルダに移動して`./configure`して`make`なんですが、`./configure`でエラーが出ました。

```{bash}
$ ./configure
...
checking whether the C++ compiler works... no
configure: error: in `/Users/imadamizuho/zunda/zunda-release-1.6':
configure: error: C++ compiler cannot create executables
See `config.log' for more details
```

C++コンパイラが無いと言っています。メインで使っているMacではなかったため、開発ツールをインストールしていなかったようです。command line tools for xcodeをインストールしましょう。

```{bash}
$ xcode-select --install
```

あらためて`.configure`する。特にエラーは出ていないので問題ないと思われる。

```{bash}
$ ./configure
```

### makeする

次に`make`するが、エラーが出た。

```{bash}
$ make
...
g++ -DHAVE_CONFIG_H -I. -I..    -DMODELDIR_IPA=\"/usr/local/share/zunda/model_ipa\" -DMODELDIR_JUMAN=\"/usr/local/share/zunda/model_juman\" -DDICDIR=\"/usr/local/share/zunda/dic\"  -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.cpp
main.cpp:3:10: fatal error: 'boost/program_options.hpp' file not found
#include <boost/program_options.hpp>
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
make[2]: *** [main.o] Error 1
make[1]: *** [all-recursive] Error 1
make: *** [all] Error 2
```

boostが無いと言っているようなので、`brew`で`boost`をインストールする。`brew`も無い場合は、先に`brew`をインストールすること。

```{bash}
$ brew install boost
$ make
```

以下の警告が何回か出たけど通ったっぽい。

```{bash}
$ make
...
xml2cab.cpp:85:2: warning: bool literal returned from 'main' [-Wmain]
        return true;
...
```

### make installする

make installする。

```{bash}
$ make install
```

インストールできているか確認するために、バージョンを表示させる。

```{bash}
$ zunda --version
1.6
```

動作確認。

```{bash}
$ echo "次郎は大阪に行った" | zunda
#EVENT0	4	wr:筆者	非未来	0	叙述	成立	0	0
* 0 2D 0/1 -1.880678
次郎	名詞,固有名詞,人名,名,*,*,ジロウ,ジロウ,次郎,ジロー,次郎,ジロー,固,*,*,*,*
は	助詞,係助詞,*,*,*,*,ハ,は,は,ワ,は,ワ,和,*,*,*,*
* 1 2D 0/1 -1.880678
大阪	名詞,固有名詞,地名,一般,*,*,オオサカ,オオサカ,大阪,オーサカ,大阪,オーサカ,固,*,*,*,*
に	助詞,格助詞,*,*,*,*,ニ,に,に,ニ,に,ニ,和,*,*,*,*
* 2 -1D 0/1 0.000000
行っ	動詞,非自立可能,*,*,五段-カ行,連用形-促音便,イク,行く,行っ,イッ,行く,イク,和,*,*,*,*
た	助動詞,*,*,*,助動詞-タ,終止形-一般,タ,た,た,タ,た,タ,和,*,*,*,*
EOS
```

以上、command line toolsやboostをインストールしてあれば、特に問題なくインストールできるようだ。


### 追記
Cabochaも事前にインストールしておく必要があったはず。

```{bash}
$ brew install cabocha
```
ECCUBE４Symfony PHP ドキュメントリンク

**Symfony Doc**
https://symfony.com/doc/current/components/form.html#component-form-intro-create-simple-form

**EC-CUBE4 APIドキュメント**
https://www.xross-cube.com/EC-CUBE_doc/classes/Eccube-Util-FormUtil.html

**Symfony2で利用されているDoctrineに入門する(後編)**
https://engineering.otobank.co.jp/entry/2017/05/09/190056

**PHPマニュアル**
https://www.php.net/manual/ja/

**PHPフレームワークSymfonyの学習帳**
http://symnote.kwalk.jp/start
Cloud9でRails学習中につまづいた〜Oops VFS connection does not exist〜

Cloud9でRailsチュートリアルしていた時に、
つまづいた話、

Preview Running Application
ポチッ〜〜〜〜

Safariで開いたら、こんな感じで

![Oops](https://user-images.githubusercontent.com/59049463/102003061-15579b00-3d46-11eb-9173-52d80be1763f.png
 "Oops")

###Oops VFS connection does not exist

と煽られるわけですよ。

なんとなく、Chromeで開いたら成功しました。


以上、中身のない記事でした。
エンジニアのマネージメントについて

#はじめに
[LIFULLその2 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/lifull2)の13日目の記事になります。
~~advent calendar用にdeepcomposerで曲作っていたのだけど、納得のいくクオリティーに達しなかったので断念、機械学習の勉強としては面白いかなーと思うたので、そのうちなんか書くかも、書かないかも？~~
最近、[とあるパネルディスカッション](https://lifull.connpass.com/event/196286/ "Ltech#12 エンジニア150名以上を抱えるCTOとマネージャがマネジメントを語ります！")にてエンジニアのマネージメントについて語ることがあったので、少しそれについて考えてみることにした。




#マネージメントとは？

>組織に成果を上げさせるものがマネージメントであり、マネージャーの力である。
 by P.F.ドラッカー

続いてドラッカーの考えているマネージメントの役割を挙げてみます。

>1. 自らの組織に特有の使命、目的を果たす。
>2. 仕事を通じて働く人を生かす。
>3. 社会の問題について貢献する。

当然といえば当然ですが、組織から与えられたリソースを有効活用し、最大限の成果を出すことが重要です。
これはエンジニアとか関係なく、全てのマネージメントに当てはまるのではないでしょうか？
パネルディスカッションでも話しましたが、エンジニアかそうでないかによって、考え方が変わることはありません。



基本的に職種によってマネージメントの手法は変わらないので、エンジニアに対してのマネージメントとして気をつけているところはあるか、について考えてみました。
#エンジニアに対するマネージメントで気をつけている事

あくまでの私の経験上の意見ですので、異なる見解もあると思いますがご了承ください。

###組織の使命、目的を果たす
成果を出すという部分においては、プロダクトの作成や、売上貢献、業務効率化によるコスト削減などわかりやすい成果があるので、その部分を理解している人は多いです。
ただし、それはなんらかの課題や、使命を解決するための手段であって、達成すべき目的が疎かになっている事がそれなりにあると思っています。
なので、もちろんエンジニアだけの問題ではないと思いますが、__目的を明確化して丁寧に説明することを心がけています。__


###仕事を通じて働く人を生かす


技術力の高い人、知識の多い人において癖のある人が多いと感じています。
難しい言葉を使いがちで、説明する事が多いように感じています。
そのため
理解し適切に判断するためにも、__技術知識のキャッチアップには時間を裂くようにしています。__
また、__自分の理解、想像を超えるようなもののについては、大きな失敗をしない範囲で、積極的に採用するようにしています。__
また、口下手な人も比較的多いと思っているので、__1on1等、普段からコミュニケーションをとり、キャリアプランなどを理解し、成長の手助けになるよう努めています。__


###社会の問題について貢献する

弊社の行っている事業が、どのような社会課題に直面しているか、どのように課題に取り組むかをカンガルことは重要です。
どうしても短いスパンの事業課題に取り組んでいると、長期的な問題や社会課題がおざなりになってしまいがちです、なので、__定期的に視座を上げ、社会課題に目を向けるように心がけるように努力しています。__



#おわりに

エンジニアのマネージメントについて考えて、書いてきましたが、改めて思ったことは、職種とかあまり関係ないかなと思いました。ドラッカーから入ったのがよくなかったのかも。。。
また機会があれば、実際の業務からみるマネージメントというのを書いてみたくbなりました。
[Swift] 選択肢１つのアラートの使い方

#アラートとは
画像のような表示が出てくるやつです。
良く出てくるので今回まとめてみます。
![スクリーンショット 2020-12-10 21.45.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/8c9a07b8-11c6-894a-a0ee-eb2ec1228033.png)

#書き方
####画像のようなtitle,message,ボタンで構成されているアラートの書き方
![スクリーンショット 2020-12-13 12.15.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/755375/ca16dfac-c3e7-721e-39f2-a065f71bc789.png)
アラートのタイトルとその内容を定数dialogに代入しています。
次にdialogのaddActionでアクションを追加します。追加内容は画像のOKの部分です。
最後にself.presentで今作成したアラートを表示させます。

```swift
   let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alert, animated: true, completion: nil)
```
#最後に
今回は選択肢が１つのアラートについて書いてみました。
また他の種類の分も書いてみようと思います。
PHP でinputタグで代入された値をdate型か判定する関数（配列と変数それぞれ判定可）

PHPを扱う人なら誰もが扱ったでことがあるであると思うformタグのnameの値を$_POST型で受け取り値を反映するサイト。そのようなサイト制作に取り組んでいて、受け取る値（変数・配列）がdate型に当てはまるか判定したいときに使える関数を製作いたしました。

まだ不完全な部分もありますがデータベースと連携することでこの関数はdate型のフォーマットに当てはまるか判定できます。
#配列をそれぞれdate型か判定する関数
```PHP:test.php
$date_array=["2020-02-14","2019/01/15","1990516",//正しい日付として出力
    "2010/8/17","2022020180","2005/09-32","xxxx-yy-zz",//エラー
    "0000-00-00","9999-99-99" //極端な数字でも出力→しかもdateの限界か出力される値がおかしい。
    ];
check_array($date_array);

function check_array($date_array) {
  $pattern="#^\d{4}([/-]?)\d{2}\\1\d{2}$#";
  foreach ($date_array as $judged_date){
    if(preg_match($pattern,$judged_date,$match)){
      print date("Y-m-d",strtotime($judged_date));
      print 'は正しい日付である<br>';
    }else{
      print $judged_date."は日付ではありません<br>";
    }
  }
```
###結果
```html
2020-02-14は正しい日付である
2019-01-15は正しい日付である
1990516は日付ではありません　
2010/8/17は日付ではありません <!--　エラー　-->
2022020180は日付ではありません
2005/09-32は日付ではありません
xxxx-yy-zzは日付ではありません
-0001-11-30は正しい日付である <!--　極端な数字でも出力　-->
1970-01-01は正しい日付である
```
###解説
流れとしては対象の配列を変数`$judged_date`として出力し、その変数を`preg_match`で`$pattern`に当てはまるものなら`date`と`strottime`で日付のフォーマットとして返すという処理を行っています。

##変数をdate型か判定する関数
```PHP:test.php

    $date = "2022-06-24";
check_param($date);
function check_param($date) {
  $pattern="#^\d{4}([/-]?)\d{2}\\1\d{2}$#";
    if(preg_match($pattern,$date,$match)){
      print date("Y-m-d",strtotime($date));
      print 'は正しい日付である';
    }else{
      print "は日付ではありません";
    }
}
```
###結果
```html
2022-06-24は正しい日付である
```
###解説
配列を判定した関数の引数を変数に変換しただけのものでございます。そのため、上記の配列判定の関数が理解できれば理解できると思います！

##まとめ
配列判定の関数で示したようにまだ不完全なものではあります。
>データベースと連携することでこの関数はdate型か判定できます。

しかし、このように述べたように対象の文字列をdate型のフォーマットに当てはまるかどうか判定する時には利用しがいがあるのではないかなと思います。
（どちらにしろDBがdate型じゃないとDBに保存できず、`invalid datetime format`のエラーを返すからあまり意味がないのでは？？という意見は心にしまっておいてくださいmm）

この記事がみなさんの参考になれば幸いです。改善案等もあればよろしくお願いいたします🙇‍♂️
【Eclipse】ターミナルを表示させる方法

いつもは別窓で開いていたけどJetBrains製品と同じように表示できないかなと思ったのでメモ

![808F1FC5-51A6-4477-9538-D124BC1E0ABA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89244/ab3a5e7d-70f4-0235-e423-26b1556cba75.png)

ビューの表示→ターミナルを選択する。

![24441CDC-1879-4CA8-9495-3370217432A9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89244/c9067f03-d149-326a-65fc-0b6a9fe0c213.png)
Macであればローカルターミナルを選択して起動すればデフォルトシェルが起動する。
（Mojava以前のOSからアップグレードをしている場合はBash、Catarina以降からであればzshになっているかも）
dockerコンテナに環境変数を渡す

docker run実行時に-eオプションで環境変数が渡せる。
設定情報を渡すのに使用したりする。

```bash
$ docker run --help | grep -e "-e"
  -e, --env list                       Set environment variables
```

確認

```bash
$ docker run -it --rm -e HOGE=FUGA -e AAA=BBB centos:centos8 /bin/bash 
[root@45aa4a408e51 /]# echo $HOGE
FUGA
[root@45aa4a408e51 /]# echo $AAA
BBB
[root@45aa4a408e51 /]# 
```


また、--env-fileを使うことで環境変数が書かれたファイルから環境変数を渡すことができる。

```.env_test
HOGE=FUGA
A=B
TEST=TESTdesu
```

```bash
$ docker run --env-file ./.env_test --rm -it centos:centos8 /bin/bash
[root@d9801c8c2542 /]# echo $HOGE
FUGA
[root@d9801c8c2542 /]# echo $A
B
[root@d9801c8c2542 /]# echo $TEST
TESTdesu
```
【JavaScript】location.replaceメソッドを使ってページ遷移する方法

#プログラミング勉強日記
2020年12月13日
location.replaceメソッドで指定したURLにページ遷移させる方法をまとめる。

#location.replaceメソッドとは
　指定したURLへページを遷移させることができるメソッド。location.replaceメソッドでページ遷移した場合は履歴が残らないので、ブラウザの戻るから前のページに戻ることはできない。
　location.replaceメソッドは移動先URLを指定して使う。

```js:使い方
location.replace(移動先のURL);

// 具体例
location.replace("./page.html");
```

#サンプルコード

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>sample</title>
  <script>
	function sample(){
		location.replace("https://qiita.com/");
	}
  </script>
</head>

<body>
	<a href="#"  onclick="sample()">履歴を残さずにトップページへ移動</a>
</body>
</html>
```

#参考文献
[location.replace() …… 指定したページへ移動する](http://www.htmq.com/js/location_replace.shtml)
[JavaScriptでlocation.replaceメソッドでURLを置換する方法を現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/33062)
SambaとZFSでMacのTime Machineバックアップを実現する

# はじめに
MacユーザーであればTime Machineでのバックアップが必須であることは言うまでもない。FreeBSDをZFSでファイルサーバーにしている場合、Time Machineバックアップをファイル共有をこのサーバーで利用できれば余計なコスト避けることができる。しかし実際にこれらを実現するには、Sambaをどう設定すればよいのか。

ちなみにNetatalkを使ってAFPサーバーを構築してもTime Machieサーバーは実現できるし実際それでずっと利用してきている。ただSambaと両方動かすのも微妙な手間なので、シンプルにするためにどちらかをやめるとなると、NetatalkはSMBをサポートしないのでAFPをサポートしているSambaにまとめることになる。

ここで目的とする設定は次の通りである。

- Time Machineバックアップが正しく動作する
- ファイル共有でMacのリソースフォークをZFSの拡張属性に保存する(“._*” が作成されない)

実はSambaでのTime Machineサーバーは、以前から試行錯誤をしていてどうしてもうまくいってなかった。先日改めてテストしたところ無事動作を確認できたので、その設定を紹介する。
# SambaでMacのファイル共有
SambaではVFSモジュールの追加で特定のファイルシステムやプロトコルに対応できるようになっている。AFP用のサービスのモジュールは vfs_fruit で、Macとファイル共有を行うためにはこのモジュールの導入が必要となる。

```
	vfs objects = fruit
```

# 動作した設定
最初に動作した設定例を示す。なおMacには関係のない一般的な設定は省略してある。
## global セクション
Mac用の特別な設定は記載しない
## 個別の共有フォルダ
共有名を share とする例

```
[share]
	path = /data/share
	vfs objects = fruit streams_xattr
	fruit:resource = stream
	fruit:metadata = stream
```

## Time Machine用のバックアップフォルダ
共有名を TimeMachine とする例

```
[TimeMachine]
	path = /data/TimeMachine
	vfs objects = fruit
	fruit:resource = xattr
	fruit:time machine = yes
```

この設定では、 /data/TimeMachine 内に Mac側がバックアップフォルダを作成する際、一緒に ._ で始まるファイルができてしまうが、Time Machine 専用フォルダでファイル共有には利用しないので許容する。
## ZFSの構成
上記の設定で、/data/share と /backup/TimeMachine は ZFSでは別々のファイルシステムとして設定している。つまり zfs list では次のように見える

```
$ zfs list -o name -r zroot/data
NAME
zroot/data
zroot/data/share
zroot/data/TimeMachine
```

このように独立したファイルシステムにすると、ZFSのプロパティでTimeMachineのディスク容量の制限が簡単にできる。もちろん制限はSamba側でも設定できるが、個人的にはZFSプロパティのほうが管理しやすい。

もし、/data/shre と /data/TimeMachine が ZFSとして同じファイルシステムでのディレクトリの場合は、本設定が動作するのかどうかについては確認していない。
# 動作しなかった設定
## ダメだった例1
```
[global]
	vfs objects = fruit streams_xattr
	fruit:resource = stream
	fruit:metadata = stream

[share]
	path = /data/share
	# Mac用の特別な設定は設定しない

[TimeMachine]
	path = /data/TimeMachine
	fruit:time machine = yes
```

共有は動作するが、TimeMachineのバックアップが動作しない
## ダメだった例2

```
[global]
	vfs objects = fruit 
	fruit:resource = xattr

[share]
	path = /data/share
	# Mac用の特別な設定は設定しない

[TimeMachine]
	path = /data/TimeMachine
	fruit:time machine = yes
```

TimeMacineバックアップは動作する。しかし共有フォルダをファインダーでアクセスすると挙動不審で、例えばjpegファイルをダブルクリックすると、ファインダーからはオブジェクトが消える。しかし実際にはファイルは残っている

## ダメだった例3

```
[global]
	vfs objects = fruit streams_xattr
	fruit:resource = stream

[share]
	path = /data/share
	# Mac用の特別な設定は設定しない

[TimeMachine]
	path = /data/TimeMachine
	fruit:time machine = yes
```

共有は ._* ファイルができる。バックアップは動作しない。

# まとめ

テストした範囲では、このように共有設定とTime Machine用設定では vfs_fruit のオプションを変えないと動作しなかった。過去にいろいろ試したのは、globalセクションにvfs_fruitのオプションを設定して、Time Machine用のみに「fruit:time machine = yes」を追加したのがいけなかったようである。

ここでの結論は、FreeBSDでZFSを使いSambaでMac用の設定を行う場合は、**Time Machine用と共有用では別々の設定を行う** 、ということになる。なおUSFやLinuxでのEXT4では試していない。

動作する設定は見つけられたものの、どうもSambaのドキュメントの説明と噛み合わず自分的には少々気持ち悪い。もしZFSとSambaの組み合わせで、この設定で動いているぜというのがあれば、ぜひコメントして欲しい。
CentOS8.3でVNCサーバをセットアップする手順

| [../](https://qiita.com/taconana/items/e45f19e83c825a9ba75e) |
|---|

CentOS8.3にupdateしたら、vncserverが従来の手順で使えなくなっていた。vncserverを実行すると、以下のようなメッセージが表示されるだけである。HOWTO.mdを読んでくれとある。

```bash
$ vncserver :1
vncserver has been replaced by a systemd unit.
Please read /usr/share/doc/tigervnc/HOWTO.md for more information.
```

どうも/usr/bin/vncserverが廃止になったようだ。新たなセットアップの手順は、以下のようになる。サービスの定義を手作業で編集したり、事前に残ったプロセスをkillするといった手間がなくなった。

まず、rootで1回だけ以下を実行する。

```bash
$ su -
$ echo "session=gnome" >> /etc/tigervnc/vncserver-config-defaults
$ restorecon /usr/sbin/vncsession /usr/libexec/vncsession-start
```

利用するユーザーとディスプレイ番号は、以下のファイルに記述する。以下の例では、`taconana`というユーザでディスプレイ番号は`:1`とする。

```bash
$ vi /etc/tigervnc/vncserver.users
:1=taconana
```

各ユーザーごとにconfigファイルを編集する。そしてパスワードを設定する。

```bash
$ su - taconana
$ restorecon -RFv /home/taconana/.vnc

$ vi /home/taconana/.vnc/config
# session=gnome					# vncserver-config-defaultsに設定されていれば不要
# securitytypes=vncauth,tlsvnc
# desktop=sandbox
geometry=1360x768				# これは任意に
# localhost
# alwaysshared

$ vncpasswd						# パスワード設定
Password: ***
Verify: ***
Would you like to enter a view-only password (y/n)? n
A view-only password is not used
```

rootに戻ってサービスを開始する。

```bash
# ディスプレイ番号に対応したサービスを起動する。
$ cp -p /usr/lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@:1.service
$ systemctl daemon-reload
$ systemctl start vncserver@:1
$ systemctl status vncserver@:1
● vncserver@:1.service - Remote desktop service (VNC)
   Loaded: loaded (/etc/systemd/system/vncserver@:1.service; enabled; vendor preset: disabled)
   Active: active (running) since Sun 2020-12-13 12:27:52 JST; 27min ago
  Process: 133876 ExecStart=/usr/libexec/vncsession-start :1 (code=exited, status=0/SUCCESS)
 Main PID: 133882 (vncsession)
    Tasks: 1 (limit: 24986)
   Memory: 2.0M
   CGroup: /system.slice/system-vncserver.slice/vncserver@:1.service
           ? 133882 /usr/sbin/vncsession taconana :1

$ systemctl enable vncserver@:1			# 自動実行可能にしておくこと。
```
複数ユーザーで複数のディスプレイ番号を使用する場合は、`vncserver@:1.service`をコピーして、例えば、`vncserver@:2.service`を作成して起動すること。

## VNCビューアからの接続が切れたとき
VNCビューアで作業していると、突然接続が切れて、再接続できなくなるときがある。その場合、TeraTermでIPを指定してSSHで接続し、以下の感じでvncserverを再起動する。そしてVNCビューアで接続を試みること。
```bsh
$ su
# systemctl daemon-reload
# systemctl status vncserver@:1
● vncserver@:1.service - Remote desktop service (VNC)
   Loaded: loaded (/etc/systemd/system/vncserver@:1.service; enabled; vendor pr>
   Active: inactive (dead) since Tue 2022-06-14 13:52:55 JST; 2min 48s ago
# systemctl restart vncserver@:1
# systemctl status vncserver@:1
● vncserver@:1.service - Remote desktop service (VNC)
   Loaded: loaded (/etc/systemd/system/vncserver@:1.service; enabled; vendor pr>
   Active: active (running) since Tue 2022-06-14 13:56:07 JST; 5s ago
```
以上

| [../](https://qiita.com/taconana/items/e45f19e83c825a9ba75e) |
|---|
サーバレスNEG でCloud Run にCloud CDN やCloud Armor を有効にしてみる

こんにちは、オールアバウト SRE所属の ＠h_amakasu です。
この記事は、[All About Group（株式会社オールアバウト） Advent Calendar 2020](https://qiita.com/advent-calendar/2020/allabout) 14日目の記事です。



# 本稿の概要

今年の夏にロードバランサーの新機能として「サーバレス ネットワーク エンドポイント グループ」（以下サーバレスNEG）が追加されました。
これにより、GCP ロードバランサーのバックエンドにサーバレスサービス（Cloud Run やCloud Function など）を設定できるようになり、従来ではできなかったCloud Run やCloud Function へのCloud CDN やCloud Armor が使えるようになりました。

本稿では、サーバレスNEG にCloud Run を設定したロードバランサー構成の構築手順をまとめてみました。

# 構築手順

## Cloud Run への検証用サービスのデプロイ

今回はバックエンドサービスにCloud Run を用いるので、検証用のサービスをデプロイします。

```
$ cat << EOF > Dockerfile
FROM centos:7
RUN set -x \
    && yum -y update \
    && yum -y install httpd
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
EOF
```

```
$ docker build -t example -f Dockerfile .
$ docker tag example asia.gcr.io/gcp_project/example-httpd:latest
$ docher push asia.gcr.io/gcp_project/example:latest
```

```
$ gcloud beta run deploy example \
  --image asia.gcr.io/gcp_project/example:latest \
  --platform=managed \
  --region=asia-northeast1 \
  --allow-unauthenticated \
  --port=80
```

## ロードバランサの作成

GCP 管理画面から「ネットワーク サービス」 > 「負荷分散」とジャンプし、「ロードバランサを作成」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/01ee5d3d-b12d-918d-6c8a-a7a6b7060281.png)

## バックエンドの作成

「バックエンドの構成」を選択し、「バックエンドサービスとバックエンドバケット」から「バックエンド サービス」を作成します。

バックエンドタイプのプルダウンメニューを以下のように「サーバーレス ネットワーク エンドポイント グループ」に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/64d8cf07-a7fa-76df-a772-2d25a5abca99.png)

新しいバックエンドで「サーバーレス ネットワーク エンドポイント グループの作成」を選択し、先ほどのCloud Run で構築したサービスと紐付けます。

![ad_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/7409624e-8f2e-2e7b-f51b-8d3ab21a50dd.png)

## Cloud CDN やCloud Armor の設定

バックエンド サービスの編集では、主題でもあるCloud CDN やCloud Armor を設定することができます。
画像例ではCloud Armor を有効にしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/7d8b85be-47b0-0524-6ec8-5e8432695d60.png)

## フロントエンドの作成

最後に、フロントエンドを構成します。
(バックエンドの設定時にCloud CDNを有効にした場合は、HTTPSで受け付けられるようにする必要があります)

![ad_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/da7e70ee-d2e1-d07e-0e9f-065092dce9ff.png)

これで「作成」を洗濯すれば構築完了です。
構築後のロードバランサーの詳細は以下のようになり、バックエンドがサーバレスNEGで、Cloud Armor が有効になっていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/c16422de-b089-2fa5-eb38-49a659960c82.png)

最後に黒塗り箇所のIPアドレスにアクセスして、期待した挙動をするか確認します。
許可されたアドレスからは以下のように正常に表示され、不許可のIPアドレスからは「403 Forbidden」となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198206/99a2e4f7-8665-776f-fb09-d724b4a593df.png)

# まとめ

サーバレスNEG を使って、Cloud Run でもCloud CDN やCloud Armor が使えるようになりました。
以前弊社のテックブログでも公開した[Cloud RunからCloud SQLやMemorystoreへの繋ぎ方](https://allabout-tech.hatenablog.com/entry/2020/06/30/133859)とくみあわせることで、使えるシーンはより広がったと思います。

ただ、この構成は1点課題があることもわかりました。
この構成、Cloud Run にロードバランサーを被せるような形になりますが、**Cloud Run のサービスそのものに自動で割り当てられたURL へは直接参照できてしまう**点です。この点、抜け穴になってしまうので、今後のアップデートに期待したいとことです。

# 参考資料

[サーバーレス ネットワーク エンドポイント グループの概要](https://cloud.google.com/load-balancing/docs/negs/serverless-neg-concepts)
Slack APIのOAuthでinvalid_codeでハマった話

シンプルにSlackのAPIを利用したくてOAuth認証のコードを作成しました。
完成したアプリは問題なく動いていたのですが、ある日新機能追加のためにローカルで色々試していたところ突然認証が通らなくなりました。
最終的には解決できましたが、突破口の発見は正直偶然に近かったので同じハマりで困っている人の助けになればと記事に残しておきます。

## 起きた問題
下記はredilect_urlのサーバー内の処理です。
Slackから渡されるcodeをresponseから取り出して、それをそのままSlackの認証用APIに返すシンプルな作りです。
認証後にクライアントにレスポンスを返す部分は少しNext.jsですが、この問題には特に関係しないのでありのまま記載します。

```typescript:AuthController.ts
import { Response } from 'express';
import querystring from 'querystring';
import { getOrCreateAxios } from '../../modules/createAxios';
import Server from 'next';

export const AuthController = (handle: ReturnType<ReturnType<typeof Server>['getRequestHandler']>) => async (
  req: any,
  res: Response
) => {
  const code = req.query.code as string;
  const error = req.query.error as string;
  if (!code) {
    res.redirect('/home');
    return;
  }
  if (error === 'access_denied') {j
    res.redirect('/home');
    return;
  }
  console.log('code', code); // デバッグ用
  const params = {
    code: code,
    client_id: 'validclientid', // 記事用の仮の値
    client_secret: 'validclientsecret',
  };
  console.log('params', querystring.stringify(params)); // デバッグ用
  const result = await axios.post(
    'https://slack.com/api/oauth.v2.access',
    querystring.stringify(params)
  );
  console.log('result', result.data); // invalid_codeが返されることがわかる
  req.token = result.data;
  req.botToken = appConst.SLACK_BOT_TOKEN;
  handle(req, res);
};
```

そしてSlack認証用のフロント側のリンクのURLがこちら
ほとんどSlack公式からのコピー&ペーストなので特に問題のないものです。

```
https://[正しいワークスペース名].slack.com/oauth/[クライアントID]?client_id=[正しいクライアントID]&scope=[正しいスコープ]&user_scope=[正しいスコープ]&state=&granular_bot_scope=1&install_redirect=&response_type=&response_mode=&nonce=&openid_connect=0&single_channel=0&redirect_uri=http://localhost:3000/callback
```

で、axiosでの認証リクエストのレスポンスがこちら

```json
{ ok: false, error: 'invalid_code' }
```

途中でcodeやparamsといった変数を出力していますが、どちらも期待通りの結果でした。
Slackから渡されたコードをそのまま出力できます。

## 解決編
原因は今でも腑に落ちていませんが、Slackに登録しているRedirect URLsでした。
登録値が**http://localhost:3000**になっていたのです。ボタンのURLで指定しているredirect_uriと一致していません。

http://localhost:3000 **/callback** に直すことで解決しました。

ドメインが同じであれば問題なくリダイレクトされる公式Docのどこかで読んだと思っていたのでパスを最後まで書いてはいませんでした。
どうやら他のプロダクトのAPIとの勘違いだったようで、下記にはAppセッティングでもURLパラメータでもサブディレクトリまで指定しろと書いてありました。
[公式Doc: More on Redirect URLs](https://api.slack.com/authentication/oauth-v2#redirect_urls)

それにしてもエラーコードがinvalid_codeだったので気づくのが遅くなりました。
'bad_redirect_uri'というエラーコードもあるはずなのですが、今回なぜこちらが出なかったのかまで調べられていません。
とはいえ、起きた事実として共有させていただきます。

困っている人（あるいはまた同じハマり型をした未来の自分）の役に立てば幸いです。
Year End Looker Meetup 2020で登壇しました

※この記事は[Looker Advent Calendar 2020](https://qiita.com/advent-calendar/2020/looker)の12/13の記事です。

## はじめに
弊社もLookerの導入から1年が経ち、「そろそろ登壇でも…？」と機会をいただきましたので
12/7に開催された[Year End Looker Meetup 2020](https://discover.looker.com/2020yearendmeetup_ja.html)で登壇してきました。
発表の内容は[資料](https://www.slideshare.net/easasaki/20201207lookeryemfsasaki)を見てもらえればと思いますが、これをまとめるにあたって考えたことと、
発表して＆交流会に参加して思ったことを書いてみようと思います。

## 現状の振り返り
すっかり発表資料に入れ込み忘れていたのですが定量的な部分で言うと、
一年で**約40のダッシュボード**を作成し**約150名のユーザー**がそれを閲覧しています。
Slackのチャンネルにも配信しているので、可視化された数字は
もう少し多くのメンバーが見ている数字をLookerで管理・運用しているということになります。

1年間という時間で、かなり少数のメンバーで構築を進めてきたという意味では
なかなか良い状態までたどり着けているんじゃないかなと思っています。

## Lookerをデータ基盤として捉え直す
今回のYear End Looker Meetup 2020では、登壇のテーマが「Looker運用の創意工夫」でした。
私は全社横断の分析組織に所属しており、
動きとしてはデータ整備人〜データアナリスト/BIエンジニアの領域を広く触っていることもあるため、
せっかくならLookerの位置づけを広く捉え直しつつこの1年間で試行錯誤してきたことをまとめてみようと思いました。

Lookerはデータガバナンスと集計定義のコード管理（Git管理）が強力なツールです。
データガバナンスと使いやすさを両輪で考えることは、もはやデータ基盤全体の構成を考えることと同義であり、Lookerの運用はBIツール運用として考えるよりデータ基盤の運用そのものと考えた方が整理しやすいと感じました。
広範囲におよぶ考慮すべき点を、以下に例を思いついた限り挙げてみます。


* 何を優先して可視化すべきかを判断するためのビジネスモデル理解
* どう集計結果を共有することが最も日々の意思決定につなげやすいか判断するための業務フロー理解
* 示唆を得るために必要十分で、かつ一人歩きしてもミスリードを引き起こさないデータ可視化
* 上記可視化を組み合わせ、さらに深い示唆を得るためのダッシュボード構築
* 上記可視化を動的に制御するためのフィルタ設計
* データ抽出とVisualization描画のリードタイム短縮に向けた取り組み
* Project/Model/Explore/Dashboard/Look/Folder × Userの権限という超多階層でのデータ閲覧権限管理（DWH側でも権限設定できることを考えたら選択肢は無限大）
* APIを活用したSlack等他ツールへの配信
* APIを活用したHubspot等他ツールからのデータ抽出
* 他部署含む複数名でサイロ化を起こさず集計定義を管理するためのルール
* 今後ユーザーを増やしていくためにわかりやすいフィールド命名規則
* 今後ユーザーを増やしていくためのわかりやすいメタデータ管理

アドベントカレンダーに間に合わせるために笑、限られた時間でざっと思いついただけでもこんなところでしょうか。

## やったこととやらなかったこと（とできなかったこと）
そのため、「創意工夫」というテーマでお話しするとしてもまとまりがなくなりそうだと感じ、今回は
**"創意工夫 to ビジネスユーザー/開発者 × やったこと/やらなかったこと/できなかったこと"**
というフレームで整理してみました。
ガバナンスと使いやすさの両立を目指すにあたり敢えて使わないと決めた機能もあったため、
この整理は比較的理にかなっていたのかなと思っています。

## いただけた反応
やったこととやらなかったことについての反応ももちろん嬉しかったのですが、
できなかったことに挙げた

* Exploreユーザーの育成ができなかった
* イケてるModel/Explore/View構成ができなかった

の二点も共感してもらえたようで、やはり皆様悩んでらっしゃるポイントなんだな〜と思いました。
相談会のような形で交流会でもこの点が話題に上ったのですが、各社試行錯誤はしつつもまだベストプラクティスという感触はなさそうな雰囲気でした。
一方で、微妙に相談内容と回答の噛み合わなさを感じた瞬間もあり、今振り返って考えると何がベストかは**Looker管理組織の体制とミッションに依る部分が大きいから**ではないかなと思っています。
例えば我々の部署だとデータエンジニアがいるため、データレイクからデータマートへのETL部分はそれほど大きくボトルネックになっている感覚はありません。また、私のようなデータアナリストでもLookerのみでなくAirflowにコミットしているような体制になっているため、Lookerでデータマート管理を完結する必要がなく（むしろリスクだと捉え）定常的に利用するテーブルについてはデータマート側に吸収させています。
ただ、ここでデータエンジニアがおらずデータレイクから直接Lookerに繋ぎ込んで分析をしている組織だとデータマート機能がLookerの中にできることになり、"イケてるModel構成"の意味合いが全く変わってくるのではないでしょうか。

## 今後に向けて
登壇という良い機会をいただいたことで、原理的な部分と各社の個性に向いたベストプラクティスは切り分けて整理すべきという気づきがありました。この辺りはもうすこし思考を煮詰めて整理しなおしたいところ。

弊社でも可能な範囲で試行錯誤した結果を情報公開していければと思っておりますので、
是非皆様の試行錯誤が詰まったLookMLも見せていただけることを期待しております！

## 最後に
今回のユーザー会を取りまとめくださった @hase-ryo さん、本当にありがとうございました。
また、光栄にも弊社をData Evangelistとして選出いただいたLookerの皆様本当にありがとうございました。
引き続き、何卒よろしくお願いいたします。
なでしこv3で音声合成

いつもの通り、自分が悩んだ末にたどり着いた記録を残します。

この記事は、「なでしこ」のv3ブラウザ版（[簡易エディタv3](https://nadesi.com/doc3/index.php?%E3%81%AA%E3%81%A7%E3%81%97%E3%81%933%E7%B0%A1%E6%98%93%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF)）で実行できます。v1 Windows版では動きません。

# プログラムで音を扱う
「なでしこv3ブラウザ版」では、音声合成する方法と，音声ファイルを再生する方法の2つがあります。

## 音声合成
ブラウザがWEBブラウザが音声合成API(Speech Synthesis API)に対応している必要がありますが，なでしこの[簡易エディタv3](https://nadesi.com/doc3/index.php?%E3%81%AA%E3%81%A7%E3%81%97%E3%81%933%E7%B0%A1%E6%98%93%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF)で次のプログラムを実行すると，ブラウザがお話ししてくれます。

```talk1.nako
「私はなでしこです」と話す。
```

パラメータを変更して，話し方を変えることができます。パラメータは**声高，ピッチ，速度，音量**を指定できます。値を設定する時はJSON形式で指定します。

```talk2.nako
{"声高" : 1.8,
  "ピッチ" : 2.0,
  "速度" : 0.6,
  "音量" : 1.0 }に話者詳細設定。
「私はなでしこです」と話す。
```

話者は何人かいるので（ブラウザに依ります），選択することができます。詳細はマニュアルに譲りますが，[話者一覧](https://nadesi.com/v3/doc/index.php?plugin_browser%2F%E8%A9%B1%E8%80%85%E4%B8%80%E8%A6%A7%E5%8F%96%E5%BE%97&show)を調べて，その中から[話者を選んで設定](https://nadesi.com/v3/doc/index.php?plugin_browser%2F%E8%A9%B1%E8%80%85%E8%A8%AD%E5%AE%9A&show)します。

余談ですが，私のプログラム歴のスタートは[**PC-6001mk2**](https://kunisan.jp/p6mk2/)というパソコンをサンタさんからもらった時でした。内蔵のBASICでは，音声合成する命令や，MMLで3和音まで演奏できる命令が組み込まれていて，最初はすごーく感激したのを覚えています。その後PC-6601が登場した時，**音声合成する命令で歌を歌えるようになった！**んです。初○ミクよりも数十年昔の話。

## 最後に
v3ブラウザ版は，どうしてもブラウザの機能によって動作する・しないが左右されるので，このメモが全てのブラウザに対応するとは限りませんが，一応。

## 参考

- v3マニュアル [音声合成](https://nadesi.com/v3/doc/index.php?plugin_browser%2F%E9%9F%B3%E5%A3%B0%E5%90%88%E6%88%90&show)
sleep,timeコマンド、テスト的に時間がかかるコマンドを実行してコマンド実行時間を計測する方法【bash,linux,mac】

コマンドライン上でテスト的に時間がかかるコマンドを実行したい場合、sleepコマンドが使えます。

#####sleep,timeコマンド

sleepコマンドは、指定した時間の間、停止状態になります。下のコマンドは10秒間停止します。

```
$ sleep 10
```
timeコマンドでコマンドの実行時間を計測できるので、確認してみます。

```
$ time sleep 10

real	0m10.014s
user	0m0.001s
sys	0m0.006s
```
コマンド実行時間(real)が10秒になっています。


あと、ただ長時間実行するコマンドを実行したいなら、watch、topコマンドなども使えます。

#####watchコマンド

watchコマンドは定期的に引数に指定したコマンドを繰り返し実行します。

```
$ watch date
```

ちなみにmacにはwatchコマンドはデフォルトで入っていないので、インストールする必要がある。

```
$ brew install watch
```

#####参考サイト、リンク
[【Linux】ターミナル上にて無限ループでコマンドを発行する](https://www.mtioutput.com/entry/howto-terminal-loop)
Amazon ECS タスク定義ファイルに機密情報を埋め込む方法

環境別に異なる機密情報をAmazon ECSタスク定義ファイルに埋め込む方法のメモ記事。

## 背景

* DB接続先情報やクライアント認証情報など環境ごとに異なる機密情報をAmazon ECSのタスク定義に展開したい。

  * Dockerでは、以下のように環境変数をコンテナのプロセスに渡すことができる。

    ```shell
    docker run -d \
      --env DB_USER=db_user \
      --env DB_PASSWORD=db_pass \
      myapp:latest
    ```

  * Amazon ECSの場合、`docker run`オプションを事前にタスク定義ファイルとして持たせておく必要がある。

    ```json
    [
      {
        "image": "myapp:latest",
        "name": "myapp",
    	...
        "environment": [
          {
            "name": "DB_USER",
            "value": "db_user"
          },
          {
            "name": "DB_PASSWORD",
            "value": "db_pass"
          }
        ],
     	...
      }
    ]
    ```

    

### 課題

* ECSタスク定義ファイルへの機密情報の埋め込み/管理方法。
  * コンテナ内部などに埋め込みたくない。
  * セキュアに保持したい。



## 対応方法

**AWS System Manager(SSM) パラメータストアに機密情報を格納し、コンテナ実行時に動的に環境変数を設定する。**

### 0.パラメータストアキーの作成

* AWS CLIで作成する。※出力結果のキーIDをひかえておく。

  ```shell
  aws kms create-key --description test-key --query KeyMetadata.KeyId --output text
  ```

  

### 1. AWS Systems Manager パラメータストアに機密情報用のSecureString パラメータを作成する

### 2. ECSタスクが1.で作成したSecureStringパラメータを取得/復号する為のECSタスクロールを作成する

* `Task Execution Role`に以下のようなポリシーをアタッチする。
    * `<key_id>`には、**0**で作成したキーIDを指定する。

  ```json
  {
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action": [
          "ssm:GetParameters",
          "kms:Decrypt"
        ],
        "Resource": [
          "arn:aws:ssm:<region>:<aws_account_id>:parameter/<parameter_name>",
          "arn:aws:kms:<region>:<aws_account_id>:key/<key_id>"
        ]
      }
    ]
  }
  ```

### 3.機密情報を参照するタスク定義ファイルを作成する

* `secrets`と`executionRoleArn`を以下のように設定する。

  ```json
  {
  	...,
  	"executionRoleArn": "2で指定したタスクロールのARN",
    "containerDefinitions": [
        {
        	...,
  			"secrets": [{
       			"name": "environment_variable_name",
       			"valueFrom": "1で作成したパラメータのARN"
  			}],
  			...,
      	}
    ],
    ...
  }
  ```

  ※機密情報でない場合は`secrets`ではなく、`environment`に指定する。

## 参考情報

* [Systems Manager パラメータストアを使用した機密データの指定](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/specifying-sensitive-data-parameters.html)
* [ECSの機能でSSMのParameter Storeに格納した機密情報をTaskDefinitionに埋め込む](https://engineering.mobalab.net/2019/03/06/allocate-secure-env-in-ssm-parameter-to-ecs-task-definition/)
* [create-key](https://docs.aws.amazon.com/cli/latest/reference/kms/create-key.html)
* [AWS CLI からのコマンド出力の制御](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-output.html)
react-colorで透過度を機能させる

## 困っていたこと

reactでcolor-pickerを使おうとしていたときに、hexの値のみの管理だと透過度（A: alpha値）の値が更新できていなかった。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371854/caad3710-e8d7-f1c0-42e0-c46d99c3d936.gif" alt="react-color" />

```jsx
import React, { useState } from 'react';
import { ColorResult, SketchPicker } from 'react-color';

const Main: React.FC = () => {
  // state
  const [hex, setHex] = useState('');

  const handleColorChange = (color: ColorResult) => setHex(color.hex);

  return (
    <>
      <div style={{ color: `${hex}` }}>{hex}</div>
      <SketchPicker color={hex} onChange={handleColorChange} />
    </>
  );
};

export default Main;
```

## 解決策

下記のissueに解決策が上がっていました。
この問題は公式でマイルストーン3.0.0に追加されたようですがまだリリースはされていないようです。

一応`color: ColorResult => color.rgb.a`から透過度を取得し、16進数に変換してから`color.hex`の後に付与することでSketchPickerのalpha値にも反映されるようです。

参考： [Alpha not updating・Issue #655・casesandberg/react-color](https://github.com/casesandberg/react-color/issues/655#issuecomment-573051343)

gif画像の#〇〇の文字列をみると末尾に透過度を表す16進数が追加されていることがわかります

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/371854/35165926-20dc-c5ef-6fba-1972e51d53aa.gif" alt="react-color" />

```jsx
  // Alpha値を16進数に変換する処理
  const decimalToHex = (alpha: number) =>
    alpha === 0 ? '00' : Math.round(255 * alpha).toString(16);

  const handleColorChange = (color: ColorResult) => {
    // "ff0500" + "80"の形式になるように
    const hexCode = `${color.hex}${decimalToHex(color.rgb.a || 0)}`;
    setHex(hexCode);
  };
```

## colorスタイルでの透過度の扱い

Hex（#ff0500など）の後に更に16進数を追加してやると透過度（alpha値）を適用してくれるようです。
たとえば`#ff050080`（#ff0500 + 透過度50%）など


> **Hexadecimal notation: #RRGGBB[AA]**
R (red), G (green), B (blue), and A (alpha) are hexadecimal characters (0–9, A–F). A is optional. For example, #ff0000 is equivalent to #ff0000ff.

参照: [<color> - CSS: Cascading Style Sheets | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value)
Ruby：FizzBuzzプログラムを作ってみた！

# 最初に

**カレンダー企画2020の13日目**
プログラミングの勉強を始めて3ヵ月程経ったので学んだことのメモをアウトプットとして記事に残します。
これからプログラミングの世界に入る人の手助けになれたら嬉しい限りです。
間違っていたり、言葉が違っていたり、誤解されるような言葉があったら教えてください^^
言葉を長々と読みづらかったら申し訳ありません。少しずつなれてがんばります。


## FizzBuzzプログラムを作ってみた

個人的な復習の為に再度作成してみようと思います！

>
### 条件

- 3で割り切れる数値を引数で渡すと、[Fizz]を返す
- 5で割り切れる数値を引数で渡すと、[Buzz]を返す
- 3と5の両方で割り切れる数値を引数で渡すと、[FizzBuzz]を返す
- その他の場合は引数を文字列にして返す

>今回はgetsメソッドを使ってキーボードに入力できるようにする（数字以外の入力は除く）


```ruby:demo_fizz_buzz.rb
def fizz_buzz(number)
  if number % 15 == 0
    "FizzBuzz"
  elsif number % 3 == 0
    "Fizz"
  elsif number % 5 == 0
    "Buzz"
  else
    number.to_s
  end
end

puts "数字を入力してください"

input = gets.to_i

puts "結果は！？"
puts fizz_buzz(number)
```

こんな感じになるはず！（他にも答えの記述はあるかもしれないです！）

`fizz_buzz(number)`メソッド名と引数を設定する。
if文を使って条件をクリアしていく。
条件に対しての戻り値を処理として記述をしてメソッドは完成！！

ちゃんと条件にあった型変換も忘れずに行っておく。

if文の中身で最初に「3と5の両方が割り切れる」条件を書くこと！
理由は処理の順番にある！上から順に処理をされるので、
「3か5片方が割れる」条件を先に書くと「両方割れる」条件が一向に引っかからなくなってしまう^^;

ここだけ気をつければ完成できる！

## 最後に

私はまだ理解していない頃、この順番を間違えていて完成できずに悩んでいました、、、^^;
JsonComponentを使ってオブジェクトを任意のJson形式にする

`Spring-Boot`の`@JsonComponent`を使用したJsonのシリアライズ・デシリアライズです。
オブジェクトをそのままJsonにすると、プロパティなどの階層関係をそのまま出力してしまうので、それを避けて任意のJson形式にしたいときなどに使用します。

#目的
**オブジェクトを任意の`Json`形式にしたい。**

例えば以下のような`User`クラスについて、`User`のリスト等をバックエンド側で取得して`Json`形式で返す処理を考えてみます。

```kotlin
//Userクラス
data class User(val name: UserName, val email: Email)
//以下はUserが持つ値オブジェクト
data class UserName(val value: String)
data class Email(val value: String)
```

`JsonComponent`を使用しない場合、以下のようなJsonが返ります。

```
[
	{
		"name": {
			"value": "taro"
		},
		"email": {
			"value": "sample@example.com"
		}
	}
]
```

これはこれとして使えないわけではありませんが、`Json`を使用する側で`name.value`や`email.value`などといった具合にアクセスする必要がでてきます。
どうせなら`name`だけで欲しい値にアクセスできる方がコードも冗長ではないですし、その方が直感的にも思います。そうした時に`JsonComponent`を使用することで`"name":"taro"`のような形式でJsonを返すことができます。

それでは実際に`JsonComponent`のクラスを見てみましょう。

#準備
特にありません。
`JsonComponent`は`Spring-Boot`の標準機能なので、依存関係等の追加はありません。

#実装

```kotlin

@JsonComponent
class UserNameJsonComponent {

    class UserNameSerializer: JsonSerializer<UserName>() {
        override fun serialize(userName: UserName, gen: JsonGenerator, serializers: SerializerProvider) {
            gen.writeString(userName.value)
        }
    }

    class UserJsonDeserializer: JsonDeserializer<UserName>() {
        override fun deserialize(p: JsonParser, ctxt: DeserializationContext): UserName {
            return UserName(p.valueAsString)
        }
    }
}
```

上記のように、`@JsonComponent`アノテーションを付与したクラスについて、内部クラスとして`JsonSerializer<T>`と`JsonDeserializer<T>`を継承したクラスを作成します。それぞれ抽象メソッドの実装をすることで任意の型（この場合は`UserName`）をJsonにシリアライズ（デシリアライズ）する方法を指定することができます。
このクラスを作成した状態で`User`のリストをJsonにすると、

```

[
	{
		"name": "taro",
		"email": {
			"value": "sample@example.com"
		}
	}
]
```

こうなります。当初の目的通り、`"name:taro"`の形式のJsonを作ることに成功しました。

なお、上記の`JsonComponent`はシリアライズ、デシリアライズをまとめて一つのクラスで実装しましたが、以下のようにシリアライザ・デシリアライザを分けて内部クラスとせずに実装することも可能です。どちらか一つだけで良い場合などはこれでもいいでしょう。

```kotlin
@JsonComponent
class UserNameSerializer: JsonSerializer<UserName>() {
    //省略
}

```

以上、`JsonComponent`の使い方でした。

#参考
https://www.baeldung.com/spring-boot-jsoncomponent
pygameを使って簡単なシューティングゲームを作ってみた

# はじめに
「グラディウス」というシューティングゲームもどきをpygameで遊ぶついでに作ってみました。

# グラディウスとは
「グラディウスシリーズ」は、コナミ（後のコナミデジタルエンタテインメントならびにコナミアミューズメント）より発売された、シューティングゲームのシリーズ作品。
ゲームの内容は自機であるビックバイパー（VIC VIPER）などの「超時空戦闘機」を操作し、バクテリアン軍などの敵の殲滅を目指す、というものである。（Wikipediaより）

# 作る上で使ったもの
要らないと思いますが一応載せておきます。

- ハード
    - macbook pro 2016（catalina）
- ソフト
    - VSCode
    - FireAlpaca（ドット絵作るアプリ）

# 作ったもの

![shooting_game.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912702/9e790ee2-9c5d-4fa8-35e2-e71770154586.gif)


![shooting.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912702/43095992-474c-d98a-2c19-61f245419781.gif)

![shooting_game2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/912702/d3a78f69-908d-833a-29a2-334c32974e98.gif)


遊び方としては、マウスポインターで自機を操作して弾幕を避けながら敵にレーザーを25回当てるだけです。


# シューティングゲームのコード
githubにコードを公開しておきました。もしよければプレイしてみてください。
https://github.com/oshiro0460/shooting-game


# さいごに
最初はキャラの画像も正方形を塗りつぶしたものにしていたのですが、背景とかキャラを自分で作ってみると意外とそれっぽくなりました。
弾幕の数を鬼畜にしたので自分で作っておいて負けることの方が多いですｗ


# 参考サイト
シューティングゲームを作るにあたって、参考にさせていただいたサイトを載せておきます。
http://westplain.sakuraweb.com/translate/pygame/
https://aidiary.hatenablog.com/entry/20080927/1281192848
https://woraise.com/2019/03/21/desert-shooting/
https://goodlucknetlife.com/pygame-shooting-background/
linuxでコマンドの操作が終わったら通知がほしい！

##はじめに
この記事は[Linux Advent Calender 2020のその2](https://qiita.com/advent-calendar/2020/linux2)の13日目の記事です。
あと急遽ICT Advent Calender 2020の14日目の記事にもなってしまいました。

皆さんは、linuxでふと`yum update`とかしたときにパッケージが500個とか出てきて憂鬱になったことはありませんか？
僕はあります。
なので、これをChromeのSecure Shellと簡単なスクリプト([hterm-notify](https://chromium.googlesource.com/apps/libapps/+/master/hterm/etc/hterm-notify.sh))で解決しちゃおう！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/593714/01e6e1d8-2fd4-876c-4613-3ba8f83ac895.png)
というのが今回やりたいことです。



##環境
今の僕の環境です。

CentOS Stream release 8[^1]
[^1]: 最近移行しました、[記事](https://qiita.com/honahuku/items/6dfb8f4e252d93f6b168)
Google Secure Shell
Chromeブラウザ

Secure Shellはchromeのタブでコンソールにアクセス出来るので凄く便利です。おすすめ。
##とりあえずやってみる
Google先生が偉大なものを残してくれたので、これをそのまま使います(おい
[このページ](https://chromium.googlesource.com/apps/libapps/+/master/hterm/etc/hterm-notify.sh)にシェルスクリプト(hterm-notify)の内容がそのまま載っているので、これをコピーします。
コンソールにアクセスし、/bin にnotifyというファイルを作成、編集します。

```sh
vim /bin/notify
```
さっきコピーした内容をそのまま全部コピーします。

##使い方
```
notify タイトル "本文"
```
で出来ちゃいます。
なので、

```sh
sleep 5 && notify Hooray "The sleep's done!"
```
とやれば5秒後に`The sleep's done!`という文字列を送信することが出来ます。
やったね！


##さいごに
この記事はICT Advent Calender 2020の14日目の記事です。
昨日は[ふんど](https://twitter.com/noname_303)さんでした。
前も野球の記事書いてました？[記事はこちらから](https://hundo.hatenablog.com/entry/2020/12/12/185448)

明日は[セビロ](https://twitter.com/suitzealot_111)です。
彼はなかなかクリエイティブ寄りな記事が多いので楽しみです。[記事はこちらから](https://suitsebiro111-10010.hatenablog.com/entry/2020/12/15/000000)

それでは皆さまよいクリスマスを！
魅力的なデザインを作る簡単なテクニックとは？

## 1) 色でメッセージを表現する

デザインを作り始める前に、まずは**「自分が表現したいメッセージは何か？」**を考えてください。

![whi-freshWebsite.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/0e1dbffd-aef8-cdb5-3501-b37ad412e455.png)

例えば、こちらの画像は自然食品販売用のWebサイトです。このWebサイトで伝えたいメッセージは、「天然の素材と健康」です。これらのキーワードを表現するために、どのような配色を思い浮かべますか？

明るい色や緑色は、人々に無意識のうちに健康のイメージを与えることができます。
あなたは以下のような自然な色を思い浮かべるかもしれません。

![whi-color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/8dbd359e-c52e-d6c1-0cea-f7b48cbb9f4f.png)

また、健康に関連して清潔感を表現するために白色や白いスペースを使用するのも有効です。

**「メッセージに応じて色を選ぶ」**ということを忘れないでください。

[Adobe Color](https://color.adobe.com/create/color-wheel "Adobe Color")のようなツールでさまざまな配色を選択・閲覧・検索してみると良いでしょう。

## 2) 色で視線を誘導する

一般的なデザインから色を抽出して、自分のデザインのテキストや他のさまざまな要素に色を使用してみましょう。

![whi-freshWebsite-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/71a3824f-8039-5d76-be9f-443076f23c36.png)

例えば、画像のオレンジから色を抽出し、テキストにその色を使用することで、閲覧者に統一感を感じさせることができます。単なるテキストでも、どのような色を使っても良いというわけではありません。小さなことの積み重ねがデザインを良くすることを忘れないでください。

## 3) コンテキストでメッセージを効果的に伝える

**コンテキストはとても大切です**。メッセージを効果的に伝えるだけでなく、デザインに深みを出すことができます。

![whi-travel-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/868a5548-15f1-9233-901a-dbc9303c5d39.png)

例えば、この旅行用のWebサイトは若く行動力のある女性をターゲットにしています。メインメッセージに関連した画像やアイコンを使用することはとても重要で効果的です。このポイントを意識することで、自分のデザインをレベルアップさせることができます。

![whi-travel-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/da42ed3f-1b5d-8c33-9123-7f0a350ff1d0.png)

どちらの写真も綺麗ですが、右側の写真は直感的ではなく、若くて行動力のある女性向けには目立ちにくい写真です。

見ている人がコアメッセージを瞬時に理解できるコンテキストを追加してください。コンテキストを追加するには、画像やアイコンを使用すると良いでしょう。

## 4) フォントのコントラストをつける

コントラストのある2つの異なるフォントを使用してみましょう。例えば、セリフとサンセリフ、太字と細字の組み合わせなどです。

![whi-fonts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/eba29e48-9379-62ec-6cea-d9aae91d5c4e.png)

異なるフォントが使用できない場合は、同じ色の複数で異なるレベルの色を用いてコントラストを強調してください。

![whi-useGoodColor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/ec50c6ab-c8dc-1bdc-bb99-31f2b4242129.png)

フォントの色と大きさは、デザインの階層の一部です。時と場合に応じて柔軟に使い分けましょう。

## 5) 面白味のある箇所を作る

**全てにおいて始まりが必要です。**デザインとレイアウトには見る側がメッセージを理解できるように、「初めに見る場所」が必要になります。デザインの要素を大きくしたり、グループから外したりすることで、面白味のある箇所を作ることができます。これは画像や言葉、文字でも有効です。
色の場合も同じく、1つの色を他の色から目立たせることで目を引くポイントを作ることができます。

![whi-books.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/890686/4aa4e14a-7746-452b-ad4c-347964ed2845.png)

## 6) 最後に

この記事では、デザインを始める前に考慮すべきポイントをご紹介しました。要約すると、この5つのポイントがあります：

1. 色の選び方
2. 色の例
3. コンテキスト
4. フォントの種類
5. 面白味のある箇所

デザインを始める前に、これらのステップについて一度考えてみると良いでしょう。時間はかかりますが、長い目で見れば役に立つ内容になっているので是非実践してみてください。
LaravelでJsonのレスポンスが文字化けしてしまう時の解決法

# 前提条件
Laravel 6.20.4
PHP 7.3.24

# 問題
Laravel６でJsonのレスポンスが文字化けしてしまう。
本来であれば、nameの部分が鈴木と表示される。
![スクリーンショット 2020-12-13 11.59.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243749/713c8977-80d0-8557-e8da-345167c9ad88.png)

# 解決方法
app\Http\Controllers\Controller.phpにJSON_UNESCAPED_UNICODEを設定したレスポンスを返すfunctionを作る。

```php:Controller.php
<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;

    public function jsonResponse($data, $code = 200)
    {
        return response()->json(
            $data,
            $code,
            ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
            JSON_UNESCAPED_UNICODE
        );
    }
}

```

使い方
全てのコントローラーがController.phpを継承しているので、
$thisを使ってjsonResponseを呼び出すことができる。

```php:UserController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class UserController extends Controller
{
    public function index()
    {
        $users = User::all();
        return $this->jsonResponse($users);
    }
}
```

正しく表示されました。
![スクリーンショット 2020-12-13 12.06.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243749/7afa457f-4974-74f1-1b92-139a6dfeda07.png)


# 参考記事
https://stackoverflow.com/questions/50717005/laravel-encode-json-responses-in-utf-8
docker run -itとは？


```bash
$ docker run --help | grep -e "-i," -e "-t,"
  -i, --interactive                    Keep STDIN open even if not attached
  -t, --tty                            Allocate a pseudo-TTY
```

・-iはアタッチされていなくても(コンテナの)標準入力を開いたままにしておく
・-tは擬似 TTY を割り当てる??


## -itあり
cmdを/bin/bashで上書きしてbashを起動する。-itを付けるとコンテナの中に入っていbashを使って操作できる。

```bash
$ docker run -it --rm centos:centos8 /bin/bash
[root@fe990f80d393 /]# aa
bash: aa: command not found
[root@fe990f80d393 /]# echo hoge
hoge
[root@fe990f80d393 /]# exit
```

## -itなし
コンテナが起動して直ぐに/bin/bashが終了し、--rmによってコンテナが削除される。
--rmなしでやるとコンテナが削除されず直ぐに停止したことがわかる。

```bash
$ docker run --rm centos:centos8 /bin/bash
$ 

$ docker run centos:centos8 /bin/bash
$ docker ps -a
CONTAINER ID   IMAGE            COMMAND                  CREATED          STATUS                      PORTS                               NAMES
7a9cf7a97800   centos:centos8   "/bin/bash"              6 seconds ago    Exited (0) 6 seconds ago                                        admiring_goldstine
```

## -tあり
-tを付けると擬似ttyが開きコンテナ内で操作できそうだけどコマンドを打っても応答がない。
exitも効かない。閉じれなくなる。

```bash
$ docker run --rm -t centos:centos8 /bin/bash
[root@bb3ad19806ed /]# echo hgoe

```

## -iあり
実行すると応答が返ってこないように見える。
しかしコマンドを打つとレスポンスが返ってくるし、exitで抜けられる

```bash
$ docker run -i --rm centos:centos8 /bin/bash
echo hoge
hoge
echo hoge
hoge
exit
```

-iを付けることでコンテナの標準入力に入力できる。
-iと--rmと組み合わせると一回だけコンテナを起動して結果だけ受けとることができる。

```bash
$ echo "echo hoge" | docker run -i --rm centos:centos8 /bin/bash
hoge
$ 
```

## まとめ
-t を付けると`[root@bb3ad19806ed /]#`のようなプロンプトが表示される。
-i を付けるとコマンドを打った時にレスポンスが返ってくる。