OmniAICreator/Qiita-1.07M huggingface dataset:
JAWS DAYS 2020エンジョイ・オンライン！！～アウトプットしよう！～（2020年3月）

今までQiitaは読むだけで記事を書くことはありませんでした。
しかし、初めて投稿してみようと思います。

きっかけをくれたのは、本日開催された、
[『JAWS DAYS 2020　～サメの恩返し』](https://jaws-ug.doorkeeper.jp/events/105155)というオンラインイベントです。


このイベントは[JAWS-UG（AWS User Group - Japan）](https://jaws-ug.jp/)という、
AWSユーザのコミュニティーのメンバによって開催されました。
今年で10回目の開催とのことですが、私は初参加です。


#■私とAWSの出会い
私とAWSの出会いは2019年10月のことでした。
「顧客がAWSを希望しているので勉強して提案して」
との指示を上司から受けたのです。

私はインフラエンジニアでしたが、
AWSどころかパブリッククラウドについて全く知識がなく、
えっAWS？アマゾン？のような状況でした。

これは、ヤバイ、と思い勉強をはじめましたが、
私がインフラエンジニアとして問題と感じていた事が、
AWSで大きく改善できることに気付き、ひたすら勉強しまくりました。
顧客の環境をAWSに置き換えるとどうなるか考えるのが楽しくなり、
勝手に構成図を書いて妄想したりしていました。
解らないところはBlackBeltを読み漁りました。

結果、今年の3月に[「AWS Solution Architect Professional」](https://aws.amazon.com/jp/certification/certified-solutions-architect-professional/)の
資格を取得できるレベルまで成長できました。

そんなこんなで、今ではAWSの資料があれば読み漁り、
イベントがあれば参加する、といった生活となっています。

そういうこともあり『JAWS DAYS 2020　～サメの恩返し』
の視聴も実施した訳です。


#■『JAWS DAYS 2020』の感想

コロナの影響も跳ね返す初のオンライン開催で、
準備も大変な中、とても有意義な時間を提供して頂きました！！
最後は通信トラブル見舞われましたが、
きちんとバックアップで復旧させたところが、
さすがだ！と感じました。
まさに『Design for Failure』です。

登壇者の皆さんも運営の皆さんも、すごいです。

結局、明日が資格試験の受験日だというのに、
最初から最後まで視聴してしまった私です・・・・。


その中で、今回の初投稿のきっかけになったのは、
吉田真吾さんの
**「アウトプットしよう。これはあなたの成長の物語」**
という講演になります。

「アウトプットすることで自分に起こる30個のよいことを書き出してください」
という話から始まり、私も一生懸命に書き出していきました。
20個くらいはかけるんですが、最後の10個くらいはなかなか思い浮かばず、
絞り出す感じになりました。

でも、これがアウトプットを出し続けるための、
大事な「動機付け」になるんですね。

**自分の技術力を高めたい！**
**顧客の信頼を得たい！**
**収入を増やしたい！**
**評価されたい！**
**もてたい！？**

人には色々な「動機付け」がある訳ですが、
それが明確に意識できていれば、人は行動し続けることができる訳です。
きちんと「動機付け」を事前に考えるってのは大事なステップなんですよね。
これが出来ていないと何事も三日坊主で終わってしまうわけです。

私の場合、「動機付け」以前の話で、ROMってるだけで、
いままでアウトプットを出すことがありませんでした。

それじゃダメだと感じたので、Qiitaに初投稿することにしたんです。

『JAWS DAYS 2020　～サメの恩返し』は、
こんな形で私に良い刺激を与えてくれました。
また、技術的にもいろいろな新しい気付きをくれました。

顧客にAWSを使った新しい提案をしてみたい！
もっと勉強して、自分も登壇できるようなレベルになりたい！
色々と思いは膨らみます。

未視聴の方は、ぜひ来年参加されては如何でしょうか？

あと、JAWS-UG自体の日頃の勉強会の開催をオンラインで実施したら？
との話がライブ中にあったのですが、是非実現してもらえたら嬉しいです！

以上、『JAWS DAYS 2020』視聴感想と、私の初投稿でした！
GitLab 12.9のUnicornをPumaに変更する

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。


# 0. はじめに

GitLab 12.9がリリースされました。

GitLab 12.9 released with Vault App, Code Quality Reports and Group Deploy Tokens | GitLab https://about.gitlab.com/releases/2020/03/22/gitlab-12-9-released/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/6737514e-9ab8-61f1-fac5-e51a05c3d37c.png)

これまで、UnicornがGitLabのWebサーバーとして利用されてきました。しかし、バージョン12.9からUnicornから、Pumaを利用できるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15176/7c61c2e1-05d7-b3b3-24a9-6fa129b9e2d7.png)

メモリーは40%削減され、UnicornのマルチプロセスからPumaのマルチスレッドで動かすことができます。

# 1. なぜ、Pumaにするの？

Switching to Puma | GitLab
https://docs.gitlab.com/ee/administration/operations/puma.html

Pumaの方がマルチスレッドで動かす事ができるので、MRI Ruby will release the GVL (Global VM Lock) を避けることができ、多くのリクエストを裁くことができます。

# 2. 今回の設定の前提

omnibusインストールされているGitLabです。

# 3. Pumaに設定を変更する

Puma | GitLab 
https://docs.gitlab.com/omnibus/settings/puma.html

```jsonnet
unicorn['enable'] = false
puma['enable'] = true
```

# 4. reconfigureする

reconfigureコマンドを動かします。

```
sudo gitlab-ctl reconfigure
```

実行結果の最後の方は以下の通りです。

```
Warnings:
The version of the running postgresql service is different than what is installed.
Please restart postgresql to start the new version.

sudo gitlab-ctl restart postgresql

gitlab Reconfigured!
```
と出ていれば大丈夫でしょう。

# 5. unicornが動いていないのを確認する

```
# ps axwwu | grep unicorn
root     15293  0.0  0.0  12940   968 pts/0    S+   19:43   0:00 grep --color=auto unicorn
```

# 6. 変更してどうだったか

感覚的にしかわかりませんが、キビキビ動くように思います。
AWS SNS から送られてくる POST リクエストは text/plain なので body パラメーターをパースするときは注意する

# 概要
AWS SNS から来る POST リクエストの body パラメーターをパースしようとしたときに、上手く行かなくてはまったので、解決策を共有します。

# 解決策
AWS SNS は HTTPS POST リクエストでアプリケーションにメッセージを送信してくれます。
参考記事： [受信者が HTTP/S エンドポイントの場合のシステム間メッセージングに Amazon SNS を使用する](https://docs.aws.amazon.com/ja_jp/sns/latest/dg/sns-http-https-endpoint-as-subscriber.html#SendMessageToHttp.prepare)

その際に、body パラメーターにメッセージの内容が入っているのですが、Rails の params メソッドを使用してもパラメーターの中身を取得できませんでした。

```ruby
class SnsController < ApplicationController
  def message
    params # メッセージがない
  end
end
```

リクエストの中身を調べたところ、content-type に text/plain が設定されていたことが原因でした。
もし content-type に application/json が設定されていれば、パラメーターを params メソッドで取得できたはずです。

なので、下記のようにすることででパラメーターを取得できます。

```ruby
class SnsController < ApplicationController
  def message
    raw_body = request.body.read
    body_params = JSON.parse(raw_body)
  end
end
```

メッセージの文章はあくまで単純なテキストで、そのテキストが json の形式になっていることもあれば XML かもしれないし、あるいは何の形式にも当てはまらないテキストかもしれない、というのが AWS SNS の考え方なのだと思います。

考えてみれば AWS SNS はメッセージを送信するのが役割で、そのメッセージ文字列の形式を固定するのは責務の対象外なんだなと納得しました。

参考記事:
https://github.com/s12v/sns/issues/45
phpで、$a~$zの変数についてワンライナーで定義する

# はじめに
このコードはネタコードです。
\$a ~ \$zの変数について、ワンライナーで定義したいと思います。格納する値は5です。

# ワンライナー

```php
$a = ( $b = ( $c = ( $d = ( $e = ( $f = ( $g = ( $h = ( $i = ( $j  = ( $k = ( $l = ( $m = ( $n = ( $o = ( $p = ( $q = ( $r = ( $s = ( $t = ( $u =  ( $v = ( $w = ( $x = ( $y = ( $z = 5 )))))))))))))))))))))))));
```

# 出力すると
```shell-session
$ php -a
Interactive shell

php > $a = ( $b = ( $c = ( $d = ( $e = ( $f = ( $g = ( $h = ( $i = ( $j  = ( $k = ( $l = ( $m = ( $n = ( $o = ( $p = ( $q = ( $r = ( $s = ( $t = ( $u =  ( $v = ( $w = ( $x = ( $y = ( $z = 5 )))))))))))))))))))))))));
```
何も出力されず終わります。

## `get_defined_vars()`で中身を確認

\$a ~ \$zがちゃんと定義されているか、その中身を`get_defined_vars()`の出力で確認してみましょう。

```shell-session
php > $a = ( $b = ( $c = ( $d = ( $e = ( $f = ( $g = ( $h = ( $i = ( $j = ( $k = ( $l = ( $m = ( $n = ( $o = ( $p = ( $q = ( $r = ( $s = ( $t = ( $u =  ( $v = ( $w = ( $x = ( $y = ( $z = 5 )))))))))))))))))))))))));
php > var_dump(get_defined_vars());
array(33) {
  ["_GET"]=>
  array(0) {
  }
...
  ["a"]=>
  int(5)
  ["b"]=>
  int(5)
  ["c"]=>
  int(5)
  ["d"]=>
  int(5)
  ["e"]=>
  int(5)
  ["f"]=>
  int(5)
  ["g"]=>
  int(5)
  ["h"]=>
  int(5)
  ["i"]=>
  int(5)
  ["j"]=>
  int(5)
  ["k"]=>
  int(5)
  ["l"]=>
  int(5)
  ["m"]=>
  int(5)
  ["n"]=>
  int(5)
  ["o"]=>
  int(5)
  ["p"]=>
  int(5)
  ["q"]=>
  int(5)
  ["r"]=>
  int(5)
  ["s"]=>
  int(5)
  ["t"]=>
  int(5)
  ["u"]=>
  int(5)
  ["v"]=>
  int(5)
  ["w"]=>
  int(5)
  ["x"]=>
  int(5)
  ["y"]=>
  int(5)
  ["z"]=>
  int(5)
}
```
きちんと定義できていることが確認できました。


# 説明
phpの式について調べていたら、こんな記述を見つけました。

> 代入式は、それ自体、代入値を評価します。 この場合、その値は 5 になります。 このことは、実際には、`$a = 5` は、それが何をするかによらず、 値 5 を有する式であることを意味します。 つまり、 `$b = ($a = 5)` のように書くことは、 `$a = 5; $b = 5;` と書くのと 同様なのです。
ref: https://www.php.net/manual/ja/language.expressions.php

phpにおける式の定義は、"値のあるもの全て"です。
代入式もこの定義に漏れず値を持っています。`$a = 5;`の代入式それ自体が持つ値は5であり、`$b = ( $a = 5 );`と記載した場合、それはすなわち`$a = 5; $b = 5;`と同意となります。

ということで、それを\$a ~ \$zまで入れ子にして繰り返したのが、本ワンライナーでした。

## 追記
この長い式も、値を持っています。
再帰的に処理され、最終的には`$a = 5`という式になります。

```shell-session
php > echo $a = ( $b = ( $c = ( $d = ( $e = ( $f = ( $g = ( $h = ( $i = ( $j  = ( $k = ( $l = ( $m = ( $n = ( $o = ( $p = ( $q = ( $r = ( $s = ( $t = ( $u =  ( $v = ( $w = ( $x = ( $y = ( $z = 5 )))))))))))))))))))))))));
5
```
"echo"で式自体の値を吐き出させると、5が出力されます。


# おわりに
本ワンライナーは思いつきで書いたネタコードです。
プロダクトのコードではこんなことはせずに配列を使いましょう。

## 追記
よければコメント欄もご覧ください。
jQuery 基本集①~導入~

#jQuery 基本集①~導入~
**※ Ruby on Rails版です。**
##gemを使用した導入方法
###Gemfileにgemを追加
Gemfileの一番下の行に、

```ruby
gem 'jquery-rails'
```
を追加して、コマンドラインに『bundle install』を入力して、追加したgemをインストール。
直後に『rails s』を入力してサーバーを再起動させること。

###インストールしたgemの読み込み
/app/assets/javascripts/application.jsに次のコードを追加して保存する。

```js
//= require jquery　
//= require jquery_ujs
//= require_tree .
```
**※jsコードは上から読み込まれる為、//= require_tree .よりも上に記述すること**

用意はこれだけ:santa:

##公式サイトからダウンロードする方法
以下のリンク先にjQueryを読み込むための記述があるので移動
**[リンク先](https://developers.google.com/speed/libraries/#jquery)**

リンク先のページをスクロールしていき、jQueryという見出しと、その下の『**3.x snippet**』という記述があるので、**3.x snippet**の下のscriptタグに囲まれた記述をコピーする。<img width="1360" alt="スクリーンショット 2020-03-28 19.19.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/e95dbf24-a9df-c67a-724f-fd31305e4175.png">

コピーした記述をhtmlファイルのhead内に貼り付ける(貼り付けたコードは三行目)。

```html
<head>
  <meta charset="utf-8">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="./main.js"></script>
  <title>ki-ra-co</title>
</head>
```
Hamlの場合(貼り付けたのは５行目)

```haml
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title ki-ra-co
    %script{src: "https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"}
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'

  %body
    = yield
```

##jQueryってどこに書けばいいの！？
####HTMLファイルに直接記述する場合

```html
<script type="text/javascript">

/* この中にjQueryのコードを記述 */

</script>
```
####hamlファイルに直接記述する場合

```haml
:javascript
  $(function() {

  });
```

####JavaScriptのファイルを作って記述する場合
①HTMLの中に直接記述せず、jsの拡張子で別のjsファイルを作成して記述する
②操作対象のHTMLファイルと紐付けする。HTMLのhead内にリンク先を記述する（４行目のこと）。

```html
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!-- headの中に以下のように記述 -->
<script type="text/javascript" src="js/作成したjsファイル名"></script>
</head>
```
注意としては**先にjQueryを読み込む記述**をすること。

今回はここまで:santa:
a, bの最小公倍数と最大公約数の積がabであることを利用した競技プログラミング解法

自然数 $a, b$ の最小公倍数と最大公約数の積が $ab$ であることを利用すると、競技プログラミングで最小公倍数を求める必要が生じたときに役立つ。具体的には、$a, b$ の最小公倍数を $l$ 、最大公約数を $g$ とおくと $ab = gl$ が成り立つため、

```math
l = \frac{ab}{g}
```

で最小公倍数を求められる。

例えばAtCoderの[ABC148  C - Snack](https://atcoder.jp/contests/abc148/tasks/abc148_c) の解答で役立つ。問題文を見ると分かる通り単に最小公倍数を求める問題である。上式を利用すると解答は以下のように書ける（Pythonによる解答です）。

```python
def gcd(a, b):
    while a:
        a, b = b % a, a
    return b

A, B = map(int, input().split())
print(A // gcd(A, B) * B)
```

# 補足：a, bの最小公倍数と最大公約数の積がabであることの証明

$a, b$共に $g$の倍数であるため

```math
a = ga' \\
b = gb'
```

を満たす互いに素な自然数 $a', b'$が存在する。また、$l$ は$a$ の倍数であるため

```math
l = cga'
```

を満たす自然数 $c$ が存在する。同様にして、

```math
l = dgb'
```

を満たす自然数 $d$ が存在する。これらより、

```math
cga' = dgb' \\
ca' = db' \\
```

が成り立ち、$ca'$ は $b'$ の倍数であることがわかる。ここで、$a', b'$ は互いに素であるため $c$ は $b'$ の倍数である。$c$ は最小公倍数 $l$ の因数であるため $c = b'$ である。よって

```math
l = ga'b'
```

である。両辺に $g$ をかけると

```math
gl = ga'gb' \\
gl = ab
```

である。以上より証明された。

# 参考文献

【標準】最大公約数と最小公倍数の積 | なかけんの数学ノート https://math.nakaken88.com/textbook/standard-product-of-greatest-common-divisor-and-least-common-multiple/#i
Javascript基本集(4)~DOM操作~

#Javascript基本集(4)~DOM操作~

**DOM**とはDocument Object Model(ドキュメントオブジェクトモデル)の略称で、
HTMLを解析し、データを作成する仕組みのこと。

HTMLは階層構造になっており、DOMによって解析されたHTMLは、階層構造のあるデータとなる。
このことを、**DOMツリー**やドキュメントツリーと呼び、JavaScriptを使うとDOMツリーを操作してCSSを変更したり、要素を増やしたり、消したりすることが可能。
DOMツリーの一部のことを、**ノードオブジェクト**と呼ぶ。
<img width="305" alt="スクリーンショット 2020-03-28 18.40.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/1a01146a-6d02-4d3f-1df1-4092ba7c6943.png">

##ノードの取得

####①document.getElementById("id名");
引数に渡したidを持つ要素を取得出来る。

####②document.getElementsByClassName("class名");
同じclassを持つ要素を全て取得することが可能。

####③document.querySelector("セレクタ名");
引数で指定したセレクタに合致するもののうち一番最初に見つかった要素1つを取得する。

##イベント
HTMLの要素に対して行われた処理要求のこと。
「ノードオブジェクト」に「イベント」が起きた時、「関数」を実行出来る。
一つのイベントと一つの関数を紐付ける仕組みのことを**イベントリスナ**と呼ぶ。
####①addEventListener

```js
(ノードオブジェクト).addEventListener("イベント名", 関数);
```
addEventListenerは、あるノードオブジェクトに対して、イベントリスナを追加するメソッド。

####②window.onload
ブラウザは上から順に実行をするため、document.getElementById("id名")等のJavaScriptのコードを読み込む際、まだhtmlファイルのheadタグ内までしか読み込まれておらず、bodyタグ内にあるコードは読み込まれないので、ノードオブジェクトは取得できない。
ページの読み込みが終わったらjsの中身を実行するようにできるのが、**window.onload**。


例は２つ

```js
window.onload = function() { 

  (ノードオブジェクト).addEventListener("イベント名", 関数); 

};
```

```js
window.addEventListener('load', function() { 

  (ノードオブジェクト).addEventListener("イベント名", 関数);

 });
```

####③innerHTML
innerHTMLを使用するとHTML要素の中身を書き換えることが出来る。

```js
window.addEventListener("load", function() {
  
  // テキストの要素を取得し、変数で定義
  let btn = document.querySelector("#Button");
  let changeText = document.querySelector("p");
  // ボタンをクリックしたらテキストが置換される
  btn.addEventListener("click", function() {
    changeText.innerHTML = '変更されました';
  });

});
```

####④classList.add
あらかじめ用意されているクラスを追加することが出来る。

```js
// Buttonを取得して、変数で定義
let btn = document.querySelector("#Button");

// クラス追加を押したらクラスが追加される
btn.addEventListener("click", function() {
  changeText.classList.add("クラス名");
});
```

####⑤classList.remove
指定したクラスを削除することが出来る。
　　
他にもありますが、今回はここまで:santa:
[Python]リスト内包表記を使おうとして、小一時間ハマった

# はじめに
Pythonの勉強中で、リスト内包表記を使ってみようと思ったら、小一時間ハマりました。
Pythonの関数は参照渡しだと思ってしまったのが原因だと思います。
（筆者が「参照渡し」を誤解しているかもしれないですが）

実行結果を見比べれば、何が起きたか分かります、きっと。

# ハマったコードと実行結果
冒頭の関数`findDiff()`を作って、追加要素と削除要素を調べようとしました。
しかし、関数から戻ったら、リストの要素が消え（たように見え）ました。

``` py
def findDiff(oldList, newList, adds, dels):
	adds = [x for x in newList if oldList.count(x) < 1]
	dels = [x for x in oldList if newList.count(x) < 1]

oldList = [1,2,3,5,6,7,8,9]
newList = [1,2,4,5,6,7,8,10]
adds = []
dels = []

print(adds)
print(dels)
findDiff(oldList, newList, adds, dels)
print(adds)
print(dels)

#>>> []
#>>> []
#>>> []
#>>> []
```

# 修正したコードと実行結果
冒頭の関数`findDiff()`のみ、修正しています。

``` py
def findDiff(oldList, newList, adds, dels):
	for x in newList:
		if oldList.count(x) < 1:
			adds.append(x)
	for x in oldList:
		if newList.count(x) < 1:
			dels.append(x)

oldList = [1,2,3,5,6,7,8,9]
newList = [1,2,4,5,6,7,8,10]
adds = []
dels = []

print(adds)
print(dels)
findDiff(oldList, newList, adds, dels)
print(adds)
print(dels)

#>>> []
#>>> []
#>>> [4, 10]
#>>> [3, 9]
```

# 終わりに
記事を書いた後に調べたら、先人の知恵が既にありました。。。

- https://qiita.com/ponnhide/items/cda0f3f7ac88262eb31e
- https://qiita.com/raccy/items/d4c5e7995a8fc90109ee
ModalBottomSheetでうまくproviderが動作しなかったケースの解決策

## うまく動作しなかったコード
`Provider.of`での取得がうまく動作しませんでした。

```dart:main.dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChangeNotifierProvider(
        create: (context) => TaskStore(),
        child: TasksScreen(),
      ),
    );
  }
}
```

```dart:task_screen.dart
class TasksScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.teal,
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showModalBottomSheet(
              context: context, builder: (context) => AddTaskScreen());
        },
      ),
    );
  }
}
```

```dart:task_store
class TaskStore extends ChangeNotifier {
  List<Task> tasks = [
    Task(name: "buy milk."),
  ];

  void addTask(String taskTitle) {
    Task task = Task(name: taskTitle);
    tasks.add(task);
    notifyListeners();
  }
}
```


```dart:add_task_screen.dart
class AddTaskScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    String textValue;

    return Container(
      child: Container(
        child: RaisedButton(
          child: Text("Add"),
          onPressed: () {
            Provider.of<TaskStore>(context, listen: false).addTask("test task");
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}
```

## 実行時のエラー
```
════════ Exception caught by gesture ═══════════════════════════════════════════════════════════════
The following ProviderNotFoundException was thrown while handling a gesture:
Error: Could not find the correct Provider<TaskStore> above this AddTaskScreen Widget

To fix, please:

  * Ensure the Provider<TaskStore> is an ancestor to this AddTaskScreen Widget
  * Provide types to Provider<TaskStore>
  * Provide types to Consumer<TaskStore>
  * Provide types to Provider.of<TaskStore>()
  * Ensure the correct `context` is being used.

```

Providerがみつからないと。

## 解決策
`ChangeNotifierProvider` の`child` に `MaterialApp` を設定します。

```dart:main.dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => TaskStore(),
      child: MaterialApp(
        home: TasksScreen(),
      ),
    );
  }
}
```

`ModalBottomSheet` の階層的に、MaterialAppの下層という位置づけなのでしょうか。


何か間違ってたらご指摘いただけると助かります。
Python で Google Spreadsheets (など)の無人操作

# TL; DR

 - Google Spreadsheets の表を Python プログラムを使って無人操作する方法を書きました。
 - [公式 Quick Start](https://developers.google.com/sheets/api/quickstart/python) は人間が介在する OAuth2 のやり方だけど、ようはこれの無人版です。
 - サービスアカウントというものを作って、それに必要な権限を与え、そのアカウントの秘密鍵を使ってアクセスします。

# スプレッドシートの準備

これは何も特別なことはありません。Google Drive に適当なシートを作成して、ファイルの ID だけ控えておいてください。

# プロジェクトとサービスアカウント

各種ドキュメントを操作するには当然権限が必要です。プログラムから操作する場合は、大雑把に行って2とおりの権限獲得の手法があります。

 - 一時的に人間の許可を得て、その人間のアカウントで操作
 - 権限を与えられた **機械ようのアカウント** で操作
 
ざっくり言うと前者はインタラクティヴなソフトで使う方法で、後者は自動化システムで使う方法です。今回は後者の方法を使います。ここで「機械ようのアカウント」を [**サービスアカウント**](https://cloud.google.com/iam/docs/service-accounts?hl=ja)と言います。つまり、まずはサービスアカウントを作り、必要な権限を与える必要がります。だいたい以下の手順です。

 1. [GCPのコンソール](https://console.cloud.google.com) に行って、プロジェクトを作ります。
 2. GCPの左上のハンバーガーメニュー > [IAMと管理](https://console.cloud.google.com/iam-admin) > サービスアカウント > サービスアカウントを作成
 3. 入力は必須項目だけで良いと思います。`name@project.iam.gserviceaccount.com` というアカウントができます。
 4. アカウントを作ると秘密鍵 (private key) をダウンロードできると思います。JSON形式でダウンロードしてください。
 5. **このアカウントに対して**、操作したいファイル(スプレッドシート)の操作権限を与えてください(=共有してください)。与え方は通常の人間向けの権限操作といっしょです。
 6. ハンバーガーメニュー > APIとサービス > ダッシュボード > +APIとサービスを有効化 と進み、`Google Sheets API` を有効化してください。

# パッケージのインストール

たぶんこれだけでいいはず。

```shell
$ pip3 install google-api-python-client google-auth-oauthlib oauth2client
```

# コード

シートの A1 セルに test と書き込むコードです。たったこれだけ！

```python
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials

PRIVKEY_FILE = "projectname-*********.json"  # ダウンロードした秘密鍵
SPREADSHEET_ID = "********"                  # シートのファイルのID
SCOPE = ["https://www.googleapis.com/auth/spreadsheets"]

creds = ServiceAccountCredentials.from_json_keyfile_name(PRIVKEY_FILE, SCOPE)
service = build("sheets", "v4", credentials=creds)
sheet = service.spreadsheets()

result = sheet.values().update(
    spreadsheetId=SPREADSHEET_ID,
    range="a1",
    valueInputOption="RAW", # USER_ENTERED とすると式を式として入力できる(例: "=sum(a1:a100)")
    body={"values": [["test"]]}).execute()
```

# おわりに

Ruby でも同じくらい簡単にできました。
1ヶ月でwebサービスを2つ作った


# はじめに

プライベートと仕事で、2つほどwebサービスを作ったので、ノウハウをまとめます。
（※暇な時間にちょこちょこやって約1ヶ月でした。）

短時間で作れている理由の一つとしてNocodeツールを駆使しました。
Nocodeツールとは、名前の通り、コードを1行も書かずにサービス開発が作れるツールです。

この記事ではNocodeに間することをメインでまとめていきます。

nocode meetupなどイベントなどもぼちぼち盛んです。
https://nocoders-japan.connpass.com/event/167872/

## Nocodeの何が良いか？
大きくはこの2つかと個人的には思います。

- 誰でも簡単にサービスが作れる
- 価値検証が素早くできる

### 誰でも簡単にサービスが作れる
<img width="1618" alt="スクリーンショット 2020-03-28 18.08.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/dde3f144-33d6-9ce6-fae5-fba33c750145.png">

Nocodeツールでは、プログラミングを必要とせずに作ることができるので、エンジニアに限らず非エンジニアでも可能です。
プログラミングの民主化ですね。

### 価値検証が素早くできる
DBの構築や、デプロイ先の選択、サーバサイドの開発など、サービスを作るにあたって多くの環境構築や、考えることが必要です。
ですが、Nocodeツールでは上記が全て内包されていて、しかもGUIで行うので、小さいな準備で、ハマりどころも少なく開発できます。
なので、最初の開発ではコーディングするより早いと感じています。
（大規模や中規模の開発になると、プログラミングしたほうが早いと感じています。）

こういった理由から、サービスの価値検証が素早くできます。

めっちゃ時間かけて作ったサービスが使われないとなるなら、早い段階で価値検証をしたいですよね・・・

# 1. Our Favorite Books
ここからは作ったサービスの紹介です。1個目の作品がこちらです。
[OurFavoriteBooks](https://celebritybooklist.bubbleapps.io/)

![ourfavoritebooks.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/3ce20bfb-c6cb-581a-a80a-a2848ca6167d.gif)

### サービス概要
サービス内容としては、有名人がオススメしている書籍のまとめサイトです。
有名人がツイッターや、インタビューメディアなどで読んでよかった書籍を紹介していますが、
その情報が散らばっていて検索するのが大変だったため、1つのサイトで管理したいという思いから作りました。

### 制作時間
webサービス自体はデザイン含めて、だいたい4時間ほどかかりました。
そのあと、暇な時間を使って有名人の書籍を検索しては乗せてというのを行いました。

### どうやって作ったか？
Nocodeツールの[bubble](https://bubble.io/)を使って作っています。
apiなど使っていないためこちらは一切コーディングをしていません。


# 2. BBBTool
社内ツールのため作りました。
（※こちらは複数人で作っています。）
こちらは、Nocode × プログラミングで作っています。

![BBBTool.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/6c543364-a6b7-3061-bf8f-08c4db8de406.gif)

### サービス概要
社内で手作業でやっていた仕事を全て自動化するために作ったツールです。
（サービス内容自体は今回は割愛します。）

### 制作時間
画面自体はredashでの分析画面も含めて、だいたい20時間ほどかかりました。
(要件組み直したり下部分があって少し時間かかってます。)

### どうやって作ったか？
こちらのサービスの構成は以下の構成になっています。
![bbbtool あーき.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234760/6702d522-f0ac-d204-3ab1-454c5dbb0f51.png)

フロントの、表示部分や、データの分析部分をNocodeで作っていて、
裏側は機械学習やAPIなどを作っています。

全体の流れとしては、

- ユーザが写真をslackにアップロード
- アップロードされた写真が自動でCloud Storageにupload
- 機械学習によって画像解析し、解析結果をDBに保存
- フロントからapiを叩くことで、DBの結果を返却

といった流れです。

こちらも機械学習の部分が一番重要なところで、他はそこまで重要ではありませんでした。
なので、そういったのの時短のために、nocodeツールやBIツール（redash）が使えて便利です！

# 最後に
技術検証という意味も含めNocodeツールを約1ヶ月ほど触れてみました。
使ってみた感想として、プロトタイプ開発や、小規模開発にはすごく良いと感じました。

中規模から大規模になる場合は、設計などエンジニアの腕の見せ所になってくるかと思います。
さすがNocodeでロジック大量に書くのはメンテナンスがしづらいと感じました。
カプレカ数で遊ぶ

カプレカ数という概念があることを某チャットで知りました。

* カプレカ数（Wikipedia）  
  <https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%97%E3%83%AC%E3%82%AB%E6%95%B0>

Wikipediaによると2種類の定義があるようですが、そのうち「数字の各桁をシャッフルしてできる数のうち、最大のものから最小のものを引き算して、元の数字と同じになるもの」という2つめの定義のほうをHaskellで実装して遊んでみました。

まず、「数字の各桁をシャッフルしてできる数のうち、最大のものから最小のものを引き算する」関数をさくっと書きます。

```haskell
module Kaprekar where

import Data.List (permutations, unfoldr)

toDigits :: Int -> [Int]
toDigits n = unfoldr moddiv n
  where
    moddiv i =
      if i == 0
      then Nothing
      else Just ((i `mod` 10), (i `div` 10))

toInt :: [Int] -> Int
toInt s = sum $ zipWith f s [0..]
  where f x i = x * 10^i

arrange :: [Int] -> [Int]
arrange = (map toInt) . permutations

kaprekar :: Int -> Int
kaprekar = diffK . arrange . toDigits
  where diffK xs = maximum xs - minimum xs 
```

Wikipediaによると「6174」はカプレカ数らしいので、確かめてみます。

```haskell
λ> kaprekar 6174
6174
```

確かに同じ数になっていますね。カプレカ数でない「6173」だと一致しません。

```haskell
λ> kaprekar 6173
6264
```

> （追記）
> nobsun にもっとかっこいいのを教えてもらいました。
> https://twitter.com/nobsun/status/1243939964137562113
> 
> ```haskell
> kaprekar :: Int -> Int
> kaprekar = (subtract . read <*> read . reverse) . sort . show
> ```

さらにWikipediaによると、どんな数もこの操作を繰り返すといつかはカプレカ数になるそうです。そこで、カプレカ数になるまで`kaprekar`を繰り返す関数`kaprekaring`を書いて確かめてみます。

```haskell
kaprekaring :: Int -> [Int]
kaprekaring n = n : unfoldr isKaprekar n
  where
    isKaprekar i =
      if kaprekar i == i
      then Nothing
      else Just (kaprekar i, kaprekar i)
```

やはりWikipediaに載っている例として、「2005」で試してみます。

```haskell
λ> kaprekaring 2005
[2005,5175,5994,5355,1998,8082,8532,6174]
```

Wikipediaの例と同じ列が得られました。「2005」の場合は8回の`kaprekar`でカプレカ数に収束するようです。

こうなると、カプレカ数に収束する列がどれくらいまで長くなりうるのかが気になってきます。4桁のすべての数字についてカプレカ数に到達するまでの列をもとめて、その最大の長さを割り出してみます。

```haskell
λ> fst $ maximum $ map ((\xs -> (length xs, xs)) . kaprekaring) [1000..9999]
8
```

ずいぶん拍子抜けする感じですが、4桁の数はどれも高々8回の繰り返しでカプレカ数に到達してしまうようですね。

ほんとかな。ちょっと不安なので、1回でカプレカ数になるもの（つまりカプレカ数そのもの）から、8回でカプレカ数になるものまで、それぞれどれくらいの個数があるのか見てみます。

```haskell
λ> [length $ filter (\(x,_) -> x == i) $ map ((\xs -> (length xs, xs)) . kaprekaring) [1000..9999] | i <- [1..8]]
[1,365,587,2124,1124,1311,1508,1980]
```

4回でカプレカ数に収束するものが2124個でいちばん多いようです。先頭の1は4桁のカプレカ数の総数なので、すでに判明している「6174」だけという事実を表しています[^1111]。

[^1111]: ちなみに、`kaprekar　1111` の値は「0」で、0は自明なカプレカ数なので、ここでは「1111はカプレカ数0に収束」と考えることにします。つまり上記のリストでは2回のところに計上されています。

各回の総数を合計すると4桁の数の総数になるので、たぶんあってそう。

```haskell
λ> sum [1,365,587,2124,1124,1311,1508,1980]
9000
```
MySQL の interval hour/minute 加減算で小数を与えると round される

## 概要

- MySQL の時刻計算で `interval` を使うと時刻の加減算ができる
  - 例: `NOW() + interval 1 hour`
- `0.4 hour` `0.6 minute` のように小数を与えると、整数に四捨五入されて計算される
- second の場合は四捨五入されない

## 検証環境

- Amazon Aurora (5.6.mysql_aurora.1.19.5)
- MySQL 5.6.47

## 検証

`2020-01-01 00:00:00` に小数の hour, minute, second を足してみる。

### hour

```
MySQL> select '2020-01-01 00:00:00' + interval 0.4 hour;
+-------------------------------------------+
| '2020-01-01 00:00:00' + interval 0.4 hour |
+-------------------------------------------+
| 2020-01-01 00:00:00                       |
+-------------------------------------------+
1 row in set (0.01 sec)

MySQL> select '2020-01-01 00:00:00' + interval 0.5 hour;
+-------------------------------------------+
| '2020-01-01 00:00:00' + interval 0.5 hour |
+-------------------------------------------+
| 2020-01-01 01:00:00                       |
+-------------------------------------------+
1 row in set (0.01 sec)
```

- + 0.4 hour = + 0 hour
- + 0.5 hour = + 1 hour

### minute

```
mysql> select '2020-01-01 00:00:00' + interval 0.4 minute;
+---------------------------------------------+
| '2020-01-01 00:00:00' + interval 0.4 minute |
+---------------------------------------------+
| 2020-01-01 00:00:00                         |
+---------------------------------------------+
1 row in set (0.00 sec)

mysql> select '2020-01-01 00:00:00' + interval 0.5 minute;
+---------------------------------------------+
| '2020-01-01 00:00:00' + interval 0.5 minute |
+---------------------------------------------+
| 2020-01-01 00:01:00                         |
+---------------------------------------------+
1 row in set (0.00 sec)
```

- + 0.4 minute = + 0 minute
- + 0.5 minute = + 1 minute

### second

```
mysql> select '2020-01-01 00:00:00' + interval 0.4 second;
+---------------------------------------------+
| '2020-01-01 00:00:00' + interval 0.4 second |
+---------------------------------------------+
| 2020-01-01 00:00:00.400000                  |
+---------------------------------------------+
1 row in set (0.00 sec)

mysql> select '2020-01-01 00:00:00' + interval 0.5 second;
+---------------------------------------------+
| '2020-01-01 00:00:00' + interval 0.5 second |
+---------------------------------------------+
| 2020-01-01 00:00:00.500000                  |
+---------------------------------------------+
```

second の場合は round は行われず、小数部分はミリ秒として扱われていた。
macintosh replace

Mac Book Pro(Retina 13-inchi mid 2014)
2.6Ghz intel Core i5
16GB 1600 MZH DDR3
Intel Iris 1536MB
macOS High Sierra 10.13.6

から、別のMac にtime machineでバックアップをして、導入しようとした。

<img width="424" alt="mac2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/3bf420bf-79c0-c1fd-6eb0-d6d950c9de1b.png">

だめだ。

<img width="434" alt="mac.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/a5d245c8-d9f0-4c69-5b56-10b6417e4b52.png">

フォーマットして、OSを導入しようとした。

エラーでできない。

今ここ。

バックアップから Mac を復元する
https://support.apple.com/ja-jp/HT203981

Mac の起動時のキーコンビネーション
https://support.apple.com/ja-jp/HT201255

macOS 復元について
https://support.apple.com/ja-jp/HT201314

#昔話

Mac Book Proを持ってドイツのニュールンベルグへ行った時のこと。
ディスクから起動しなくなった。

ニュルンベルグの街中のパソコンショップで、Apple のmac Bookを売っているお店に相談にいった。

お店のWi-Fiを使って、OSから導入し直す方法を教えてもらった。

やり方を教えてもらって（自分の機材は動かないのでネットで調べられる）作業は自分で行った。

３時間ほど、その場所で、何度かやりなおしながら、OSの導入に成功した。

ドイツがすごく好きになった。
応用 Lesson2　検索力についてのまとめ

#応用カリキュラム Lesson2対応　リンク集

エンジニアにとって検索力がとても重要なことを学び、
テキストにあるワードを検索してみました。

##初投稿
まずQiitaの使い方からよく分かりませんので、その辺は徐々に。
とりあえず自身のアウトプットとして書きます。
どなたかの何かのお役に立てたら光栄です。


では、ワードごとにリンクを貼っていきます。
あえて、ワードに対する答えは載せません。
あくまでリンク集です。（自分のためにも…）


##【リンク集 ~Link Page〜】

###1. jQueryのメリット・デメリットは簡単に言うと？

＜検索ワード＞
　jQuery メリット


＜参考サイト＞
　AtoOne 様
　https://www.atoone.co.jp/column/10176/

###2. Queryは最近のトレンドの中でどのような立ち位置か？

＜検索ワード＞
　jQuery トレンド　立ち位置

＜参考サイト＞
　Hideout der Eremit 様
　https://dereremit.jp/archives/260

###3. deviseとは簡単に言うと？

＜検索ワード＞
　deviceとは

＜参考サイト＞
　キツネの惑星 様
　https://kitsune.blog/rails-devise

###4. deviseと同様な機能で他によく使われるものは何か？違いは何か？なぜdevise以外にそれが生まれたか？

これ、めちゃくちゃ苦戦しました。
もっと分かりやすい、的確なサイトがあると思います。

＜検索ワード＞
　rails　認証 gem トレンド　…他多数💦

＜参考サイト＞
　Tech Blog 様
　https://www.for-engineer.life/entry/rails-sorcery/

###5. unicornとは簡単に言うと何か？
###6. unicornと同様な機能で他によく使われるものは何か？違いは何か？なぜunicorn以外にそれが生まれたか？

＜検索ワード＞
　unicornとは

＜参考サイト＞
　@takahiro1127 様
　https://qiita.com/takahiro1127/items/fcb81753eaf381b4b33c

####〜気づき〜
検索力にはある程度自信を持っていましたが、
信憑性のある、確からしい情報を得るためには
テクニックがあることを知りました。

同時に自分の無力さに愕然（笑）

今後も学習のノート代わり、アウトプットとして活用させていただきます。
npmって？

# npmって？
node package manager

Node.jsで使うパッケージを管理するために使う
Nodeをインストールすると一緒にインストールされる

# npmのインストール

僕はMacOSにnodebrewでインストールした

nodebrewはNode.jsのバージョン管理システム
Homebrewでインストールする

```
$ brew install nodebrew
```
```
$ echo "export PATH=$HOME/.nodebrew/current/bin:$PATH" >> ~/.bash_profile
```
```
$ source ~/.bash_profile
```
```
$ which nodebrew
```
これでnodebrewのパスが表示されればOK

この後，nodeをインストールして，その後npmをインストールする

# npmコマンド

インストールディレクトリを確認
```
npm root
```

インスロールしたパッケージをみる(グローバル)
```
npm ls -g --depth=0
```

インスロールしたパッケージをみる(ローカル)
```
npm ls --depth=0
```
Rails ×　Docker　ログに「Cannot render console from Allowed networks」と出力される対処法

# ログに「Cannot render console from Allowed networks」と出力される対処法

### 環境
ruby 2.5.1
rails 5.2.4
docker 19.03.8

Ruby on Railsの開発環境で、DockerかVagrantを使っていて、”Cannot render console from 172.20.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255″ 「このIPアドレスではレンダリングできない」と言われた場合

# うぉおおん？

```
Started GET "/" for 172.20.0.1 at 2020-03-28 09:15:23 +0000
web_1  | Cannot render console from 172.20.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
```
[![Image from Gyazo](https://i.gyazo.com/4e85795d30e274b143394f115a4b5e82.png)](https://gyazo.com/4e85795d30e274b143394f115a4b5e82)

# 対処法は簡単だった

Webコンソールの設定で172.20.0.1ネットワークをホワイトリストに登録する

[ホワイトリストとは？](https://yougo.ascii.jp/caltar/%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88%E3%83%AA%E3%82%B9%E3%83%88)

`config/environments/development.rb`に`config.web_console.whitelisted_ips = ‘172.20.0.1’`を追加（IPアドレスは自身のログに書いてあるIPアドレスを記述）

```rails:config/environments/development.rb
config.web_console.whitelisted_ips ='172.20.0.1'
```
[![Image from Gyazo](https://i.gyazo.com/012997c5a11ce73a25232854796427ce.png)](https://gyazo.com/012997c5a11ce73a25232854796427ce)

# これで解決しました

## docker →　kubernetesに関してこれから投稿していきます。

##[docker公式](https://docs.docker.com/)
SQLArchemyの基本的な構文など

##SQLArchemy
SQLArchemyを少し勉強して、頭の中に入らなかったのでここに書き残しておきます

###engine
どうやってDBに接続するか、設定内容を保持したものがengine
####データベースへの接続
```
create_engine(接続するDB,ログ出力の有効化フラグ)
```
###クラスの定義
####テーブルの作成
```
from sqlalchemy.ext import declarative　#declartiveをインポート
Base = declarative.declarative_base()  #Baseクラスを作成
from sqlalchemy　import フィールド定義に使用するデータ型をインポート

class 派生モデルクラス(Base):
    __tablename__="テーブル名"　#テーブルを定義
    カラム名 =　Column(型,オプション)
    id=Column(Integer, primary_key=True)
    name=Column(String(255))
    def __repr_(self):
        return "<派生クラス名('型,型,型')>" % (self.カラム,self.カラム, self.カラム)
    
      
```

###テーブルの作成
metadataはテーブルなどの情報を登録するためのオブジェクト

```
Base.metadata.create_all(engine) #引数は作成したengine
```

##セッションを用いて操作する
SQLAlchemyはセッションを通して取得や更新を行う。値を操作するにはほぼsession.commit()を用いる

####セッションの作成

```
from sqlalchemy.orm import sessionmaker   #インポート
Session = sessionmaker(bind=engine)  #engineを関連付けしてSessionクラスを作成
session = Session()   #インスタンスを作成
```

####トランザクション
派生したクラスのオブジェクトを生成して、session.add()の第一引数に渡す

```
インスタンス = クラス(カラム=値,)  #クラスインスタンスの生成
session.add(インスタンス)　　#インスタンスをセッションに持たせる
session.add_all([インスタンス,インスタンス])　　#複数の値を持たせる
session.commit()  #オブジェクトの更新を反映させる
```

####オブジェクトの取得

```
query = session.query(クラス)　　#Queryオブジェクトの生成
for 変数　in query.all():  #すべてのオブジェクトを取得
query.get(プライマリーキー)　　#プライマリーキーを用いてオブジェクトを取得
query.filter(条件):  #条件を付けてオブジェクトを取得
```

####オブジェクトの更新

```
インスタンス　= query.get(key)  
インスタンス.カラム名 = 新しい値
session.commit()
```

####オブジェクトの削除

```
インスタンス　= query.get(key)  
session.delete(インスタンス)
session.commit()
```

##まとめ
外出制限中にいくつかinputしようと思います。
もしなにかご指摘などあれば、ありがたいです。
#Rails / Controller 以外で ActiveModelSerializers の動作確認、JSON出力をする ( rails  console とか )

モデルのインスタンスを Serializer に与えて to_json するだけで良さげ

# Serializer

```rb
class UserSerializer < ActiveModel::Serializer
  attributes :id, :name
end
```

# 動作

空のインスタンス

```rb
user = User.new

# <User:0x000055cfd1dcf6f8
#   id: nil,
#   name: nil,
#   email: nil,
#   created_at: nil,
#   updated_at: nil>

serialized_user = UserSerializer.new(user)

serialized_user.to_json
# => "{\"id\":null,\"name\":null}"
```

DBからインスタンスを得る例

```rb
user = User.last

# #<User:0x000055cfd1ea0730
#  id: 19,
#  name: "吾輩",
#  created_at: Fri, 20 Mar 2020 01:02:10 UTC +00:00,
#  updated_at: Fri, 20 Mar 2020 01:02:10 UTC +00:00>


serialized_user = UserSerializer.new(user)

serialized_user.to_json
# => => "{\"id\":19,\"name\":\"吾輩\"}"
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/3050








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
CSSアニメーションでキラッと光るボタンの実装

CSSアニメーションを使ってキラッと光るボタンを実装する際、ボタンの形が角丸だった場合に
safariだとアニメーション部分が四角く表示されてしまうということがあったのでその解決方法メモ。
以下、pugとstylusです。

```
button(type='button').btn ボタン
```

```
.btn
  width: 300px
  color: #fff
  background-color: #76bddd
  font-size: 18px
  font-weight: bold
  border-radius: 40px
  border: 2px solid transparent
  padding: 14px 20px
  position: relative
  overflow: hidden
  &:before 
    content: ''
    width: 30px
    height: 100%
    background-color: #fff
    animation: shine 3s ease-in-out infinite
    position: absolute
    top: -180px
    left: 0
    opacity: 0
    transform: rotate(45deg)

@keyframes shine 
  0% 
    transform: scale(0) rotate(45deg)
    opacity: 0
  
  80% 
    transform: scale(0) rotate(45deg)
    opacity: 0.5
  
  81% 
    transform: scale(4) rotate(45deg)
    opacity: 1
  
  100% 
    transform: scale(50) rotate(45deg)
    opacity: 0
```

chromeだとこんな感じ。
![chrome.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174180/b55efaec-2dbc-5465-fbb0-46ad433a222f.gif)
ボタンの形に沿ってキラッと光ってくれてます。

safariだと、
![safari.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174180/26a0e168-ebbb-0964-fe0b-03768855b1b4.gif)
ボタンの形に沿わず四角く光るフィルターが被さっただけのように見えてしまっています。


解決方法は、.btnに `z-index` を書いてあげるだけです！

```
.btn
  width: 300px
  〜
  z-index: 10
```

簡単！:thumbsup:
問答無用でReactコンポーネントを初期化・リセットする方法

# はじめに

とにかくコンポーネントをリセットしたい！マウントからやり直したい！
という時に使えるテクニックを紹介します。


# やり方

初期化したいコンポーネントの`props`に`key`を設定し、keyを更新します。


```react
const Component = () => {
  return (
    <div key={something}>
      ...
    </div>
  )
}
```


# 説明

コンポーネントにはライフサイクルがあります。

![DZ-97vzW4AAbcZj.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452235/e107c3d0-4b37-64eb-d68b-00bcf874b7ae.jpeg)


Reactコンポーネントはとても賢いので、うまく差分を計算してコンポーネントは不要な再描画が走らないようにしています。

そのため、マウント後の更新に関しては基本的にUpdateが適用されます。


一方で`key`はコンポーネントの一意性を保つための仕組みですので、`key`が更新されるという事は、まるっきり新しいコンポーネント扱いになります。

そのため、Updateではなく、Mountから新規で描画できる、というわけです。
【Ruby】インスタンスメソッド・クラスメソッド・特異メソッドの違い

インスタンスメソッド、クラスメソッド、特異メソッドの違いについてまとめてみました！！

## インスタンスメソッドとは？

- インスタンスから呼べるメソッドのこと

### 定義の仕方と解説
<img width="739" alt="スクリーンショット 2020-03-28 11.14.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/f63ab3eb-97ca-54d5-d21f-d02e00fde97f.png">
Human.instance_methods.grep(/say_hello/)でメソッドがあることがわかるのでインスタンスメソッド
## クラスメソッドとは？
- クラスから呼べるメソッドのこと

### 定義の仕方と解説1
<img width="725" alt="スクリーンショット 2020-03-28 11.26.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/2512483b-3062-3085-e7ff-1631c4d23280.png">

### 定義の仕方と解説2
<img width="933" alt="スクリーンショット 2020-03-28 11.29.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/287773/6bb9921e-295d-445d-718c-71e2aa4bde49.png">

クラスメソッドのselfはクラスそのものです。
厳密にいうとselfが書かれた場所に参照するレシーバを返します。
selfの代わりにクラス名をそのまま使ってもクラスメソッドになります。

Human.methods.grep(/say_hello/)でメソッドがあることがわかるのでクラスメソッド
Human.singleton_methods.grep(/say_hello/)でメソッドがあることがわかるので特異メソッド(シングルトンメソッド
上記の検証からクラスメソッドは特異メソッドであることがわかります。
 
## 特異メソッド(シングルトンメソッド)とは？
- １つのオブジェクト固有のメソッド
- クラスメソッドは特異メソッド

## 特異メソッドがオブジェクト固有のメソッドとは？
- オブジェクト固有とはオブジェクトIDが同じということ
- インスタンスのオブジェクトIDは一つ一つ違う

### コードで説明
- インスタンスのobject_idをみるとそれぞれ違う。クラス、モジュールは同じ
- classメソッドはオブジェクトのクラスが確認できる
- ancestorsメソッドは継承関係を確認できる
- object_idは各オブジェクトに対して一意な整数を確認できる

class Human
end

p BasicObject.class
=> Class
p BasicObject.ancestors
=> [BasicObject]
p BasicObject.object_id
=> 580
p BasicObject.object_id
=> 580
BasicObjectはnewメソッドがなくインスタンス化できない
❌ p BasicObject.new.object_id
❌ p BasicObject.new.object_id

p Kernel.class
=> Module
p Kernel.ancestors
=> [Kernel]
p Kernel.object_id
=> 600
p Kernel.object_id
=> 600
Kernelはモジュールのためnewメソッドがなくインスタンス化できない
❌ p Kernel.new.object_id
❌ p Kernel.new.object_id

p Object.class
=> Class
p Object.ancestors
=> [Object, Kernel, BasicObject]
p Object.object_id
=> 60
p Object.object_id
=> 60
p Object.new.object_id
=> 620
p Object.new.object_id
=> 640
p Human.class
=> Class
p Human.ancestors
=> [Human, Object, Kernel, BasicObject]
p Human.object_id
=> 660
p Human.object_id
=> 660
p Human.new.object_id
=> 680
p Human.new.object_id
=> 700

## 参考
[Ruby 2.7.0 リファレンスマニュアル ](https://docs.ruby-lang.org/ja/latest/class/Object.html)
laravel/frameworkとilluminate/supportの依存関係が解決できなかった【小説印刷支援サイト】

# 承前

投稿した小説をそのまま印刷できるWebサイトを立ち上げようとしている。

## 開発言語・環境

- PHP7.2
- Laravel 6

# 困ったこと

ライブラリを追加しようとしたところ、いつの間にか `composer update`が通らなくなっていた。

## 現象

```
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Conclusion: don't install laravel/framework v6.18.3
    - Conclusion: don't install laravel/framework v6.18.2
    - Conclusion: don't install laravel/framework v6.18.1
    - Conclusion: don't install laravel/framework v6.18.0
    - Conclusion: don't install laravel/framework v6.17.1
    - Conclusion: don't install laravel/framework v6.17.0
    - don't install illuminate/support 7.x-dev|don't install laravel/framework 6.x-dev
    - don't install illuminate/support v7.2.0|don't install laravel/framework 6.x-dev
    - don't install illuminate/support v7.2.1|don't install laravel/framework 6.x-dev
    - don't install illuminate/support v7.2.2|don't install laravel/framework 6.x-dev
    - don't install illuminate/support v7.3.0|don't install laravel/framework 6.x-dev
    - Installation request for laravel/framework ~6.17||6.x-dev -> satisfiable by laravel/framework[6.x-dev, v6.17.0, v6.17.1, v6.18.0, v6.18.1, v6.18.2, v6.18.3].
    - Installation request for illuminate/support ~7.2 -> satisfiable by illuminate/support[7.x-dev, v7.2.0, v7.2.1, v7.2.2, v7.3.0].

```

# 原因

- `laravel/framework`のアップデート前に`"illuminate/support":"~7.2"`を記載してしまった。
- そもそも`illuminate/support 7.*`は`laravel/framework ver6.*`をサポートしていなかった。

# 対処

`require`を下記のように修正したところ、`composer update`が通るようになった。

```json:composer.json
    "require": {
        "php": "^7.2",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "^6.18",
        "laravel/tinker": "^2.0",
        "webpatser/laravel-uuid": "^3.0",
        "illuminate/support":"^6.0",
        "tecnickcom/tcpdf": "6.2.*"
    }
```

# 反省

- composerは依存関係を解決してくれるが競合はどうしようもない。
- ので、依存関係は自分で把握する。

# Webサイトの公開予定

8～9月頃を予定しています。
段階的に機能開放していくかもです。
DockerでMySQLコンテナを立ち上げて.sqlファイルからDBを作る

## 環境
macOS : catalina 10.15.3
Docker Desktop : 2.2.0.4(43472)
Docker Compose : 1.25.4

## ローカルファイル構成
以下、図参照
![スクリーンショット 2020-03-28 16.49.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319205/f8f9cca8-3450-dfe1-88b6-8ec333bed0e9.png)

自前のsqlファイルを使いたかったので、それをDBフォルダ配下に配置

以下に示すファイルの中身は[DockerでMySQLを使ってみる](https://qiita.com/TAMIYAN/items/ed9ec892d91e5af962c6)を引用

### docker-compose.yml
```
version: "3"
services:
  mysql:
    build: ./mysql/
    volumes:
      - ./mysql/db:/docker-entrypoint-initdb.d
    image: local_mysql
    environment:
      - MYSQL_ROOT_PASSWORD=
```

### Dockerfile
```
FROM mysql

EXPOSE 3306

ADD ./my.cnf /etc/mysql/conf.d/my.cnf

CMD ["mysqld"]
```

### my.conf
```
[mysqld]
character-set-server=utf8

[mysql]
default-character-set=utf8

[client]
default-character-set=utf8
```

# コンテナ起動
```
$ Docker-Compose up -d --build

# コンテナへログイン
$ docker exec -it Docker-mysql_mysql_1 bash -p

# MySQLを起動
$ mysql -u root -p -h 127.0.0.1  # パスワードはdocker-compose.ymlで記述したやつ
```

### DB作成したい場合
DB作成コマンド

    $ create database hoge_db;

DBができているか確認

    $ mysql -u root -p -h 127.0.0.1  

パスワードは`docker-compose.yml`で記述したやつ
DB内に入れたら

    mysql> show databases;

作ったDBがあればOK


### .sqlファイルからDBを作る場合
mysqlからはexitして以下のコマンドを叩く

    mysql -u root -p < インポートしたいsqlファイル

既存のDBを指定することも可能
success的なメッセージが出れば完了


# 参考資料
[DockerでMySQLを使ってみる](https://qiita.com/TAMIYAN/items/ed9ec892d91e5af962c6)

[MySQLで.sqlファイルを実行する](https://crimnut.hateblo.jp/entry/2018/08/19/213731)
RustでHit & Blowを作ってみた

##社内のRust勉強会に参加した
[以前の記事](https://qiita.com/kazsharp/items/9557d0824f5ab9b05556)にも書いたように、社内の勉強会でRustの勉強会があり、私も参加いたしました。
内容は、講師がRustの基本的な文法などを解説し、その後参加者がそれぞれ好きなアプリケーションを作るというものでした。

##Hit & Blow
私が作ったアプリはHit & Blowという古くからあるゲームでした。
細かいルールの違いは方々であるようですが、私が作ったHit & Blowは

* 4桁の数字を当てる
* 4桁の数字は1～9を使う
* 同じ数字は使わない
* 数字を推理し、その推理した数字にたいする評価を得る
* 評価は
    * 場所も数字も合っている場合はhitにカウントされる
    * 数字は合っているが場所が間違っている場合はblowにカウントされる
* 4桁の数字を当てるまで推理と評価を繰り返す

例えば4桁の数字が  **4738**  の場合

推理した数字が **1932** なら  hit: 1  blow: 0
推理した数字が **8395** なら  hit: 0  blow: 2
推理した数字が **4837** なら  hit: 2  blow: 2

となります。
この推理に対する評価をもとに、4桁の数字を絞っていくのですがやってみると適度な難しさでなかなか面白いです。
何回か推理すると必ず正解にたどりつけるので難しすぎるということもありません。

##Rustでの実装
このアプリの肝となるのは「ランダムな4桁の数字を生成」という部分と「推理した数字の評価」の部分になると思います。
ぶっちゃけ、自分の得意な言語ならこの程度の処理は5分程度でコーディングできると思うのですが、不慣れなRust言語だったため色々調べたりしながらでかなり時間がかかりました。
以下はその部分のコードです

```rs
extern crate rand;

use rand::seq::SliceRandom;

//判定結果構造体
pub struct JudgeResult {
    pub hit: i32,
    pub blow: i32
}

//4桁の数値を生成
pub fn create_numbers() -> Vec<i32> {
    let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];

    let mut rng = rand::thread_rng();
    v.shuffle(&mut rng);
    vec![v[0], v[1], v[2], v[3]]
}

//判定
pub fn judge(numbers: String, answer: Vec<i32>) -> JudgeResult {

    let mut h = 0;
    let mut b = 0;

    let mut nums = numbers.chars();

    for i in 0..4 {
        //charをi32に変換（この方法以外わからなかった）
        let n = nums.next().unwrap() as i32 - 48;
        if n == answer[i] {
            h += 1;
        } else if answer.contains(&n) {
            b += 1;
        }
    }

    JudgeResult {
        hit: h,
        blow: b
    }
}
```

Rustプログラマから見れば「なんじゃこれ！」みたいなコードかもしれませんが、初心者のため良いのか悪いのかさえあまり分かりません。
もしアドバイスなどありましたらコメントを頂ければ嬉しいです。
特に気になっているところは、4桁の数字（文字列）をcharに分解してそれを数値に変換しているところです。
方法がわからず
```let n = nums.next().unwrap() as i32 - 48;```
とやけっぱちな実装になっています。

ちなみに、実際のアプリはWeb APIの部分（RustでIronを使いました）とHTMLの画面（Riot.jsとMaterializeを使いました）も含んでいるのですが、長くて退屈なコードなので省略させていただきます。

以上、RustでHit & Blowを作ってみた話でした。
[開発プロセス] ド素人が挫折しない開発プロセス

# はじめに

> 自由は不自由や。

>by ジョージ富士川

[参考はこちらです](https://amzn.to/34kSSoy)

適度な制約（不自由さ）が自由な創作の拠り所となるという考えが大事だよって解釈かなと思います。
開発においても自由過ぎず不自由過ぎない適度な塩梅でやりましょうというのがモダンな考え方なんだと思います。ソシャゲ開発などではゲーム中毒者たちを飽きさせないために超高速回転でアジャイルしているらしいですし。


# ☓ やらないこと

☓　トップダウン型の開発
☓　複雑な規則は取り入れない
☓　難しいこと


##設計設計しない
プロセス中心設計、 データ中心設計、 構造化設計(トップダウン)、  オブジェクト指向設計、 多層アーキテクチャ


## 設計書に縛られない
個人開発においては設計のエッセンスは限りなく少なくする


## 依存地獄から逃れる
ルール通りに開発することは精神面で楽なことも多いと思う
が、ルールを課すことはそのルールに依存するということでもあるので
依存をできる限り減らす


# ◎ やること

◎　必要に応じて機能を追加(JIT)
◎　デプロイは自動化
◎　楽なこと


## 設計っぽいことをやる

### 全体の流れ

#### 工程
要求分析　→　分析　→　アーキテクチャ設計　→　詳細設計　→　実装　→　テスト

#### 成果物
ユースケーズモデル　→　イベントフロー　→　画面遷移図　→　概念モデル　→　分析モデル　→　アーキテクチャ設計書　→　設計モデル　→　ソースコード　テスト仕様書、テストコード

#### UML
ユースケース図　→　アクティビティ図　→　クラス図、オブジェクト図、コミュニケーション図　→　パッケージ図、クラス図、シーケンス図　→　クラス図、シーケンス図

#### まとめ
| 工程 	| 主な成果物 	| UMLモデル図 	|
|--------------------	|----------------------------------------------------	|--------------------------------------------------	|
| 要求分析 	| ユースケースモデル<br>イベントフロー<br>画面遷移図 	| ユースケース図<br>アクティビティ図<br>なし 	|
| 分析 	| 概念モデル<br>分析モデル 	| クラス図、オブジェクト図<br>コミュニケーション図 	|
| アーキテクチャ設計 	| アーキテクチャ設計書 	| パーッケージ図、クラス図<br>シーケンス図 	|
| 詳細設計 	| 設計モデル 	| クラス図、シーケンス図 	|
| 実装 	| ソースコード 	| なし 	|
| テスト 	| テスト仕様書、テストコード 	| なし 	|

テーブル作成に用いたWEBツール
https://www.tablesgenerator.com/markdown_tables


### 補足①
- 上記は順不同
- 好きな（やりやすい）順にやる
- データ揃っているならデータ設計(モデリング・詳細設計)から始めるのも全然あり


## ミニマムなルール
- 箇条書き
- 文字数制限
- 用語集をつくる


## 少し詳細な流れ

- アイディアを図にする
 - UIをスケッチする
  - 文字やレイアウトなど
  - 画面遷移図 (この段階で作らなくても良い)

- 実現したいこと（機能）を書き出す
 - 列挙する
 - 綺麗に整理する必要なし
 - must do , should do , could do

- 機能を実装する方法を考える
 - 機能に優先順位をつける
 - 本当に必要な機能かどうか

- UMLっぽいものを書く (モデリング)
 - 原則は守る
 - 但し複雑な規則は取り入れない
 - ユースケース図 → オブジェクト図 → クラス図 → シーケンス図
 
- ユースケース図
  - システムで実現することを明確にする
  - 検討対象のシステムがアクターに対して提供する機能・振る舞いのこと
  - アクターとユースケースの候補は「誰が」と「名をするか」の観点で見つける
 
- オブジェクト図
 - オブジェクトの持つ属性値の情報やオブジェクト同士のつながりを明記することで、システムのスナップショットを表現する
 - オブジェクト図は、クラス候補の洗い出しや、クラス間の関連や多重度など、クラス図を作成する際のヒントを得るために必要に応じて作成する
 
- クラス図
 - システムの静的な構成を表現する
 - オブジェクトの情報を抽象的に定義したクラスとクラス間の関連を表現する
 - クラスの候補は、ユースケース図やオブジェクト図などから抽出する
 - クラスの属性や操作、クラス図の関連は、シーケンス図やアクティビティ図などから抽出する
 - それぞれのUMLを行ったり来たりしながら徐々に完成に近づける
 
- シーケンス図
 - システムの振る舞いを時系列で表現する相互作用図
 - 図の詳細度やクラス図との整合性に注意する

- アーキテクチャを選択する
 - ちょうど良いフレームワークがあれば使う
 - 自作するならドメインモデルっぽい構成など

- コーディング
 - 見直しは適当でOK
 - 速攻デプロイしてしまう

- デプロイ
 - 自動デプロイ

- 上記を繰り返す
 - 追加・変更を繰り返す(JIT)
AWS上にRedmineを構築してSESで通知メールを送信（上げ直し）

# 前提
SESにドメイン、アドレスを設定済み。
SESでメールの送信制限を緩和済み。

# メール送信設定
## サーバ作成
MarketplaceのAMIを使って、EC2インスタンスを起動。
インスタンスの設定はよしなにやってください。動かすだけならデフォルトで問題ないです。
<img width="1258" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/525671d2-6f51-496e-ab85-a4a7c26f8fc3.png">

## SMTPサーバの設定
作成したインスタンスにSSHでログインして、設定ファイルを編集。

```
vi /opt/bitnami/apps/redmine/htdocs/config/configuration.yml
```

```
  email_delivery:
    delivery_method: :smtp
    smtp_settings:

      address: "SESで確認"
      port: 587
      domain: "あなたのドメイン"
      authentication: :login
      user_name: "SESで作成されたユーザー"
      password: "SESで作成されたパスワード"
```

入力項目はSESで確認。SMTP SettingsのServer Nameが上記のaddressです。
<img width="1249" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/49ffc6d4-6cde-a1b3-5c6d-1996f56afd78.png">

続いて、「Create My SMTP Credentials」をクリック。
続けて「作成」をクリックして、ユーザー、パスワードを作成し、上記のユーザー、パスワードに記載します。
ドメインはSESで設定しているドメインを記載してください。
（""も必要です）

## メール送信テスト

設定の反映には再起動が必要ですが、その前にadminユーザーのパスワードを確認しておきます。
/home/bitnami配下のbitnami_credentialsに書かれています。
パスワードをメモしたら、インスタンスを再起動します。

再起動できたら、インスタンスのDNSまたはIPをブラウザで入力。Redmineのログイン画面が開きます。

<img width="1269" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/6237517a-9c02-f2ce-03aa-6a918895de29.png">

IDにuser、パスワードに先ほど確認したパスワードを入力してログイン。

メール送信テスト用に、先に右上のMy Accountから自分のアドレスを修正します。
<img width="1269" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/2e63ebc7-85cb-e906-c0e2-5721a734c2cb.png">

続けて、画面左上のAdministrationから、Settings。
<img width="1266" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/940d8540-c9fa-93a2-25ab-9f3b2a5bf04e.png">

Email Notificationへ。送信元メールアドレスを設定します。
ページ下までスクロールして保存ボタンをクリック。

<img width="1259" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/eaae8d5b-6e75-d5b2-344a-a80be9175e28.png">

<img width="1007" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306809/e34fd711-4bac-3acf-16b4-b64b5390f979.png">

続いて、ページ下部右にあるSend a test emailでテストメールを送信します。
問題なくメールが届けば、設定完了です。
aws-shell を dockerでクリーンに動かす

# TL;DR
https://github.com/hiroga-cc/docker-images/blob/master/aws-shell/Dockerfile

# 詳細

`aws-shell` の調子が良くないので、dockerでクリーンに実行します。  

aliasでdockerを動かし、かつ `~/.aws` をボリュームとしてマウントする、という構成です。

```Dockerfile
# alias aws-shell='docker run --rm -it -v "$HOME/.aws:/root/.aws" hiroga/aws-shell:latest'
FROM python:3.7.7-alpine3.11

RUN pip install --upgrade pip;\
    pip install --upgrade aws-shell
ENTRYPOINT [ "aws-shell" ]
```

# 今後の改善点

* できれば毎度イメージを作るのを避けたいので `start` を利用したいのだが、 startにprofileオプションを渡す方法が思いつかないです...
* Creating doc index が毎回走るのもなんとかしたい。コンテナビルド時にindexを作るという手もあるが...うーん。
Dovecot Sieveメールフィルタリング入門

# Dovecot Sieve
- SieveはDovecotと連携するメールフィルタリング用のプログラミング言語
- Dovecot内部では、Sieveを実装したPigeonholeがプラグインとして含まれている
- Postfixの仕様でバーチャルドメイン配送( virtual_transport = virtual )では .forward使えないから回避策でsieveを使ったりする

# 基本の使い方
基本書式はif文を使う

```
require ["fileinto"]; // オプションコマンド

if address :is "from" "test@example.com" // エンベロープFromが指定のメールアドレスなら
{
    fileinto "testfolder"; 指定のメールボックスに配送
}
```

# オプションコマンド
- fileinto 指定したメールボックスに配送
- keep デフォルトのメールボックスに配送
- discard メール破棄
- reject メール拒否
- redirect 指定したメールアドレスにメール転送
- stop 処理停止

vacation拡張で自動返信機能も実装できる

# SPAMメールを拒否する

```
require ["reject"];

if header :contains "X-Spam-Flag" "YES" // メールヘッダにSPAM判定を付けられているなら
{
    reject "your mail is rejected."; // メール拒否
}
```

DKIM, YENMAと組み合わせて使うイメージ

# 複数条件でフィルタリング
AND条件はallof、OR条件はanyof

```
require ["body", "fileinto", "mailbox"];

if allof {
    header "X-Spam-Flag" "YES", // メールヘッダにSPAM判定を付けられているかつ
    not body :contains "TEST", // メールボディに指定の文字列が含まれていないなら
} {
    fileinto :create "spamfolder"; // 指定のメールフォルダに配送する
}
```

# 自動返信（vacation拡張）
```
require "vacation";

vacation
    :days 1 // 同一送信元には1日1回まで返信
    :subject "auto reply"
    :from "test@example.com"
"this mail is auto reply."
```

# Dovecot LDA(Local Delivery Agent)との組み合わせ