OmniAICreator/Qiita-1.07M huggingface dataset:
【Python】圧縮されたS3オブジェクトをローカルに保存せず読み込む

S3に保存されたgzip/zip圧縮ファイルを、ローカルファイルとして保存することなく読み込みたい。

# 前提条件

- Python: 3.7.4
- AWS SDK: boto3-1.9.230以上

# ポイント

- 標準の`gzip`, `zipfile`パッケージを使ってファイルを読み込んでファイルオブジェクトに変換する。<br>

（bzip2とかは考えなくて良いんじゃないかな）

つまり、以下のようにして読み込んだ際と同様に扱いたい。

```python
import gzip
gz_file = 'path/to/file.csv.gz'
file = gzip.open(gz_file, 'rt')

file.read()
..
```

パッケージ毎にファイルオブジェクトの変換方法に癖があるので、それぞれ対応する。
`io`パッケージの`BytesIO`やら`TextIOWrapper`を使う。
ついでに、圧縮形式も正しいかチェックする。

# コード

## gzip圧縮の場合

```python
import boto3
import gzip
import io


# 圧縮形式が正しいかチェック
def valid_gzip_format(obj):
    file = gzip.open(io.BytesIO(obj), 'rt')
    try:
        file.read()
        return True
    except OSError:
        return False


s3 = boto3.client('s3')
bucket = 'bucket_name'
key = 'path/to/file.csv.gz'
# S3オブジェクトの取得
obj = s3.get_object(
    Bucket=bucket,
    Key=key
)['Body'].read()

# main
if valid_gzip_format(obj):
    file = gzip.open(io.BytesIO(obj), 'rt')
else:
    raise InvalidCompressError('ファイル拡張子(.gz)に対して圧縮形式が正しくありません。')

# 中身確認
for row in file.readlines():
    print(row.replace('\n', ''))
```

## zip圧縮の場合

```python
import boto3
import io
import zipfile


# 圧縮形式が正しいかチェック
def valid_zip_format(obj):
    return zipfile.is_zipfile(io.BytesIO(obj))


s3 = boto3.client('s3')
bucket = 'bucket_name'
key = 'path/to/file.csv.zip'
# S3オブジェクトの取得
obj = s3.get_object(
    Bucket=bucket,
    Key=key
)['Body'].read()

# main
if valid_zip_format(obj):
    zf = zipfile.ZipFile(io.BytesIO(obj))
    if len(zf.namelist()) > 1:
        raise InvalidCompressError('zipアーカイブの中にファイルが複数あります。')
    file = io.TextIOWrapper(zf.open(zf.namelist()[0], 'r'))
else:
    raise InvalidCompressError('ファイル拡張子(.zip)に対して圧縮形式が正しくありません。')

# 中身確認
for row in file.readlines():
    print(row.replace('\n', ''))
```

`zipfile`ではopenのモードに`'rt'`が無いので`TextIOWrapper`を使う必要がある。
参考 - [ZIP アーカイブの処理 &#8212; Python 3.7.5rc1 ドキュメント](https://docs.python.org/ja/3/library/zipfile.html#zipfile.ZipFile.open)
> バージョン 3.6 で変更: Removed support of mode='U'. Use io.TextIOWrapper for reading compressed text files in universal newlines mode.

# まとめ

上記のコードで取得したS3オブジェクトは`bytes`型で保持されるだけなので、`with`構文で扱う必要はないと思う（合ってる？）。
あと実際に中身を読み込む際に、末尾に改行コードが含まれるのでそのあたりも考慮が必要（もろちん、バイナリモードでも含まれるけど）。
GOLANGを勉強しはじめた

おひさしぶり　皆、

先週からGOLANGを勉強しはじめました。

[UDEMY](http://udemy.com) 　で　コースを　買って、毎日　１　ヴィデオ　見ていった。

今週で、３回　ホームページのデザイン　はじめた。

NUXT.JS とTAILWINDCSSを　けいかくしています。

少し　NODE.JS　わかります、

来週も、GOLANGビデオを見続けます,

コード例をとこしてみます。



またね.
【adb logcat】windows+javascriptのandroid開発でconsole.logのログ出力をフィルタする方法

# 解決したいこと
windows 環境でjavascript を使ってandroid アプリを開発しているとき、console.log の出力を確認したかった。
具体的には、cordova を使って開発していた。
デバック方法としては、chrome を使うやり方もあるが`adb`を使ったほうがアプリを再起動しても常に監視できるので楽。

```
$ adb logcat | grep CONSOLE
```

調べるとLinux環境では上記のように`grep hoge`を使ってフィルタしてあげれば`hoge`が含まれる文章だけが表示される
でもwindowsでは`grep`は使えない...
# 解決方法
```
$ adb logcat -s chromium:I
```
logcat に関する公式の説明を見ると、普通にコマンドからフィルタできた。
上記のコマンドは実際にcordova の`console.log`をフィルタしたい場合の指定の仕方。
フィルタに関する説明は、

  * https://developer.android.com/studio/command-line/logcat
    
の**「ログ出力をフィルタリングする」**から見ることができる。

指定の仕方だが、まずフィルタをかけずに`logcat`してフィルタしたい目的の`console.log`を見つける。

```
$ adb logcat
>  I/ActivityManager(  585): Starting activity: Intent { action=android.intent.action...}
```
`I`,`ActivityManager`は任意に変わっているはずなので、それを確認して

```
$ adb logcat -s ActivityManager:I
```

とすれば目的の`console.log`だけ出力される

# 参考サイト

* https://maku77.github.io/android/filter-logcat.html
任意の周波数特性を持ったFIRフィルタの設計

# はじめに
マイクで収録した音にFIRフィルタで周波数補正をかけたくなりました。FIRフィルタというとscipy.signal.firwinなどがありますが、今回は単純なローパスフィルタやハイパスフィルタではなく、複雑な周波数特性の実現を目指します。私はFIRフィルタの理論を深く理解しているわけではないので、間違っている箇所があると思います。そのときはコメントで教えていただけるとありがたいです。

# 参考
東北大学講義資料の以下を参考にさせていただきました。
[やる夫で学ぶディジタル信号処理](http://www.ic.is.tohoku.ac.jp/~swk/lecture/yaruodsp/main.html)

# 手順
ファイル読み込みなどのコードは省略しました。
## 1. マイク付属の周波数特性表の読み込み
これはとあるマイクの周波数特性と自由音場補正データです。
![通常補間.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/92f49a22-8356-971d-3e4a-7f49eff14bbd.png)

補正すべき値は以下のようになります。
![response.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/71230ad5-a1a7-c123-5bd0-080f72b6790a.png)


## 2. 実現したい周波数特性をつくる
ここで、補正値は対数から線形になおしておきます。
このマイクは140 kHzまでが計測可能範囲なので、それより高い周波数ではゲインを0にします。

```python
N = 128 #タップ数 + 1
fs = 500.0e3 #補正をかけたいデータのサンプリングレート
freq_array = np.linspace(0.0, fs, num=N)

gain_correction = np.zeros(N//2)
lim_freq = freq_array[freq_array <= 140.0e3]
# f_pro_funcとf_pro2_funcはスプライン補間テーブル
gain_correction[0:len(lim_freq)] = 10**(-(f_pro_func(lim_freq) + f_pro2_func(lim_freq))/20.0)
gain_correction = list(gain_correction) + list(gain_correction[::-1]) #反転して合わせる

fig, axes = plt.subplots(figsize=(8,4))
axes.plot(freq_array/1000.0, gain_correction)
axes.set_xlabel("Frequency kHz")
axes.set_ylabel("Relative response")
axes.set_ylim(-0.1, 1.1)
```
![mic_response_linier.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/1dec135b-6ea9-90ee-d9e1-a19e7bfd952d.png)

## 3. FIRフィルタの係数を計算する
波形データにフィルタ係数を畳み込み計算した結果は、それぞれのデータのフーリエ変換の積になります。フィルタ係数のフーリエ変換は、実現したい周波数特性そのものです。従って、先程の周波数特性を逆フーリエ変換すればフィルタの係数が求まります。また、FIRフィルタの係数は左右対称になります。

```python
b = list(np.real(np.fft.ifft(gain_correction)))[0:N//2]
b = b[::-1] + b[1:]
b = b * np.hamming(N-1)
b /= np.sum(b) # 係数の和を1にする
```

![fir.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/134c14b4-9696-6bac-baf8-3a0065972bd8.png)

フィルタ係数をフーリエ変換してみます。
![response1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/68f9a9b5-3f3a-8525-79c8-570735c7e728.png)

## 4. FIRフィルタの適用
計算したFIRフィルタをホワイトノイズに適用して、適用された波形のスペクトルを確認してみます。

```python
NN = 8192
ave_num = 1000
y = np.random.rand(NN*ave_num) # ホワイトノイズ
yy = signal.lfilter(b, 1, y) # FIRフィルタを適用した信号

fft_sum_w = np.zeros(NN)
fft_sum_f = np.zeros(NN)
for i in range(ave_num):
    fft_sum_w += np.abs(np.fft.fft(y[NN*i:NN*(i+1)]) / NN)
    fft_sum_f += np.abs(np.fft.fft(yy[NN*i:NN*(i+1)]) / NN)
fft_ave_w = 20.0 * np.log10(fft_sum_w / ave_num)
fft_ave_f = 20.0 * np.log10(fft_sum_f / ave_num)

fig, axes = plt.subplots(figsize=(8,4))
axes.plot(np.linspace(0.0, 500.0, num=NN), fft_ave_w)
axes.plot(np.linspace(0.0, 500.0, num=NN), fft_ave_f)
axes.set_xlim(1.0, 250.0)
axes.set_ylim(-50.0-15, -50.0)
axes.set_xscale("log")
axes.set_xlabel("Frequency kHz")
axes.set_ylabel("Amplitude dB")
```
ちゃんと実現したかった周波数特性になっています。
![whitenoise.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/4e1775de-a212-c66e-be0b-042fda1cc5d8.png)

# まとめ
実現したい周波数特性からFIRフィルタの係数を計算し、波形に適用しました。
今後はリアルタイム信号処理にも挑戦してみたいです。
モダンなアプリケーションロギングについて

# ログは何に使うのか詳細に
○: デバッグ、トラブルシューティング(事後)
△: 予見: 検知 -> 主にメトリクスの役割

デバッグやトラブルシューティングに使える情報を出しましょう！
SRE本によると、Googleは常にサーバのデバッグログ全開らしい。

UT時にもデバッグに使える。
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Underutilized testing strategy: test your log output. This forces you to do several things you should be doing anyway:<br><br>- Loggers are dependencies, not globals<br>- Routable log output (to in-mem buffers)<br>- Well-defined log schemas (structured logging)<br>- Deterministic components</p>&mdash; ✕✕✕✕✕ (@peterbourgon) <a href="https://twitter.com/peterbourgon/status/1151886045861928961?ref_src=twsrc%5Etfw">July 18, 2019</a></blockquote>


## メトリクスとの違い
* 出力物の大きさ
* 頻度。メトリクスは統計なので比較すると少ない。

ログは常時出力されます。ログ内で統計取ると負荷が厳しいことに

# ログに必要な項目
## コンテキスト重要
なるべくそのログ1つだけ見れば理解できるように。
ログを突き合わせるのではなく、完結させる。
L7レベルで出そう。sentryが参考になります
コンテキストを付与すれば付与するほど後で属性ごとに分析集計しやすくなります。
high cardinalityな項目が一番です。

なんとなく分解してみる。
Who: e.g. ユーザーID, UA, 会社名
Where: どのエンドポイント、どのボタン(ユーザー行動)、どのメソッド、スレッド名
Why: スタックトレース。
What: どの外部リソース/3rd party tool , バージョン(API, アプリ),コミットID 
When: 時間。JST/UTCわかるように。そもそもどのタイミングでの時間か
How:  リクエストパラメータ, featureフラグ(あれば), **trace id** 、(いわゆる)ログレベル。PCの状況(とれれば)

### tips
多くの言語でスレッド名を動的につけることができる。
デフォルトだとよくわからないのでデバッグしやすい名前にするとよい。
AWSインスタンス名あたりは集約サーバ側で付与することもできる。

どういうときに出すか-> サービスやDBの呼び出しといった外部接続部分がわかりやすい


# 形式
構造化ログであること。だいたいJSON

## メリット
- 項目が可変にできる。csvからjsonへ。並び替え自由、追加も自由、試してみて不要なら削除可能
- 例外のバックトレースなど複数行にまたがるものも対応できる
- 解析しやすい。grepからクエリ言語へ
- どうせログフォワーダーや集約基盤では構造化される

項目名は長くなっても良いので注釈無しで理解できるように、
単位やウィンドウを記載しましょう。

# 閲覧&可視化方法
閲覧方法まで揃って初めて役に立ちます。
ログ基盤に集約しましょう。

例
- グラフ化
- アドホック検索
- パターン分析
- またがった検索(join)
- ドリルダウン
- ブックマーク
- ライブログ(tail)


などなど。
開発環境やローカルのログも投入できると開発効率が上がります。

# ツールの制約
ログ基盤は大量データを扱うことになるので原理上お値段がそこそこかかります。


# 似てるけど違うもの
##行動ログ

用途が違うので閲覧方法を分けたほうが良いです。

##閲覧とアーカイブ
アーカイブ要件と閲覧用件は異なります。
法対応で数年間の保存が義務付けられているなら、例えばS3のコールドストレージに仕舞って放置しましょう。3年分のelasticsearchはそれだけで技術的な挑戦です

# 注意事項
- 個人情報はログ出力の段階でマスクしましょう
- 非同期で出力しましょう
- stringの扱いに注意しましょう。string結合のタイミングでパフォーマンス劣化もありえる
- Observabilityの項目のうちロギングは比較的侵襲的な操作です。ログで障害を起こさないように！

# Q&A
## 構造化ログだとパフォーマンスやサイズが気になります。
伝統的なログはログファイルに書き出していたので、
I/Oの負荷やローテーションの問題がありました。
Twelve-Factor Appにあるとおり、STDOUTに出すべきでしょう。
そしてログ基盤にネットワーク転送する。
そうすればパフォーマンス問題が少なくなります。

サイズもログ基盤側で圧縮されるので非構造化に比べてそこまで気にしなくて良いです。

## Sentryとの使い分けは？
- フロントJSエラーを拾う
 (※とはいってもnewrelicは既に対応済み。datadogは直近で対応予定)
- エラーログのチケット管理に使う
- より詳細なエラーのコンテキスト確認(それがsentryの売り)

あたりでしょうか。

# 参考資料
日本語ではいいものがあまりないです
<iframe src="//www.slideshare.net/slideshow/embed_code/key/KdrChVysxlForc" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/KunihikoIkeyama/datadog-technical-overview" title="Datadog Technical Overview （日本語）" target="_blank">Datadog Technical Overview （日本語）</a> </strong> from <strong><a href="https://www.slideshare.net/KunihikoIkeyama" target="_blank">Kunihiko Ikeyama</a></strong> </div>

[Observabilityマニフェスト](https://www.honeycomb.io/blog/observability-a-manifesto/)
コマンドでherokuに無料でMysqlをたてる

ひょんなことからherokuにmysqlを立てたいと思ったのでそのときのメモです。

すでにアカウントとアプリが作られている前提です。

## ログイン

```
heroku login
```


## 自身の保持しているアプリ一覧をだす

```
heroku list
```

一覧がでてくるのでここでmysqlを導入したいアプリの名前をだしておくとコピペが楽ってだけです。

## Mysqlを追加する

ここからが本番です。

```
heroku addons:create cleardb:<プラン名> --app <アプリ名>
```

`cleardb`というのがherokuでmysqlを使うためのアドオンになります。
※cleardbというクラウド上でMysqlを使うためのサービスがあってそれをherokuから使う形になります。

プラン名は`ignite`を使っておけばタダです。

詳しいプランについては以下
https://elements.heroku.com/addons/cleardb

結果的にはこんなコマンドになります。

```
heroku addons:create cleardb:ignite --app my-super-app
```


## ClearDBのコンフィグを取得

```
heroku config --app <アプリ名> | grep CLEARDB
CLEARDB_DATABASE_URL: mysql://ユーザ名:パスワード@ホスト名/DB名?reconnect=true
```

という出力がされるのでメモっておきます。

## 自身のアプリの環境変数に上記コンフィグを設定

```
heroku config:set --app <アプリ名> DATABASE_URL='mysql://ユーザ名:パスワード@ホスト名/DB名?reconnect=true
```

## ブラウザから確認

```
heroku addons:open cleardb
```
を叩くと立てたDBをブラウザから確認できるっぽいです。
なかなかイケてるUIで感動しました。


Pythonといったプログラムからはもちろん、MacであればSequel Proなどからもつなげるのでお試しください。

幸せいっぱいですね。
WordPressを静的化するメリット・デメリット

## メリット
### 定期的なアップデートやバージョン管理をしなくていい
WordPressには様々なプラグインを追加できますが、追加した分だけそれらプラグインのバージョン管理を行わなければいけません。
本体のバージョンを上げると動かなくなるプラグインが出てくる可能性があるからです。
静的化しない場合これの管理を誰がするのか？誰かに依頼するとしてもその分のコストが発生してしまいます。

静的化するだけでこれだけの面倒がなくなります。

### 表示速度が速い
WordPressは動的サイトなので、アクセスされる度にページを生成します。
しかし静的化することで、すでに生成されているページを表示するだけになるので圧倒的に早いです。

1~2秒待たされるだけでもユーザーは気になってしまいます。
サイトを見てくれる人のストレスを第一に考えるのであれば、静的化した方が良いでしょう。

### 大量のアクセスにも耐えられる
よく、アクセスが急増してサーバーがダウンした！なんて話聞きませんか？
静的化することで、アクセスの集中によるサーバーのダウン発生確率を下げることができます。
アクセスされる度にページを生成する必要がない分、負荷が少ないからです。


### バックアップが簡単
必要なファイルのバックアップを取るだけになります。復元する場合も過去のファイルをアップロードするだけなので簡単です。
静的化することで、データベースの事などを考慮してバックアップを取る必要がなくなるのでこの差は大きいです。

### セキュリティ対策が簡単
静的化することで、サーバーのセキュリティを考える必要がほぼなくなります。

## デメリット
### サイト内検索などの機能が使えない
サイト内検索や、関連記事、ランキングなどの動的な機能は当然使えません。

一応、外部サービスを使用するといった対策案はあります。
それを探したり、コストやセキュリティ面でどうかなどの調査をする必要がありますが…

### ユーザーごとの表示切替ができない
SNSのような、ユーザーがログインしてマイページを表示してって機能は静的サイトではできません。
ブログなどの運用であれば問題と思いますが、会員制のサイトだったりすると厳しいかもしれません。

### 静的化するにあたって作業が増える
将来的な運用コストを考えればなんてことはないかもしれませんが、静的化するツールなどを調べたり実際に静的化したりの作業が発生します。

## さいごに
ここまで読んでくださってありがとうございました。
WordPressを静的化するとどんなメリットがあるのか聞く機会があったので、アウトプットとして簡単にまとめました。
少しでも参考になれば嬉しいです。
誤字脱字・発信した情報に間違い等ございましたら、指摘して頂けますと幸いです:bow:
また、説明にわかりづらい点がございましたら、改善致しますのでぜひコメントください:pray:
Google Apps Script を TypeScript + Docker で開発する

以下のやり方で

* Google Apps Script をローカルで書け、Git管理できる
* TypeScriptで書ける
* Docker内に環境構築するため、ホストOSを汚さない

の3つを満たすことができます。

# Docker 環境を構築する

## 完了後のファイル構成

```
./
├── docker
│   ├── Dockerfile
│   └── docker-compose.yml
└── src
    ├── gas
    │   ├── appsscript.json
    │   └── hello.ts
    ├── package.json
    └── node_modules
        └── @types
```

## docker-compose.yml

```
version: '2'
services:
  gas-build:
    build: .
    container_name: 'gas-build'
    tty: true
    volumes:
      - "../src:/opt/src"
```

## Dockerfile

```
FROM node:8.16.2

RUN npm -v

RUN npm i @google/clasp -g
```

## Docker Build
```
cd ./docker
docker-compose build
```

## Dockerをデーモンとして起動して bash に入る


### 起動

```
docker-compose up -d
```

### 起動後、bash に入る

```
docker-compose exec gas-build bash
```

### 終了

```
docker-compose stop
```

これで npm + google/clasp が実行できる環境で bash に入ることができた。

# clasp を使えるようにする

docker に bash で入って clasp による Google ログインを行う
docker であるため、 --no-localhost オプションをつける

```
clasp login --no-localhost
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/fe8ca6b4-4701-96c4-b61c-ca89404e2cce.png)

色々権限を求められるので、許可する。
許可完了後、コードが表示されるため、コピーをして、 bash 内に入力する

# clasp のプロジェクトを作成する

## GoogleAppsScript API の許可をしておく

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/4264392b-77d8-510a-d7d8-4929714968e7.png)



##  プロジェクト作成

```
cd /opt/src
clasp create --title clasp-sample-project --parentId {GoogleDriveのフォルダID} --rootDir ./gas
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/03362f33-b284-8f28-7f84-7516da79f4eb.png)

Google Drive のフォルダIDは、フォルダを開いた後のURLを参照してください
https://drive.google.com/drive/folders/{GoogleDriveのフォルダID}

## IDE で Google Apps Script のコード補完をできるようにしておく

```
cd /opt/src
npm install @types/google-apps-script
```

## 作成結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/1400d139-7ce0-289a-4a95-7fe43c27e134.png)


# TypeScript作成

## テスト用ソースコード作成

ホストOS上にて、
./src/gas/hello.ts を作成

```
const greeter = (person: string) => {
  return `Hello, ${person}!`;
}

function testGreeter() {
  const user = 'Grant';
  Logger.log(greeter(user));
}
```

## テストとして、Google Drive に Pushする

修正するたびに実行するため、Dockerコンテナ内からではなく、
ホストOSから実行できるようにする

```
docker-compose exec gas-build bash -c "cd /opt/src/ && clasp push"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/ba117043-2684-0763-93bc-a8623d6a80e5.png)

clasp push に --watch のオプションをつけると、監視状態になり、変更の都度、自動でPushされる。

# clasp でプッシュした結果

正常に Google Apps Script が反映されている！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/147535/6849e73e-64ae-e077-b1da-17990daf3824.png)
curlコマンド　よく使うやつ

```bash
# レスポンスヘッダーを確認したい時
$ curl -I {URL}

# ステータスだけを確認したい時
$ curl -LI {URL} -o /dev/null -w '%{http_code}\n' -s

# 詳細をログでみたい時
$ curl -v {URL}

# リダイレクト先の情報を確認したい時
$ curl -L {URL} 
```
Google Remote Desktop を少しだけ安全にする

## 内容
Google Remote Desktop は、イベントに記録を残しませんし、カーテン機能が標準で無効ですし、外部からアクセスできます。

もっとも、Google アカウントに接続され、PIN も割れた場合にしか成り立ちません。ですので気休めで適当に設定して安全ぽくします。

環境は Windows10 を想定しています。

## ローカルネットワークからのみ接続する

[RemoteAccessHostFirewallTraversal](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=RemoteAccessHostFirewallTraversal) をいじります。

レジストリエディタを利用して`HKEY_LOCAL_MACHINE\Software\Policies\Google\Chrome\RemoteAccessHostFirewallTraversal`を`0`にします。

設定したら`chrome://policy/`にアクセスして、ポリシーが更新されていることを確認してください。成功していれば、例えばモバイル回線等から接続できなくなります。

## 誰かが接続したことを記録する

[Chromeリモートデスクトップでリモートログを記録する](http://outliner.sblo.jp/article/182449292.html) を参考にします。

```bat
@echo off
tasklist /FI "IMAGENAME eq remoting_desktop.exe" /FI "SESSIONNAME eq Console" | find "remoting_desktop.exe" > NULL
if %ERRORLEVEL% == 0 (
    echo runing
)
```

こういった条件分岐で定期実行させておけば、Remote Desktop の開始時と停止時に自作の関数を実行できるようにできます。私の場合は Google App Script を作成して、開始時と停止時にシートに記録、開始時にメールを送信するようにしました。

## おわり

こんなことを設定するより、Google アカウントに接続されないようにした方が楽です。
2FA に似た[機能](https://cloud.google.com/docs/chrome-enterprise/policies/?policy=RemoteAccessHostTokenUrl)もあるのですが、まだ利用できないようです。

標準の RDP みたいに、接続元の IP なんかを標準でイベントに残してくれれば気が楽なのに
ファイルに Tab が入っているか確認したい

# 問題

ファイルに Tab が入っているかどうか確認したいが、普通のエディタで開くと空白文字と見分けがつかない。

# 解決策

less のオプション -U を使う。

```
less -U hoge.txt 
```

これは、バックスペース・タブ・改行文字を制御文字として表示する。
ファイル中に `^I` が含まれていたら、それは Tab 文字。
検索したい場合は `/` の後に `Control + i` で検索できる。
CMake で assembler を使う設定

```
enable_language(ASM)
```

を CMakeLists.txt に追加します(もしくは, projects にリストアップ).

自動で assembler プログラムの検出をしてくれますが,
assembler の dialet やプログラム名を指定するときは, 以下を参考ください.

https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/languages/Assembler

## Sanitizer との連携

https://github.com/arsenm/sanitizers-cmake

ASM を有効後に, sanitizers-cmake を利用し, clang で find_package(Sanitizers) とするとうまくいかないことがわかりました.

`enable_language(ASM)` を, `find_package(Sanitizers)` のあとに定義すると, とりあえず解決します.
Promiseのメモ - その3: 小ネタ

[その1](https://qiita.com/kazutosato/items/41639c3877a83b9ecee2) と [その2](https://qiita.com/kazutosato/items/94118b30ddf6c26cd24f) の追記の小ネタです。

プロミスチェーンは、新しいPromiseオブジェクトを次々に作ってコールバック関数を登録していくものです。ところで、新しいPromiseではなく、同じPromiseに対して2回thenで関数を登録したらどうなるでしょう。

```JavaScript
function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0)
      resolve('OK');
    else
      reject('NG');
  });
}

let promise = makePromise(2);

promise.then((x) => {
  console.log(`then1 callback: ${x}`);
  return x + x;
});

setTimeout(() => {
  console.log(promise);
  promise.then((x) => {
    console.log(`then2 callback: ${x}`);
  });
}, 1000);
```


```text:結果
then1 callback: OK
Promise {<resolved>: "OK"}
then2 callback: OK
```

履行済み、かつコールバック関数を1度実行したことのあるPromiseオブジェクトでも、あとからコールバック関数を追加すれば実行される、ということがわかります。結果の値（`"OK"`）はそのままです。

以上、特に実用性はない実験でした。

- [Promiseのメモ - その1: resolveとthen](https://qiita.com/kazutosato/items/41639c3877a83b9ecee2)
- [Promiseのメモ - その2: チェーン、例外](https://qiita.com/kazutosato/items/94118b30ddf6c26cd24f)
- [Promiseのメモ - その4: asyncとawait](https://qiita.com/kazutosato/items/c1c047991315128271f5)
anyenvをシステムワイドにインストール：aws linux2

## 背景
anyenvは個人でも便利でよく使うものですが、主に開発環境のところで利用していました。今回は本番などでウェブサーバー（phpenv）を利用する場合を想定してシステムワイドにインストールする方法をやってみます。
参考：https://qiita.com/mikesorae/items/e8e2d13b6b46b60ef4c4

### 概要
- Versionのインストールはrootユーザー
- 利用は全ユーザー

## インストール
上記の参考URLの内容にすると以下のエラーに出ました。

```
ANYENV_DEFINITION_ROOT(/*********/.config/anyenv/anyenv-install) doesn't exist. You can initialize it by:
```

解決方法として調べた内容がこちらです。sudo及びrootで実装で実行します。

```
cd /opt
git clone https://github.com/riywo/anyenv
echo 'export PATH="/opt/anyenv/bin:$PATH"' >> /etc/profile.d/anyenv.sh
echo 'export ANYENV_ROOT="/opt/anyenv"' >> /etc/profile.d/anyenv.sh
echo 'export ANYENV_DEFINITION_ROOT="/opt/anyenv/share/anyenv-install"' >> /etc/profile.d/anyenv.sh
echo 'eval "$(anyenv init -)"' >> /etc/profile.d/anyenv.sh
exec $SHELL -l
```
勿論、直ぐにphpenvをインストールしたりしたければ、上記の設定が反映されないと動けないです。
**＊2019-10-28：以下の実装を入れた方が良いかと**

```
ln -s /opt/anyenv/envs/phpenv/shims/php /bin/php
```

## phpenvでの注意点
基本的にversionのインストールはroot権限があるユーザーで行う設定ですが、phpenvでインストールした後にcomposerを実行すると「/opt/anyenv/envs/phpenv/shims/composer」が実行されてcomposerをインストールを行います。
ただし、ファイルの権限で以下のようになってしまい、他のユーザーが使用時にpermissionエラーが出る場合があります。

```
# /opt/anyenv/env/phpenv/versions/*.*.*/composer/の内容
-rw-------  1 root root     124 Nov 11 12:32 auth.json
-rwxr-xr-x  1 root root 1933813 Nov 11 12:32 composer.phar
-rw-------  1 root root      21 Nov 11 12:32 config.json
-rw-r--r--  1 root root      13 Nov 11 12:32 .htaccess
```
なので以下のコマンドでpermissionの修正をした方が良いです。phpenvの設定でできるか調べてはいますが、まだ見つからない状態です。

```
# chmode 644 *.json
```

## AWS Linux2での注意点
phpenvでphp７.３.*をインストールする際に以下の物を先にインストールしました。

```
sudo yum -y install gcc libxml2 libxml2-devel libcurl libcurl-devel libpng libpng-devel libmcrypt libmcrypt-devel libtidy libtidy-devel libxslt libxslt-devel openssl-devel bison libjpeg-turbo-devel readline-devel autoconf bzip2-devel libicu-devel gcc-c++ libzip libzip-devel re2c libtidy
```

だが、AWS Linux2では以下のエラーでlibtidyが出来ませんでした。

```
$ yum -y install libtidy libtidy-devel
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
26 packages excluded due to repository priority protections
No package libtidy available.
No package libtidy-devel available.
```
原因は「amzn-main？」ではlibtidyがないことでした。それで以下のコンマンドでインストールがでいました。
参考：https://dev.classmethod.jp/cloud/aws/amazon-linux-2-enable-epel-repository-with-amazon-linux-extras/

```
amazon-linux-extras install -y epel
yum --enablerepo=epel install libtidy-devel
```
[saml2aws] error authenticating to IdP: page is missing saml assertion

## 問題
いつも使っている`aws-auth`でAWSにログインしようとすると、以下のエラーが返してきた。

```
error authenticating to IdP: page is missing saml assertion
```
## 背景
- MacOS 10.14.6

## 対応

```shell
brew upgrade saml2aws
```

## 原因
認証画面が変わった気がします。ちなみに、**iOS**だと発生しますが、Androidは発生してないようです。

---

## aws-auth
一発ログイン

```shell
saml2aws login -a idp_account_name —username=username --password=‘password' --role='arn:aws:iam::31xxxxx:role/Administrator' --skip-prompt
```
Ruby 正規表現の学習2

# 正規表現の様々なパターンを使ってみる
先日は```subメソッド```、```matchメソッド```の基本的な使い方を載せてみました。
今回は、正規表現の様々なパターンを使って少しだけ応用的な使用方法を使ってみたいと思います。
今回、使ってみるパターンは以下の３つ。

+ 電話番号のハイフンを取り除く
+ パスワードに英数字8文字以上という制約を設定
+ メールアドレスからドメインの部分のみ抽出

# 1. 電話番号からハイフンを取り除く
```:ターミナル
irb(main):001:0> tel = '090-1234-5678'
=> "090-1234-5678"

irb(main):002:0> tel.sub(/-/,'')
=> "0901234-5678"
# 最初のハイフンしか置換えされない

irb(main):003:0> tel.gsub(/-/,'')
=> "09012345678"
```
__ポイント__

+ グローバルマッチの```g```<br>
```sub```の前に```g```が追加された、```gsub```メソッドと言い、```g```が意味するのは、グローバルマッチと言う。<br>
文字列内で指定した文字が複数含まれている場合、その全てを置換えすると言う意味になる。<br>
```gsub```だけではなく```sub```を使用した場合は、初めの１つだけ置換えされることになる。

# 2. パスワードに英数字8文字以上という制約を設定
以下はパスワードに「Hoge1234」という大文字小文字を区別した英字と数字を使用して、```matchメソッド```を使用して記述してみる。

```:ターミナル
irb(main):001:0> pass = 'Hoge1234'
=> "Hoge1234"

irb(main):002:0> pass.match(/[a-z\d{8,}/i)
=> #<MatchData "Hoge1234">
```
__ポイント__

+ ```[a-z]```: 角括弧で囲まれた文字のいずれか１個にマッチ
+ ```\d```: 数字にマッチ
+ ```{n, m}```: 直前の文字が少なくとも n 回、多くても m 回出現するものにマッチ
+ ```i```: 大文字・小文字を区別しない検索

### [a-z] : 角括弧で囲まれた文字のいずれか １個にマッチ
__a~cの英字を抽出__
「dog」にはa〜cのどの英字も含まれていないのでマッチしない。

```:ターミナル
irb(main):001:0> 'dog'.match(/[a-c]/)
=> nil
```
### \d : 数字にマッチ
+ ```\d```の```d```は数字を表す。数字と表す```d```のような文字を__特殊文字__と呼び、特殊文字を使用する場合は直前に```\```を記述するというルールがある。
+ ```[a-z\d]```は「英数字のいずれか１つにマッチ」という意味になる。

```:ターミナル
irb(main):001:0> 'I have 3 pens'.match(/\d/)
=> #<MatchData "3">
```
### {n, m} : 直前の文字が少なくとも n 回、多くても m 回出現するものにマッチ
__少なくとも4回、多くても6回出現するものにマッチ__
波括弧を使用することで文字数の制約を追加することができる。```{4,6}```は、直前の文字が少なくとも下記の場合は4回多くても6回数字がマッチという意味になり、2回目のirbはマッチする数字がないので``nil``と返される。

```:ターミナル
irb(main):001:0> '12345678'.match(/\d{4,6}/)
=> #<MatchData "123456">

irb(main):002:0> '123'.match(/\d{4,6}/)
=> nil
```
### i : 大文字・小文字を区別しない検索
+ ```i```オプションを加えることで大文字・小文字を区別しないで検索する。
+ ```i```オプションをつけずに```[a-z]```と小文字で記述すると大文字にマッチしなくなる。
+ 
__大文字・小文字の区別__

```:ターミナル
irb(main):003:0> 'Cat'.match(/cat/)
=> nil

irb(main):004:0> 'Cat'.match(/cat/i)
=> #<MatchData "Cat">
```
__実践的な使用例__

```:irb
pass = 'Hoge1234'
if pass.match(/[a-z\d]{8,}/i)
  // パスワード設定の処理
else
  puts 'パスワードの形式が間違えています。'
end
```
# メールアドレスからドメインの部分のみ抽出
「hoge@sample-taka.com」というアドレスから「@sample-taka.com」の部分のみを取得したい場合。

```:ターミナル
irb(main):001:0> mail = 'hoge@sample-taka.com'
=> "hoge@sample-taka.com"

irb(main):002:0> mail.match(/@.+/)
=> #<MatchData "@sample-taka.com">
```
__ポイント__

+ ```.``` : どの1 文字にもマッチ
+ ```+``` : 直前の文字の 1 回以上の繰り返しにマッチ 

### ```.```どの1文字にもマッチ
ハイフンやピリオドなど含めた全ての英数字において、どの1文字にもマッチする。

(例)

```:ターミナル
irb(main):001:0> 'hoge'.match(/./)
=> #<MatchData "h">
```
### ```+```直前の文字の 1 回以上の繰り返しにマッチ
直前の文字が 1 回以上の繰り返しにマッチする。

(例）

```:ターミナル
irb(main):001:0> 'aaabb'.match(/a+/)
=> #<MatchData "aaa">
```
以上の例に沿ってみると

+ ```.+```は何かしたの文字が一回以上繰り返されるものにマッチする。
+ 先頭に```@```をつけることで「@から始まり、何かしらの文字が 1 回以上口返すものにマッチ」という意味になる。

# まとめ
|パターン|意味|
|:----:|:--:|
|[a-z]|角括弧で囲まれた文字のいずれか 1 個にマッチ|
|\d|数字にマッチ|
|{n,m}|直前の文字が少なくとも n 回、多くても m 回出現するものにマッチ|
|.|どの 1 文字にもマッチ|
|+|直前の文字の 1 回以上の繰り返しにマッチ|
まだまだ奥深い正規表現ですが以上のことだけは最低限おさえて置きたいと思います。。。
デモンエクスマキナのコンソール風アニメーション

![ezgif-3-a39df8b3db24.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126428/572ae781-416b-fc81-31f8-e340bb129d44.gif)

こんな感じのアニメーションをJSで作ってみました。

デモページ: https://sujoyu.github.io/dxm-text-animation/demo

## インストール

リポジトリ: https://github.com/sujoyu/dxm-text-animation

npm に上げたりモジュール化してないので愚直に。

```html
<script src="DXMEffect.js"></script>
<script>
  const elements = document.querySelectorAll('.dxm-effect');
  [].forEach.call(elements, function (el) {
      const dxmEffect = new DXMEffect(el, { 
      speed: 30,
      delay: 100,
      })
      dxmEffect.init()
  })
</script>
```

## サンプルコード

### 普通の使い方
```html
<p class="dxm-effect">The quick brown fox
jumps over the lazy dog.</p>
```

### 遅いアニメーション

```javascript
const elements = document.querySelectorAll('.dxm-effect');
[].forEach.call(elements, function (el) {
    const dxmEffect = new DXMEffect(el, { 
    speed: 300,
    delay: 1000,
    })
    dxmEffect.init()
})
```

### 開始にディレイを入れる

```html
<p class="dxm-effect" data-dxmeffect-start-delay="1000">The quick brown fox jumps over the lazy dog.</p>
```

<p class="dxm-effect" data-dxmeffect-start-delay="1000">The quick brown fox jumps over the lazy dog.</p>

### 複数要素を順次アニメーションする

```html
<p id="effect1" class="dxm-effect">The quick brown fox jumps over the lazy dog.</p>
<p id="effect2" class="dxm-effect" data-dxmeffect-after="#effect1">The quick brown fox jumps over the lazy dog.</p>
<p id="effect3" class="dxm-effect" data-dxmeffect-after="#effect2">The quick brown fox jumps over the lazy dog.</p>
```

## 注意
- 等幅フォント使うのがおぬぬめ。
- 中に使えるのはプレーンテキストだけです。 `white-space: pre`を使ってるので不要な改行や空白を入れないよう注意してください。
Vuexメモ

<h1>state</h1>
dataのようなもの
状態を表している

<h1>getter</h1>
computedのようなもの
stateから別の値を算出するために用いられる。
ステートの値を書き換える力はない。
getterの中で他のgetterを使うことも可能

<h1>mutation</h1>
唯一stateを更新する役割。
methodsのようなもの。
第一引数に渡されたstateを更新する。
呼ぶときは、store.commit(mutation)のように呼ぶ。
この時第二引数に何らかの値を渡すと、mutationの第二引数に渡される。
この値のことを<strong>ペイロード</strong>という。
まあメソッドの引数みたい感じ。
mutationの中ではsettimeoutのような非同期の処理は用いらない。

<h1>action</h1>
非同期処理や外部APIとの通信を行い、最終的にmutationを呼び出すために用いられる。
actionの定義はmutationに似ているが、第一引数にステートではなく、コンテキストと呼ばれる特別なオブジェクトが渡される。
コンテキストとは、state、getters、dispatch、commitが含まれる。
actionはmutationを実行するために用いられるため、commitが使われることが多い。
dispatchでactionを呼ぶ。
いろいろ複雑だが、流れ的には
１、store.dispatch(incrementAction)でincrementActionというactionを呼び出す。
２、incrementActionの中のcommit(incrementMutation)でincrementMutationというmutationを実行する。
という風なる。
dispatch→action→commit→mutationという感じにコードを追っていけば、実際に行われている処理にたどり着くであろう。

<h1>モジュール</h1>
ストアを分割して、ステート、ゲッター、ミューテーション、アクションを定義できる。

<h2>名前空間</h2>
モジュールを作って、ストアを分割するのだが、同じ名前のステートやミューテーションなどが出てきてしまうかもしれない。また、例えばAというゲッターがどこのモジュールのゲッターなのかわからなくなってしまう場合があるかもしれない。
そこで、モジュールを定義するときに、`namespaced: true` を記述することによって名前空間を設定できる。

```
const store = new Vuex.Store({
   state: {
      count: 1
   },
   
   getters: {
      double: state => state.count + state.count //state.countを2倍にして返す
   },

   mutations: {
      update (state, payload) {
         state.count = payload
      }
   },

   modules: {
      example: {
         namespaced: true, //ここで名前空間を設定
         
         getters: {
            triple: (state, getters, rootState, rootGetters) => {
   // rootState,rootGettersはそれぞれモジュールの外のstateとgetterにアクセスすることを示している
               return rootstate.count + rootGetters.double
            }
         },
      
         actions: {
            multiplyByFive (ctx) {
               const payload = ctx.rootGetters.double + ctx.getters.triple
               ctx.commit('update', payload, { root: true })
       // { root: true }をつけることによって、モジュール外のmutationにアクセスすることを示している
            }
         }
      }
   }
})

console.log(store.state.count) // -> 1

store.dispatch('example/multiplyByFive') 
//　この書き方によってexampleモジュールのアクションを呼び出している

console.log(store.state.count) // -> 5 
```

基本的に`root` がついているものは、モジュール外（グローバル）のものにアクセスしている

<h1>ストアとコンポーネントの通信のヘルパー関数</h1>

ストアとコンポーネントの通信のヘルパー関数は、mapState、mapGetters、mapMutations、mapActionsがある。
基本的に、コンポーネントからストアにアクセスするときには、下記のように`this.$store` を使用する。

```
...
   computed: {
      count () {
         return this.$store.state.count
      }
   },
...
```

そこでヘルパー関数を使えば、上記のコードを下記のように短く書ける。

```
...
   computed: mapState([
      'count'
   ])
...
```

普通のcomputedも定義したいときは、

```
...
   computed: {
      double () {
         return this.count * 2
      },


      ...mapState([
      'count'
   ])
...
```

上記のように、先にcomputedを定義して、そのあとに`...mapState` と記述し始めればよい。
Photoshop Jsxで複数選択したレイヤーに共通処理を行う

PhotoshopのExtendScriptApiだと選択しているレイヤーの取得に```app.activeDocument.activeLayer```を使いますが、これだと複数のレイヤーを取得している時に、代表レイヤーしかobjectの取得ができず、選択している全てのレイヤーに何か共通処理を施すことができません。

この問題に関して、チャレンジしている方が何人もおり、下の記事を参考にさせてもらっておりました。

- [中 綴 製 作 所 ・ 複数のアクティブレイヤーの取得・変更](http://nakatoji.lolipop.jp/index.php/extendscript/photoshop/ps-layer/449-2015-05-15-19-07-67)
- [ねこまたや web出張所 ・ 複数レイヤをスクリプトで扱う](http://www.nekomataya.info/nekojyarashi/wiki.cgi?photoshop%CA%A3%BF%F4%A5%BB%A5%EC%A5%AF%A5%C8)

色々と試行錯誤していく中で、自分なりにこれがいいかなーという手法を見つけたので紹介します。


# 選択しているレイヤー全てに共通処理を行うスクリプト
```executeSelectLayersAction.jsx
function executeSelectLayersAction(exec_action)
{
  // 元のactiveLayer位置を覚えておく
  var active_layer = app.activeDocument.activeLayer;
  var is_visible = active_layer.visible;

  var doc_ref = new ActionReference()
  doc_ref.putEnumerated(charIDToTypeID("Dcmn"),charIDToTypeID("Ordn"),charIDToTypeID("Trgt"));
  var target_layers = executeActionGet(doc_ref).getList(stringIDToTypeID('targetLayersIndexes'));

  // 選択しているレイヤーのIDを取得しておく
  for(var i=0;i<target_layers.count;i++)
  {
    var index = target_layers.getReference(i).getIndex() + 1;

    // レイヤーを選択状態にする
    var desc = new ActionDescriptor();
    var ref = new ActionReference();
    ref.putIndex(charIDToTypeID( "Lyr " ), index);
    desc.putReference(charIDToTypeID( "null" ), ref );
    desc.putBoolean(charIDToTypeID( "MkVs" ), false );
    executeAction(charIDToTypeID( "slct" ), desc, DialogModes.NO );

    var select_layer = app.activeDocument.activeLayer;
    exec_action(select_layer);
  }

  app.activeDocument.activeLayer = active_layer;
  app.activeDocument.activeLayer.visible = is_visible;
}
```

使い方は以下の通り

```jsx
#target photoshop;

var select_layer_names = [];
executeSelectLayersAction(function(layer){
  // 選択したレイヤーに対して行いたい処理をここに書く。
  select_layer_names.push(layer.name);
});

alert(select_layer_names.join(", "));
```

選択状態
![スクリーンショット 2019-10-11 13.37.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189041/f32810e9-acf0-f387-b917-9e112929d94c.png)
実行結果
![スクリーンショット 2019-10-11 13.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/189041/870744fb-d089-eca2-29a2-fce6d6327ca2.png)


# 動作の説明
上のスクリプトは次のロジックで動作しています

- 選択されているレイヤーのIndexのリストを取得
- このレイヤーのIndex情報をforで回し、一つずつ選択状態にさせる(**ActionDescriptorを使って選択状態にする**)
- app.activeDocument.activeLayerを取得し、登録されているactionを実行する

動作も軽くていい感じです！
ただし、Command押しで複数選択した場合は問題ないですが、Shif押しでグループレイヤーを選択した時、グループレイヤー内の全てのレイヤーが選択状態になるため、意図していない動作になる場合があります。
Discord.pyで起動時に特定の名前のチャンネルでメッセージを出す。

[前回](/tskikoh/items/26327ed6ccfe737269bd)はDiscord.js向けに書きましたが、今回はDiscord.py向けです。

# 前提条件
既にPython3でDiscord.pyが動く前提で書きますので、環境を揃えてからお願いします。
実行方法等も特に説明しません。

# コードの内容
同じ名前のチャンネルが複数のサーバーにある事を想定して書いてます。
なので、BOTがいる全てのチャンネルを読み込むような動作をします。
そうで無い場合はもっと無駄の少ないコードになると思います。

```on-ready.py
import discord

client = discord.Client()
TOKEN = "<Token>"

@client.event
async def on_ready():

	ch_name = "チャンネル名"

	for channel in client.get_all_channels():
		if channel.name == ch_name:
			await channel.send("起動しました")

client.run(TOKEN)
```
これだけです。

# コードの説明
Discord.pyを読み込んで、変数「Discord」に代入します。
`import discord`

Discordにクライアント接続をします。
`client = discord.Client()`

トークン変数に代入しておきます。
<Token>の箇所にはあなたのBOTのトークンを入れてください。
`TOKEN = "<Token>"`

BOTのクライアントが起動したときに実行します。
`@client.event
async def on_ready():`

BOTが接続している全チャンネルの情報を順番に`channel`に代入して、チャンネルの数だけ繰り返します。
`for channel in client.get_all_channels():`

チャンネルの名前がch_nameと一致したら実行します。
`if channel.name == ch_name:`

指定したチャンネルに「起動しました」と送信します。
`await channel.send("起動しました")`

トークンを読み込んでクライアントを実行します。`@client.event`より前に書くと読み込まなくなってしまうので、必ず最後に書いてください。
`client.run(TOKEN)`

以上です。
間違い等があれば、[Discord](https://discord.gg/RBGKgSg)までご連絡ください。

このソースコードは[GitHub](https://github.com/Tsukikoh/Start-up-message-on-discord.py)に掲載しています。
破壊的メソッド　非破壊的メソッド


- 大元も値を変更するかいなか

```ruby

破壊的メソッドとは本体のデータを変更する事

- 非破壊的

string = "test code"
string.slice!(0,4)
p string

→ "test code"

- 破壊的

string = "test code"
string.slice!(0,4)
p string
→ " code"
```
文字単位の差分を取ってHTMLタグをつける

文字単位のdiffを取って、いい感じにHTMLで表示したくなることありませんか？ ぼくはあります。
ただ、この前それをやりたくなったのが10年以上前で、すっかり忘れてまた作り直すはめになったので、自分用を兼ねてメモしておきます。

欲しいのはこういうやつです。

```sh
$ echo -e "今日はいい天気ですね。\t今日はとてもいい天気でしたね" | xxx
今日は<u>とても</u>いい天気で
す
<u>した</u>ね
。

```

入力はタブ区切りで、左右の行は常に対応しているとします。対応していない場合はちゃんとしたツールを使って何とかしたほうがいいと思いますが、ここでは行は対応しているとして、その場合の文字単位のdiffをワンライナーで取ることにします。

Perlで書いたワンライナーが次のものです。

```sh
perl -MFile::Temp -Mutf8 -CSD -F/\\t/ -nale 'for $i(0..1) { ($fh[$i], $fname[$i]) = File::Temp::tempfile(UNLINK=>1); binmode $fh[$i], ":utf8"; @{$l[$i]} = split//, $F[$i]; print {$fh[$i]} $_ for @{$l[$i]}; close $fh[$i]; } for (reverse grep { m{^\d}; } map { chomp; $_; } `diff $fname[0] $fname[1]`) { @t = map { m{^(\d+),(\d+)$} ? [$1-1, $2-1] : m{^(\d+)$} ? [$1-1, $1-1] : $_; } split/([acd])/; @new = @{$l[1]}[$t[2]->[0]..$t[2]->[1]]; if ($t[1] eq "a") { splice @{$l[0]}, $t[0]->[0]+1, 0, "<u>", @new, "</u>"; } elsif ($t[1] eq "d") { splice @{$l[0]}, $t[0]->[1]+1, 0, "
"; splice @{$l[0]}, $t[0]->[0], 0, "
"; } else { splice @{$l[0]}, $t[0]->[1]+1, 0, "
<u>", @new, "</u>"; splice @{$l[0]}, $t[0]->[0], 0, "
"; } } print join("", @{$l[0]});'
```

[Gist](https://gist.github.com/hiroshi-manabe/23ee459e4e51d407150b359443fb6cc2)

これを使うと、上のことが実現できます。

```sh
echo -e "今日はいい天気ですね。\t今日はとてもいい天気でしたね" | perl -MFile::Temp -Mutf8 -CSD -F/\\t/ -nale 'for $i(0..1) { ($fh[$i], $fname[$i]) = File::Temp::tempfile(UNLINK=>1); binmode $fh[$i], ":utf8"; @{$l[$i]} = split//, $F[$i]; print {$fh[$i]} $_ for @{$l[$i]}; close $fh[$i]; } for (reverse grep { m{^\d}; } map { chomp; $_; } `diff $fname[0] $fname[1]`) { @t = map { m{^(\d+),(\d+)$} ? [$1-1, $2-1] : m{^(\d+)$} ? [$1-1, $1-1] : $_; } split/([acd])/; @new = @{$l[1]}[$t[2]->[0]..$t[2]->[1]]; if ($t[1] eq "a") { splice @{$l[0]}, $t[0]->[0]+1, 0, "<u>", @new, "</u>"; } elsif ($t[1] eq "d") { splice @{$l[0]}, $t[0]->[1]+1, 0, "
"; splice @{$l[0]}, $t[0]->[0], 0, "
"; } else { splice @{$l[0]}, $t[0]->[1]+1, 0, "
<u>", @new, "</u>"; splice @{$l[0]}, $t[0]->[0], 0, "
"; } } print join("", @{$l[0]});'
今日は<u>とても</u>いい天気で
す
<u>した</u>ね
。

```

中でdiffコマンドを実行しているので、diffコマンドが入っていることが必要です。
macOS Catalina にしたら、Anaconda 使えなくなった場合の対処法

楽しみにしていた「macOS　Catalina」にアップデート。
あれっ、、アップデートしたらAnacondaが使えなくなってる。。。
そんな方への対処法をまとめました。

# なんで使えなくなった
Catalinaではルートディレクトリへの書き込みをセキュリティ上推奨しないようです。
一方、Anacondaはディフォルトではルートに生成されています。
OSアップグレードの際にルートディレクトリから丸ごと移動されてしまうため、使えなくなってしまいます。

追い出されたanacondaは以下に移動されています。
`/Users/Shared/Relocated Items/Security/anaconda3`
デスクトップにエイリアス「場所が変更された項目」が生成されているのでそちらからも辿れます。

#対応方法
詳しくは以下の海外サイト、こちらを参考にしました。
https://superuser.com/questions/1456518/anaconda-not-working-in-mac-catalina

##対応Step
1 追い出されたanacondaディレクトリをホームディレクトリに移動

```bash
#追い出されたanaconda
/Users/Shared/Relocated Items/Security/anaconda3 
#ホームディレクトリに移動
/Users/[your_user_name]/anaconda3
```

2 condaを使用可能にする

```bash
#binディレクトリに移動
cd /Users/[your_user_name]/anaconda3/bin/

#condaファイルのshebangを変更
vi conda
#1行目
 #!/anaconda3/bin/python
#↓以下に変更
 #!/Users/[your_user_name]/anaconda3/bin/python

#condaファイルを保存
```

3 condaの初期化
初期化することで、依存ファイルが最適化され、shellにanacondaのパスが通ります。

```bash
conda init bash　（conda init zsh）
#(catalinaのディフォルトshはzsh。私は取り急ぎbashでしましたが、zsh移行済みの方は、zshで初期化してください）

#以下のステータスが走ります。
modified 〜〜〜
・・・
・・・
==> For changes to take effect, close and re-open your current shell. <==
```

4 確認
~/.bash_profileにパスを通す記述が自動追記されます。

```bash
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!                   

#<パスを通すコマンドが自動記述される>

unset __conda_setup
# <<< conda initialize <<<
```

5　読み込み、正常使用を確認
terminalを再度立ち上げるか、
`source ~/.bash_profile`で設定を再読み込み。

これでエラーがなければ、anacondaは正常に使えるようになっていると思います。
anaconda経由のpythonや、ライブラリ、condaも使用できるようになります。

*まだ、Catalinaがリリースされてから日が浅いので、一部不具合の可能性もあります。心配な方は少し経ってからの移行をおすすめします。*

6 anaconda-navigatorの対応
私はanaconda-navigatorを利用してませんが、参考サイトに対応方法ありましたので、ついでに対応してみました。

- anacondaディレクトリに移動  
/Users/[your_user_name]/anaconda3/
- Anaconda-Navigator.app を右クリック  
パッケージの内容を表示を選択
- Contents/MacOS/run.sh を開く
- 以下の部分を全て書き換える

```
#変更前
/anaconda3
↓
#変更後
/Users/[your_user_name]/anaconda3
```
ファイルを保存する。
これで「Anaconda Navigator」は使用できるようになりました。

7 番外
私の場合は、「jupyter notebook」も使えなくっていました。
以前、conda経由でインストールしたのですが、今回のOSアップグレードに関係あるかもしれません。
私の場合ですが、アップグレードしたら使えるようになりました。

```bash
#conda自体をアップデート
conda update conda
#jupyter notebookのアップデート
conda update jupyter
```
ただ、環境により人それぞれ対応方法は異なるかもしれません。

#　追伸
試してないけど、違うやり方です。
https://medium.com/@justinaugust/upgrading-to-osx-catalina-as-an-anaconda-user-2e71db194764

ざっくりこんな方法みたいです。
1. セキュリティディレクトリに避難された、anacondaディレクトリをホームディレクトリに移動するのは同じ。
2. anacondaの公式ページからダウンロードインストーラーをダウンロード
3. Terminalで　インストール作業
 `./<name of anaconda installer> -u`
 ホームディレクトリを指示してanaconda3をインストール

要はインストールすることで設定を上書きするやり方のようです。

# おわりに
以上、macOS Catalinaを入れた際のAnacondaの対応方法をまとめてみました。
OSリリースしてまだ日が浅いこともあり、まだ他の不具合が出てくる可能性もありますが、
ひとまず私の環境ではAnaconda/pythonは使えております。

稚拙なまとめでしたが、みなさんのお力になれると幸いです。
Railsで既存モデルをポリモーフィック化したら大変だった話

# 前提
社内でやろうとしてたことそのまま書けないので、
例えを探しましたが・・・わかりにくいかもですw
ポリモーフィックについては、[こちらの記事](https://qiita.com/yu-croco/items/0aa9b2f8a797ee0a3515)がわかりやすかったです！感謝感激。

モデルは下記とします。 
**モデル図** ＊()の中がモデル名
普通自動車(Car)-<部品(Part)>-人(Owner)

**Car**
  has_many :parts
  has_many :owners, through: :parts

**Part**
  belongs_to :cars
  belongs_to :owners

**Owner**
  has_many :parts
  has_many :cars, through: :parts

目的は、
**「ある人が所持している、ある普通自動車に搭載されている部品達をDBで管理できる」**
とします。

もうちょっと具体的にいうと、
**「AさんのIDから次郎号という自動車を特定できて、
　　　　かつ次郎号に搭載されている部品(前輪・後輪とか)も把握できる」**
みたいな感じです。

# 異なるモデルも同一のモデルで管理したい
上記モデルをポリモーフィック可したらどうなるかというと
モデルはこんな感じになります。＊()の中がモデル名
**モデル図**
なんかの乗り物-<部品(Part)>-人(Owner)

**なんか乗り物(ここではCarとShipとしておきます）**
  has_many :parts
  has_many :owners, as: :vehicle, through: :parts

**Part**
  belongs_to :vehicles, polymorphic: true
  belongs_to :owners

**Owner**
  has_many :parts
  has_many :cars, as: :vehicle, through: :parts
  has_many :ships, as: :vehicle, through: :parts

要するに
**「ある人が所持している、ある乗り物に搭載されている部品達をDBで管理できる」**

何が良いの？となりますが
普通自動車以外の乗り物（バイク、船 etc...）の部品もPartモデルに突っ込めます！
Partモデルにvehicle_typeとvehicle_idというカラムを追加してあげることで
(vehicle_type = 'Car'　とか　vehicle_type = 'Ship'とか・・・)
**Partからみたら、繋がりは一つに見えるのに色々な乗り物モデルと繋がれる**
という状態になります。

# 何が大変だったか
さて、本題ですが
１つ前のセクションでポリモーフィック化は完了したとします。
となると、既存のソース内で変更が必要になってきます。

まず当時の私は、下記のクエリは問題ないと思っていました。(いつ使うんだこのクエリは！と言わないでくださいw）
「ある車に紐付いている、personを取り出す。条件は、男性で前輪を持っている人」
`car = Car.find_by("123-456-789")`
`car.persons.joins(:parts).find_by('persons.sex = ? AND parts.name = ?', "male", 
 "前輪")`

これを叩くと、以下を含んだクエリが作成されます。
**WHERE "parts"."car_id" = $1**
ポリモーフィック化する以前は、Carモデルしかなかったのでこれで良かったのですが
ポリモーフィック後はvehicle_idというカラムに変わっているのでエラーになります。

ここで注意すべきは、**「じゃあparts.vehicle_idにすればいいのでは？」・・それでは、事足りないということです。**
具体的には、先ほどのクエリをこんな風にすればOKです。
`Person.joins(:parts).find_by('vehicle_id = ? AND vehicle_type = ? AND persons.sex = ? AND parts.name = ?', car.id, 'Car', "male", "前輪")`
vehicle_idと合わせてvehicle_typeも引き合いに出すことで期待する値を確実に取ることができます。

# まとめ
既存モデルをポリモーフィック化すると、そのモデルの先で叩くクエリを書き直さなければならない場合があります。
その際は、XXX_typeというようにクエリへモデルのタイプ(String)を含める必要があります。

# おまけ： さらに抽象度を上げるには？
下記のクエリは、Carモデル用にハードコーディングされてます。
`Person.joins(:parts).find_by('vehicle_id = ? AND vehicle_type = ? AND persons.sex = ? AND parts.name = ?', car.id, 'Car', "male", "前輪")`

こんな風に変えるといい感じです！
`Person.joins(:parts).find_by('vehicle_id = ? AND vehicle_type = ? AND persons.sex = ? AND parts.name = ?', vehicle.id,  vehicle.class.to_s, "male", "前輪")`
こうすれば、仮に変数vehicleにCarモデルが入ろうが、Shipモデルが入ろうが吸収してくれます。

# 参考
[【初心者向け】Railsのポリモーフィック関連付けを理解しよう
](https://qiita.com/yu-croco/items/0aa9b2f8a797ee0a3515)
UbuntuにMicroK8sを導入する

##はじめに
###前提環境
- Windows10マシンのVirtualBox上に構築
- Ubuntu 16.04.6 LTS
- snap 2.42
- MicroK8s v1.16.0

###参考にした情報
- [Install Kubernetes on Ubuntu](https://ubuntu.com/kubernetes/install)
- [Ubuntu Weekly Recipe 第560回microk8sでお手軽Kubernetes環境構築](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0560)

##セットアップ作業
### MicroK8sのインストール
数分で完了した。

```cmd:
hanako@myubuntu:~$ sudo snap install microk8s --classic
microk8s v1.16.0 from 'canonical' installed
hanako@myubuntu:~$
```

###グループへのユーザー追加と権限確認
- status確認をしようとすると、一般ユーザーをグループに入れるようにとのメッセージが表示され、追加した。

```cmd
hanako@myubuntu:~$ microk8s.status --wait-ready
Insufficient permissions to access MicroK8s.
You can either try again with sudo or add the user hanako to the 'microk8s' group:

    sudo usermod -a -G microk8s hanako

The new group will be available on the user's next login.
hanako@myubuntu:~$ sudo usermod -a -G microk8s hanako
hanako@myubuntu:~$
```

- ログインしなおし、ステータスの確認をする。（コマンドは正常に実行できた。）

```cmd:
hanako@myubuntu:~$ microk8s.status --wait-ready
microk8s is running
addons:
rbac: disabled
knative: disabled
ingress: disabled
dns: disabled
metrics-server: disabled
linkerd: disabled
prometheus: disabled
istio: disabled
jaeger: disabled
fluentd: disabled
gpu: disabled
cilium: disabled
storage: disabled
dashboard: disabled
registry: disabled
hanako@myubuntu:~$
```

- ちゃんとNodeは動いてる

```cmd:
hanako@myubuntu:~$ microk8s.kubectl get nodes
NAME      STATUS   ROLES    AGE     VERSION
myubuntu   Ready    <none>   5m41s   v1.16.0
hanako@myubuntu:~$
hanako@myubuntu:~$ microk8s.kubectl get services
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.152.183.1   <none>        443/TCP   6m1s
hanako@myubuntu:~$
```

###エイリアス設定
- microk8s.kubectlではなくkubectlでコマンドを実行したい場合は、エイリアスを設定する

```cmd:
hanako@myubuntu:~$ sudo snap alias microk8s.kubectl kubectl
[sudo] password for hanako:
Added:
  - microk8s.kubectl as kubectl
hanako@myubuntu:~$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://127.0.0.1:16443
  name: microk8s-cluster
contexts:
- context:
    cluster: microk8s-cluster
    user: admin
  name: microk8s
current-context: microk8s
kind: Config
preferences: {}
users:
- name: admin
  user:
    password: UzBDUi9Vbi9ObWJ5dnVCUjJLSlFDNXJsN1JBZXVvVllta0t0V05CckRrRT0K
    username: admin
hanako@myubuntu:~$
```

##感想
- 本当に簡単に導入できるのでビックリした！
TypeORMのnullableまわりをどうにか回避する

## TL;DR

```ts
@Column({ nullable: true, type: 'varchar', width: 64 })
nickname: string | null;
```

とする。

## 問題

以下の記事の"2, デフォルトNULLのカラム"のような問題がある。

>TypeORMでエンティティを定義する際のガイドライン
>https://tech.bitbank.cc/typeorm-entity-guideline/

以下のように設定すると

```ts
@Column({ nullable: true })
nickname?: string;
```

nicknameはTypescript上は `string|undefined` だが、値はnullになっている。

記事中では、以下のような形にしていたが、`DataTypeNotSupportedError` としてエラーが発生した。

```ts
@Column({ nullable: true })
nickname: string | null;
```
```
{ DataTypeNotSupportedError: Data type "Object" in "User.nickname" is not supported by "postgres" database.
```

記事では`string`ではなく`Date`を使っていたが、`Date`の場合も同様だった。
データベースのエンジンが記事とは違うなどがあるのかもしれない。

## ~~解決（むりやり）~~

記事中にあるように`transformer`で変換するのは現状できないっぽいので、`setter / getter`で回避した。

```ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number

  @Column({ name: 'nickname', nullable: true })
  nicknameV?: string

  get nickname(): string | undefined {
    return this.nicknameV !== null ? this.nickname : undefined
  }

  set nickname(v: string | undefined) {
    this.nicknameV = v
  }
}
```

もうちょっといい感じのやり方あれば知りたい

## 追記

データベース内の型を明示すればよいのではと思ってやってみたらいけた。
これが1番よい気がする。

```ts
@Column({ nullable: true, type: 'varchar', width: 64 })
nickname: string | null;
```
Node.js: http.IncommingMessageをHTTP形式の文字列に変換する関数

Node.jsの`http.IncommingMessage`をHTTP形式の文字列に変換するデバッグ用関数を作ったので紹介します。

どんな関数かというと、次のように第一引数に`http.IncommingMessage`オブジェクトを渡すと:

```js
textifyRequest(req)
```

下記のような文字列を`Promise`で返す関数です:

```http
POST /foobar HTTP/1.1
Host: localhost:9000
Connection: close
Transfer-Encoding: chunked

hello
```

## `http.IncommingMessage`をHTTP形式の文字列に変換する関数

```typescript
const textifyRequest = (req: IncomingMessage): Promise<string> =>
  new Promise(resolve => {
    let text = `${req.method} ${req.url} HTTP/${req.httpVersion}\n`

    // serialize headers
    let nextKey = undefined as string | undefined
    for (let keyOrValue of req.rawHeaders) {
      if (nextKey === undefined) {
        nextKey = keyOrValue
      } else {
        text += `${nextKey}: ${keyOrValue}\n`
        nextKey = undefined
      }
    }
    text += '\n'

    // serialize body
    req
      .on('data', chunk => text += chunk)
      .on('readable', () => req.read())
      .on('end', () => resolve(text))
  })
```

## 使用例

```typescript
// HTTPサーバ
http.createServer((req: IncomingMessage, res: ServerResponse): void => {
  textifyRequest(req).then(console.log) // リクエストを受け取ったところに仕込む
  res.end()
}).listen(9000, () => {
  // 上で立てたHTTPサーバにリクエストを送ってみる
  const req = http.request({ host: 'localhost', port: 9000, method: 'POST', path: '/foobar' })
  req.write('hello')
  req.end()
})
```

実行結果

```http
POST /foobar HTTP/1.1
Host: localhost:9000
Connection: close
Transfer-Encoding: chunked

hello
```

## 注意点

HTTPボディを文字列バッファに積んで返すので、データサイズの大きいリクエストには不向きな実装になっています。
Unity玉転がしチュートリアル 2-2.プレイエリアの構成

# この記事の対象者
* Unity入門したい人
* 最初の一歩が踏み出せない人

# OSとか環境とか

* Windows 10 Pro
* macOS Mojave
* Unity 2019.2.8f1
* Rider 2019.2.2

# 補足
* 公式動画にて利用しているのはMacなので、Windowsユーザーはある程度脳内変換して見る事
* 筆者はWindows、Macの両方の環境で確認。Ubuntuとかでは検証してない。
* 基本Unityは英語メニューで利用
* 間違いがあったらツッコミ大歓迎

## 公式
https://unity3d.com/jp/learn/tutorials/projects/roll-ball-tutorial/setting-play-area

## プレイエリアの作成

4方向を壁で囲まれたシンプルで奥深いプレイエリア
という条件の元、プレイエリアを作成する

## オブジェクトの整理

**GameObject>Create Empty**で名前をWallsとしてGameObjectを作成する
→これは親オブジェクトとなり、壁群を整理する為に利用する

Projectの整理はフォルダ
Hierarchyの整理にはゲームオブジェクトを利用
→Emptyはフォルダのように利用出来るので覚えておく事

追加したらいつもどおり原点に配置

## 壁の追加

**GameObject>3D Object>Cube**で名前をWest wallとしてGameObjectを作成する

Wallsの子としてWast Wallを配置する

![addCube.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324639/5d16be65-e943-87cb-87f7-1084c133f803.png)


CubeのTransformでスケールのXYZをゲームエリアに合わせる
今回は
**Scale**
X:0.5
Y:2.0
Z:20.5

**Position**
X:-10
とする

上記値を入れると、プレイエリアにぴったりな壁が出来ます
※出来ない場合は、GroundのScaleを調整しましょう

![westWall.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324639/a44b5759-5c21-8551-a8db-4e3165de8593.png)


このまま4つの壁を同様の手順で追加しても良いが、せっかくなのでコピーする
Edit>Duplicateで複製が可能

複製したら名前をEast Wallへ変更する
**Position**
X:10
とすれば、逆側に壁が出来上がる

同じく残りの壁も作成する
パラメータはこんな感じです

**North Wall**
Scale
X:20.5
Y:2.0
Z:0.5

Position
Z:10

**South Wall**
Scale
X:20.5
Y:2.0
Z:0.5

Position
Z:-10

4つ配置したら、玉が外に出ていかないエリアが完成します
気の済むまでボールを動かしましょう

ここまで来るとある程度「あれ？ゲーム出来る？」って感じがします

![4thWall.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324639/bae7c333-e013-515f-38a3-d2fa88cfd227.png)
【JavaScript】map関数を用いたおしゃれな配列処理

## はじめに
決まった繰り返し処理といえばforですが、JavaScriptのES6以降では**map関数**を使ってもっと簡単でおしゃれな書き方で書けます。

map関数は各要素に対して決まった繰り返し処理をして、新しい配列を生成するのに使える便利な関数です

例として、`[1,2,3,4,5,6]`といったような各要素を二乗した配列を作ることを考えます。
<br>

## 通常のfor文から書き換え
まずは通常のfor文で書いてみます。

```javascript

const list = [1,2,3,4,5,6];
const newList = [];

for(let i = 0; i< list.length ; i++){
    newList[i] = list[i]*list[i];
}

console.log(newList); //[1,4,9,16,25,36]
```

list[i]が煩わしい気がします。
これをforEach文で書き直すとこうなります。

```javascript

const list = [1,2,3,4,5,6];
const newList = [];

list.forEach(function(item, index){
  newList[index] = item*item;
}

console.log(newList);
```

newListの宣言が煩わしい気がします。
これをmapで修正するとこうなります。

```javascript

const list = [1,2,3,4,5,6];

const newList = list.map(function(item){
    return item*item;
});

console.log(newList) //[1,4,9,16,25,36]
```

returnされたものが新しい配列の要素一つになります。

「**新しい配列はlistから生成するんだ**」ということが一瞬で伝わって、非常にすっきり書けていますね。
「**自分自身を更新(して複製)**」する時にMapは便利です。

これを使うとReactのDOMを複数生成するのに便利だったりします。
<br>

## 参考
この記事は「CodeShip」内での実際の質疑応答や指導・アドバイスの一部を基に作成しています。