OmniAICreator/Qiita-1.07M huggingface dataset:
django girls tutorial をやってみた

progateの次は色々作りながら学んでいこうと考えていたところ、ちょうどgirls tutorial というサイトを見つけたのでやってみました。
このページでは自分がつまずいたところをメモしておきます。

１　特定のurlに対して、対象を指定する時
＃path関数を使って、warningのようなエラー
path→re_pathに変更
（そうすると、url指定する部分　引数？に正規表現を使える）
ただ、ここでpathやre_pathを使っても、htmlファイルに組み込む時には（{% %}と書く時）、urlと書く。
（tutorialではurlという関数を使っていたのですが、pathまたはre_pathという関数がよく使われるらしいのでこちらを使った。基本的に問題なかったが、上記に部分は気をつけて！）

２　gitigmoreが反映されない時
＃　unapplied migration みたいなエラー
中身を確認（自分はsettings.pyをsetingと書いてた汗）

３　iconが出ない時
＃エラーは出ないけど、アイコンが表示されない
tutorialではflybiconを使っていたが、今はfontawesomeというものに変わっている。
公式サイトからlinkをコピーして、htmlファイルに貼る
fa-fa に変更

４　追記　__ に気をつける
pythonでは __ (アンダーバー２つ)をよく使う（らしい）ので、要チェック

かかった時間　１２時間ほど（３日）

django girls tutorial
https://djangogirlsjapan.gitbooks.io/workshop_tutorialjp/
ASP.NET > 危険な可能性のある Request.Path 値がクライアント (?) から検出されました。の対応


## 現象
WebAPIサービスで以下のようなエラーが表示されました。

![image](https://qiita-image-store.s3.amazonaws.com/0/49910/95fdd132-1e74-82f8-8afc-685c17dd1738.png)

HTTP Get処理にて？文字（%3F）をURLに含めて送信した事からです。

### Request URLの例
`http://localhost:61902/api/Translate/en/ja/What%20is%20the%20schedule%20for%20tomorrow%3F`


## 解決方法

2018/7/20 現在、以下の解決法でうまくいきました。
Web.configファイル中の`<httpRuntime />`に` requestPathInvalidCharacters=""`を追加

```xml
<system.web>
    <httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0" />
...
</system.web>
```



## 参考

[WebMatrix 3：危険な可能性のある Request.Path 値がクライアント (:) から検出されました。 - だるろぐ](https://blog.daruyanagi.jp/entry/2013/04/21/143904)

[.NET Framework4 / ASP.NET4を導入 | 水無月ばけらのえび日記](http://bakera.jp/ebi/topic/4208)

[ASP.NET 4 URL limitations: why URL cannot contain any %3f characters - Stack Overflow](https://stackoverflow.com/questions/2831142/asp-net-4-url-limitations-why-url-cannot-contain-any-3f-characters)
[JavaScript]null または空文字判定

自戒メモ
## 結論
勝手に判定してくれる
（JavaScript では null ないし空文字を条件式において false と判定する）

## コード
やってたこと：
　文字列が入ってくることを想定している変数 str について null か空文字なら何か処理をいれたかった

```javascript
// Java のライブラリとかである String.isEmpty みたいなことをやってた
if (str == null || str == '') {
  // do something
}
```

こうすればよい

```javascript
// null か空文字なら false と判定してくれる
if (!str) {
  // do something
}
```
Dockerでslim実行したらInvalidByteSequenceError


rubyのテンプレートエンジンであるslimを使っています。
実行環境をDockerに移そうとしたところ、slimrbを実行したところ以下のエラーが発生しました。

```bash
$ slimrb index.slim 
Encoding::InvalidByteSequenceError: index.slim is not valid US-ASCII
  Use --trace for backtrace.
```

index.slimはUTF-8で日本語が含まれています。

解決方法は次のように環境変数を設定することです。(Dockerファイルでの記述方法)

```
ENV RUBYOPT -EUTF-8
```
TLS1.3で使える・使えない暗号アルゴリズム

間もなくRFCとして公開される、TLS 1.3。
（追記：公開されました！->[RFC 8446](https://tools.ietf.org/html/rfc8446)）

利用できる暗号アルゴリズム（※）を押さえておくことで、
高速ハンドシェイクにいち早く移行したいものです。
※ 2018年7月23日時点の情報

では早速見ていきましょう。

★：TLS1.2から新たに追加 or 変更
# 鍵交換
## <font color="Blue">OK
* DHE
 * 楕円曲線：secp256r1
* ECDHE
 * 楕円曲線：secp256r1
* PSK

## <font color="Red">NG
* DSS（DSA）
* RSA ★
  * [ROBOT攻撃](https://robotattack.org/)などに対する脆弱性
  * 前方秘匿性の考えによる安全性向上（static RSAを利用しない）
* ECDSA ★
  * 前方秘匿性の考えによる安全性向上（static RSAを利用しない）
* DH ★
  * 前方秘匿性の考えによる安全性向上（static DHを利用しない）
* ECDH ★
  * 前方秘匿性の考えによる安全性向上（static DHを利用しない）

# 署名
## <font color="Blue">OK
* RSA
 * パディング：PSS,PKCS#1 v1.5
* ECDSA
 * 楕円曲線：secp256r1,secp384r1,secp521r1
* [EdDSA](https://tools.ietf.org/html/rfc8032) ★
 * 楕円曲線：ed25519,ed448
 * エドワーズ曲線デジタル署名アルゴリズム。乱数を利用しない特徴を持つ。
* PSK

## <font color="Red">NG
* DSS（DSA）

# 対称暗号
## <font color="Blue">OK
* AES
* ChaCha20

## <font color="Red">NG
* DES
* IDEA
* RC2
* RC4       ★
 * 平文回復攻撃などへの脆弱性
* TripleDES ★
 * SWEET32攻撃などへの脆弱性
* Camellia  ★
* ARIA      ★
* SEED      ★
 * 上記3つは特に脆弱性の話題はないが、外された模様

# 暗号モード
## <font color="Blue">OK
* CCM
* GCM
* Poly1305

## <font color="Red">NG
* CTR
* CFB
* OFB
* CBC ★
 * BEAST攻撃などへの脆弱性

# ハッシュ関数
## <font color="Blue">OK
* SHA-256
* SHA-384

## <font color="Red">NG
* MD5      ★
  * コリジョン攻撃への脆弱性（1995年頃よりこれまでに多くの指摘）
* SHA-1    ★
  * コリジョン攻撃への脆弱性（2017年にGoogleが発表した[Identifical-prefix攻撃](https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html)など）
* SHA-224  ★
  * 計算機性能向上による安全性の低下

# 組み合わせ（暗号スイート）
#### 鍵交換と署名
* DHE-RSA
* ECDHE-RSA
* ECDHE-ECDSA

鍵交換はDH系、署名はRSA系と覚えましょう。

#### 対称暗号と暗号モード、鍵の導出（ハッシュ関数）
* AES_128_GCM_SHA256
* AES_256_GCM_SHA384
* CHACHA20_POLY1305_SHA256
* AES_128_CCM_SHA256
* AES_128_CCM_8_SHA256
 
# 結論
組み合わせが少なくなりました（にっこり）

# 参考
[The Transport Layer Security (TLS) Protocol Version 1.3 draft-ietf-tls-tls13-28](https://tools.ietf.org/html/draft-ietf-tls-tls13-28)
[SSL/TLS 暗号設定 ガイドライン - IPA](https://www.ipa.go.jp/security/ipg/documents/ipa-cryptrec-gl-3001-2.0.pdf)
[SSL/TLS 暗号設定ガイドライン改訂及び鍵管理ガイドライン作成のための調査・検討](https://www.ipa.go.jp/files/000067459.pdf)
[TLS 1.3 - wolfSSL](https://www.wolfssl.jp/wolfsite/wp-content/uploads/2018/01/TLS13-full-jp.pdf#search=%27TLS1.3+GCM+CBC%27)
[CRYPTREC 暗号技術ガイドライン(SSL/TLS における近年の攻撃への対応)](https://www.cryptrec.go.jp/report/c13_kentou_giji02_r2.pdf)
[The Transport Layer Security (TLS) Protocol Version 1.2](https://tools.ietf.org/html/rfc5246)
なぜStatefullWidgetではなくStateがbuildメソッドを持っているのか

転載: https://www.yslibrary.net/2018/07/22/flutter-statefullwidget-build/

最近趣味と実益を兼ねてFlutterを触っている。

だいたいReactっぽくて良さそうな感じ。React Nativeと違って、UIレイヤについては基本的にFlutterの中で完結するのが好み。

ただ`StatefulWidget`を作るときにちょっと気になることがあった。`StatefulWidget`はそれ以外にWidgetの状態を管理する`State`クラスが必要なんだけど、`StatefulWidget`ではなく`State`の方にUIを描画する`build`メソッドがあるのだ。

ReactでもそうだしMVPやらMVVMでもそうだけど、だいたい状態を管理するクラスとUIを描画するクラスを分離することで責任を分離している。それをなぜわざわざ`State`クラスに`build`メソッドが生えているんだろう？　と違和感しかなかった。

そんなわけでちょっと調べてみたら、やっぱり同じように思う人はいたらしくissueがたっていた。

[FAQ request: why is the build() method on State, and not StatefulWidget ?](https://github.com/flutter/flutter/issues/8794)

要約すると下記のような理由らしい。

`StatefulWidget`に`build`メソッドを生やすことにすると、メソッドシグネチャが`StatefulWidget#build(BuildContext, State)`になる。  
このメソッドの中でクロージャを定義すると暗黙的に`this(この場合はStatefulWidget)`がキャプチャされる。で、`build`メソッドが呼ばれたときに、`StatefulWidget`は作り直されたにも関わらずクロージャの`this`は古い`StatefulWidget`を参照したままで古い状態を参照してしまう。  
一方`State#build(BuildContext)`であれば、`State`は`StatefulWidget`が再生成されたときでもそのまま保持されるので、`this`の対象が変わることはない、ということだ。

あとは、`StatefulWidget#build(BuildContext, State)`だと、これ継承した新しい`StatefulWidget`を作ったときに実装の詳細である`State`を子クラスに公開しなければならなくなる、とか。

仕様的にこうせざるを得なかった、というのはわかったけどやっぱり釈然としない感じはある。

こういった点を何とかするためにBLoCパターンとかMVW系のデザインパターンを実装するんだろうけど、そのへんはまだ分かりきっていないので引き続き調べる。

ちなみに上述のissueの中身は現在[APIドキュメントの方](https://docs.flutter.io/flutter/widgets/State/build.html)にも記載されている。
エラー:"dyld: Library not loaded" or "cwd = process.cwd()" or "internal/modules/cjs/loader.js" など

node -v できるのに, npm -vできない状況で、
以下3通りのNPM周りのエラーが出た時に解決できた方法

---
エラータイプ１
---
path.js:1086
          cwd = process.cwd();
                        ^

Error: ENOENT: no such file or directory, uv_cwd
    at Object.resolve (path.js:1086:25)
    at Function.Module._resolveLookupPaths (internal/modules/cjs/loader.js:479:17)
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:574:20)
    at Function.Module._load (internal/modules/cjs/loader.js:507:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at /usr/local/lib/node_modules/npm/bin/npm-cli.js:19:21
    at Object.<anonymous> (/usr/local/lib/node_modules/npm/bin/npm-cli.js:148:3)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)

---
AND/OR　エラータイプ２
===
internal/modules/cjs/loader.js:583
    throw err;
    ^

Error: Cannot find module '../lib/utils/unsupported.js'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
    at Function.Module._load (internal/modules/cjs/loader.js:507:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at /usr/local/lib/node_modules/npm/bin/npm-cli.js:19:21
    at Object.<anonymous> (/usr/local/lib/node_modules/npm/bin/npm-cli.js:148:3)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)

---
AND/OR　エラータイプ３
---
dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.60.dylib Referenced from: /usr/local/bin/node Reason: image not found Abort trap: 6

---
解決策：
1) 強制的にアンインストール
sudo rm -rf /usr/local/lib/node_modules/npm
2) 再インストール
brew reinstall node
3) 動作確認
npm -v
おまけ) 不要な旧ファイルの削除
npm cache clean --force

参照もと：
https://docs.npmjs.com/troubleshooting/try-clearing-the-npm-cache
https://stackoverflow.com/questions/44363066/error-cannot-find-module-lib-utils-unsupported-js-while-using-ionic
https://stackoverflow.com/questions/47861124/npm-cannot-find-module-bash
https://github.com/olefredrik/FoundationPress/issues/780
https://github.com/npm/npm/issues/16542
https://github.com/npm/npm/issues/18535
https://github.com/nodejs/node/issues/19702
SEO 勉強メモ

### canonical（カノニカル）属性
- 正式な URLを 検索エンジン側に伝える URLの正規化を目的としたもの
- head要素の中で使用する
- anonicalを設定すると、複数の重複 ページが存在している場合に、 検索エンジンに優先させるべき ページを伝えることができる


```html
<!-- 記述例 -->
<link rel="canonical" href="正規ページURL">

```
[参考URL](https://ferret-plus.com/1809)

### 301リダイレクトを利用したURLの正規化
- <link rel=”canonical">で、検索エンジンに対してインデックスされるURLは統一できる
しかし、
- index.htmlのあり・なし
- wwwのあり・なし
- URL末尾のスラッシュのあり・なし

※<font color="red">「301リダイレクト(恒久的な転送)」を利用して正規化しておくこと</font>
自宅のグローバルIPアドレスの変更をMackerelで通知する

## 背景

- 自宅のRaspberry Piから、Google Cloud PlatformのAPI使ってる
- Google Cloud Platformは課金上限の設定が出来ないので、APIキーの漏洩が怖い
- APIキーが漏洩しても大丈夫なように、Google Cloud Platform側でIPアドレスの制限かけよう
- 自宅は固定IPじゃ無いので、グローバルIPアドレスが変わるたびに、手作業でGoogle Cloud Platformのホワイトリストにプロバイダのネットワークアドレスを追加する
- とりあえず、グローバルIPアドレスの変更通知はMackerelで対応しよう

ということで、Raspberry Pi上で動かしているmackerel-agentから、グローバルIPアドレスの変更をアラートとしてあげる設定を行いました。
なお、以下Raspberry Piを前提として記述していますが、スクリプト自体はLinux汎用です。

## MacherelでRaspberry Piを監視する

参考：[Raspberry Pi を Mackerel で監視する](https://qiita.com/ww24/items/5409aefd87f14beff504)

## グローバルIPアドレスの変更検知スクリプトを作る

参考：[LinuxでグローバルIPアドレスを確認する方法](https://qiita.com/ksugawara61/items/887ddd1792d7d5dabb25)

http://globalip.me でグローバルIPアドレスを取得し、変更が検知されたらエラーを返すスクリプト、checkglobalip.shを作る。Raspberry Piで動作させます。

/home/pi/bin/checkglobalip.sh

```sh:checkglobalip.sh
#!/bin/sh
IPFILE='/tmp/globalip'

PREVIP=`cat $IPFILE` 2>/dev/null
IP=`curl globalip.me` 2>/dev/null

if [ "$IP" != "" ]; then
  echo "Global IP address: $IP"

  if [ "$PREVIP" != "$IP" ]; then
    echo $IP > $IPFILE
    if [ "$PREVIP" != "" ]; then
      echo "Global IP address changed from $PREVIP"
      echo
      whois -h whois.nic.ad.jp $IP | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.\S*' | tr '\n' ' '
      exit 1
    fi
  fi
else
  echo "Can't get IP address"
  exit 1
fi

return 0
```

## Macherelのチェック項目として追加

グローバルIPアドレスが変わると、Google CLoud Platformに登録しているIPアドレスの範囲外となり、APIが403を返して使えなくなります。趣味の利用で即時対応は必要ないので、検知は一時間おきにします(Macherelで設定可能な最大値)。あまり頻繁に http://globalip.me にアクセスするのも気が引けますし。
なお、AM4:00頃にglobalip.meが毎度503を返すようなので、max_check_attempts = 2 にします。

/etc/mackerel-agent/mackerel-agent.conf

```
[plugin.checks.globalip]
command = "/home/pi/bin/checkglobalip.sh"
max_check_attempts = 2
check_interval = 60
memo = "This check monitors change of global IP address."
```

## Mackerel再起動

```
sudo systemctl start mackerel-agent
```

## MackerelからLINE Notifyでアラート通知

<img src="https://qiita-image-store.s3.amazonaws.com/0/12960/25486784-0574-0336-14d1-ab26b56ac029.png" width="33%"></img>

こんな感じで通知が着ます。通知がきたら[CMAN](https://www.cman.jp/network/support/ip.html)見て割り当てIPネットワークアドレスを調べ、Google Cloud Consoleの「APIとサービス」-「認証情報」のサーバーIPアドレスリストに追加。とりあえず自分が使っているプロバイダからのアクセスなら許可ということにします。

正直もうちょっといい方法ないのかなと思わないでもないですが、はたしてどのくらい追加を続けたら、プロバイダのネットワークアドレスを網羅できるのやら。

## 追記

CMANでネットワークアドレス調べるより、whoisコマンドのほうが良いかも。チェックスクリプトにも仕込みました。

```
pi@raspberrypi:~ $ whois -h whois.nic.ad.jp 122.26.128.XXX
Network Information:            
a. [Network Number]             122.26.128.0/17
b. [Network Name]               OCN
g. [Organization]               Open Computer Network
(略)                                
Less Specific Info.
----------
NTT COMMUNICATIONS CORPORATION
                     [Allocation]                                122.16.0.0/12
```

よくわからないけど、アドレスの範囲がOCN(122.26.128.0/17)よりも、Less Specific InfoででてるNTT COM(122.16.0.0/12)のほうが広い。Google Cloud Platformにはこっちを設定したほうが楽。
関係ないけど、OCNがOpen Computer Networkの略だというのは始めて知りました。
UnityGameDevメモ#1「パズルピースの挙動」

#１．はじめに
　本記事には私が思いついたこと・学習したこと等をメモとして書いていきます。場合によってはタイトルから少し外れた内容も含まれるかもしれませんし、言葉が足りない・知識が間違っている部分もあるかもしれません。できる限り事細かく書きますので、なにかの参考になればと思います。
#２．本編
##Ⅰ．パズルピースをドラッグで動かす
| 使った関数       |関数の意味                        |
|:-----------------|:-------------------------------|
|     OnMouseDrag()         　　　　|オブジェクトがマウスでドラッグ判定時に行われる|
|    Input.mousePosition        　　|マウスの座標（ワールド座標を取得する）|
| Camera.main.ScreenToWorldPoint() |ワールド座標をカメラスクリーン座標に変換する|
###コード例

```C#:move_piece.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move_piece : MonoBehaviour {

    private void OnMouseDrag()
    {
        Vector3 ObjPos = Input.mousePosition;
        ObjPos.z = 10f;
        transform.position = Camera.main.ScreenToWorldPoint(ObjPos);
    }
}
```
　ObjPosという座標の格納変数を用意します。最終的に、この変数の座標がオブジェクトの位置になります。

```C#:move_piece.cs
ObjPos.z = 10f;
```
　このコードがなければオブジェクトのz座標が０となり、ゲーム画面でうまく表示されません。

```C#:move_piece.cs
transform.position = Camera.main.ScreenToWorldPoint(ObjPos);
```
　Debug.Log(ObjPos)で確認できると思いますが、このコードによってワールド座標とスクリーン座標を切り替えています。
　通常mousePositionはワールド座標であるため、そのままObjPosに代入するとゲーム画面ではゲーム画面の遥か彼方に飛ばされます。

##Ⅱ．ピースがはまるときの挙動
　各ピースに目的の座標を設定しておき、その点に任意の距離ほど近づいた際、設定した座標にワープすることで「穴にはまるパズルピースの挙動」を目指しまた。

| 使った関数       |関数の意味                        |
|:-----------------|:-------------------------------|
|     OnMouseUp()         　　　　|オブジェクトからマウスを離した時に行われる|
|Mathf.Abs()|()内の絶対値をとる|
###コード例
```C#:move_piece.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move_piece : MonoBehaviour {

    public Vector3 GoalPos;
    public float span;

    private void OnMouseDrag()
    {
        Vector3 ObjPos = Input.mousePosition;
        ObjPos.z = 10f;
        transform.position = Camera.main.ScreenToWorldPoint(ObjPos);
        Debug.Log(Input.mousePosition);
    }

    private void OnMouseUp()
    {
        float x_length = Mathf.Abs(GoalPos.x - transform.position.x);
        float y_length = Mathf.Abs(GoalPos.y - transform.position.y);

        if (x_length <= span && y_length <= span)
        {
            transform.position = GoalPos;
        }
    }
}
```
　OnMouseUp()をさらに追加しました。
　spanに任意に距離を設定し、ドラッグ後のオブジェクトの座標と目的の座標の距離の絶対値をspanと比較し、span以下だった場合にワープさせています。

##Ⅲ．実行例
![tech_blog1.gif](https://qiita-image-store.s3.amazonaws.com/0/273940/60608cb6-9a10-55fd-29f4-8024a01f3885.gif)
　spanの値を調整することで、ピースがワープする距離を変更できます。

#３．まとめ
　今回はピースの目的位置を座標として与えましたが、パズルによっては複数の穴にはまるものもあります。その場合、Rayを使って穴を取得し、もっとも近い穴にワープするというのも手かもしれません。
　以上をもちまして、「パズルピースの挙動」とさせていただきます。
　少しでも参考にでもなればと思います。ありがとうございました！
【AWSメモ】DynamoDB StreamsのストリームデータをLambdaで読み込む

DynamoDB StreamsのストリームデータをLambdaで読み込む方法を記載します．

# **1. DynamoDB Streamsについて**

一言で言うと，DynamoDBテーブル内の変更を時系列順に最大24時間保存する．

DynamoDB Streamsは下記を保守する
- 変更内容はストリームに 1 回だけ出現する
- 変更された各項目について、実際の変更と同じ順序で出現する

# **2. ストリームの有効化**

DynamoDB Streamsを有効化する前に，まずテスト用のテーブルを作成する．
- プライマリーキーは`name`で，その他項目は`value`とする．

![スクリーンショット 2018-07-13 21.37.19.png](https://qiita-image-store.s3.amazonaws.com/0/262328/8c776d33-8541-0f39-4ee4-9037389eb51f.png)

DynamoDB Streamsを有効化するのは非常に簡単です．
DynamoDBコンソールのダッシュボードから、[テーブル]を選択．

![スクリーンショット 2018-07-13 21.41.30.png](https://qiita-image-store.s3.amazonaws.com/0/262328/64106286-c981-4854-78e6-cf133cd6d9db.png)

[概要]タブで、[ストリームの管理]を選択．

![スクリーンショット 2018-07-13 21.38.15.png](https://qiita-image-store.s3.amazonaws.com/0/262328/45c15688-4df9-a5f2-8eb2-9fc6dd753bb3.png)

[ストリームの管理]ウィンドウで、テーブルのデータが変更されるたびにストリームに書き込まれる情報を選択し，[有効化]をクリック

![スクリーンショット 2018-07-13 21.38.33.png](https://qiita-image-store.s3.amazonaws.com/0/262328/e3e6c186-0bd7-550b-3abb-24160e71079c.png)

各ストリームは，Amazonリソースネームで一意に識別されます．

```
arn:aws:dynamodb:ap-northeast-1:111122223333:table/height/stream/2018-07-13T12:38:41.050
```

# **3. ストリームの読み込み**

読み込む方法としてLambdaからDynamoDBをトリガーとして読み込む方法がある．

## **3.1. Lambda関数を作成**

Lambda関数を作成する．設計図を選択し，「dynamodb-process-stream-python3」を選択する．

![スクリーンショット 2018-07-13 22.33.15.png](https://qiita-image-store.s3.amazonaws.com/0/262328/bf475319-15d1-e8fe-cdce-8047e172fbf3.png)

Lambda関数名やIAMなどは必要な情報を埋める．

![スクリーンショット 2018-07-13 22.36.14.png](https://qiita-image-store.s3.amazonaws.com/0/262328/a02c32b5-f5a3-afc1-297f-116b830eb442.png)

DynamoDB トリガーは`トリガーの有効化`を選択するとDynamoDB Streamsからデータを読み込む設定が完了する．

![スクリーンショット 2018-07-13 22.35.50.png](https://qiita-image-store.s3.amazonaws.com/0/262328/664f5d35-8241-7680-c521-b215b73f09d4.png)

Lambda関数を作成する．下記は既存のテンプレート．

![スクリーンショット 2018-07-13 22.35.55.png](https://qiita-image-store.s3.amazonaws.com/0/262328/9ba9f505-a884-0d9e-712f-a9347f7f15b6.png)

## **3.2. DynamoDBにデータを挿入し動作確認**

実際にDynamoDBに下記の通り値を挿入してみる．

![スクリーンショット 2018-07-13 22.28.08.png](https://qiita-image-store.s3.amazonaws.com/0/262328/282cedff-0198-b4b7-ffd9-5d81d9fe656b.png)

下記の通りログが流れていることがわかる．

![スクリーンショット 2018-07-13 22.30.41.png](https://qiita-image-store.s3.amazonaws.com/0/262328/edcefdde-0e64-5599-fc53-40fc9f042687.png)

下記がログの抜粋

```
{
    "ApproximateCreationDateTime": 1531488480,
    "Keys": {
        "name": {
            "S": "tarou"
        }
    },
    "NewImage": {
        "name": {
            "S": "tarou"
        },
        "height": {
            "N": "160"
        }
    },
    "SequenceNumber": "17700000000000480644429",
    "SizeBytes": 27,
    "StreamViewType": "NEW_AND_OLD_IMAGES"
}
```

# **4. 参考リンク**

- [DynamoDB ストリーム を使用したテーブルアクティビティのキャプチャ
](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Streams.html)
react-bootstrap-table2を使ってみた。

# [react-bootstrap-table2](https://react-bootstrap-table.github.io/react-bootstrap-table2/)を使ってみた。

```react
 <BootstrapTable keyField={'artist songTitle'}
            data={ results.data.maxResultList } 
            columns={ columns }
            rowEvents={rowEvents}
            pagination={ paginationFactory()}/>
```

## jsonに対応するdataFieldを指定する
```javascript
const columns=[
  {
      dataField: 'date',
      text: '日付',
      classes:'',
      sort:true,
      formatter: dateFormatter,
  },
...
]
```

## keyFieldにはプロパティを２つ以上指定できる
1つのkeyFieldで値が一意にならなかったので、
カンマ区切りで2つ指定しようとしたら失敗。
スペースを空けてプロパティ名を２つ指定するらしい。

## onRowClickはrowEventに統合された
rowEventの中でonClick(event, row, rowIndex)という関数が用意されているようです。

```javascript
const rowEvents={
    onClick:(e,row,rowIndex)=>{
        console.log(row);
        
    }
}
```

## formatter
ミリ秒から日付を表示するformatter。

```react
const dateFormatter=(cell,row)=>{
    var date=new Date();
    date.setTime(cell);
    return (
    <span>
      {date.toLocaleDateString()}
    </span>)
}
```

## classesにもfunctionが使える
```javascript
{
      dataField: 'score',
      text: '得点',
      classes:judgePointStyle,
      sort:true,
  },

```


```javascript
const judgePointStyle=(cell,row)=>{
    var cssName;
        if(cell===100){
            cssName='';
        }else if(cell>=99){
            cssName='total_over99'
        }else if(cell>=98 && cell<99){
            cssName='total_over98'
        }else if(cell>=95 && cell<98){
            cssName='total_over95'
        }else if(cell>=90 && cell<95){
            cssName='total_over90'
        }else if(cell>=85 && cell<90){
            cssName='total_over85'
        }else if(cell>=80 && cell<85){
            cssName='total_over80'
        }
        return cssName;
}
```
Djangoでrequest情報をどこからでも参照できるようにする

requestされたurlのパスに応じて、データベースの振る舞いであったりコアな部分の挙動を少し変えたい……ということがあったので。
reqeust情報をこの関数まで持ってくるのが辛いな、ということがあったので、
あまり良い実装ではなさそうなんですが、どこからでも参照できるようにしてみました。

# 実装例

Djangoのミドルウェアを新規に追加して、
そのミドルウェアの中でrequest情報を保存、参照できるようにしました。
ミドルウェアについては下を参照で。

https://docs.djangoproject.com/ja/2.0/topics/http/middleware/

```py
import threading

GLOBAL_REQUEST_CONTEXT = threading.local()

def custom_middleware(get_response):
    def middleware(request):
        GLOBAL_REQUEST_CONTEXT.request = request
        return get_response(request)

    return middleware

def get_request():
    try:
        return GLOBAL_REQUEST_CONTEXT.request
    except AttributeError:
        return None
```

やっていることは超単純なんですが、キモはthreading.local()です。
これを設定してあげないと、リクエストを受けた際に各ユーザごとの情報が入り乱れてしまうので😭
ここまで実装できたら、後はget_request()　をrequest情報が欲しいところで呼んであげればOKです！

# 最後に
[株式会社ネコカリ](https://www.nekokari.co.jp/)では猫の手も借りたい🔥炎上中🔥なお仕事を募集しています！
一緒に働くメンバーも募集していますので、よかったら是非！
TODO管理をvimとiPhoneで手軽にやってみたった

# Summary
`todo`管理を`vim`と`iPhone`でやってみた
`todo`のデーター形式は `todo.txt`

## motivation
`toodledo`での柔軟なタスク管理と、`iPhone's reminders.app`での手軽なタスク管理をもっと手軽にやってみたかった

手軽にフォルダ管理・サブフォルダ管理がしたい
→ プロジェクトとしてのタスク管理

手軽に日付からの時間帯コンテキストで管理がしたい
→ 実行フェーズでのタスク管理

手軽に`iPhone`で上記のタスク管理（特に実行フェーズでのタスク管理）をしたい
手軽に`vim`で上記のタスク管理がしたい

## todo.txt format とは？

plain text です
タスクを一行で表します
`+foo` で foo project
`@bar` で bar context

see: [todo.txt format](https://github.com/todotxt/todo.txt)



## 工夫したところ
`+foo ++bar` でサブフォルダを表現するところ
@thinca さんの [vim-partedit](https://github.com/thinca/vim-partedit) を利用することでいい感じに（ `partedit` を使うことが`filter`になっている。そのおかげで ソート by folding marker が柔軟になる）

## こんな感じ

![todo.gif](https://qiita-image-store.s3.amazonaws.com/0/149269/334c4a62-6395-379f-9248-93926aba6b0b.gif)

## こんな感じ２

まずはフォルダ`+`表示

![Screen Shot 2018-07-23 at 3.21.10.png](https://qiita-image-store.s3.amazonaws.com/0/149269/a0ea37c6-8f47-099c-5aec-88e01902b535.png)

たとえば日付`due:`でフォルディング表示。日付の上でスペース２回押す。

![Screen Shot 2018-07-23 at 3.21.23.png](https://qiita-image-store.s3.amazonaws.com/0/149269/1fdd6d62-21c6-60ce-a802-4202809571cd.png)

その日付だけのデーターが別窓で開く

![Screen Shot 2018-07-23 at 3.21.36.png](https://qiita-image-store.s3.amazonaws.com/0/149269/4025e5ca-7c91-a0f0-f60a-25073ccbb987.png)

ここでコンテキスト（この場合時間帯）でフォルディング表示。これで今日、何をすればいいかのタスク表示をゲッツ

![Screen Shot 2018-07-23 at 3.21.48.png](https://qiita-image-store.s3.amazonaws.com/0/149269/fc52feab-808c-936b-bd2c-c3a3030f90ce.png)

タスクを`done`してみる

![Screen Shot 2018-07-23 at 3.22.04.png](https://qiita-image-store.s3.amazonaws.com/0/149269/7059cf0d-fddf-6a44-1226-91cd87533669.png)


## こんな感じ３

`iPhone`でも同じような表示をしてみる

<img width="375" alt="IMG_7431.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/149269/e5ad869f-c784-e2ed-5c2c-7f33d686e4e3.png">


## Vimのコード

[vim-todoedit](https://github.com/callmekohei/vim-todoedit)

## iPhone アプリ
[SwiftoDo](http://swiftodoapp.com/) というのを使ってますっ
Atcoder埋め反省会 CODE FESTIVAL 2017 Final B問題

自分用なので悪しからず

#問題
https://cf17-final-open.contest.atcoder.jp/tasks/cf17_final_b

#投げたコード
```cpp
#include<bits/stdc++.h>
using namespace std;
 
#define P(p) cout<<(p)<<endl
#define rep(i,m,n) for(int i = (m); i < (int)(n); i++)
#define rrep(i,m,n) for(int i=(int)(m); i>=(int)(n); i--)
#define vsort(v) sort(v.begin(), v.end());
#define rvsort(v) sort(v.begin(), v.end(),greater<int>());
#define YES cout<<"YES"<< endl
#define NO cout<<"NO"<<endl
#define Yes cout<<"Yes"<<endl
#define No cout<<"No"<<endl  
#define yes cout<<"yes"<<endl
#define no cout<<"no"<<endl
#define ret return
#define lb(v,n) lower_bound(v.begin(),v.end(),n)
#define ub(v,n) upper_bound(v.begin(),v.end(),n)
#define mae(v) max_element(v.begin(),v.end())
#define mie(v) min_element(v.begin(),v.end())
#define INF 0x7FFFFFFF
#define mod 1000000007
typedef long long ll;
////////////////////////////////////////////////////////////

int main(){
	string s;
	cin >> s;

	int n = s.size();

	string s2 = "";
	int cnt = 0;
	int lim = 0;
	while( !q.empty() ){
		char c = q.front();
		q.pop();
		
		if( cnt > lim ){
			NO;
			ret 0;
		}

		if( s2.size() == 0 ) s2 += c;
		else if(s2.size() == 1 ){
			if( s2[0] != c ) s2 = c + s2;
			else{
				q.push(c);
				cnt++;
				lim = q.size();
			}
		}
		else{
			if( s2[0] != c && s2[1] != c ){
				s2 = c + s2;
				cnt = 0;
			}
			else if( s2[s2.size()-1] != c && s2[s2.size()-2] != c ){
				s2 += c;
				cnt = 0;
			}
			else{
				q.push(c);
				cnt++;
				lim = q.size();
			}
		}
	}

	YES;
	ret 0;
}

```

諦めて解説見るまで37分

#嘘解法
2文字連続，もしくはabaのような部分文字列があるとNO．
→queueに詰めてそうならないように文字列を作る
→queueを一周したらNO

#良かった点
2文字連続，もしくはabaのような部分文字列があるとNOという考えまでは合っていた

#悪かった点
- 文字列が'a','b','c'の3文字で構成されるのを読んでいなかった
- すぐ実際に作ろうとするところ
Google Cloud Datalabが起動しないときの対処方法

# Google Cloud Datalabが起動しないときの対処方法

## 何が起こったのか
久しぶりにdatalabを使おうとした。

```console
datalab connect (VMインスタンス名)
```
すると延々と次のメッセージが表示されて一向に接続できない。

```console
Attempting to reconnect...
Waiting for Datalab to be reachable at http://localhost:8081/
datalab@XX.XXX.XXX.XX: Permission denied (publickey).
ERROR: (gcloud.compute.ssh) [/usr/bin/ssh] exited with return code [255].
Connection broken
```

どうやら立ち上がっていないようだ。

## 何をやらかしたのか
https://cloud.google.com/datalab/docs/how-to/adding-libraries
に書いてある startup.sh にライブラリを追加する pip コマンドを追加した。
ただし pip ではなく pip3 で！
なぜなら python3 ユーザだから。

## どうやって直したのか
コンソールでログインをする。

```console
gcloud compute ssh (VMインスタンス名)
```

ログインした後、次の2つのファイル

- /mnt/disks/(永続化ディスク名)/content/startup.sh
- /mnt/disks/(永続化ディスク名)/content/datalab/.config/startup.sh

の pip3 部分を削除。作ったばかりなら2つのファイルごと削除しても構わない。
その後 VMインスタンス を再起動した。

## 結局どうしたか
pip の部分を /usr/local/envs/py3env/bin/pip3 に変えた。

## 教訓
startup.sh にエラーとなるコマンドを追加すると datalab ごと起動しなくなる。
【Swift 4.0】 APIでキャッシュを無視してリクエストする方法

先日、[Alamofire](https://github.com/Alamofire/Alamofire)を用いてAPIのリクエストを行っていたところ、キャッシュが原因で不具合が発生していたため、その時に行った対処法をご紹介します。

##発生していた不具合
APIが一度リクエストされたあとにiPhone端末自体の時刻を過去の時間に戻したところ、以前のAPIのレスポンスが返却され、サーバのアクセスログにもログがなく、API自体がリクエストされていない。

##対処法
[URLRequest](https://developer.apple.com/documentation/foundation/urlrequest)の[cachePolicy](https://developer.apple.com/documentation/foundation/urlrequest/2011593-cachepolicy)に`.reloadIgnoringLocalCacheData`を設定することでキャッシュを無視することができました。具体的には下記のようになります。

```Swift
let request = URLRequest(url: URL(string: "https://example.tetsukick.com"),
                         cachePolicy: .reloadIgnoringLocalCacheData,
                         timeoutInterval: 5.0)
```

##補足事項
cachePolicyには他にも下記の設定ができるようです。まだ実際に使用することはできておりませんが、ネットワークの通信状況によっては、あえてキャッシュのデータを返すようなこともできるのではと思います。

|cachePolicy  |説明  |
|---|---|
|useProtocolCachePolicy  |特定のURLロード要求に対して、プロトコル実装で定義されているキャッシング・ロジックがあればそれを使用します。  |
|reloadIgnoringLocalCacheData  |ローカルに保存されたキャッシュデータを無視して取得します。  |
|~~reloadIgnoringLocalAndRemoteCacheData~~  |~~ローカルのキャッシュデータに加え、ネットワーク途中のプロキシなども含めてキャッシュを無視して取得します。~~現在、使用不可の設定値  |
|returnCacheDataElseLoad  |キャッシュデータがあれば、その有効期限などは考慮せずキャッシュを使います。なければ、取得します。  |
|returnCacheDataDontLoad  |キャッシュデータがあれば、その有効期限などは考慮せずキャッシュを使います。なければ、失敗になります。  |
|reloadRevalidatingCacheData  |HEADリクエストを発行し更新を確認します、更新があればリクエストを発行します。  |

##参考資料
[AlamofireでCache-Controlを設定する](https://qiita.com/sl2/items/1ffca167ababf48d095e)
[\[Swift\] Alamofireでキャッシュを無効化してリクエストを発行する](https://www.yoheim.net/blog.php?q=20180306)

##更新履歴
2018/07/23　[tokorom](https://qiita.com/tokorom)様より、ご指摘いただき、`reloadIgnoringLocalAndRemoteCacheData`→`reloadIgnoringLocalCacheData`に変更いたしました。
下記、公式ドキュメントに記載の通り、現在実装されていないようです。
https://developer.apple.com/documentation/foundation/nsurlrequest/cachepolicy/reloadignoringlocalandremotecachedata
tokorom様ありがとうございます。
MySQL 8.0 で validate_password を有効化・無効化する方法

# 概要

MySQL の新規パスワードの強度チェック機能 "validate_password" がバージョン8から扱いが変わってプラングインでなくコンポーネントになったとのこと。
従来とは有効化、無効化の方法とは違っているが、ググってもぱっと出てこなかったので自分用メモ。

## 方法

mysql のコンソールで以下を実行。

```sql
-- 有効化
INSTALL COMPONENT 'file://component_validate_password';

-- 無効化
UNINSTALL COMPONENT 'file://component_validate_password';
```

## 参考サイト

https://dev.mysql.com/doc/refman/8.0/en/validate-password-installation.html
S3の静的WebホスティングでSwagger UIを動作させる

## 前提条件

`この記事ではAWSの環境作成にTerrformを使っています。`
`リソース名などは適宜読み替えてください。`

## Swaggerとは？

まとめて頂いている素晴らしいページがありました

https://qiita.com/gcyata/items/342073fa7607fd4082bd

本家サイトはコチラ
https://swagger.io/

## 今回のゴール

今回はその中のSwagger UI（Swagger-Specを読み込んで、HTML形式でドキュメントを生成するためのツール）をWebホスティングで構築したいと思います。
本来は Swagger UI が動作するサーバーを用意する感じみたいなのですが、実業務で利用する際にメンバーが簡単に使えないと利用されないと思い、利用側は裏側を意識せず利用することを目的としています。

## 構築

AWSの構築は terraformで作成します。

### terraform で静的ウェブサイトホスティング用に S3 バケットを作成

※アクセスできるIP許可設定は設定してください。

````
variable "website_bucket_name_apidoc_com" {
  default = "apidoc.com"
}

# AWS S3 bucket for static hosting
resource "aws_s3_bucket" "apidoc_com" {
  bucket = "${terraform.workspace}.${var.website_bucket_name_apidoc_com}"
  acl = "private"

  tags {
    Environment = "${terraform.workspace}"
  }

  policy = <<EOF
{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "PublicReadForGetBucketObjects",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::${terraform.workspace}.${var.website_bucket_name_apidoc_com}/*",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            <<許可するIPアドレス群>>
          ]
        }
      }
    }
  ]
}
EOF

  website {
    index_document = "index.html"
    error_document = "error.html"
  }
}

````

### ドキュメントファイル

公式がgithubに提供しています。
https://github.com/swagger-api/swagger-ui

dist フォルダをS3に展開します。
展開する際にindex.htmlだけ少し修正します。
※また SwaggerJsonの展開先として、「json/v2」フォルダを作成してあります

````javascript:index.html
      // Build a system
      const ui = SwaggerUIBundle({
        url: "https://petstore.swagger.io/v2/swagger.json", <- 変更
        dom_id: '#swagger-ui',
        deepLinking: true,
````

↓ 

````javascript:index.html
      // Build a system
      const ui = SwaggerUIBundle({
        url: "http://apidoc.com/json/v2/swagger.json",
        dom_id: '#swagger-ui',
        deepLinking: true,

````

S3にアップロード後、 http://apidoc.com/json/v2/swagger.json にアクセスすることでドキュメントを閲覧することができます。


## 次回の内容
完全なゴールを目指すため、CodeCommit と CodePipeline を利用してドキュメントを自動更新するようにします
Vagrant で VirtualBox に Ubuntu 環境を構築


# 構成
- Windows 10
- VirtualBox 5.2.16
- Vagrant 2.0.2
- Ubuntu 18.0.4 LTS

# Virtualboxのインストール
1. 本家サイトから[Virtualbox platform packages](https://www.virtualbox.org/wiki/Downloads)をダウンロード
2. 取得したパッケージをインストール
3. 本家サイトから[Virtualbox Extension Pack](https://www.virtualbox.org/wiki/Downloads)をダウンロード
4. 取得したパッケージをインストール

# Vagrantのインストール
1. 本家サイトから[Vagrant](https://www.vagrantup.com/downloads.html)をダウンロード
2. 取得したパッケージをインストールし、OSを再起動
3. 動作確認

```bat:コマンドプロンプト
C:> vagrant -v
Vagrant 2.0.2
```

# Ubuntu 18.04 LTS をインストール
・本家サイトの[Box検索](https://app.vagrantup.com/boxes/search)でゲストOSを検索

・任意の場所にゲストOSの起動ディレクトリを作成

```bat:コマンドプロンプト
C:> mkdir C:\data\Vagrant\Ubuntu18
C:> cd    C:\data\Vagrant\Ubuntu18
```


・Vagrantfileのテンプレート作成
※以下の初期化コマンドは検索したBoxのページの「New」タブに記載されている

カレントディレクトリにVagrantfileのテンプレートを作成する。

```bat:コマンドプロンプト
カレントディレクトリにVagrantfileのテンプレートを作成する（ベンダー名/Box名）
C:\data\Vagrant\Ubuntsu16> vagrant init pristine/ubuntu-budgie-18-x64
```

・Vagrantfileをエディタで編集する

※以下の編集内容は検索したBoxのページの「Vagrantfile」タブに記載されている

```rb:Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "pristine/ubuntu-budgie-18-x64"
end
```

必要があれば以下のコメントアウト部分を編集してGUIを有効にしたり、VMのメモリを増やす。

```rb:Vagrantfile
  # config.vm.provider "virtualbox" do |vb|
  #   # Display the VirtualBox GUI when booting the machine
  #   vb.gui = true
  #
  #   # Customize the amount of memory on the VM:
  #   vb.memory = "1024"
  # end
```

VMを起動する（VMはVirtualBoxを指定）
※初回はVMイメージのダウンロードに時間がかかります。

```bat:コマンドプロンプト
C:\data\Vagrant\Ubuntsu18> vagrant up --provider virtualbox
```



# VMの起動と停止

■VMを起動する。

```bat:コマンドプロンプト
C:\data\Vagrant\Ubuntsu18> vagrant up
```


■VM上のOSにSSH接続する。
慣例としてVagrantイメージのパスワードはvagrantとなっている。
- スーパーユーザー（root : vagrant）
- 一般ユーザー （vagrant : vagrant）

```bat:コマンドプロンプト
C:\data\Vagrant\Ubuntsu18> vagrant ssh
```


■VMを停止する

```bat:コマンドプロンプト
C:\data\Vagrant\Ubuntsu18> vagrant halt
```


■VMを再起動する

```bat:コマンドプロンプト
C:\data\Vagrant\Ubuntsu18> vagrant reload
```

# おまけ：minimum構成のOSにGUIをインストールしたい場合

```bash:bash
sudo apt-get install xfce4
sudo add-apt-repository ppa:gnome3-team/gnome3
sudo apt-get update
sudo apt-get install gnome-shell
sudo apt-get install ubuntu-desktop
sudo apt-get install gdm
sudo dpkg-reconfigure gdm
```

再起動後、GUIが使えるようになる。
デザイン自動化メモ（InDesignのアクティブドキュメントのファイル名とフォルダ名を取得する）

ファイル名とフォルダ名を取得する関数です。
フォルダの方が少し厄介で、Folderオブジェクトを経由してMacとWindowsの両方で使えるようにしています。
※macとWindowsではファイル区切り文字が異なるため。

```js
function getActiveDocumentFileName() {

   var fileObj=app.activeDocument.name;
   return fileObj.toString();
}

function getActiveDocumentFolder() {

   var activeDocumentFolder = Folder(app.activeDocument.filePath);
   return activeDocumentFolder.toString();
}

function main() {

      var filename = getActiveDocumentFileName();
      var foldername = getActiveDocumentFolder();
      
      alert(filename);
      alert(foldername);
 }

main();
```
rubyのスクリプトでslackのAPIを使って簡単なメッセージを投稿してみる_100DaysOfCodeチャレンジ31日目(Day_31:#100DaysOfCode)


## はじめに
この記事はTwitterで人気のハッシュタグ#100DaysOfCodeをつけて、
100日間プログラミング学習を続けるチャレンジに挑戦した31日目の記録です。

## 動作環境
* Ruby 2.4.1p111 (2017-03-22 revision 58053)

## 本日学んだこと

* slackのAPIを使って、Botにメッセージを送ってみる

## SlackのAPIを使うために必要なTOKENを取得する

公式サイト: https://api.slack.com/

上記のリンク先からアクセスして、「start building」ボタンを押します。

「Create a Slack App」というモーダルが立ち上がるので、任意の名前と開発対象となる既存のワークスペースを選択します。

「Basic Information」というページに遷移するので、「Add features and functionality」から追加する機能を選択します。

今回はBotsを選択しましょう。

Bot Userページに遷移するので、「Add a Bot User」ボタンを押します。

「Display name」と「Default username」に表示させたい名前を入力して、「Add Bot a User」ボタンを押します。


サイドメニューにある「OAuth & Permissions」を選択し、「Install App to Workspace」を押しましょう。

確認画面が表示されるので、「許可する」を選択します。

そうすると、画面が遷移し、「OAuth & Permissions」ページに「OAuth Access Token」と「Bot User OAuth Access Token」という二つのトークンが表示されているのがわかります。

今回のスクリプトでは、「OAuth Access Token」を使います。

## ターミナルの作業:Rubyのスクリプトを作成する

ここからはターミナルの作業です。

任意の場所で、適当なディレクトリを作成します。rubyでslackのAPIを使うために、gemをインストールするので、`bundle init`をしておきましょう。

```bash
$ mkdir slack-bot
$ cd slack-bot
$ bundle init
```

`Gemfile`に次のgemを追加します。

```ruby
gem 'slack-api'
gem 'dotenv'
```

bundle installします。

```bash
$ bundle install --jobs=4
```

続いて、先ほど取得した「OAuth Access Token」をdotenvに記述します。

```ruby
SLACK_TOKEN="jfirjirifxkXXXXXXXX45454fekdoe0fikeo"
```

そして、ここからslackのAPIを使うためのファイルを作成します。

```bash
touch slack.rb
```

`slack.rb`の中身はこんな感じです。

```ruby
#slack.rb
require "dotenv/load"
require "slack"

Slack.configure do |config|
  config.token = ENV['SLACK_TOKEN']
end


# ワークスペースにいる全員にメッセージを送る
def send_message_to_all
  Slack.users_list["members"].each do |member|
    Slack.chat_postMessage(channel: member["id"], text: "Hello! テストだよ!")
  end
end

send_message_to_all
```

保存したら、ターミナルで実行してみましょう。

```bash
$ bundle exec ruby slack.rb
```

対象となるワークスペースで、テキストが表示されていたら成功です。

これを応用して、ポモドーロで25分ごとに休憩を促すBotとかを作ったら、色々はかどりそうですよね。

時間見つけて実装してみようと思います。


## 参考

https://www.rubydoc.info/gems/slack-api/Slack/Endpoint/Chat#chat_postMessage-instance_method

https://api.slack.com/methods/chat.postMessage
ターミナルから爆速で天気予報をみる

#天気予報、知りたいですよね？

みんな仕事中にオイミャコン[^1]って今どれくらいの気温かな？って気になるときがあると思う(俺はない)。そんなときいちいち天気予報アプリや検索するのは面倒って人に朗報です。あなたがいつもよく使っているその「黒い画面」から天気予報がわかるのです。

---

#### 2019/06/28 追記
現在サービスを停止しているようです。復旧を待ちましょう。

>Sorry, we processed more than 1M requests today and we ran out of our datasource capacity.
We hope to solve the problem as soon as possible, so you can enjoy
your favourite weather service 24x365 even if it rains or snows.

[wttr.in](http://wttr.in/)

#### 2019/07/08 追記
復旧したようです。

---

#自分の環境
OS: macOS High Sierra
shell: zsh
ターミナル: iTerm2

# ターミナルを使って天気予報を表示させるには
[wttr.in](http://wttr.in/)を利用する。このサイトを `curl`なり何なりすることによって黒い画面に天気予報を表示させる仕組み。

```
curl wttr.in/Tokyo
```
ヘルプページを見たい人は[wttr.in/:help](http://wttr.in/:help)に書いてある。
それとこちらの[Githubのwttr.in](https://github.com/chubin/wttr.in)にもいろいろ書いてある。

## 天気予報を見るためのエイリアスの設定方法

bashでのaliasの設定の仕方が
http://wttr.in/:bash.function
ここに書いてあるので、こちらのページを参考にエイリアスの設定をしていく。

```bash.
wttr()
{
    # change Paris to your default location
    curl -H "Accept-Language: ${LANG%_*}" wttr.in/"${1:-Paris}"
}
```
とのことなので、東京に設定したい場合は

```bash.

wttr()
{
  curl -H "Accept-Language: ${LANG%_*}" wttr.in/"${1:-Tokyo}"
}
```
こんな感じ？ちなみに私はzshを使っているのでこう書いた。

```zsh.
alias wttr='() { curl -H "Accept-Language: ${LANG%_*}" wttr.in/"${1:-Tokyo}" }'
```

これで(zshを使っている場合) `source ~/.zshrc` して変更を適用させる。

### 言語設定について
コメントで@webmaster-patcheさんに教えてもらいまいした。Accept-Languageヘッダの他にRequestパラメータでも言語設定を変えられます。

```shell
 curl wttr.in/Tokyo?lang=ja
```

# ターミナルから天気予報をみてみよう

```zsh.
wttr
```

 って打つと東京の天気予報が日本語で表示される。
マルチリンガル対応なので引数に日本語を指定してもOK.もちろん、ロシア語も。

```zsh.
wttr 東京
```

<img width="1068" alt="スクリーンショット 2018-07-11 10.57.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/241879/65b99c89-49fb-f0b4-0b99-3d2a15fb1cd8.png">

オイミャコンの気温を知りたいときはこうする。

```zsh.
wttr Оймякон
```

さらには月の満ち欠けもわかってしまうのだ。

```zsh.
wttr moon
```
<img width="1071" alt="moon.png" src="https://qiita-image-store.s3.amazonaws.com/0/241879/050ce392-9a44-61c6-fc88-b90474eb8e69.png">


#感想
これでターミナルで作業中でもすぐに天気予報が確認できますね！

## あわせて設定したい
[【Zsh】ターミナルから爆速で自分のグローバルIPアドレスを調べる方法](https://qiita.com/mtoutside/items/52e4b387254d1224894f)

###参考

[コマンドラインで天気予報を見る方法](https://linuxfan.info/wttr-in)

[^1]: 世界一寒い地域らしい。 c.f.[オイミャコン](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%82%A4%E3%83%9F%E3%83%A3%E3%82%B3%E3%83%B3)
Tmux のセッション名を楽に変えて楽に管理する

`tmux`、便利ですよね。僕は使わない日が無いほど依存しています。

`tmux`はセッション・ウィンドウ・ペインという単位で画面を管理します。
僕の`tmux`の使い方だと、プロジェクト単位(リポジトリ、フォルダ等)でセッション、目的単位(常駐プロセス起動、ソースコード編集等)でウィンドウ、タスク単位(サーバー起動・ファイル変更監視等)でペインを割っています。

しかし何も考えずにセッションをバンバン立ち上げまくっていると

<img width="303" alt="スクリーンショット 2018-07-22 21.31.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/29000/16b1e6eb-befd-2fdf-f588-5443ba26e707.png">

こうなります。

どのセッションで何やってるか分からなくなるので、切り替えるときに迷います。

`tmux`にはセッションに名前を付けるコマンド(`rename-session`)もありますが、いちいちセッション名を打つのも面倒なので、半自動でいい感じにセッション名をつけてくれるスクリプトを書きました。

```bash:tmux-rename-session
#!/bin/bash

if [ $# -lt 1 ]; then
    git status > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        directory=`basename $(git rev-parse --show-toplevel)`
    else
        directory=`basename $(pwd)`
    fi
else
    directory=$1
fi

tmux rename-session ${directory//./_}
```

スクリプト単体で動かすと、今いるディレクトリに応じて次のような法則でセッション名を変更します。

1. git管理下のフォルダにいる場合
    * プロジェクトのルートフォルダ名
1. git管理外のフォルダにいる場合
    * 今いるフォルダ名
1. スクリプトに引数を渡した場合
    * 引数の文字列

また、セッション名に`.`が使えないようなので、名前に`.`が含まれている場合は`_`に置換しています。

`~/.tmux.conf`で、このスクリプトをキーバインド設定します。

```:~/.tmux.conf
bind-key (key) command-prompt -p "Session name >" "run-shell 'cd #{pane_current_path} \; tmux-rename-session %%'"
```

キーバインドを打つと、ステータスバーに以下のようなプロンプトが出ます。

<img width="331" alt="スクリーンショット 2018-07-22 23.35.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/29000/51eb633f-0257-cbfb-314c-e3c2ec41a75e.png">

そのままエンターすると、上記`1.`または`2.`の法則でセッション名が変わります。
自分でセッション名を決めたい場合は、プロンプトに何か入力するとそちらを優先します。

<img width="335" alt="スクリーンショット 2018-07-22 23.54.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/29000/0d77ca74-0aba-b03b-4b88-b00f5ca12b54.png">

基本は名前を付けたいセッションにいるときにキーバインド > EnterでOKです。
ガンガン名前を付けて、管理しやすくしていきましょう。
<img width="398" alt="スクリーンショット 2018-07-23 0.14.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/29000/19579fa1-31a1-f2eb-54d6-15dc76f865d4.png">
Scrapboxで自分のプロファイルを設定する

ひょんなことから[Scrapbox](https://scrapbox.io/)というノート共有・共同編集サービスを使い始めました（少し続けてみて、様子を見て本採用するか判断）。
使い始めにおいて、自分のプロファイルの設定手順が若干トリッキーだったので、備忘録も兼ねて手順を記します。

0. まず知っておく必要があること
-------------------------------
Scrapboxでは、自分のプロファイルもScrapbox内のノートとして作成します。アバター画像はこのノートに貼り付けた画像から抽出されて自動設定される仕組みのようです。

1. プロファイルを作成する
-------------------------
自分のプロジェクトを開始したり、自分以外から招待されてプロジェクトに参加したりすると、その時点では自分のプロファイルのノートは存在しません。

プロファイルを作るには、左上のメニューをクリックして、[Edit Profile]を選択します。

![hhiroshell's project_036.png](https://qiita-image-store.s3.amazonaws.com/0/108645/c15439af-b2b8-6a84-35c2-03d78d458828.png)


するとPersonal Settingsという画面が表示されます。ここで、NameとUsernameを必要に応じて変更し、[Save changes]をクリックします。

![Scrapbox_037.png](https://qiita-image-store.s3.amazonaws.com/0/108645/7fbcf727-7090-7669-f10a-9a9c8a0cf06f.png)

上がってくるダイアログで[OK]をクリック

![Scrapbox_038.png](https://qiita-image-store.s3.amazonaws.com/0/108645/0ca7471e-ad16-6719-a17e-e0bfceba218e.png)

自動でプロファイルのノートが作成されます。画像はGoogleアカウントでScrapboxにログインしていれば、そちらのアイコンが使われる模様。

![hhiroshell - hhiroshell's project_039.png](https://qiita-image-store.s3.amazonaws.com/0/108645/b83d0500-7643-adaa-2e40-5855fc102ad9.png)

画像の辺りにカーソルを持っていくと、画像のURLを編集できるようになります。ここで自分が設定したい画像のURLを書いてあげればそれが使えます（あらかじめオンラインにアップロードしておく必要あり）。

![hhiroshell - hhiroshell's project_041.png](https://qiita-image-store.s3.amazonaws.com/0/108645/c4f39802-7762-57e9-5532-ff4c44a3a630.png)

2. （おまけ）他のノートに自分のアイコンを書き込む
---------------------------------------
ノートを編集しているときに`Ctrl + I`を入力すると、自分のアイコンをそこに書き込むことができます。共同編集だといろいろな使いみちがありそうな機能です。

![てすと - hhiroshell's project_040.png](https://qiita-image-store.s3.amazonaws.com/0/108645/86be4962-c86a-aa14-71d3-18f2a7a44a44.png)

このエントリーの内容は以上です。

少し触った感じでは、今の所なかなか使い勝手が良さそうな感触です。期待。
Pythonのライブラリをインストールできないときに確認したいこと

よくPythonのライブラリをインストールすると（特にRaspberry Piを使っていた時に）、エラーの中にこんな記述がありませんか？

```
Command "python setup.py egg_info" failed with error code 1
```

このようなエラーが出るときはセットアップツールをアップデートをすると、解決できることがあります。Raspberry Piを使っているなら以下のコマンドを入力します。

```
$ sudo pip install --upgrade setuptools
```
【Androidアプリ】通知を受信したらダイアログを表示する

Androidアプリに、通知を受信したらダイアログを表示する機能を実装してみたのですが、思った以上に考慮することが多かった、というお話。
# 通知を受信したらダイアログを表示する
「android 通知 ダイアログ」でググってヒットした下記の記事を参考に実装しました。
[Android]サービスからダイアログを表示する方法 | Coffee Breakにプログラミング備忘録 [http://to-developer.com/blog/?p=925](http://to-developer.com/blog/?p=925)
## 端末でアプリの通知をオフに設定してもダイアログが表示されてしまう
今回の仕様を考慮すると、通知をオフに設定しているのであれば、ダイアログは表示しない方がユーザに優しい。
「android 通知設定 取得」でググってヒットした下記の記事を参考に、通知設定を取得してオンの場合のみ、ダイアログを表示するように改修しました。
androidでpush通知設定を確認、変更画面を開く [https://qiita.com/shim0mura/items/097f6e0cfe091615ea7e#通知設定値を取得する](https://qiita.com/shim0mura/items/097f6e0cfe091615ea7e#%E9%80%9A%E7%9F%A5%E8%A8%AD%E5%AE%9A%E5%80%A4%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B)
## アプリの起動状態でダイアログのボタンの挙動を変えたい
今まさにユーザがアプリを起動している(フォアグラウンドまたはバックグラウンド)のであればダイアログを閉じるだけ、未起動であればメイン画面に遷移する、といった感じでボタンの挙動を変えたかった。
検索ワードを控えそびれたのですが、下記の記事を参考に、判定処理を実装しました。
Androidアプリのプロセスの状態(フォアグラウンド、バックグラウンド、未起動)を調べる方法 [https://qiita.com/k-yamada-github/items/ac7d745e170a38931437](https://qiita.com/k-yamada-github/items/ac7d745e170a38931437)
## アプリ未起動でダイアログを表示後、ダイアログを閉じると思ったような処理ができない
例えば、端末のホーム画面でダイアログが表示された後、ダイアログを閉じる。その後、ホーム画面のアプリアイコンをタップしてもアプリが起動しない現象が発生します。
これはどういうことかというと、□ボタンを押して分かったのですが、このホーム画面、実はアプリの背景なんですね。アプリではホーム画面の処理を実装していないので、「ユーザ は アプリアイコン を タップした！ しかし なにもおこらない」という状態を作り上げてしまっていたのでした。
「android アプリ 終了処理」でググってヒットした下記の記事を参考に、finishではなくfinishAndRemoveTaskを実装し、アプリが終了するように改修しました。
Activity#finish() でアプリが終了できないときは [https://qiita.com/okaxaki/items/f3a4a4ab0616ac2f68ed](https://qiita.com/okaxaki/items/f3a4a4ab0616ac2f68ed)
## ダイアログの枠外をタップすると、ダイアログは閉じるが思ったような処理ができない
ダイアログのボタン以外の操作を失念していました。上記と同じ現象にハマってしまいます。
「android ダイアログ 枠外 タップ」でググってヒットした下記の記事を参考に、setCancelable(false)を実装し、ダイアログのボタン操作を促すよう改修しました。
AlertDialog の背景をタップできなくする [http://tomoyamkung.net/2013/06/11/android-modal-dialog/](http://tomoyamkung.net/2013/06/11/android-modal-dialog/)

***

以上、Androidアプリに、通知を受信したらダイアログを表示する機能を実装してみたら、思った以上に考慮することが多かった話でした。
Mac で Windowsで作られてしまった日本語ファイル名混じりなzipファイルを解凍したい

普通に開こうとして怒られるこういうケースです。
<img width="490" alt="スクリーンショット 2018-07-23 0.07.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/16825/0f2b76ca-37d8-65df-1933-4f205a903801.png">
自分の場合は、Windows→Macとファイルシェアする際に[MEGA](https://mega.nz/)を使ったところ、DLしたファイルが開けなくてハマりました。

- [The Unarchiver](https://theunarchiver.com/)や[Stuffit Expander](https://itunes.apple.com/jp/app/stuffit-expander-16/id919269455?mt=12)で開いてもうまくいかない場合
- そもそもコマンドラインでやりたい場合

におすすめです

#　手順
Docker for Macがインストールされている状態で、以下のとおり

```
docker run --rm -v `pwd`:/data ca54makske/ubuntu-unzip -Ocp932 ./解答したいファイル.zip
```
# 補足など
ただただ ubuntuのDockerイメージでunzip叩いてるだけです
Dockerfile: https://github.com/ca5/ubuntu-unzip

わざわざイメージ作るに至った経緯は以下

- そもそも macのunzipに -O オプションがない
- dockerhubの野良unzipイメージ試す→alpineがベースだと -O オプションがない

もっといい方法がありそう


# 参考
https://qiita.com/toyoshim/items/be4613fa373b4847196f
→ Ubuntuで直接解凍する場合はこれでOK

https://qiita.com/suin/items/856bf782d0d295352e51
→ Dockerイメージ内でlocale指定しないと文字化けしたファイル名で書き出される
【VBA】エクセルファイルを一旦閉じて開きなおすコード＆ファイルの存在するフォルダを開くコード

## コード内容
- エクセルファイルを一旦閉じて開きなおすコード
- ファイルの存在するフォルダを開くコード

## 詳細
- PCに登録したネットワークドライブでファイルやフォルダを開きなおしたい場合が多いので、その機能を追加している。
- Subモジュール2つを個人用マクロに登録して使うと便利な人には便利。

```vb
Option Explicit

Sub ReopenActiveFileUsingNetworkDrive()
    Dim ConfirmationMessage As String
    ConfirmationMessage = _
        "Reopen active file using network drive?" & vbNewLine & _
        "If opened as ReadOnly, close without save and reopen as ReadOnly"
    Call confirmRun(ConfirmationMessage)
    
    Dim wb As Workbook
    Set wb = ActiveWorkbook
    Call EndProcedureIfFileHasNoPath(wb.Path)
    Dim targetFileFullName As String
    targetFileFullName = _
        makeFullPathUsingNetworkDrive(wb.Path, wb.Name)
    
    If wb.ReadOnly Then
        wb.Close saveChanges:=False
        Workbooks.Open targetFileFullName, ReadOnly:=True
    Else
        wb.Close
        Workbooks.Open targetFileFullName
    End If
End Sub

Sub OpenFolderOfActiveFileUsingNetworkDrive()
    Call confirmRun("Open foder of active file?")
    Call EndProcedureIfFileHasNoPath(ActiveWorkbook.Path)
    Dim targetFilePath As String
    targetFilePath = replaceWithNetworkDrive(ActiveWorkbook.Path)
    
    Dim strPath
    strPath = "explorer.exe /e,""" & targetFilePath & """"
    Dim objShell
    Set objShell = CreateObject("Wscript.Shell")
    objShell.Run strPath
End Sub

Private Sub EndProcedureIfFileHasNoPath(wb_path As String)
    If wb_path = "" Then
        MsgBox "This file has no path"
        End
    End If
End Sub

Private Sub confirmRun(confirmation_message As String)
    If MsgBox(confirmation_message, vbYesNo + vbQuestion) <> vbYes Then
        MsgBox "You have chosen not to run the macro"
        End
    End If
End Sub

Private Function makeFullPathUsingNetworkDrive(file_path As String, file_name As String) As String
    Dim targetFilePath As String
    Dim targetFileName As String
    targetFilePath = replaceWithNetworkDrive(file_path)
    targetFileName = file_name
    makeFullPathUsingNetworkDrive = targetFilePath & "\" & targetFileName
End Function

Private Function replaceWithNetworkDrive(file_path As String) As String
    'see: http://www.wmifun.net/sample/vb6/win32_mappedlogicaldisk.html
    Dim MldSet As Object 'SWbemObjectSet
    Dim Mld As Object 'SWbemObject
    Dim Locator As Object 'SWbem Locator
    Dim Service As Object 'SWbem Services
    Set Locator = CreateObject("WbemScripting.sWbemLocator") 'New Wbem Scripting.swbem Locator
    Set Service = Locator.ConnectServer
    Set MldSet = Service.ExecQuery("Select * From Win32_MappedLogicalDisk")
    For Each Mld In MldSet
        file_path = Replace(file_path, Mld.ProviderName, Mld.Name)
    Next
    replaceWithNetworkDrive = file_path
    Set MldSet = Nothing
    Set Mld = Nothing
    Set Locator = Nothing
    Set Service = Nothing
End Function
```
Vue.jsとMaterializeを組み合わせてはイケない理由

## はじめに
Vue.js使ってますか？？？

とっても便利ですよね！

今回はマテリアルデザインのCSSフレームワークの
Materialize(マテリアライズ)
https://materializecss.com/

を導入しようとしたけど、やめた話です。


まず、どんな経緯だったかというと「ちっちゃいサービス」を思いついたので
RailsとVueで作ろうと思ったわけです！

で特に画面のデザイン部分ですが、コンポーネントフレームワークのElement UI とかも良いかなと思ったけど、なるだけコンポーネントをライブラリに依存させないほうがいいかなと思って、マテリアルデザインをささっと導入しようと思ってMaterializeを選択しました！

## それからどしたの

最初は良かったんです！
カラム構成で画面を整えつつ、ボタンとかもイケてる感じに簡単に実装できるので。
しかしFormパーツを作ろうとしてSelectのタグを配置した瞬間に異変に気づきます。

Selectが動かない、optionに並べた選択肢が出ない！？
なんでと思ってMaterializeのリファレンスを見たら、
初期化が必要という事でmaterializeのJS読み込むか、jQueryを導入しないといけないとの事！

いずれの方法でもVueのイベントサイクルに影響するとかReal DOMを取り扱うのに気が引けてしまって
結局導入をやめてElement UIを使う事にしました。

よくよく考えれば分かる事だったのと、気づいてから上手く外部JSを導入する方法を見つけた訳では無かったのでちょっと知見とかもフィードバックできずにごめんなさい。

Materiarizeを導入するためのnpm ライブラリもちらほらありましたが結局Elementに戻る形になってしまいました。

なので上手く利用できる人はいいですが、特別な理由がなければコンポーネントフレームワークの方が実は簡単に使えてるなと思った次第です。



お土産に他に使ってるコンポーネントフレームワークの紹介を置いていきます。

### Vuetify

GoogleのWEBアプリっぽい管理画面の素材があって試しに導入するのも簡単です。
またサイトのサンプルの完成度が高く動作を確認しながら導入できるサンドボックスもあります。
全体的にフレームワークを導入しないといけないので部分的にコンポーネント利用するのには不向きだと思います。

https://vuetifyjs.com
WebJarsでbootstrapを追加したのでちょっとおしゃれにしてみた

[前回](https://qiita.com/keb/items/49601a3ad8e1513dc0c9)の続き

WebJarsでbootstrapを追加したので、おしゃれな画面を作成した。

### 環境

- Mac High Sierra 10.13.5
- Java 1.8.0_11
- Maven 3.5.4
- springboot 2.0.3

### 手順

[Bootstrap](https://getbootstrap.com/docs/4.1/examples/sign-in/)のサインイン画面を利用し、一部変更。

```html:index.htmlの一部
2行目
<html lang="en"> 
↓
<html xmlns:th="http://www.thymeleaf.org"> 

8行目
<link rel="icon" href="../../../../favicon.ico">
↓
コメントアウト

13行目
<link href="../../dist/css/bootstrap.min.css" rel="stylesheet"> 
↓
<link rel="stylesheet" href="webjars/bootstrap/4.1.1/css/bootstrap.min.css" />

16行目
<link href="signin.css" rel="stylesheet"> 
↓
<link href="css/style.css" rel="stylesheet"> 

21行目
<img class="mb-4" src="../../assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
↓ 
自分の好きな画像に変更

34行目
<p class="m5-5 mb-3 text-muted" th:text="${hello}"></p>
を追加
```

16行目、21行目の変更に対応するため、

```
src/main/resources/static/assets 配下にアイコンを追加
src/main/resources/static/css 配下にstyle.cssを追加
```

style.cssの中身はhtml同様、bootstrapよりコピペ。

mvn clean packageでjarファイルを作成して実行