OmniAICreator/Qiita-1.07M huggingface dataset:
【iPhone】「信頼されていないデベロッパ」ダイアログが出た時の対処法

<h2><font color="Hotpink">【iPhone】「信頼されていないデベロッパ」ダイアログが出た時の対処法</font></h2>
iPhone7(IOS11.4.1)

<img width="375" alt="IMG_0001.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/cd5e4344-1090-b068-986f-b363600a7ef5.png">

上記のダイアログが表示され、アプリが実行できない場合、
<font color="HotPink">**「設定」-「一般」-「デバイス管理」**</font>をTapする

<img width="375" alt="IMG_0002.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/a1624d8f-ec1d-31c8-3b8d-04b5218ba903.png">


<img width="375" alt="IMG_0003.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/9edfaa4c-add4-7110-1513-57ff9f4f1843.png">


![IMG_0004.png](https://qiita-image-store.s3.amazonaws.com/0/93155/7748cedb-fd7a-250f-b9ad-7029388e8bb9.png)

<img width="375" alt="IMG_0005_2.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/816d4658-741d-0b24-44c4-d1bde2d3ff89.png">



<b><font color="HotPink">これで完了 OK</font></b>

これで、アプリを起動することができる。
<img width="375" alt="IMG_0009.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/9e8bfb1f-7cbc-18e0-84fc-99bb9efc35a6.png">

Unity起動OK
<img width="375" alt="IMG_0008.png" src="https://qiita-image-store.s3.amazonaws.com/0/93155/ef38c852-38ce-4819-d24d-b6553c2cf33b.png">
モニタが消えてもMacをスリープさせない設定

Macはデフォルトで一定時間操作がないと省エネのためモニタの電源が切られる。モニタの電源が切れるとMac本体もスリープになるため、その間にバッチ処理やコンパイル、単体テストなどが実行中だと、タスクが止まってしまうといった不都合が生じる。

そうなると作業がはかどらないので、モニタの電源が切れてもMacがスリープしないように設定にしておいたほうがいい。

設定手順は「環境設定」→「省エネルギー」→「電源アダプタ」→「ディスプレイがオフのときにコンピュータを自動でスリープさせない」にチェックを入れる。

<img width="668" alt="省エネルギー.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/d3f17977-5bbb-ca40-6ef6-f179854b8130.png">
Amazon Linux2 + PHP7.1(LTS) の環境を作る

6月にやっとAmazon Linux2の正式リリースがされましたね。
サーバーレスが主流(？)な昨今ですが、業務要件によってはまだまだサーバーが必要なこともあるかと思います。
今回EC2に表題の環境をセットアップしましたので、備忘録として残しておきたいと思います。

## PHP7.1(LTS)のインストール
* httpdをインストール(PHPインストール時に必要)
    * sudo yum install httpd
* リポジトリ登録
    * epel
        * wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
        * sudo rpm -ivh epel-release-latest-7.noarch.rpm
    * remi
        * sudo yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
    * amzn2-coreを無効化(yum install時にこちらを見てしまい、5系を入れようとするので)
        * sudo yum-config-manager --disable amzn2-core
    * remiを有効化
        * sudo yum-config-manager --enable remi
        * sudo yum-config-manager --enable remi-php71
    * PHPをインストール
        * sudo yum install --enablerepo=remi,remi-php71 php
            * (実際にはいろいろextension追加してます)
git diffでよく使うコマンド(随時更新)

#git addする前にdiff
```zsh
git diff
```

#最後のコミットと今の修正点をdiff
```zsh
git diff HEAD
```

#最後のコミットとその前のコミット間のdiff
```zsh
git diff HEAD HEAD^
```

#今ステージされた内容をdiff
```zsh
git diff --cached
```
.NETのキャストについて

SIerならではというか、
経験長いにも関わらず、違いをわかってない方に
多く出会います。
以下だけは理解しておきましょう。

**VB.NET**
CType → 暗黙の型変換が可能、VB時代からの関数
DirectCast → 変換失敗時、InvalidCastExeption発生
TryCast → 変換失敗時、Nothingを返す。
セーフティに変換したいならこれ使っとけばok。

**C#**
() → 変換失敗時、InvalidCastExeption発生
as → 変換失敗時、nullを返す。
セーフティに変換したいならこれ使っとけばok。

**その他**
convert.to〜 →
.NET Frameworkなので
将来的なVB.NETからのC#へのリプレイスなど考慮するならベスト
コマンドライン（シェル）でバイナリをテキストに変換する

バイナリをテキストで出力したい時にツール作ったり探したりしなくてもodコマンドで出力できる

参考：[【 od 】 バイナリ・ファイルの内容を閲覧する](http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230853/?rt=nocnt)

#◆1byte単位で16進数で出力する

###**`od -A n -t x1 -v filename`**
##・アドレスを非表示にする
バイナリの値が欲しいだけなのでアドレス表示されると邪魔なので非表示オプションを指定
`-A n`
##・16進数で表示する
バイナリの値なので16進数で欲しいのでオプションで指定
`-t x1`
##・重複値を*で省略させない
省略されると困るのでさせないようにオプションで指定
`-v`
TerraformによるAWS Certificate Manager(ACM)からの証明書取得とドメイン検証



掲載したコードをみてくださいで終わっても良いのですが、まぁそれではあんまりだと言うことで。
まぁ、Terraformの公式サイトと大差ありませんがコメントは入ってるよと言うくらいです。

**※ 2024-02-18 検証用レコードの登録方法を修正しました**

## 前提
  * ワイルドカードはやりません
  * SANの利用も同様にしません
  * なので、対象はFQDN（サブドメイン付き）1つのみ

## 補足

ワイルドカードの証明書は便利ですが、万が一の場合利用する全サービスに影響が及ぶことを考えれば利用すべきではないと思っています。
特に、ACMのようにマネージドで自動的に更新されるのにワイルドカード証明書を使う必要はないと思います。

セキュリティのために証明書を利用するのに、セキュリティを損ねる運用を採用するのは本末転倒だと思っています。

## 実際のスクリプト

```json

# zone apex domain:サブドメインを含まないものを書く
variable "aws_acm_domain_name" {
  description = "Domain Name"
  default = "example.com"
}
# 取得対象のFQDN（サブドメイン付き）
variable "aws_acm_sub_domain_name" {
  description = "Sub Domain Name"
  default = "ex.example.com"
}
# 検証方法（mailはterraform外部で手作業が必要なので非推奨）
variable "aws_acm_validation_method" {
  description = "validation method"
  default = "DNS"
}
# tagはお好みでどうぞ
variable "aws_acm_env_tag" {
  description = "environment tag"
  default = "sample"
}
# 証明書発行リクエスト
resource "aws_acm_certificate" "cert" {
  domain_name       = "${var.aws_acm_sub_domain_name}"
  validation_method = "${var.aws_acm_validation_method}"

  tags {
    Environment = "${var.aws_acm_env_tag}"
  }

  lifecycle {
    # lifecycleにこれを入れておくのが推奨されています
    create_before_destroy = true
  }
}

# Route53で管理されているドメインの情報を持ってきます
data "aws_route53_zone" "zone" {
  name = "${var.aws_acm_domain_name}"
  private_zone = false
}

# DNSによる検証用レコードの登録
resource "aws_route53_record" "cert_validation" {
  zone_id = "${data.aws_route53_zone.zone.id}"
  for_each = {
    for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
      name   = dvo.resource_record_name
      record = dvo.resource_record_value
      type   = dvo.resource_record_type
    }
  }

  allow_overwrite = true
  name    = each.value.name
  records = [each.value.record]
  type    = each.value.type
  ttl     = 60
}

# 検証
resource "aws_acm_certificate_validation" "cert" {
  certificate_arn = "${aws_acm_certificate.cert.arn}"
  validation_record_fqdns = ["${aws_route53_record.cert_validation.fqdn}"]
}
```

## 利用
certのarnを利用します

```json
  resource "aws_lb_listener" "alb" {
    # snip...
    certificate_arn   = "${aws_acm_certificate_validation.cert.certificate_arn}"
  }
```
MacにScalaの環境構築

## JVMをインストールする


Scalaを動かす環境であるJVMをインストールする。

**JVM をインストールするために、Oracle という企業から配布されている Java SE Development Kit 8 (JDK 8) のインストールを行う。**

[Java SE Development Kit 8 Downloads](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)にアクセスし、ava SE Development Kit の項目の Accept License Agreement と書かれているラジオボタンをクリックするとダウンロードできるようになります。

### JDK8をインストールする
Mac OS X x64ってとこのものをダウンロードします。
<img width="550" alt="スクリーンショット 2018-10-11 00.33.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/222453/57e60405-fbe2-9774-64da-faf758bd5cc6.png">

ダウンロードすると .dmgで終わるファイルが現れるためそれを実行します。
実行することによりさらに .pkgというファイルがあらわれるのでこれを実行しインストールを行います。

```
$ java -version
```
を実行して画像のように表示されればOK！！

<img width="474" alt="スクリーンショット 2018-10-11 00.43.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/222453/89709f47-738a-1dc2-5c7e-2bba1fec7ef8.png">

## パッケージ管理システムとScalaの実行環境をインストールする

### Homebrewをインストールする
Homebrewはインストールされている前提で進めます。

### sbtのインストール

```
$ brew install sbt
```

## sbtを動かす

以下のコマンドを実行して画像のように表示されればOK

```
$ sbt console
```

<img width="550" alt="スクリーンショット 2018-10-11 11.03.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/222453/b08b8c1a-9744-a822-c10d-4905046e8c17.png">
git で指定したブランチ以外を削除する(大量のローカルブランチを特定の物以外削除)

```
git branch | rg -v 'master'| rg -v 'remotes'| xargs git branch -D
```

なんでこんなんが必要になったかというと、改めて git branch -a とかやったらローカルに大量のブランチがあって、しかもマージが終わってたりするせいで多分二度と使わぬやつが大量だったので綺麗にしたくなった次第です。
RipGrep必須。

`rg -v 'hogehoge'`
オプションの「-v」がinvert match。excludeと同じ意味。除外する。hogehoge以外。
上記だと**masterとremotesに一致したブランチ以外**を `git branch -D`しましょうというコマンド。

RipGrepは`rg -v 'hogehoge'`としたときに
hogehogeはもちろん、hogehogehogeやaaaahogehoge、hogehogexxxなども除外対象、つまり部分一致でやってくれます。
重要なのは殺しすぎないということ。大体8割〜9割ぐらい削除できるぜコマンドになるのでうっかり事故は減ります(削除コマンドほど大は小を兼ねると大変な事故になるんで、できるだけ殺さないのが良いですね)。

最後に xargs で実行するだけ。
RipGrepのオプション次第で反転ももちろん可能です。

```
git branch | rg -v 'staging' | rg -v 'master' | rg -v 'remotes'| xargs git branch -D
```

実際に使ったコマンドはこっちです。
僕らはstagingブランチで作業したりここをベースに別ブランチを切ってます。masterをリリースブランチとして運用していますのでstagingってついているものも残したかったという形。
Pythonにおけるif文の長いor列挙の回避方法

```Python
# ifのor列挙は長い
if flag=="apple" or flag=="banana" or flag=="donuts" or flag=="eggnog":
    pass

# リストのin演算子を使えば少しスマート
if flag in ["apple", "banana", "donuts", "eggnog"]:
    pass
```

# 追記
速度を比較しました
[or列挙、リスト、タプル、集合でのif文の速度評価](https://qiita.com/takey/items/15b629a2c442222a68aa)
Google Maps API のAPIキーの取得方法

# 概要
- Google Maps APIの利用方法が変わったので、新しい方法でAPIキーの発行する
- [Google Maps Platformの価格とプラン](https://cloud.google.com/maps-platform/pricing/?hl=ja)

## やったこと
- [GCPのプロジェクト作成](https://www.apps-gcp.com/gcp-startup/)
- 使用するAPIを有効化する
- 認証情報画面でAPIキーに対して許可する

## Map表示用で有効化するAPI
### Maps JavaScript API
- JavaScriptからGoogle Mapを表示する用のAPI

## 呼び出し方
``` html
<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <meta name="viewport" content="initial-scale=1.0">
    <meta charset="utf-8">
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      var map;
      function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: -34.397, lng: 150.644},
          zoom: 8
        });
      }
    </script>
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
    async defer></script>
  </body>
</html>
```
- [Maps JavaScript APIのドキュメント](https://developers.google.com/maps/documentation/javascript/tutorial?hl=ja)

## 設定する制限
- アプリケーションの制限
- APIの制限

```
デフォルトで、API キーは制限されていません。制限されていないキーは、ブラウザ内などから公開されたり、
キーが置かれているデバイスからアクセスされたりする可能性があるため、安全ではありません。
キーを保護するために、制限を追加することをおすすめします。
```

### アプリケーションの制限
- 利用できるアプリケーションを制限する
- ドメインやIPを登録できる

### APIの制限
- 利用できるAPIの種類を制限する


## 参考URL
- [Googleのドキュメント](https://cloud.google.com/docs/authentication/api-keys?hl=ja&visit_id=636748160124911271-1143403935&rd=1)
- [Google Map APIs を使用するためのAPIキー取得と設定方法](https://maps.multisoup.co.jp/blog/2967/)
Alfredで設定をクラウド同期する方法(要Powerpack)

Alfredで設定の複数のMacで共有したり、クラウド上にバックアップを取っておきたいときは、設定の「Advanced」→「Syncing」の「Set preferences folder」ボタンを押して設定の保存先をiCloudやDropboxにしておくと良い。なおこの機能を使うには有償のPowerpackのライセンスを購入しておく必要がある。

<img width="1100" alt="スクリーンショット 2018-10-11 10.29.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/31a261bd-0e77-7a3f-7e78-1f5354c293a0.png">
【メモ】気になる論文リスト

用途：自分用に気になったのを適当に追加していく。ついでに周知してみる。

##金融市場と物理系のブラウン運動、類似の謎を解明　東京工業大学
https://univ-journal.jp/20269/
https://journals.aps.org/prl/pdf/10.1103/PhysRevLett.120.138301
Alfredで計算するなら千の位のカンマを無視する設定にしておいたほうが便利

Alfredは簡単な数式を計算してみることができるが、デフォルトの設定では千の位のカンマがあると計算がされない:

<img width="577" alt="スクリーンショット 2018-10-11 10.07.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/714de6d5-a760-5012-2354-997c93462f15.png">

数値をコピペで扱うときに不便なので、設定の「Features」→「Calculator」→「Ignore thousands grouping separator」にチェックをいれる:

<img width="1100" alt="スクリーンショット 2018-10-11 10.07.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/a2c631e2-34c1-4ce6-d13c-316ab04d56f6.png">

すると千の位にカンマがあってもそれを無視して計算されるようになる:

<img width="577" alt="スクリーンショット 2018-10-11 10.07.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/b9747979-f8df-5f19-9518-311c864fc30a.png">
社内Proxy環境下でSorceTreeからbitbucketにプッシュするときにエラー

# 事象
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138392/16860ecf-5e42-a085-52c5-7bf929c7f028.png)

# 原因
プロトコルが「https」じゃないから
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138392/b1e7cdcf-1e60-4192-bcfc-80c935c03553.png)

# 対処方法
![image.png](https://qiita-image-store.s3.amazonaws.com/0/138392/0feadbde-d51f-d0c8-65ad-2651aeb2f63a.png)

- httpsに変更
- ユーザIDを追加
Nuxtでホットリロードの切り替えについて

Nuxtのインストール時に作成されるpackage.jsonのscripts部分にあるコマンドのうち、

```
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
  },
```

上記の`dev`コマンド、つまり`nuxt`コマンドがホットリロードが有効になる。

逆に`start(nuxt start)`コマンドはプロダクションモードでの起動のため、ホットリロードは無効になっている。
unzipに対応していないパスワードzipを解凍する

普通のパスワードzipは`unzip`で解凍してくれますが、
圧縮の種類によっては以下のようにエラーが出るので、7zを入れてみました。

```shell:terminal
% unzip test.zip
Archive:  test.zip
   skipping: out/hoge.txt  unsupported compression method 99
```

## 前提条件
```shell:terminal
% sw_vers
ProductName:	Mac OS X
ProductVersion:	10.13.6
BuildVersion:	17G65

% brew --version
Homebrew 1.7.7
Homebrew/homebrew-core (git revision 9f5c; last commit 2018-10-10)
Homebrew/homebrew-cask (git revision 232f2c; last commit 2018-10-10)
```

## 7zをインストール
```shell:terminal
% brew install p7zip
```

## 解凍する方法
```shell:terminal
# -pとパスワードの間は空白を開けない
% 7z e -p{パスワード} {zipファイル名}.zip
```

## オプション
`7z`と叩くと見ることができます。

```shell:terminal
% 7z

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,4 CPUs x64)

Usage: 7z <command> [<switches>...] <archive_name> [<file_names>...]
       [<@listfiles...>]

<Commands>
  a : Add files to archive
  b : Benchmark
  d : Delete files from archive
  e : Extract files from archive (without using directory names)
  h : Calculate hash values for files
  i : Show information about supported formats
  l : List contents of archive
  rn : Rename files in archive
  t : Test integrity of archive
  u : Update files to archive
  x : eXtract files with full paths

...
```

## 雑感
変な圧縮形式を使わないに越したことはない。
LTSVをpandasに読み込む

LTSVは主にログファイルの形式として最近好まれているテキストフォーマットです。
http://ltsv.org/
一行一レコード、各セルをタブで区切っているところはTSVと同じなのですが、ヘッダ行に列タイトルを付ける代わりに各セルに直接ラベルをつけた形になっています。

```
host:example.com	url:/api/users	status:200	time:2018-01-01T00:00:00+09:00
host:example.com	url:/api/users	status:200	time:2018-01-01T00:00:01+09:00
```
このような見た目。
人の目にも読みやすく機械的にもパースしやすいのが利点です。
パースしやすさのためにあえて仕様にエスケープを含めていないほど。

さてこのLTSV形式、pandasに読み込み用メソッドが用意されていません。
pandasで処理したいときはどうするか。
ltsvというライブラリも公開されているのですが https://pypi.org/project/ltsv/ そこで何しろパースしやすいのが利点のLTSV形式、特にライブラリを追加しなくてもこんなコードで読み込めてしまいます。

```python
from collections import OrderedDict
import pandas as pd

def ltsv_to_data_frame(filename):
    """
    LTSVファイルを読み込んでpandas DataFrameを生成します
    値はすべて文字列型となります
    """
    with open(filename) as f:
        return pd.DataFrame(
            [OrderedDict(cell.split(':', 1)
                         for cell
                         in line.rstrip('\r\n').split('\t'))
             for line in f])
```

これでは数字データもすべて文字列型になってしまう、それでは困るという場合。
いったんtsvに変換してからそれをpandasに読み込ませるとpandasがよしなに型付けしてくれます。
tsvに変換するには、上記のltsv_to_data_frame関数で作ったDataFrameがそのまま使えますね。

```python
from io import StringIO  # Python2の場合は from cStringIO

tsv = ltsv_to_data_frame(filename).to_csv(sep='\t', index=False)
df = pd.read_table(StringIO(tsv))
```

これで数値データはちゃんと数値型になったDataFrameが得られます。
カレントフォルダにあるCSVをExcelシートに読み込む

# 概要

カレントフォルダに置かれているCSVファイルを、Excelの各シートへ読み込みたい時に書いたマクロ。

## 背景

予め別のマクロを組み込んであるレポーティング用のExcelファイルに、元になるデータをCSVエクスポートしたCSVを読み込ませたかった。

レポーティング周りは他のBIツールとかを使ったほうがいいよねという話はもちろんあるが、すでにあるExcelマクロの資産を使うべきだと思うということで。

そのため、報告用のシートは残しつつ、データの部分だけCSV_という接頭辞をつけた状態で毎回削除し、読み込めるようにしている。

# コード

```visualbasic


Option Explicit


Sub readCsvListToWorksheet()
    Dim newSheet As Worksheet
    Dim sheetName As String
    Dim tmpSheet As Worksheet
    Dim textFile As String
    Dim preFix As String
    preFix = "CSV_"
    ' preFix で始まるシートは全消し
    Application.DisplayAlerts = False 'データの入っているシート削除の警告を一時抑止
    For Each tmpSheet In Worksheets
        If Left(tmpSheet.name, Len(preFix)) = preFix Then
            tmpSheet.Delete
        End If
    Next tmpSheet
    Application.DisplayAlerts = True


    
    ' カレントのCSVファイルを全件読んでいく
    textFile = Dir(ActiveWorkbook.Path & "\*.csv")
    Dim tmp As String
    Do While textFile <> ""
        sheetName = "CSV_" & Left(textFile, 20)
        
        Set newSheet = ActiveWorkbook.Worksheets.Add
        newSheet.name = sheetName
        
        tmp = ActiveWorkbook.Path & "\" & textFile
        Call readCsv(newSheet, newSheet.name, "TEXT;" & tmp)

        
        textFile = Dir()
    Loop
End Sub

Sub readCsv(newSheet As Worksheet, name As String, textFile As String)
    With newSheet.QueryTables.Add( _
        Connection:=textFile, _
        Destination:=Range("$A$1"))
        .name = name
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .TextFilePromptOnRefresh = False
        .TextFilePlatform = 932 'SJISの意味
        .TextFileStartRow = 1
        .TextFileParseType = xlDelimited
        .TextFileTextQualifier = xlTextQualifierDoubleQuote
        .TextFileConsecutiveDelimiter = False
        .TextFileTabDelimiter = True
        .TextFileSemicolonDelimiter = False
        .TextFileCommaDelimiter = True
        .TextFileSpaceDelimiter = False
        .TextFileColumnDataTypes = Array(1, 1, 1, 1, 1, 1, 1, 1)    'CSVのフィールドの分を収める長さで定義しないといけないのでここが汎用的ではない
        .TextFileTrailingMinusNumbers = True
        .Refresh BackgroundQuery:=False
    End With

End Sub
```
Cloud Functions(Python)でコードファイルを分割する

## 概要

Cloud FunctionsでPython(Bata)を利用する場合、関数のエントリーポイントは必ず```main.py``` ファイルである必要があります。


Cloud Functions The Python Runtime
https://cloud.google.com/functions/docs/concepts/python-runtime

>Your function's entrypoint must be contained in a Python source file named main.py.

素直に```main.py``` に関数を追加していくと、きっと肥大化して悲しくなります。

なので、ファイル分割できないか試してみました。


## 実装

デプロイするファイルを準備します。

```sh
> mkdir 任意のディレクトリ
> cd 任意のディレクトリ
> mkdir src
> touch main.py
> touch hoge.py
> touch src/huge.py
```

```python:main.py
from hoge import *
from src.huge import huge_huge

```

```python:hoge.py
from flask import make_response


def hoge_hoge(request):
  return make_response('hoge!', 200)

```

```python:src/huge.py
from flask import make_response


def huge_huge(request):
  return make_response('huge!', 200)

```

はい。
見てのとおりで、```import ファイル名 from *``` とインポートすることで、実現できました。
```import ファイル名 from 関数名``` とすることも可能です。


## 検証

実際にデプロイして実行できるか、試してみます。


```sh:デプロイ
> gcloud functions deploy hoge_hoge --runtime=python37 --trigger-http
> gcloud functions deploy huge_huge --runtime=python37 --trigger-http
```

デプロイできたら実行してみます。

```sh
> gcloud functions call hoge_hoge --data "{}"

executionId: m10cogh13tx8
result: hoge!

> gcloud functions call huge_huge --data "{}"

executionId: 2adly82qzlts
result: huge!
```

やったぜ。
これで、```main.py``` には実装を含めず、エントリーポイントとしての役割に特化させることができます。

まだ試していませんが、おそらくは規模が大きくなった場合、パッケージ化することで、さらにすっきりさせることができそうです。


## 参考

Cloud Functions The Python Runtime
https://cloud.google.com/functions/docs/concepts/python-runtime


簡単なPythonのパッケージを作る方法
https://qiita.com/himenoglyph/items/77f2534bc32eaad494dc
Slackでスレッド駆動分報  (社内チャット活用事例)

## アイディア

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/a76973ea-095d-5de5-c91f-aa0df36a9e66.png)

---

2018年下旬、Slackのスレッド機能がアップデートされた。画像アップロードも出来るようになった。

そこでSlackスレッドを分報に活用してみる。

## やってみた感想

- Twitterと掲示板の中間ぐらいの感覚。フローすぎず、ストックすぎない。
  - 普通の分報とは書き味もかなり変わるし、かなり落ち着いて「自分の学びになること」をまとめられる気がした。
  - かといって何か記事一個を書くより重すぎず、ちょうど良いテンポ、ちょうど良い単位で「流れ」を作っていける感覚。
- 分報はまず「自分が書きやすいこと」「書きたくなること」「自分のスパイクにできること」が一番重要だと思うので、「しっくり来る感」はとても大事。
  - 自分にはなかなか合っている手触りだと感じた。
- 技術関係に限っていうと「技術記事を書くのは敷居が高い」と思うときや「技術記事を書く前段階の、下書き、着想を練ったり、自分の考えをまとめる段階」として、Slack分報のスレッド使うのも良いと思う。
  - ノンスレッドでフラットな投稿をしていくよりも、かなり考えがまとまりやすいように感じた。
  - ( 参考: [エンジニアは全員技術記事を書くことを習慣化した方がいいぞ - Qiita](https://qiita.com/HiromuMasuda0228/items/a71dea7ef4d77a30b118) )

## やり方

- テーマごとに分報にスレッドを作る。
- 書く。

以上。

カテゴリ分けしない投稿は、通常通りノンスレッドで投稿していく。

## 例1. 「エンジニアリング」スレッド

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/cec25afc-ffec-d3ee-f7a0-9b5922035047.png)

## 例2. 「Qiita」スレッド

自分が書いたQiitaの記事 + ひとことを付け足して書く。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/76f2cd4e-1d6c-9263-b1b0-0b6b544ea1f1.png)

## 例3. 「体のこと」スレッド

食事や睡眠、瞑想やヨガなど、体に良さそうなことなら何でも書いていく。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/89618/90dabbb6-b96c-3c4d-bb8a-4a9e4441a65f.png)

## その他の例

### 実装スレッド

今取り掛かっている実装の専用スレッド。

コードや悩みなど、何かを書いていたら、他の人からツッコミやアドバイスを貰えるかもしれない。

### 仕事のことスレッド

一般的な仕事論などについて。

### 趣味スレッド

趣味の単位でスレッドを作ってみても面白いかもしれない。

### 自己紹介スレッド

「自分ってこんなやつだ」的な、取扱説明書がわりになるようなことを書いていったら面白いかもしれない。

他の人から見た付き合いやすさというのは、「自分がどんな人間か、どれだけ伝わっているか」にもかかってくると思うから。

### その他のその他

何でも思いつくままに。

## あわせて読みたい？

- [科学的にも証明された、日記を書き続ける効果と実用的なメリット | ライフハッカー［日本版］](https://www.lifehacker.jp/2014/06/140604journal.html)
- [Slackで簡単に「日報」ならぬ「分報」をチームで実現する3ステップ〜Problemが10分で解決するチャットを作ろう | | Craftsman Software Inc.](http://c16e.com/1511101558/)
- [Slack — 分報を、荒らしちまった悲しみに。(失敗談) - Qiita](https://qiita.com/YumaInaura/items/d4d6adfdf20234d14136)








<!-- Update From Qiita API -->

# チャットメンバー募集


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

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





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
CertificateがIssuerNotReadyのまま進まない


> $ kubectl describe cert

```shell
Name:         hoge.example.com
Namespace:    default
(略)
Events:
  Type     Reason          Age               From          Message
  ----     ------          ----              ----          -------
  Warning  IssuerNotReady  4s (x3 over 16s)  cert-manager  Issuer letsencrypt-prod not ready
```

こういうやつ。待てど暮らせど通らない。

## １．いくつもIssureを放り込んでいる

あちこちの記事を見ながら、kubectl apply -f ....とかやってる間に、どうも複数のIssureが登録されていた。
なんかkubectl describe certした時に対象としてる証明書の名前が変だったので、チュートリアル記事を読みながら作業していたときの残骸が邪魔していた。
同じyamlファイルの中身を書き換えながらapplyしていたのが多分原因。
あらかたkubectl deleteしてまっさらからやり直す。Issure3つくらい登録あってがっかり。。。

## 2.IssureのServerアドレスが間違ってる

Certificateを消しIssureを消し再度投入。

> $ kubectl describe issuer

```shell
Name:         letsencrypt-prod
Namespace:    default
(略)
Spec:
  Acme:
    Dns 01:
      Providers:
        Clouddns:
          Project:  my-project-name
          Service Account Secret Ref:
            Key:   cert-manager-key.json
            Name:  clouddns-service-account
        Name:      prod-dns
    Email:         admin@hoge.example.com
    Http 01:
    Private Key Secret Ref:
      Key:
      Name:  letsencrypt-prod
    Server:  https://acme-v01.api.letsencrypt.org/directory
Status:
  Conditions:
    Last Transition Time:  2018-10-10T22:26:51Z
    Message:               Your ACME server URL is set to a v1 endpoint (https://acme-v01.api.letsencrypt.org/directory). You should update the spec.acme.server field to "https://acme-v02.api.letsencrypt.org/directory"
    Reason:                InvalidConfig
    Status:                False
    Type:                  Ready
Events:                    <none>
```

> Your ACME server URL is set to a v1 endpoint (https://acme-v01.api.letsencrypt.org/directory). You should update the spec.acme.server field to "https://acme-v02.api.letsencrypt.org/directory"

アドレス変えろと言われている。
Server:  https://acme-v01.api.letsencrypt.org/directory
この箇所を指示されているとおりに変更する。

> $ kubectl apply -f certmanager-issuer.yml
> issuer.certmanager.k8s.io "letsencrypt-prod" configured
> 
> $ kubectl describe issuer

```shell
Name:         letsencrypt-prod
Namespace:    default
(略)
Spec:
  Acme:
    Dns 01:
      Providers:
        Clouddns:
          Project:  my-project-name
          Service Account Secret Ref:
            Key:   cert-manager-key.json
            Name:  clouddns-service-account
        Name:      prod-dns
    Email:         admin@hoge.example.com
    Http 01:
    Private Key Secret Ref:
      Key:
      Name:  letsencrypt-prod
    Server:  https://acme-v02.api.letsencrypt.org/directory
Status:
  Acme:
    Uri:  https://acme-v02.api.letsencrypt.org/acme/acct/43637263
  Conditions:
    Last Transition Time:  2018-10-10T22:28:53Z
    Message:               The ACME account was registered with the ACME server
    Reason:                ACMEAccountRegistered
    Status:                True
    Type:                  Ready
Events:                    <none>
```

> ACMEAccountRegistered

通った！
SQLI-LABSでphpがダウンロードされてしまって実行できない問題の解決

[SQLインジェクション体験ツール『SQLI-LABS』で遊ぶ](
https://blog.motikan2010.com/entry/2017/06/11/SQL%E3%82%A4%E3%83%B3%E3%82%B8%E3%82%A7%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E4%BD%93%E9%A8%93%E3%83%84%E3%83%BC%E3%83%AB%E3%80%8ESQLI-LABS%E3%80%8F%E3%81%A7%E9%81%8A%E3%81%B6
)

をnginxで試したところ、PHPファイルがダウンロードされてしまう事象に遭遇したので解決方法をメモ

[HomebrewでNginx + php-fpmの環境を作ろうとしたらPHPファイルがダウンロードされる](https://utano.jp/entry/2016/07/nginx-and-php-fpm-download-php-file/)

上記の記事にもあるが、Chromeのキャッシュがなかなか消えないので注意
どうしたらいいかわからない→セイチョウジャーニー

※個人的には「セイチョウジャーニー」を技術書だと思っています。これからエンジニアになる人、セイチョウの仕方で迷っている人に技術書を読む前に目を通すべく技術書かなあと思います。

# 第一印象「あっ。これって自分のことじゃん。」
もしかしたらこの本を手に取った人からしたら共感できる部分が沢山あったのではないでしょうか。

きっとそれは**著者たちの本音と実体験だけ**が書かれているからだと思います。

特に自分みたいに、やってみたいことがあっても上手く動けてないなあって人にとっては、現在から1年後までの指針になるのでオススメです！

# 人それぞれのセイチョウ論
この本で共通されてる考え方として、「好きなこと続けられる時のセイチョウ」「日々の小さな成功を積み上げていくセイチョウ」がよく出てきました。
普通の指南書や自己啓発本より行動のハードルはかなり低い事項が多いので、実行しやすいです。

# 既にセイチョウジャーニーしちゃってる人からしたら当たり前なことばかり!?
本の中で沢山の共感を得たと同時に、「少なくともゼロ→イチは自分にもできてるんじゃね？」と言う感情も浮かんてきました。

既に
1. Twitterアカウントを作って、気になる人や分野をフォローしている
2. 好きなことを仕事にしようとして、それに向けて努力している
3. 気になるコミュニティ（勉強会）に参加している

となると自分自身はこの本に書いてあるゼロ→イチのセイチョウに関しては少なからず達成できているのではないかと感じました。

しかし、あくまでもゼロ→イチのセイチョウなだけであって、イチ→ニのフェーズの人にとっては「ゼロ→イチが出来たあとはどうやって成長しよう…」と悩み、ゼロ→イチでやってきた事をベースに自走することが次のセイチョウになるのだと思います。

#最後に
結局、色々な体験談をインプットし、自分なりのセイチョウジャーニーを楽しめるかが大事ってことなんですかね。
セイチョウジャーニーに登場する方々は、「自分はこうやってセイチョウできたからみんなにも教えたい！参考にして！」との思いで出展されたのかと思います。

こうやってセイチョウ体験を沢山の人にシェア出来て、成長の輪がどんどん広がっていくのはきっと世の中にとってもプラスに働くし、自分も現状打破(転職)に成功できたタイミングで、セイチョウを発信したい思います！

PDF版は購入できるそうです！
[セイチョウジャーニーPDF版](https://booth.pm/ja/items/1038923)
[PHP] DateTime型のmodifyメソッドでハマった話

# はじめに
`DateTime`型の`modify()`メソッドの認識が不十分だったので自分用メモ。

#コード

```php
$date = new \DateTime('2018-05-31');

echo $date->modify("+1 month")->format("Y-m-d");             // 2018-07-01
echo $date->modify("+2 month")->format("Y-m-d");             // 2018-07-31
echo $date->modify("+3 month")->format("Y-m-d");             // 2018-08-31

echo $date->modify("-1 month")->format("Y-m-d");             // 2018-05-01
echo $date->modify("-2 month")->format("Y-m-d");             // 2018-03-31
echo $date->modify("-3 month")->format("Y-m-d");             // 2018-03-03

echo $date->modify("last day of +1 month")->format("Y-m-d"); // 2018-06-30
echo $date->modify("last day of +2 month")->format("Y-m-d"); // 2018-07-31
echo $date->modify("last day of +3 month")->format("Y-m-d"); // 2018-08-31

echo $date->modify("last day of -1 month")->format("Y-m-d"); // 2018-04-30
echo $date->modify("last day of -2 month")->format("Y-m-d"); // 2018-03-31
echo $date->modify("last day of -3 month")->format("Y-m-d"); // 2018-02-28
```
git-pr-releaseについて


※2021年8月13日にgithubパスワード認証が廃止になったことに伴い、
セットアップ方法が少し変わったので、改めてこちらに記事を書きました。
https://www.fuwamaki.com/article/187


gitを用いてgitflowで開発しているチームで、
リリース時に `develop` -> `master` マージ作業をするとき、
git-pr-releaseを用いると、いい感じのPullRequestを自動で作ってくれます。

## git-pr-releaseのインストール

```
$ gem install git-pr-release
```

※gemは事前にできるようにしておいてください。

## 要注意！！

最新バージョン0.8.0ではgit-pr-releaseが動作しない模様！
https://github.com/motemen/git-pr-release

実行しても、エラーもなにも起きない、という事態が発生します。
バージョン0.6.0で動作問題なく確認できてるので、バージョン指定してインストールしましょう。

```
$ gem install git-pr-release -v "0.6.0"
```

SEO用: 動かない 動作しない コケる

## git-pr-releaseの設定

対象リポジトリに `.git-pr-release` ファイルを作成、下記を記載。
`.git/config` に書いてもいいみたいです。
この場合だと、 `develop` -> `master` へのPullRequestとなります。

```
[pr-release "branch"]
  staging = develop
  production = master
[pr-release]
  template = .git-pr-template
```

## git-pr-templateの作成

PullRequestに記載するテンプレートを作成します。
この手順は必須ではありませんが、テンプレートがあったほうが便利なので記載します。

対象リポジトリに `.git-pr-template` ファイルを作成、下記を記載。

```
Release <%= Time.now.strftime("%Y-%m-%d") %>
<% pull_requests.each do |pr| -%>
<%= pr.to_checklist_item %>
<% end -%>

- - - 

### リリース作業

- [ ] xxx
- [ ] xxx
- [ ] xxx
```

これで、リリースタイトルが **Release 20xx-xx-xx** で、
developにマージされたPullRequestの一覧が載るテンプレートになります。


## git-pr-releaseを実行

```
$ git-pr-release
```

UserIDとPasswordを聞かれたら、GitHubのUserIDとPasswordを入力します。

-> これでいい感じのPullRequestが、いい感じに作れます。

より細かい設定・利用をしたい方は、git-pr-releaseのGitHubを参照。
https://github.com/motemen/git-pr-release
php-master-changes 2018-10-10

今日は autoconf の要求バージョン引き上げ、オブジェクトハンドラ get_properties_for の導入、flexble heredocに関連した字句解析のバグ修正があった！


ところで最近わりと朝の更新が増えてきたので、「今日は」という出だし、嘘もよいところなのではないか
いや気にしないようにしよう

# 2018-10-10
## petk: Bump minimum Autoconf requirement to 2.68
- https://github.com/php/php-src/commit/0b0d4b5f0d5de7d3172e995c34e951790fedafb5
- [7.3~]
- autoconf の要求バージョンを 2.68 へ引き上げ
- 元々 phpize.m4 で 2.59、configure.ac で 2.64 を要求していた
    - が、phpize も中では 2.64 以降のマクロを使っていたりした……
- CentOS 6 は autoconf 2.63 を使うシステムだが、現状で PHP 7.2+ をビルドするにはいずれにせよ 2.68 が必要という[話](https://github.com/php/php-src/pull/3562#issuecomment-424980819)
- autoconf 2.68 は [8 年前にリリースされた](http://lists.gnu.org/archive/html/autotools-announce/2010-09/msg00000.html)バージョン
    - ちなみに最新版 2.69 は [6 年前](http://lists.gnu.org/archive/html/autotools-announce/2012-04/msg00004.html)で、最近のディストリビューションだとわりと 2.69 が入ってる奴
    - [コミット自体は入ってる](http://git.savannah.gnu.org/gitweb/?p=autoconf.git)ので、リリース作業の時間は取れないけど死んでるというわけではない、という感じなのかな

## petk: [ci skip] Update UPGRADING about Autoconf version
- https://github.com/php/php-src/commit/1386b029f9834d9e77a644c58fc1d50006a82e67
- [7.3~]
- ↑の UPGRADING への追記

## nikic: Introduce get_properties_for() handler
- https://github.com/php/php-src/commit/7ec8087f8097955bfc6b97d1a916c6ffc39908f4
- オブジェクトハンドラ get_properties_for() を追加
- 配列へのキャストやシリアライズといった用途フラグを渡すと、オブジェクトのハッシュテーブルを適切に取ってくる
- [PR:3579](https://github.com/php/php-src/pull/3579) から経緯が追える
- 型付プロパティを念頭に、可視性チェックの最適化で prop_info を効率的に見つける機構、という [PR:3573](https://github.com/php/php-src/pull/3573) が別にあった
- そっちで [ArrayObject のテストがこけるという問題](https://github.com/php/php-src/pull/3573#issuecomment-426789181)が出た
- ArrayObject が master でなんかバグいぞ、というので [PR:3574](https://github.com/php/php-src/pull/3574) が出て、その中で「必要なのは用途フラグ取れて部分的に挙動をオーバーライドできる get_properties_for() だ！」となり、 PR:3579 が別立てされマージされた形

## nikic: Migrate ext/date to get_properties_for where appropriate
- https://github.com/php/php-src/commit/1270e5008a1828863a7f96873dff002680eac5c5
- ext/date で get_properties_for を使うよう修正
- DateTime を var_dump() したりするとアクセスできるプロパティが増えるという [#75232](https://bugs.php.net/bug.php?id=75232) が修正されている

## nikic: Don't overload get_properties for ArrayObject
- https://github.com/php/php-src/commit/a5fa51afbbd87bedeb1c5fd7c9a6cf3c971ab14c
- ext/spl の ArrayObject で get_properties_for を使うよう修正

## nikic: Add UPGRADING notes
- https://github.com/php/php-src/commit/5a679341b8ffe049916edb1dae196a847a4edb1d
- ↑の get_properties_for 関連の修正内容を UPGRADING へ追記

## nikic: Specify timezone in test
- https://github.com/php/php-src/commit/4f4d0eccafedfc454b9af1d2e8411aabfccfe318
- [先の ext/data の修正](#nikic-migrate-extdate-to-get_properties_for-where-appropriate)で [#75232](https://bugs.php.net/bug.php?id=75232) を直した際にテストでタイムゾーンを指定していなかったのを修正

## nikic: Fixed bug [#76991](https://bugs.php.net/bug.php?id=76991)
- https://github.com/php/php-src/commit/01948f20b8ae8eed252177f63bf2c9c11a8f1b94
- [7.3~]
- [flexble heredoc](https://wiki.php.net/rfc/flexible_heredoc_nowdoc_syntaxes) 関連のバグで、字句を変な位置で切ってしまう問題の修正
MessagingAPIの新機能、LIFFアプリのデバッグ方法

最近LINE BOOT AWARDの応募が終わりましたね。今回私もアプリを応募させていただきました。その際、せっかくなので6月に登場したLIFFを使ってアプリを作ってみました。

しかしながら2018/10/11 現状、PCの開発環境でLIFFをデバッグする良いツールがありませんので、いろいろとやり方を模索しました。

時間がない中やったのでもしかしたらもっと良い手法があるかもしれません。よい方法知ってる方いらっしゃれば教えていただけると幸いです！

# LIFFとは
非常にざっくり言えば、「LINEのメッセージ画面上に表示できるブラウザ」。通常のブラウザとの違いとして、
戻る、進む、アドレス表示などの機能がなく、簡易的な構造になっています。代わりに、 **画面切り替えがいらず、LINEのメッセージ画面を見ながらアプリを動かせる**、**アプリ上のjavascript等で生成したデータをメッセージとして送れる**という点が特徴です。

LIFFの使い方は以下公式ページがわかりやすいので、この記事では補足的な情報だけ載せることにします。
[Messaging APIの新機能LIFFの使い方を解説します。 : LINE Engineering Blog](https://engineering.linecorp.com/ja/blog/detail/299)

# 開発環境にLIFFからアクセスする
まずは、開発環境で立ち上げたサーバーにアクセスしたいです。とはいえ、`http://localhost`は登録できません。登録しようとすると`{"message":"Non https url"}`というエラーがでます。こんなときはngrokを使うとhttpsでサーバーにアクセスできます。

### ngrokのインストール
ngrokはこちらを参考にインストールします。
https://ngrok.com/download

1. macの場合、以下リンクでngrokをダウンロード
$ curl https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip
2. zipを展開します。
$ unzip /path/to/ngrok.zip
3. 出てきたngrokにpathを通します。
$ mv ngrok ~/path/to/bin

### LIFFからサーバーにアクセス
まずローカルでサーバーの立ち上げ。例としてRailsを使います。
$ bin/rails s

railsはデフォルトだと`http://localhost:3000`でアクセスできます。そこで以下コマンド。
$ ngrok http 3000
すると、図のようにngrokがhttpsのURLを作ってくれます。これでLIFFに登録できますね。

![ngrok.png](https://qiita-image-store.s3.amazonaws.com/0/30677/4a6501ba-a0da-31a1-05c4-2070bd6c3ad5.png)


LIFFにURLを登録します。

```
curl -XPOST \
-H "Authorization: Bearer <Access Token>" \
-H "Content-Type: application/json" \
-d '{
    "view": {
        "type": "tall",
        "url": "<先程のURL>"
    }
}' \
https://api.line.me/liff/v1/apps

```

これでローカルのサーバーを修正して、即LIFFで確認できるようになりました！


# javascriptでliffのデバッグ
liff上ではjavascriptで機能作成をしました。liffではsendmessage()でliffアプリ上でメッセージ送信ができ、これを利用したいのですが、スマホのLINE上でしか動作確認できません。
毎回スマホのLINEで確認するのも時間的コストがかかるので、PC上で開発を完結させたいです。今回は単純にuserAgentで分岐させます。

## liffアプリでユーザーIDを取り出す
今回のアプリではユーザーアカウントごとに日記を読み書きする方式にしたかったので、LIFFアプリ初期化時にアカウント情報、すなわちuserIdを取り出します。

LIFFアプリはnavigator.userAgentに「Line」が含まれているので、以下のようにしてPC上mock処理とLIFFアプリ上処理を使い分けます。以下、雑なコードで失礼します。

```js
$(window).on('load', function(){

  if (navigator.userAgent.indexOf("Line") !== -1) {

    // liffアプリ処理
    liff.init(function (data) {
      var userId = data.context.userId;
      yourProcess(userId);
    }, function(error) {
      window.alert(error);
    });

  } else {

    // PC上の処理
    var userId = '<自分のuserId>'
    yourProcess(userId);
  }
});
```

※自分のuserIdはLINE Developersのアプリのチャンネル基本設定の、その他＞Your user IDから確認できます。

## liffアプリのメッセージ送信をする
`liff.sendMessages()`でメッセージ送信ができます。こちらも同様です。

```js
if (navigator.userAgent.indexOf("Line") !== -1) {

  // liffアプリ処理
  liff.sendMessages([
    {
      type: 'text',
      text: '<メッセージ>'
    }
  ]).then(function () {
    liff.closeWindow();
  });

} else {
  // PC上の処理
  console.log('complete sending')
}
```
Angular6+firebaseでチャットアプリを作ってみた

# はじめに
Qiita初投稿です。
Webエンジニアになっていながら、jQueryとほんの少しだけ趣味でAngularJSを使っただけという状態でした。
なので、知識のアップデートがてらAngular 6でこんなものを作ってみました。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/Angular6?src=hash&amp;ref_src=twsrc%5Etfw">#Angular6</a> + <a href="https://twitter.com/hashtag/bootstrap4?src=hash&amp;ref_src=twsrc%5Etfw">#bootstrap4</a> + <a href="https://twitter.com/hashtag/firebase?src=hash&amp;ref_src=twsrc%5Etfw">#firebase</a> でチャットアプリが出来て自己満に浸りたいので初投稿です <a href="https://t.co/87tGVv3mbD">pic.twitter.com/87tGVv3mbD</a></p>&mdash; roottool (@roottool) <a href="https://twitter.com/roottool/status/1049659908654796806?ref_src=twsrc%5Etfw">2018年10月9日</a></blockquote>

## レポジトリ
使用者を友達だけに限定したいので、サンプルはありません。ごめんなさい。
作成したプロジェクトのソース全文を、以下のレポジトリに展開しています。
https://github.com/roottool/OrgaSound

## 作成したアプリの仕様
- レスポンシブデザインによるマルチデバイス対応
- チャットルームへの入室は認証を必要とする
- ユーザーはメッセージの発信のみを可能とする
- チャットメッセージはリアルタイムで他の端末に反映される
- 音声ファイル名をメッセージとして発信すると、チャットルーム内にいる全員に対してファイルを再生する

このWebアプリはAngular 4で作成されている[BaseChat](https://github.com/wesdoyle/base-chat)を基に、Angular 6で作成したものとなっています。
参考文献に作成者が解説しているYoutubeの動画リンクを記載していますので、ご覧下さい。(※英語です)

## 開発環境
- Windows10 Pro 64bit
- Visual Studio Code
- Node.js：v8.12.0
- @angular/cli：v6.2.2
- firebase-tools：v5.0.1

## 使用したライブラリ
- @angular/material：v6.4.7
- @angular/cdk：v6.4.7
- @angular/animations：v6.1.9
- bootstrap：v4.1.3
- firebase：v5.5.0
- angularfire2：v5.0.1

# トピック
参考文献に記載した「[Angular+Firebaseでチャットアプリを作る](https://qiita.com/Yamamoto0525/items/a76ea4b3924eeb82b0f9)」に、チャットアプリ作成の手順が既に記載されています。
ですので、そこには載っていないけれども今回実装した以下の点に絞って書こうと思います。

- [Angular Materialのsidenavを実装](https://qiita.com/roottool/items/37aaf477e2dd9b99815f)
- [firebase storageから音声ファイルをダウンロードして再生](https://qiita.com/roottool/items/b522f403fcb9eb2f7320)

# 参考文献
- [Angular+Firebaseでチャットアプリを作る](https://qiita.com/Yamamoto0525/items/a76ea4b3924eeb82b0f9)
- [Angular Firebase Chat Tutorial - Part 1](https://www.youtube.com/watch?v=-j0LVc-zLh0)
- [Angular Material - Get started](https://material.angular.io/guide/getting-started)
このメソッドどこ？処理内容は？となったときに　Search In This Folder　Ruby on Rails チュートリアル

AWSでやっています。

Railsチュートリアルをやっていると、メソッドがたくさん出てきます。

たくさんありすぎて、どのメソッドをどこで宣言したのか(def)忘れてしまいます。

そこで、このファイルだっけ？あのファイルだっけ？と全てのファイルを探していました。

###便利な探し方があります！

"Serch In This Folder"

です。

たとえば、いま、作業しているフォルダが sample_app
だとします。

そしたら、sample_app フォルダの上で右クリックをします。


![2018-10-11.png](https://qiita-image-store.s3.amazonaws.com/0/253014/895e7657-d308-8d16-3eb5-586b54d381fe.png)

すると、Serch In This Folder

があると思うのでクリックします。

あとは

Find

というボタンが出てくるとおもうので

Findの　左側にある検索窓に探したい言葉を入力してFindボタンをクリックします。

後は、その言葉がフォルダ内に存在すれば、検索結果が出てくると検索結果をクリックすれば、ファイルが開きます。

その後は、メソッド内容を確認するといいと思います。

def 検索したい言葉

で検索すれば、メソッドの処理内容は簡単に見つけられると思います。
Xcode10で"Command CompileAssetCatalog failed with a nonzero exit code"が出た時の対処法

# 結論
Xcode10で`Command CompileAssetCatalog failed with a nonzero exit code`が起こってビルドできない場合、xcassetsのwarningを修正することでビルドできるようになります。

# やったこと
![スクリーンショット 2018-10-11 8.02.31.png](https://qiita-image-store.s3.amazonaws.com/0/62305/760a1ca9-bab2-b16a-cdd7-f196d592fbb2.png)
スクリーンショットはtvOSアプリのものですが、いくつかのリソースにwarningが出ていることがわかります。
これらのwarningを修正することによってビルドができるようになりました。
Google AppEngine standard environment 2nd generation for PHP で環境の違いを判別する

# 目的

現在コードが **本番** / **開発環境** / **Unit Test** のうち、どの環境で実行されてるか実行時に知りたい。

# 環境

* 本番
 * Google AppEngine
* 開発環境
 * nginx + php-fpm
* Unit Test
 * phpunit 

# 解決方法

それぞれの環境に識別用の環境変数を定義して、それを参照します。

# 環境変数の定義方法

## 本番 (Google AppEngine)

`app.yaml` で環境変数を設定できます。

```yaml:app.yaml
env_variables:
  SERVER_ENV: prod
```

## 開発環境 (Docker)

下記は `nginx` の設定ファイル `default.conf (でなくても良いけど)` の要約です。

```sh:default.conf
location ~ \.php$ {
    # ↓ サーバプロセスの環境変数を設定する
    fastcgi_param SERVER_ENV dev;
}
```

## Unit Test (phpunit)

phpunit.xmlで環境変数を設定できます。

```xml:phpunit.xml
<phpunit bootstrap="bootstrap.php" >
    <php>
       <env name="SERVER_ENV" value="test" />
    </php>
</phpunit>
```

## おまけ (PHP built-in server)

```sh
SERVER_ENV=dev php -S localhost:8080 -t public
```

built-in server は `$_SERVER` に環境変数を import しないので参照時に注意が必要です。

併せて参照: [PHPのビルトインサーバでは、環境変数を$_SERVERから読み出せない](https://qiita.com/tkykmw/items/0d2761852f1afa449998)

# 判定コード

上記のように環境変数を設定しておけば php 側では、下記のように取得できます。

```php
// 下記3つのいずれでも取得できます
echo $_SERVER['SERVER_ENV'];
echo $_ENV['SERVER_ENV'];
echo getenv('SERVER_ENV');
```

関数にするとこんな感じ。

```php
function getEnvName(): string
{
  $serverEnv = getenv('SERVER_ENV');
  switch ($serverEnv) {
    case 'prod':
    case 'dev':
    case 'test':
      break;
    default:
      $serverEnv = 'unknown';
      break;
  }
  return $serverEnv;
}
```
TabBarItemを押下してViewのトップへ移動する機能の実装方法

よくInstagramやFacebookで実装されている、TabBarItemを押すとページの最上部までスクロールできる機能。

意外と実装方法に関する情報が少なく、特に日本語での記事が皆無に近かったので記録として残します。

# 実装
今回は**Collection View**を使用した時に参考になる例を扱います。同じく*Table View*でも少しいじるだけで実装できるはずです。

``` swift:ViewController.swift
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UITabBarControllerDelegate {

 @IBOutlet weak var collectionView: UICollectionView!

 var canScrollToTop: Bool = false

 override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.delegate = self
        collectionView.dataSource = self
 }

 override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        self.tabBarController?.delegate = self
        canScrollToTop = true
 }

 override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        canScrollToTop = false
 }

 // TabBarItemが押下された時に呼ばれる
 func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {

        // 呼ばれたTabBarItemの番号(0, 1,..)
        let tabBarIndex = tabBarController.selectedIndex
        // 一応確認する
        print(tabBarIndex)

        if tabBarIndex == 0 && canScrollToTop {

            // 一番上に移動
            self.collectionView.setContentOffset(CGPoint.zero, animated: true)
        }
 }
}
```

#ポイント
### `canScrollToTop`の設置
一度目のdidSelectで受け取った押下アクションはTabを切り替える時に発動されるので、二度目のアクションでViewのトップへスクロールしたい。
そんな時に、`canScrollToTop`を`func viewWillAppear`で`true` 、`func viewWillDisappear` で`false`にすることで任意のTabBar上にいるときのみ`didSelect`を呼べます。

### 複数のタブ上でViewを動かしたいときの`self.tabBarController?.delegate = self`の位置
``` swift
self.tabBarController?.delegate = self
```
これを`viewDidLoad()`でなく、各ViewControllerの`viewWillAppear`の中で呼ぶことによって、VCごとの要素を使ったアクションを実装することが可能です。

#終わりに
`UITabBarController`や`UITabBarControllerDelegate`を使用してTabBarが押された時のアクションを追加する方法もいくつか見かけましたが、ViewControllerごとのCollection Viewだったりを使用したかったので今回の実装方法が一番しっくりきました。

他に良い方法があれば是非教えてください！

#参考元
https://stackoverflow.com/questions/22392151/tap-tab-bar-to-scroll-to-top-of-uitableviewcontroller
Androidのアニメーション(画像複数)

アニメーション効果

![多数画像のアニメーション効果.gif](https://qiita-image-store.s3.amazonaws.com/0/296847/57342017-0ba5-2f34-04e8-5651b012f2bd.gif)

１、アニメーションの画像を用意して、drawableに追加
自分は手書きの１２３、、、９までの数字を用意しました。


２、アニメーションのanimation-listをdrawableに追加（R.drawable.animation）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/296847/934de398-c6e4-9f98-a8a4-8ceecac094c0.png)


３、ImageViewとanimationDrawableの初期化

        //ImageView　初期化
        animationImage = (ImageView)findViewById(R.id.image);
        //AnimationDrawable　初期化
        animationDrawable = (AnimationDrawable)getResources().getDrawable(R.drawable.animation,null);
        //animationImage　背景
        animationImage.setBackground(animationDrawable);

４、開始ボタンと終了ボタンの挙動

    public void startAnimation(View view) {
        animationDrawable.start();
    }

    public void stopAnimation(View view) {
        if(animationDrawable.isRunning()){
            animationDrawable.stop();
        }
    }

サンプルコード

https://github.com/YanHengGo/android/tree/master/animation
google appengine 2nd generation でスタティックファイルをルーティングする

Google AppEngine 2nd generation for php では front controller 式になったので、 app.yaml でのルーティング方法がいろいろ変更になっています。

リファレンスは [app.yaml Configuration File](https://cloud.google.com/appengine/docs/standard/php7/config/appref) ですが、スタティックファイルへのルーティングと `script` の両立に絞ったシンプルケースは以下の `app.yaml` になります。

以下ではスタティックファイルとして `favicon.ico` を指定しています。

```yaml:app.yaml
runtime: php72
entrypoint: serve public/index.php # ★ entryポイントを指定
service: default

handlers:
- url: /favicon\.ico
  static_files: static/favicon.ico
  upload: static/favicon\.ico
- url: .*
  script: auto # ★ script = auto を指定
```

# 勘所

`entrypoint` ディレクトリが追加になった為に目を引きますが、肝は `script: auto` です。

```yaml
- url: .*
  script: auto
```

# エントリーポイントの指定

エントリーポイントは `entrypoint` で指定できますが、 `index.php` もしくは `public/index.php` であれば指定する必要はないです。

指定して損はないので明示しておくと良いと思いますけど。

# 参考

* [GAE/SE PHP 5.5環境と7.2環境のapp.yamlの違い](https://qiita.com/hnw/items/debbac04674cd7fbe869)

私はこの記事を読んでいながら同じ轍を踏みました。斜め読みせずにきちんと読むことが大事です。

[リファレンス](https://cloud.google.com/appengine/docs/standard/php7/config/appref) は網羅的だから、通して読むのも辛いし、あまり記憶に残らないんだよね。リファレンスというのはそういうものではないし。
JWTについてまとめたい

## なぜやるの?
私はチーム開発をやっている.そこでJWTを使って認証を行うことになった
JWTを触ってることが多いのでまとめたい
## どうやるの?
- JWTとは?
- JWTの構造
- JWTが有効だと考えられる場所

## JWTとは?
jwtはjson web tokenの略で読み方はジョットと読むらしい
認証情報を持ったJSONをbase64urlencodeで送受信するtokenのことで
署名を付けることによりtokenが改ざんされているのかされていないのかをチェックすることができる.

```console
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidGVzdCIsImFkbWluIjp0cnVlLCJleHAiOjE1MzkxOTQ3MTZ9.b6uuYw5ZA-LEfcpkerobCVm5aXSBv88iID4k-HesieA
```
jwtは上のようになっていて
ピリオドで区切ることができる

## JWTの構造
ヘッダー,ペイロード,シグネチャに分かれる

### ヘッダー部分
```console
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
```
base64urlencodeされている
デコードすると
以下のようになる

```console
{"alg":"HS256","typ":"JWT"}
```
algはシグネチャでどのアルゴリズムを使うかを宣言している
この場合はhmacsha256を使うことがわかる
tyopeはJWTであることを表している

### ペイロード部分

```console
eyJuYW1lIjoidGVzdCIsImFkbWluIjp0cnVlLCJleHAiOjE1MzkxOTQ3MTZ9
```
ヘッダと同じようにデコードすると

```console
{"name":"test","admin":true,"exp":1539194716}
```
ここはまぁ...自由に定義することができる
expは有効期限を表している
### シグネチャ部分
```console
b6uuYw5ZA-LEfcpkerobCVm5aXSBv88iID4k-HesieA
```
シグネチャは検証部分に使われる.
このシグネチャ部分は以下のように求められる

```console
ハッシュ関数(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
```
今回ハッシュ関数はHMACSHA256になっている

## JWTが有効だと考えられる場所
これの役立つところはSSOみたいにサービス間の認証が容易であるということである
マイクロサービスで構築している認証に関してはsessionよりも楽にセキュリティを担保することができるだろう

## まとめ
マイクロサービスをやりたいときはとても有効だと考える
なぜならサーバにtokenを持たなくていいのでどこのでスケールしたあとも管理が楽というメリットがあると考える

ありがとうございました
PythonをWindowsにインストールする

PythonのディストリビューションとしてよくAnacondaのインストール手順が解説されていますが、なるべく最小構成として開発環境を整えることを想定し、Python（およびPythonのパッケージ管理ツールpipなどの基本的なツール群）をインストールする手順を記載します。

導入環境

* Windows 7 (SP1) Ultima x64

## Pythonのインストーラーをダウンロードする

以下のPythonのダウンロードページにジャンプします。  
[https://www.python.org/downloads/](https://www.python.org/downloads/)

ここでは、Pythonのバージョン等を確認した上でダウンロードしたいので、画面の赤枠のWindowsをクリックします。

![python_dl1.png](https://qiita-image-store.s3.amazonaws.com/0/299676/8e6f3236-5e41-29d4-6e60-e9850bee350f.png)

2018年10月のPythonの最新バージョンは3.7.0で、ライブラリ等の互換性を考慮し、今回は32bit版をダウンロードします。また、個人的にはWebインストーラがあまり好きではないので、通常のインストーラとして、画面の赤枠をクリックしてインストーラをダウンロードします。

![python_dl2.png](https://qiita-image-store.s3.amazonaws.com/0/299676/95f71aa7-1c72-92ac-a277-a126c0ee8831.png)

![python_dl3.png](https://qiita-image-store.s3.amazonaws.com/0/299676/7e8afea2-bc37-5d3f-6eb5-b48140c29dc6.png)

ダウンロードしたインストーラpython-3.7.0.exeをダブルクリックして起動しウィザードを表示させます。  
Windows版のPythonは複数バージョンのインストールと管理に対応しているため、PATHを通さない方がよいので、下部のAdd_Python 3.7 PATHのチェックをはずします（デフォルトでチェックは付いていませんが・・・）

>とはいってもPATHを通したほうが使い勝手が良い場合もあるので、インストール後のPATHの通し方を後ほど簡単に記載します。

設定を確認してからインストールしたいので、Customize installationを選択します。

![python_install1.png](https://qiita-image-store.s3.amazonaws.com/0/299676/a1b1f0ed-a40f-116b-218f-129943bb9bf7.png)

ここでは特に設定を変える必要はないので、そのままNextをクリックします。  
 (※因みに、pipがPythonのパッケージ管理ツールです。また、py launcherにより、複数のPythonのバージョンを管理することができます。）

![python_install2.png](https://qiita-image-store.s3.amazonaws.com/0/299676/d541f99b-ca6b-c862-2c5b-41b25c8d9481.png)

ここでもチェックボックス欄は特に設定を変える必要はありませんが、このままではインストール先がユーザーフォルダの奥深くになってしまうので、インストール先のみ変更することにします。

>因みに、バージョン3.6までのデフォルトインストール先は、C:\Program Filesに（Windowsが64ビット版の場合は）(Program Files (x86)に)となります。

![python_install3-1.png](https://qiita-image-store.s3.amazonaws.com/0/299676/6d24695f-ab82-fc21-f318-aeac40de83be.png)

Pythonのインストール先はお好みでよいのですが、ここでは、Cドライブ直下にbinフォルダを作成し、そのフォルダにインストールすることにします。  
インストール先を設定したあとは、Installボタンをクリックします。

![python_install3-2.png](https://qiita-image-store.s3.amazonaws.com/0/299676/728c94cd-f03f-52a3-5f9f-36d5abb13b2a.png)

Pythonをインストール中ですので、暫く待ちます。

![python_install4.png](https://qiita-image-store.s3.amazonaws.com/0/299676/030f728b-4e9a-6d1a-5e78-55ece69c8017.png)

PythonがインストールされましたのでCloseボタンをクリックします。

![python_install5.png](https://qiita-image-store.s3.amazonaws.com/0/299676/9da91750-57a9-95ca-2aaa-97c78db70978.png)

## Pythonの実行を確認する

Pythonの実行とバージョンの確認をします。コマンドプロンプトを立ち上げて、次のように入力します。

```console
py -V
```

または

```console
py --version
```

と入力すると、Python 3.7.0と表示されます。  

---

因みに、PATHの通し方ですが、システムのプロパティを開き、詳細設定タブの環境変数ボタンをクリック、開いたウィンドウのシステム環境変数で「Path」の項目を探し、以下文字列（Python実行環境へのパス2箇所）を最後部に付け加えてください。

>以下の最初の;（セミコロン）は前のPATHの最後を表す区切り文字です。

```text
;C:\bin\Python\Python37-32;C:\bin\Python\Python37-32\Scripts
```

PATHを付け加えてウインドウを閉じた後、新しくコマンドプロンプトを開き、pythonコマンドを入力します。

```console
python -V
```

すると、Python 3.7.0と表示されます。  

---

余談ですが、Pythonのバージョンを指定して実行する場合(3.7を実行する場合)は、次のように記述します。

```console
py -3.7 -V
```

すると同じく、Python 3.7.0と表示されます。
Alfred: Force Keybordで入力が英語になるようにしておくとアプリの起動が捗る

Alfredはすばやくアプリを起動したりするのに便利なツールだが、入力ソースが日本語になっていると、アプリ名が補完されなかったりとストレスがある。

この悩みは設定でAlfredを開いたときに、入力ソースが英語に切り替わるようにしておくことで解消できる。

<img width="1100" alt="スクリーンショット 2018-10-11 2.36.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/cf070504-340a-eb6a-22cd-4e5661c5f21c.png">
【Tips】Podで管理されている特定ライブラリのSwiftバージョンを指定する方法

# はじめに
Podで管理しているライブラリのSwiftバージョンを指定したいライブラリがある場合の対応方法になります。

# 特定のライブラリのSwiftバージョンを指定する場合
**Test4**のライブラリのSwiftバージョンを4.0に指定する例

```Podfile
# platform :ios, '11.4'
inhibit_all_warnings!

target 'SampleProject' do
  use_frameworks!
  pod 'Test'
  pod 'Test2'
  pod 'Test3'
  pod 'Test4'
end

post_install do |installer|
  swift4_pods = ["Test4"]
  installer.pods_project.targets.each do |target|
    if swift4_pods.include?(target.name)
        target.build_configurations.each do |config|
            config.build_settings['SWIFT_VERSION'] = '4.0'
        end
    end
  end
end

```

# 全ライブラリのSwiftバージョンを指定する場合
```Podfile
# platform :ios, '11.4'
inhibit_all_warnings!

target 'SampleProject' do
  use_frameworks!
  pod 'Test'
  pod 'Test2'
  pod 'Test3'
  pod 'Test4'
end

post_install do |installer|
  swift4_pods = ["Test4"]
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
        config.build_settings['SWIFT_VERSION'] = '4.0'
    end
  end
end

```