OmniAICreator/Qiita-1.07M huggingface dataset:
畳み込みニューラルネットワークの学習メモ

# はじめに
深層学習のCNN（**畳み込みニューラルネットワーク**）を学習したので、素人なりに理解したことをメモに残します。

# 参考サイト
これらのサイトを参考にしました。アニメーションでの図解がとても参考になりました。

- [畳み込みニューラルネットワークの仕組み](https://postd.cc/how-do-convolutional-neural-networks-work/)
- [高卒でもわかる機械学習 (7) 畳み込みニューラルネット その1](http://hokuts.com/2016/12/13/cnn1/)
- [定番のConvolutional Neural Networkをゼロから理解する](https://deepage.net/deep_learning/2016/11/07/convolutional_neural_network.html)
- [Standford wiki / Convolution schematic.gif](http://deeplearning.stanford.edu/wiki/index.php/File:Convolution_schematic.gif)
- [深層学習 第6章 畳込みニューラルネット](https://qiita.com/t_niimura/items/423468de4dc1e0fca8f4)


# 画像から物体を認識したい

ピクセル画像から物体を識別・認識したい！というニーズは昔からあります。
例えば、

- 紙資料を撮影した画像から、文字を認識したい
- 楽譜を撮影した画像から、音符を認識したい
- ドライブレコーダーの映像から、障害物を認識したい

みたいなヤツです。
このようなニーズに応えるのがCNNです。

# どうやって物体を認識するのか？

以下のような処理で、特徴を強調します！！

- 畳み込み ：フィルタをかけて特徴を強調します
- プーリング ：リサイズしてノイズを間引きます

特徴を強調することで、物体の認識がしやすくなります。（間違っていたらすみません）


# 畳み込みとは？

CNNは**Convolutional neural network**の略で、Convolutionalの日本語訳が**畳み込み**です。
**フィルタをかけて特徴を強調する**処理のことを畳み込みと呼びます。
こちらのアニメーションがわかりやすいです。

![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/221845/3cb12b21-859a-9311-2ae6-756928211910.gif)

引用：[Standford wiki / Convolution schematic.gif](http://deeplearning.stanford.edu/wiki/index.php/File:Convolution_schematic.gif)


畳み込み前は、解像度が5x5の白黒画像です。

```math
\begin{align}
  畳み込み前 = \left(
    \begin{array}{ccc}
      1 & 1 & 1 & 0 & 0 \\
      0 & 1 & 1 & 1 & 0 \\
      0 & 0 & 1 & 1 & 1 \\
      0 & 0 & 1 & 1 & 0 \\
      0 & 1 & 1 & 0 & 0 \\
    \end{array}
  \right)
\end{align}
```

フィルタは3x3で、こんな感じです。


```math
\begin{align}
  フィルタ = \left(
    \begin{array}{ccc}
      1 & 0 & 1 \\
      0 & 1 & 0 \\
      1 & 0 & 1
    \end{array}
  \right)
\end{align}
```

フィルタをかけると、こんな風に3x3のデータが生成されます。


```math
\begin{align}
  畳み込み後 = \left(
    \begin{array}{ccc}
      4 & 3 & 4 \\
      2 & 4 & 3 \\
      2 & 3 & 4
    \end{array}
  \right)
\end{align}
```

`4` のように値が大きいところは、特徴が強いところで、`2`のように値が小さいところは特徴が弱いところとみなします。

このように特徴を強調するのが、畳み込みです。

ただ、この方法だと、解像度が5x5から3x3に落ちてしまい、外側のデータが欠落していってしまうという問題があります。




# パディング

単純に畳み込みをすると、外周のピクセルが欠落してしまうので、元画像の外側に１ピクセル分の**余白（パディング）**をつけることで、この問題を回避します。パディングは**余白**という意味です。

余白の値を0で埋めるのが**ゼロパディング**です。ただし、画像データの場合、0は**黒**という意味を持ってしまうので、明暗を重視するフィルタとの相性は悪いです。

そのため、余白を0ではなくそれっぽい値で埋める手法がいくつかあるようです。



# ストライド

ストライドとは直訳すると**歩幅**です。
今まではフィルタを１ピクセル間隔でかけていきました。これはストライドが１です。
フィルタを２ピクセル間隔でかけていけば、ストライドが２になります。


# プーリング

プールは**貯める**とか**残す**みたいな意味です。
元画像の解像度が大きいと、ノイズも多くなります。
特徴を残しつつ、縮小リサイズして解像度を減らすのが**プーリング**です。（間違っていたらすみません）

リサイズ手法として

- 周辺ピクセルの最大値を採用する。
- 周辺ピクセルの平均値を採用する。

等の様々な手法があります。


# さいごに

間違いが多々ある気がします。ご指摘いただけますと嬉しいです。
【iOS】RemotePush通知の仕組みが知りたいときに読む公式ドキュメント

# 公式ドキュメント一覧
## [APNs Overview](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1)

APNsの仕組みが知りたいときに読む記事。実際にどのようなフローでコネクション立てているかとか、証明書のやりとりしているかも図解してあるので、かなりわかりやすかった。プロバイダー（サーバー側）でやるべきことも書いてあるので、プッシュ通知担当するサーバーサイドエンジニアの人にも役立つかも！

## [Configuring Remote Notification Support](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW1)
iOSでリモート通知を構成するために必要なことが書いてある(ネイティブ側の実装ドキュメント)。サンプルコードと共に書いてある公式記事なので、わかりやすい。

# ps
随時更新します。
【Unity】何かを動かす時に必ずやるべきこと

#今回やること
Unity上でオブジェクトを動かしたりする時にやっておくべきことをご紹介します。
#例えば
1秒間にX座標60移動させるとします。

```C#:Move.cs
{
    transform.position=new Vector3(0,0,0);
	void Update()
	{
		transform.position += new Vector3(1,0,0);
	}
}

```
これを60fpsの状態で起動すると毎秒60移動していることになります、ですがこれが30fpsになると毎秒30しか進まなくてなってしまいます。
なら60fpsでいいじゃんって話なのですが必ず60fps出る保証もありません。ではどんなfpsでも毎秒進む距離が変化しない状態にするにはどうすればいいのかというと。
#Time.deltaTimeを使う
このTime.deltaTimeってなにかというと「1 / 現在出ているfps」が戻り値として取得できます。
つまり60fps時なら「約0.0166」30fpsなら「約0.0333」を返してくれます。
それを元にコードを書くと。

```C#:Move.cs
{
    transform.position=new Vector3(0,0,0);
	void Update()
	{
		transform.position += new Vector3(60*Time.deltaTime,0,0);
	}
}

```
これでどんなfpsが出ていても１秒後には限りなく60に近い数値になります。
fpsの数値によって動く速さが変わるのはあまりよろしくないと思うのでこのようにどんなfpsになっても１秒間に動く距離が変わらないようにしてあげると良いと思います。
GitHub と Slack を連携させる


`/github subscribe リポジトリ名`
　↑
上記コマンドでは、以下の4つはデフォルトで通知されないので設定する。

```
/github subscribe リポジトリ名 reviews
/github subscribe リポジトリ名 comments
/github subscribe リポジトリ名 branches
/github subscribe リポジトリ名 commits:all
```

- 参照

https://get.slack.help/hc/ja/articles/232289568-GitHub-%E3%81%A8-Slack-%E3%82%92%E9%80%A3%E6%90%BA%E3%81%95%E3%81%9B%E3%82%8B#slack-%E3%81%A7-github-%E3%82%92%E4%BD%BF%E3%81%86--1
環境変数をディレクトリごとに指定するdirenv

#direnvとは
プロジェクトごとに環境変数が違う際、特定のフォルダ内でのみ指定環境変数を適用させてくれるもの。
例：プロジェクトAフォルダではPATH=hoge,プロジェクトBフォルダではPATH=fooを使いたい。

#環境
MacOS Mojave
Version:10.14.2

#使用方法
まずはインストール（brewはすでにインストール済み）

```
brew install direnv
```

.bash_profileに下記を書き込む。

```python:.bash_profile
eval "$(direnv hook bash)"
```

対象フィルダへ移動し、.envrcを作成→環境変数を記述

```
touch .envrc
vi .envrc
```

環境変数を記述

```python:.envrc
export PASSWORD="hogehoge"
export HOSTNAME="127.0.0.1"
```


#完成
指定フォルダへ移動した際に、自動的に記述した環境変数が`そのフォルダ内でのみ`適用されます。

```
#該当フォルダへ移動した際に、下記のようなメッセージがでる。
direnv: export +HOSTNAME +PASSWORD ~PATH
```

最後に、git管理をしていて外部流出していけない情報がある場合、.gitignoreに.direnvを含めるようにしましょう。


```python:.gitignore
.envrc
```

#参照元
[direnvを使ってディレクトリごとの環境変数設定を行う](https://qiita.com/tmzkysk/items/d85540b04d086fa82c62)
個人的TensorFlowまとめ(1)~そもそもTensorFlowって何編~

#注意書き
自分用のメモかつ知り合いに説明する際に使う用のTensorFlowまとめ。
間違ってることとかあったらコメントで指摘してもらえると助かります。

#TensorFlowとは
すごい身も蓋もない言い方をすれば「バックエンド(C++)に完全に計算を丸投げできる配列計算ライブラリ」。
やってることはバックエンドで動くNumPy、機械学習に特化したNumPy。
これを分かってればそこそこ気楽な心構えで入門できるはず。

#機械学習ライブラリの魅力
そもそもニューラルネットワークや機械学習する際に機械学習ライブラリ使う理由について挙げてみる。

- 機械学習関連の関数や機能が豊富
- GPUが使える
- 並列学習ができる
- 計算中はPythonレイヤーに戻ってこないので計算が早い

#TensorFlowの魅力
最近だと機械学習ライブラリにはPytorchとかChainerとかいろいろあるけどじゃあ今TensorFlowを使うメリットはなんなのか挙げてみる。

- TPUを現在唯一公式サポートしている
- 利用者数が機械学習ライブラリで最多だから資料が豊富
- 行列を意識するような低レベルAPIでの計算をゴリゴリ書ける
- Define by Runであるため理論上の計算速度はDefine and Runのライブラリより早い

#動作の仕組み
TensorFlowは計算グラフという物を構築して、その計算グラフに従ってバックエンドで計算している。
この計算グラフとは「こういう計算をしてください」という指示を有向グラフで示した物であり、基本的には計算手順を示す道具にすぎない。
例えば、２項の足し算の計算グラフの場合はこのようになる。

![足し算の計算グラフ](https://lh3.googleusercontent.com/a9GjnBZ64pbOeO3ff63dErxrw4E-Ys9F-5gl_uXXh54jeqaxhW4bnrnf3Z__hB6PTuapxUxu8D2AO6APqoT2v3hN5R54uFx-GJ59CDJG73zdTJy6yeo8RUm1_g4-1QMnXPZLyFpKUQ=w841-h421)

それでは実際にプログラムでこの計算グラフの再現を行ってみる。
まずは普通にPythonコードから。

```python:add_default.py
a = input()
b = input()
y = a + b
print(y)
```

しかし、TensorFlowの場合は以下のように途端に回りくどくなりめんどくさくなる。

```python:add_tf.py
import tensorflow as tf
a = tf.placeholder(tf.int32, name="a")
b = tf.placeholder(tf.int32, name="b")
y = tf.add(a,b)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(y, feed_dict={a:int(input("input a >>")),b:int(input("input b >>"))}))
```
「aとbのplaceholderを確保してadd(a,b)でa,bの足し算のノードを定義して、そのノードの出力をyへ入れる。with文でtfのSessionを開始し、global_variables_initializerで計算グラフ内の変数を初期化、sess.runで実際の計算を開始」という回りくどいことをやって初めて計算可能になる。
なんでこんなことをしているのかというと計算グラフ形式だといくつかの性質から偏微分が簡単になりニューラルネットの計算がやりやすくなるだけでなく、そもそもバックエンドに完全に計算を任せるために必要になる。

#終わりに
今回はそもそもTensorFlowって何なのかとざっくりその仕組みについて書いてみた。
次は簡単な使い方について解説してみたい。
Postgresで歯抜けデータをゼロ埋めする

## なにがしたいのか

* 過去30日の日別の売上を集計したい
* 休日は明細データがないケースがある（休日は歯抜けになる）
* 歯抜けの日はゼロ埋めしたい

![image.png](https://qiita-image-store.s3.amazonaws.com/0/355748/2e780f87-cc5b-60a2-d5be-13bccfb4f7a0.png)

こういうグラフを作りたい

## 日付テーブルを用意する

`generate_series()`がミソ

```sql
  SELECT
    days.dt::date as date
  FROM generate_series(
    date_trunc('day', current_date)+'-1 month',
    date_trunc('day', current_date), '1 days') as days(dt)
```

## 売上を日別に集計
この時点では、歯抜けがあります。

売上明細テーブル: `sales`

売上金額は`amount`、日付を`date`とする

```sql
SELECT
	date::date AS date
  , SUM(amount) AS total
FROM sales, DATE_TRUNC('day', date) AS date
GROUP BY 1
ORDER BY 1
```


## ２つをジョインしてゼロ埋めする

```sql
WITH month_calendar AS (
  SELECT
    days.dt::date as date
  FROM generate_series(
    date_trunc('day', current_date)+'-1 month',
    date_trunc('day', current_date), '1 days' ) as days(dt)
  )
, sales_group_by_day AS (
  SELECT
    date::date AS date
    , SUM(amount) AS total
  FROM sales, DATE_TRUNC('day', date) AS date 
  GROUP BY 1
  ORDER BY 1
)
  
SELECT
  m.date
  , COALESCE(s.total, 0) AS total
FROM month_calendar AS m
LEFT JOIN sales_group_by_day s ON s.date = m.date
オンラインサンドボックスサービスまとめ

##単なるメモです。

###hybrid-analysis
https://www.hybrid-analysis.com/

###JOESandbox Cloud
https://www.joesandbox.com/

###malwr.com
https://malwr.com/
(2019/04/23 現在休止中 Coming back soon!!とのこと)

###Any.Run
https://app.any.run/
ロシア発サンドボックス。
完全自動化のものと違い、インタラクティブ操作が可能等特色がある。
　参考URL: http://ed3159.hatenablog.com/entry/any-run-realtime-interactive-malware-analysis-sandbox-service

###Yomi
イタリアのセキュリティ企業の提供するサービス
https://yomi.yoroi.company/

###Padawan live
EURECOMが提供するマルチアーキテクチャに対応したELFの解析サービス
IoTマルウェアの解析に使える。
Public reportは誰でも参照可能
ログインには、Request accessをしてacceptされる必要がある。（自分はまだacceptされてないのでログイン出来ない）
https://padawan.s3.eurecom.fr/
JuliaでグラフのGIFアニメを作ってみた

![test.gif](https://qiita-image-store.s3.amazonaws.com/0/204284/d55b3527-9f8d-c214-1777-ded8c4069667.gif)

# 環境
- MacOS Mojave 
- Julia version 1.0.3
- Plots v0.23.0

Juliaのインストール手順は[以前の記事](https://qiita.com/MTNakata/items/54b8c0fc49df4d026eef)参照。

# 手順

下記の３ステップで行います。

### 1. Animationオブジェクトの初期化

```julia
using Plots
anim = Animation()
```

### 2. フレームの保存

```julia
for i=1:100
    plt = plot(...)
    frame(anim, plt)
end
```

### 3. フレームからアニメーションへの変換（gif,mp4など）

```julia
gif(anim, "test.gif", fps = 30)
```

参照元：https://docs.juliaplots.org/latest/animations/

# 実例

複素関数 $w = z^3$を描いてみます。

$$
z = x + iy
$$

$$
z^3 = (x^3-3xy^2) + i(3x^2y-y^3)
$$
 
$u(x,y)$を実部、$v(x,y)$を虚部とすると、

$$
u(x,y) = x^3-3xy^2
$$

$$
v(x,y) = 3x^2y-y^3
$$

yを動かした時の曲線を、異なるxごとにグラフを描いてアニメーションで表示します。

```julia
#パッケージのインポート
using Plots
gr()

#uとvの定義
function u(x,y)
    return x^3 - 3*x*y^2
end
    
function v(x,y)
    return 3*y*x^2 - y^3
end

#yの範囲設定
y = [i*0.1 for i in -100:100]

#アニメーションのインスタンス生成
anim = Animation()

#xを-10から10まで0.5刻みで動かしてグラフを描き、フレーム画像として保存
for x0=-20:20
    x = x0*0.5
    u_result = map(u,[x for i in 1:length(y)],y)
    v_result = map(v,[x for i in 1:length(y)],y)
    plt = plot(u_result,v_result,label="x=$x",
                xlims=(-1000, 1000), ylims=(-500, 500),
                xlabel="u",ylabel="v")
    frame(anim, plt)
end

#gifに変換
gif(anim, "test.gif", fps = 5)
```

![test.gif](https://qiita-image-store.s3.amazonaws.com/0/204284/d55b3527-9f8d-c214-1777-ded8c4069667.gif)

簡単ですね。

Jupyter上でも動くのが便利。

ちなみに重ね書きすると以下のようになります。

```julia
y = [i*0.1 for i in -100:100]

for x0=-20:20
    x = x0*0.5
    u_result = map(u,[x for i in 1:length(y)],y)
    v_result = map(v,[x for i in 1:length(y)],y)
    if x0==-20
            plot(u_result,v_result,label="x=$x",
                xlims=(-1000, 1000), ylims=(-500, 500),
                xlabel="u",ylabel="v")
    else
        plot!(u_result,v_result,label="x=$x",
                xlims=(-1000, 1000), ylims=(-500, 500),
                xlabel="u",ylabel="v")
    end
end
plot!(legend=:none)
savefig("test.png")
```

![test.png](https://qiita-image-store.s3.amazonaws.com/0/204284/6b2aea15-1a20-9b20-04ba-6fd3071d9a15.png)


# マクロを使った方法

`@animate`や`@gif`というマクロを使った方法もあるそうです。

参照元：https://docs.juliaplots.org/latest/animations/

```julia
anim = @animate for i=1:100
    plot(...)
end
gif(anim, "/tmp/anim_fps15.gif", fps = 15)
```

```julia
@gif for i=1:100
    plot(...)
end every 10
```

試していませんが、とりあえずメモ。

# 参考にしたページ
- [Plots - Animations](https://docs.juliaplots.org/latest/animations/)
- [Julia言語と Plots + GR で複素関数のgifアニメーションを作る](http://optie.hatenablog.com/entry/2018/03/29/210619)
- [Julia におけるアニメーションのしくみ](https://qiita.com/Lirimy/items/8976bb4dcf5febad178e)
RaspberryPiに任意のUSB(W95 FAT32)をオートでマウントする

RaspberryPiのDefaultではUSB-Memoryを刺しても認識しませんでした。
認識していないのでマウントをして使う事も出来ないので調べてみました。

$ ls -l /dev/disk/by-uuid
で任意のusbのuuidを調べる。

$ sudo vi /etc/fstab
/etc/fstabを編集して上で調べたUUIDをmountpointにvfatを起動時に認識できれば自動でマウントする為に以下のエントリを追加する。

UUID=XXXX-XXXX /media/usb0 vfat defaults,nofail 0 2

これで起動時にusbが刺さっていれば自動でマウントして起動するようになる。

hddでもUUIDを指定して同じ事が可能です。

その場合はまず
/media/にhdd0とゆうdirectoryを作成します。
$ sudo mkdir /media/hdd0
その後
$ sudo vi /etc/fstabに以下のエントリを追加します。
UUID=XXXX-XXXX-XXXX-XXXX /media/hdd0 vfat defaults,nofail 0 2

あとは、"murasaki" (package)とゆうのをインストールしてもよいらしいです。
コマンドは
$ sudo apt-get install murasaki
です。
これで起動中のrasspberrypiの空いているUSBスロットに新しいusbを刺して
$ df -h [enter]すると

/dev/sdb1 全体の容量　使用中容量　使用可能容量　XX% /media/pi(username)/NEW-USB
となりました。

再起動などで変動をしますsda sdb sdc等(sd？)の変更のcheckを無しでUUID(番号)でマウントにすればsd?は変動しても起動時に自動でマウントされます。

【後日ですが注意事項の報告】
Kernel Version Up 4.19.25+ 4.19.25-v7+　になってから自動でのマウントが出来なくなりました。
自分の設定が駄目なのか皆に共通して駄目なのかまでは分かりませんが当方の知識や技術では対応が出来ません。

$ sudo mount -t vfat /dev/sda1 /media/usb0
$ sudo mount -t vfat /dev/hda1 /media/hdd0
とか

実行が可能であれば
$ sudo mount -a

と、コマンドで手動でのマウントをしてくださいませ。。

【改善】
2019/06/21現在Kernel=4.19.50+にアップデートされており、これによる対策がされたのかどうか
UUID=xxxx-xxxx　と"/etc/fstab"に記載した項目は起動時に自動的にマウントできるようになっています。
【現状】
2019/08/03 kernel version 4.19.58+
起動時にmountしているよとかしたよ表示されて快適に動作をしています。

Mounting /media/usb0...
Mounted /media/usb0...

何度も追加編集をしてしまい申し訳ありません。m(_ _)m。。
この安定版が良く感じてしまいます。
LpicかLinucか・・・それが問題だ

オープンスペースで情報を発信するのはこれが初めてになります。
最初の記事としては資格試験について書きたいと思います。

資格試験にこだわってもスキルがある事の証明にはなりませんが、系統立てて学習できる事とモチベーションアップのための小目標としては有効だと思いいます。

そこでLinuxのスキル認定試験として知られるLPICとLINUC・・・・昨年LPICがLinucに代わる噂がありました。

2018年の夏から今までLPICの日本国内の窓口であったLPI-Japanが独自にLinucという認定資格を国内限定の認定資格として新しく始まったようです。

2019年2月13日現在LPICはLPICの主催団体Linux Professional Institute（ https://www.lpi.org/ja/ ）でそのままLPICがそのまま続行されていますし、2018年の10月下旬には新しいバージョンとして問題が更新されリリースされているようです。

まあ、受験する側としては結局ピアソンVUEで申し込みピアソンVUE認定の会場で受験するのでどちらでも良いかと思います。

Linucの良いところはでは学習資料のPDFを無料配布しています。（登録必要）
Linux標準教科書
https://linuc.org/textbooks/linux/

Linuxサーバー構築標準教科書
https://linuc.org/textbooks/server/

高信頼システム構築標準教科書－仮想化と高可用性－
https://linuc.org/textbooks/system/

Linuxセキュリティ標準教科書
https://linuc.org/textbooks/security/

Linuxシステム管理標準教科書
https://linuc.org/textbooks/admin/


LPICの良いところは国際資格というところで
現状、世間的にはLPICが広く認知されていると思います。
そこで2019年2月現在のLPIC受験手順を説明します。

<p><font size="7" color="#ff0000">■■■　LPICを受験する手順　■■■</font></p>

Linux Professional Instituteのページから
言語を選択して日本語に変更
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/a1885723-3adf-4165-7cab-d5a04b1acc54.jpeg)

左上のマイアカウントをクリックします。
![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/5ae62f9b-3367-d746-37e9-7c7a4c569b7d.jpeg)

画面が切り替わり「こちらから登録」をクリックします。
![3.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/52c6a21b-229d-ada1-0621-4eb64c29d672.jpeg)


個人情報を入力し登録します。
![4.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/1e2789b0-58f9-97da-8521-1d069f724766.jpeg)

登録が完了した後、使う言語を登録します。
（右上にLPIXXXが表示されます。）
![5.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/0f3bf5a0-e21d-71c8-cab6-f3615dcee482.jpeg)

登録が完了すると正式にLIPI IDが確定します。（試験を申し込むときに使用するので忘れないように注意！）
![6.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/253a64b5-a500-2d65-d848-8559c2b808ae.jpeg)

その後ピアソンVUEで受験できるすべての試験一覧から
https://www.pearsonvue.co.jp/test-taker/All-Tests.aspx
LPI　|　LinuxProfessionalInstitute認定試験を選択します。
![7.jpg](https://qiita-image-store.s3.amazonaws.com/0/169550/1bad5eb6-70ec-c630-63e6-12b180cb56d3.jpeg)

後はメニューに従って受験する試験（Level1の101やLevel2の202等）を選択して支払方法や受験会場を選択して完了です。
AWS Lambdaビルダー

Box-SDK(＊1)をLambdaで使おうとした際に色々ハマったのでメモ。

# pipインストール時のプラットフォーム

ローカル環境（Mac）でテストができたので、いざデプロイ！
Serverless Frameworkは早速Layerに対応していたので、SDK部分をLayerに切り出しも簡単：）

ところが。。。

```
[ERROR] ModuleNotFoundError: No module named '_cffi_backend'
```

モジュールがないと言われる。

sdkのリポジトリ眺めてみると、環境依存がちらほら見つかる。
MacとLambda環境の差異と見受けられる。

ググるとEC2でビルドする手順が多く引っかかったが、今はLambdaのDockerイメージ(＊2)が公開されているので、そっちを使う。


# docker内での圧縮コマンド

Lambdaのdockerイメージの使い方についてもググると結構見つかった。
その中から、以下のDockerファイルを作ってビルド＆デプロイ！


```
FROM lambci/lambda:build-python3.6
  
ENV AWS_DEFAULT_REGION us-east-1

ADD . .

CMD pip3 install -r requirements.txt -t /var/task && \
  zip -9 deploy_package.zip lambda_function.py && \
  zip -r9 deploy_package.zip *
```

また実行エラー。。。

```
lambda libffi-d78936b1.so.6.0.4: cannot open shared object file: No such file or directory: ImportError
```

ググってみると、情報 （＊３）が見つかった。
"*" でなく、"."を使えとのこと。
よくみると、本家サイト(＊2)のサンプルも、"."になっていた。本家サイトの熟読は急がば回れ。

最終行の"*" を"."に変更して再ビルド＆デプロイ！

成功 :)


ついでにDockerHubにアップしておいた。
https://hub.docker.com/r/pict3/aws-lambda-builder

以下のファイルを用意して、
<dl>
  <dt>lambda_function.py</dt>
  <dd>Lambdaコード</dd>
  <dt>requirements.txt</dt>
  <dd>pipインストール対象</dd>
</dl>

その後、以下のコマンドを叩けばパッケージが生成される。

```
$ docker run -v "$PWD":/var/task pict3/aws-lambda-builder
```

参考）
 (＊1) https://github.com/box/box-python-sdk
 (＊2) https://github.com/lambci/docker-lambda
 (＊3) https://github.com/snowflakedb/examples/issues/4
TypeScript + Serverless + ORM + RoutingMiddlewareを探す旅

[こちら](https://qiita.com/shinichi-takahashi/items/1a3da4158d7d5ff48f2b)の続きです。

# 結論

- Docker
- [serverless](https://serverless.com/)
- [nest](https://docs.nestjs.com)
- [DynamoDB Data Mapper](https://github.com/awslabs/dynamodb-data-mapper-js)
- [TypeORM](https://typeorm.io)

このあたりをうまく組みあわせるとそこそこ楽ちんだった

# 僕のわがまま

1. Requestの検証をしたい
2. ドメイン駆動的にEntityを中心とした設計をしたい
3. ローカル開発をDockerで、Deployはserverlessでやりたい
4. DBは案件に応じて柔軟に変更できるようにしたい
5. （後から出てきたけど）webpackもうやだ。消したい


_今回はDynamoDB編として紹介します_


## 1. Requestの検証をしたい
nestの[このへんの仕組み](https://docs.nestjs.com/controllers)と[class-validator](https://github.com/typestack/class-validator)で無事解決。
書いておくだけで勝手に検証してくれて適切なエラーを返してくれるのでチョー楽。

```ts:UserController.ts
@Put(':id')
@HttpCode(200)
async update(@Param() params: IdRequest, @Body() body: AddUserRequest) {
  await this.repository.save({...params, ...body});
}
```

## 2. ドメイン駆動的にEntityを中心とした設計をしたい

勝手にEntityつくればおｋ
`1.` と同様にclass-validatorのおかげでだいぶ楽
簡単に扱えるようにBaseEntityを生やした。

```ts:BaseEntity.ts
abstract class BaseEntity {
  async validate(): Promise<void> {
    const errors = await validate(this);

    if (errors.length > 0) {
      throw new BadRequestException(errors.toString());
    }
  }
}
```

```ts:User.ts
class User extends BaseEntity {
  @IsNotEmpty()
  id: string;
}
```

## 3. ローカル開発をDockerで、Deployはserverlessでやりたい

これも勝手にやれって感じなんだけど、DynamoDBはdynamodb-localなdocker imageが公開されてるのでそれを利用しました。
serverless.ymlは適宜いい感じに！

```yaml:docker-compose.yml
version: '3'
services:
  user-db:
    image: amazon/dynamodb-local
    ports:
      - 8000:8000
  user-app:
    build: .
    command: npm run start:dev
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - 3000:3000
    depends_on:
      - user-db
```

```dockerfile:Dockerfile
FROM node:8-alpine

RUN mkdir /app

WORKDIR /app

RUN npm install -g serverless

COPY package*.json ./

RUN set -x \
    && npm install
```

デプロイするときはこんだけ

```sh:deploy
$ docker-compose run --rm --no-deps user-app serverless deploy
```

## 4. DBは案件に応じて柔軟に変更できるようにしたい

以前はTypeORMマジヤベー！ブクロサイコー！ってノリでTypeORMばっか使ってたんですが、今回DynamoDB使いたかったので[DynamoDB Data Mapper](https://github.com/awslabs/dynamodb-data-mapper-js)ってのを使いました。
そこそこ使いやすくてよい。

そうじゃない場合 === TypeORMを使って済む場合は[nestの公式doc](https://docs.nestjs.com/recipes/sql-typeorm)を参考にやればおｋっぽい。
これはまだ試してないけど問題ないっしょ!!


## 5. （後から出てきたけど）webpackもうやだ。消したい

nestのValidationPipeなるものを使って `1.` を実現するんだけど、serverless-webpack/offlineな環境だとどうしても `Cannot find module 'class-validator'.` が発生して解決不能に。
[nestのissue](https://github.com/nestjs/nest/issues?utf8=%E2%9C%93&q=is%3Aissue+class-validator+)を見ても解決せず、でもなんとなくwebpackが悪いっぽいってところまで到達。
いろいろwebpackを騙そうとしたけど、最終的にはwebpackやめました。そしてwebpackを徐々に嫌いになっていっている自分に気づきました。

ローカル開発のときは[nodemon](https://github.com/remy/nodemon)、デプロイのときは[serverless-plugin-typescript](https://github.com/prisma/serverless-plugin-typescript)を使うことで解決できそうってところまで調査して、webpack関連を全部消しました。


# まとめ

TypeScriptっていうかJavaScriptっていうかその界隈は、フロントエンドな人たちもサーバーサイドな人たちも使っているせいかライブラリがかなり充実してるため、選択肢が数々ありながら最適なものを組み合わせて使うキメラフレームワークみたいな使い方がやりやすいなあっておもいましたあ！
ちょうどフロントはAngular、アプリはionicだったのでnestは違和感なく使えたのもなかなか面白いところですね。
[WIP] 良いレビューをする技術

## TL;DR

的を射たレビューをするのが難しく、ふとしたときに**どうなっていれば良いレビューなのか？**と何度か考えたことがあるが自分がきちんと良いレビューを行えていないなと感じたので
自分がされて良いと感じたレビューの共通項や悪いレビューをしてしまったなと感じたときの原因などを記載して良いレビューをするためのチェックリストを作成。

随時更新していく。
よい意見などがあれば採用、追加していくので多分永遠にFixしない。

## 良いレビュー

- [ ] コードの裏にある背景が理解した上で実装されたコードがそこから逸脱していないか指摘する
    - [ ] 書かれているコードがチケットやissueの課題を解決するか？
    - [ ] 書かれているコードがチケットやissueの課題の本質的な問題を解決しているか？
    - [ ] 書かれたコードが暫定的な対応になっていないか？(最初から暫定対応すると決めている場合は除く)
- [ ] 完了条件が明確なチケットであること
    - [ ] 解決したいことではなく、問題が共有されていること
- [ ] 変更されたコードだけでなく変更されていないが影響を受けるコードに関して指摘がある
- [ ] 「私はこう思う」ではなくロジックで「こうなっているほうがよい」という説明になっている
- [ ] 議論可能なレビューコメントになっている
    - [ ] 「何故疑問に思ったのか？」という背景が書かれている
    - [ ] 同じ指摘内容でも「わかるでしょ？」という感じで省略しない。コピペでよいのでちゃんと指摘する。あまりに多い場合はその旨をきちんと伝える。
- [ ] レビュー指示が明確である
    - [ ] 確認なのか、質問なのか、修正依頼なのか、代替案なのかひと目でわかるようなコメントになっている

## 悪いレビュー
- [ ] レビューコメントを読んだがレビューされた側がどうアクションすればいいのかわからない
    - [ ] 質問なら質問、改善なら改善、意見なら意見ということがわかるように伝えていない
- [ ] 完了条件があいまい
    - レビューというかチケットの問題だがチケットの完了条件、解決したい問題がレビュアーに伝わらないとレビューできない
- [ ] テストコードがない
    - レビューできる状態にないので論外
- [ ] コーディング規約に違反したコードでレビュー依頼がされる
    - Linterなどで自動で検知する、あるいは何かしらのツールでリフォーマットされる、テスト項目に違反しているコードが含まれていないかチェックするものを追加する
    - 基本的にレビュー依頼した段階で論外。

## ユースケース1: テストの粒度が大きすぎる

多くの場合テストの粒度がレビュイーからすると適切でないとき、問題のメソッドやAPIが変更されることが考慮されていないことが多いように思う。
背景としてそのテスト対象が不変なものであるかどうかが焦点になると思う。

- [ ] 不変であることが自明の場合、そこに対して無用なテストを書いていたら無用なテストを書いていることを指摘する
- [ ] 不変であるかどうかわからない、もしくは変わり得る可能性がある場合は書かれているテスト対象のメソッドやAPIが変更されることが考慮されていないケースが多いと思うので「このテスト対象が変わったらどうなりますか？」と質問する
    - [ ] このとき「テスト対象が変わったときにテストが失敗するように書かれていないので修正してください」と書いてしまうとレビュイーの考える余地がほぼなくなってしまうので気をつける。

## ユースケース2: テストケースが不足している

テストケースが不足している場合考えられることは多々あるが一番やりがちなのが複雑な振る舞いや仕様のためわかりやすい異常系のテストだけ実装されているケース。

- [ ] 複雑な仕様や複数の状態、ふるまいが考えられるチケットの場合は事前にチケット登録者か担当者を決める人がチケットの完了条件の1つに「TDDで実装されること」という条件を追加する
Amazon WorkDocs の Admin 設定

# 概要

Amazon WorkDocs を導入した後、管理者としてまず行う設定についてです。具体的には、タイムゾーン、言語、IP ホワイトリストの設定を行い、最後に、ユーザーを招待してみます。  
  
導入については、以下をご参照ください。  

https://stangler.hatenablog.com/entry/2019/02/12/124148


# 参考サイト
  
*  [Amazon WorkDocs ドキュメント](https://docs.aws.amazon.com/workdocs/index.html#lang/ja_jp)

# タイムゾーン
  
WorkDocs にログインし、下の画像の矢印の位置にあるアイコンをクリックしてください。  
  
![20190126_Admin_01_アイコン.png](https://qiita-image-store.s3.amazonaws.com/0/344724/25df0259-c3f7-f22e-2ce9-020877743b0b.png)
  
  
  
まずは、タイムゾーンを「 ( UTC+9:00 ) Asia / Tokyo 」に設定しましょう。  
  
![20190126_Admin_03_タイムゾーン.png](https://qiita-image-store.s3.amazonaws.com/0/344724/a955c492-e44d-08bc-26a5-ade71dd4e2a0.png)


# 優先言語
  
次に、「管理コントロールパネルを開く」リンクをクリックします。  
  
![20190126_Admin_02_管理コントロールパネル.png](https://qiita-image-store.s3.amazonaws.com/0/344724/4c7e0145-dbdc-bfe6-3039-7fa1fccec65a.png)

  
管理ダッシュボードと書かれた画面が表示されます。そこに「優先言語の設定 メール通知」という項目があるので、とりあえず「 Japanese - 日本語」を選択しておくのが、無難だと思います。
  
![20190126_Admin_04_メール言語.png](https://qiita-image-store.s3.amazonaws.com/0/344724/2f2a01d5-fcee-2579-c75a-1dcdf56edfd2.png)

  
# IP ホワイトリスト
  
使う場所を社内に限定したりする場合には、IP ホワイトリストの「変更」ボタンをクリックして設定します。現在アクセスしている IP アドレスが、ご丁寧に表示されている（下の画像のモザイクの部分）ので、例にならって入力します。  
  
![20190126_Admin_05_ホワイトリスト.png](https://qiita-image-store.s3.amazonaws.com/0/344724/2264e28a-1a34-c0c9-3af6-a3d1c8f8a6da.png)


  

# ユーザーの招待
  
メールアイコンのついた「ユーザーの招待」リンクをクリックして、招待したいユーザーのメールアドレスを記入し「送信」ボタンをクリックします。  
  
![20190126_Admin_06_ユーザーの招待.png](https://qiita-image-store.s3.amazonaws.com/0/344724/cd291072-34a0-0b73-e9ec-4db85e861d09.png)

  
この時点では、管理ダッシュボードでは、今、招待メールを送信したユーザーのステータスは「保留中」となっています。  
  
![20190126_Admin_07_ユーザーのステータス.png](https://qiita-image-store.s3.amazonaws.com/0/344724/8ee5f1a4-8470-0999-3f4a-5f7d65d0d98b.png)

  
招待メールはデフォルトの状態だと、以下のような文面で送信されます。  
  
![20190126_Admin_08_招待メール.png](https://qiita-image-store.s3.amazonaws.com/0/344724/01a744fc-f481-2449-198f-e6d82985d22e.png)

  
「今すぐ始める！」ボタンをクリックするとブラウザが開いて登録画面になります。招待した方に記入してもらって、アカウントをアクティベートしてもらいましょう。  
  
![20190126_Admin_09_認証.png](https://qiita-image-store.s3.amazonaws.com/0/344724/65016364-8e27-72b7-0de5-d513b4728250.png)


  
以上です。
Macで外部ディスプレイを使用する際にメインディスプレイを変更する方法

メインディスプレイの切替方法が見当たらなかったのですが、「白いバー」も移動できます。
こちらをメインにしたいディスプレイ側に付けることで、メインディスプレイを切り替えることが可能です。

![スクリーンショット 2019-02-13 11.36.03.png](https://qiita-image-store.s3.amazonaws.com/0/226008/7bd489df-61f4-7abc-839d-6199142db0cb.png)
大量にアイテムが保存された SharePoint Online リストに PowerApps からアクセスする

# 大量にアイテムが保存されたリストの問題

大量にアイテムが保存された SharePoint Online リストをギャラリーコントロールにバインドした際、次のようなエラーメッセージが表示されることがあります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/3f38d7bb-2906-78fe-277e-f515f26b221b.png)

また、このときのギャラリー コントロールの Items プロパティは、次のようになっています。

```PowerApps:Items
SortByColumns(Filter(Threshold, StartsWith(Title, TextSearchBox1.Text)), "Title", If(SortDescending1, Descending, Ascending))
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/4cbab28a-4f04-27eb-13ca-df646a7379a0.png)

タイトル列（Title）に対して操作が行われていることがわかります。どうやらこの操作が失敗しているようです。

このときに利用されている PowerApps 関数の SortByColumns 関数と Filter 関数（関数内で指定されている StartsWith 操作）は、いずれも SharePoint Online をデータソースとした場合、委任可能な関数となっています。

Delegable data sources in canvas apps
https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/delegation-list

つまりは、SharePoint Online 側の設定に問題がありそうです。

# SharePoint Online リストに列インデックスを作成する

SharePoint Online の対象のリストにアクセスし、「リストの設定」を開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/0bf1f980-b781-431c-ee34-c0b4cfc69c33.png)

列セクションの下にある「インデックス付きの列」を開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/22e801f8-4c39-73b0-eb03-2bdfacc2d003.png)

「新しいインデックスの作成」を開きます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/10ee1f61-8a79-4a71-b50b-524ca192f808.png)

「タイトル」を指定してインデックスを作成します。（今回は SortByColumns 関数や Filter 関数で利用している列がタイトルなのでタイトルを指定しています）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/c10809c1-abc3-ac01-9b11-f03b6e3f1b9f.png)

インデックスの作成処理がはじまります。「（インデックスを作成中です）」の表示が消えるまで待ちます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/d55b16b5-6530-3280-dcf4-542afc9a7f13.png)

# 動作を確かめる

インデックス作成完了後、PowerApps のアプリでデータ更新をすると、今度はエラーが返ることなく表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/1d44cd9a-9cf9-336f-2e8a-defb89ccbddf.png)

フィルターも動作します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/167110/3741e20a-3225-023f-6961-754ad4b86eb7.png)

# さいごに
PowerApps アプリで SharePoint Online リストをデータソースとする場合、同じようなエラーが発生したときは SharePoint Online リストの列インデックスの設定も確認してみてください。

ちなみに、今回の検証は、SharePoint Online のリストに 20,001 アイテムが保存された状態で行いました。
Attribute android:foreground has no effect on API levels lower than 23 (current min is 21)

背景色を指定していたときに `foreground` よく利用してたけど、`View`で使えるようになったのはAPI23から。それ以下で使いたいときは `FrameLayout` で使おう

```xml

android:foreground="?android:attr/selectableItemBackground"
```
Ubuntu16.04 on Macで左commandキーをmetaキーにする

いまさらですが、あっちこっちさがすはめになったので備忘録の為。
/usr/share/X11/xkb/symbols/pcの
```key <LWIN> { [ Super_L ] };```
を
```key <LWIN> { [ Meta_L ] };```
に変更。もっとよいやり方あるとは思いますが
コマンドプロンプト操作

##Windowsのコマンドプロンプト個人的によく使う操作

最近、何かと触ることが増え、Linuxのコマンドとは異なるので備忘録的な感じでまとめる。

###フォルダ一覧取得

Linuxでいうところの `ls`コマンド
`cd`で対象のディレクトリまで行き、以下を流すとファイル一覧を取得できる。
パス指定しても一覧取得は可能

```:コマンド
dir /b
```

###ファイル名変更

`rename`か`ren`コマンドを使用し、第一引数に変更前のファイル名、第二引数に変更後のファイル名を指定する。

```:コマンド
rename test.html change.html
```
公開リポジトリをフォークして非公開リポジトリにする

どうも。
OSSなどで公開されているリポジトリをフォークして、社内で使用したりしたい場合があります。
しかし、安易にgithubのforkボタンを押すと、公開リポジトリとしてフォークされてしまいます。
そこで、公開されているリポジトリを非公開なリポジトリとしてフォークしましょう。

追記:  him0 さんより以下のコメントを頂きました。
フォークする場合は必ずライセンスを確認しましょう。

> プライベートリポジトリにするにあたってライセンス確認しないとけないと思います。

### 1. まず、フォークしたい元のリポジトリを、bareモードでクローンします。

```bash
$ git clone --bare https://github.com/hoge/hoge
```

また、この時Git lfsを使用している場合は以下のようにしてGit lfsのfetchもしましょう。

```bash
$ cd hoge.git
$ git lfs fetch --all
$ cd ../
```

### 2. 次に、githubで新しく空のリポジトリを作ります。ここでプライベートにするのを忘れないでください。

![k.png](https://qiita-image-store.s3.amazonaws.com/0/154157/6a40a6bf-188f-14b6-3aa6-b2655814c9b3.png)


### 3. 最後に、先程クローンしたコードを、ミラーモードで自分のリポジトリにプッシュします。

```bash
$ cd hoge.git
$ git push --mirror git@github.com:myname/myrepo
$ git lfs push --all git@github.com:myname/myrepo #git lfsを使用している場合のみ
$ cd ../
$ rm -rf hoge.git
```

これで終わりです。結構簡単ですね。

参考: https://help.github.com/articles/duplicating-a-repository/
JenkinsにMSBuildを追加し、ビルドを設定する

## Jenkinsトップページから、Jenkinsの管理－Global Tool Configuration を開く
![image.png](https://qiita-image-store.s3.amazonaws.com/0/281492/9ae7e4b5-fb4d-0f09-ffa8-368f835e6e08.png)

# MSBuild追加
* MSBuildボタン押下
* "名前"に任意の名前を設定
* "MSBuild.exeファイルパス"にパスを設定
 Visual Studio Community 2017 の場合は → 「C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin」
* Saveボタン押下
![image.png](https://qiita-image-store.s3.amazonaws.com/0/281492/3a6165fc-d074-5137-181a-dd3003066c68.png)


# ビルドの設定
## 対象プロジェクトの設定を開く
![image.png](https://qiita-image-store.s3.amazonaws.com/0/281492/c133dfcd-84e3-d48e-4459-e4bfeb673e82.png)

## ビルド手順を追加
* ビルド手順の追加から、MSBuildの実行を選択する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/281492/5cab1571-f78c-7065-9096-e2f6529b75a8.png)
* MSBuildファイルに、MSBuild バージョン、ソリューションファイルパス(ワークスペースからのパス)を設定して保存
MSBuildが1件のみ追加されていた場合は、MSBuild バージョンにはDefaultと表示される
![image.png](https://qiita-image-store.s3.amazonaws.com/0/281492/5038d34d-ef36-870e-051c-b83ef7950c54.png)

# ビルドを実行して、コンソール出力内容を確認し、MSBuildが実行されている事を確認して完了
CloudWatch + SNS + Lambda + SlackでSlackにMetrics画像を送信する

### 上記の設定でだいぶ詰まったのでメモ

* [SlackBot](https://api.slack.com/apps?new_app=1)を作る


* TOKENのメモ
    * `https://api.slack.com/apps/xxx/oauth?`
    * 色々TOKENとかあるけど`OAuth Access Token`


* 上記ページで`SCOPE`も適切なものを選択
    * 今回のBotは以下のポリシー適応(要らないものも入ってるかも)
    * 設定したのちに画面上部のメッセージから承認作業も

<img width="669" alt="スクリーンショット 3.png" src="https://qiita-image-store.s3.amazonaws.com/0/155875/4e08e693-ad01-039e-75b8-c7aaf4e62f8d.png">



* Lambda関数については[ここ](https://qiita.com/hayao_k/items/026e704b5fad3037aea0)を参考に
    * ロールに必要な権限は**CloudWatch**,**LambdaExecute**
    * Lambdaの環境変数に設定するChannelIDはチャンネル名ではなく**ChannelID**が必要
        * 下のSlackAPIからも取得出来るがSlackのWebサイトのURLから取得可能
            * [参考記事](https://qiita.com/YumaInaura/items/0c4f4adb33eb21032c08)


#### おまけ
* [この辺](https://api.slack.com/methods/channels.list/test)でSlackAPIをお試し出来る
* Lambdaのタイムアウト時間を伸ばさないと3秒だとタイムアウトする


#### おまけのおまけ
* [CloudWatch DashboradStructure](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/CloudWatch-Dashboard-Body-Structure.html#CloudWatch-Dashboard-Properties-Metric-Widget-Object)
* AWS使用可能メトリクス一覧取得コマンド

```
aws cloudwatch --profile <profilename> list-metrics
```

* Lambdaデプロイコマンド
    * IAMユーザに**UpdateFunctionCode**の権限ないと出来ない
    * aws credentialでregionも指定しないと怒られる

```
aws lambda update-function-code --profile <profilename> --function-name <lambda function name> --zip-file fileb://<zip file name> --publish
```


#### TODO
* Dockerを用いたLambdaのローカル開発環境構築の記事を書く。
（レポート）NRIアジャイルハブ #11～マシュマロチャレンジ～

#はじめに
社内アジャイルコミュニティ「NRIアジャイルハブ」の#11企画として、マシュマロチャレンジを開催しました。
https://nri-agile-community11.peatix.com/view

今回はそのレポートです。

#マシュマロチャレンジとは
マシュマロチャレンジとは、その名のとおり、マシュマロを使ったゲームです。乾燥パスタ、マスキングテープ、ひもを用いて自立可能なタワーを作り、マシュマロをより高い場所に置きます。18分の時間制限を終えたときのマシュマロの高さを競います。

アジャイルなチームを作る際や、アジャイル関連の研修などでよく使われるワークショップで、みんなで楽しくワイワイとアジャイルな考え方を学ぶことができます。

トム・ウージェック氏が語っている、下記のTEDの動画も参考にしてください。
https://www.ted.com/talks/tom_wujec_build_a_tower?language=ja


#ゲームレポート
今回は参加者７名、うち２名の経験者、という構成でした。４人・３人の２チームに分けて、マシュマロの高さを競いました。

結果は･･･
成功！65cm！（程度だったはず）
![自立したタワー.jpg](https://qiita-image-store.s3.amazonaws.com/0/215534/2f77db7e-1dfb-1ccf-0942-c2d9206147ed.jpeg)

失敗（この後タワーが崩れて記録0cm）
![タワーを手で支えている画.jpg](https://qiita-image-store.s3.amazonaws.com/0/215534/b58ee646-04ff-3785-df56-785c1137270c.jpeg)

見事に自立したタワーを囲んで、みんなで何が良かった・改善できた、を話しました。
![タワーを囲んでふりかえり.jpg](https://qiita-image-store.s3.amazonaws.com/0/215534/33f0ccee-c61e-461a-64ff-153d5428a1e2.jpeg)

 - トライアンドエラーで組み立てていったことでマシュマロの高さを保ったまま強い構造物に仕上げていけた
 - タワーだけ組み立ててあとからマシュマロを乗せたときタワーが崩れてしまった
 - マシュマロは以外と重たい
 - 時間が迫りその時点の高さでは自立が難しかったので、ある時点で自立していた高さまで戻そうとしたが、その時の状態どおりに戻すことができず、タワーが崩れてしまった
 - マシュマロを置いた状態で自立可能かを確かめながらタワーを組み立てていくのが良さそう

などなど、様々なふりかえりの声が出てきました

#ふりかえり
アジャイルの考え方を体感するのにもとても効果的で、１時間という短い時間の中でも、参加者の方々にも持ち帰ってもらえたと感じました。
18分という時間制限がスプリントに相当し、スプリントの中でリリースできるものを作り上げる。常にリリース可能な状態を保って組み立てていく。このような開発スタイルの疑似体験ができるものだな、と思います。
また、チームビルディングにも効果を発揮しますね。一体感を醸成することのできるゲームであるとも感じました。

このようなアクティビティを、現場のチームでも行うことができると、新たな気づきを得たり、よりよいチームになれるなどの効果が期待できると思っています。
様々な引き出しを作り、現場に持ち帰ってもらえるように、NRIアジャイルハブの活動を活性化させていければと思います。


#NRIアジャイルハブ
##このコミュニティのステートメント
アジャイルにまつわる様々なプラクティスを実践・実験し、
多様な価値観・背景を持つ人々が知識・経験を共有し、
我々を取り巻くチーム・組織の文化・マインドを変革し、
NRIを通じて世界をより魅力的にする。
そんなコミュニティです。

##大事にする価値観
NRIアジャイルハブは
* 失敗を恐れず実験するマインド
* 変化を楽しむ姿勢
* 多様な人とのつながり

を大事な価値観としています。

・・・ということになりました。今後共よろしくお願いいたします。
Peatix のコミュニティページはこちら。ぜひフォローをば。
https://n-agile-community.peatix.com/view
VimやNeovimコマンドで覚えなきゃいけないコマンド覚書

# VimやNeovimで素早くコードを書きたい・変更したい
vimやNeovim(以下vim)を使い始めてみたものの使い慣れていなくて速度が遅い・・・うろ覚えで使ったコマンドが間違えててコードレビュー中にvim辞めたら？と言われてしまう・・・そんな辛い現実を超克するための覚書です。

速度を上げたかったらこんなテクもあるよ！や、なぜこれを使わない？というものがありましたら、ぜひご教示ください！

# 移動技
vim使いに特に必要なのは縦横無尽に速攻でカーソルを動きまわらせること。素早く動いてペアプロしている人たちの目を撹乱するくらいに早く動きたい・・・一度でいいから「もっとゆっくり打って・・・」と相手を困らせてみたい・・・
## 上下に1行ずつ移動
基本中の基本。jで下に一行ずつ、kで上に一行ずつ進む。jkにさわれている気分になれる良いコマンド。
## 左右に1文字ずつ移動
これも基本中の基本。lで右に一文字ずつ、hで左に一文字ずつ進む。
## 文頭・文末へ飛ぶ
これも基本中の基本。gを2回押下することで行の一番上へ飛ぶ。shift + gで行の一番最後へ飛ぶ。
## 行頭・行末へ飛ぶ
^コマンドでその行の一番最初の文字へ飛ぶ。shift + $コマンドでその行の一番最後の文字へ飛ぶ。
## 単語区切りで左右へ移動
wコマンドは単語区切りで前へ進む。bコマンドは単語区切りで後ろに進む。

# 編集技(単発コマンド編)
編集するときに初めてvimを触る人には独特な動きに見えるカーソルの位置が特徴的。初めて使うキャラが思うようにいうこと聞いてくれないあの感覚を味合わせてくれるそんなコマンド。
## iコマンド
インサートモードに入って編集することができる。カーソルを変更したい文字に合わせてこいつを押すと、その文字の後ろに編集カーソルが出現するからなれる必要がある。
## aコマンド
iコマンドがハラタツ動きをするので、カーソル変更したい文字に合わせてこのコマンドを押せば、変更したい文字の前で編集カーソルが出現してくれる。現時点で重宝しているコマンド。
## oコマンド
カーソル位置から次の行へ挿入する形でインサートモードになるコマンド。
##rコマンド
上書き編集するコマンド。これさえあれば書き直す時にわざわざインサートモードに入る必要なんてない。
## ctl + pコマンド
補完をしてくれるコマンド。
## yコマンド
ヤンクと呼ばれる独特なコピーコマンド。選択した行をコピーしクリップボードに乗せることができる。
## pコマンド
ペーストコマンド。コピーした行をカーソル位置から一行下に貼り付ける
## d×2コマンド
dを2回押下することで一行を削除することができる。削除した行は一旦クリップボードにコピーされるので、pコマンドで別の場所に貼り付けることも可能。メソッドの場所きもいなぁってなった時とか便利。
## xコマンド
一文字ずつ削除することができる。

#　編集技(コンボ編)
vimコマンドは組み合わせることで効果を伸ばすことができる。よく使うコンボは今の所以下のものですが、組み合わせ次第で効果的に使えるはず・・・超必ライクな組み合わせを編み出していきたい・・・
## shift + v　からのjコマンドからのyコマンド
shift + vがvisual lineのモードに移行し、一行を選択した状態になるので、ここからjコマンドで下に移動し、選択したい範囲まで動いてからコピーする。
## shift + v　からのjコマンドからのd×2コマンド
これは選択範囲を選んでまるごと吹き飛ばすことができる。
## ctl + vからのw or bコマンドからのd×2コマンド
ctl + vでvisual blockモードに移行し単語区切りで横移動して削除。

# :を使ったコマンド
vimには:を使ったコマンドも数多く存在する。

# :w・:q・:wq
基本中の基本。wで保存。qで終了。:wqで保存して終了。

# :行番号
これも基本中の基本。指定した行番号へ飛ぶ。

# 行番号 + shift + g
こっちの方がコロン打法の移動より便利だし、覚えやすいかもしれない。gは多分、GO!!の意味。

# visual mode + : s/置換される文字列/置換する文字列/g
visual modeからコロンを打つと、自動で置換用のコマンドを使えるようになる。使えば、簡単に置換範囲を決めることができ、範囲分だけ置換をおこなえる。

# :’a,’bs/書き直したい文字列/書き直す文字列/g
こちらも全部置換されて欲しくない時、範囲を指定してその範囲だけで置換を行えるものだが、上記のものより扱いやすい。理由は行数なんていちいち数えてられないから。つまり、局部分的に置換することができる。

始点で　ma　と押し、
行きたい場所まで移動したら、
終点で　mb　と押して、コマンドを入力する。

# .\\{-} という便利なやつ
特定の同じ記述に対して有効な置換方法。例えば、

```
class="aaa"
class="bbb"
class="ccc"
```

という記述があったとして、

```
:'<,'>s/class=".{-}"/class="置換後の文字"/g
```

と記述することで、

```
class="置換後の文字"
class="置換後の文字"
class="置換後の文字"
```

上記のような置換を行うことができる

## 他の文字列置換方法

最後にgを入れるとファイル内の全ての文字列を一括で置換

```
:%s/置換対象文字列/置換後の文字/g
```

最後にcを入れると。文字列を1つずつ確認しながら置換

```
:%s/置換対象文字列/置換後の文字/c
```

最後にgcを入れるとファイル内すべてのマッチした文字列を確認しながら置換

```
:%s/置換対象文字列/置換後の文字/gc
```

## 文字のエスケープ処理について
\も含めた文字列を変換したい場合、\をもう１つ入れて特殊文字扱いの\をエスケープさせてあげないと文字列扱いされず、置換対象に取れないので注意。
**;を使うことで見易くできる。**

```
ex）　:%s;\書き直したい文字列;\書き直す文字列;g
```

## 置換する記述を補完することができる
visualモードで（shift+vなりctrl+v）で範囲を選んでshiftを押しながら「：」を押すと「:'<,'>」の置換を意味する文字列を補完してくれる。これに続けてs/・・・と繋げていくことができる。

# 終わりに・・・
もっと強くなるためのコマンドがあるはずなので、もっと調べて吸収したい・・・ぶっちゃけまとめ終わった後に見返してみたら知ってるコマンド少な！！！！！となった・・・
vimのカスタム状況はこちらです。ご参考になれば・・・また、このプラグインで強く慣れる！というのがあればそちらもまた教えていただけると嬉しいです。
[私のvimカスタム](https://github.com/Ohnao/neovim)
PHPは上書きしないrenameができない

PHPのrename関数はファイルが存在すると上書きする仕様になっている。上書きrenameをさせたくなくてもだ。`rename`の直前で`file_exists`でrename先のファイルが存在しないことをチェックしたとしても、上書きrenameの仕様を完全に解消することはできない。もちろん意図しない上書きが起こる可能性を下げることはできる。

```php
file_put_contents('a', 'a');

echo "check if file does not exist\n";
file_exists('b') && exit(1); // ファイルが存在しないことチェック

echo "other program create file b\n";
file_put_contents('b', 'b'); // 他のプログラムが同時期にbを作ってしまう

echo "before rename\n";
rename('a', 'b'); // 他のプログラムが作ったbをaで上書きしてしまう

echo 'now file b content is ' . file_get_contents('b') . "\n";

unlink('b');
```

## renameが内部でどんなシステムコールを使っているのか？

```php
touch('a');
echo 'before rename';
rename('a', 'b');
echo 'after rename';
unlink('b');
```

```c
write(1, "before rename", 13before rename)           = 13
rename("a", "b")                        = 0
write(1, "after rename", 12after rename)            = 12
```

### Linuxの`rename`インターフェイス

```c
int rename(const char *oldpath, const char *newpath);
```

> **newpath が既に存在する場合、それは不可分操作で (atomically) 置き換えられる** (ただし、いくつかの条件がある; 以下の「エラー」のセクションを参照)。 そのため、 newpath にアクセスしようとしている他のプロセスがファイルを見失うことはない (訳註: 常にアクセス可能である)。
> *── [Man page of RENAME](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/rename.2.html)*

PHPの`rename`関数はLinuxの`rename`システムコールをそのまま使っているようで、PHPの`rename`の「newname が存在する場合、上書きされます」という仕様はLinuxの仕様を踏襲していると考えられる。

<img width="865" alt="PHP__rename_-_Manual.png" src="https://qiita-image-store.s3.amazonaws.com/0/889/940d80c2-855e-285b-e1d7-0dba7de086bd.png">

Linuxのシステムコールには`renameat2`があり、これは上書きしないオプションが存在する。が、PHPではこれを使っていない。

## 考えられる対策

* ファイル名がかぶらないものにする(UUIDとか)
* linkで一時ファイルのハードリンクを作ってから一時ファイルを消す

続く
オブジェクトの作成権限がないとVisualforceに項目が表示されない

検索画面の作成時に検索条件として選択リスト項目を配置したのですが、以下のように表示されない状態となってしまいました。
![検索画面2.PNG](https://qiita-image-store.s3.amazonaws.com/0/260521/ae496d10-9215-3063-e996-c7a36bc51a0f.png)
本来であれば以下のように選択リスト項目(会社種別)が表示されます。
![検索画面.PNG](https://qiita-image-store.s3.amazonaws.com/0/260521/e7d47ce4-2be5-72b6-5ebc-c2028e099b20.png)
これはプロファイルや権限セットで、オブジェクトへの参照権限が付与されていない場合に発生します。
対策としては以下の2通りかと思います。

1. プロファイルや権限セットでオブジェクトへの参照権限を付与
2. 項目をApexの変数で定義してVisualforceにセット

基本的には検索画面ではそのオブジェクトのレコードが参照できるはずなのでこの事象は発生しないのですが、今回は参照権限を極力絞りたいカスタムオブジェクトに対してApexのシステム権限でレコードを取得して表示するという仕様を実現しようとして事象が起こりました。

あまり出会う機会はありませんが、同じ事象に出会ってしまった方の助けになれば幸いです。
それではよいSalesforceライフを( ^_^)/~~
初めてのRuby on rails 開発の流れ確認 [Memo for neko]

まだ慣れていないと、作っている途中で開発の流れが分からなくてなってしまうこともあるかと思います。
そのためのメモです。

開発環境 (念のために・・・):
・Mac book Pro (Retina, 13-inch)
・mac OS High Sierra　バージョン10.13.6
・Ruby: ruby 2.3.7
・RubyGems: gem 2.5.2.3
・Rails: Rails 5.1.6.1
 
まとめ：
1.2.3. Rails 新規作成ー＞newで
4.モデル作成ー＞modelで
5.コントローラ作成ー＞controllerで
6.ビュー作成ー＞index.html.erbなどで

<h4>1.PC内に指定のディレクトリ（フォルダ）を新規作成</h4>

```terminal.例
mkdir 新しいディレクトリ名
cd 先ほど作った新しいディレクトリ名
```

例えばRailsディレクトリなら、

```terminal.Rails例
mkdir Rails
cd Rails
```

<h4>2.Rails アプリの新規作成</h4>

```terminal.例
rails new アプリ名
```
例えばTodoアプリなら、

```terminal.例Todo
rails new Todo
```

<h4>3.新規作成したRailsアプリディレクトリへの移動</h4>

```terminal.例
cd アプリ名
```

<h4>4.モデル新規作成（モデル名、中身の型決める）</h4>

```terminal.例Post
rails g model Post title:string body:text
rails db:migrate
```
（db:migrateは、データ反映のため）

<h4>5.コントローラ新規作成（コントローラー名、複数形）</h4>

```terminal.例Post
rails g controller Posts
rails routes
```
（rails routesは、パスの確認）

<h4>6.ビューの作成と編集</h4>
これは基本的にindex.html.erbなどです。
（この辺に関しては、後日記載できたらなと）

つづく。
Chrome 72 で contenteditable のスペース textnode が消えるバグが直った？

バグメモ

contenteditable を使って編集可能にした DOM のキャレット座標を取得するために、キャレットに空の `<span>` を挿入し、その DOM の座標から割り出すという方法を実装していたところ、Chrome 71 ではスペースが消えてしまうという症状に出くわしました。そして解決方法としてスペースを `&nbsp;` に置き換えることで消えないというハックを使いました。が、最近リリースされた Chrome 72 だとその症状が出なくなりました。バグイシューを調べたけど、該当の修正は見当たらず…。

## 再現コード

```html
<!DOCTYPE html>
<html>
<body>
<div id="editor" contenteditable="true">abc def</div>
<script>
  const editor = document.getElementById('editor')
  editor.addEventListener('keyup', () => {
    const anchor = document.createElement('span')
    const sel = window.getSelection()
    const range = sel.getRangeAt(0)
    range.insertNode(anchor)
    const caret_position = anchor.getBoundingClientRect()
    console.log('caret_position: ', caret_position)
    anchor.parentElement.removeChild(anchor)
  })
</script>
</body>
</html>
```

消える様子

![1.gif](https://qiita-image-store.s3.amazonaws.com/0/2152/d34ba5d6-6010-e754-b06e-f93e38dee04d.gif)

もともとの挙動がおかしかったので直ったのは素直に嬉しい。
拡張子の偽装 （拡張子 .html でアクセスした場合に .php を動かす設定）

拡張子 `.html` でアクセスした場合に `.php` を動かす設定

```conf:.htaccess
RewriteEngine On
RewriteBase /test
RewriteCond %{REQUEST_FILENAME} ^(.*)\.(html) [NC]
RewriteCond %1.php -f [NC]
RewriteRule ^(.*).html $1.php [L]
```
KtorでSlackBot作ってみた

Slackで`/chomado`を入力するとちょまどさんの写真を返すbotを作ってみました。  
![](https://i.imgur.com/nTijaWZ.png)

サンプルコードはこちらです。
https://github.com/hiroga-cc/chomadlin

また、サーバーも公開しているので、SlackBotだけ利用したい方は [3. Slackへのつなぎこみ](#3-slack%E3%81%B8%E3%81%AE%E3%81%A4%E3%81%AA%E3%81%8E%E3%81%93%E3%81%BF)から読んでください。

# Steps
1. Ktorアプリの作成
2. Herokuへのデプロイ
3. Slackへのつなぎこみ

# 1. Ktorアプリの作成
[公式ドキュメント](https://ktor.io/quickstart/)に則ってセットアップします。  

http://localhost:8080 で動くようになったら、次はロジックを作成します。  
Ktorはレスポンスを返すメソッドにdata classを渡すといい感じでjsonに変換してくれるようなので（すみません、仕組みはよくわかってません...!）、Slackのレスポンスに準じてdata classを作成します。 


```SlackResponse.kt
# SlackResponse.kt
package cc.hiroga

data class SlackResponse(
    val response_type: String,
    val text: String,
    val attachments: Array<SlackResponseAttachement>
)
```

```
# SlackResponseAttatchment.kt
package cc.hiroga

data class SlackResponseAttachement(
    val image_url: String
)
```

データクラスのオブジェクトの生成 & レスポンス  

```
        post("/chomado") {
            val TEST_CHOMADO_PIC = "https://pbs.twimg.com/profile_images/1086536800791740417/uvkmvoBk_400x400.jpg"
            val attachment = SlackResponseAttachement(TEST_CHOMADO_PIC)
            val response = SlackResponse(
                "in_channel",
                "(*ﾟ▽ﾟ* っ)З. (*ﾟ▽ﾟ* っ)З ‬",
                arrayOf(attachment)
            )

            call.respond(response)
        }
```

結果
  
```
# POST https://chomadlin.herokuapp.com/chomado
{
    "response_type": "in_channel",
    "text": "(*ﾟ▽ﾟ* っ)З. (*ﾟ▽ﾟ* っ)З \u202c",
    "attachments": [
        {
            "image_url": "https://pbs.twimg.com/profile_images/1086536800791740417/uvkmvoBk_400x400.jpg"
        }
    ]
}
```


# 2. Herokuへのデプロイ
[公式ドキュメント](https://ktor.io/servers/deploy/hosting/heroku.html)のガイド通り、`app.json`(Herokuが使用するコンテナのイメージなどを指定する)と`Procfile`(イメージの中で起動されるべきコマンドを指定する)を設定します。  
(system.propertiesは設定しなくてもなんかいけました...)


# 3. Slackへのつなぎこみ
もしSlackでちょまどさんbotを使いたいだけの人がいれば、以下のURLで手順を進めてみてください！  
https://chomadlin.herokuapp.com/

WorkSpace内でアプリを作成  
![](https://i.imgur.com/kH9z1je.png)

アプリの機能として`Slash Command`を追加  
![](https://i.imgur.com/9mdXQbx.png)

作成したアプリをWorkspaceにインストール  
![](https://i.imgur.com/E35NyXB.png)

疎通完了！  
![](https://i.imgur.com/Wvo0xKI.png)


# まとめ
Ktorを使って手早くSlackBot用のAPIを構成することができました。  
そこそこ小さいフレームワークながらもJSONに対するサポートがあり、APIサーバーとしてはいい感じ（でも仕組みを早く理解したい）という印象です。  
次はKtorの仕組みを細かく追いつつ、Botのロジックも修正していきます！
Excel VBAの性能改善


# はじめに
Excel VBAを使って、ちょっとした定型作業をツール化することがありますが、処理時間が非常に長くなるケースがあります。
VBAでExcelを操作するときにはいろいろとコツがあるので、それを紹介してみた
いと思います。

## 今回作成したサンプル

```vb
    Dim i As Long
    Dim j As Long
    
    For i = 0 To MAX_ROW
        For j = 1 To MAX_COL
            sheet.Cells(i + 5, j).FormulaR1C1 = "=ROW() *COLUMN()"
        Next
    Next
```

ひたすら、各セルに行＊列の計算式を代入するプログラムです。
MAX_ROW=500、MAX_COL＝100で私のPCで55秒程度かかりました。

# 改善方法

## 1．画面の描画を止める
```vb
        
    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    Application.EnableEvents = False
    
    Dim i As Long
    Dim j As Long
    
    For i = 0 To MAX_ROW
        For j = 1 To MAX_COL
            sheet.Cells(i + 5, j).FormulaR1C1 = "=ROW() *COLUMN()"
        Next
    Next

    Application.ScreenUpdating = True
    Application.Calculation = xlCalculationAutomatic
    Application.EnableEvents = True

```
画面描画と、自動計算を止めるようにしました。
結果、3.5秒と大幅短縮

## ２．セルへの代入に配列を使う

```vb
    Dim i As Long
    Dim j As Long
    
    Dim values(0 To MAX_ROW, 1 To MAX_COL)
    
    For i = 0 To MAX_ROW
        For j = 1 To MAX_COL
            values(i, j) = "=ROW() *COLUMN()"
        Next
    Next

    sheet.Range(sheet.Cells(5, 1), sheet.Cells(5 + MAX_ROW, MAX_COL)).FormulaR1C1 = values
```

なんと、0.3秒・・・

# まとめ
画面描画しない改善については、前から知っていたのですが、配列で代入の改善効果には驚きました。
セルに対する操作の回数を減らすほうがより良い効果を生むようですね。今回は試しませんでしたが、セルの入力規制や背景色を変えるなども同様に、Rangeでの操作にしたほうが圧倒的に早くなります。
[iOS]初アプリリリース出来ました!!(アプリ紹介,申請で困った点など紹介)

#案外あっさり通った審査
前回の記事
https://qiita.com/konbei/items/0ee0c1093f88cd5bc423
で実機ないipadでクラッシュしたというリジェクトを食らってからまたバンバン来るだろうなとびびりながら再提出しました。で、次の日起きたらAppleからメール来ていて今度はどんなリジェクトかなーと思って開いてみたら
Welcome to the App Store.
とのことでしばらく実感わかなかったのですがリリース出来ました笑。結果的にリジェクト１回で通ってよかったです。Dropboxを導入しているのですがそこの初期設定がちょっとややこしいのでまずそこはいちゃもんつけられるなと思っていたのですがあっさりスルー。アプリ内に詳しく説明した動画(youtube)を埋め込んでおいたのが効いたのかなと思っています。
#アプリ紹介
ではどんなアプリ作ったのかというとhttps://itunes.apple.com/jp/app/%E6%99%82%E9%96%93%E5%89%B2%E3%82%AB%E3%83%A1%E3%83%A9-%E6%8E%88%E6%A5%AD%E6%AF%8E%E3%81%AB%E5%86%99%E7%9C%9F%E3%82%92%E8%87%AA%E5%8B%95%E5%88%86%E9%A1%9E/id1451784896?mt=8

時間割カメラ(授業毎に写真を自動分類!!)
授業の写真と普段の写真が混ざるのがいや、テスト前に授業の写真を探すのが大変といったお悩みを解決!!!
・アプリ内のカメラで撮影することで時間、曜日から授業を特定して自動でフォルダ分類!!
・写真を時間割のレイアウトから簡単に見つけることができる!!
・dropboxを用いた端末間の同期、バックアップ、アップロード対応でデータの保全性も抜群!!
・メールやtwitterへの写真の書き出しにも対応!!
・内臓カメラはオートフォーカス、タップフォーカス、ピンチズーム機能付!!

といったものです。自分でも上記の悩みから使いたいなと思ったアプリを実際に作ったのでとても楽しくずっと作れました笑。必要な機能は全部付けられたと思っているので満足です。

#制作上大変だった点、工夫した点。
大変だった点は正直いっぱいあるのですが今回は2つに絞って紹介します。

・画面全機種対応
当然いろんな画面サイズの機種に対応しなきゃいけませんがオートレイアウトなる便利な機能を使って画面の端っこに制約をつければだいたいなんとかなります笑。
しかし時間割の画面はそれだとレイアウトが崩れてしまったので授業ひとマスをその機種の画面サイズの何分の1みたいに設定したり、iPhoneX以降のベゼルレス(Safe Area)の影響で画面がズレたりした部分を計算して修正するのがめんどくさかったです笑

・DropBox同期機能
等アプリではボタン一つ押すだけでDropboxと同期できる機能を作りました。Dropboxの機能は公式ライブラリのSwiftyDropboxを使ったのでサーバー通信などのAPIを直接叩くことなく比較的楽に導入できたのですが同期自体のメソッドがなかったのでアップロード・ダウンロード・削除を組み合わせたアルゴリズムを作って実現しました。このアルゴリズム、1つのファイルをアップロード・ダウンロード・削除した度に端末やDropbox側のファイルを確認しとかないと通信が失敗してもアップロードした事になったりしてしまうのでそこのもれが無いように組むのが大変でした。

最後に一番工夫した、こだわった点ですがズバリ「データの保全性」です。写真データをアプリに内臓してるのでじゃあアプリ消えたらどうなるんだという部分が解決されないとこの手のアプリは使う価値がないと思ったので入念に対策しました。具体的には
・標準アルバムアプリへの書き出し
・gmailなど外部アプリへの書き出し
・Dropbox同期、バックアップ機能
・万が一アプリが起動しなくなった場合でもituensに接続してデータ取り出し可能

バッチリです。

#アプリ申請で苦労した点まとめ
・機種ごとのサイズのアプリアイコンをxcodeで登録しておかないとビルドアップロードできない。
・display name,bundle nameなどには「camera」など標準アプリを匂わせる名称は使えない。
・ストア説明画面に使うiPhoneとiPadのサイズのスクリーンショットが必要。
・Dropboxなどの外部サービスを利用する場合はテストアカウントを提示する必要がある。
・プライバシーポリシーを載せたサイトを提示する必要がある。
・クラッシュログの解析の仕方
　https://qiita.com/ruwatana/items/cc470eb229d267d693b0
　を参考にさせてもらいました。

参考になれば幸いです。

#今後の展開
今回リリースしたアプリですがまだまだ夢があります。大学・授業ごとのグループラインを作ってそこで写真や情報などを共有できるような機能を追加したらこのアプリ便利すぎて覇権取れるんじゃないかと笑。写真の著作権などの問題はありそうですがとりあえず今はこの機能の根幹となるDBとやりとりするサーバー通信の勉強(javascript,node.js)をしています。明確なビジョン見えたらサーバー構築取り組んでみたいです。
あとAndroid版もkotlin勉強しながらぼちぼち作ってます。今回のアプリ作成でswift及びiOSフレームワークかなり網羅して触れることができたのでいい勉強になりました。
Ruby on Rails: js.erbが効かないときの対処

railsアプリのページにセレクトフォームを作成し、動的に変更する仕様にする際に気を付けておきたい点。

```controller

respond_to do |format|
  format.js
  format.html
end
```

と`format.js`を先に書きこむことで`js.erb`を`html.erb`よりも先に処理します。逆の場合ではjsの非同期通信が後回しになってviewに反映されないらしい。
DeviseのFacebook認証でハマった（解決済み）


認証時に便利なgemファイル「Devise」を使っていた際に、ハマりました。

2年以上前から、このライブラリを使ってきたのですが、FacebookがHTTPS通信を必須したのにも影響あってか一筋縄では実装できなくなっていたので、備忘録的に残しておきます。
ちなみに、開発環境では問題なく通ったけど、本番でハマったので厄介でした。

1) Deviseのデフォルトになっている「user_facebook_omniauth_authorize_path」はどうやっても、SSLにはできなかったので、今回別にURLをヘルパーで設定することにしました。

```erb:registrations.new.html.erb
<!-- <%= link_to user_facebook_omniauth_authorize_path do %> -->
<%= link_to facebook_url do %>
 <div class="btnFacebook">
   <span>
     <i class="fab fa-facebook"></i> Signin with Facebook
   </span>
 </div>
<% end %>
```

```ruby:application_helper.rb
module ApplicationHelper
  def facebook_url
    case Rails.env
    when "development"
      "https://www.facebook.com/dialog/oauth?client_id=（クライアントID）&redirect_uri=https%3A%2F%2Flocalhost:3000%2Fusers%2Fauth%2Ffacebook%2Fcallback&scope=email"
    when "production"
      "https://www.facebook.com/dialog/oauth?client_id=（クライアントID）&redirect_uri=https%3A%2F%2F（ドメイン名）%2Fusers%2Fauth%2Ffacebook%2Fcallback&scope=email"
    end
  end
```

2) FacebookのomniauthのコールバックURLを指定する

```ruby:devise.rb
・・・
  config.omniauth :facebook,
    Rails.application.credentials[Rails.env.to_sym][:facebook][:app_id],
    Rails.application.credentials[Rails.env.to_sym][:facebook][:app_secret],
    provider_ignores_state: true,
    callback_url: 'https://（ドメイン名）/users/auth/facebook/callback'
・・・
```

CloudflareでAlways HTTPSしていたからかもしれませんが、関係ないかもしれません。。
いつもスムーズに行くところでハマると、思いがけない工数が発生して焦りますよね。
日本語で作成した列の内部名から列名を調べる方法

小ネタです。

# 背景

自社内でこんなヘルプ依頼をもらいました。

> 検索の管理プロパティ設定でクロールされたプロパティを探しています。
> 作成時の列名から変更されている列があり、それを探すときに日本語名が分からなくて困りました。

# どういうこと？
リストの設定画面を開いて、内部名を確認したい列をクリックして列の設定画面を開きます。
列の設定画面を開いたときのURLで「Field=○○○○」の○○○○部分が内部名です。

列を作成する際に日本語の文字列を入力して列を作成した場合は、内部名はエンコードされた文字列になります。
 
「この内部名から列名を調べたい」ということです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/357828/0b73550e-75af-9c08-28ca-da9dd7027839.png)


# 手順

1.列の設定画面のURLで「Field=○○○○」の○○○○部分をメモする。
　Field=%5Fx8ffd%5F%5Fx52a0%5F%5Fx3057%5F%5Fx305f%5F%5Fx52-
 
2.手順1で取得した文字列をデコードする
　デコード前：
　%5Fx8ffd%5F%5Fx52a0%5F%5Fx3057%5F%5Fx305f%5F%5Fx52
 
　デコード後：
　\_x8ffd\_\_x52a0\_\_x3057\_\_x305f\_\_x52
 
3.手順2で取得した文字列を 16進数Unicode形式から変換
　変換前：
　\_x8ffd\_\_x52a0\_\_x3057\_\_x305f\_\_x52
 
　変換後：
　\_x深\_\_x井\_\_xで\_\_xす\_
 
4.手順3で取得した文字列から以下の文字を削除 

　・先頭の「\_x」
　・「\_\_x」
　・末尾の「\_」

　削除前：
　\_x深\_x井\_\_xで\_\_xす\_
 
　削除後：
　深井です


ご参考までに上記の例ではデコードを以下のサイトを使って行いました。
 
> エンコード / デコード
> https://so-zou.jp/web-app/text/encode-decode/