OmniAICreator/Qiita-1.07M huggingface dataset:
[JavaScript] 伸び縮みするテキストボックスを実装する (Vanilla JS)

# やりたいこと

値の長さに応じて幅が変わる input 要素を実装したい。

# 実装

```js
/*
 * fromElement から toElement にスタイルをコピーする。
 */
const copyComputedStyle = (fromElement, toElement, except = []) => {
  const computedStyle = getComputedStyle(fromElement);
  Array.from(computedStyle).forEach((key) => {
    if (!except.includes(key)) {
      const value = computedStyle.getPropertyValue(key);
      const priority = computedStyle.getPropertyPriority(key);
      toElement.style.setProperty(key, value, priority);
    }
  });
};

/*
 * 文字列を HTML エスケープする。
 */
const escapeHTML = (text) => {
  if (typeof text !== 'string') {
    return text;
  }
  
  return text.replace(/[&'`"<> ]/g, (match) => {
    return {
      '&': '&amp;',
      "'": '&#x27;',
      '`': '&#x60;',
      '"': '&quot;',
      '<': '&lt;',
      '>': '&gt;',
      ' ': '&nbsp;'
    }[match]
  });
};

/*
 * 仮の span 要素の innerHTML に input 要素の値を設定して width を計測する。
 */
const getTextWidth = (input) => {
  // span 要素はなるべく input 要素と同じスタイルにする。
  const span = document.createElement('span');
  copyComputedStyle(input, span, ['display', 'width']);
  span.style.maxWidth = '100vw';
  
　span.innerHTML = escapeHTML(input.value);
  document.body.appendChild(span);
  const width = span.getBoundingClientRect().width;
  document.body.removeChild(span);

  return width;
};

const adjustWidth = (input) => {
  input.style.width = `${getTextWidth(input)}px`;
};

const input = document.querySelector('input');
adjustWidth(input);
input.addEventListener('keyup', adjustWidth.bind(null, input));
```

# デモ

デモ用画面の幅に余裕を持たせるため 0.5x で試すことをおすすめします。

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="quanon" data-slug-hash="dEqdeo" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="伸び縮みするテキストボックス">
  <span>See the Pen <a href="https://codepen.io/quanon/pen/dEqdeo/">
  伸び縮みするテキストボックス</a> by QUANON (<a href="https://codepen.io/quanon">@quanon</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 参考

* [Adjust width of input field to its input](https://stackoverflow.com/questions/3392493/adjust-width-of-input-field-to-its-input)
  * 全体的なアイディアとして参考にした。 
* [Set / Copy javascript computed style from one element to another](https://stackoverflow.com/questions/19784064/set-copy-javascript-computed-style-from-one-element-to-another)
  * CSS によるスタイルを別の要素に適用する方法を参考にした。 
* [JavaScriptでHTMLエスケープ処理](https://qiita.com/saekis/items/c2b41cd8940923863791)
  * Vanilla JS で文字列を HTML エスケープする方法を参考にした。
* MDN Web Docs
  * [Element.getComputedStyle()](https://developer.mozilla.org/ja/docs/Web/API/Window/getComputedStyle)
  * [CSSStyle​Declaration](https://developer.mozilla.org/ja/docs/Web/API/CSSStyleDeclaration)
  * [Element.getBoundingClientRect()] (https://developer.mozilla.org/ja/docs/Web/API/Element/getBoundingClientRect)
Socksサーバのインストール on CentOS

# 前書き
俗にいう串が欲しかったもののhttp proxyサーバを立てるだけでは芸がないので、socksサーバを立てた。
ネットでは、内部のネットワークから外のインターネットに接続する際に用いる使い方の記事が多いが、本記事では「発信元IPを偽装する」ような使い方をするための設定を記載する。

なお、socksサーバはプロトコルを考慮せずともすべてプロキシ経由にできることがhttp proxyサーバとの最も大きな違い。

## 環境
```bash
[puri@banana ~]$ cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
```

# インストール方法
[CentOSでSOCKSサーバ(Dante)を構築する](https://kagasu.hatenablog.com/entry/2017/08/26/173052)を参考にインストール

# 設定
- clientなんちゃらはsocksサーバに接続する際に適用される設定項目
- socksなんちゃらはsocksサーバで認証された後に適用される設定項目

[公式ドキュメント](http://www.inet.no/dante/doc/latest/config/server.html)を確認のこと

```sockd.conf
internal: eth0 port = xxxx
# 認証方法 （passwdを用いた認証。平文でパスワードが送信されることに注意）
socksmethod: username
clientmethod: none
# passさせるクライアントの設定。
# ここではIP制限は設けていない
client pass {
        from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0
        clientmethod: none # match all idented users that also are in passwordfile
        socksmethod: username
}
# ローカルへのアクセスをブロック
socks block {
        from: 0.0.0.0/0 to: lo0
        log: connect error
}
socks pass {
        from: 0.0.0.0/0 to: 0.0.0.0/0
        command: bind connect udpassociate
        log: error
        socksmethod: username
        clientmethod: none
        protocol: tcp udp
}
```

# ポート開放
```bash
sudo firewall-cmd --add-port=xxx/tcp --permanent
sudo firewall-cmd --reload
```

# 起動
```bash
sudo systemctl start sockd
```

# 起動確認
Firefox + FoxyProxyで確認する
認証付きsocks5サーバはFx単体でアクセスできないことに注意
発信IPがsocksサーバのものになっていることを確認する
VScodeでLLDBでC++をデバッグするときファイルをリダイレクトする方法

# 背景
vscodeでC++のデバッグをするとき、ファイルをリダイレクトしたいと思った。launch.jsonのデバッグのタスクを作る時、argsのところに[">", "input.txt"]としたがリダイレクトできなかった。
## フォルダ構成
/src
-　 target.cpp
-　 input.text

# 解決策
launch.jsonでデバッグのタスクの"configurations"に

```cpp:launch.json
"setupCommands": [
                {
                    "text": "settings set target.input-path ${fileDirname}/input.txt"
                }
]
```
を追加する。

# 参考記事
[Cannot get lldb to read file input - stack overflow](https://stackoverflow.com/questions/35582881/cannot-get-lldb-to-read-file-input)
[VS Code lldb debugging with stdin](https://vincepergolizzi.com/programming/2018/04/03/vscode-lldb-debugging-stdin.html)
【書評】現場で使える Django REST Framework の薄い本

## 買ったきっかけ
Django REST Framework（DRF）を使った開発を行うことになり、
ネット等で情報収集やサンプルプログラムの作成をしていたのですが、
なかなか欲しい情報がなく、まとまった知識を得る為に購入しました。
（ちなみにDjangoはいくつか本があるのですが、DRFはこの本以外にたぶんない）
[現場で使える Django REST Framework の薄い本【紙の本】（技術書典6バージョン） - - BOOTH](https://booth.pm/ja/items/1314617)
で買いました。

## 内容と感想

#### 第1章： Django REST Framework（DRF）の概要
REST APIの基本から、DRFの全体構成などの説明など
図があってわかりやすい。

#### 第2章： モデル・シリアライザ・ビュー・URLconf の基本的な使い方
使い方や処理の流れが記載されてます。
他サイトのチュートリアルは、ModelViewSetを使ったものばかりで、
少し複雑なAPIを作ろうとする時にどうすればいいかわからなかったのですが、
ここでは、APIViewにも言及されていて、こちらの方が汎用的であることがわかりました。
開発ではAPIViewを使うことが多くなりそうです。

#### 第3章： DRF とセキュリティ
基本的なセキュリティーに関する知識で、DRF特有の情報が少ないです。

#### 第4章： DRF と認証
Basic認証、Cokkie認証、トークン認証、リモートユーザー認証、JWT認証の各方式に関しての紹介とどれを使うべきが記載されています。
今回使う予定だった認証方式についても詳しく紹介されていて参考になりました。

#### 第5章： チュートリアル その1、第6章チュートリアル その2
よくある本では、前半はチュートリアルで、後半に詳細な機能やリファレンスが記載されていることが多いのですが、この本は逆でした。
書籍にもソースコードが記載されていますが、全部ではないので、サンプルコードをダウンロードした上で読み進めるとわかりやすいです。
チュートリアル その1は比較的簡単にできますが、チュートリアル その2はVueの知識が少し必要です。
（dockerを使ったローカルの動作環境が特殊でその2はうまく動かなかった・・・。）
今回、APIのみ実装予定だったので、その1を作り、JWT認証に変えたものを試しました。
JWT認証は第6章よりも、第4章の方が参考になります。

#### 第7章： 現場で使える Tips 集
今後、実際に開発する中で適宜読む予定。

#### 全体を通して
DRFは、Djangoの知識が前提になるので、Djangoをうろ覚えだったらまずDjangoを覚えた方がいいです。
ネットのチュートリアルの方が環境の作り方からわかりやすく載ってたりするので、この書籍が難しければそちらを試してから読む方がいいです。
全体通してとてもわかりやすく詳しく書かれていて、最初からこれを読んだらよかったと思いました。

## 今後は
書籍にも書かれていましたが、
[[Django REST Framework] Serializer の 使い方 をまとめてみた](http://note.crohaco.net/2018/django-rest-framework-serializer/)
[[Django REST Framework] View の使い方をまとめてみた](http://note.crohaco.net/2018/django-rest-framework-view/)
を見ていく予定です。
【Docker】よく使うコマンドまとめ

最近Dockerの履修を始めたので自分用めも。

#確認系
```
# dockerの色々を確認
$ docker info

# 動いているコンテナを見る
$ docker ps

# 動いていないコンテナも見る
$ docker ps -a

# イメージの確認
$ docker images
```

#コンテナ起動関係
CONTAINER IDは特定ができる所まで入力すれば省略が可能。

```
# コンテナを起動
$ docker start [CONTAINER ID]

# コンテナを終了
$ docker stop [CONTAINER ID]

# コンテナに入る
$ docker attach [CONTAINER ID]

# コンテナを終了
$ exit

# コンテナを抜ける
$ Ctrl + p + q
```

#削除系
イメージが使っているコンテナが存在する場合エラーを投げてくれるので、不要なイメージを削除する場合は不要なコンテナを先に削除する。

```
# コンテナの削除。複数指定可能
$ docker rm [CONTAINER ID] [CONTAINER ID] ......

# コンテナを全て削除。注意
$ docker rm `docker ps -a -q`

# イメージの削除
$ docker rmi [IMAGE ID]
```

#その他
```
# イメージのリネーム
$ docker tag [SRC REPOSITORY]:[SRC TAG] [DST REPOSITORY]:[DST TAG]
$ docker rmi [SRC IMAGE ID]

# コンテナをファイル出力
$ docker export [CONTAINER ID] > [DST].tar

# ファイルからコンテナを作成
$ cat [SRC].tar | docker import - [REPOSITORY]:[TAG]
```
NSDの設定を(できるだけ最低限に)設定してみた。

NSDを構築してみた。


# 動作環境
- Virtualbox 6.0
- Alpine Linux
- Network
  - NAT
  - ホストオンリーアダプタ


| サーバー | IPアドレス |
|---|---|
|NSD|192.168.57.2|
|HTTP|192.168.57.151|


# NSD側

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

```
apk add nsd
```

## IPアドレスの設定

`/etc/network/interfaces`に以下を追記します。

```
auto eth1
iface eth1 inet static
    address 192.168.57.2
    netmask 255.255.255.0
```

## `/etc/resolv.conf`の変更

ローカルから`nslookup`コマンドで確認を取りたい場合は変更します。

```
nameserver 192.168.57.2
```


## `/etc/nsd/nsd.conf`の設定

NSDの設定をします。

```
server:
  ip-address: 192.168.57.2
  port: 53
  do-ip4: yes
  do-ip6: no
  zonesdir: "/etc/nsd/zone"

remote-control:
  control-enable: no

zone:
  name: "example.com"
  zonefile: "example.com.zone"

zone:
  name: "57.168.192.in-addr.arpa"
  zonefile: "example.com.rev"
  
```


## 正引きのゾーンファイルの作成

`/etc/nsd/zone/example.com.zone`を作成します。


```
$TTL 3600
$ORIGIN example.com.

@ IN SOA ns.example.com. mail.example.com. (
;    2019052601; Serial
;    3600; Reflesh
;    900;  Retry
;    3600000; Expire
;    3600 ; Minimum
    )

test IN A 192.168.57.151
```


## NSDの起動

```bash
/etc/init.d/nsd start
```


## 動作の確認

### Test 1 ローカルから

ローカルマシンからの以下のコマンドを実行し、登録した名前が解決されるのか確認します。


```bash
drill test.example.com @192.168.57.2
```
`ANSWER SECTION`に登録した名前が反映されていれば成功です。


### Test 2 外部から

他のマシンから先ほどと同様のテストを行います。
ホストマシンからでも、ゲストマシンからでも、どちらでも構いません。


## 逆引きのゾーンファイルの作成

`/etc/nsd/zone/example.com.rev`を作成します。


```
$TTL 3600
$ORIGIN 57.168.192.in-addr.arpa

@ IN SOA ns.example.com. mail.example.com. (
;    2019052601; Serial
;    3600; Reflesh
;    900;  Retry
;    3600000; Expire
;    3600 ; Minimum TTL
  )

151 IN PTR test.example.com.
```

## 動作の確認

正引きのゾーンファイルを作成したときと同じテストを行います。今回のコマンドは次のとおりになります。

```bash
drill -o rd @192.168.57.2 -x 192.168.57.151
```




## サービスの登録

仮想マシンを立ち挙げた時にNSDも同時に立ち上がってほしいので、サービスを有効化します。

```bash
rc-update add nsd
```


# テスト用HTTPサーバ

## 動作環境

- Lubuntu 
- ネットワークアダプター２
  - ホストオンリーアダプタ


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

```bash
apt install apache2
```


## IPアドレスの設定

`/etc/systemd/network/50-enp0s8.network`を新しく作成し、次のとおりに書き込みます。

```
[Match]
Name=enp0s8
Virtualization=yes

[Address]
Address=192.168.57.151/24
```

書き込んだ後、サービスを有効化し、起動します。

```bash
systemctl start systemd-networkd
systemctl enable systemd-networkd
```


## HTTPサーバの起動

```
systemctl start apache2
```


## 起動の確認

他のマシンから次のコマンドを実行します。

```bash
wget http://192.168.57.151 
```

カレントディレクトリに`index.html`がダウンロードされていれば、起動は成功しています。


# 確認：NSDが機能しているか

別のマシンの`/etc/resolv.conf`を次のとおりに書き換えます。

```
nameserver 192.168.57.2
```

そして、次のコマンドを実行します。
```bash
wget http://test.example.com -O url-to-addr.html
```

ファイルがダウンロードされていれば、成功しているでしょう。


# 参考

- [FreeBSD 12.0 RELEASE - DNS サーバ - nsd 設定](https://freebsd.sing.ne.jp/02/12.00/05/02.html#3.)
- [BINDによるDNSの運用](http://www.fc-lab.com/network/server/dns/zone.html)
- [DNSサーバー構築(BIND)](https://centossrv.com/bind.shtml)
- [TCP/IP - DNS 2](https://www.infraexpert.com/study/tcpip23.html)
Swiftの全角文字の活用

全角の変数や関数はほとんど使わないけど、どこかで活用できないかと考えてみた

開発環境
`Xcode 10.2.1`
`Swift 5`

# Date型をString型にするとき

```swift:
import Foundation

let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .gregorian)
formatter.locale = Locale(identifier: "ja-JP")
formatter.dateFormat = "yyyy/MM/dd"

let date = Date()
print (formatter.string(from: date))    // 2019/05/28
```


## dateFormatをenumで定義する
日時を表すアルファベットをよく忘れるのでenumを使用する

```swift:DateFormat
enum DateFormat {
    case yyyyMMdd
    case HHmmss
    
    var string: String {
        switch self {
        case .yyyyMMdd:
            return "yyyy/MM/dd"
        case .HHmmss:
            return "HH:mm:ss"
        }
    }
}
```

```swift:
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .gregorian)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = DateFormat.yyyyMMdd.string

let date = Date()
print (formatter.string(from: date))    // 2019/05/28
```

## 問題点
- 区切り文字が定義できない
- switch文で返す文字列を分岐させなきゃいけない

## 全角文字の使用
区切り文字を全角にすることで定義できる
文字列は `"\(self)"` で受け取り、 `applyingTransform(transform: , reverse: )`を使用し半角にすればOK

```swift:
enum DateFormat {
    case yyyy／MM／dd
    case HH：mm：ss

    var string: String {
        return "\(self)".applyingTransform(.fullwidthToHalfwidth, reverse: false)!
    }
}
```

### Extension

```swift:Date&nbsp;+&nbsp;toString
extension Date {
    
    func toString(_ dateFormat: DateFormat,
                  calendar: Calendar = Calendar(identifier: .gregorian),
                  locale: Locale     = Locale(identifier: "en_US_POSIX"),
                  timeZone: TimeZone = TimeZone.current) -> String {
        let formatter = DateFormatter()
        formatter.calendar   = calendar
        formatter.locale     = locale
        formatter.timeZone   = timeZone
        formatter.dateFormat = dateFormat.string
        
        return formatter.string(from: self)
    }
    
}
```

```swift:
print (Date().toString(.yyyy／MM／dd))    // 2019/05/28
```

# まとめ
- 全角記号は意外と使える場面があると思う
- 全角スペースは使用できないので注意

他に使用できそうなところがあったら教えてください
plunkerで真理値表 その３

#概要

plunkerで真理値表やってみた。
全加算器つくってみた。

#真理値表

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/c87c1b08-602c-ccde-f8a6-810c542a891e.png)

#回路図

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/18e5c5fc-76eb-59c2-c3c0-6855e8bcb7f1.png)


#サンプルコード

```
var c0 = new C(8);
c0.init(0, 2);
c0.xor(1, 2, 3);
c0.and(1, 2, 4);
c0.xor(0, 3, 7);
c0.and(0, 3, 5);
c0.or(4, 5, 6);
c0.table();
```
#成果物


https://embed.plnkr.co/Mk5BzYVF9Wjk6mpNIQTa/

以上。
外部からHomestead開発環境へアクセスできるようにする

Homesteadの開発環境に外部からアクセスしたいなーって思うとき（特に別の仮想環境から）
いろいろと設定めんどくさいなーって。

でもHomesteadすごい！
コマンドポチーですぐに外部からアクセスできるようになる！

とりあえず vagrant ssh で開発環境に入ってから

```
share homestead.test  // Homestead.yaml内の sitesで設定したmapを指定
```

こうすると、ngrokが起動して
![スクリーンショット 2019-05-29 20.10.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140846/3515e31f-35d2-71b2-c241-c060b67024cf.png)

```
ngrok by @inconshreveable
(Ctrl+C to quit)
                                                                                                                                                                                                                                                                                 
Session Status                online
Session Expires               7 hours, 57 minutes
Update                        update available (version 2.3.29, Ctrl-U to update)
Version                       2.2.8
Region                        United States (us)
Web Interface                 http://192.168.10.57:4040
Forwarding                    http://6ff770f8.ngrok.io -> localhost:80
Forwarding                    https://6ff770f8.ngrok.io -> localhost:80
                                                                                                                                                                                                                                                                                 
Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00    
```

こんなのがでてくる。

そしたら Forwarding されているURL(この場合は http://6ff770f8.ngrok.io )にアクセスする。


ばんざーい
[Vue.js] 複数の引数を持つfilterを使ってみたメモ


### Filter.js

**src直下にpluginsディレクトリを切り**、その中にfilter処理だけを書くFilter.jsを置く

```javascript

export default {
  install(vue) {
　　// 複数の引数を持つfilterはこれ↓
    vue.filter('関数名', (value, sum) => {
        console.log('関数名',value,sum)
      return (value / sum) * 100
    })
  },
}

```


## 使い方

```html

<p>
{{ 【value】 | percentageCalculation(【sum】) | decimalPointShaping }}%
</p>

```
plunkerで真理値表　その２

#概要

plunkerで真理値表やってみた。
ツールつくった。
画像に、番号を振るやつ。

#写真

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/18e5c5fc-76eb-59c2-c3c0-6855e8bcb7f1.png)

#成果物

https://embed.plnkr.co/9wlCZsPoicL5yq6YWFCQ/

以上。
SIerがWin-Winになる鍵。仮説(101)

SIerは、顧客に育てられるとよく言われます。

 <この項は書きかけです。順次追記します。>

顧客の方に技術力のある方がおみえになり、そういう方に出会うことが飛躍の機会かもしれません。

顧客側では、技術力のある人が疎まれて、担当から排除されることがあるかもしれません。

そこがSIerの出番かも。

顧客側の技術力のある人を見極めることが大事。

顧客側の技術力のある方に、協力要請するとWin-Winになる可能性がある。

確率分布として、SIerの８割よりも、顧客の２割の方が技術力があるというのが経験則です。

図描きます。

平均を求めると、Sierに技術力があるように感じるかもしれません。

確率分布で物事が捕らえられれば、どんどん見えてくるものがあるかも。

 ＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞

最後までおよみいただきありがとうございました。

いいね　💚、フォローをお願いします。

Thank you very much for reading to the last sentence.

Please press the like icon 💚　and follow me for your happy life.
【JS】時間を遅らせる必殺技,setTimeout

## こんなときに
* 数秒、遅らせて処理を行いたい。

## コード
```js
setTimeout(() => {
	//処理
}, 2000);
```

第一引数に処理。
第二引数に時間。単位はミリ秒（1000=1秒
Ruby製CLIツールの起動時間を最適化する

以下のようなbinstubを作りましょう。

```ruby
#!/usr/bin/env ruby
require 'bootsnap'
gem_name = 'rubocop'
exe_name = 'rubocop'
cache_dir = File.join(ENV['HOME'], '.cache', 'bootsnap', gem_name, exe_name)
Bootsnap.setup(cache_dir: cache_dir, load_path_cache: false, autoload_paths_cache: false)
load Gem.bin_path(gem_name, exe_name)
```

`Gem.bin_path`[^Gem.bin_path]は2つ引数を取ります。1つ目がgemの名前で2つ目が実行ファイルの名前です。
`gem_name`/`exe_name`を編集するとrubocop以外の他のCLIツールにもこのbinstubを適用できます。

[^Gem.bin_path]: https://www.rubydoc.info/github/rubygems/rubygems/Gem.bin_path

このbinstubなしの場合

```
% time rubocop -v
0.70.0
rubocop -v  0.76s user 0.20s system 97% cpu 0.983 total
```

このbinstubありの場合、初回は多少多めに時間がかかる

```
% time bin/rubocop -v
0.70.0
bin/rubocop -v  1.04s user 0.57s system 98% cpu 1.640 total
```

しかし一度実行してしまえばキャッシュが作られてるので早くなる

```
% time bin/rubocop -v
0.70.0
bin/rubocop -v  0.53s user 0.23s system 79% cpu 0.969 total
```

CLIツールのソースコードを一切変更せずbinstubつくるだけで起動時間を最適化できます。

やったね ✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌
#Slack に使いそうな「文字」絵文字 保存しとく記事

![ある_ある](https://user-images.githubusercontent.com/13635059/58540325-23ad9700-8234-11e9-8d61-3ef304635427.png)
![わかる](https://user-images.githubusercontent.com/13635059/58540341-26a88780-8234-11e9-8fca-f25197bb2097.png)

![いいね](https://user-images.githubusercontent.com/13635059/58540327-23ad9700-8234-11e9-83fa-d3d9e790fd49.png)
![うそ_やろ](https://user-images.githubusercontent.com/13635059/58540328-24462d80-8234-11e9-88c5-d823d66e5bf9.png)
![おつ_かれ](https://user-images.githubusercontent.com/13635059/58540329-24462d80-8234-11e9-96fc-0d7c2f61e64d.png)
![お大事に](https://user-images.githubusercontent.com/13635059/58540330-24462d80-8234-11e9-9a98-5a18b017528c.png)
![すば_らしい](https://user-images.githubusercontent.com/13635059/58540331-24dec400-8234-11e9-8a43-7ca874415e3b.png)
![すばら_しい](https://user-images.githubusercontent.com/13635059/58540332-24dec400-8234-11e9-9ea7-253cc6e28c0f.png)
![それな](https://user-images.githubusercontent.com/13635059/58540333-25775a80-8234-11e9-9e84-cba6a6f9d9ec.png)
![どん_まい](https://user-images.githubusercontent.com/13635059/58540334-25775a80-8234-11e9-9427-02e52f772a4d.png)
![へぇ](https://user-images.githubusercontent.com/13635059/58540335-260ff100-8234-11e9-883b-05daaad39ef6.png)

![まか_せろ](https://user-images.githubusercontent.com/13635059/58540336-260ff100-8234-11e9-8e0d-b73f7205bdff.png)
![まじ_でか](https://user-images.githubusercontent.com/13635059/58540337-260ff100-8234-11e9-8c40-902410f710da.png)
![やっ_たぜ](https://user-images.githubusercontent.com/13635059/58540338-260ff100-8234-11e9-933e-bc3c5d1e2b07.png)
![やばい](https://user-images.githubusercontent.com/13635059/58540339-26a88780-8234-11e9-93bb-1cf0e835fcdb.png)
![わか_らん](https://user-images.githubusercontent.com/13635059/58540340-26a88780-8234-11e9-8783-66bf8eb692ce.png)





[絵文字ジェネレーター - Slack 向け絵文字を無料で簡単生成](https://emoji-gen.ninja/#!/emoji?align=center&back_color=FFFFFF00&color=000000FF&font=notosans-mono-bold&public_fg=true&size_fixed=false&stretch=true&text=%E3%81%8A%E5%A4%A7%E4%BA%8B%E3%81%AB)

# Original by Github issue

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








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
ABC070C - Multiple Clocks

つまり与えられたN個の整数の最小公倍数を求めればいい問題なので、最大の整数を選んで、それを整数倍していき、その他の入力された整数で割り切れる最小の整数を出力すればいいと思ったが、そうは問屋が卸さなかった。

```ABC070Ca.cpp
#include <bits/stdc++.h>
using namespace std;

int main(){
 int n;
 cin >> n;
 vector<long long> clock(n);
  long long nmax=0;
  for(int i=0;i<n;i++){
    cin >> clock[i];
    nmax=max(clock[i],nmax);
  }
  long long m;
  for(long long i=1;m<1000000000000000000;i++){
    m=i*nmax;
    bool ok=true;
    for(int j=0;j<n;j++){
      if(m%clock[j]!=0)ok=false;
    }

    if(ok){
    break;
    }
  }
  cout << m << endl;//これだと計算量がO(NA)なので当然間に合わない。
}
```
最大公倍数(lcm)、最小公約数(gcd)が絡んでくる問題はユークリッドの互除法を用いればいい。
まずgcdを求める関数を以下のように求める。

```gcd.cpp
ll gcd(ll a,ll b){ //ユークリッドの互除法で最大公約数を求める
  if(b==0) return a;
  return gcd(b,a%b);
}
```
ユークリッドの互除法について　
https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%AF%E3%83%AA%E3%83%83%E3%83%89%E3%81%AE%E4%BA%92%E9%99%A4%E6%B3%95

次にgcdからlcmを求める

```lcm.cpp
ll lcm(ll a,ll b){//a*b=lcm(a,b)*gcd(a,b)の関係式からa,bのlcm最小公倍数が求まる。
    ll g=gcd(a,b);
  return a/g*b;//a*b/gとすると間違った答えが出力される。
}
```
GNU globalでいい感じにコードを閲覧するウェブページを生成する

大規模なソースコードを読むのは骨が折れる。`grep`や目grepでは限界がある。そこでGNU Globalを使っていい感じにコードを閲覧するページを生成したい。今回使ったディストリビューションはDebian busterである。作業は静的ファイルに関する作業とCGIに関する作業に分かれる。静的ファイルだけでもハイパーリンクによるジャンプは可能なのでそこそこ使える。CGIも使えるようになると検索できてさらに便利になる。

#静的ファイル
GNU Globalには`gtags`,`global`,`htags`コマンドが含まれる。`gtags`コマンドはソースコードをスキャンして識別子などを抽出し、GPATH、GRTAGS、GTAGSといったファイルを生成する。`global`コマンドは生成されたそれらのファイルを使って検索を実行する。`htags`は良い感じにハイライトとハイパーリンクを付けたHTMLファイル群を生成する。

##必要なパッケージ
GNU Globalはパッケージになっているのでapt-getするだけで`gtags`,`htags`,`global`が使えるようになる。今回はウェブサーバとしてはnginxを使用してみた。Apacheでも何でもいいと思う。

```
$ apt-get install global nginx
$ service nginx start
```

##nginxの設定
nginxではURL内のパスとファイルシステム上のディレクトリの関係を`location`ディレクティブで設定する。初期設定では`/etc/nginx/sites-available/default`で次のようになっている。

```
location / {
  # First attempt to serve request as file, then
  # as directory, then fall back to displaying a 404.
  try_files $uri $uri/ =404;
}
```

普通は`/var/www/html`以下にウェブサービス用のHTMLファイルを置くことが想定されているが、`htags`コマンドはデフォルトで`HTML`という名前のディレクトリを生成するので、`/var/www/HTML`をドキュメントルートにしておく。`htags`コマンドが生成するHTMLファイルの場所やディレクトリ名はオプションで変えられるので、各人の好みでいいと思う。

```
location / {
  # First attempt to serve request as file, then
  # as directory, then fall back to displaying a 404.
  try_files $uri $uri/ =404;
  root /var/www/HTML/;
}
```
nginxの設定ファイルを変更した後は忘れずにnginxを再起動する。

```
$ service nginx restart
```

##閲覧したいソースコードの展開
ブラウザから見たいのは`htags`コマンドが生成したHTMLファイルなので、ソースコード自体をどこに展開するかは自由なのだけど、今回は`/var/www/`に閲覧したいソースコードを展開し、そこで`htags`コマンドを実行することにする。そうすればデフォルトで`/var/www/HTML`が生成されるので手間いらずである。今回は例としてGNU makeのソースコードを展開してみた。

```
$ cd /var/www
$ cd wget -nd -nH http://alpha.gnu.org/gnu/make/make-4.1.90.tar.gz
$ tar zxvf make-4.1.90.tar.gz
$ ls
html  make-4.1.90  make-4.1.90.tar.gz
```

##HTMLファイルの生成
`gtags`コマンドによりGTAGSファイルを生成し、`htags`コマンドによりHTMLファイルを生成する。

```
$ cd /var/www
$ gtags
$ htags -aosnFf
$ ls
GPATH  GRTAGS  GTAGS  HTML  html  make-4.1.90  make-4.1.90.tar.gz
```
`htags`はコマンドラインオプション全部入りにしてみた。これで`/var/www/HTML`以下にはいい感じにハイライトとハイパーリンクのついたソースコードが生成されているので、ブラウザから見える。ただしCGIの実行ファイルが無いので検索フォームは動かない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/15158/ba299960-7c8f-61e9-7708-72fdc4f8134f.png)

#CGI
GNU Globalのパッケージには`htags`が生成したHTMLファイル群をいい感じに検索してナビゲーションするために必要なCGIである`global.cgi`と`completion.cgi`がついているので、これを活用するためにnginxでCGIが使えるようにする。
##fcgiwrapのインストール
nginxはFastCGIプロトコルに対応しているようなので、global.cgiがFastCGIプロトコルから呼び出せるようにすればいい。そこでfcgiwrapをインストールする。

```
$ apt-get install fcgiwrap
$ service fcgiwrap start
```
##nginxの設定
nginxの設定ファイルには .cgi で終わるURLが要求されたらFastCGIを使うように教えてやる。

```
location ~ \.cgi$ {
  root /var/www/HTML/;
  fastcgi_pass unix:/var/run/fcgiwrap.socket;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  include fastcgi_params;
}
```

##CGI実行ファイルのコピー
GNU Globalのパッケージに同梱されているCGIの実行ファイルであるgloba.cgiとcompletion.cgiをを`htags`が生成してくれたHTMLのディレクトリにコピーする。これで検索フォームが機能するようになる。

```
$ cd /var/www/HTML
$ cp /usr/share/global/gtags/global.cgi .
$ cp /usr/share/global/completion.cgi .
$ chmod +x *.cgi
```
アクセスログを見ると`global.cgi`は呼び出されているようなのだけど、`completion.cgi`がいつ使われるのかはよく分からない。
Ruby　ターミナル上で動くヌメロンを作成してみた

#ヌメロンとは
簡単にいうと数当てゲーム
今回は、コンピューターが持つランダムな数値列を当てたら勝ち

##ルールについて
1. それぞれのプレイヤーが0～9までの数字が書かれたカードを使って3桁または4桁の番号を作成する。ただし、「112」「121」といった同じ数字を2つ以上使用した番号は作れない。
2. 先攻のプレイヤーは相手が作成したと思われる番号をコールする。相手はコールされた番号と自分の番号を見比べ、コールされた番号がどの程度合っているかを発表する。
  - 数字と位置が合っていた場合は「EAT」
  - 数字は合っているが位置は合っていない場合は「BITE」
  - 例として相手の番号が 「765」、コールされた番号が「746」であった場合「1 EAT - 1 BITE」となる。
3. これを先攻・後攻が繰り返して行い、先に相手の番号を完全に当てきったプレイヤーの勝利となる。

ルールは Numer0n数当てゲーム から抜粋しました。

##今回作成したもの
今回はコンピュータのもつ数字を当てていくスタイルを採用しました
一方的に攻めていきます

##ソースコード
```ruby:numelon.rb
class Numelon

  #桁数を３桁か４桁で選択できる
  def select_digits
    puts "プレイする桁数を選んでください\n3 or 4"
    @select_num = gets.to_i
    if @select_num == (3 || 4)
      return @select_num
    else
      puts "桁数が間違っています"
      select_digits
    end
  end
    
  #ランダムな数値列の作成
  def make_num
    program_num = [*(0..9)]
    rand_array = program_num.shuffle
    @rand_num = rand_array.take(select_digits)
  end

  #入力された数値を取得
  def enter_num
    puts "#{@select_num}桁の数字を入力してください"
    num = gets.chomp
    enter_array = num.split('').map(&:to_i)
    
    #数字の重複を調べる
    num_dup = enter_array.group_by(&:itself).map{ |key, value| value.count }
    num_dup.delete(1)
    
    #桁数が違う場合、再入力を求める
    if enter_array.length != @select_num
      puts "桁数が違います。再入力してください"
      enter_num
    #同じ数字が入力されていた場合、再入力を求める
    elsif num_dup.length != 0
      puts "同じ数字が入力されています。再入力してください"
      enter_num
    else
      check_num(enter_array)
    end
  end
  

  def check_num(enter_array)
    eat_count = 0
    bite_count = 0

    enter_array.each_with_index {|num, i|
      if num == @rand_num[i]
        eat_count += 1
      elsif @rand_num.include?(num)
        bite_count += 1
      end
    }

    puts "#{eat_count} eat - #{bite_count} byte"

    if eat_count == @select_num
      puts "あなたの勝ちです"
      exit
    else
      enter_num
    end

  end

end

player = Numelon.new
player.make_num
player.enter_num
```

##実際のプレイ
```
ruby numelon.rb
プレイする桁数を選んでください
3 or 4
5
桁数が間違っています
プレイする桁数を選んでください
3 or 4
3
3桁の数字を入力してください
12345
桁数が違います。再入力してください
3桁の数字を入力してください
112
同じ数字が入力されています。再入力してください
3桁の数字を入力してください
789
0 eat - 2 byte
3桁の数字を入力してください
198
1 eat - 0 byte
3桁の数字を入力してください
837
0 eat - 3 byte
3桁の数字を入力してください
378
3 eat - 0 byte
あなたの勝ちです
```

##最後に
rubyの勉強ということで今回はヌメロンを作成
本家のヌメロンは対人戦だから、コンピューターと戦わせようと思ったけど難しかったから一方的に当てるスタイルにしてみた

時間ができたらひらがなヌメロンや英単語ヌメロンを作りたい

クラス・メソッドについての理解が浅いので汚いコードになっています
もっと簡潔な記述などあればコメントで教えてください！
C++ Builder 10.2 Tokyo > TRegEx > Error: プロジェクトProject1.exeは例外クラスERegularExpressionError(メッセージ オフセット0で正規表現にエラーがあります: nothing to repeat')を送出しました。

```txt:動作環境
RAD Studio 10.2 Tokyo Update 3
```

### 概要

- TRegExで不正な正規表現文字列を入れたときにエラーが出る
- try, catchしてもデバッガ例外通知ダイアログが表示されるエラーとなる

### 実装

```Unit1.cpp
bool __fastcall TForm1::isValidRegex(String regexStr)
{
	TRegEx *myRegEx;

	try {
		myRegEx = new TRegEx(regexStr, TRegExOptions() << roNotEmpty << roCompiled);
		delete myRegEx;
		return true;
	} catch (Exception &exp) {
		return false;
	}
}
```

上記にてtry,catchをしているが、`new TRegEx()`の行にてエラーが出る。

![2019-05-29_18h44_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/09b6c617-4811-aa10-7ad0-d37cbbb1f255.png)

> プロジェクトProject1.exeは例外クラスERegularExpressionError(メッセージ オフセット0で正規表現にエラーがあります: nothing to repeat')を送出しました。

デバッグ時のみのエラー表示として継続して良いかどうか。

不正文字として使った文字列は`*_itemNo`。

デバッガ例外通知において「継続」を選ぶと例外補足してreturn falseにはなる。


### 設定変更と解除

デバッガ実行時のエラー無視設定とその解除については以下にまとめている。

- [C++ Builder 10.2 Tokyo > Indy > EIdReplyRFCError > デバッガ動作時 > try, catch以前にエラーになる > エラー回避設定とその解除](https://qiita.com/7of9/items/8a633e2570457e092316)
機械学習のモデル評価と説明可能性のための指標　その3。Brier Score（ブライアスコア）

## 予測された延滞率が実際どれだけ当たっているか。予測と結果の合致性の評価  
###   はじめに  
- 今回は、説明可能性についての3回目、モデルを評価するための指標の1つであるブライアスコアについてまとめています。
- MLで作成されたモデルをどう評価するか、どう説明するかについてさまざまな指標・方法を用いて行うことを目的としており、主にPoCなどで利用していくことを想定しています。  
- 説明可能性についてのまとめはこちら。  
    - [POC作成のために、機械学習したモデルをどう評価し説明するかのまとめ。](https://qiita.com/Derek/items/562cdce4fe357df96242)


### Brier Score（ブライアスコア）
#### -　Brier Scoreとは
- 日本語ではWIKIもないブライアスコアですが、天気予報のWIKIの中にこんな記述があります。
    > 予報確率Fi、実際値Ai（発生した場合1、発生しなかった場合0などとする）としたときの確率誤差の総和を予報回数Nで割ったもの。値が0に近いほど精度が高い。  

    $$\frac{1}{N} \sum_{i=1}^N(F_i - A_i)^2$$ 

- 英語版のWikiにある例を引用すると  
    - 延滞予測が100%（$F_i$=1）で結果も延滞（$A_i$=1）の場合は、Brier scoreは0となり、最高値となります。  
    - 延滞予測が100%（$F_i$=1）で結果は延滞しない（$A_i$=0）の場合は、Brier scoreは1となり、最低値となります。  
    - 延滞予測が70%（$F_i$=0.7）で結果も延滞（$A_i$=1）の場合は、Brier scoreは$(0.70-1)^2$=0.09となります。  
    - 延滞予測が30%（$F_i$=0.3）で結果も延滞（$A_i$=1）の場合は、Brier scoreは$(0.30-1)^2$=0.49となります。
- 予測値と結果に乖離があるほどスコアが下がる（Bier scoreの値が高くなる）ことになります。　
- 上記のように、確率は0から1の値となり、結果も0と1の2項分類となるときには機能しますが、それ以外の場合には別な方法を使用することとなります。別な方法についてはWikiのOriginal definition by Brierを参照してください。   
- 検索して出てくる文献のほとんどは天気予報関連でした。たぶんそちらの業界ではかなり一般的な指標と思われますが、あまり金融系では使われていないようです。
- こちらでも書いた通りに、Forecastに拘りたい私としては、予測した確率の精度は重要な指標の1つとなります。
- クレジットスコアで置き換えて考えると、機械学習で得られた延滞確率が実際にはどれだけの確率で発生しているのか、その確率の誤差を評価できます。   


#### - 利用方法  
- 上記のように計算も割と単純ですが、Sklernにも準備されているので容易に使うことができます。  
- サンプルは下記のようになります。  

    ```
    import numpy as np
    from sklearn.metrics import brier_score_loss

    # Probabilityの値
    y_prob = np.array([0.1, 0.9, 0.8, 0.3])

    # 2項分類の場合  
    # 結果の値。
    y_true = np.array([0, 1, 1, 0])
    brier_score_loss(y_true, y_prob)
    0.037...
    ```

- ちなみに、多項分類なども準備されています。 

    ```
    # 多項分類の場合  
    # 結果の値。
    y_true_categorical = np.array(["spam", "ham", "ham", "spam"])
    brier_score_loss(y_true_categorical, y_prob, pos_label="ham")
    0.037...
    ```

### まとめ  
- 0と1の予測結果の精度を評価するのがAUCやジニ係数などになります。今回のブライアスコアは何%の確率と予測して、その結果がどうだったのかを評価します。
- クレジットスコアでは、延滞する・しないの予測のほかに、何%で延滞するのかを適切に予測する必要があります。その確率が正しければ、延滞確率に見合う融資金額や利率、全体のポートフォリオでの許容アセットなどを適切にすることで、しっかりとリスクをコントロールしていくことができます。
- 学習する分類器によっては、予測値の値をそのまま使用すると正確ではない数値を利用することになります。それを防ぐため適切な予測値に変換するprobability calibrationを行ってから利用しましょう。たとえばランダムフォレストの場合は予測値が >0.1 <0.7の値になっていますので、他の分類器と比較する際は注意が必要です。  


#### 関連・参考記事
- [金融リスクと統計的学習](http://ibisml.org/ibis2009/pdf-invited/yamashita.ppt)  
- [sklearn.metrics.brier_score_loss](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.brier_score_loss.html#sklearn.metrics.brier_score_loss)
PHPのタイプヒントでbooleanを指定しているのにbooleanを指定しろと言われるんだが

## 問題のコード

```php:type_hint.php
<?php
class Main{
    public function type_hint_boolean(boolean $arg){
        var_dump($arg);
    }

    public function type_hint_integer(integer $arg){
        var_dump($arg);
    }
}

$main = new Main();
$main->type_hint_boolean(true);
$main->type_hint_integer(1);
```

出力

```bash
PHP Fatal error:  Uncaught TypeError: Argument 1 passed to Main::type_hint_boolean() must be an instance of boolean, boolean given,
```

<font color="Red"><b>must be an instance of boolean, boolean given</b></font>

booleanじゃなきゃいけないのにbooleanが渡されました？？？
ちなみにintegerの場合は以下のエラー

```bash
must be an instance of integer, integer given
```

## 解答

`boolean`や`integer`はタイプヒントでは使えず`bool`, `int`で指定する必要がある

```php:type_hint.php
<?php
class Main{
    public function type_hint_bool(bool $arg){
        var_dump($arg);
    }

    public function type_hint_int(int $arg){
        var_dump($arg);
    }
}

$main = new Main();
$main->type_hint_bool(true);
$main->type_hint_int(1);
```

出力

```
bool(true)
int(1)
```

## 解説

`boolean`や`integer`を指定するとその名前のクラスのインスタンスのタイプヒントになってしまう
よって以下のコードは通る

```php:type_hint.php
<?php
class Main{
    public function type_hint_boolean(boolean $arg){
        var_dump($arg);
    }
    public function type_hint_integer(integer $arg){
        var_dump($arg);
    }
}

class boolean{
}
class integer{
}

$main = new Main();
$main->type_hint_boolean(new boolean());
$main->type_hint_integer(new integer());
```

出力

```
object(boolean)#2 (0) {
}
object(integer)#2 (0) {
}
```

納得納得 :smiley: 

## 参考

[公式ドキュメント](https://www.php.net/manual/ja/functions.arguments.php#functions.arguments.type-declaration)
[PHP7調査(36)スカラ型のタイプヒントが書けるようになった](https://qiita.com/hnw/items/8631c99349509c504d35)
[PHP: bool vs boolean type hinting](https://stackoverflow.com/questions/44009037/php-bool-vs-boolean-type-hinting)
Anacondaの仮想環境でgitをつかうときはpathを通す必要がある

# 概要
Anaconda Navigatorでつくった仮想環境で

「'git' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。」

が出て、gitが使えなかったときの解決法を載せておきます。

git以外にも適用可能なはずです。
環境はWindows10です。

# エラー内容
anacondaの仮想環境を新たにつくり、Open Terminalからコマンドプロンプトを開きます。（下の画像）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164223/a5b8b6c0-6f6f-5d09-05c1-41e0594e37df.png)
開いたコマンドプロンプトでgitと入力すると、以下の画像のようなエラーが出ます。（個人情報にモザイク処理をしました）
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3136343232332f33643132333861392d363431312d313938392d303635652d36383634373031356.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/164223/ae53530b-d45c-3643-a04f-8a2170b1badb.png)
「'git' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。」

これは、pathが通っていないためです。

# 解決法
Anaconda Navigatorから開いたターミナルで

```
path
```


と入力した際に表示されるPATHのなかに、gitのパスが含まれているか確認して下さい。

ない場合には、まず通すべきpathを探します。
今回はgitなので
C:\Program Files\Git\cmd
を通せばよいですが、自分で見つける場合には以下のように探します。

まず、gitが使える普通の(?)コマンドプロンプトを別に起動し、

```
path
```

と入力します。そのなかに、先ほどのAnaconda Navigatorから開いたターミナルでの結果と異なる部分でそれっぽい名前の部分（今回の場合はC:\Program Files\Git\cmd）があるはずです。それをコピーします。
再びAnaconda Navigatorから開いたターミナルに戻り、


```
set PATH=%PATH%;コピーしたパスをここに入力します
```

と入力してみます。今回の場合は

```
set PATH=%PATH%;C:\Program Files\Git\cmd
```

です。これでgitが使えるようになるはずです（確認してみてください）。
今回の場合はgitを例にしましたが、node.jsなども同様でした。
Amazon API Gatewayのオンラインセミナー受けてみた

「[AWS Black Belt Online Seminar Amazon API Gateway](https://www.slideshare.net/AmazonWebServicesJapan/20190514-aws-black-belt-online-seminar-amazon-api-gateway)」の自分向けメモ
API Gateway語感はなんとなく分かるけど......レベルの人向け


## まずAPIとは
 - プログラムやソフトウェア同士がやり取りをするための取り決め（IF仕様も含む）
 - APIにもいくつか種類があるがそのうちのWeb APIがAPI Gatewayの対象領域
 - Web APIの特徴は他システムとの緩やかな連携、エコシステムとの親和性
 - 課題
    - インフラ管理が必要（サーバー管理は本質ではない）
    - APIのバージョンや設定値の管理が必要
    - 認証認可の考慮が必要
    - 流量制御と保護（スロットリングへの対策）

## 概要
### API Gatewayとは
 - クライアントからのリクエストを受け付ける窓口となるAWSサービス
 - リージョンサービス
 - フルマネージドサービス（オートスケール、サーバー管理不要）
 - CloudFrontとの併用も可能（レイテンシ削減可能）

### ユースケース
 - パブリックなWeb API基盤の提供
 - プライベートなWeb API基盤の提供
 - AWSサービスのAPI化
 - サーバーレス構築


## API新規作成の流れ
 1. APIの設計
 * プロトコル種別とエンドポイントタイプ選択
 * APIの設定
 * デプロイとステージ設定

※既存のRESTなAPIからのクローンで作成することも可能

### プロトコル種別
 - RESTとWebSocketの2種類可能
    - REST：ステートレス（単一HTTPメッセージで完結する通信、セッション管理なし）なAPIの実装
    - WebSocket：ステートフル（双方向のリアルタイム通信）なAPIの実装

### RESTのエンドポイントタイプ
 - エッジ最適化
    - まずはエッジロケーション（CloudFront）にルーティング
 - リージョン
    - リージョンに直接ルーティング
    - 同一リージョン内のレイテンシ削減
 - プライベート
    - パブリックアクセスされない
    - VPCエンドポイント経由でのみアクセス可能



### REST APIの場合
#### リソースとメソッド
 - ツリー構造にてリソースを定義し、各ブランチにHTTPメソッドを指定
 - デプロイ単位はリソース単位

#### メソッド設定
 - 4つの設定がある
 - リソースとメソッドを指定して、一意のパラメータをバックエンドに渡せる
 - リクエストとレスポンス、それぞれでパラメータの加工が可能

### WebSocket APIの場合
#### ルート
 - 2つのURLを提供
 - イベントをRouteとして定義する

#### ルート選択式
 - URLパスは1つ、受信データ（JDON）の中身にどのルートを選択するか記述する

#### ルート設定
 - 3つの設定がある

### ステージ設定
 - 作成したAPIを指定したステージにデプロイする
    - ステージ：環境設定
 - 複数のエンドポイントをステージで容易に準備できる

## 認証認可
 - Rest：メソッド単位で設計可能
 - API単位で設定
 - 認証方法は以下
    - IAM権限
    - Lambdaオーソライザー
    - Cognitoオーソライザー

## 統合タイプ
 - Lambda：リクエスト内容を処理する
 - HTTP：外部サービス等パブリックなところにアクセス
 - Mock：固定値を返す
 - AWSサービス：AWSサービスをラップして公開
 - VPCリンク：VPCリソースにアクセス

※Lambda、HTTP、VPCリンクはプロキシ統合を設定可能（リクエストをパススルー）

## リクエストレスポンス変換
 - バックエンドに処理を渡す前にデータ形式の変換が可能
 - バックエンドから渡されたデータをクライアントに返す前にデータ形式の変換が可能

## ログ
 - 実行ログ、アクセスログをlogsに出力可能
 	- アクセスログは任意に設計可能
 - メトリクス設定可能

## RestAPI キャッシュ
 - ステージ毎にキャッシュ
 - バックエンドのトラフィック削減

## リソースポリシー
 - APIから見て、どこからのアクセスを許可するかを指定できる
 	- 特定のAWSユーザーアカウントからしか呼び出せないなどの設定ができる

## カナリアリリース
 - 部分公開機能
 - 特別なステージ「Canary」を作成し、リクエストを指定の比率でCanaryに流せる

## AWS WAFとの連携
 - SQLインジェクション等を防げる

## X-Ray連携
 - 呼び出しトレースの記録が可能
 - Lambadaも併せて、End2Endでトレース可能

## クライアント証明書
 - 外部サービスの利用時にステージに設定した証明書を利用可能

## 利用料金
以下に依存する

 - APIコール数
 - メッセージ要求数
#Slack API を叩いて全メンバーを一個のチャンネルに招待する #python スクリプトの例 (雑バージョン)

# ATTENTION

- チャンネルIDの取得方法は適当にググる (チャンネル名ではない)
- Slack App を登録して Tokenを得て、適切な Permission を設定しておく
- メンバー数が多い場合には対応していない、ページングに対応していない
- 重複招待でエラーが返ってくる問題にも対応していない
- API制限に引っかかったら適当に sleep 入れるなりして対処してください
- 例では無意味に jq コマンドかましてます

# all-member-list.py

```py
#!/usr/bin/env python3

# https://api.slack.com/methods/users.list

import requests, os, json

url = "https://slack.com/api/users.list"

params = {
  "token" : os.environ.get('SLACK_TOKEN'),
}

headers = {
  'Content-type': 'application/json'
}

res = requests.get(url, headers=headers, params=params)

print(json.dumps(res.json()))

```

# invite-to-channel.py

```py
#!/usr/bin/env python3

# https://api.slack.com/methods/channels.invite
# https://slack.com/api/channels.invite

import requests, os, json, sys

url = "https://slack.com/api/channels.invite"

members = json.loads(sys.stdin.read())

for member in members:
  params = {
    "token" : os.environ.get('SLACK_TOKEN'),
    "channel" : os.environ.get('CHANNEL'),
    "user" : member.get('id'),
  }
  
  headers = {
    'Content-type': 'application/json'
  }

  res = requests.post(url, headers=headers, params=params)

  print(json.dumps(res.json()))

```

# exe

```
export SLACK_TOKEN=xxxxxxxxxxxxxxxx && ./all-member-list.py | jq -r '.members' | CHANNEL=xxxxxxx ./invite-to-channel.py
```


# ワークスペースのデフォルトチャンネルを設定

一度全員招待しても、WorkSpaceのメンバーが増えたらやり直しなので、admin設定でデフォルトチャンネルも設定しておくと良いかも

https://example.slack.com/admin/settings

![image](https://user-images.githubusercontent.com/13635059/58536882-a6caef00-822c-11e9-9f07-4d8b5fb7ea5c.png)

# 有料プランなら

- 全メンバーをSlackグループに入れておく
- グループに対して invite する

っていう手順で、API叩かなくてもできるかもしれません。

# Original by Github issue

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








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
【Fortran】指定したパスからディレクトリを作成

流れ
- 与えられた文字列がディレクトリなのか，ファイル名まで含むのかを判定
- ファイル名まで含む場合，ディレクトリ部分のみを取り出す
- ディレクトリ作成

## 文字列の末尾の判定

Pythonで言う`str.endswith()`

``` Fortran:endswith.f90
module mymod
    implicit none
contains

function endswith(longtext, tailtext) result(ends)
    logical ends
    character(len=*), intent(in) :: longtext, tailtext
    character(len=256) longtext_, tailtext_
    integer long_eloc, tail_eloc

    ends = .FALSE.
    longtext_ = trim(longtext)
    tailtext_ = trim(tailtext)
    long_eloc = len_trim(longtext)
    tail_eloc = len_trim(tailtext)
    if (long_eloc == 0 .or. tail_eloc == 0) return
    if (long_eloc < tail_eloc) return
    if (longtext_(long_eloc - tail_eloc + 1:) == tailtext_) then
        ends = .TRUE.
    endif
end function endswith

end module mymod

program main
    use mymod
    implicit none
    write(*, *) endswith('abc' , 'c' ) ! T
    write(*, *) endswith('abc' , 'bc') ! T
    write(*, *) endswith('abc' , 'a' ) ! F
    write(*, *) endswith('abc' , 'ac') ! F
    write(*, *) endswith('abc ', 'c' ) ! T
    write(*, *) endswith('abc/', '/' ) ! T
end program main
```

## パスからディレクトリの取り出し

Pythonで言う`os.path.dir_name()`

``` Fortran:dir_name
module mymod
    implicit none
contains

function dir_name(path) result(dir)
    character(len=256) dir
    character(len=*), intent(in) :: path
    integer iloc
    logical is_found

    if (endswith(path, '/')) then
        dir = path
        return
    endif

    is_found = .FALSE.
    do iloc = len_trim(path), 1, -1
        if (path(iloc:iloc) == '/') then
            is_found = .TRUE.
            exit
        endif
    enddo

    if (is_found) then
        dir = path(:iloc)
    else
        dir = path
    endif
end function dir_name

end module mymod

program main
    use mymod
    implicit none
    write(*, *) trim(dir_name('abc/de'))   ! abc/
    write(*, *) trim(dir_name('abc/'))     ! abc/
    write(*, *) trim(dir_name('abc/de  ')) ! abc/
    write(*, *) trim(dir_name('abc/  '))   ! abc/
    write(*, *) trim(dir_name('/abc/'))    ! /abc/
    write(*, *) trim(dir_name('/abc/de'))  ! /abc/
end program main
```

1文字取り出すのはtext(1)ではなくtext(1:1)．
http://www.nag-j.co.jp/fortran/FI_13.html

## ディレクトリの作成は`call system()`で

Pythonで言う`os.makedirs()`

``` Fortran:mkdir.f90
module mymod
    implicit none
contains

subroutine makedirs(outdir)
    character(len=*), intent(in) :: outdir
    character(len=256) command
    write(command, *) 'if [ ! -d ', trim(outdir), ' ]; then mkdir -p ', trim(outdir), '; fi'
    write(*, *) trim(command)
    call system(command)
end subroutine makedirs

end module mymod

program main
    use mymod
    implicit none
    call makedirs('./test/sub')
    call makedirs('./test/sub')
end program main
```

https://qiita.com/aisha/items/5ce5971a4c179ac83c6e#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%AFcall-system%E3%81%A7
https://sites.google.com/site/fcfortran/home/recipe/mkdir

## まとめ

以上のサブルーチンを利用すると，

``` Fortran
call makedirs(dir_name(path)) ! pathは出力したいファイルのパス
```

と1行でディレクトリ作成可能．
WordPressとCloudFunctionsを連携してアプリ内にブログ機能を実装する

## WordPressとCloudFunctionsを連携してアプリ内にブログ機能を実装する
[PORT Firebase × PostCoffee #2](https://stamp.connpass.com/event/128826/) で登壇したときの内容です。

コーヒーのサブスクアプリ**「PostCofee」**の開発をしている中川です。
このPostCofeeのアプリはバックエンドが*Firebase*のみで作られています。
コーヒーが好きな方はぜひ[ダウンロード](https://itunes.apple.com/jp/app/postcoffee-%E3%82%B9%E3%83%9A%E3%82%B7%E3%83%A3%E3%83%AB%E3%83%86%E3%82%A3%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%92%E3%83%BC%E3%81%AE%E3%82%B5%E3%83%96%E3%82%B9%E3%82%AF/id1455826647?mt=8)してみてください！


さて、先日のアップデートでストーリーというタブが追加されました。
<img width="375" alt="IMG_5925.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106260/799d8f0d-dbf8-0506-e895-93b8da27d61f.png">
ストーリーはアプリ内でブログを閲覧できる機能です。
アプリ内でWebサイトを閲覧できるというのはごく普通の機能ですが、これをFirebaseで実現する場合どのようにするのかを紹介したいと思います。

## WordPressとの連携の流れ
ストーリーで表示しているブログはWordPressで書かれていて、構成はこのようになっています。

![ストーリー実装の裏側.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106260/1220d4b6-5282-e3d5-6958-e5c40830482e.png)


1. WordPressで記事を公開、更新する
2. 上記のタイミングでWordPress側からCloudFunctionsで用意したfunctionを必要なparamを入れて叩いてもらう
3. CloudFunctionsが叩かれたらparamを受け取ってFireStoreへ保存し、アプリ側へPush通知を送る
4. アプリ側はCloudFireStoreへデータを取りに行く

 
##CloudFunctionsでやること
まずはCloudFunctionsを実装します。
トリガーは `functions.https` を使用します。
詳細はこちら [HTTP リクエスト経由で関数を呼び出す](https://firebase.google.com/docs/functions/http-events?hl=ja)

また、Push通知もこのCloudFunctionsの中で送るようにします。
今回は全ユーザーを対象に送るためトピック配信を使いました。
[トピックにメッセージを送信する](https://firebase.google.com/docs/cloud-messaging/js/topic-messaging?hl=ja)

```typescript

exports.wordPressCreated = functions.region('asia-northeast1').https.onRequest(async (req, res) => {
	// ここでWordPressからのデータを受け取ってFireStoreへ保存します。

	// WordPressからのデータはreq.bodyの中に入っくるので
	// 例) const title = req.body.title
	// このように取得します。

	// FireStoreへの保存が完了したらPush通知を送る
})
```

###Push通知について補足
記事によってPush通知を送る、送らないを分けたい場合、WordPress側から送るデータにBool値を入れると良いです。
Bool値といっても受け取る際にStringの '0', '1' に変換されてしまうようなので判定に注意が必要です。

```
例) WordPressからのparam
{
   "title" : "ほげほげ",
   "thumbnail" : "https://○○○.png",
   "url" : "https://qiita.com/",
   "isSnedPush" : "1" // Push通知を送るかどうか
}

```
```typescript
// isSendPushが '1' のときにPushを送る
if (req.body.isSendPush === '1') {
	// Push通知を送る
}
```
CloudFunctionsでの実装は以上です。
実装が完了したらデプロイしましょう。

##WordPressでやること
WordPress側では記事の公開、更新をフックして上記で実装したCloudFunctionsを叩くようにします。
FireStoreに保存したいデータもここで送るようにします。

叩くURL(CloudFunctions)はFirebaseコンソールの

Functions → ダッシュボード → トリガー

に記載されています。

##デバッグについて
最終的には実際にWordPressで記事を公開して確認するのが良いのですが、実装途中で確認したい場合や、WordPressを自分でいじれない場合、直接CloudFunctionsを叩いて確認することができます。

デプロイ済みのCloudFunctionsを叩く方法はいくつかあると思うのですが、今回は[Postman](https://www.getpostman.com/downloads/)を使用しました。

<img width="1058" alt="スクリーンショット 2019-05-29 18.05.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106260/c5187489-6b15-cdd4-2861-bb84711417e4.png">
使い方はURLを入力して `POST` でリクエストするだけです。
今回はWordPress側からparamを受け取るので実際に送るデータをjson形式で指定します。

CloudFunctionsが叩かれたかどうかは

Firebaseコンソールの Functions → ログ

で確認できます。

##まとめ
今回はWordPressとCloud Functionsの連携について紹介しました。
WordPressに限らず、他のサービスとの連携もほぼ同じような構成でいけると思いますので、参考になれば幸いです。

ここもっと詳しく知りたいなどありましたら書ける範囲で追記しますのでお気軽にコメントください！
docker run hoge && tail -f hoge.logでゾンビコンテナになる

# 概要

dockerコンテナを永続化する方法としてRUNコマンドに`hoge & tail -f hoge.log`のようにしているならば要注意です！
場合によっては**ゾンビコンテナ**になります！
なぜそうなるのかというと、メインプロセス（フォアグラウンドプロセスでも）が異常終了しても`tail`コマンドが正常である限り、そのまま稼働し続けるからです！
restart policyが定義されていても期待した動作にならないでしょう！

# 検証方法

例として、RUNコマンドで`hoge && tail -f hoge.log`が定義されているとする。
hogeプロセスをkillしてみてください！
`tail -f hoge.log` だけを実行するゾンビコンテナの出来上がりです！

# 対策法

監視システムが導入されているならば、メインプロセスの状態を監視して異常時に自動起動するような仕組みを導入する。
他にいい方法があればご教授ください！
GitBookのMarkDown

GitBookでmarkdownを書くのを手こずったので備忘録
とりあえずコードブロックで気になった部分のみ後で追加予定

# コードブロックのファイル名

<img width="757" alt="スクリーンショット 2019-05-29 17.50.41.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251885/4c1bf5f1-b394-0a9f-68e2-0dd3e31f0643.jpeg">

{% code-tabs %}
{% code-tabs-item title="bash." %}
```bash
$ pwd
~/xxxx/xxx/
```
{% endcode-tabs-item %}
{% endcode-tabs %}

<br>

# コードブロックのタブ化
タブ`aaa`
<img width="758" alt="スクリーンショット 2019-05-29 17.53.31.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251885/4cbff4a3-c863-a58b-4823-2c07d6ccaf4f.jpeg">
タブ`Plain Text`
<img width="755" alt="スクリーンショット 2019-05-29 17.55.56.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251885/039bed19-862e-e6a0-bf3f-ece20bfe1b66.jpeg">

{% code-tabs %}
{% code-tabs-item title="aaa" %}
\`\`\`text
aaa
\`\`\`
{% endcode-tabs-item %}

{% code-tabs-item title=undefined %}
\`\`\`text
plain1
\`\`\`
{% endcode-tabs-item %}
{% endcode-tabs %}
simplekmlのシンプルな使い方

#初カキコ…ども…

表題の通りですが、簡単に使い方を説明していこうと思います

#simplekmlとは
簡単に言えばKMLをシンプルに作成できるpythonのパッケージですね。
あんまりsimplekmlに関する記事がないようでしたので、自分のコードとかを備忘録的に記事にしておこうと思いました。

**記事作成時点でのバージョンは1.3.1になります。**
https://simplekml.readthedocs.io/en/latest/index.html

#めちゃ簡単なsample
```simplekml.py
kml = simplekml.Kml()
kml.newpoint(name="Kirstenbosch", coords=[(18.432314,-33.988862)])  # lon, lat, optional height
kml.save("botanicalgarden.kml")
```
ざっくりこれだけでkmlが作れます。
sampleでは点だけを作ってますが、これ以外にもpolygonやlineが描画できます。
またフォルダを作成して、その中にpointやlineを作ることももちろん可能です。

#ポリゴンのスタイル
polygonやline,pointにはそれぞれスタイルが設定できます。
設定できるものはオブジェクトによって違います。詳細は公式Documentを参照してください

```polygonStyle.py
pol = kml.newpolygon(name = testName)
pol.outerboundaryis = [a, b, c, d, a]
pol.style.linestyle.color = "bf00ffff"
pol.style.polystyle.color = "3f00ff00"
pol.style.linestyle.width = 3
```

上のサンプルではまずポリゴンの外形境界線(outerBoundary)を設定し
境界線の色、ポリゴンの色、境界線の太さを設定しています。
また、このほかに内側の境界線(innerBoundary)を設定することもできます。

#ポイントのスタイル
```pointStyle.py
point = kml.newpoint(name = testName)
point.coords = [(a,b)]
point.style.iconstyle.icon.href = None
point.style.labelstyle.scale = 0.8
```
pointのスタイルになります。
割と使いそうなのはiconstyleだと思います。
こう記述するとiconなしで表示することができます。

#注意点
最後に注意したい点なんですが、kmlの座標の表記は度分秒ではなく十進数表記になります。
若干めんどうなんですけど、そこだけ注意してください。

#おわり
いかがでしたか！？
初めての記事なのでちょっと締めの言葉がわかりません。

以上です。

2019/07/18
一部修正しました。内容に変更はありません。
Chrome なら Web ページ全体のスクリーンショットが簡単に取れる

macOS でも Windows でも、OS のスクリーンショットの機能を使うと、ディスプレイサイズに依存する形でしかスクリーンショットが取れない。しかし、Chrome の機能を利用すると、ディスプレイで Web ページ全体が表示しきれない場合でも、1枚の画像としてスクリーンショットが取得できる。

1. スクリーンショットを取りたいページを開く。
2. Developer Tools を開く (macOS の場合は __Cmd+Opt+I__、Windows の場合は __F12__)。
3. Developer Tools のプロンプトを開く (macOS の場合は __Cmd+Shift+P__、Windows の場合は __Ctrl+Shift+P__)。
4. プロンプトで `full` と入力して Enter を押す。

すると、そのページのスクリーンショットがダウンロードされる。