OmniAICreator/Qiita-1.07M huggingface dataset:
SwiftでWebAPIにGETリクエストしてみた。

# SwiftでWebAPIにGETリクエストしてみた。

## はじめに

今Swiftの勉強中で、いろいろやってみたことをまとめます。

### 環境
- macOS Mojave
- Xcode ver10.2.1
- Swift 5.0.1


## JSONをパースしよう

APIを叩いたらJSONで返ってくる予定なので、まずJSONパースをやってみます。
仮にこんなJSONがあるとします。

```json:user.json
[
    {
        "id":"A0001",
        "name":"モンキー D ルフィ",
        "remarks":"ゴムゴムの実の能力者"
    },
    {
        "id":"A0002",
        "name":"うずまき ナルト",
        "remarks":"元落ちこぼれ忍者"
    }
]
```

このJSONを受けるための構造体を作ります。

```swift:struct.swift
// Codableの継承を忘れないこと！
struct User: Codable {
    let id: String
    let name: String
    let remarks: String
}
```
Swift4.0から標準ライブラリでJSONDecoderなるものがあるらしい。
以下のようにすると、構造体にマッピングできる。

```swift:struct.swift
// JSONDecoderはData型しか受け付けないので、文字列型から変換する。
let jsonData = jsonStr.data(using: .utf8)

// さっき定義した構造体(User)の形にデコードしてくれる！
let users = try! JSONDecoder().decode(User.self, from: jsonData!)

// 結果をコンソールに表示
for user in users {
  print("id:\(user.id) name:\(user.name) remarks:\(user.remarks)")
}
/*  結果 
 *  id:A0001 name:モンキー D ルフィ remarks:ゴムゴムの実の能力者
 *  id:A0002 name:うずまき ナルト remarks:元落ちこぼれ忍者
*/
```
Codableを継承していないと、JSONDecoderは使えないので注意。
[ドキュメント](https://developer.apple.com/documentation/foundation/jsondecoder)

## APIにGETリクエストしよう

いよいよAPIにリクエストしてみます。
WebAPIの用意は、GoogleAppsScriptで作りました。
[GoogleSpreadSheetをDBみたいにするAPIを作成しました。](https://qiita.com/hajime_manul/items/a20e8c53f445bbe9f657)


### SwiftでGETリクエストしてみる
いろいろ格闘してこんな感じになりました。

```swift:get.swift
private func get(){
    let urlString = "https:〜〜〜〜〜〜〜〜〜〜〜〜〜"
    
    guard let url = URLComponents(string: urlString) else { return }

    // HTTPメソッドを実行
    let task = URLSession.shared.dataTask(with: url.url!) {(data, response, error) in
        if (error != nil) {
            print(error!.localizedDescription)
        }
        guard let _data = data else { return }

        // JSONデコード
        let users = try! JSONDecoder().decode([User].self, from: _data)
        for row in users {
            print("id:\(row.id) name:\(row.name) remarks:\(row.remarks)")
        }
    }
    task.resume()
}

```

## 結果
ストーリーボードで実行してみたら、ちゃんと出力してくれた！
<img width="928" alt="スクリーンショット 2019-05-28 20.21.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418332/a261ce45-4f7f-a0ec-140a-8037491f7339.png">

## あとがき
実はPOSTリクエストも作成済みなので、いずれPOSTも記事を書きます。
オリジナルアプリ制作中に振り返った基礎的な学習内容

#背景 
基礎的なPHPの学習を終えオリジナルアプリの制作に入ったが、つまづくことが多々ある。
ここに振り返った学習内容をまとめていくことにした。

---

関数
何度も利用する処理を定義しておく。次からは呼び出すだけで実行できる。
戻ってくる値を戻り値、返り値と呼ぶ。

引数
`mt_rand(1,100)`
このように関数に渡す値を引数(パラメータ)と呼ぶ。
この場合、乱数を生成する際の最小値と最大値を引数として与えている。
本番「用」環境と本番環境

本番「用」環境と本番環境

本番用環境は、本番と同じハードウェア、同じ設定で、そのまま顧客に納品できるハードウェア・設定で、納品ソフトウェアを試験するために用いる。

そのまま納品する場合もある。

納品前検査を、納品用ソフトウェアを使って行い、本番用環境と納品用ソフトウェアの組み合わせで、顧客側の納品検査が通るかどうかを確認する。

エラー、警告が出た場合は、本番用環境の設定を変更するか、メモリ増設などのハードウェアの構成を変更するか、ソフトウェアの設定を変更するか、ソフトウェアを変更するか、納品条件を変更するかの５つの方法がある。

本番用環境を本番検証環境と呼ぶ場合もある。その場合は、その環境を納品に回すことがないことが決まっている場合だけである。

#本番用環境の設定変更

対応する自然言語の範囲、対応するライブラリの範囲など、設定だけで対応できる警告の場合には、警告消しのような記述をすることもある。

#本番環境の構成変更

メモリ増設、ディスク増設、通信路増設、CPU／メモリの高速版への挿換。

設定変更を伴う場合もある。

#ソフトウェアの設定変更

利用するメモリの上限、ディスクの上限など、ソフトウェアの動作制約を記述できる仕様になっている場合には、その制約を調整することがある。

対応する自然言語の範囲、対応するライブラリの範囲を変更することもある。

#ソフトウェアの変更

設定変更だけでは対応できない場合、ソースコードを変更し、コンパイルし直すこともある。

#納品条件
エラーは操作で回避する方法、警告は無視するように納品条件に加筆する。

#組み合わせ
上記の複数の項目を同時に実施して対応することもある。
.NETメモ　.NET Framework, .NET Coreサポート期間 2019/05

# 図

![dotNetSupport.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142879/079ac14f-1e58-0470-26c6-b789c6496e82.png)


# 参考URL

* [Microsoft サポート ライフサイクル - 製品のライフサイクルの検索](https://support.microsoft.com/ja-jp/lifecycle/search/548)
* [core/microsoft-support.md at master · dotnet/core · GitHub](https://github.com/dotnet/core/blob/master/microsoft-support.md)
オブジェクト指向を理解したい

#背景
laravelを使用していて「なぜこうなるのか」が分からないことが多々ある。
原因はオブジェクト指向についての理解が浅いからだと思う。
理解を深めるために、ここに自分なりに噛み砕いた解釈を書いていく。

##オブジェクト、クラス、インスタンス
クラスとは、機能の仕様(設計図、レシピ)であり、そのクラスの仕様から作られたものがオブジェクト。
**厳密に言えば、クラスから作られたものはインスタンスと呼ぶ。**

オブジェクトとは、「機能とデータを持ったもの」。
プログラミング的に言うと、「メソッド(処理)とプロパティ(属性)を持ったもの」。
車(オブジェクト)は走るという機能と、色や車種というデータを持っている。

オブジェクトにどんなプロパティがあり、メソッドがあるかを定義したものがクラスともいえる。

##オブジェクトとインスタンスの違い
**重要なのはオブジェクトは一つ上の概念であるということ。**
意味的にインスタンスは「～の子ども」、オブジェクトは「人間」に相当する。

鈴木さんの子ども(インスタンス)は人間(オブジェクト)である
iPhoneはスマートフォンである
レクサスは車である

というようにどのインスタンスもオブジェクトといえる。
この概念をもう少し広げれば、世の中のほとんどのものがクラスとインスタンスの関係にあるといえる。
[Ruby] Kernel.#Array に困ったら Active Support コア拡張機能の Array.wrap を使おう

# TL;DL

```rb
require 'active_support/core_ext/array/wrap'

hash = { name: '中川夏紀', instrument: 'ユーフォニアム' }
Array(hash)
#=> [[:name, "中川夏紀"], [:instrument, "ユーフォニアム"]]
Array.wrap(hash)
#=> [{:name=>"中川夏紀", :instrument=>"ユーフォニアム"}]

range = 1..10
Array(range)
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Array.wrap(range)
#=> [1..10]
```

# Kernel.#Array について

さまざまなオブジェクトを配列に変換してくれる [Kernel.#Array](https://docs.ruby-lang.org/ja/latest/method/Kernel/m/Array.html)、便利ですよね。

```rb
Array(nil)
#=> []

Array(1)
#=> [1]

Array([1, 2, 3])
#=> [1, 2, 3]
```

しかし、ときに困った振る舞いをします。例えば Hash オブジェクトを、それを要素とした配列に変換したいときに Kernel.#Array を使うと

```rb
hash = { name: '中川夏紀', instrument: 'ユーフォニアム' }

# [hash] を期待したが、実際はキーと値のペアの配列を返す。
Array(hash)
#=> [[:name, "中川夏紀"], [:instrument, "ユーフォニアム"]]
```

のように期待と異なる値を返します。

この振る舞いは [Kernel.#Array のリファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/method/Kernel/m/Array.html) に記載されている

> arg.to_ary と arg.to_a をこの順に呼び出して、返ってきた配列を変換結果とします。
> arg に to_ary, to_a のいずれのメソッドも定義されていない場合は 一要素の配列 [arg] を返します。

という性質によるものです。Hash オブジェクトには Hash#to_a メソッドが定義されているため、それが呼ばれるわけです。 

```rb
hash = { name: '中川夏紀', instrument: 'ユーフォニアム' }

hash.to_a
#=> [[:name, "中川夏紀"], [:instrument, "ユーフォニアム"]]

hash.to_ary
# NoMethodError
```

では「Hash オブジェクトをそれを要素とした配列に変換したいとき」はどうすればよいのでしょうか？

# Array.wrap について

ここで役に立つのが [Active Support コア拡張機能](https://railsguides.jp/active_support_core_extensions.html) に含まれる [Array.wrap](https://api.rubyonrails.org/classes/Array.html#method-c-wrap) です。使用するにはまず Active Support をインストールしてください。

```rb
gem install activesupport
```

Array.wrap メソッドに Hash オブジェクトを渡すとどうなるでしょうか？

```rb
require 'active_support/core_ext/array/wrap'

hash = { name: '中川夏紀', instrument: 'ユーフォニアム' }

Array.wrap(hash)
#=> [{:name=>"中川夏紀", :instrument=>"ユーフォニアム"}]
```

無事やりたいことが実現できました :tada:

この振る舞いは [Rails ガイドの Active Support コア拡張機能のページ](https://railsguides.jp/active_support_core_extensions.html) に記載されている

> 引数がnilの場合、空の配列が返されます。
> 上記以外の場合で、引数がto_aryに応答する場合はto_aryが呼び出され、to_aryの値がnilでない場合はその値が返されます。
> 上記以外の場合、引数を内側に含んだ配列 (要素が1つだけの配列) が返されます。

という性質によるものです。Hash オブジェクトには to_ary メソッドが定義されていないので「引数を内側に含んだ配列を返す」ということです。

# その他の例

同様の理由で、例えば Range オブジェクトを引数に渡した場合も Kernel.#Array と Array.wrap とで振る舞いが異なります。

```rb
range = (1..10)

range.to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

range.to_ary
# NoMethodError

# Range#to_a が呼ばれる。
Array(range)
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 引数を要素として含んだ配列を返す。
Array.wrap(range)
#=> [1..10]
```

うーん、このかゆいところに手が届く感じが好き :hearts:

# 参考

* Array.wrap のソースコード (v5.2.3)
  * [rails/activesupport/lib/active_support/core_ext/array/wrap.rb](https://github.com/rails/rails/blob/v5.2.3/activesupport/lib/active_support/core_ext/array/wrap.rb#L39)
numpyの配列やpandasのデータフレームをファイルとして保存したい

まず、適当に配列やデータフレームを作ります。

```py:sample.py
import pandas as pd
import numpy as np
txt =np.array([letter for letter in 'abcdefghijklmno']).reshape(3,5)
array = np.arange(12).reshape(3,4)
df = pd.DataFrame(array.T, index=['A','B','C','D'],columns=['a','b','c'])
print(txt) >>>
[['a' 'b' 'c' 'd' 'e']
 ['f' 'g' 'h' 'i' 'j']
 ['k' 'l' 'm' 'n' 'o']]

print(array) >>>
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

print(df) >>>
   a  b   c
A  0  4   8
B  1  5   9
C  2  6  10
D  3  7  11
```
まず、`numpy`のコマンドで配列やデータフレーム、リストを保存して、さらにロードします。

```py:sample.py
np.savetxt('save1.txt', array)
np.save('save2.npy', txt)
np.savez('save3.npz', save_array=array, save_df=df)
np.save('save4.npy', [1,2,3])

loaded_array=np.loadtxt('save1.txt')
loaded_txt=np.load('save2.npy')
loaded_array_df=np.load('save3.npz')
loaded_list=np.load('save4.npy')

print(loaded_array) >>>
[[ 0.  1.  2.  3.]
 [ 4.  5.  6.  7.]
 [ 8.  9. 10. 11.]]

print(loaded_txt) >>>
[['a' 'b' 'c' 'd' 'e']
 ['f' 'g' 'h' 'i' 'j']
 ['k' 'l' 'm' 'n' 'o']]

print(loaded_array_df['save_array']) >>>
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

print(loaded_array_df['save_df']) >>>
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
#元はデータフレームだったのに配列になっている。

print(loaded_list) >>>
[1 2 3]
```
基本的に`np.save()`で保存し、`np.load()`でロードできます。`np.savez()`で一つのファイルに複数の配列を保存することができます。複数保存するときは名前を付けるとロードするときに便利です。ここでデータフレームは、インデックスや列名は保存されず、ロードしてみると要素だけの配列になってしまうので注意です。
データフレームをきちんと保存して取り出すには`.to_csv()`で保存し、`pd.read_csv()`で読みださねばなりません。しかしインデックスの列が要素に含まれてしまうときは、オプションとして`index_col=0`としましょう。これは0列目をインデックスにすることを意味します。

```py:sample.py
df.to_csv('save5.csv')
loaded_df = pd.read_csv('save5.csv')
loaded_df2 = pd.read_csv('save5.csv', index_col=0)

print(loaded_df) >>>
  Unnamed: 0  a  b   c
0          A  0  4   8
1          B  1  5   9
2          C  2  6  10
3          D  3  7  11

print(loaded_df2) >>>
   a  b   c
A  0  4   8
B  1  5   9
C  2  6  10
D  3  7  11
```

#追記
投稿後に頂いたコメント（@nkay さんより）の中で指摘がありましたので追記します。
以下のように、`.to_pickle()`で保存し、`pd.read_pickle()`でロードすると、オプションなしで元の形でデータフレームを保持できます。こちらのほうが便利ですね。ご教授いただきありがとうございました。

```py:sample.py

>>> df.to_pickle("save.pkl")
>>> 
>>> loaded_df = pd.read_pickle("save.pkl")
>>> print(loaded_df)
   a  b   c
A  0  4   8
B  1  5   9
C  2  6  10
D  3  7  11
```
オフライン環境のUbuntuでapt install

オフライン（ローカル）環境のUbuntuにapt installが必要なパッケージを入れる方法。
今回はUbuntuのdockerコンテナを例に説明する。

……この記事はネットワークにUbuntu接続禁止、という組織向け(　ﾟдﾟ)

### DL;DR
1. ネットワークに接続したubuntuにapt installでパッケージを導入
2. インストール時に残されたアーカイブをローカル環境のUbuntuにコピー
3. アーカイブを使用してパッケージをインストール

※今回の手法はUbuntu16.10、18.10で確認済み。

#### 1. ネットワークに接続したUbuntuを準備
Windowsの場合はWSLで該当するUbuntuを入れて使用する。

#### 2. ネットワーク接続したUbuntuで必要なパッケージをapt installで入れる
今回の例はDocker ce

```
$ sudo apt update
$ sudo apt install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io
```
#### 3. パッケージのインストールに必要なdebファイルを固める
apt install時に取得したdebファイルは下記フォルダにアーカイブされている。

```
/var/cache/apt/archives
```
このフォルダをtarで固める(今回はdebs.tar.gzという名前）。

```
$ cd /var/cache/apt/archives
$ cd ..
$ sudo tar -zcvf debs.tar.gz archives
```

・Ubuntuの場合はtarファイルを直でUSBメモリへコピー
・Windowsの場合はアクセス可能なフォルダに移してからUSBメモリへコピー。

```
# windowsの場合の例。c:\tmpにファイルを移動
$ sudo mkdir /mnt/c/tmp
$ sudo cp debs.tar.gz /mnt/c/tmp/
```
#### 4. ローカルのUbuntuにインストール
先ほどのtarファイルをローカルUbuntuにコピーしてインストール

```
$ cp debs.tar.gz ~/
$ tar -jxvf ~/debs.tar.gz
#パッケージのインストール
$ sudo apt -y install ./archives/*.deb
```

多分 apt updateも同じ手順で対応できるはず。

##### 参考：docker-composeの場合
apt installのdocker-composeは古いので、下記コマンドで入手したものをコピーする。

```
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
```

コピーした先で実行権限を付与

```
$ sudo chmod +x /usr/local/bin/docker-compose
```
コマンドが存在しないとエラーが出る場合はエラーのアドレスにリンクを張る。

```
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
```

#### 注意点
apt installでパッケージを多く入れている場合は下記コマンドで事前にパッケージのアーカイブをクリーンアップしておくとコピーする量が少なく済むが、不足パッケージで依存性の問題が発生する可能性がある。

```
$ sudo apt clean
````


#### 参考資料
https://vogel.at.webry.info/201702/article_3.html
https://diary.masasuzu.net/entry/2018/08/09/143934
plunkerで真理値表

#概要

plunkerで真理値表やってみた。


#写真

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/5492cfb7-97cf-c7f2-d150-5200eef89244.png)

#サンプルコード


```
var c0 = new C(5);
c0.init(0, 1);
c0.xor(0, 1, 2);
c0.and(0, 1, 3);
c0.or(0, 1, 4);
c0.table();
```


#説明

巷の物は、出力がひとつだけど、これは、いっぱいある。
init(0, 1)で、0bitと1bitに、組み合わせをつくる。
00, 01, 10, 11ができる。
xor(0, 1, 2)は、入力0bit,1bitで出力2bitにxorする。
論理ゲートは、xorとandとorだけ。
and(0, 1, 3)は、入力0bit,1bitで出力3bitにandする。
or(0, 1, 4)は、入力0bit,1bitで出力4bitにorする。
table()は、テーブルで表示する。

#半加算器を作る。

xorゲート1個とandゲート1個で作る。
なので、上の真理値表で出力が２でキャリーが３です。


#成果物

https://embed.plnkr.co/sZxpk3nLh0hWbWUFwy0x/

以上。
atomhelperのCPU使用率が100%を越えてMacのキーボード左上らへんが溶けそうで不安な時


#きっかけ不明だがatomhelperのCPUが100%越えた

タイトル通りなのですが、その結果、Macのキーボード左上らへんが溶けるんじゃないかと不安になるくらい熱い（真夏の黒クラウンのボンネットくらい）。
冷却ファンの音もハンパない（ラジコンヘリくらい）。
なんとかしなくてはと調べていると...


##私の場合はこれで治りました↓↓

atomのパッケージ管理から
（画面左上のpreferences→settings→package）
↓
”github”と検索
↓
状態をdisableに変更
↓
atomを一旦閉じて再度立ち上げ
↓
再度アクティビティモニタでCPU使用率を確認


##...どうでしたか？？

これでCPU使用率が落ち着いて幸せになられている事を願います。

ちなみに...
atomをsafeモードで立ち上げる事で拡張機能をOFFにして、CPU使用率を落ち着かせる方法もあるようですが、根本的な解決にはならないので、上記の対策1つで問題が解決された方がbetterだと思います。

他にも良い方法があれば教えて下さいm(_ _)m
Rails カラム名変更方法

#はじめに
プロジェクト開発をしている時にカラム名を間違えてmigrateしてしまったので
備忘録としてまとめていきます。

バージョン:Rails 5.2.3

#
|モデル名|変更前のカラム名|変更後のカラム名|
|:---:|:---:|:---:|
|user|remember_digesgt|remember_digest|


#1.migrationファイルを作成
カラム名を変更するためにmigrationファイルを作成する。

```
$ rails generate migration rename_[変更前のカラム名]_column_to_[モデル名(複数形)]
```

#2.migrationファイルを編集
生成されたファイルにchangeメソッドを追加し、そこに変更したいカラム名を記述する。
`rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名`

```rb:db/migrate/20190528101725_rename_remember_digesgt_column_to_users.rb
class RenameRememberDigesgtColumnToUsers < ActiveRecord::Migration[5.2]
  def change
    rename_column :users, :remember_digesgt, :remember_digest
  end
end
```

#3.DBに反映
下記コードでDBに反映させる。

```
$ rails db:migrate
```
POIで大容量ファイルの読み込みでZip bombエラーを回避

問題の実装

        OPCPackage p = null;
		try {
			p = OPCPackage.open(file, PackageAccess.READ);
			log.info("Read File:[" + file + "]");
			XSSFStringsTable strings = new XSSFStringsTable(p);
			XSSFReader xssfReader = new XSSFReader(p);
			StylesTable styles = xssfReader.getStylesTable();
			XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
			List<CommonRecord> resultList = new ArrayList<CommonRecord>();

			List<String> targetSheetList = ConfigUtil.getTargetSheet(key);
			while (iter.hasNext()) {
				InputStream stream = iter.next();
				String sheetName = iter.getSheetName();
				if (targetSheetList.isEmpty()
						|| !targetSheetList.isEmpty() && targetSheetList.contains(sheetName.trim())) {
					log.info("Read Sheet:[" + sheetName + "]");
					resultList.addAll(processSheet(styles, strings, stream, key, file));
				}
				stream.close();
			}
			return resultList;

StylesTable styles = xssfReader.getStylesTable();のところで下記エラーが発生。


java.lang.ClassCastException: org.apache.poi.xssf.usermodel.XSSFWorkbook cannot be cast to org.apache.poi.xssf.streaming.SXSSFWorkbook

ZipSecureFile.setMinInflateRatio()を呼び出すことでエラーを回避


改修後の実装

        OPCPackage p = null;
		try {
			p = OPCPackage.open(file, PackageAccess.READ);
			log.info("Read File:[" + file + "]");
			XSSFStringsTable strings = new XSSFStringsTable(p);
			XSSFReader xssfReader = new XSSFReader(p);
			StylesTable styles = xssfReader.getStylesTable();
			XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
			List<CommonRecord> resultList = new ArrayList<CommonRecord>();

			List<String> targetSheetList = ConfigUtil.getTargetSheet(key);
			while (iter.hasNext()) {
				InputStream stream = iter.next();
				String sheetName = iter.getSheetName();
				if (targetSheetList.isEmpty()
						|| !targetSheetList.isEmpty() && targetSheetList.contains(sheetName.trim())) {
					log.info("Read Sheet:[" + sheetName + "]");
					resultList.addAll(processSheet(styles, strings, stream, key, file));
				}
				stream.close();
			}
			return resultList;
#git管理-自分でdevelopをマージする

#git管理-自分でdevelopをマージする
（状況）
ネットでプルリクエストができなかったので自分でしないといけなかった


(初見)
PHPStreemで、GIT管理ができる。

window右下に[git: xxxx ]
となっているところをクリックすると
みんなのブランチが見れる。

チェックアウト（選択）をするとそのブランチに切り替えることができる。
developをチェックアウトし、
VCSのGITのPULLを押すと最新の状態に保存できるので、
一度行う。
自分のfeatureブランチをmargin into current して
そのまま、プッシュすることで、プルリクエストが完了する。

この時にいらない処理があると、マージができないので、
検証用にブランチを切り分ける事が必須になる。

逆に自分のfeutureブランチにdevelop をmargin into current したら最新になる。



クラスのCONST定数を参照するマーク
::
クラス名：：名前
Desktop : OpenCV Find Chessboard Corners By WebCam

<h5>Goal</h5>
Test OpenCV find chessboard corners by webcam.

```OpenCV_FindChessboardCornersByWebCam.java
import javax.swing.JFrame;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Size;
import org.opencv.core.TermCriteria;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;

public class OpenCV_FindChessboardCornersByWebCam {
    static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
    public static void main(String arg[]) throws Exception{
        // It is better to group all frames together so cut and paste to
        // create more frames is easier
        JFrame frame1 = new JFrame("尋找出棋盤格Live版");
        frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame1.setSize(640,480);
        frame1.setBounds(0, 0, frame1.getWidth(), frame1.getHeight());
        Panel panel1 = new Panel();
        frame1.setContentPane(panel1);
        frame1.setVisible(true);

        //-- 2. Read the video stream
        VideoCapture capture = new VideoCapture();
        capture.open(0);
        Mat webcam_image=new Mat();

        capture.read(webcam_image);
        frame1.setSize(webcam_image.width()+40,webcam_image.height()+60);

        if( capture.isOpened())
        {
            while( true )
            {
                Thread.sleep(200);


                capture.read(webcam_image);
                if( !webcam_image.empty() ){

                    Mat destination=webcam_image.clone();
                    Imgproc.cvtColor(destination, destination, Imgproc.COLOR_BGR2GRAY);
                    Size boarderSize=new Size(9,6);
                    MatOfPoint2f imageCorners=new MatOfPoint2f();
                    boolean found=Calib3d.findChessboardCorners(destination, boarderSize, imageCorners,Calib3d.CALIB_CB_ADAPTIVE_THRESH+Calib3d.CALIB_CB_NORMALIZE_IMAGE+Calib3d.CALIB_CB_FAST_CHECK);
                    if (found){
                        Imgproc.cornerSubPix(destination, imageCorners, new Size(11,11), new Size(-1,-1),new TermCriteria(TermCriteria.EPS|TermCriteria.MAX_ITER,30,0.1));
                        Calib3d.drawChessboardCorners(webcam_image, boarderSize, imageCorners, found);
                    }
                    panel1.setimagewithMat(webcam_image);
                    frame1.repaint();
                }
                else
                {
                    System.out.println(" 無補抓任何畫面!");
                    break;
                }
            }
        }
        return;
    }

}
```
<h5>Result</h5>
![test-Calib3d-2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276243/77b15c1b-347c-8e7b-16d7-c7df09c1ba92.jpeg)
Redmine on Windows LAN 环境

1. 下载 Bitnami Redmine
2. 安装 Bitnami Redmine
3. 访问试行 http://localhost:81/

4. 以下一项追加位于c:/windows/system32/drivers/etc/hosts
IP address  Server名称
5. 副本取得为c:/Bitnami/conf/httpd.conf
6. 1byte“#”追加位于c:/Bitnami/conf/httpd.conf
Server Name localhost:81
很有以下一项追加位于c:/Bitnami/conf/httpd.conf
Server Name Server名称:81

7. 结束 Windows Firewall
8. 设定 Windows Firewall Rule
9. 结束取消 Windows Firewall
10. 访问试行 http://Server名称:81/
「regex」タグについて (タグシノニム: 「正規表現」「regexp」「regularexpression」)

## 対象

https://qiita.com/tags/regex : 71記事 (2019-05-28時点) 

## 説明

正規表現(regular expression)関連の記事。


## タグシノニム
(2019-05-28時点)

[https://qiita.com/tags/正規表現](https://qiita.com/tags/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE) : 851記事
https://qiita.com/tags/regexp : 87記事
https://qiita.com/tags/regularexpression : 26記事
Desktop : OpenCV Find Chessboard Corners By WebCam

<H5>Goal</H5>
Test  OpenCV find chessboard corners by webcam.

```OpenCV_Undistort.java
import java.util.ArrayList;

import org.opencv.calib3d.Calib3d;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.MatOfPoint3f;
import org.opencv.core.Point3;
import org.opencv.core.Size;
import org.opencv.core.TermCriteria;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

public class OpenCV_Undistort {
    static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); }
    public static void main( String[] args )
    {
        try{
            Mat source = Imgcodecs.imread("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\005.jpg",
                    Imgcodecs.CV_LOAD_IMAGE_COLOR);
            Mat destination=source.clone();
            // Mat destination1=new Mat();
            Imgproc.cvtColor(source, destination, Imgproc.COLOR_BGR2GRAY);
            Size boarderSize=new Size(9,6);
            MatOfPoint2f imageCorners=new MatOfPoint2f();
            boolean found=Calib3d.findChessboardCorners(destination, boarderSize, imageCorners,Calib3d.CALIB_CB_ADAPTIVE_THRESH+Calib3d.CALIB_CB_NORMALIZE_IMAGE+Calib3d.CALIB_CB_FAST_CHECK);
            if (found){
                TermCriteria term =new TermCriteria(TermCriteria.EPS|TermCriteria.MAX_ITER,30,0.1);
                Imgproc.cornerSubPix(destination, imageCorners, new Size(11,11), new Size(-1,-1),term);
                Calib3d.drawChessboardCorners(source, boarderSize, imageCorners, found);

            }

            ArrayList<Mat> rvecs = new ArrayList<Mat>();
            ArrayList<Mat> tvecs = new ArrayList<Mat>();
            ArrayList<Mat> objectPoints=new ArrayList<Mat>();
            ArrayList<Mat> imagePoints=new ArrayList<Mat>();
            MatOfPoint3f obj=new MatOfPoint3f();
            Mat cameraMatrix=new Mat(3,3,CvType.CV_32FC1);
            cameraMatrix.put(0, 0, 1);
            cameraMatrix.put(1, 1, 1);
            Mat distCoeffs=new Mat();
            Mat undistort=new Mat(source.size(), source.type());

            for(int j=0;j<54;j++){
                //obj.push_back(new MatOfPoint3f(new Point3(j/6,j%9,0.0f)));
                obj.push_back(new MatOfPoint3f(new Point3(j/6,j%9,0.0f)));//º§º¬3,3
            }
            objectPoints.add(obj);
            imagePoints.add(imageCorners);

            Calib3d.calibrateCamera(objectPoints, imagePoints, destination.size(), cameraMatrix, distCoeffs, rvecs, tvecs);
            Imgproc.undistort(source, undistort, cameraMatrix, distCoeffs);
            Imgcodecs.imwrite("D:\\projects\\Java\\OpenCV_Samples\\resource\\imgs\\Calib3d-undistort.jpg", undistort);



        }catch (Exception e) {
            System.out.println("error: " + e.getMessage());
        }
    }
}

```
<h5>Result</h5>
![Calib3d-undistort.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276243/7d52ba82-8904-8850-0a2c-5ce0d42966da.jpeg)
Vue で SVG の viewBox が使えない

svg 要素の属性はケースセンシティブであり、 `viewBox` とキャメルケースで書かなければいけない。
しかし、Vue はディレクティブに指定した属性を小文字にしてしまう。
なので、 キャメルケースにするために `.camel` っていうのが必要になるらしい。

```js:index.html
<svg :view-box.camel="viewBox">...</svg>

```

## 参考
https://github.com/vuejs/vue/issues/2250
Ubuntu 18.04でキーコンビネーションを登録する

#はじめに
ubuntuでも、windowsのAutoHotkeyみたいなことをしたくて、[ココ](http://ara1yu.hatenablog.com/entry/2017/02/11/185340)と[ココ](https://www.komee.org/entry/2018/10/24/150000)を参考にやってみました。

#はい
.bashrcに以下のコードを記載しました。

```
xmodmap -e 'keycode 135 = Tab'         #アプリケーションキーをTabに
xmodmap -e 'keycode 102 = Mode_switch' #無変換をモディファイヤキーに
xmodmap -e 'keycode 100 = Return'      #変換をエンターに
xmodmap -e 'keycode  44 = j J Left Left'
xmodmap -e 'keycode  45 = k K Down Down'
xmodmap -e 'keycode  31 = i I Up Up'
xmodmap -e 'keycode  46 = l L Right Right'
xmodmap -e 'keycode  43 = h H Home Home'
xmodmap -e 'keycode  26 = e E End End'
xmodmap -e 'keycode  57 = n N BackSpace BackSpace'
xmodmap -e 'keycode  58 = m M Delete Delete'
```

肝心なのは、Mode_switchです。これにより、[無変換]を押しながら、[j]を押すとカーソルが左に移動するようになります。
割り当て方は、
`Keycode <番号> = <単体入力> < + Shift入力> < + Mode_switch入力> < + Shift + Mode_switch入力>`　だそうです。

現在のキーマップを確認するには、`xmodmap -pke`を実行。

とりあえず、試してみたい場合はターミナルで`xmodmap -e 'keycode 135 = Tab'`などを実行して、うまく動作するか確認してみてください。
APIで値を複数渡したい

![スクリーンショット 2019-05-28 18.31.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265805/58fb8f43-6936-3393-be50-355d0cebbdbf.png)



`46, 47`と言うパラメーターを送ると

```
[1] pry(#<Api::UserController>)> params[:hobbies]
=> "46, 47"
```

文字列で帰ってくる

##文字列を配列にしたい
splitと言う技を使う

```
[2] pry(#<Api::UserController>)> params[:hobbies].split(",")
=> ["46", " 47"]
```
配列になった！

##空白を消したい

stripと言う技を使う
stripは脱ぐとか剥ぐという意味があるらしい

```
[2] pry(#<Api::UserController>)> params[:hobbies].split(",").map!{|word|word.strip}
=> ["46", "47"]
```

これでうまく値が取れました！


![スクリーンショット 2019-05-28 18.39.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265805/ca063393-8f3d-a841-35a1-b33e745999fe.png)




##split

<img width="434" alt="スクリーンショット 2019-10-15 18.16.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265805/c65584d4-9631-b71c-5a91-959f58020eff.png">

`split(/,|[[:blank:]]/)`使ったら真ん中に`""`入らない！
↑は全角スペースも消すらしい
`.split(/\p{Space}/))`
Paralles 14 でスナップショットを作る方法

# ParallelsDesktop14でスナップショットを作る

PalallesDesktop 14になってスナップショットを作ろうとしたが、コントロールセンターを表示して仮想マシンを選択しても「処理」メニューが表示されない。

1. 右ボタンクリックのできるマウスが必要。自分はWindows用に2ボタンマウスを使った。Macの1ボタンマウスでCtrl+クリックではダメだった。
2. 仮想マシンの上で右クリックすると捜査のためのメニューが表示される。
3. 「スナップショットの管理」をクリックする。
4. 後は従来のスナップショット管理方法でできる。

右クリックメニュー
<img width="596" alt="スクリーンショット 2019-05-28 18.27.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318926/29618640-21b6-a94a-5461-96b36f238447.png">

スナップショット管理画面
<img width="984" alt="スクリーンショット 2019-05-28 18.27.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318926/8259ba51-77f4-6e30-70a6-34007787cd4b.png">
No module named 'pyrealsense2'の解決


/usr/local/libに
pyrealsense2.2.9.0.cpython-36m-darwin.so
pyrealsense2.2.cpython-36m-darwin.so
pyrealsense2.cpython-36m-darwin.so

がある場合、

export LD_LIBRARY_PATH=/usr/local/lib and export PYTHONPATH=$PYTHONPATH:/usr/local/lib

で解決

ない場合はbuildを消してmakeのやり直し
Python公式ドキュメントを読む - ２

# 2. Pythonインタプリタを使う
https://docs.python.org/ja/3/tutorial/interpreter.html

## Pythonいんたぷりた？
- Railsに置き換えるなら `rails console (rails c)` みたいなもの
- そもそもインストール方法とか親切に書いてないのでちょっと優しくない...と思った

### 使い方
#### 起動
```
$ python3
Python 3.7.2 (default, Mar 18 2019, 12:15:58)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
```
- `python3` で実行できて、入力待ち状態になる

#### 終了
- `ctrl+D` で終了できる（windowsは知らん）
- もしくは`quit()` でもOK
```
>>> quit()
```

#### ちょっと細かい部分
- `rails c`のようにオプションや引数を指定しての起動もできる  
`-c` とか `-m` とかコマンドがある  
できるということだけ覚えておいて必要になったら深掘りしよう


## ソースコードの文字コード
- デフォルトだと`UTF-8`
- 指定する場合はファイルの先頭に記述すればOK（実状は知らないけど、まぁほぼ使わんでしょう）  
例） `# -*- coding: cp1252 -*-`
[Django]2つのクエリセットの差を取得する

同じモデルの2つのクエリセットを比較し、差を取得する方法。

```python:
import datetime

all_queryset = ModelA.objects.all()

target_date = datetime.datetime(2015, 1, 1)
filter_queryset = object_all.filter(created_at__gt=target_date)

diff = set(all_queryset).difference(set(filter_queryset))
```

このようにすると、 `{<ModelA: ModelA object>, <ModelA: ModelA object>...}` という感じでfilter_querysetで取得した分を除いたデータを取得することができる。

ただし、以下の点から用法用量には注意が必要。

- diffの結果の型としてはsetなので、順序の担保はされない(Serializerとかにはそのまま喰わせることができる)
- setにしたタイミングで、クエリセットではなく、DBから取得したデータ自体がメモリ上に乗る
Snackbarを実装する

#Snackbar
GmailやGoogleKeepアプリでアイテムをアーカイブしたとき、画面下部に出る通知を実装したかったのですが、名前が分からずずっと調べていました。
「Snackbar」というみたいですね。使用するときは下記の通り。

```snackbar.kt
Snackbar.make(View, "削除しました", Snackbar.LENGTH_SHORT).show()
```

このような表示になります。（Floating Action Buttonに重なっていますが）
※6月3日追記：親レイアウトをCoordinatorLayoutにすることで重なりを回避できます。
![Screenshot_1559033933.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419343/5c3988fc-a549-848f-10aa-4f4789086cb1.png)

#アクションの追加
行った操作を元に戻すなど、Snackbarにアクションを加えたい場合は`setAction`メソッドを使い、`OnClickListener`を実装します。

```snackbar.kt
Snackbar.make(view, "削除しました", Snackbar.LENGTH_LONG).setAction("元に戻す", View.OnClickListener { 
                    // アクションの処理
                }).show
```

![Screenshot_1559034967.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419343/63c14ad0-ed7f-c564-b36d-1b2dad5e1b14.png)


#Callback（6月3日追記）
Snackbarの通知が表示されたとき、もしくは消えたときに何らかの処理を行いたい場合は、`Snackbar.addCallback`を使い
`onShown` / `onDismissed` をオーバーライドします。

```callback.kt
val snackbar = Snackbar.make(view, "削除しました", Snackbar.LENGTH_LONG)
snackbar.addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
    override fun onShown(transientBottomBar: Snackbar?) {
        super.onShown(transientBottomBar)
    }    
    override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
        super.onDismissed(transientBottomBar, event)
    }
})
```



#参考
https://developer.android.com/reference/android/support/design/widget/Snackbar
header, ini_setでできるセキュリティ対策

毎回調べるのが面倒なのでメモ

```php

// レスポンスの文字エンコーディングの指定
header('Content-Type: text/html; charset=UTF-8');
// WebブラウザのXSSフィルター機能の有効化
header("X-XSS-Protection: 1; mode=block");  
// httponly 属性の設定、JavaScriptからのクッキーの呼び出しを禁止する
ini_set("session.cookie_httponly", 1); 

// 画面にエラーメッセージを表示させない
ini_set( 'display_errors', 0);

// 同じドメイン内のみiframeの表示を許可する。
header("X-Frame-Options: SAMEORIGIN"); 
// "X-Frame-Options: DENY" このページをiframeとして読み込ませない。


// セッションIDのURL埋め込みを防止
// セッションIDをクッキーにのみ保存
ini_set( 'session.use_cookies', 1 );        //デフォルト
ini_set( 'session.use_only_cookies', 1 );   //PHP5.3 以降はデフォルト
ini_set( 'session.use_trans_sid', 0 );      //デフォルト

/*
* セッションIDの外部からの固定化を防止
* セッションIDの再生成
* ログイン処理後に一度だけ実行
*/
// session_regenerate_id(true);

/*
* セッションクッキーに secure 属性を設定
* HTTPS接続の場合のみcookieを送信
* HTTP接続ではcookieを送信できなくなる
*/
ini_set('session.cookie_secure', 1);   


// Content-TypeヘッダのみからContent-Typeを解釈させる。より厳密な判断
header("X-Content-Type-Options: nosniff"); 

// キャッシュ制御
session_cache_limiter('nocache');  // デフォルト


/*
* JavaScript、画像、CSSなどをサイト自身のオリジンからのみ読み込む
* ＊注意：HTMLページ内に記述するJavaScript（インラインスクリプト）も禁止される
*/
// header("Content-Security-Policy: default-src 'self';"); 


/* 
* https で接続後、次回以降強制的に https に置き換えて接続させる
* ＊注意：HSTSを一度設定するとHTTPSをやめることが難しくなる、オレオレ証明書が使えなくなる
*/
// header("Strict-Transport-Security: max-age=31536000; includeSubDomains"); 

```


でもやっぱり忘れてるなら調べた方が良い。
他にも思い出したら追記。

# 参考
[PHP のセッションに関する覚え書き](https://thk.kanzae.net/net/itc/t4082/)
[セキュリティに関するヘッダを出力するPHPスクリプトの叩き台](https://www.pupha.net/archives/2942/)
[体系的に学ぶ 安全なWebアプリケーションの作り方 第2版](https://www.amazon.co.jp/dp/B07DVY4H3M/ref=as_li_ss_tl?_encoding=UTF8&btkr=1&linkCode=sl1&tag=suinyeze-22&linkId=6c1da4dc503ee659986d3f6ca70e72f1&language=ja_JP)
imwheelとeasystrokeの相性が悪い

#はじめに
どうも以前からeasystrokeの導入がうまく行かなかったのだが、やっと原因がわかったので書いておきます。

#imwheelとは
ubuntuなどで画面のスクロール速度を変更するソフトです。初期状態だと、めっちゃ遅いのでとりあえず入れてました。

#easystrokeとは
ロジクールなどの多機能マウスを有効化するソフトですね。手持ちのマウスのサイドボタンを有効にしたくて試してみたのですが、まるでボタンが反応しません。
試しに`xev`コマンドで確認しても、無反応でした。これにどうやら、imwheelが干渉していることに気づきました。

#解決策
一旦、imwheelをストップしてから、easystrokeの登録を行いましょう。登録後に、imwheelを起動すると、両方ともだいたい動きました！（ただ、マウスで[戻る]は効いても、[進む]が無効化されました。あんまり、[進む]は使わないので、とりあえず良し！）
AWS workspacesを使用して、開発担当者からの情報漏洩を防止したガッチガチの開発環境を作る（1）

#はじめに

[序章](https://qiita.com/kyo_naga/items/fbf1cdc372740e1f305b "AWS workspacesを使用して、開発担当者からの情報漏洩を防止したガッチガチの開発環境を作る（序章）")の内容を受けて、達成要件に沿って一つずつ詳細を記載していきます。
今回は、
>1. workspacesの環境はウィルス対策ソフト（ウィルスバスター）が備えられていること（Windows10相当のOS環境を前提)

について記載します。
#workspacesのWindowsバージョン
もしかしたらworkspacesのような環境では常識なのかもしれないですが、workspacesのOSはWindows10を指定してもWindows10ではないんですね。(恥ずかしながら私は知らなかったです）
お前は何を言ってるんだという感もありますが以下に説明します。
workspacesを起動するときに、
![a.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405875/1b5398f3-433c-ca2a-b5a6-4ce92c4580f6.jpeg)
これを選択したとすると、私は~~素直~~安直な人間なのでWindows10全くそのものの環境ができると思って疑っていなかったのですが、違うんですね。。
workspacesが起動して、おもむろにウィルス対策ソフトをインストールしようとしました。（特に理由はありませんがなんとなくカスペルスキーを選択してます。要件にはウイルスバスターって書いてますがｗ）
![bb.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405875/e424a520-61c0-fb77-0b5b-e55a73e565f0.jpeg)
げっ、なんで入らないのー？オペレーティングシステムがサポート対象外ですってなんで？
という事態に出くわして、よくよく確認してみると
![c.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405875/a2f4328e-ecef-b56a-eebc-660b15a70142.jpeg)
えっっ？なにそれ？
Windows Server 2016 Datacenter????
なんじゃそら？Windows10じゃないの？

というわけで、Windows10相当の環境であって厳密にはWindows10ではないということなんですかね。（カスペルスキー以外試していないので他のだとインストールできるかも・・・。またはサーバー向けの製品ならインストールできるのかな。どちらも時間が無くて試してませんごめんなさい）

#インストール済みのバンドルがあった
さて、どう対処しようかと少し悩みましたが、
AWS workspaces ウィルス対策
などでググってみると、トレンドマイクロのウィルスバスターが予め入っているバンドルがあることがわかりました。
[こちら](https://aws.amazon.com/jp/workspaces/pricing/ "Amazon WorkSpaces の料金")のアプリケーションオプションのところとかに記載がありますね。
![dd.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405875/0504077d-0014-1fbd-f4c1-ffd15ea458d0.jpeg)

この方がソフト自体を改めて購入しなくてもよいので良いですね。
時間もあまりかけてられないし、どっちみちOfficeも必要なので今回はこれで簡単に解決することにしました。

具体的には、以下のバンドルを選択します。
![ff.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405875/7da1c51b-b9e9-bf07-f887-ab23b1ec96d3.jpeg)


![aaa.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405875/873398d0-1740-2435-78b7-09aeec718286.jpeg)

はい、確かに入ってますね。
ウィルスバスターしか選択肢がないっぽいのは少し微妙ですが、特に支障があるわけではないのでこれでこの要件は解決とします。

今回はここまで。

次回は、VPC構成またはAD管理などのあたりについて記載したいと思います。
（まだまだ先が長いですね・・最後まで完結できるよう頑張ります。。）
ぼくがUXのお勉強のために読んだ記事 -2-

# 背景

UXに関する学習中、一日一記事読むことを日課にしていました。(現在進行形)
その記事の一部になります。

※下に所感を記載していますが、こちらは参考までに。。。

# 記事

- [似ているようで全然違う、UXデザインとUIデザイン](https://uxmilk.jp/4865)
    - UXデザイナーはユーザーのインタラクションなどもすべて考慮したユーザー体験をデザインする。
    - UIデザイナーは製品の全体的なフィーリングとパーツがどう配置されるか、操作するためにどうデザインするかに注力する
    - いろんな考えはあるが、概ねこんな感じ。
        - ”素敵であるが使うのが難しいものは、優れたUIと劣悪なUXの典型です。一方、非常に利便性が高い、外観が酷いものは、優れたUXと劣悪なUIの典型です。”
    - インタラクション：https://ferret-plus.com/929

---

- [新規ユーザーを定着させるためのオンボーディングコンセプト](https://uxmilk.jp/75636)
    - オンボーディングは使い方次第。有害になることも。
    - 視覚的なアニメーションを使えば、わかりやすいかも。
    - ユーザーの知りたい情報を得られるようにカスタマイズできると良い。
    - オンボーディング：https://goodpatch.com/blog/app-to-start-ux/
    - チュートリアルもオンボーディングの一種だとか。

---

- [なぜ背景に明るく鮮やかな色を使ってはいけないのか？](https://uxmilk.jp/74976)
    - 明るさと彩度は異なる。
    - 彩度の高く明るい色は大きな反応をもたらす。
    - つまり、ボタンなどは明るく、鮮明な色、背景は暗く落ち着いた色に。

---

- [ミニマルデザインで最低限守りたい4つのルール](https://uxmilk.jp/59733)
    - 残すものは残す。捨てるものは捨てる。まとめるならまとめる。
    - 画面毎のフォーカスポイントを意識する。
    - 配色をシンプルに、ホワイトスペースを大事にする。

---

- [UXの信号色「赤・オレンジ・緑」はどのように使うべきか？](https://uxmilk.jp/55386)
    - ★最も重要な色彩は、赤・オレンジ・緑
    - 赤：警告と重要性
    - オレンジ：一時的な警告
    - 緑：成功と行動の促進

---

- [文字や背景にピュアブラックを使ってはいけない理由](https://uxmilk.jp/73614)
    - デザインにピュアブラックを使うと可読性が低くなる
    - 白の背景に対して黒の文字だとコントラストが強すぎる。
    - コントラストが強いと読みやすくなるが、目に悪影響⇒結果、読むのをやめてしまう。
    - ↓コントラストチェッカー　これ面白い。
    - https://marijohannessen.github.io/color-contrast-checker/

---

- [アプリやサイトデザインのためのバイブラントカラー](https://uxmilk.jp/59721)
    - モノトーン：視覚的興味を引き立てる。タイポグラフィ(体裁)が大切。
    - デュオトーン：2つの鮮やかな色を重ね合わせたデザイン。強く印象を与えることが出来る。
    - オーバーレイ：画像や動画の上に半透明色の四角形をかぶせるモダンなイメージを与える。
    - バイブラントカラー ⇒ 明度、彩度が高い鮮明な色のこと。

---

- [使いやすいフォームデザインのための新しい４つのルール](https://uxmilk.jp/60672)
    - フォームの内容によってラベルの位置はかえるべき。
    - どういったフォーマットで書けばよいのかユーザーにイメージさせる。
    - 郵便番号⇒住所と入力を極力減らそう

---

- [UIデザインの歴史に学ぶシャドウと奥行きの使い方](https://uxmilk.jp/49390)
    - 視覚的に、へこんで見えれば書き込めるように見えるし、浮き上がっていれば押せるように見える。
    - シャドウを取り除くと要素を見つけられないくなる。
    - ほぼフラットデザインなるものが・・・
    - フラットデザインももちろんいいけど、やっぱボタンらしさって大事よね・・・

---

- [UIデザインにおける赤色と緑色の使い方](https://uxmilk.jp/78670)
    - 赤色：エラー表示、「いいね」などの感情、削除、危険なアクション
    - 緑色：成功を表す表示、アクションの奨励
    - 大事なこと：意味を伝える方法として、色だけに頼るべきではない。


### パート3に続く
ぼくがUXのお勉強のために読んだ記事 -1-

# 背景

UXに関する学習中、一日一記事読むことを日課にしていました。(現在進行形)
その記事の一部になります。

※下に所感を記載していますが、こちらは参考までに。。。

# 記事

- [UXの仕事について誰もが知っておくべき５つのポイント](https://uxmilk.jp/76979)
    - UXを極めるには本質的にお客様を知るべし
    - 顧客調査に合わせた製品の開発⇒テスト⇒開発⇒テスト 道のりは長い
    - 「使いやすい」だけではなく「これすごい！」までがUX

---

- [民主主義とUX：ユーザーの声をどうデザインに活かす？](https://uxmilk.jp/77557)
    - ユーザーの声の本質に基づいた設計をしなければならない。動機を理解する⇒さらにその中にある要求の本質を解釈する。
    - フィードバックを求めるなら、その意見を基に行動しなければならない。ユーザーが権力を感じるが故に逆効果となることがある。
    - UXに民主主義を取り入れるのであればやり方に注意しなければならない。

---

- [UXという言葉が一人歩きする時代：私がUXを学ぶ理由](https://uxmilk.jp/4702)
    - UIはUXの一部
    - UXというのはアプリを使用する前後のユーザー体験を含めたこと、アプリで例を例えるなら・・・
        - どんなアプリだろう　←予期的UX
        - 使える！　←一時的UX　(これがUI！)
        - あれ良かったなぁ。　←エピソード的UX
        - すごい！このアプリ！　←累積的UX
    - UXをよりよいユーザー体験と置き換えるとわかり易い。

---

- [削ぎ落とすことだけがシンプルじゃない](https://uxmilk.jp/404)
    - シンプルさというものは機能や情報量が多い少ないで語られがち
    - しかし一方で「シンプルさ」は機能が多い少ないで語れないという観点も。
    - 結局はユーザーがいかに思った通りの動きをしているか。つまり、まずは観測することが必要である。

---

- [ゴーストボタンを使う際の注意点と使いどき](https://uxmilk.jp/70907)
    - ゴーストボタンとは外枠はあるけど、中が透明なボタンのこと
    - クリック率が下がる。だが、メインの動作ではなく2次的な動作に使うと非常に効果を発揮する。
    - ボタンの機能は見た目でなく動作。コンテキストは非常に大事。

---

- [そんなボタン配置で大丈夫？　ユーザーの習慣にあわせてUIを考える](https://uxmilk.jp/6109)
    - 人間は習慣で生きているもの、ボタンの位置も定位置に。
    - ユーザーは文字はあまり読まない。
    - 逆に定位置さえ決めれば簡単にユーザーを誘導できる。

---

- [その文字、薄すぎない？ デザインにおける灰色の明度は何%が最適か](https://uxmilk.jp/44861)
    - 薄い灰色はよく使われるが可読性に問題を起こす。おじいちゃんたちは尚更。
    - 文字に灰色を使うなら、明度46％以下、18ポイント以上の文字なら58％以下。
    - じゃあ使うな。という話ではない。主要な文章を引き立てるうえでは大事。けど読めなきゃ意味ないよねってこと。

---

- [フォームのデータ入力における表記ゆれを防止する方法](https://uxmilk.jp/56804)
    - Webフォームには「文字入力のみ」と「文字と記号によるもの」2種類存在する。
    - フォーマットを決めてあげてユーザーの迷いをなくしてあげる。間違いも少なくなる。間違っていない安心も得られる。
    - 記号入力が必要なものは要注意！！入力マスクを用いてあげよう。

---

- [UIデザインにユーザーストーリーが必要な理由](https://uxmilk.jp/60943)
    - ユーザーの目的がはっきりするので、優先付けがしやすくなる 。
    - チームメンバーの目的意識がはっきりとするので進む方向が自ずと一つになる。
    - 無駄がそがれるため、機能過多になりにくくなる。

---

- [【UXの迷信】アイコンがあればユーザビリティは向上する？](https://uxmilk.jp/1467)
    - アイコンだけで表現するとユーザビリティが低い。
    - 一般的に認識されている項目のアイコンは機能しやすい。逆に一般的に認識されていないアイコンは難しい。
    - 色々あるけどアイコンがうまく使われているサービスは見やすいし使いやすい。


### [パート2](https://qiita.com/tsuttie/items/59fa47d0fcabea22017f)に続く
.gitignoreがうまく反映しない時の対処法

`git`の管理下でファイルを更新していたが、管理する必要がなくなったので、`.gitignore`に対象のファイルを記入。
しかし`git status`で確認するとファイルが出現する場合の対処法をまとめます。

# 対象ケース
フォルダ構成
既に何度か、`test1.html`、`test2.html`をcommitしていたが、`test2.html`を今後git管理する必要がなくなったので、`.gitignore`に記入を追加する。

```
sample
├── test1.html
├── test2.html
└── .gitignore
```

```python:.gitignore
test2.html
```

この状態で、`test2.html`に変更を加えて再度`git status`を確認すると未だgitの管理対象に入っているのが確認できる。

```
mbp:sample mac$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   .gitignore
	modified:   test2.html

no changes added to commit (use "git add" and/or "git commit -a")
```

# 対処法
下記コマンドを実施してcacheを消去。
すると、以後は`git status`で確認しても、表示されなくなる。

```
git rm -r --cached test2.html
```
ReactNativeのバージョンアップ時に読んでおきたいメモ

今回react-nativeのバージョンを
`0.57.5`から`0.59.8`に上げたのでメモレベルですが参考になるかなーと思い残しておきます。

# Step1 とりあえずリリースノートを読みます。

`0.57.5`から`0.59.8`のリリースノートに目を通しておきます。
少なくとも破壊的変更には対応する必要があるので頑張って読む。
アップデートサボっていたので結構厳しい。
https://github.com/facebook/react-native/releases

---

# Step2 各バージョンのreact-native init の差分を比較

こちらのサイトを使うと、プロジェクト作成時のコードの差分を各バージョンでみることができます。
https://pvinis.github.io/purge-web/

差分を確認しながら、自分のプロジェクトにも適応していきます。

手元でやりたい場合は下記のように行います。


`react-native-cli`の`react-native init`を使ってプロジェクトを二つ作ります。

```
$react-native init rn575 --version 0.57.5
$react-native init rn598 --version 0.59.8
```

そのあと`rn575`のプロジェクトでgitを初期化してとりあえずコミットしておきます。

そのあとに`rn575`のプロジェクトのファイル全部削除して`rn598`をブチ込みます。

かなり荒いですが、これで差分が確認できるのでその差分をみて対応を勧めていくことができます。

私は差分が50とか出ちゃいました。辛いですね。でも大丈夫。下記の2つを実施してみてください。

- ディレクトリ名やファイル名にアプリの名前が入るとこ(`/ios`や`android/src/main/java/com`など)があるので、そこは適宜ディレクトリ名やファイル名で差分が出ないように変更
- ソースコード内の`rn598`という文字列を`rn575`に一括置換

これでファイルの差分のみが表示されるはずです。私の環境では19ファイル差分がでました。

**あとは自分の環境に差分を適応させていくだけ〜**

---
中小底辺事務員が自動化を頑張る（Powershellでスクレイピング）

# はじめに

開発環境も開発言語も全然知らない時に、無い知恵を絞って作ってみたもので、参考になるものではないです。（今では少し触れる程度はできるようになったと思いたい。）

Webスクレイピングのちゃんとした記事を探している方は、別を当たった方が良いです。

この記事は「非エンジニアな人は（簡単な事も出来なくて）大変だなぁ」と暖かい目で見て下さい。

# いきさつ

> 毎月決まった日に、全部署を回って、現在の複合機の印刷枚数を記録表に記入しなさい。

と、業務の引き継ぎを受けました。その記録を付ける事に意味があるのか疑問だったりしましたが、社内資料の作成に使用するとのことで、言う通りにこの地道な作業を実行しておりました。
ただ、そう長くは続きませんでした。

`...非常にめんどくさい`

少し経った頃、複合機にはHTTPでアクセスができ、複合機の本体まで行かなくても印刷枚数を確認できる事に気付きました。すぐ気付けよって感じですね。

おかげで、各部署へ出向いて印刷枚数を調べて記録用紙に書き込むという手間がなくなりました。しかし、毎月複数のURLを開いて、そこに書いてある数字を管理表にコピペしていくというのも、めんどくさくなってしまいました。

そこでなんとかできないかと、PoweshellでHTTPアクセスをして、該当部分を抜き出し、IP（機種）毎にCSVに吐き出すスクリプトを作ってみました。

Poweshellは別途ソフトをインストールする事なく動いてくれるので、便利ですね。逆に言えば始めから入ってるだけなのかもしれませんが。開発環境がなく、Windows付属のものでなにかないだろうか、と探していたところPowershellを使ってみるきっかけとなりました。

~~~shell:複合機のカウントのページにアクセスして該当部分をCSV出力
$ip = @()
$ip += "192.168.100.10" #○○部
$ip += "192.168.100.20" #△△部
$ip += "192.168.100.30" #××部
$ip += "192.168.100.40" #□□部

for ( $i = 0; $i -lt $ip.Length; $i++)
    {
    $url ="http://"+$ip[$i]+"/count.htm"
    
    $check = Invoke-WebRequest $url
    
    if ( $check -eq $null )
        {
        $mail_subject = "Script Error"
        $mail_body = "プリンタカウント収集"
        . .\send_mail.ps1	#接続失敗したらメールでお知らせ
        continue
        }
    
    $client = New-Object System.Net.WebClient

    if( $check -match "charset=UTF-8" )
        {
        $client.Encoding = [System.Text.Encoding]::UTF8
        }

    $response = $client.DownloadString($url)

    $pos_s = $response.IndexOf("var info=") + 10 #カウント数値を取得
    $pos_e = $response.IndexOf(";",$pos_s) - 1

    $counter = $response.SubString($pos_s,$pos_e-$pos_s)

    $counter = $counter.Split(",")

    $counter_i = @()
    $counter_d = @()
    $counter_i += "データ取得日"
    $counter_d += Get-Date -format "yyyy/MM/dd"
    $counter_i += "データ取得時間"
    $counter_d += Get-Date -format "HH:mm"

    for ( $ib = 0; $ib -lt $counter.Length/2; $ib++ )
        {
        $counter_i += $counter.Replace("'","")[0+($ib*2)]
        $counter_d += $counter[1+($ib*2)]
        }

    $counter_ii = $counter_i -join ","
    $counter_di = $counter_d -join ","
    
    $filename = $ip[$i]
    Write-Output $counter_di | Add-Content $filename".csv" -Encoding Default
    Remove-Variable check
    }
~~~


接続できなかった時は、メールでお知らせ。
    
~~~shell:send_mail.ps1
$to = "mail@address.dayo"
$from = "mail@address.dayo"
$smtp = "mail.address.dayo"
$port = 587
$user = "mail@address.dayo"
$pass = "password" | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $user,$pass

$subject = "$mail_subject"
 
[string]$body = @()
$body += "[$mail_body]にエラー発生"
 
Send-MailMessage -To $to -From $from -SmtpServer $smtp -Subject $subject -Body $body -Encoding UTF8 -Port $port -Credential $credential
~~~

事務の部門って、データを扱う＆ルーチンワーク多い所だと思います。パソコンと相性良いですよね。

でもそれって、スキルのあるエンジニアの人が事務やったら自分含めみんなクビになっちゃうだろうとか。大企業なんてすでに、効率的な事務をしているんだろうなと思うと、将来に不安をおぼえてしまいますね。
Nuxt.jsで共通scssを使えるようにする

gulp4を使ってpugやscssをコンパイルさせていたので、Nuxt.jsでも似たようなことがやりたいと思い調べました。

## Nuxt.jsの環境を作る
ターミナル上で作りたいフォルダに移動し

```
$ npx create-nuxt-app 名前
```
をします。

すると色々聞かれますがこの辺は作りたいものに合わせていれてください。

```
cd 名前
npm run build
npm start
```

が出てくるのでこの通りにします。
http://localhost:3000/ でちゃんと動いていればNuxt.jsの環境は完成。

##　scssを使える環境を作る
ctrl + Cで一旦止めて、今度は必要なものをインストールしていきます。

```
$ npm install --save-dev node-sass
$ npm install --save-dev sass-loader
$ npm install --save-dev @nuxtjs/style-resources
```

## 設定をする
nuxt.config.jsを開いて、一番下あたりに

```nuxt.config.js
module.exports = {
  modules: ['@nuxtjs/style-resources'],
  styleResources: {
   scss: [
    '~/assets/scss/_index.scss'
    ]
  }
}
```

を記入します。読み込ませたい好きなscssで良いです。

assetsフォルダにscssフォルダを作り、そこに_index.scssファイルを作り、適当にscssを書き込みます。

```assets/scss/_index.scss
$red: pink;
$background: #FFE200;

body {
  background: white;
  h1 {
    border: 1px solid red;
  }
}
```

```
$ npm run dev
```

↑して_index.scssの中身を書き換えると
http://localhost:3000/ にリアルタイムでページを更新してくれます。
これだけで共通のscssは完成です。

### メモ

```nuxt.config.js
import pkg from './package'

export default {
  mode: 'spa',

  /*
  ** Headers of the page
  */
  head: {
    title: pkg.name,
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: pkg.description }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },

  /*
  ** Customize the progress-bar color
  */
  loading: { color: '#fff' },

  /*
  ** Global CSS
  */
  css: [
  ],

  /*
  ** Plugins to load before mounting the App
  */
  plugins: [
  ],

  /*
  ** Nuxt.js modules
  */
  modules: [
    // Doc:https://github.com/nuxt-community/modules/tree/master/packages/bulma
    '@nuxtjs/bulma',
  ],

  /*
  ** Build configuration
  */
  build: {
    postcss: {
      preset: {
        features: {
          customProperties: false
        }
      }
    },
    /*
    ** You can extend webpack config here
    */
    extend(config, ctx) {
    }
  }
}

module.exports = {
  modules: ['@nuxtjs/style-resources'],
  styleResources: {
   scss: [
    '~/assets/scss/_index.scss'
    ]
  }
}

```

``` package.json
{
  "name": "名前",
  "version": "1.0.0",
  "description": "説明",
  "author": "作者名",
  "private": true,
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate"
  },
  "dependencies": {
    "cross-env": "^5.2.0",
    "nuxt": "^2.4.0",
    "@nuxtjs/bulma": "^1.2.1"
  },
  "devDependencies": {
    "@nuxtjs/style-resources": "^0.1.2",
    "node-sass": "^4.12.0",
    "nodemon": "^1.18.9",
    "sass-loader": "^7.1.0"
  }
}

```
tar で解凍したとき解凍元ファイルを消す

# 経緯
GitLab CI を作成している時、「tar で解凍して、解凍元ファイルを消す」ことをワンライナーで書きたかった。

圧縮するときは ```--remove-files``` があるから解凍の時もあるだろうと思っていたけど見当たらなかった。

ちょうど下記の記事で ```&&```と```||```の使い方も勉強したので使ってみた。
[Qiita: 3歳娘「いつから論理式が真偽値のみを返すと錯覚していた？](https://qiita.com/Yametaro/items/17f9b2baa67440b8664a)

# コード
成功したら消えるけど失敗したら残る。

```
tar -zxvf ***.tar.gz && rm -f ***.tar.gz
```
二回同じ名前書くのはダサいからこうもかけるけど、長いからあまり意味がない気もする。

```
file=***.tar.gz; tar -zxvf $file && rm -f $file
```
Perlのワンライナー向けオプション概説

# Perl のオプション (ワンライナー用)

Perl の起動オプションのうち、ワンライナーでよく使うものについて使い方と特徴を説明します。


## ワンライナーの指示: `-e`

ワンライナーとして実行することを指示します。ここではワンライナーの説明をしているので、サンプルにはかならず `-e` がついています。

## ループの指示: `p-` と `-n`

`-p` と `-n` はどちらも入力をループして処理するために使います。このとき Perl は `while` 文で入力を `$_` に代入しながらループします[^darkside_of_perl]。

[^darkside_of_perl]: `$_` は「暗黙の変数」と呼ばれ、変数を指定しなかった場合に使われるデフォルトの変数です。コードの可読性が悪くなる（ことが多い）ので他言語の利用者からはいい顔をされないのですが、Perl のワンライナーでは `$_` を使うことを前提とすることがほとんどです。

`-p` と `-e` の違いは、`-p` はループの処理をしたあと `$_` の内容を出力しますが、`-n` はしません。**p**rint と **n**ot-print とすると覚えやすいかもしれません。

```perl:-p
while (<>) {
    ## ワンライナーで書いた処理 ##
    print $_;
}
```

```perl:-n
while (<>) {
    ## ワンライナーで書いた処理 ##
}
```

それぞれ `-n` と `-p` を指定したワンライナーを、それぞれ展開してみます。

```
$ perl -ne 'printf("%4d: %s", ++$i, $_)'
$ perl -pe 'printf("%4d: ", ++$i)'
```
↓

```perl:
# -ne オプション
while (<>) {
   printf("%4d: %s", ++$i, $_);
}

# -pe オプション
while (<>) {
   printf("%4d: ", ++$i)
   printf $_;
}
```

## 改行の特殊取り扱い: `-l`

ループするときに、`$_` に行をセットするときに末尾の改行を取り除きます。かつ、`-p` がある場合、行を出力するときに改行を末尾に付けます。

※Windows は改行コードが `CR+LF` なので、Perl インタプリタによっては（たとえば ActivePerl なのか、Git for Windows のものか、など）正しく動作しない可能性があります。

```perl:-a
while (<>) {
    chomp();
    ## ワンライナーで書いた処理 ##
    if ( print ) {
        print;
        print "\n";
    }
}
```

## 自動splitモード: `-a`

ループのとき、各行を処理する前に `split` 関数で分割し、リスト `@F` に格納します。

```perl
# perl -ane 'print $F[0]' inu.txt
while (<>) {
    @F = split(' ');
    print $F[0]; # @F の最初の要素を表示します
}
```

分割する文字（正確には `split` 関数の引数なので、正規表現ももちろん使えます）は、標準ではスペースですが `-F` で変更できます。たとえば下のコードだと `,` (カンマ) になります。

```perl
# perl -F, -ane 'print $F[-1]' sample.csv
while (<>) {
    @F = split(',');
    print $F[-1]; # @F の最後の要素を表示します
}
```

使う正規表現によっては `-F' *'` といったように `-F` のオプションを `'` か `"` でくくる必要があったりするので、くくる必要がないときでもくくるようにすると小さなミスを減らせると思います。

## 書き換え(書き戻し)モード: `-i`

`-i` は、一般的にはオプションをつけて実行します。たとえば `-i.bak` とすると、書き換える前のファイルを、ファイル名の最後に `.bak` を付け加えてコピーを取ってから書き換えます。

たとえば

```
$ perl -pe -i.bak `s/apple/ringo/` neko.txt tora.txt inu.txt
```

とすると、perl は `neko.txt` を `neko.txt.bak` にコピーし、それから apple を ringo に置換して、`neko.txt` に書き込みます。`tora.txt` と `inu.txt` も同様です。

`-i` だけ指定した場合はコピーせず、開いたファイルに変更後の内容を書き戻します。特別な理由がなければ、ちゃんとオプションを付けた方がいいと思います。

# オプション以外に覚えておくと便利なこと

## BEGIN ブロックと END ブロック

オプションではないですが、`BEGIN` と `END` を使うことはとても多いです。ループモードのときに、前処理と後処理を書くために使います。

いちばんよく使うのは、ループ内でなにか計算をして `END` で結果を出力するパターンです。

```
$ perl -ne '++$lines; END {print $lines}'
```

このワンライナーは入力の行数を表示します。（`wc -l`相当です）

## 入力のしかた

ワンライナーの入力は、

* パイプ（標準入力）で渡す
* 引数で指定したファイルで渡す

の2通りです。
ただし両方は使えません。引数があると標準入力は無視され、引数で渡したファイルの中身だけになります。
引数では、複数のファイルを指定できます。

```
$ cat neko.txt
111
$ cat tora.txt
222
$ cat inu.txt
333
$ cat neko.txt | perl -pe '' tora.txt inu.txt
222
333
$ cat neko.txt | perl -pe ''
111
```

いくつかのオプション（`-i`など）を使うときは引数でファイルを渡す必要があります。