OmniAICreator/Qiita-1.07M huggingface dataset:
Ubuntu 18.04にPHP-FPM 7.2をインストール（OS標準）

# はじめに

Ubuntu18.04にPHP-FPMを標準インストール
親記事：[PHP, PHP-FPMの各種インストール方法とEOLまとめ](https://qiita.com/witchcraze/items/dfe3823554b7caba6f6a)

## LOG

### インストール

```shell-session
# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.3 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.3 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic

# apt update;apt install -y php-fpm
... 略
```

### 各種確認

```shell-session
# which php
/usr/bin/php

# which php-fpm7.2
/usr/sbin/php-fpm7.2

# php -v
PHP 7.2.19-0ubuntu0.18.04.2 (cli) (built: Aug 12 2019 19:34:28) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.19-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies

# php-fpm7.2 -v
PHP 7.2.19-0ubuntu0.18.04.2 (fpm-fcgi) (built: Aug 12 2019 19:34:28)
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.19-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies

# apt show php-fpm
Package: php-fpm
Version: 1:7.2+60ubuntu1
Priority: optional
Section: universe/php
Source: php-defaults (60ubuntu1)
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Debian PHP Maintainers <pkg-php-maint@lists.alioth.debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 12.3 kB
Depends: php7.2-fpm
Download-Size: 3172 B
APT-Manual-Installed: yes
APT-Sources: http://archive.ubuntu.com/ubuntu bionic/universe amd64 Packages
Description: server-side, HTML-embedded scripting language (FPM-CGI binary) (default)
```
(質問です)rubyのapiの叩き方について

# rubyでapiを叩きたい
現在プログラミング歴１ヶ月でlinebotを作成しながら勉強しています。
##ぐるなびAPIをlinebotに使用したい
ぐるなびAPIをlinebotに使用する所でつまづいており、皆様にご質問があります。

下記エラーが解決出来ません
 NoMethodError (undefined method `sample' for nil:NilClass):

該当コードは

```linebot_controller.rb
events.each { |event|
      if event.message['text'] != nil
        place = event.message['text'] #ここでLINEで送った文章を取得
        result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008&category_s=RSFST08009&#{place}`
      else
        latitude = event.message['latitude']
        longitude = event.message['longitude']

        result = `curl -X GET https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=ffb92f0f997a628153ecfa407099fe9b&category_s=RSFST08008category_s=RSFST08009&latitude=#{latitude}longitude=#{longitude}`#ここでぐるなびAPIを叩く
      end
      
      hash_result = JSON.parse result  #レスポンスが文字列なのでhashにパースする
      shops = hash_result["rest"] #ここでお店情報が入った配列となる
      shop = shops.sample #任意のものを一個選ぶ

```
hash_result = JSON.parse result  部分まではしっかり値が入っているのですが、
shops = hash_result["rest"]　　　←この部分がnilで返ってきてしまいエラーを吐き出してしまいます。
文法のミス等自分なりにapiを叩く記述を参考にしながら行なったのですが解決出来ません。
皆様のお力をお貸しいただけると幸いです。

以下参考記事
https://qiita.com/NoharaMasato/items/6fb1ac277c965905e019
presence メソッド

## presenceメソッドは

```
def presence
  self if present?
end
```

で定義されている

## 使い所

例えば、site_titleというWebページのタイトルを返すメソッドの場合、このような実装になるかと思います。

```
def site_title(title)
  title.present? ? title : 'サイト名'
end
```

これをpresenceを使うと下記のようになります。

```
def site_title(title)
  title.presence || 'サイト名'
end
```


## REFERENCE
http://www.monokoto.xyz/rails-presence/
binding.pryの使い方

## デバッグツールのbinding.pryの基本的な使い方の備忘録
1. gemfileに`binding.pry`を記述
2. ターミナルでbundle insatall を実施する
3. 動作を止めたいところ（変数の中身を確認したいところ）に挿入する。

```ruby:user_contorller.rb
def login
    @user = User.find_by(
      email:params[:email],
      password:params[:password]
    )
    binding.pry
    if @user
      flash[:notice] = "ログインしました"
      redirect_to action: :index
    else
      @error_message = "メールアドレスまたはパスワードが間違っています"
      @email = params[:email]
      @password = params[:password]
      render action: :login_form
    end  
  end
```
アクションに該当する動作を実施するとターミナルに以下のように表示される。

```terminal
    40: def login
    41:   @user = User.find_by(
    42:     email:params[:email],
    43:     password:params[:password]
    44:   )
    45:   binding.pry
 => 46:   if @user
    47:     flash[:notice] = "ログインしました"
    48:     redirect_to action: :index
    49:   else
    50:     @error_message = "メールアドレスまたはパスワードが間違っています"
    51:     @email = params[:email]
    52:     @password = params[:password]
    53:     render action: :login_form
    54:   end  
    55: end
```
あとはterminalで確認したい中身の変数をたたけば確認できる！

```terminal

[1] pry(#<UsersController>)> @user
=> nil
```
docker(68)今日のdocker error: requested access to the resource is denied: 解決

```shell-session:macOS
$ docker commit 92edaa5cf839  kaizenjapan/posix
sha256:150b4e135e37ffec6d92901c95d54b2e886a11a6377fe68ca199c3b35b4af7a3
$ docker push kaizenjapan/posix
The push refers to repository [docker.io/kaizenjapan/posix]
3bc9aa75c2c1: Preparing 
18f7e20c4125: Preparing 
bdb3ef4d81d2: Preparing 
5c4512ea6db7: Preparing 
01da96bac413: Preparing 
8c487c756d71: Waiting 
05c027e771c8: Waiting 
e9313b51f46d: Waiting 
46601dcd4114: Waiting 
31b0e148310d: Waiting 
denied: requested access to the resource is denied

$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
kaizenjapan/posix    latest              150b4e135e37        13 minutes ago      1.14GB
kaizenjapan/http3a   latest              863371d53d45        4 weeks ago         98.1MB
kaizenjapan/http3    <none>              863371d53d45        4 weeks ago         98.1MB
debian               buster-slim         83a10817c894        7 weeks ago         69.2MB
gcc                  latest              e05f48a4f898        2 months ago        1.14GB

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
92edaa5cf839        gcc                 "/bin/bash"         23 hours ago        Up 23 hours                             bold_minsky

# docker rmi 83a10817c894 
Error response from daemon: conflict: unable to delete 83a10817c894 (cannot be forced) - image has dependent child images
```

docker loginしなおしたらpushできた。

commit時点でエラーが出なかった理由は不明。
### 最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。
#### Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
半自動モフり機

# † 半自動モフり機
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/1iiGt7SBo0">pic.twitter.com/1iiGt7SBo0</a></p>&mdash; ちゃり (@amb98) <a href="https://twitter.com/amb98/status/1179349883368742914?ref_src=twsrc%5Etfw">October 2, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

実際にモフってるところが撮影できればよかったのですが、動画を撮影できる機器はスマホしかなく。
FGOメンテだからFGO周回しよみたいな。

# † 元ネタ
[モータードライバー(TA7291P)の使い方 [Arduino]](https://www.petitmonte.com/robot/motor_driver_ta7291p.html)

※こちらを見てすべてわかる方は、当記事を読む必要はありません。

# † 動機というか前年のつらみ
某人気ゲームは年に一度、廃人祭を開催する。ボックスガチャという、うまみはあるがつらみも半端ない仕込みである。
昨年、つまり2018年のこと、あまりにひどいタップ沼に懲りて、なにか楽する方法はないかと調べたとき、[ソーセージと百均のミルクフォーマーというコスパのよさと、ソーセージというひそかな工夫を、ものすごい絵面で台無しにしたマシン](https://twitter.com/hjk_iii/status/1047119389181370375)に出会った。
見た目の雑さもよりも調整に職人技を要すると感じ、避けたことは余談である。

# † 実装
| 部品一覧 |
|:-----------|------------:|:------------:|
| Arduino Uno |
| ブレッドボード |
| ジャンパワイヤ |
| モータードライバ(TA7291P) |
| Rasbee MB102ブレッドボード用 電源モジュール 3.3V 5V パワーモジュール|
| ACアダプター x 2|
| タミヤ 楽しい工作シリーズ No.157 ユニバーサルプレート 2枚セット|
| タミヤ 楽しい工作シリーズ No.103 ユニバーサルギヤーボックス |
| ラック（ギアの歯がついた棒|
| いいカンジの洗濯バサミ |
| 固定するナニカ（百均の引き出し付きケースなど）|
| ダイソーのクレヨン型スタイラスペン |

Amazonでほぼ全てそろう。
リンクを貼らなかったのは、一部不当と思える価格設定の品があったからで、適宜良いと思えるものを選んでいただければと思う。
ダイソーのクレヨン型スタイラスペンの先端は取り外し可能で、これをラックの先端にクリップで固定している。前述のソーセージに相当する工夫としては、この先端部をジャンパワイヤでArduinoのGNDに接続していること。

## † 回路図説
![半自動モフり機_ブレッドボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167384/37026df8-534b-3fb7-d368-6b855ee523d3.png)
元ネタの方では電池を使っており、それで十分だが、本例では部品一覧に挙げた「Rasbee MB102ブレッドボード用 電源モジュール 3.3V 5V パワーモジュール」を使用した。
ブレッドボードの両端に電力を供給するものだが、Arduinoからモータドライバ駆動用の電源を取っているため、そちら側はOFFにしている。DCモーター駆動用には3.3Vに設定した。

## † ソースコード
元ネタのソースコードほぼまんまだが、ラックのストロークにあわせて時間を調整している。

```c
#define PIN_IN1  7
#define PIN_IN2  8
#define PIN_VREF 9 // PWM
 
void setup(){
  Serial.begin(9600);
  pinMode(PIN_IN1,OUTPUT); 
  pinMode(PIN_IN2,OUTPUT); 
}
 
void loop(){
      
  // モーターの回転速度を中間にする
  Serial.print("モーターの回転速度を中間にする\n");
  analogWrite(PIN_VREF,127); 
 
  // 回転
  Serial.print("回転\n");
  digitalWrite(PIN_IN1,HIGH);
  digitalWrite(PIN_IN2,LOW);
  delay(180);                     // <- 調整箇所
 
  // ブレーキ
  Serial.print("ブレーキ\n");
  digitalWrite(PIN_IN1,HIGH);
  digitalWrite(PIN_IN2,HIGH);
    
  // 逆回転
  Serial.print("逆回転\n");
  digitalWrite(PIN_IN1,LOW);
  digitalWrite(PIN_IN2,HIGH);    
  delay(180);                     // <- 調整箇所
 
  // ブレーキ
  Serial.print("ブレーキ\n");
  digitalWrite(PIN_IN1,HIGH);
  digitalWrite(PIN_IN2,HIGH);
  delay(1000);                     // <- 調整箇所
}
```

# † 免責事項
Arduinoは回路に電源を供給できますが、本例のようによそから電源を取っている場合など、誤ってArduinoにそれが流れてしまうようなことがあると機器の故障につながるようです。実行の際は、十分ご注意ください。
自己責任でお願いいたします。
cli-kintoneでやってみた「後で追加した計算フィールドに一括で値を反映する方法」

cybozu developer network の kintone Tips に、
[後で追加した計算フィールドに一括で値を反映する方法](https://developer.cybozu.io/hc/ja/articles/201883830-%E5%BE%8C%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%9F%E8%A8%88%E7%AE%97%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AB%E4%B8%80%E6%8B%AC%E3%81%A7%E5%80%A4%E3%82%92%E5%8F%8D%E6%98%A0%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95)
という記事があります。

今回、Go製の kintoneコマンドラインツール cli-kintone を使って、コードを書かずワンライナーで自動計算フィールドに値を一括して反映する Tips を公開します。

追記：2021.2.26
別にこれは計算フィールドだけのことではなくて、文字列1行フィールドで自動計算を選択した場合でも同じ動きになります。
例えば。
「姓」「名」の２つのフィールドがあって、それを連結する「氏名」フィールドを後で作った場合。
氏名フィールドを文字列1行で追加して、設定で自動計算するにして、姓 & 名 とかすればOK。

# 動作環境

* macOS 10.13.6
* cli-kintone 0.9.4


# cli-kintone の準備

cli-kintoneのZipファイルをダウンロード、解凍後に実行ファイルをパスの通ったディレクトリに配置します。

https://github.com/kintone/cli-kintone
https://github.com/kintone/cli-kintone/releases

# kintoneアプリの準備

テスト用のkintoneアプリを用意します。

## 営業支援パック導入

スペースを作り、アプリストアから[営業支援パック](https://jp.cybozu.help/k/ja/user/basic/sales_pack.html)をサンプルデータを含めて作成します。

![FireShot Capture 007 - 営業支援パック - kintone アプリストア - od4sa.cybozu.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214523/10b0dae0-672e-0e21-fcbd-2cd2d3cf7000.png)

## 案件管理に集計用年月フィールドを追加

文字列１行フィールドを追加して、自動計算を設定します。

![FireShot Capture 004 - アプリの設定 - od4sa.cybozu.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214523/d79b9ca5-4f21-6104-8f6c-5c229e27aeb6.png)

![FireShot Capture 005 - アプリの設定 - od4sa.cybozu.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214523/3eda8a48-02b7-089c-6548-e42e657507fa.png)

一覧の項目に追加したフィールドを表示させておきます。

![FireShot Capture 006 - 案件管理（営業支援パック） - レコードの一覧 - od4sa.cybozu.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214523/be030f97-2ee6-b138-f663-0ec92e837193.png)

# 考え方

下記の仕組みにより計算フィールドのみの更新を可能としています。

* リクエストのJSONデータに記述しないフィールドは更新されません
* 更新時にテーブルのデータを含まない場合、テーブルのデータは保持されます

* [kintone REST API レコードの更新（PUT）注意事項](https://developer.cybozu.io/hc/ja/articles/201941784#step3)

# cli-kintoneによる処理

処理の流れです。

1. レコードIDのみを取得します
2. 取得したレコードIDを読み込みます

## 処理コードと結果

```bash
$ cli-kintone -a 123 -t API-Token -d Domain -c "\$id" | cli-kintone --import -a 123 -t API-Token -d Domain
Start from lines: 1 - 11 => SUCCESS
DONE
```

cli-kintoneの1,2の処理をパイプで繋げて実行する事で、新規に追加した自動計算フィールドが更新されます。

![FireShot Capture 008 - 案件管理（営業支援パック） - レコードの一覧 - od4sa.cybozu.com.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214523/39a7e94a-ef3a-cfca-4aa6-78e96fb29552.png)


# 参考リンク

* [レコードの一括登録と更新](https://jp.cybozu.help/k/ja/user/using_app/import_records.html)
* [[レコードの一括更新] ファイルを編集する](https://jp.cybozu.help/k/ja/user/using_app/import_records/update_record_bulk.html)
* [入出力できるデータの一覧](https://jp.cybozu.help/k/ja/admin/other/import_export.html#appdata)
* [kintone REST API レコードの更新（PUT）](https://developer.cybozu.io/hc/ja/articles/201941784)
* [kintone REST API レコードの更新（PUT）注意事項](https://developer.cybozu.io/hc/ja/articles/201941784#step3)
* [kintone コマンドラインツール Version 0.9.0 新機能紹介](https://developer.cybozu.io/hc/ja/articles/360000126643)


——
Promise Async await


## 設定

```javascript

npm install promise

var Promise = require('promise')
```

## 文法

- 処理を一時保存する（new promise）
- 実行する（result.then）

```

var result = new Promise(function(resolve){

    resolve(console.log("hello"))
})

result.then(function(data){
  data
}

```

## チェーンメソッド


## Async 

- `promise`と同じ

```
const getOne = async _ => { 
  return 1 
} 

getOne()
  .then(value => {
    console.log(value) // 1
  })
```

## await

- `await`が`then`の代わり見たい

```
const test = async _ => {
  const one = await getOne()
  console.log(one) // 1
}

test()
```



## 記事


https://zellwk.com/blog/async-await/
AWSのAPIでスロットリングされたらリトライするようにする

`e.code === 'Throttling'`でエラーがthrowされるので、これを拾ってリトライするように実装すればとりあえずOK。
ただし再帰呼び出しになるので、リトライ数を記録して無限ループにならないようにする必要はある。

```javascript
// Wait処理
const sleep = async (time = 1000) => {
  return new Promise(resolve => setTimeout(resolve, time))
}

// CloudFrontのupdate処理
const worker = async (targetID, retryCount = 0) => {
  try {
    const dist = await cloudfront.getDistribution({
      Id: targetID
    }).promise()
    const distributionConfig = dist.Distribution.DistributionConfig
    distributionConfig.Enabled = false
    await cloudfront.updateDistribution({
      Id: dist.Distribution.Id,
      IfMatch: dist.ETag,
      DistributionConfig: distributionConfig
    }).promise()
  } catch (e) {
    if (e.code === 'Throttling') {
      if (retryCount < 2) {
        await sleep(2000)
        return worker(targetID, retryCount + 1)
      }
    }
    throw e
  }
}

const distIds = ['a', 'b', 'c']
Promise.all(distIds.map(async id => worker(id))

```
【ThinkPad E440】ふたを閉めると解像度が変わる現象とその対策

# 概要

## 環境

<dl>
  <dt>機種</dt>
  <dd>ThinkPad E440</dd>
  <dt>OS</dt>
  <dd>Windows 10 Pro 64bit 1903 (発生は1903以前より継続していた)</dd>
</dl>

## 問題となる事象

蓋をしめると解像度が変わり、ウィンドウが左下に集められた形になる。
蓋をあけると解像度は本に戻るがウィンドウ配置がもとに戻らない。

## 解決方法

ふたをしめた状態のPCに[Chrome リモート デスクトップ](https://remotedesktop.google.com/access)等でログインし、解像度設定を変更する。

### スクリーンショット

通常のログイン状態では解像度が **1600 × 900 (推奨)** となっている。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502524/c654cfda-7e71-6497-de40-3646ec7e55fa.png)

ふたをとじた状態でリモートログインすると、**640 × 480** となっていたので、これを **1600 × 900** に変更する。
ふたの開閉前後で同じ解像度となり、ウィンドウ位置の変更は発生しなくなる。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502524/0cc482ab-240f-a201-e929-d78bdccd9fc5.png)

この状態では本来の内蔵ディスプレイでは選択できない解像度まで選択できる。
何らかの理由で仮想ディスプレイのように動作しているのかもしれないけどよくわからない。
Jenkins Web API まとめ

## Overview

curl で Jenkins の Web API を叩きたかったのですが、なかなか自分が欲しい情報が集まりませんでした...。
他にも困っている人がいるかなと思ったのでまとめておきます。

## 各 Node 情報を取得

```shell
curl -s -u user:passward http://jenkins.co.jp:8080/computer/api/json
```

取得したレスポンスをパイプして `jq` とかで成形すればいい感じ。

## Job を実行

```shell
curl -X POST -u user:{$apiToken} http://jenkins.co.jp:8080/job/{$projectName}/build
```

API トークンは、`http://jenkins.co.jp:8080/user/${username}/configure` から取得できます。

パラメータ付きで実行する場合はこんな感じ。

```shell
curl -X POST -u user:{$apiToken} http://jenkins.co.jp:8080/job/{$projectName}/buildWithParameters?{$key}={$val}
```

## Project / Job を削除

```shell
curl -X POST -u user:{$apiToken} http://jenkins.co.jp:8080/job/{$projectName}/doDelete
curl -X POST -u user:{$apiToken} http://jenkins.co.jp:8080/job/{$projectName}/{$jobNumber}/doDelete 
```

Delete だけどなぜか POST 使います。
成功すると、`200` ではなく `302 Found` 返します。

## Jenkins-crumb を取得

```shell
curl -s -u user:passward http://jenkins.co.jp:8080/crumbIssuer/api/xml
```

Jenkins に post する際に、`Jenkins-crumb` を要求されるケースがあります。
`xpath` 使うといい感じで取り出せます。

```shell
crum=curl -s -u user:passward http://jenkins.co.jp:8080/crumbIssuer/api/xml | xpath "concat(//crumbRequestField, ': ', //crumb)" 2>/dev/null
echo $crum
> Jenkins-Crumb: xxxxxxxxxxx
```

## Node の online / offline を切り替える

```shell
curl -s -u user:passward http://jenkins.co.jp:8080/computer/{$node}/toggleOffline -d "offlineMessage=temporary" -d $crum
```

`$crumb` は上で取得した `Jenkins-crumb` をセットしましょう。

## Groovy Script を Jenkins で実行させる

```shell
script="for(j in jenkins.model.Jenkins.theInstance.getAllItems()) {
  j.delete()
}"

curl -s -u user:passward -H $crumb -d "script=$script" http://jenkins.co.jp:8080/script
```

Web 上だとスクリプトコンソールで実行できるやつです。

## その他

`http://jenkins.co.jp:8080/computer/{$node}/configSubmit` でラベル情報とか更新できそうな気配なのですがなかなか難しい...

他にも使えそうな API あったら追記します。
Java 8 (OpenJDK: Zulu Community) を Homebrew で macOS にインストールする

## 概要
- macOS に Homebrew で Java 8 (OpenJDK をビルドした Zulu Community) をインストールする方法を示す

## Zulu Community とは

Zulu Community は Azul Systems が配布している OpenJDK ディストリビューション。

[Zulu Community Java OpenJDK無料ダウンロード TCKテスト済](https://jp.azul.com/products/zulu-community/)

> Azulは、2023年7月までOpenJDK7のZulu Communityビルドのアップデートを毎四半期に提供し、OpenJDK 8のビルドは2026年3月までアップデートされ、OpenJDK 11のビルドは2027年9月までアップデートされます。Java 9、10、12、15、16のような中間リリースは、最初のリリースから少なくとも6か月はアップデートされます。
> Azulはまた、2014年以降のOpenJDK Zulu Communityビルドのアーカイブを保持します。

Zulu Community 8 は2026年3月までサポートされるとのこと。

## Zulu Community 8 をインストールする

Zulu Community 8 は homebrew/cask-versions にあるのでこれを使用してインストールする。

```
$ brew cask install zulu8
```

## java_home コマンドでインストールされたディレクトリの場所を確認する

```
$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home
```

## 環境変数 JAVA_HOME と PATH を設定する

必要に応じて .bash_profile や .bashrc などに記述する。

```
$ export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
$ PATH=${JAVA_HOME}/bin:${PATH}
```

## インストールされた Zulu Community を確認する

```
$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (Zulu 8.40.0.25-CA-macosx) (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (Zulu 8.40.0.25-CA-macosx) (build 25.222-b10, mixed mode)

$ javac -version
javac 1.8.0_222

$ which java
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/bin/javac
```

## 不要になったらアンインストールする

```
$ brew cask uninstall zulu8
```

## 参考資料
- [Zulu Community Java OpenJDK無料ダウンロード TCKテスト済](https://jp.azul.com/products/zulu-community/)
- [Azul Systems (https://github.com/zulu-openjdk)](https://github.com/zulu-openjdk)
- [homebrew\-cask\-versions/zulu8\.rb at master · Homebrew/homebrew\-cask\-versions · GitHub](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/zulu8.rb)
ssl.get_server_certificateで証明書を取得できない場合の対処

# 概要

Python でSSL証明書の情報を確認したい場合、以下のようなコードが紹介されていることが多い。

```python
import ssl
import OpenSSL # required pyopenssl

cert = ssl.get_server_certificate(('www.google.com', 443))
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
```

試してみると、多くの場合はこの方法で正常に情報が取得できたが、正常に情報が取得できないケースがあったため、調査を実施した。

実際のところ invoke (Fabric 2) でローカルの openssl コマンド叩けばうまくいったけれど、何故 Python でやるとうまくいかなかったのかが疑問だったので。


# 原因

[Server Name Indication(SNI)](https://ja.wikipedia.org/wiki/Server_Name_Indication) の指定がないため。
`openssl s_client` コマンドで言えば `-servername` が未指定のため。

IPアドレス直打ちの場合などにアクセスさせないためや、１つのサーバー上で複数のドメイン管理をしている場合などにSNI設定なしでアクセスすると別設定の証明書を返してきたり、そもそも返さなかったりする。

わざと `openssl` コマンドで `-servername example.com` など全く別のサーバーネームを与えた場合に同様の事象が再現した。


# 対処

原因がSNIと分かれば[同じような質問](https://stackoverflow.com/questions/49132025/ssl-get-server-certificate-for-sites-with-sni-server-name-indication)があった。 結果としては、`ssl.get_server_certificate` は使わず、その中身と同じようなことを自分で書いてやる必要がある。

```python
import socket
import ssl
import OpenSSL

def get_server_certificate(hostname):
    context = ssl.create_default_context()
    with socket.create_connection((hostname, 443)) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as sslsock:
            der_cert = sslsock.getpeercert(True)
            return ssl.DER_cert_to_PEM_cert(der_cert)  

cert = get_server_certificate('www.google.com')
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
```
PHPで型宣言を使ってみた

WordPressもサポートPHPバージョンが７以上になったので、ちょっと触ってみようかなと思っての覚書。

## 普通の書き方

```php
<?php
function get_greeding_message($number) {
  return $number;
}
print_r( get_greeding_message( 1 ) );
```

messageなのに数字返ってきますね。これを型宣言でつぶしてみます。

## 型を宣言する

```php
<?php
function get_greeding_message( int $number ): string {
  return $number;
}
print_r( get_greeding_message( 1 ) );
```

普通に書くとこんな感じですね。
ただ、これをこのまま実行しても、エラーにはなりません。

## 強い型付け
`declare(strict_types=1);`を書くことで、厳密にチェックすることができます。
https://www.php.net/manual/ja/functions.arguments.php#functions.arguments.type-declaration.strict

```php
<?php
declare(strict_types=1);
function get_greeding_message( int $number ): string {
  return $number;
}
print_r( get_greeding_message( 1 ) );
```

ここまで書くと、実行時にエラーがでます。

```
PHP Fatal error:  Uncaught TypeError: Return value of get_greeding_message() must be of the type string, integer returned in /home/ec2-user/test.php:4
Stack trace:
#0 /home/ec2-user/test.php(6): get_greeding_message(1)
#1 {main}
  thrown in /home/ec2-user/test.php on line 4
```

## 動くようにする

```php
<?php
declare(strict_types=1);
function get_greeding_message(int $number): string {
  return 'Hello No.' . $number;
}
print_r( get_greeding_message( 1 ) );
```
A3RTのTalk APIで返事をしてくれるDiscord Botを作ってみた

[簡単なDiscord Botの作り方（初心者向け）](https://note.mu/bami55/n/ncc3a68652697)
[自動応答のDiscord Botを完全無料で構築する[gas][glitch]](https://qiita.com/yuzuki_/items/23935e4a49035d313e5e)

これらの記事を参考にしながら、A3RTの[Talk API](https://a3rt.recruit-tech.co.jp/product/talkAPI/)を使ったDiscordのbotを作ってみました。
Botにリプライをすると、返事をしてくれます。

以下のコードはBotの返信部分の実装です。




```javascript

const discord = require("discord.js");
const client = new discord.Client();

client.on("message", message => {
//メッセージが他のユーザーによるものだったら反応する
if (message.isMemberMentioned(client.user)) {
   
  //先頭のユーザーIDを削除する
  var talkMassage = message.content.slice(22);
  
  const fetch = require('node-fetch');
  
  const params = new URLSearchParams();
  params.append('apikey', "APIキー");
  params.append('query', talkMassage);

  fetch("https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk", { method: 'POST', body: params } )
    .then(Response => {
    Response.json().then(Data => {
      message
      .reply(Data.results[0].reply);
    });
  });
  }
});
```
何かありましたら気軽にコメントをください。
Java 8 (OpenJDK: Amazon Corretto) を Homebrew で macOS にインストールする

## 概要
- macOS に Homebrew で Java 8 (OpenJDK をビルドした Amazon Corretto) をインストールする方法を示す

## Amazon Corretto とは

Amazon Corretto は Amazon が配布している OpenJDK ディストリビューション。

[Amazon Corretto（本番環境に対応したOpenJDKディストリビューション）\| AWS](https://aws.amazon.com/jp/corretto/)

> Amazon Corretto は、マルチプラットフォームで本番環境に対応した、無料の Open Java Development Kit (OpenJDK) ディストリビューションです。Corretto は、パフォーマンスの向上とセキュリティの修正などの長期サポートを用意しています。Amazon は、社内において何千もの本番サービスで Corretto を実行しており、Corretto は Java SE 標準と互換性があると認定されています。Corretto を使用することで、Linux、Windows、macOS などの一般的なオペレーティングシステムで Java アプリケーションを開発し、実行できます。

Amazon Corretto 8 は少なくとも2023年6月まではサポートされるとのこと。

[よくある質問 \- Amazon Corretto \| AWS](https://aws.amazon.com/jp/corretto/faqs/)

> Amazon Corretto は、マルチプラットフォームで本番環境に対応した、長期サポート (LTS) を含む無料の Open Java Development Kit (OpenJDK) ディストリビューションです。LTS には、最短でも関連するリリースバージョンの指定日 (例: Corretto 8 の場合は 2023 年 6 月) までは、パフォーマンスの向上とセキュリティの更新を無償で提供するという Amazon のコミットメントが含まれています。アップデートは四半期ごとにリリースされる予定です。Amazon では、通常の四半期サイクルの範囲外で、利用可能になった際に緊急で対応できる修正 (セキュリティを含む) を適用することも計画しています。

## Amazon Corretto 8 をインストールする

Amazon Corretto 8 は homebrew/cask-versions にあるのでこれを使用してインストールする。

```
$ brew tap homebrew/cask-versions

$ brew cask install corretto8
```

## java_home コマンドでインストールされたディレクトリの場所を確認する

```
$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
```

## 環境変数 JAVA_HOME と PATH を設定する

必要に応じて .bash_profile や .bashrc などに記述する。

```
export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
PATH=${JAVA_HOME}/bin:${PATH}
```

## インストールされた Amazon Corretto を確認する

```
$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment Corretto-8.222.10.1 (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM Corretto-8.222.10.1 (build 25.222-b10, mixed mode)

$ javac -version
javac 1.8.0_222

$ which java
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home/bin/javac
```

## 不要になったらアンインストールする

```
$ brew cask uninstall corretto8
```

## 参考資料
- [Amazon Corretto（本番環境に対応したOpenJDKディストリビューション）\| AWS](https://aws.amazon.com/jp/corretto/)
- [corretto/corretto\-8: Amazon Corretto 8 is a no\-cost, multi\-platform, production\-ready distribution of OpenJDK 8](https://github.com/corretto/corretto-8)
- [homebrew\-cask\-versions/corretto8\.rb at master · Homebrew/homebrew\-cask\-versions](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/corretto8.rb)
【Ruby】Slack APIを使用してメッセージを送信する

# 前提
この記事は以下の前提で書きます。
まだの方は[こちら](https://qiita.com/kou_pg_0131/items/56dd81f2f4716ca292ef)の記事を参考にして準備を進めてください。

- Slack APIで使用するトークンを取得済みであること
- APIにメッセージ送信の権限を与えていること

# 準備
`slack-ruby-client`をインストールします。
下記コマンドを実行するか、`Gemfile`に追記します。

```bash
$ gem install slack-ruby-client
```

or

```ruby:Gemfile
gem 'slack-ruby-client'
```

# ソースコード

```ruby:slack.rb
require 'slack-ruby-client'

Slack.configure do |config|
  # APIトークンを設定
  config.token = 'xoxp-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
end

# APIクライアントを生成
client = Slack::Web::Client.new

# #チャンネル名 of @ユーザー名
channel = '#slack-test'

# メッセージ
text = 'Hello World'

response = client.chat_postMessage(channel: channel, text: text, as_user: false)

pp response
```

実行してみる

```
$ ruby slack.rb
{"ok"=>true,
...
```

送信できた。
<img width="1440" alt="スクリーンショット 2019-09-13 0.08.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/349145/def95421-aa4f-9058-c260-aa7b199cc6e6.png">


# 参考
[slack-ruby/slack-ruby-client](https://github.com/slack-ruby/slack-ruby-client)
気象庁防災XML PUSH型提供でなくてもPubSubHubbubで割と通知が来る話

**以下、気象庁としては一切保証する話ではありません。品質も万全ではないですし、どうしてもという場合だけにしか利用価値はないです。**
(2019-10-31 最新状況をふまえて改題加筆修正)
(2020-09-05 PUSH型提供廃止をふまえ動作確認を補足)

# はじめに

気象庁防災XMLのPUSH型提供は2020年８月末での廃止が予告されています。
http://xml.kishou.go.jp/open_trial/index.html

気象庁防災XMLのPUSH型提供では、PubSubHubub手順により利用者の皆さんに新着電文が通知されるわけですが、技術的にはそれは Google Alert Hub を通じてトピックURLつまり4つのAtomフィードの更新が通知されるということです。実はそのトピックURLは xml.kishou.go.jp に置かれており、PULL型提供で利用者さんがアクセスしていただくために用意したURL（www.data.jma.go.jp）とは異なります。

で、実は今のところGAHは公開されているフィードであれば誰でも勝手に登録していいんだそうです（cf. https://alert-hub.appspot.com/ のFAQ欄）。実際問題として誰かがPULL型用のフィードURLを登録してpublishの実験をしているようで、下記のフィードをsubscribeすると更新通知が流れてくるのです。じゃあ、PUSH型提供が廃止されても、ほとんど同じものが送られてきますね。

ところがそうは甘くないのです。2019-10-01夜まで数日間に観測した限りでは、なぜか publish notification の間隔が１～２時間と開きすぎていて、その間の更新がほとんど（9割近く）抜けてしまいます。誰かがプッシュしているのか、Googleさんがポーリングしているのか知りませんが、ちょっとこれでは使えません。

でも、ちゃんとさせられないでしょうか。更新通知も誰が送ってもいいので、僕がPULL型フィードを見て送り付けて、全部キチンと配信されるかチェックしてみよう…　という実験をやっています。

# 実験設定

* フィード：以下の４つ（PULL型高頻度フィード）
    * http://www.data.jma.go.jp/developer/xml/feed/regular.xml
    * http://www.data.jma.go.jp/developer/xml/feed/extra.xml
    * http://www.data.jma.go.jp/developer/xml/feed/eqvol.xml
    * http://www.data.jma.go.jp/developer/xml/feed/other.xml
* タイミング：上記フィードを毎分監視して、更新があったらプログラムを起動
* プログラム： https://github.com/etoyoda/feedfollow/blob/master/notifygah.rb
    * 監視プログラムの作りの関係で、4つのフィードのどれかに更新があるとプログラムが起動します。受信記録をチェックして Last-Modified 時間が直近180秒以内であれば GAH に通知するようになっています。

# 結果

2019-10-28/30 に観測した限りでは次のようでした。

* 更新通知漏れは全体の10％程度に減少した
* 更新通知漏れが発生するのは、日本時間10時台、16時台、4時台で、これは府県天気予報など大量の（しかし緊急度は必ずしも高くない）電文が出る時間帯
* うまく動く日は、気象庁PUSH型提供の2～3分後に更新通知がやってくるが、うまく動かない日は10分くらい遅れる

胸を張って「完璧な代替です！」といえるような水準ではありませんが、仮にどうしても PubSubHubbub しか使えない場合、
まるきり稼働しないわけでもない程度には動くと言えましょうか。
すみません、Google Alert Hub の内部についてもわかりませんし、現時点ではこれ以上のことはわかりません。

# 2020-09-05補足: 気象庁PUSH型提供廃止後も動作しています

予告通り、気象庁からのPUSH型提供は 2020-09-01T10:05:14+09:00:00 の更新通知を最後に廃止となりました。その後も本件更新通知は今日まで動作を続けていることを確認しています。品質についてはまだチェックしていません、すみません。
[初心者]Rails6にbootstrap4を導入する



Ruby on railsを学び始めて約2ヶ月、
初めてbootstrapを導入したので、記事を作ってみました。


***
### 環境

```
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.6
BuildVersion:	18G95

$ ruby -v
ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-darwin18]
$ rails -v
Rails 6.0.0
```

***

### 目次

1. `bootstrap`の`gem`を追加
2. `applicationファイル`を編集
3. `index.html.erb`を編集
4. `bootstrap`が導入されているかを確認 

***


## 1.bootstrap gemを追加

Gemfileに以下を追加

```ruby:Gemfile
~
gem 'bootstrap', '~> 4.1.1'
gem 'jquery-rails'
~
```

`terminal`で`bundle install`を実行
(ローカルでgemを管理している場合は、`bundle install --path=vendor/bundle`で実行)

これで、プロジェクト内にbootstrapのgemが追加されました。

## 2.applicationファイルを編集
#### 2.1 application.cssの編集

app>assets>stylesheets>application.cssをエディタで開き、`@import "bootstrap";`を追加

```css:application.css
~
@import "bootstrap";
~
```

次に拡張子を`.css`から`.scss`へ変更
application.css → application.scss


#### 2.2 application.jsの編集

app>assets>javascript>application.jsをエディタで開き、`//= require bootstrap`を追加
(フォルダ、ファイルがなければ作成)
bootstrapはjqueryとpopperに依存しているらしいので導入

```javascript:application.js
//= require jquery3
//= require popper
//= require bootstrap-sprockets
```

## 3.index.html.erb を編集

適当なcontrollerに以下のコードを追加
app>assets>views>コントローラ名>index.html.erb
このコードはbootstrapのサイトにあるテストコードです。

```html:index.html.erb
<a class="btn btn-primary" href="#" role="button">Link</a>
<button class="btn btn-primary" type="submit">Button</button>
<input class="btn btn-primary" type="button" value="Input">
<input class="btn btn-primary" type="submit" value="Submit">
<input class="btn btn-primary" type="reset" value="Reset">
```

## 4.動作確認

下準備は整いました。

`bundle exec rails s`でローカルにサーバーを立ち上げます。
ブラウザに`localhost:3000/コントローラ名/index`を入力し、画面を確認してください。
以下の表示になっていれば完了です。
<img width="535" alt="スクリーンショット 2019-10-02 19.11.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/460262/79b8e04e-7d69-7143-21c7-ea2858091357.png">
Java 8 (OpenJDK: AdoptOpenJDK) を Homebrew で macOS にインストールする

## 概要
- macOS に Homebrew で Java 8 (OpenJDK をビルドした AdoptOpenJDK) をインストールする方法を示す

## AdoptOpenJDK とは

AdoptOpenJDK は Amazon, Azul Systems, IBM, Microsoft, Pivotal, Red Hat などがスポンサーになっていて配布されている OpenJDK ディストリビューション。

[AdoptOpenJDK \- Open source, prebuilt OpenJDK binaries](https://adoptopenjdk.net/)

> Java™ is the world's leading programming language and platform. AdoptOpenJDK uses infrastructure, build and test scripts to produce prebuilt binaries from OpenJDK™ class libraries and a choice of either the OpenJDK HotSpot or Eclipse OpenJ9 VM.

AdoptOpenJDK 8 は少なくとも2023年9月まではサポートされるとのこと。

[Support \| AdoptOpenJDK \- Open source, prebuilt OpenJDK binaries](https://adoptopenjdk.net/support.html)

> At Least Sep 2023

## AdoptOpenJDK 8 をインストールする

インストール方法が公式リポジトリの README に載っている。

[AdoptOpenJDK/homebrew\-openjdk: AdoptOpenJDK HomeBrew Tap](https://github.com/AdoptOpenJDK/homebrew-openjdk)

```
brew tap AdoptOpenJDK/openjdk
brew cask install <version>
```

README には AdoptOpenJDK/openjdk を tap して追加するように書いてあるが、 AdoptOpenJDK は homebrew/cask-versions にも存在する。

今回は homebrew/cask-versions を使用してインストールする。

```
$ brew tap homebrew/cask-versions

$ brew cask install adoptopenjdk8
```

## java_home コマンドでインストールされたディレクトリの場所を確認する

```
$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home
```

## 環境変数 JAVA_HOME と PATH を設定する

必要に応じて .bash_profile や .bashrc などに記述する。

```
export JAVA_HOME=`/usr/libexec/java_home -v 1.8`
PATH=${JAVA_HOME}/bin:${PATH}
```

## インストールされた AdoptOpenJDK を確認する

```
$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.222-b10, mixed mode)

$ javac -version
javac 1.8.0_222

$ which java
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java

$ which javac
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/javac
```

## 不要になったらアンインストールする

```
$ brew cask uninstall adoptopenjdk8
```

## 参考資料
- [AdoptOpenJDK \- Open source, prebuilt OpenJDK binaries](https://adoptopenjdk.net/)
- [GitHub \- AdoptOpenJDK/homebrew\-openjdk: AdoptOpenJDK HomeBrew Tap](https://github.com/AdoptOpenJDK/homebrew-openjdk)
- [homebrew\-cask\-versions/adoptopenjdk8\.rb at master · Homebrew/homebrew\-cask\-versions](https://github.com/Homebrew/homebrew-cask-versions/blob/master/Casks/adoptopenjdk8.rb)
index.tsを再帰的に生成するshell script

## やりたいこと

指定したディレクトリ内で再帰的に `index.ts` を生成したい。（ライブラリとして使用する `utils` ディレクトリ内などで実行する想定）
各 `index.ts` ではその階層にある ts, tsx ファイルとサブディレクトリを `export * from "./filename"` もしくは `export * from "./directory_name"`  のようにエクスポートする。

## スクリプト

```bash
#!/bin/bash

# index_ts_generator.sh

# configs
ADD_SUB_DIRECTORY_EXPORT_IN_INDEX_TS="true"
TS_FILENAME_REGEX="^[a-zA-Z0-9_\-]+.tsx?$"
MAX_RECURSION_DEPTH=10

# args
target_directory=$1
clear=$2

# move to target directory
cd ${target_directory}

# regenerate index.ts recursively
for directory in $(find . -maxdepth ${MAX_RECURSION_DEPTH} -type d); do
  index_ts="${directory}/index.ts"

  if [ "${clear}" = "clear" ]; then
    rm ${index_ts}
  else

    # reset index.ts
    echo -n "" > ${index_ts}

    # files in a current directory
    for file in $(find ${directory} -mindepth 1 -maxdepth 1 -type f); do
      filename=$(basename $file)

      # filename without extension
      filename_without_ext="${filename%.*}"

      # only files that match a regular expression "[a-zA-Z0-9_]+.ts"
      if [ ${filename} != "index.ts" ]; then
        if [[ ${filename} =~ ${TS_FILENAME_REGEX} ]]; then
          # add line "export * from 'filename'"
          echo "export * from './${filename_without_ext}'" >> ${index_ts}
        fi
      fi
    done

    if [ ${ADD_SUB_DIRECTORY_EXPORT_IN_INDEX_TS} = "true" ]; then
      # directories in a current directory
      for sub_directory in $(find ${directory} -mindepth 1 -maxdepth 1 -type d); do
        # add line "export * from 'directory_name'"
        sub_directory_basename=$(basename ${sub_directory})
        echo "export * from './${sub_directory_basename}'" >> ${index_ts}
      done
    fi

  fi

  echo ${directory} "done"

done

```

## 使い方

### config

* `ADD_SUB_DIRECTORY_EXPORT_IN_INDEX_TS="true"` ： サブディレクトリをエクスポートするかどうか
* `TS_FILENAME_REGEX="^[a-zA-Z0-9_\-]+.tsx?$"` ： マッチさせるTypeScriptファイル名の正規表現
* `MAX_RECURSION_DEPTH=10` ： 再帰の深さ上限


### 生成

```
$ ./index_ts_generator.sh ./target_directory
```

実行前

```
|--target_directory
|  |--dir1
|  |  |--dir2
|  |  |  |--file4.ts
|  |  |  |--file5.tsx
|  |  |  |--file6.test.tsx
|  |  |  |--file6.tsx
|  |  |  |--file_3.ts
|  |  |--dir3
|  |  |  |--file7.ts
|  |  |--file-1.test.ts
|  |  |--file-1.ts
|  |  |--file2.test.ts
|  |  |--file2.ts
|  |--file_0.ts
```

実行後

```
|--target_directory
|  |--dir1
|  |  |--dir2
|  |  |  |--file4.ts
|  |  |  |--file5.tsx
|  |  |  |--file6.test.tsx
|  |  |  |--file6.tsx
|  |  |  |--file_3.ts
|  |  |  |--index.ts
|  |  |--dir3
|  |  |  |--file7.ts
|  |  |  |--index.ts
|  |  |--file-1.test.ts
|  |  |--file-1.ts
|  |  |--file2.test.ts
|  |  |--file2.ts
|  |  |--index.ts
|  |--file_0.ts
|  |--index.ts
   
```

デフォルトの正規表現で `##.test.ts` のようなファイルは除外される。

```ts
// dir1/index.ts

export * from './file-1'
export * from './file2'
export * from './dir2'
export * from './dir3'
```

### 削除

```
$ ./index_ts_generator.sh ./target_directory clear
```




---

久々にシェルスクリプトを書いたので拙い部分がいろいろある気がします。改善すべき部分などがあればぜひコメントで教えてください。
iptablesのパケットフィルタの基本コマンド例

iptablesの基本的な使用例についてのメモ。
最初に使いたくなるのはfilterテーブルだと思うのでfilterテーブルでパケット破棄するルールの設定例を紹介する。

## まずはパケットのフィルタリングテーブルを表示
iptables -nvL　でfilterテーブルの内容を確認できる。


```console
# iptables -nvL
Chain INPUT (policy ACCEPT 798 packets, 69179 bytes)
 pkts bytes target     prot opt in     out     source          destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source          destination         

Chain OUTPUT (policy ACCEPT 793 packets, 70755 bytes)
 pkts bytes target     prot opt in     out     source          destination         
# 
```

## パケットのフィルタリングを設定してみる
UDPで送信元IPアドレスが10.10.10.0/24で、送信先アドレスが20.20.20.5で、送信先ポート番号が20000で、eth0インタフェースに入ってくるパケットを、破棄する設定を入れるコマンドはこんな感じ。

```console
# iptables -A INPUT -p udp -i eth0 -s 10.10.10.0/24 -d 20.20.20.5 --dport 20000 -j DROP
```

- チェインについて
<br>
入ってくるパケットに対しては INPUT チェインを指定。送信するパケットに対しては OUTPUT チェイン、転送するパケットに対しては FORWARD チェイン。<br>
-A [チェイン] でルールを追記。<br>
-I [チェイン] [数字] でルールを数字で指定されたインデックスに挿入。<br><br>
- プロトコルについて
<br>
-p でプロトコル指定(tcp / udp / icmp)。<br><br>
- NWインタフェースについて
<br>
-i でパケットが入ってくるインターフェース名を指定。<br><br>
- IPアドレス、ポート番号について
<br>
-s で送信元IPアドレス、-dで送信先IPアドレス、--dportで送信先ポート番号の指定。<br><br>
- パケットの処理方法について
<br>-j でパケットの処理方法を指定(DROP(破棄) / ACCEPT(許容) / REJECT(拒否))。<br><br>


## 再度filterテーブルを確認。
コマンド投入後にルールを再表示するとこんな感じでINPUTチェインにルールが追加されたことがわかる。

```console
# iptables -nvL
Chain INPUT (policy ACCEPT 121 packets, 9944 bytes)
 pkts bytes target     prot opt in     out     source          destination         
    0     0 DROP       udp  --  eth0   *       10.10.10.0/24   20.20.20.5        udp dpt:20000

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source          destination         

Chain OUTPUT (policy ACCEPT 110 packets, 9142 bytes)
 pkts bytes target     prot opt in     out     source          destination         
```

## IPパケットのフィルタリングを削除
ルールの解除は、設定投入時のコマンドに対し、-Aを-Dに変更するだけでOK。

```console
# iptables -D INPUT -p udp -i eth0 -s 10.10.10.0/24 -d 20.20.20.5 --dport 20000 -j DROP
```

あるいは、インデックス指定でも削除可能。

```console
# iptables -D INPUT 1
```

## ルールの全消し
ルールをすべて削除したいときは -F オプション。危険なので気軽に打たないこと。

```
# iptables -F
```

## もっと深くしりたい？
- 他のオプションについて
<br>iptablesの全オプションはこちらのURLが参考になります。<br>
https://linuxjm.osdn.jp/html/iptables/man8/iptables.8.html<br><br>
- チェインやテーブルについて
<br>チェインには、今回紹介した INPUT / OUTPUT / FORWARD の他にも、PREROUTING / POSTROUTING などがあります。<br>
また、テーブルについても、今回のフィルタ(filter)テーブルの他にも nat や mangle などがあります。<br>
これらのチェインやテーブルは、パケットフローの中でどの部分にルールを適用するかによって使い分けることになります。<br><br>
パケットフローの仕組みは以下の図が参考になります。iptablesの領域は「Network Layer」の箇所です。<br>
https://commons.wikimedia.org/wiki/File:Netfilter-packet-flow.svg<br>
matplotlib plot の勉強

#plotの勉強

複数のcsvを読み込むことはできたが、
plotした図は正直、、、な状態だったので、どうにか見れる状態にすることが目的。

#線グラフ
<pre>
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import glob
import csv

csv_files = glob.glob(r'インプットファイルフォルダ\*.csv')
list = []

for f in csv_files:
    list.append(pd.read_csv(f, index_col=0).drop(['企業コード','企業名称','店舗コード','店舗名称','支払番号','返金番号'], axis=1))
df = pd.concat(list)

df_pre = df["日時"].str.split("\"").str[1]
df_pre_pre = df_pre.str.split(" ").str[0]
df["日時"] = df_pre_pre.str.split(":").str[0]

data = pd.pivot_table(df, index='日時',  columns='種別',  values='金額', aggfunc=[sum])
data2 = data.fillna(0)


#plotはここからdata2を使用
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(1,1,1)

data2.plot(ax=ax ,kind='bar' ,stacked=True)

plt.title("dayly",fontsize=14)
plt.xlabel("day", fontsize=7)
plt.ylabel("money", fontsize=7)
plt.subplots_adjust(bottom=0.3)
plt.tick_params(labelsize=5)
plt.legend(bbox_to_anchor=(1.0,1), loc='upper left',borderaxespad=0,fontsize=10)
plt.subplots_adjust(left = 0.1, right = 0.8)

plt.savefig(r"アウトプット")

</pre>

##できた図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395963/21619013-ebe2-8adc-a406-f3427cd21b8f.png)


注意したのは↓
stacked=True


#折れ線
<pre>
#plotはここからdata2を使用するよん
fig = plt.figure(figsize=(8,6))
ax = fig.add_subplot(1,1,1)

data2.plot(rot=30)

plt.title("dayly",fontsize=14)
plt.xlabel("day", fontsize=7)
plt.ylabel("money", fontsize=7)
plt.subplots_adjust(bottom=0.3)
plt.tick_params(labelsize=10)
plt.legend(bbox_to_anchor=(1.0,1), loc='upper left',borderaxespad=0,fontsize=10)
plt.subplots_adjust(left = 0.1, right = 0.8)

plt.savefig(r"アウトプット")
</pre>

##できた図。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395963/a1cd6a11-025b-43d7-4c88-9739d5009a44.png)
ISUCON9予選参戦記

# はじめに
本記事はISUCON9予選の参戦記です。
ISUCONは初参加で、組み込みからWeb系へ転職して1年半でどの程度知識が得られているのかの確認に気持ちで参加を決めました。言語はRubyです。
結果は3020点と振るわなかったのですが、意外と多くのことができたかなと考えています。
事前にあまり準備ができなかったのが後悔で、次回の実施があれば予選通過を目指して準備する予定です。

# 前日までにやったこと
過去問を解きたいと考えていたのですが、時間が取れずツールの使い方を確認しただけでした。
ただ、これだけの準備でも当日スコアを伸ばすために貢献したかなと考えています。

* チームでの役割分担
* 当日午前中の時間の使い方の確認
* 自分が担当する作業の手順確認
    * Githubへバックアップする手順
    * alpの使い方

# 当日やったこと
ここに挙げる内容は自分が行なった作業です。チームとしてはもう少し試みています。
スコアを伸ばすのに直接貢献した修正はcategoryのオンメモリ化とN+1問題の解消でした。
NginxやMySQLのチューニングは期待していたほどの効果は得られず、方法に問題があったと考えています。

* Githubのリポジトリ作成
* Nginxのログの設定
* alpでNginxのログ解析
* categoryのオンメモリ化
* getNewCategoryItemsのN+1問題を解消
* 複数台構成に変更（Nginx + App, DBの2台構成）
* MySQLのチューニング
* Nginxのチューニング

# 当日出来なかったこと
基本的には技術力不足が原因で実現しなかったのが以下に挙げる内容です。
着手したにも関わらず完遂しなかったという点で、複数台構成が一番悔しいポイントでした。

* 3台構成
    * 本当はNginx + App, App, DBの3台構成にしたかった
    * NginxでL7ロードバランサを実現する方法が分からなかった
* キャンペーンの還元率の設定
    * ルールの理解が足りず、設定しようと思ったタイミングはなかった
* 配送サービスAPIのチューニング
    * ボトルネックであることは認識したが、具体的な対策が分からなかった
    * 不要なAPIアクセスの存在には気が付けなかった
* ログイン問題
    * bcryptがボトルネックであることは認識したが、優先順位が低かった
    * 3台構成にできたら対応した可能性もあったか?
* その他のN+1問題の解消
    * 着手できる箇所が他にもあることは競技中に認識していた
    * 優先順位がチーム内で決定できておらず、他の作業を行なった

# 感想
冒頭にも書きましたが、事前準備の割には色々手をつけることはできたかなと思います。
一切スコアを伸ばせないことも考えていたので、少しでもスコアを伸ばすことができたのは率直に嬉しかったです。

一方で、同じ条件でこれだけの差がついてしまったのは非常に悔しいです。
技術力、事前準備、当日の段取りの全てで劣ってしまったのだと認識しています。

次回、開催されることがあればせめて事前準備などの努力で補える部分ではやりきったと思えるようにしたいと思います。
フォトショになりたい Part 1: トーンカーブ

# フォトショになりたい

- 画像加工系の機能を一つづつ実装するだけ

## 概要
- トーンカーブ
- LUT
- 露出
- ガンマ
- 両対数スケール
- コントラスト

注: この記事は[Python3 & OpenCV で画像処理を学ぶ[3] 〜 トーンカーブ と LUT を理解する実装実験](http://optie.hatenablog.com/entry/2018/03/03/141427)と内容が鬼ほど被っています

## トーンカーブ

↓これ
<img width="315" alt="スクリーンショット 2019-10-02 17.33.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204792/9ec88c01-6846-e542-898a-5a7a3095d4e4.png">

要するに$[0, 255] \rightarrow [0, 255]$の関数


## LUT
全ピクセルに毎回演算してたら重すぎてたまったもんじゃない

→$[0, 255] \rightarrow [0, 255]$で、基本的には整数値なのだから**256×256の表があればいい**

→**LUT(Look Up Table)**

トーンカーブ編集系のエフェクトは、全て「LUTをいじる→LUTに従って画像を変換する」とすると良い

```Javascript:editLUT.js
function editLUT(img) {
  const lut = new Array(256);
  for (let i = 0; i < 256; i += 1) {
    let val = hoge(i); //ここでエフェクトをかける
    lut[i] = val;
  }
  LUT(img, lut);
  return img;
}
```

## 露出
k倍するだけ

```math
f(v) = kv
```

ただ、kが1を超える時に明るいところがクリップするので対処する

```Javascript:exposure.js
function exposure(x, t) {
  return Math.min(x * t, 255);
}
```

## ガンマ
正規化してγ乗するだけ

```math
f(v) = v^\gamma
```

(詳しくは[ガンマ補正のうんちく](https://qiita.com/yoya/items/122b93970c190068c752)を参照)

```Javascript:gammaFunc.js
const gammaFunc = (val, gamma) => 255 * Math.pow(val / 255, 1 / gamma);
```

## 両対数スケール
ガンマよりも両端に関して滑らからしい
(詳しくは[スケール対数曲線をトーンカーブとする画像補正](https://mikio.hatenablog.com/entry/2018/11/16/015606)を参照)

```math
f(v) = \frac{{\rm log}(1+Cv)}{{\rm log}(1+C)}\\
```
逆関数:

```math
f^{-1}(v) = \frac{e^{v{\rm log}(1+C)}-1}{C}
```

```Javascript:log_log_scale.js
const log_log_scale = (v, C) =>
    C == 0 ? v
  : C > 0 ? 255*Math.log(1+v/255*C)/Math.log(1+C)
  : -255*(Math.exp(v/255*Math.log(1-C))-1)/C;
``` 


## コントラスト
暗いところをより暗く、明るいところをより明るく→**S字カーブ**

基本的には**シグモイド**でいい
(詳しくは[シグモイド関数でコントラスト強調](http://kesaranpa.hatenablog.com/entry/2018/02/10/211641)を参照)

でも定義域が有界じゃないので少し修正してもいい
(詳しい議論は[Sigmoid曲線の定義域と値域を[0,1]にしたいだけ](https://qiita.com/music_shio/items/305e92baf79ae9ae13c6)を参照)

```Javascript:pseudoSigmoid.js
const pseudoSigmoid (x, t, MAX) => // Maxは255とか
    t === 0 ? x
  : t > 0 ? (Math.asinh((2 * x / MAX - 1) * Math.sinh(t)) / 2 / t + 0.5) * MAX
  : (Math.sinh(t * (2 * x / MAX - 1)) / 2 / Math.sinh(t) + 0.5) * MAX;
```

中心の値をいじりたければ[シグモイド関数でコントラスト強調](http://kesaranpa.hatenablog.com/entry/2018/02/10/211641)の実装が良さそう


## まとめ
- トーンカーブはLUTを使って実装する
- この辺りの関数は後に他でも用いるので覚えておく
JavaScript（定数、テンプレートリテラル）

##定数
変数と似たものに定数がある。
**定数は更新（上書き）が出来ない。**
###定数の定義
「let」の代わりに**「const」**を用いて定義する。

##テンプレートリテラル
「+」とは違う、連結方式。
定数（変数）を文字列のなかに埋め込むことができる。

`${（定数・変数）}`
文字列全体をバッククォート(`)で囲む。

```js
//テンプレートリテラルの書き方
const name = "太郎" ;
console.log(`こんにちは、${name}さん`);

//コンソール
こんにちは、太郎さん
```
コンテキストのテーブル間伝播（PowerBI/PowerPivot/DAX）

[前回](https://qiita.com/zaboom/items/132190c52bc68f7c1bff)、PowerBI/PowerPivot（以下、総称してDAXと呼びます）におけるコンテキスト（行コンテキスト、フィルターコンテキスト）のALL関数について書きました。
今回は、テーブルのリレーションシップを跨いでコンテキストがどのように影響を及ぼすかについて書いてみたいと思います。

## 行コンテキストのリレーション間伝播

例として、下記のようなテーブル構成を考えてみます。

![リレーション.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/499774/fb18454e-a3d3-089f-b0e0-bf4ba32f5b76.png)


この場合において、売上明細テーブルに計算列を作成し、下記のようなDAX式を定義してみます。

[予実比較] = 売上明細[販売単価] - 商品[定価]

売上明細テーブルで行コンテキストが評価されるため、売上明細テーブルを反復処理します。この場合、商品テーブルは参照できません。エラーになります。

しかし、よく考えてみると、不思議です。売上明細テーブルから商品テーブルへのリレーションは一方向で、[商品]1：[売上明細]多の関係です。売上明細から商品は一意に特定できるので、参照可能ではないかとも思えます。

DAXではこのような場合、RELATED関数を使用して明示的にリレーションの参照を指示する必要があります。下記のように変更すると、うまくいきます。

[予実比較] = 売上明細[販売単価] - RELATED(商品[定価])

RELATED関数はリレーションシップの（1対多）関係のうち、「多」側のテーブルで行コンテキストが評価される場合に機能します。「多」側テーブルから、関係テーブルを参照できます。
その逆はどうでしょうか。逆の場合はデータを一意に特定できず、複数の値が返されるためRELATED関数ではうまく機能しません。このような場合にはRELATEDTABLE関数を使用します。

[販売数] = COUNTROWS(RELATEDTABLE('売上明細'))

RELATEDTABLE関数は、指定されたリレーションシップテーブルにおいて、関連する行を全て返します。上記の式は、ヒットした行をカウントしています。

## フィルターコンテキストのリレーション間伝播
行コンテキストでは明示的に関数によってリレーションの参照を行う必要がありました。フィルターコンテキストの場合は、いわば自動的に参照します。参照が可能な場合にのみ参照する、とも言えます。
しかし、難しく考えることはありません。基本的に、リレーションダイアグラムの矢印方向に沿ってのみ参照が可能であるという理解で問題ありません。

例えば、[顧客]テーブルの[顧客ID]を行要素として表示している際に、

[顧客別販売量] = COUNTROWS（売上明細）

として販売量をだすことは可能です。なぜなら、顧客テーブルから売上明細への矢印方向に従っているからです。上記の例では他にも[商品]から[売上明細]への参照も同様に有効です。
逆の参照が行われた場合（例えば、売上明細から顧客テーブルへの参照が行われた場合）には全数が返されます（つまり、全顧客数が返されることになります）　適切な参照が行われず、列全体が返されています。

また、フィルターコンテキストも行コンテキストの場合と同じように、関係をいくつも跨いでいくことができます。リレーションシップの矢印方向に従った形であれば、ホップ数に関係なく参照することができます。
CentOS 8 について今までと変わったところ

CentOS 8をインストールしてつまずきそうなところをメモするページ

## network.serviceがなくなった

ではどうするか


[How to Start/Stop/Restart Network Service on CentOS 8 or RHEL 8](https://www.osetc.com/en/how-to-start-stop-restart-network-service-on-centos-8-or-rhel-8.html)

1. NetworkManagerを使用する

2. nmcliを使用する

## pam_krb5がなくなった
sssdに吸収されたってことなのかな？
Sambaをドメインに参加させるのに影響はなかった

## tarがなくなった

まじかよ。
[CentOS8 (Minimum) インストールしてとんでもなかったこと一覧](https://north.thco.mp/2019/09/26/centos8-minimum/)

```Base
$ sudo dnf install tar
```
Laravel：Trait内で毎回呼び出す処理を実装できた

Traitってなんだ？はこちらの記事を参照。
https://qiita.com/mokkos/items/53d1d4cbf57bd6ceba5e

Trait に共通処理を実装している場合、常に呼び出したい処理ってありますよね。
公式ドキュメントに載っていなかったのでまとめました。

まず、laravel は Model の基盤を Eloquent というクラスで定義しています。
それにより、Model内で boot() を書けば・・・あら不思議。Eloquentが呼び出されたとき、自動的に関数が呼び出されます。

```php5

class Fugafuga extends Model
{
  public static function boot()
  {
   // __construct() が呼び出された後に実行されます
  }
}
```

深掘りして、Model.php をみてみると・・・・

```php

/**
  * Boot all of the bootable traits on the model.
  *
  * @return void
  */
protected static function bootTraits()
{
    $class = static::class;

    foreach (class_uses_recursive($class) as $trait) {
        if (method_exists($class, $method = 'boot'.class_basename($trait))) {
            forward_static_call([$class, $method]);
        }
    }
}
```


が実装されていました。 
つまり、Traitでも boot+（Trait名）って書くと勝手に初期に呼び出してくれることになります。

```php

Trait Hogehoge
{
  public static function bootHogehoge()
  {
  }
}
```

このように実装することで、Hogehoge 内の関数が呼び出される直前に bootHogehoge() が呼び出されました！
git 忘却録


## 問題　pushしたいが403が出てしまう場合

例えば

```
git clone https://github.com/{ユーザ名}/{レポジトリー名}.git
cd {レポジトリー名}
echo "# {レポジトリー名}" >> README.md
git add README.md
git commit -m "first commit"
git push -u origin master
```
みたいなことをした場合、以下のエラーがでてしまうことがあります

```
remote: Permission to {ユーザ名}/{レポジトリー名}.git denied to xxxx.
fatal: unable to access 'https://github.com/{ユーザ名}/{レポジトリー名}.git/': The requested URL returned error: 403
```

## 対処方法
ドメイン部分の先頭に「{ユーザ名}@」を入れるのがコツです。そうすると対話形式でパスワードを確認してくるので、パスワードを認証することができます。

```
git remote set-url origin https://{ユーザ名}@github.com/{ユーザ名}/{レポジトリー名}.git
git push -u origin master

成功！
```
【RubyMine】アプリの動作が重くなったときはWindows Defenderのスキャンから除外してみよう

RubyMineの起動や一部の操作後（例えば`bundle install`でファイルが大量に作成された時）にCPUを専有してアプリの挙動が重くなることがありました。

タスクマネージャでしらべてみると、Windows Defender（Windows謹製のウィルス対策ソフト）のリアルタイムスキャン機能が働いていることがわかりました。

任意のプロセスをスキャン対象から除外することでこの挙動を抑制することができたので紹介します。

## 設定方法

IDEプロセスをインストール済みのウイルス対策の除外リストに追加します。Windows Defenderの手順は次のとおりです。

1. **Windows セキュリティ** を開きます
2. そこから以下の項目をすすみます
   1. **ウイルスと脅威の防止**
   2. **ウイルスと脅威の防止の設定 > 設定の管理**
   3. **除外 > 除外の追加または削除**
   4. 最後に **除外の追加** を選択し、「`rubymine64.exe`」プロセスを指定します。

> ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883/4d352638-84a2-274e-f3d4-766b54bb0037.png)

このようになっていればOKです。


## 参考

* ウィルス対策ソフトがビルド時間に与える影響について：[Antivirus Impact on Build Speed – IDEs Support \(IntelliJ Platform\) \| JetBrains](https://intellij-support.jetbrains.com/hc/en-us/articles/360006298560)
* プロセスの除外設定の方法について：[Slow startup on Windows: splash screen appears in more than 20 seconds – IDEs Support \(IntelliJ Platform\) \| JetBrains](https://intellij-support.jetbrains.com/hc/en-us/articles/360005028939-Slow-startup-on-Windows-splash-screen-appears-in-more-than-20-seconds)

* [Windows セキュリティでのウイルスと脅威の防止 - Windows Help](https://support.microsoft.com/ja-jp/help/4012987)
> ウイルスのスキャンから項目を除外する 信頼できることが確実で、スキャンする必要がないと思われる場合は、特定のファイル、フォルダー、ファイル形式、プロセスをスキャンから除外することができます。