OmniAICreator/Qiita-1.07M huggingface dataset:
AWS Cognito 対話型スクリプトでユーザー作成してみた

## はじめに
Cognitoを用いてユーザー認証基盤作成しています。

ユースケースではサインアップをサーバー側で行う仕様なので自前でユーザー作成する必要がありました。

はじめは

```
sh test.sh name email company-id
```

といった形で引数でユーザー名等の必要な情報を渡していたのですが、

- 引数の順番を忘れる
- 引数を間違って入力した時に作成やめたい

などを感じたのでシェルスクリプトを用いて対話側でユーザー作成するプログラムを書くことにしました。

参考にしたサイトは[こちらのQiita記事](https://qiita.com/na0AaooQ/items/f2759c9b2c49d2210265)

## コード
```sh
function AdminCreateUser() {

  echo "----------------------------"
  echo "ユーザー名を入力してください"
  read username
  echo "メールアドレスを入力してください"
  read email
  echo "company_idを入力してください"
  read company_id


  echo "  下記構成でユーザーを作成します。実行する場合は yes、実行をキャンセルする場合は no と入力して下さい."
  echo "username:\t${username}"
  echo "email:\t${email}"
  echo "company_id:\t${company_id}"

  read input

  if [ -z $input ] ; then

    echo "  yes または no を入力して下さい."
    AdminCreateUser

  elif [ $input = 'yes' ] || [ $input = 'YES' ] || [ $input = 'y' ] ; then

    echo "  ユーザーを作成します"
    aws cognito-idp admin-create-user --user-pool-id ap-northeast-1_hogehoge --username $username --message-action SUPPRESS --user-attributes Name=email,Value=$email Name=email_verified,Value=True Name=custom:company_id,Value=$company_id --desired-delivery-mediums  EMAIL --temporary-password Easy1pass
    #セッションの取得
    session=$(aws cognito-idp admin-initiate-auth --user-pool-id ap-northeast-1_hogehoge --client-id 6hogehoge --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=$username,PASSWORD=Easy1pass | jq -r ".Session")
    # パスワードの作成
    password=$(pwgen -c 8 1)
    aws cognito-idp admin-respond-to-auth-challenge   --user-pool-id ap-northeast-1_hogehoge   --client-id 6hogehoge --challenge-name NEW_PASSWORD_REQUIRED --challenge-responses NEW_PASSWORD=$password,USERNAME=$username --session $session

    echo "  ユーザーを作成しました"
    echo "  パスワードは ${password} です"

  elif [ $input = 'no' ] || [ $input = 'NO' ] || [ $input = 'n' ] ; then

    echo "  ユーザーの作成を中止します"
    exit 1

  else

    echo "  yes または no を入力して下さい."
    AdminCreateUser

  fi

}

# シェルスクリプトの実行を継続するか確認します。
AdminCreateUser
```

内容こちらになります。

このスクリプトでは
1. ユーザーの作成
2. セッション情報の取得
3. 仮パスワードの更新

を行なっています。
CognitoはCLI等でユーザーを作成した場合はパスワードを再設定する必要があります。
そこを認証済みにするためにパスワードを再設定させるところまで実行させています。

### 注意
Macで使用する場合



```
brew install jq
brew install pwgen
```

でライブラリインストールする必要ありです
## 実行結果

```
----------------------------
ユーザー名を入力してください
test
メールアドレスを入力してください
test@gmail.com
company_idを入力してください
t

  下記構成でユーザーを作成します。実行する場合は yes、実行をキャンセルする場合は no と入力して下さい.
username:	test
email:	test@gmail.com
company_id:	t

~~~作成ログ省略~~~
ユーザーを作成しました
パスワードは dhXe3mer です

```

こんな感じに出力されます。
これなら必要事項順番に記入するだけだし、間違えてもno選択すれば取り消せるので便利ですね

## 終わりに
シェルスクリプトあまり書いたことなかったのですが、結構色々なことできるんですね

ただもっと複雑になると何らかの言語使った方がいいのかな、、と思いました

AWS　CLIは入力楽になりますが記述方で詰まってしまうことが多いので勉強して使いこなせるようになりたいですね、それでは！！！
Amazon Ground Station の紹介動画を和訳してみる

# はじめに
re:Invent 2018で発表された新機能の1つである Amazon Ground Station についての概要がAWSのサービス学習サイトにて公開されています。本記事では英語版のみのコンテンツを和訳しながら、Amazon Ground Station についての紹介を行います。

コンテンツへのアクセス方法は[こちら](https://qiita.com/Yoshiyuki03/items/bfbf416ab47ef5121927)に記載しています。

# Introduction

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/e289261d-7394-57cb-22b6-66613e9dc81e.png)

衛星放送設備は政府機関、大学などの教育機関、そしてビジネスなど幅広い分野で利用されています。これらには衛星と通信を行う際に地表アンテナが必要となりますが、これらを自前の設備とする際は膨大なコストと時間がかかるだけではなく、定期的な管理も必要となります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/d3805a36-fbee-6b43-9a97-43dd36ba43f2.png)

AWS Ground Stationはそういった問題を解決できる新しいサービスです。このサービスを利用することで以下のようなメリットを得られます。

- 自社で保有するよりも安価に衛星設備が利用可能
- 必要なときだけ利用することが可能
- データの送受信を従来よりも早く行うことが可能
- 他のAWSサービスとの連携が可能

# Ground Station とは?

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/10710f73-d2f7-ecfb-6c9f-d59facc2545c.png)

Ground Station は、衛星と通信する際に必要となる機器のことです。AWS Ground Stationは、AWS Regionとつながっているため、従来の地上局の役割に加えて以下の特徴を備えています。

- 低レイテンシ
- 高可用性
- データを素早く生成

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/96c146e9-9ad9-245f-304c-d9e76a06786b.png)

AWS Ground Stationは世界中に設置されており、地図にある円の中心地に設置されています。この円は、衛星が低軌道に入った際の通信可能な範囲を表示しています。

# AWS Ground Station のアーキテクチャ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/77d8db62-32ca-b542-e40b-dbe8b9d02497.png)

AWS Ground Station を利用する際の構成図の一例です。AWS Ground Station が衛星と通信していることが、構成図の左側の部分から分かります。ここで衛星からのデータ通信を受け取り、データを生成しています。構成図の右側は顧客のVPC環境です。こちらで AWS Ground Station のコンソールにログインし、生成されたデータを受け取ったり、そのデータを他の AWS サービスで利用したりすることができます。

構成図を見ると、いくつかのサービスは AWS Ground Station 側と Customer VPC 側で共有されていることが分かりますが、これは自前のフロントインでも AWS サービスのどちらも使えるように AWS 側が設定をしているためです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/d3687d90-306c-14c9-c214-ec82e36041fd.png)

AWS Ground Stationでは2つのタイプの通信サービスが用意してあります。

1. 衛星通信サービス
    - AWS Ground Station は以下の衛星との通信が可能です
        - 低軌道
        - 中軌道
        - 対地同期軌道
    - AWS Ground Station のアンテナは以下の周波数帯との通信が可能です
        - S- (Sバンド、S帯)
        - X- (Xバンド、X帯)
        - UHF (極超短波)
- 地表通信サービス
    - 以下の地上システムと利用者間の通信をサポートします
        - 固定電話
        - 衛星通信
        - イーサネット

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/8f1494fa-1c30-9f34-620f-c107a2825d21.png)

AWS Ground Stationの最大のメリットは、高性能な地上局を手頃な価格で必要に応じて利用することができる、という点です。

# 実際のコンソール画面とまとめ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/3c223f5c-1fcd-0b78-8992-32098cc15efe.png)

AWS Ground Stationのコンソール画面から、いつ・どの衛星と通信を行うかのスケジュールを決めることができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/56cbf6d5-a8d1-def5-6d59-78d899f0a3af.png)

通信する衛星を追加することも可能です。また、必要に応じてAWS Ground Stationのリソースの設定もすることができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/321349/ec99a559-79e9-cdd3-7d7e-15b92636e8ca.png)

最後に、AWS Ground Stationの内容について改めてまとめます。

- オンデマンドでのダウンリンクが可能
- AWSストレージなどへの直接アクセスが可能
- 従量課金制
- 衛星通信のためのインフラ整備の必要なし
- 衛星を使った幅広い構築や実験が可能に

# まとめ
AWS Ground Stationについての紹介は以上になります。AWS を利用することで大規模なテレビ局のみが利用出来た設備ですらも従量課金で利用できるようになりました。これらの新サービスを利用することで登場する新しいサービスが楽しみですね！
fpdf の multi_cell の使い方 (python3)

PHP のポートの　FPDF の multi_cell の使い方です。

次のような PDF を作成します。
![pdf_feb0201.png](https://qiita-image-store.s3.amazonaws.com/0/179446/c5c81f35-1a25-6065-6eae-6afa383ca6b1.png)

```py:fpdf_multi_cell.py
#! /usr/bin/python
#
#	fpdf_multi_cell.py
#
#					Feb/02/2019
# ------------------------------------------------------------------
import	sys
from fpdf import FPDF

# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
file_out = sys.argv[1]
sys.stderr.write(file_out + "\n")
#
pdf=FPDF()
pdf.add_page()
pdf.add_font('TakaoMincho','','/usr/share/fonts/OTF/TakaoMincho.ttf',uni=True)
pdf.set_font('TakaoMincho', '',14)

sys.stderr.write("pdf.x = %d\n" % pdf.x)
sys.stderr.write("pdf.y = %d\n" % pdf.y)

top = pdf.y
#
ww = [40,30,20,30]
#
offset = [0,0,0]
offset[0] = pdf.x + ww[0]
offset[1] = offset[0] + ww[1]
offset[2] = offset[1] + ww[2]

pdf.multi_cell(ww[0],10,'こんにちは\nおはよう\n今晩は\nさようなら',1,0)

pdf.multi_cell(ww[0],10,'下野市\n小山市\n真岡市\n佐野市',1,0)
pdf.multi_cell(ww[0],10,'AAAA\nBBBB\nCCCC\nDDDD',1,0)

pdf.y = top
pdf.x = offset[0]

sys.stderr.write("pdf.x = %d\n" % pdf.x)
sys.stderr.write("pdf.y = %d\n" % pdf.y)

pdf.multi_cell(ww[1],60,'Test AAA',1,0)

pdf.x = offset[0] 
pdf.multi_cell(ww[1],60,'Test BBB',1,0)

pdf.x = offset[1]
pdf.y = top
pdf.multi_cell(ww[2],60,'Sample\nPPP',1,0)

pdf.y = top
for season in ['春','夏','秋','冬']:
	pdf.x = offset[2]
	pdf.multi_cell(ww[3],30,season,1,0)
#
pdf.output(file_out,'F')
#
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

使い方

```bash
./fpdf_multi_cell.py out01.pdf
```
Google Cloud の認証トークンを gcloud コマンドで取得する。環境変数でサービスアカウントファイルを指定する例。

Google Cloud の認証トークンを gcloud コマンドで取得する。環境変数でサービスアカウントファイルを指定する例。

# つまづき

この手順でつまづいた。


[クイックスタート  |  Cloud Translation API  |  Google Cloud](https://cloud.google.com/translate/docs/quickstart)


# Command

```
gcloud auth application-default print-access-token
```

# Error

なんだよこれふざけんな‥！ うう 😭

```
Yumas-MacBook-Air:tmp yumainaura$ gcloud auth application-default print-access-token
ERROR: (gcloud.auth.application-default.print-access-token) The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.
```

あとでよく見たらちゃんと書いてあった‥よくある例‥がんばれ俺‥

>環境変数 GOOGLE_APPLICATION_CREDENTIALS をサービス アカウント キーが含まれる JSON ファイルのファイルパスに設定します。


# Credential


https://console.cloud.google.com/apis/credentials/serviceaccountkey

ここではテストで何やら強い権限を与えてしまうが、テストが終わったら一瞬で消したほうが良いかも。

![image](https://user-images.githubusercontent.com/13635059/52160100-c8d6b980-26f1-11e9-8d7f-8377c7d1491d.png)


![image](https://user-images.githubusercontent.com/13635059/52160107-f15eb380-26f1-11e9-92d5-df43015dacea.png)


# 再度チャレンジ

上で作ったファイルを環境変数で指定する。 `example.json` 的な。

```
$ GOOGLE_APPLICATION_CREDENTIALS=example.json gcloud auth application-default print-access-token
トークン！トークン！トークン！トークン！トークン！生成！
```

# うまくいった。

喜びのポーズ！！！

![image](https://user-images.githubusercontent.com/13635059/52160139-a42f1180-26f2-11e9-9c14-a9d32b181e53.png)

# Ref

[The Application Default Credentials are not available · Issue #175 · googleapis/gax-dotnet](https://github.com/googleapis/gax-dotnet/issues/175)








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
マウスホイール(中央ボタン) クリックのイベントはmousedownで

リンククリック時のイベントを書いていましたが、リンクはホイールボタンをクリックして別タブで開くこともあります。
その場合、clickイベントでは発火しないため、mousedownイベントで捕捉する必要があります。

すなわち

```js

const clickEvent = (e) => {}

const a = document.querySelector('a')

a.addEventListener('click', clickEvent)
a.addEventListener('mousedown', (e) => {
  if (e.button != 1) {
    return
  }
  clickEvent(e)
})
```

と中央ボタン判定を加える必要がある。
いっそ左ボタンクリックもmousedownに統合してclickイベントは書かなくてもよい。

clickイベントにも押されたボタンを調べられるbuttonプロパティがあるが、そもそも発火しないため罠というか無駄に継承している感があるような…

左クリックはclick,右クリックは(一応)contextmenuで検知できるのに、中央クリックにイベントがないのは釈然としなかったので調べたが、どうにも見つからない。
wheelイベントもあるのだから、もう一声。あっても良かろうに。

# 参考

[JavaScript 右クリックをキャンセル&処理を割り当てる | TM Life](http://tmlife.net/programming/javascript/javascript-right-click.html)
認証認可について学んだことまとめ

とある事情で認証・認可について学ぶ必要があったので、学んだことをまとめていこうと思います。

# 前提知識
まず前提知識となる用語の解説から学んでいきました。
この2つの記事が大変参考になり分かりやすかったです。

用語の説明 & 例え話で理解が進みやすいのはこちら
https://dev.classmethod.jp/security/authentication-and-authorization/

webサービスの例も交えており、より例が具体的で分かりやすいのはこちら
https://qiita.com/TakahikoKawasaki/items/f2a0d25a4f05790b3baa#%E8%AA%8D%E8%A8%BC%E3%81%A8%E8%AA%8D%E5%8F%AF

# 認証(authentication)とは
認証とは、その人がその人自身であることを確認する行いです。
ポイントとしては、認証とはあくまで確認だけに留まり、その人にある権限とは関係がありません。
例えば、会社によっては社員証と会社に入館できる磁気カードが分かれていたりすることがあります。
社員証ではその人が会社の社員であることの証明を行うことができますが、
磁気カードを家に忘れてしまった場合は入館はできません。

# 認可(authorization)とは
認可とは、その人に権限を付与する行いです。
先の例で言えば、磁気カードを自分ではない他人が入手した場合、
その人が「社員の○○さんであるか」とは関係なく会社に入館することができてしまいます。

「社員の○○さんである」ことと、○○さんの所属する「会社に入館できる」ことはそれぞれ、「認証」・「認可」という意味では関係はありません。

# 実際に作ってみる
ある程度意味を掴んだところで実際に作って確かめるためにオレオレOAuth認証を行うプロバイダーと、
プロバイダーサーバで認可された後に利用することができるクライアントサーバを作ってみました
やりたいことは下記のようなイメージです
![セキュリティ.png](https://qiita-image-store.s3.amazonaws.com/0/280433/696e61df-a29b-ab94-6779-ede9169b19f4.png)

構築の流れはこちらに記載しています。
いずれのサーバもlocalで起動させており、プロバイダーサーバは300ポート、Clientsサーバは3001ポートで動いています。以降の内容は、全て下記ページで構築したアプリケーション上で動作することを想定しています。
https://qiita.com/moehiko/items/300dcfa4d8f70660bcd1

# ①クライアントサーバ：認可サーバへアクセス
まずClientサーバにアクセスします。
http://localhost:3001/users/sign_in

![スクリーンショット 2018-12-24 14.07.36.png](https://qiita-image-store.s3.amazonaws.com/0/280433/c2311db5-ceea-a363-8034-7873b4e57071.png)
「Sign in with Mock」をクリックすると、プロバイダーサーバの、認証を求める画面に遷移します
※今回は「Mock」が他のAOuth認証で言うところのFacebookと思ってください

# ②プロバイダーサーバ：認証
下記ページに遷移し、プロバイダーサーバでの認可を行うために認証を行います。
http://localhost:3000/users/sign_in

![スクリーンショット 2019-02-02 13.12.04.png](https://qiita-image-store.s3.amazonaws.com/0/280433/2608d931-b33e-b334-f612-8eab7cd608e7.png)
画面は同じですが、こちらはプロバイダーサーバ側のものです。

# ③プロバイダーサーバ：アカウントに認可を与える
認可を求めるページに遷移します。
http://localhost:3000/oauth/authorize?client_id=xxxxx&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fusers%2Fauth%2Fmock%2Fcallback&response_type=code&state=xxxxx

![スクリーンショット 2019-02-02 13.17.05.png](https://qiita-image-store.s3.amazonaws.com/0/280433/bb50efa8-68ce-c154-0d3e-a8c5261799a0.png)
認証後、ログインしているアカウントに対し、mockを使ってクライアントサーバへアクセスできるようにする認可を与えるかの確認を求められます。

# ④プロバイダーサーバ → クライアントサーバへリダイレクト
認可を与えるとクライアントサーバへリダイレクトされます。
http://localhost:3001/home
![スクリーンショット 2019-02-02 13.34.42.png](https://qiita-image-store.s3.amazonaws.com/0/280433/3ff8de56-248d-4794-bfcb-eace0aba2deb.png)
クライアントサーバへリダイレクトされ、コンテンツが表示されました。
ちなみに、ログインしない状態でこのページにアクセスすると、①の画面に戻されるようになっております

# おわり
以上でAOuth認証サーバを作ってみて、認証・認可の仕組みを学んでみたまとめは終わりとなります。
意味を学ぶのは先人の記事もあり、作ってみてしっかりと理解するのはなかなか大変ですね・・
github clone⇨bundle install⇨rails db:create⇨rails db:migrate⇨rails s

gitのURLがあって自分の環境に持ってくるとき。

```
git clone
bundle install
rails db:create
rails db:migrate
rails s
```

`実際に作成されるデータベースはconfig/database.ymlでの設定内容に基づき作成されます。`
Rails consoleがreadlineの原因でうまく読み込めなかった

#### 環境
・macOS Mojave(10.14.3)
・Ruby 2.6.0
・Rails 5.2.2

ふとある日、rails consoleからエラーが返されるようになった。

```
$ rails console
　　　　　　　　・
　　　　　　　　・
　　　　　　　　・
dlopen(/Users/user/.rbenv/versions/2.6.0/lib/ruby/2.6.0/x86_64-darwin18/readline.bundle, 9): Library not loaded: /usr/local/opt/readline/lib/libreadline.7.dylib (LoadError)
  Referenced from: /Users/user/.rbenv/versions/2.6.0/lib/ruby/2.6.0/x86_64-darwin18/readline.bundle
  Reason: image not found - /Users/user/.rbenv/versions/2.6.0/lib/ruby/2.6.0/x86_64-darwin18/readline.bundle
```

とりあえずざっとバックトレースを読んでいく。
**Load Error**と**readline.bundle**
臭いますね、正常に読み込めてない様子。

別機Ubuntu18.04にクローンして動かしてみましたが問題なく動きましたので、
問題があるのはこのマシンだと思いました。

Google先生に聞いてみましたが出てくるのは`gem 'rb-readline'`をGemfileに追記して`bundle install`するようにといった記事が・・・。
このマシンの問題なのでGemfileに追記する方法はとりあえずパスすることに。

## 原因と解決方法
Homebrewにインストールされていたreadlineが更新されたことが原因でした。

```
$ brew info readline
readline: stable 8.0.0 (bottled) [keg-only]
Library for command-line editing

/usr/local/Cellar/readline/7.0.5 (46 files, 1.5MB)　
  Poured from bottle on 2018-08-12 at 14:38:05
/usr/local/Cellar/readline/8.0.0 (48 files, 1.5MB)
  Poured from bottle on 2019-01-31 at 01:03:39
・
・
・
```
以前のバージョンにロールバックをします

```
$ brew switch readline 7.0.5
Cleaning /usr/local/Cellar/readline/8.0.0
Cleaning /usr/local/Cellar/readline/7.0.5
Opt link created for /usr/local/Cellar/readline/7.0.5
```

無事動くように。

```
$ rails c
Loading development environment (Rails 5.2.2)
irb(main):001:0>
```

原因の発端はHomebrewのパッケージをごっそり更新したことでした。😔

追記)
Ruby 2.6.0ではreadline8.0.0が動かず、
Ruby 2.6.1にすることで動きました。
LINUXで実行したことのるコマンドについて[面接対策]

*業務経験1年経過し、内容を更新致しました。(2020/04)
更新した部分に＊を入れていきます。

<h2>はじめに</h2>
私は未経験エンジニアで転職活動をしている身です。選考が進むにつれて技術的な質問をされます。
今回は実際に面接でされた質問をもとに復習をかねて記事にします。

今回の質問は**「LINUXで実行したことのあるコマンドがあれば教えてください」**です。
→細かいですけど、Linuxですね。未経験らしい質問です。(*)

<h2>Linuxとは</h2>
まずは、いきなり回答するのではなくLINUXの歴史から見てみましょう。あくまで面接対策なのでかーなーり、ざっくり書きます。笑

いまでは当たり前ですが、昔はコンピュータにOSと言う概念がなく不便に感じていたところ天才が集まるベル研究所でUNIXが誕生したそうです。OSとはwindows・Mac・Android・ios等が有名ですよね。UNIXもこのOSの一種です。

ところが、UNIXはオープンソースではなかったので著作権や規制で自由な開発ができなかったそうです。
そこで、開発されたのがオープンソースであるLINUXです。

著作権も規制もないオープンなOSなので、爆発的に普及したそうです。
まあ、こんな感じです。

<h2>コマンドとは</h2>
コマンドとはPCの世界ではコンピュータに命令することです。MacOSの場合はターミナルを使用すると思いますが、ターミナルに「ls」を打ち込み実行するとディレクトリ内部の情報を一覧で表示してくれます。

<h2>コマンド一覧</h2>
未経験の面接では実行したことのあるコマンドを教えてください程度のことしか聞かれないと思いますが、以下に覚えるべきコマンドをまとめます。

**ls**    :ディレクトリの内部の一覧を表示してくれます。
**date**  :日付を表示してくれます。
**pwd**   :現在のディレクトリを表示してくれます。
**cd**    :ディレクトリを移動することができます。
**mkdir** :ディレクトリを作成することができます。
**id**    :ユーザーのidを表示してくれます。

以下、業務でかなり使ったな〜ってコマンドを追加します。(＊)
**cp**    :コピーするコマンド。
**touch** :ファイルを作成
**rm**    :ファイルを削除
**cat**   :ファイルの内容を表示
**chmod** :ファイルやフォルダのアクセス権限を変更する



実際にアプリを作る時はmkdirとcdをメインに使うと思うので、それ以外は初心者は忘れがちですが、経験を積むことで自然に覚えてくはずです。
→上記既存コマンドと追加コマンドの両方を特に使用します。初心者が覚えるのは難しいですが実務で自然と覚えるのは事実です。ただ、mkdirとcdをメインに使うという記述は間違いです。(＊)
GoogleのreCAPTCHA v3をPHPで使う

# reCAPTCHA v3について
バージョン3からユーザーが画像の選択などぽちぽちしなくてよくなって、スコアが返ってくるそうです。
[reCAPTCHA v3](https://developers.google.com/recaptcha/docs/v3)

[connpass](https://connpass.com/dashboard/)にも導入されていました。
右下にリキャプチャのマークが表示されるだけで、ユーザーからすると何も選択しなくて良いので楽ですね。

# 導入する手順
先ほどの公式のガイドにキーの取得の仕方とフロントエンドでどのように実装すれば良いか記載されています。

PHPを使う場合には下記の記事に詳細に書かれています。(英語だけど)
[Adding Google reCAPTCHA v3 to a PHP form](https://stevencotterill.co.uk/blog/adding-google-recaptcha-v3-to-a-php-form/)

問題なく導入できている場合には、右下にリキャプチャのマークが表示されますが、APIkeyが間違っている時などは赤文字が出るのでそれも確認しておくと良いと思います。


## スコアについて
先ほどの記事の中にあるコードですが、リキャプチャからのレスポンスに含まれるスコア(0.0 ~ 1.0)に応じて処理を分けています。

```php
// Take action based on the score returned:
    if ($recaptcha->score >= 0.5) {
        // Verified - send email
    } else {
        // Not verified - show form error
    }
```

スコアが返ってくる仕様になっていると聞いて、もし不正ではないと思われるユーザーが認証できない場合に、このスコアで調整できると思っていました。
実際に導入をしてみると、ほとんどのアクセスが`0.9`で、そのあと`0.7`,`0.3`,`0.1`と4パターンしか確認できなかったので、あまりスコアの調整をしてもって感じもします。


### スコアが低くなる場合
こちらの記事によると下記のパターンではスコアが低くなったそう
[reCAPTCHA v3 入れてみた](http://www.techscore.com/blog/2018/12/06/recaptcha-v3/)

```
0.1：アドオンでユーザーエージェントを変更した場合（実際はFirefoxなのにEdgeなど）
0.7：広告ブロック機能を持ったブラウザ

0.7は広告ブロックしているからではなく、ユーザーエージェントがレアだからかもしれないと考え、Firefoxにそのユーザーエージェントを設定してみましたが、スコアは0.1でした。
```

実際に[User-Agent Switcher for Chrome](https://chrome.google.com/webstore/detail/user-agent-switcher-for-c/djflhoibgkdhkhhcedjiklpkjnoahfmg)を使ってUAを変更してみると、スコアが0.1で認証できませんでした。
また、chromeの開発者ツールで変更した場合にも同様の結果でした。

## 認証ができないケース
上記の検証とは別に、ユーザーから認証ができないとの問い合わせがくるので、いくつか認証できないパターンを調べました。

### googleのjsの実行を許可していない
これは前のバージョンのリキャプチャからだと思いますが、導入しているサイトのドメインとGoogleのドメインのJSを許可する必要があります。
実際にいたユーザーの方で、ホワイトリスト形式でJSの実行を許可するaddonを使っており、リキャプチャを導入しているサイトのJSは許可しているけど、Googleは許可していないという方は認証ができていませんでした。
[NoScript Security Suite](https://addons.mozilla.org/ja/firefox/addon/noscript/)

### セキュリティソフトによる影響
これは実際に手元で検証できた訳ではないですが、どうしても認証ができないユーザーがの方が、使っていたセキュリティソフトを無効にしたところその後は認証ができるようになったとの報告がありました。

### tokenの有効期限切れ
具体的な時間はわかりませんが、10分も有効期限はないです。基本的には問題ないと思いますが。。
[Using reCAPTCHA v3 in the frontend #281](https://github.com/google/recaptcha/issues/281)

### token取得までのタイムラグ
先ほどの[Adding Google reCAPTCHA v3 to a PHP form](https://stevencotterill.co.uk/blog/adding-google-recaptcha-v3-to-a-php-form/)に沿って実装すると、トークンをhiddenタグに埋め込みます。

```php
<input type="hidden" name="recaptcha_response" id="recaptchaResponse">
```

実際にtokenの取得までに(感覚的にですが)1秒弱時間がかかるので、完了の前にリクエストを送るとエラーになります。パスワードなどがブラウザ側に保存されていて、すぐに認証が実行できる場合には、このケースは発生しうるかと思います。

## スコアを確認する方法
[admin console](https://g.co/recaptcha/admin)からリクエスト数やそれぞれのスコアを確認できるので、こちらも参考にしてください。
Computedプロパティのgetでreturnしたものがsetの引数になるっぽい

参考図書、[本家サイト](https://jp.vuejs.org/v2/guide/computed.html#%E7%AE%97%E5%87%BA-Setter-%E9%96%A2%E6%95%B0)にも明示されていなかったので検証したものを書いてみます。


#消費税計算のサンプル
```getset.js
function initial() {
    new Vue({
        el:'#msg',
        data: {
            woTax:'0'
        },
        computed: {
            wTax: {
                get: function(){
                    return parseInt(this.woTax *1.08);
                },
                set: function (val) {
                    this.woTax = Math.ceil(val / 1.08);
                }
            }
        }
    })
}
```

#曖昧だった点

```getset.js

                get: function(){
                    return parseInt(this.woTax *1.08);
                },
                set: function (val) {
                    this.woTax = Math.ceil(val / 1.08);
                }

```

set関数の引数valにはgetのリターンが返って来るんだろうな・・・
ということはわかるが、念のため検証

#検証

```getset.js

                get: function(){
                    return parseInt(this.woTax *1.08);
                },
                set: function (test) {
                    this.woTax = Math.ceil(test / 1.08);
                }

```

このように変更しても動作し、IDEでも変数として認識されていたので
getでリターンしたものがsetの引数として自動的に渡って来る動きになっているっぽいです。
認識違いなどツッコミありましたらお願いいたします。
electron で通知を使う(Notification)

デスクトップアプリをさっくり作れてしまう electron ですが、通知に関してドハマリしました。お役に立てるかどうか微妙な情報ですが、まとめておきます。

~~投稿するつもりなんて全然なかったんですが、「下書き多すぎ」ってシステムに叱られたんで公開することにしました~~

# electron の通知（Notification）種類
electron の通知システムは呼び出し場所により大きく2種類に別れます。

## renderer process で利用
HTML5 Notification API を利用することが出来ます。
[Notifications (Windows, Linux, macOS)](https://electronjs.org/docs/tutorial/notifications)

## main process で利用
Class: Notification が用意されています。
[Create OS desktop notifications](https://electronjs.org/docs/api/notification)

# ここから本題
上記の2つのうちのどちらかで対応できれば幸せなのですが、実は Windows10 の環境で「通知がされない」という、不具合を踏んでしまいました。。。
手元の環境(Windows7)では通知され、Windows10 でも一部の環境では動いてしまったので、かなり困りました＾＾；

[Notification API do not work with Windows 10 16299.19 (fall creators update) #10864](https://github.com/electron/electron/issues/10864)

色々原因があるようで、対処方法もきちんとクローズされているものからおまじないレベルまで様々です。

# 解決方法
当方豪腕なので、当然力技代替案ですｗ
ちっちゃいフレームなしブラウザを表示することで対応しました。
main process に「通知ブラウザ」を用意します。

```Node.js
    const { screen } = require('electron');
    const { width, height } = screen.getPrimaryDisplay().workAreaSize
    notifyWindow = new BrowserWindow({
        title: "notify message",
        frame: false,
        show: false,
        x: width - 290,
        y: height - 120,
        width: 280, 
        height: 80,
        icon: path.join(__dirname, '/public/icon.png'),
        setMenu: null,
        skipTaskbar:true
    });
    notifyWindow.loadURL(url.format({
        pathname: path.join(__dirname, 'notify.html'),
    }))
    notifyWindow.setAlwaysOnTop(true)

```
あとは、条件合致で show してあげればよいです。

electron 利用アプリで正しく通知できているものもあるので、根治できる気もしますが、趣味のアプリであればさっさと見切りつけて代替案採用したほうが手っ取り早いです。

# おまけ
条件合致で show する時に、音出したい場合はブラウザ起動時にオプションを追加して上げる必要があります。
[DOMException: play() failed because the user didn't interact with the document first. #14323](https://github.com/electron/electron/issues/14323)

```Node.js
const {
  app,
  BrowserWindow,
  ipcMain
} = require('electron')
app.commandLine.appendSwitch('--autoplay-policy','no-user-gesture-required')
```
Rails + Pumaの開発環境をSSL化

ローカルの開発環境をSSL化したメモ
## 自己署名証明書を発行
opensslを使用

```ssh.log
user:hoge $ mkidr tmp/   # プロジェクト配下に適当なディレクトリを作成
user:hoge $ cd tmp/
user:tmp $ openssl genrsa 2048 > server.key
user:tmp $ openssl req -new -key server.key > server.csr  # 色々聞かれるので、適当に答える
Country Name (2 letter code) [AU]:***
State or Province Name (full name) [Some-State]:***
Locality Name (eg, city) []:***
Organization Name (eg, company) [Internet Widgits Pty Ltd]:***
Organizational Unit Name (eg, section) []:***
Common Name (e.g. server FQDN or YOUR name) []:**
Email Address []:******
A challenge password []:*********
An optional company name []:*******
user:tmp $ openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt
```

## pumaの設定変更
pumaに以下を追記する
(ポート番号は好きな番号で)

```ruby:puma.rb
if 'development' == ENV.fetch('RAILS_ENV') { 'development' }
  ssl_bind '0.0.0.0', '5001', {
    key: 'tmp/server.key',
    cert: 'tmp/server.crt',
    verify_mode: "none"
  }
end
```

## 起動
`rails s` ではなく、 `bundle exec pumactl start`で起動する
(pumaの設定を読み込むため)
最後に `https://`でアクセスしてみて確認

## 最後に
`bundle exec pumactl start`
でpumaを起動すると、別でターミナルを起動して、 `tail -f`をしないとログがみれないので、
ちょっと不便になる。。
JavaScript で選択できないテキストをクリップボードへコピーする方法

### クリップボードにコピーする機能のサンプルコード

```html
<html>
    <head>
        <meta charset="UTF-8">
        <script>
            document.onselectstart = function() {
               return false;
            }
            function copyTextToClipboard(element) {
                var copyTarget = document.getElementById(element);
                var copyArea = document.createElement("input");
                copyArea.value = copyTarget.textContent;
                document.body.appendChild(copyArea);
                copyArea.select();
                document.execCommand("Copy");
                if (!('remove' in Element.prototype)) {
                    Element.prototype.remove = function () {
                        if (this.parentNode) {
                            this.parentNode.removeChild(this);
                        }
                    };
                }
                copyArea.remove();
                alert(copyTarget.textContent + "をコピーした。");
            }
        </script>
    </head>
    <body>
        <span id="copyTarget">テキスト</span> 
        <button onclick="copyTextToClipboard('copyTarget')">コピー</button>
    </body>
</html>

```

### サンプルスナップショット

![copyTarget.png](https://qiita-image-store.s3.amazonaws.com/0/155256/a84e69ae-b77a-c9f6-6343-efdb0b191edd.png)
【超簡単】Laradockの環境構築が面倒臭いので ShellScript にまとめてみた

# Laradockの調整だるい... →　まとめちゃえ！

こんにちは、どんぶラッコです。
昨日、このようなエントリーを投稿しました。

【2019年2月】Laradockの初期環境設定方法
https://qiita.com/don-bu-rakko/items/0297280553e99aa6d7b8

沢山の躓きポイントがあったため、かなり手探りをしながらのセットアップとなってしまいました。
そして、やっとの思いでセットアップ方法をまとめたわけですが、

...長い！！！これ毎回やらなきゃいけないの！？

という思いが出てきてしまったわけです...。

というわけで、↑の処理を**ShellScript**でまとめてみました！
これによってコマンド一発でLaradockが生成できてしまうわけなんです。

# デモ動画

https://www.youtube.com/watch?v=fd1Bazcl8UY
![image.gif](https://i.gyazo.com/d9719a246ed10dbfd34e8e334be2c4b0.gif)


# 使用方法
  
超簡単です！ `laradock-creator.sh` を実行するだけだもの！！

## GitHub

https://github.com/cha1ra/laradock-bash

## コマンド

もし `sample-app` を作成したい場合は、以下のように入力してください。

```shell
git clone https://github.com/cha1ra/laradock-bash.git
cd laradock-bash
bash laradock-creator.sh sample-app
```

引数に入力しなくても実行することができます（途中で質問されます）。

```shell
$ bash laradock-creator.sh


++++++++++++++++++++++++++++++
    LARADOCK CREATOR v1.0
Build Laravel env in 10 steps
      by don-bu-rakko
++++++++++++++++++++++++++++++

1. Start Laradock Setup ...

[!] Put your Project Name:
```

後は待つだけ！我ながらグッジョブすぎる...
全てのセットアップが完了したら、
http://localhost
で環境にアクセスすることができます。
  
## エラーログ　　
  
もしプロジェクト名が既に存在していた場合は怒られます。
  
```shell
~/Sites/bash/laradock-bash master* 7s
❯ bash laradock-creator.sh project-example


++++++++++++++++++++++++++++++
    LARADOCK CREATOR v1.0
Build Laravel env in 10 steps
      by don-bu-rakko
++++++++++++++++++++++++++++++

1. Start Laradock Setup ...

2. Create Project: project-example

3. Make project-example directory

------------ERROR!------------
'project-example' directory already exists!
Stop this operation.
------------------------------
```

Dockerがインストールされていなくても怒られます。

```shell
6. Build Docker containers...

------------ERROR!------------
Docker doesn't exist on your computer! Please install Docker first
Stop this operation.
------------------------------
```
  
# 実行環境
  
- Mac OS 10.14
- Git がインストールされていること
- Docker for mac がインストールされていること
    - (Docker コマンドが実行できること)

# 使用するコンテナ
- nginx
- mysql
- phpmyadmin

---

説明は以上です。

手順を全自動化したとはいえ、僕の環境ではこの手順全てを完了するまでに**約8分**ほどかかります。手動でやっていたらどんだけ時間がかかるんだろう...。考えたくもないですね。


ちなみに、今回私は人力の手順を自動化するというアプローチで記述してみました（なので、Laradockも都度githubからダウンロードしてきます）が、Laravelの構築に必要な最低限のLaradockファイルをあらかじめ持っておいて自動的にインストールする手法を取っているQiita投稿もあります。
https://qiita.com/taichi0529/items/bd45a9271354430ca952
私が通っているプログラミングスクールの先生です！  

他にもまだまだ色々なアプローチがあると思うので、色々試していきたいですね。


そんなわけで Laradock Creater, ぜひ使ってみてください( `・ω・´)
kanateaTalkで音声合成

#概要

kanateaTalkは、vectorにある、音声合成コンソールアプリだ。
シフトJISな、アクセント付きカナテキストを読み上げる。
jsdoでヘルパーを作った。

#写真

![](http://jsdo-static-contents.s3.amazonaws.com/images/capture/C/9/0/C90m.jpg?t=1549075250)

#使い方

ボタンを押すと、タグが挿入される。
downloadで、test.txtがダウンロードされる。
KanateaTalk test.txtで実行。


#サンプルコード

```
var str2array = function(str) {
    var array = [],
        i,
        il = str.length;
    for (i = 0; i < il; i++) 
    {
        array.push(str.charCodeAt(i));
    }
    return array;
};
function u2s(str) {
    var array = str2array(str);
    var sjis_array = Encoding.convert(array, "SJIS", "UNICODE");
    var uInt8List = new Uint8Array(sjis_array);
    return uInt8List;
}
var src = document.getElementById('src');
function v() {
    src.value = "<VOICE OPTIONAL=female01>" + src.value + "</VOICE>"; 
}
function r() {
    src.value = "<VOLUME LEVEL=1.5>" + src.value + "</VOLUME>"; 
}
function p() {
    src.value = "<PITCH LEVEL=0.5>" + src.value + "</PITCH>"; 
}
function s() {
    src.value = "<RATE SPEED=0.5>" + src.value + "</RATE>"; 
}
function d() {
    var txt = src.value;
    txt = u2s(txt);
    var url = URL.createObjectURL(new Blob([txt]));
    var a = document.createElement('A');
    a.download = 'test.txt';
    a.href = url;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}

```

#成果物

http://jsdo.it/ohisama1/C90m/

以上。
pythonでprint()の改造

### やりたいこと
関数を別名に退避しておき、既存関数を再定義する
print()ではあとから出力内容を整形したいな、というときに使う。


### コード
```python:hogehoge.py
# -*- coding: utf-8 -*-
import datetime

# printをppprintへ退避
ppprint = print

# printを再定義
def print(*args, **kwargs):
    try:
        ppprint(str(datetime.datetime.now())+":::", end="")
        ppprint(*args, **kwargs)
    except Exception as e:
        ppprint(*args,**kwargs)

print("qiita")

```

### 実行結果
```
> 2019-02-02 11:56:16.296658:::qiita
```

### ※2019.02.10 追記
#### グローバル変数を汚さないやり方をコメントで教えていただきました
デフォルト引数を使う方法
デフォルト引数は関数定義時に一度だけ評価されるので、元のprintをずっと覚えていられます。

```
import datetime

# printを再定義
def print(*args, print_=print, **kwargs):
    try:
        print_(str(datetime.datetime.now())+":::", end="")
        print_(*args, **kwargs)
    except Exception as e:
        print_(*args,**kwargs)

print("qiita")
```

組込み情報を参照する方法

```
import datetime

# printを再定義
def print(*args, **kwargs):
    try:
        __builtins__.print(str(datetime.datetime.now())+":::", end="")
        __builtins__.print(*args, **kwargs)
    except Exception as e:
        __builtins__.print(*args,**kwargs)

print("qiita")
```
Tkinterを使ってmacOSでシートダイアログを出す方法

Tkinterを使ってGUIアプリを作っていたのですが、macOSの場合、ダイアログは新規ウインドウではなくシート状にペロッと出てくる事が多いので、これをなんとか実現したかったので検証したところ実現できました！！

messageboxの中にparentオプションがあるのでそこに親ウインドウを指定してあげます。そうすると指定したウインドウからダイアログがシートとして表示されます。

```python
   messagebox.askyesno(
       message="シートが出ます。",
       icon='question',
       title='ダイアログ',
       # parentに対し親ウインドウを指定するとシートで表示される。
       parent=root)
```
こんな感じ。

ファイルを開くダイアログ等でも同じです。

```python

from tkinter import filedialog

filename = filedialog.askopenfile(parent=root)
```

ちなみにWindowsでやった場合はどちらも動作的に違いがありませんでした。

以下OKダイアログが出るサンプルコードとなります。

```python
import tkinter
from tkinter import ttk, StringVar, W, messagebox

root = tkinter.Tk()
root.title('シートダイアログテスト')

# Frame as Widget Container
frame1 = ttk.Frame(
   root,
   padding=5)
frame1.grid()

# String
s = StringVar()
s.set('ダイアログテスト')

# Label 2
label2 = ttk.Label(
   frame1,
   textvariable=s,
   width=30,
   anchor=W,
   padding=(5,10))
label2.grid(row=1,column=2)

# Button 1
def button1_clicked():
   messagebox.askyesno(
   message="新規ウインドウになります。",
   icon='question',
   title='ダイアログ')

# Button 2
def button2_clicked():
   messagebox.askyesno(
   message="シートが出ます。",
   icon='question',
   title='ダイアログ',
   parent=root)


button1 = ttk.Button(
   frame1,
   text='ウインドウ',
   command=button1_clicked)
button1.grid(row=2,column=1)

button2 = ttk.Button(
   frame1,
   text='シート',
   command=button2_clicked)
button2.grid(row=2,column=2)

root.mainloop()
```
Visual Studio Code のデフォルトの文字コードを設定する

# 設定のFiles: Encodingで文字コードを設定する
例）デフォルトの文字コードをshiftjisにする場合
![VSCODE_DefaultEncoding.jpg](https://qiita-image-store.s3.amazonaws.com/0/202753/72038a5b-c198-7e86-3504-b12030217d91.jpeg)
UnityのProfilerDriverでよく使うものの紹介



#概要

UnityのProfilerの情報を取得したり設定したりするときに避けては通れないProfilerDriver。
ただUnityEditorInternalに入ってるだけにどこかに使い方がまとまってたりするわけではないので、軽くよく使う項目をまとめてみました。
だいたいのことはコードに入ってるので興味ある人は覗いてみてください

動作環境
Unity 2018.1.4f1

サンプルコードのリポジトリ
UnitySandbox/ProfilerDriverSample.cs
 https://github.com/KTA552/UnitySandbox/blob/develop/UnitySandbox/Assets/Scripts/Debug/ProfilerDriverSample.cs

![](https://raw.githubusercontent.com/KTA552/MediaUploader/master/img/UnityProfilerDriverSample.png)

#サンプルコード

```CSharp

            using (new EditorGUILayout.VerticalScope())
            {
                EditorGUILayout.Space();

                EditorGUI.BeginDisabledGroup(true);

                // Profilerで選択されている関数のパスを取得
                var selectPath = ProfilerDriver.selectedPropertyPath;
                if (selectPath == string.Empty) selectPath = "not selected.";

                EditorGUILayout.LabelField("selectedPropertyPath", selectPath);

                // Profilerで計測している開始と最後のフレーム数
                var firstFrame = ProfilerDriver.firstFrameIndex;
                var lastFrame = ProfilerDriver.lastFrameIndex;

                EditorGUILayout.IntField("firstFrameIndex", firstFrame);
                EditorGUILayout.IntField("lastFrameIndex", lastFrame);

                // 計測対象がEditorかどうか
                var isProfileEditor = ProfilerDriver.profileEditor;

                // DeepProfileをしているかどうか
                var isDeepProfile = ProfilerDriver.deepProfiling;

                EditorGUILayout.Toggle("profileEditor", isProfileEditor);
                EditorGUILayout.Toggle("deepProfiling", isDeepProfile);

                var connectedProfilerCount = ProfilerDriver.connectedProfiler;
                EditorGUILayout.IntField("connectedProfiler", connectedProfilerCount);

                EditorGUI.EndDisabledGroup();

                // Profilerの中の情報をクリア
                if (GUILayout.Button("ClearAllFrames"))
                {
                    ProfilerDriver.ClearAllFrames();
                }
            }



```
WindowsでNEologd辞書を比較的簡単に入れる方法ーユーザー辞書編

#はじめに
MeCabの形態素解析用の辞書のNEologd辞書を導入にWSL(Windows Subsystem for Linux)+Ubuntuを使っていたのですが、git for Windowsと7-zipで比較的簡単に導入できました。

2020/2/10追記
これはユーザー辞書編です。
ユーザー辞書でかなりの固有名詞が解析できるようになりますが、
システム辞書については以下のリンクをご覧ください。
https://qiita.com/zincjp/items/e491f1712a701ad91a4f

#環境
Windows10 64bit 言語：日本語
MeCab 0.996-32bit
#導入するもの
git for Windows 2.20.1 64-bit
7-Zip 18.06 64-bit 
#導入手順
##MeCabにPATHを通す
MeCabの実行ファイルのある以下のフォルダを環境変数を設定しPATHを通す。
C:\Program Files (x86)\MeCab\bin
##7-zipのインストールと環境変数への設定
###7-zipのインストール
ダウンロードしてきたNEologd辞書はxz形式で圧縮されているので、展開するために7-zipを使います。
以下のサイトより7-zip 64bitをダウンロードしインストール。
https://sevenzip.osdn.jp/
###7-zipにPATHを通す
以下を環境変数に設定
C:\Program Files\7-Zip
##git for Windowsのインストール
以下のサイトを参考にgit for Windows 64bitをインストールする
https://qiita.com/taiponrock/items/632c117220e57d555099
##NEologd辞書のダウンロードとコンパイル
###gitより辞書をダウンロード

管理者でコマンドプロンプト立ち上げ以下のコマンドで作業フォルダへ移動

```
cd %homepath%
```

続いて以下のコマンドでNEologd辞書をダウンロード

```
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
```
###NEologd辞書ファイルの確認
コマンドプロンプトより以下コマンドでC:\Users\(ユーザー名)\mecab-ipadic-neologd\seedに移動しファイルを確認。

```
cd mecab-ipadic-neologd\seed
dir
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/317756/2824039c-7353-ed38-7bde-cb7b3812b867.png)

###NEologd辞書ファイルの展開
これら.csv.xzファイルを以下のコマンドで7-zipで展開。

```
7z X *.xz
```
##辞書ファイルのコンパイル
###SHIFT-JIS辞書の作成
以下コマンドでSHIFT-JIS辞書(NEologd.日付.dic)を作成し、MeCabの辞書フォルダに移動する。
以下コマンド内NEologd.20190128.dicとmecab-user-dict-seed.20190128.csvの
"20190128"は辞書ファイルについている日付です。
ダウンロードしたものと合わせてください。

```
mecab-dict-index -d "c:\Program Files (x86)\MeCab\dic\ipadic" -u NEologd.20190128.dic -f utf-8 -t shift-jis mecab-user-dict-seed.20190128.csv

mkdir "C:\Program Files (x86)\MeCab\dic\NEologd"

move NEologd.20190128.dic "C:\Program Files (x86)\MeCab\dic\NEologd"
```
###mecabrcファイルの編集
mecabの辞書はC:\Program Files (x86)\MeCab\etcにあるmecabrcで指定できる。
以下の記述をmecabrcに記載し、NEologd辞書はユーザー辞書として設定します。
dicdir =  $(rcpath)\..\dic\ipadic
userdic = C:\Program Files (x86)\MeCab\dic\NEologd\Neologd.20190128.dic
###UTF-8辞書の作成
PythonではUTF-8の辞書が必要なので以下コマンドでUTF-8辞書(NEologd.日付-u.dic)を作成する。

```
mecab-dict-index -d "c:\Program Files (x86)\MeCab\dic\ipadic-UTF8" -u NEologd.20190128-u.dic -f utf-8 -t utf-8 mecab-user-dict-seed.20190128.csv

mkdir "C:\Program Files (x86)\MeCab\dic\NEologd"

move NEologd.20190128-u.dic "C:\Program Files (x86)\MeCab\dic\NEologd"
```
###mecabrcファイルの編集
UTF-8用のmecabrc-uファイルを作成し、以下の記載でNEologd辞書をユーザー辞書に設定します。
dicdir =  $(rcpath)\..\dic\ipadic-UTF8
userdic = C:\Program Files (x86)\MeCab\dic\NEologd\NEologd.20190128-u.dic
##解析の実行は以下サイトを参考に「欅坂46が赤いきつねを食べている。」等の文章で解析してみてくださいませ。
https://qiita.com/zincjp/items/55960801d99e55c9f2a6
#参考
NEologd辞書のURL

https://github.com/neologd/mecab-ipadic-neologd/blob/master/ChangeLog

#編集履歴
2020/02/11
パス名を表記を変更しました。編集前の表記でも問題ないですが最近のわかりやすさを優先しました。
（編集前）c:\PROGRA~2\MeCab\dic\ipadic
（編集後）"c:\Program Files (x86)\MeCab\dic\ipadic"
Unityの obstacle-tower-env の実行環境を準備する(Mac)

# はじめに

https://create.unity3d.com/obstacletower の Obstacle Tower の環境構築(Mac)メモです。

## 環境

- PC: MacBook Pro (Retina, 13-inch, Early 2015)
- OS: macOS Mojave(10.14.3)
- pipenv: version 2018.11.26
    - pipenv は `brew install pipenv` などでInstallできます。

Setup On Mac
============
https://github.com/Unity-Technologies/obstacle-tower-env を参考に準備していきます。

## ディレクトリとPythonの準備
ml-agents が python3.6のみのサポートなので、python3.6を使います。

```
mkdir obstacle_tower
cd obstacle_tower
pipenv --python 3.6
```

## Install Requirements
必要なライブラリをまとめてInstallしておきます。

```
pipenv install jupyter tensorflow gym Pillow
```

### Unity ML-Agents v0.6
GitHubから直接Install。

```
pipenv install 'git+https://github.com/Unity-Technologies/ml-agents.git#egg=ml-agents&subdirectory=ml-agents'
```

## Install Environments
### obstacletower_v1_osx
UnityアプリのOSX用をDownloadして unzipします。

```
curl -LO https://storage.googleapis.com/obstacle-tower-build/v1/obstacletower_v1_osx.zip
unzip obstacletower_v1_osx.zip
rm obstacletower_v1_osx.zip
```

## Clone & Install obstacle-tower-env
ここの notebookは後でOpenしたいので、一旦LocalにCloneしてから install します。

```
git clone git@github.com:Unity-Technologies/obstacle-tower-env.git
pipenv install -e obstacle-tower-env
```

## 現在のDir構成
ここまでの手順で、以下のようなDir構成になります。

```
% tree -L 2
.
├── Pipfile
├── Pipfile.lock
├── obstacle-tower-env
│   ├── LICENSE
│   ├── README.md
│   ├── banner.png
│   ├── examples
│   ├── obstacle_tower_env.egg-info
│   ├── obstacle_tower_env.py
│   └── setup.py
└── obstacletower.app
    └── Contents
```

# Getting Startを実行する
`obstacle-tower-env/examples/basic_usage.ipynb` を使って環境がSetupできているか確認ができます。

----

まず、jupyterを起動します。
`obstacletower.app` の PATH をnotebook中で指定する必要があるので、 `PRJ_ROOT` という環境変数に現在のDirのPATHをセットしておきます。
※ 例では、`obstacle-tower-env/examples/ObstacleTower` に展開しておけとなっているけど、後々使うことを考えるとそこに配置したくはないので。

```
PRJ_ROOT=$(pwd) pipenv run jupyter-notebook
```

ブラウザが立ち上がると思うので、 `obstacle-tower-env/examples/basic_usage.ipynb`  を開きます。

------
`obstacletower.app` の PATHを指定する部分を書き換えます。

```
env = ObstacleTowerEnv('./ObstacleTower/obstacletower', retro=False)
```

↓

```
import os
env = ObstacleTowerEnv(f'{os.environ["PRJ_ROOT"]}/obstacletower', retro=False)
```

という感じで。

あとは、そのまま実行していけば、動くと思います。
全体的には [こんな感じ](https://github.com/Unity-Technologies/obstacle-tower-env/blob/master/examples/basic_usage.ipynb) になります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11124/707f16d8-25b8-1d81-91d5-5862352610ca.png)

さいごに
======

Linux上にHeadlessでSetupしたかったのですが、xvfbだとopenglが動かないとかなんとかで一筋縄にはいかなかったです。
[このドキュメント](https://github.com/Unity-Technologies/ml-agents/blob/master/docs/Training-on-Amazon-Web-Service.md) によると、AWS上でも動くはずなので、頑張ればできるとは思うのですが、、、1日くらいかかりそうな予感がするので、まずは簡単な環境から...
当番表作りを自動化してみた

PTA活動などでいろんな当番表を作ったりしますが、これが地味に時間がかかるんですよね。この曜日はNG、この日は予定があるなど、それぞれに都合がありますからね。

そんなのをお助けするプログラムをちょこっと作ってみました。

# 当番表とは
どんな条件なのかなと整理してみます。

+ 名簿がある
+ 日程が決まっている
+ 人数が決まっている
+ 公平性が求められる
+ 人によって都合がある

# ということでプログラムを作ってみます

```perl:make_shift.pl
#!/bin/perl

use strict;

# 名簿
my @baselist = (
  '山田',
  '鈴木',
  '佐藤',
  '高橋',
  '伊藤',
  '小林',
  '渡辺',
  '中村',
  '山口'
);

# NG条件（正規表現）
my %ng = (
  '山田' => '\(月\)',
  '渡辺'=> '\(月\)',
  '小林'=> '2月14日',
  '中村'=> '2月4日',
);

# 回数上限
my %limit = (
  '伊藤' => 4,
  '小林' => 4,
);

# 日付リスト
my @dt = (
  '1月31日(木)',
  '2月4日(月)',
  '2月7日(木)',
  '2月12日(火)',
  '2月14日(木)',
  '2月18日(月)',
  '2月21日(木)',
  '2月25日(月)',
  '2月28日(木)',
  '3月4日(月)'
);

# 同じ日に必要な人数
my $num_per_day = 4;

# 順番割り当てリストの初期化（開始位置はランダム）
my $i = int(rand($#baselist + 1));
my @list = ();
while ($#list < ($#dt + 1) * ($num_per_day + 1)){
  push(@list, $baselist[$i]);
  $i++;
  if ($i > $#baselist){
    $i = 0;
  }
}

# 結果データの初期化
my %check = ();
my %result = ();
my %ct = ();
foreach my $d (@dt){
  $check{$d} = {};
  $result{$d} = [];
}

# 初期値のセット
push (@{$result{'1月31日(木)'}},'小林','高橋','山田','山口');
push (@{$result{'2月4日(月)'}},'伊藤','鈴木','佐藤','小林');

# 事前にセットした名前を削除
foreach my $name (@baselist){
  $ct{$name} = 0;
}

# 初期値分をカウント＆リストからその分除去
foreach my $d (@dt){
  foreach my $name (@{$result{$d}}){
    $ct{$name}++;
    $i = 0;
    while ($list[$i] ne $name){
      $i++;
      last if ($i >= $#list);
    }
    splice(@list, $i, 1);
  }
}

# 当番表のセット
foreach my $j (1..$num_per_day){
  foreach my $d (@dt){
    my $ct = $#{$result{$d}};
    next if ($ct >= $num_per_day - 1);
    my $i = 0;
    my $name = $list[$i];
    while (check_ng($d, $name)){
      $i++;
      $name = $list[$i];
    }
    splice(@list, $i, 1);
    $check{$d}{$name} = 1;
    push (@{$result{$d}}, $name);
    $ct{$name}++;
  }
}

# 結果の出力
print "結果リスト\n";
foreach my $d(@dt){
  print join("\t",$d,@{$result{$d}}) . "\n";
}

print "回数チェック\n";
foreach my $name(@baselist){
  print "$name\t$ct{$name}\n";
}

print "結果リスト（日付抜き）\n";
foreach my $d(@dt){
  print join("\t",@{$result{$d}}) . "\n";
}

sub check_ng($$){
  my $d = shift;
  my $name = shift;
  return 1 if (exists $check{$d}{$name});
  if (exists $ng{$name}){
    my $ng = $ng{$name};
    if ($d =~ /$ng/){
      return 1;
    }
  }
  if (exists $limit{$name}){
    my $limit = $limit{$name};
    if ($ct{$name} >= $limit){
      return 1;
    }
  }
  
  return 0;
}
```

出力結果は以下の通りです。

```text:結果.txt
結果リスト
1月31日(木)	小林	高橋	山田	山口
2月4日(月)	伊藤	鈴木	佐藤	小林
2月7日(木)	渡辺	山田	山口	鈴木
2月12日(火)	中村	鈴木	渡辺	山口
2月14日(木)	佐藤	高橋	山田	渡辺
2月18日(月)	高橋	佐藤	伊藤	中村
2月21日(木)	伊藤	小林	佐藤	山田
2月25日(月)	中村	伊藤	高橋	佐藤
2月28日(木)	渡辺	中村	小林	高橋
3月4日(月)	山口	鈴木	中村	佐藤
回数チェック
山田	4
鈴木	4
佐藤	6
高橋	5
伊藤	4
小林	4
渡辺	4
中村	5
山口	4
結果リスト（日付抜き）
小林	高橋	山田	山口
伊藤	鈴木	佐藤	小林
渡辺	山田	山口	鈴木
中村	鈴木	渡辺	山口
佐藤	高橋	山田	渡辺
高橋	佐藤	伊藤	中村
伊藤	小林	佐藤	山田
中村	伊藤	高橋	佐藤
渡辺	中村	小林	高橋
山口	鈴木	中村	佐藤
```

# 最後に
今回は、とある役の仕事で必要になって作りましたけど、きっと困ってる方は結構いらっしゃるんだろうなと思ってます。
気が向いたら、Webで簡単に当番表を作れるツールを作りますね。
【Inkscape】線をアウトライン化にする


<font color="Magenta">Illustratorでアウトライン化するように
Inkscapeにも、同様の機能がありましたので、メモ書きします。</font>

環境メモ
⭐️Mac OS Mojave バージョン10.14
⭐️Inkscape 0.92
⭐️Xcode10.1
⭐️Mac book

1.ペンツールで描いた線
<img width="1141" alt="スクリーンショット 2019-02-02 9.55.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/ed09c352-9741-05a0-ebdb-9f38984dcf28.png">

2.「パス」ー「ストロークをパスに変換」を選択すればOK
<img width="645" alt="スクリーンショット 2019-02-02 9.56.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/ae53c6cf-b645-f694-e9b9-db993127e9ba.png">

<img width="805" alt="スクリーンショット 2019-02-02 9.57.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/33d52fa5-5a42-8972-cc79-c6749852cd36.png">

ちなみに、文字をアウトライン化にするのは
「パス」ー「オブジェクトをパスへ」を選択すればOK
<img width="414" alt="スクリーンショット 2019-02-02 10.38.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/e53ee618-79ad-100b-0023-390d46a2e82a.png">
DVD-RへISOイメージの書き込み

起動ディスクをつくろうとして、**.isoファイルをディスクにそのままコピーしても起動できない。**
書き込みソフトを使う、またはWindows7以上なら
**.isoファイルを右クリック**->**[ディスクイメージの書き込み]**
で対象ディスクに書き込む。

参考：
[ISOイメージファイルの焼き方、ISO形式のCD・DVDの作り方](https://memorva.jp/internet/pc/iso_cd_dvd.php)
『Team Geek』を読んでみて

[Team Geek――Googleのギークたちはいかにしてチームを作るのか](https://www.oreilly.co.jp/books/9784873116303/)
を読んでみたので、感想と心に残った箇所を書き留めておく。

※内容をまとめたものはこれが参考になる
https://qiita.com/corin8823/items/1d73a5040d646d0fffb8

# 全体的な感想

主に文化面でどんなことを大事にしてるか、いろいろな考え方が書いてあって参考になった。

ミッションステートメントを明確にしてチームの文化を作り、またメンバの入れ替わりもある中で、どうやって維持していくのか。

時には「有害なもの」の排除は必要だけど、「人」ではなくあくまで「振る舞い」を排除しようとすることが大事なんだなってのが印象深かった。『コードを憎んで、人を憎まず』に似てる気がする。

その裏には、本の中で繰り返し出てくる「HRT : 謙虚、尊敬、信頼」の考え方があって、一番強調されていた部分。

# 日本語版まえがき

本書とは直接関係ないけど、本書の中で強調されていたひとつの「ミッションステートメント」について、Chromeの例が紹介されていた印象的だった。

> 私の関わっているChromeというブラウザにおいても、ミッションステートメントとして、Speed, Security, Stability, Simplicityが定められている。

大事にしていることがすごい明確で、しかもその中にSimplicityが入ってるのがすごい好感が持てる。「美はシンプルさに宿る」という、別の本に書かれていた言葉を思い出した。

> これ(ミッションステートメント)に合致しない機能は完成が近いものであっても、すべて製品から取り除いた。足すものよりも引くものの方が多かったほどである。

めっちゃいい。特に長年続いてるサービスだと、いろんなものが捨てられなくて複雑さが増していろんな弊害が出てくる。選択と集中のためにもミッションステートメントって大事なんだなって感じた。

# 第１章:天才プログラマの神話

> 検証を重視した「早い段階で、高速に、なんども失敗せよ」の精神を忘れないようにしよう。

結構最終的な答えって分からないし、最初に考えてたものと違う場合がほとんど。だから、早めに切り上げて前に進んで、間違いに気づいたら柔軟にすぐ修正できる方がいいな。

> ソフトウェア開発はチームスポーツである。

チームで開発するってのは当たり前のことと思ってたけど、「チームスポーツ」って例えは意外と新鮮だった。

> チーム開発の3本柱→謙虚、尊敬、信頼

HRT。これがこの本の一番伝えたいこと。リーダーはもちろん、全員が大事にしなきゃいけないこと。

# 第２章:素晴らしいチーム文化を作る

> エンジニアはコミニュケーションを出来るだけ排除して、コードを書かなければいけないと考えている。しかし、チームが合意していなかったり、情報が伝わっていなかったりすると、君が正しいコードを書いているという保証はない。

いくつか具体的な事例が身近でもあるなぁと思う。出来上がるまで共有しないで、最後に全然前提が違うじゃん！みたいなのってママある。一言聞けば解決することはごまんとある。サクッと聞くのもいいし、ペアワークとかで潰すのも効果的そう。

# 第３章:船にはキャプテンが必要

> すると彼女は、子供たちは植物のようだと答えた。‥6人の子供たちに同じ水、日光、肥料を与えていたら、平等かもしれないが、誰一人として、本当に必要なものが手に入らない可能性が高い。エンジニアも植物みたいなものだ。日光を必要とする人もいれば、水を必要とする人もいる。

リーダーは、メンバがそれぞれ何を必要としているかを見極めて、それぞれに合わせた接し方をしなければいけないということ。そのために日々の1on1がある。面白い比喩だな。

> エンジニアのスキルは、ナイフの刃のようなものだ。刃を研がずに何年もナイフを「使っていれば」、いずれ切れないナイフになってしまう。新しいことを学んだり、技を身につけたりする機会を作ることが、エンジニアを鋭くて、効率的で、効果的にさせるのだ。

シニアっぽい立場でチームにいると、割と心地よくて、気をつけてないと切れないナイフになってしまいそう。自戒の意味も込めて。

# 第４章:有害な人に対処する

> 普通の人たちを排除するようなエリート指向のフラタニティではなく、ネガティブな振る舞いを拒否するような文化を作る方が健全だ。排除するのはあくまでも振る舞いであり、特定の個人ではない。

えてして、「人」に着目しがちだけど、「振る舞い」自体を排除しようとして、それでもダメなら最後の手段として、「人」の排除を検討する。チームを守るためにはそれも大事。

# 第５章:組織的操作の技法

この章はだいぶ、斜め読みしちゃったな。

# 第６章:ユーザーも人間

> 優れた設計は簡単なものを簡単に、難しいものをできるだけ簡単にする。複雑なことであっても、簡単なことをしているように感じられるようにするべきだ。

簡単なものを難しく書いちゃうって意外とある。複雑なコード読んで、結局やりたいことって、〇〇と△△だけじゃん！みたいな。で、後半の複雑なことを簡単なことしているように見せることができるようになりたい。カプセル化と抽象化をうまく使うのかな。
2パターンの1ヶ月後の日付を求める方法。

## はじめに
PHPで日付の計算をしていて、1ヶ月後や2ヶ月後の日付を求めたいというケースはよくあります。

2019年1月28日の1ヶ月後が2019年2月28日であることに異論がある人はいないはずです。
ただ、2019年1月29日の1ヶ月後として2019年3月1日という値が欲しい場合と2018年2月28日という値が欲しい場合の2つがあると考えられます。

今回はこの両者を求める方法を備忘として残して置こうと思います。


## 前者を求める方法
2019年1月29日の1ヶ月後が2019年3月1日である場合です。
こちらは単純でPHPの標準関数の`strtotime`の第１引数に`+1 month`のように相対書式を渡してあげれば求めることができます。[^1]

```PHP
strtotime('+1 month');
```
[^1]: http://php.net/manual/ja/function.strtotime.php


## 後者を求める方法
2019年1月29日の1ヶ月後が2019年2月28日である場合です。

まずはいきなりソースから。

```PHP
function addMonths( $date, $add_months ){
		//◯ヶ月後の末日
		$lastDay = strtotime("last day of +".$add_months." month", $date);

		//◯ヶ月後
		$day = strtotime("+".$add_months." month", $date);

		if ( $day < $lastDay ){
			return $day;
		}else {
			return $lastDay;
		}
}
```


分かりやすいように下に具体例を表で表しました。
基本的には、1ヶ月後の日付より1ヶ月の末日の方が大きいです。
ただ、当該の日付がない場合は、一ヶ月後の日付の方が大きくなります。
　それぞれのケースで欲しい値が異なるので、ifで◯ヶ月後の末日と◯ヶ月後の日付（前者のパターン）を比較してどちらを返すかを決めています。

|  | 1ヶ月後の日付 | 1ヶ月の末日 |
|:--|:--|:--|
| 2018-10-20 | 2018-11-20（正解） | 2018-11-30 |
| 2019-01-29 | 2019-03-01 | 2019-02-28（正解） |

## 余談
`strtotime("last day of +1 month")`とすると、内部的には以下の順で処理されているみたいです。

1. 1月29日の1ヶ月後は2月29日　←+1 month
2. 2月の末日は2月28日← last day of

1の段階では3月1日に変換されないみたいですね。
【Inkscape】MacにInkscapeをインストールする

環境メモ
⭐️Mac OS Mojave バージョン10.14
⭐️Inkscape 0.92
⭐️Xcode10.1
⭐️Mac book

<font color="Magenta">MacにInkscapeをインストールする
2019/02/02時点</font>

1.Inkscape　をダウンロードする
2019/02/02時点でのMac版最新バージョンは【0.92】
https://inkscape.org/release/0.92.2/mac-os-x/

<img width="1104" alt="スクリーンショット 2019-02-02 7.42.58.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/ab027137-b8f9-1057-2be0-ce76f375f740.png">


２.Quartz をダウンロードする（Macは、Quartzが必要）
https://www.xquartz.org/
<img width="1248" alt="スクリーンショット 2019-02-02 7.44.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/8d925365-b644-bb4b-df1d-556879c06057.png">


3.先に、Quartz　をインストールする
<img width="619" alt="スクリーンショット 2019-02-02 7.48.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/6cae9a59-896c-2d05-5596-fe845b029bfb.png">

4.Inkscapeをインストールする（アプリケーションの中にDrag＆Dropで入れる）
<img width="587" alt="スクリーンショット 2019-02-02 7.50.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/0f4bf97c-d740-87db-d301-d672700f712c.png">

5.パソコンを再起動する

6.Inkscapeを起動する際、初回起動は、「アプリケーション」からInkscapeを選択して右クリック「開く」から起動する

<img width="539" alt="スクリーンショット 2019-02-02 7.54.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/5321db9b-42d1-f4ef-ff9d-d2f6a1accdc9.png">
<img width="601" alt="スクリーンショット 2019-02-02 7.55.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/101a726a-6053-c0a3-ede0-2b0b6221a159.png">


7.Inkscapeの開発元は未確認です。開いてもよろしいですか？
ダイアログが出るので「開く」を選択する
<img width="417" alt="スクリーンショット 2019-02-02 7.55.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/e0a316fd-02ba-bf55-755d-35624a966ba1.png">

これで、Inkscapeが起動する！！

</br>
</br>
Inkscapeで書いたキャラクター↓↓↓↓
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">💎WebAR💎<br>Inkscapeで書いた絵を🎊png🎊出力して表示してみたよぉ。<br>ARマーカーに近づけたり、遠ざけたりしてみたよぉ🤩<a href="https://twitter.com/hashtag/WebAR?src=hash&amp;ref_src=twsrc%5Etfw">#WebAR</a> <a href="https://twitter.com/hashtag/XRMTG?src=hash&amp;ref_src=twsrc%5Etfw">#XRMTG</a> <a href="https://twitter.com/hashtag/XRMTG?src=hash&amp;ref_src=twsrc%5Etfw">#XRMTG</a> <a href="https://t.co/8GMhhy6Ths">pic.twitter.com/8GMhhy6Ths</a></p>&mdash; non (@nonnonkapibara) <a href="https://twitter.com/nonnonkapibara/status/1110180591343812608?ref_src=twsrc%5Etfw">2019年3月25日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>