OmniAICreator/Qiita-1.07M huggingface dataset:
[Ruby]Google Calendar APIから日程を取得しよう

※順次更新していきます。

#1　サービスアカウントの作成
[Google develop](https://console.developers.google.com/)にアクセスして[APIとサービスの有効化]をクリック。
[Google Calendar API]を有効にします。 
そのままホームページの指示にしたがって入力していきます。
そしたらjson形式のファイルがダウンロードされると思います。

#2　Googleカレンダーとサービスアカウントの連携
[APIとサービス⇨認証情報⇨サービスアカウントの管理]をクリック
以下のようなページ表が出てくることと思います。
<img width="1118" alt="スクリーンショット 2018-06-11 23.13.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/134708/94562814-6c96-92c9-fb99-0be91767ea9d.png">
メールの下に記入されているメールアドレスをコピーします。

次に、共有させたいGoogleCalendarを開き、[特定のユーザーとの共有]のところ(以下の画面)に先ほどコピーしたメールアドレスを貼り付けます。
<img width="492" alt="スクリーンショット 2018-06-11 23.18.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/134708/0519b26a-dfbd-a00f-83d6-a7fe8869d676.png">


#3　実装
```ruby:app.rb
require 'bundler/setup'
Bundler.require

APPLICATION_NAME = '「２で出てきたサービスアカウント管理の中の名前」'
MY_CALENDAR_ID = '「連動させたカレンダーのID」'
CLIENT_SECRET_PATH = '「ダウンロードしたjsonのパス」'

class Calendar
  def initialize
    @service = Google::Apis::CalendarV3::CalendarService.new
    @service.client_options.application_name = APPLICATION_NAME
    @service.authorization = authorize
    @calendar_id = MY_CALENDAR_ID
  end

  def authorize
    authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
      json_key_io: File.open(CLIENT_SECRET_PATH),
      scope: Google::Apis::CalendarV3::AUTH_CALENDAR)
    authorizer.fetch_access_token!
    authorizer
  end

  def test
    events = @service.list_events(@calendar_id,
                                    time_min: (Time.now - 365.days).iso8601,
                                    time_max: (Time.now + 365.days).iso8601,
                                   )
    puts "Calendar name: #{events.summary}"
    events.items.each do |event|
      time = if event.start.date.present?
               "#{event.start.date.to_s}〜#{event.end.date.to_s}"
             else
               "#{event.start.date_time.to_date} #{event.start.date_time.strftime('%-k:%M')}〜#{event.end.date_time.to_date} #{event.end.date_time.strftime('%-k:%M')}"
             end
      puts "#{time} :::: #{event.summary} at #{event.location}"
    end
  end
end

Calendar.new.test

```
#error

jsonがうまく引っかかっていないと以下のようなエラーが出た。
jsonのパスを確認しよう

```
 `fetch_access_token': Authorization failed.  Server message: (Signet::AuthorizationError)
{
"error": "invalid_grant",
"error_description": "Invalid JWT Signature."
}
```

#参考文献
[LINEBOTからGoogleカレンダーを取得する](https://qiita.com/LunaChevalier/items/f9c1a10cb5a1db753eae)
Mermaid - GitBook > Gantt Chart + Family Tree

### 要望

- 年代を記載
- 親子関係を記載


### Mermaid

https://mermaidjs.github.io/
にて作成。

- ガントチャートで年代を記載
- 親子関係は色で記載
    - done, active, crit, done, active, crit,...

```
gantt
  title Animation companies

  section 虫プロダクション(旧) 1961.6-1973.11
  マッドハウス(1972.10-): done, 1972-10-01, 2018-06-11
  トライアングルスタッフ(1987.1-): active, 1987-01-01, 2018-06-11
  ACGT(2000.12-): crit, 2000-12-01, 2018-06-11
  ノーマッド(2003.7-): active, 2003-07-01, 2018-06-11
  MAPPA(2011.6-): active, 2011-06-01, 2018-06-11
  イマジン(1992.6-): done, 1992-06-01, 2018-06-11
  グループ・タック(1968.3-2010.8): done, 1968-03-01, 2010-08-01
  ディオメディア(2005.10-): active, 2005-10-01, 2018-06-11
  サテライト(1995.12-): active, 1995-12-01, 2018-06-11
  シャフト(1975.9-): done, 1975-09-01, 2018-06-11
```

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/039409d2-6d58-8f26-c236-c557c86126ed.png)

[Link to view](https://mermaidjs.github.io/mermaid-live-editor/#/view/eyJjb2RlIjoiZ2FudHRcbiAgdGl0bGUgQW5pbWF0aW9uIGNvbXBhbmllc1xuXG4gIHNlY3Rpb24g6Jmr44OX44Ot44OA44Kv44K344On44OzKOaXpykgMTk2MS42LTE5NzMuMTFcbiAg44Oe44OD44OJ44OP44Km44K5KDE5NzIuMTAtKTogZG9uZSwgMTk3Mi0xMC0wMSwgMjAxOC0wNi0xMVxuICDjg4jjg6njgqTjgqLjg7PjgrDjg6vjgrnjgr_jg4Pjg5UoMTk4Ny4xLSk6IGFjdGl2ZSwgMTk4Ny0wMS0wMSwgMjAxOC0wNi0xMVxuICBBQ0dUKDIwMDAuMTItKTogY3JpdCwgMjAwMC0xMi0wMSwgMjAxOC0wNi0xMVxuICDjg47jg7zjg57jg4Pjg4koMjAwMy43LSk6IGFjdGl2ZSwgMjAwMy0wNy0wMSwgMjAxOC0wNi0xMVxuICBNQVBQQSgyMDExLjYtKTogYWN0aXZlLCAyMDExLTA2LTAxLCAyMDE4LTA2LTExXG4gIOOCpOODnuOCuOODsygxOTkyLjYtKTogZG9uZSwgMTk5Mi0wNi0wMSwgMjAxOC0wNi0xMVxuICDjgrDjg6vjg7zjg5fjg7vjgr_jg4Pjgq8oMTk2OC4zLTIwMTAuOCk6IGRvbmUsIDE5NjgtMDMtMDEsIDIwMTAtMDgtMDFcbiAg44OH44Kj44Kq44Oh44OH44Kj44KiKDIwMDUuMTAtKTogYWN0aXZlLCAyMDA1LTEwLTAxLCAyMDE4LTA2LTExXG4gIOOCteODhuODqeOCpOODiCgxOTk1LjEyLSk6IGFjdGl2ZSwgMTk5NS0xMi0wMSwgMjAxOC0wNi0xMVxuICDjgrfjg6Pjg5Xjg4goMTk3NS45LSk6IGRvbmUsIDE5NzUtMDktMDEsIDIwMTgtMDYtMTEiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9fQ)

- 色は親子関係を表す
    - 同じ代は同じ色
- 直上の別の色が親を表す
    - 別の同じ代の子も別の色なので、まぎらわしい
        - 例: ACGT

Sectionを分けることで、虫プロダクション以外の親も扱える。
僕がお世話になったアジャイル開発の古典4冊

こちらの[成り上がりたくて必死に読んだ感謝の技術書6冊](https://qiita.com/kurkuru/items/97a90e3c267bd127af9b)という記事を読んで、そういえば僕も15年前に初めてアジャイル開発を始めた時、いくつかお世話になった本があったなと懐かしく思い出したので書いてみます。アジャイル開発が当たり前になった今のエンジニアの皆さんからすると古典に分類されるかもしれませんが、僕の目にかかっていた鱗を何十枚も剥がしてくれた名著たちでした。

エクストリーム・プログラミング（ケント・ベック）
一番最初に読んだアジャイル開発の本です。根底に流れる「変化ヲ受容セヨ」というメッセージに、突然目の前が開けたような気がしたことを覚えています。いくつものプラクティスがありますが、僕が特に重視していたのは反復すること、テストを書くこと、リファクタリングすることの3つでした。これは15年経ったいまも変わっていません。今でも、テストコードを書くことに対して工数が増えるという勘違いからテストを開発プロセスの中に組み込まないチームがあります。しかしそういったチームは、「手動でデバッグする工数とどれだけ違うんですか？それ何回繰り返せます？」という問いかけに答えられません。ここにあるプラクティスを試しに実践してみれば分かるはずなのに。小さく始めたプロジェクトを、テストとリファクタリングを繰り返し、品質を確保したまま徐々に大きく広げていく。これは経営層がみんな大好きPDCAなんだけど、その辺りがまだまだ現場から遠いところにいる人には理解されてない気がします。

リファクタリング（マーチン・ファウラー）
リファクタリングは、コードにきな臭さを感じたら実施するという説明を初めて読んだとき、何を言っているのかさっぱり分かりませんでした。しかし、テストを書いて実行しグリーンランプをキープし続けながらコードの中身を洗練していくことを繰り返していると、徐々に分かってきます。気持ち悪いというかムズムズするというか、リファクタリングの神が舞い降りてくる瞬間が。この本にはいくつものリファクタリングの手順が記載されていますが、それらは全てテストコードが書かれていて、コードを洗練してもクラスの振る舞いが変わらないことが保証できる前提です。リファクタリングのタイミングが神学論争にならないようにしたければ、CheckStyle、PMD、Findbugsなどの静的／動的解析ツール、ClovaやOpenCoverなどのカバレッジ計測ツールの結果を参考にするのも良いと思います。匂いを数字で知ることができるかもしれません。

Java言語で学ぶデザインパターン入門（結城浩）
Javaで自前のXMLソケット通信サーバーを作るときに、TomcatやStrutsのソースコードを読み解きながらどうすればいいのか悩みながら、常に手元におき何周も読んでボロボロにした本。15年経った今でも手元に置いて時折読み返しています。この中で特に好んで使うパターンは、Factory、Command、Facadeかな。あと Chain of responsibility は検証ロジックを動的に構成したいときに1度だけ使いました。マルチスレッド編にあるTwo phase terminateはみなしごスレッドを作らないためには必須のパターンだと思いますし、Futureパターンはasync/awaitを理解するのにとても役立つと思います。一度だけ、自分でこのパターンを実装したことがありますが、僕自身はFire and Forgetの方が楽で好きです😁

実践UML―パターンによる統一プロセスガイド（クレイグ・ラーマン）
ものすごく分厚く重い本ですが、通勤電車の中で1ヶ月間に3周くらい読み返しました。要求というあやふやなものをどのようにしてUMLのダイアグラムで設計として表現し、実際に動くコードに落とし込んでいくかという手順が明確かつ詳細に記述されています。当時僕は、IBM RationalのUPとXPとの間で揺れている時期だったのですが、この本を精読したあとXPを選択し後にSCRUMへと移っていきます。XPを選択はしましたが、この本のおかげでデザインパターンの選択と適用、フレームワークの重要性、データの永続性などを理解し、それらをアーキテクチャとしてコードに落とし込めるようになったことは大きな転換点になりました。このときに作り上げたソケット通信サーバーフレームワークのアーキテクチャは、JavaからC#に言語が変わった今も生き続けています。

2003年頃の開発環境を参考までに載せておきます。AntとMavenで継続的インテグレーションを行っていたのも今となっては良い思い出です。

Java：Java2 SDK 1.4.2
IDE： Eclipse
バージョン管理：CVS
ビルドツール：Maven、Ant
情報共有：MoinMoin (Wiki)
課題管理：Scarab
プロジェクト管理：XPlanner
ドキュメント：JavaDoc + aurigadoclet (JavaDoc to PDF)
Rubyで言語処理100本ノック 第2章: UNIXコマンドの基礎 (10 ~ 13)

[言語処理100本ノック](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の挑戦記録です。

今回から、第2章: UNIXコマンドの基礎です！

> hightemp.txtは，日本の最高気温の記録を「都道府県」「地点」「℃」「日」のタブ区切り形式で格納したファイルである．
以下の処理を行うプログラムを作成し，hightemp.txtを入力ファイルとして実行せよ．
さらに，同様の処理をUNIXコマンドでも実行し，プログラムの実行結果を確認せよ．

# 10. 行数のカウント
> 行数をカウントせよ．確認にはwcコマンドを用いよ．

``` ruby:Ruby 
file_path = "hightemp.txt"

puts File.read(file_path).count("\n")
```
``` shell:shell
cat hightemp.txt | wc -l
```

``` ruby:結果
24
```

# 11. タブをスペースに置換
> タブ1文字につきスペース1文字に置換せよ．
確認にはsedコマンド，trコマンド，もしくはexpandコマンドを用いよ．

``` ruby:Ruby
file_path = "hightemp.txt"

File.open(file_path) do |file|
  file.each_line do |line|
    puts line.gsub("\t", " ")
  end
end
```

今回はtrコマンドでやってみました。

``` shell:shell
cat hightemp.txt | tr '\t' ' '
```

# 12. 1列目をcol1.txtに，2列目をcol2.txtに保存
>各行の1列目だけを抜き出したものをcol1.txtに，
2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ．
確認にはcutコマンドを用いよ．

``` ruby:Ruby
file_path = "hightemp.txt"
prefectures = []
cities = []

File.open(file_path) do |file|
  file.each_line do |line|
    prefectures << line.split("\t")[0]
    cities << line.split("\t")[1]
  end
end

File.open("col1.txt", "w") do |file|
  file.puts prefectures
end

File.open("col2.txt", "w") do |file|
  file.puts cities
end
```

``` shell:shell
cut -f 1 hightemp.txt
cut -f 2 hightemp.txt
```

``` :結果
# col1.txt

高知県
埼玉県
岐阜県
山形県
山梨県
和歌山県
静岡県
山梨県
埼玉県
群馬県
群馬県
愛知県
千葉県
静岡県
愛媛県
山形県
岐阜県
群馬県
千葉県
埼玉県
大阪府
山梨県

# col2.txt

江川崎
熊谷
多治見
山形
甲府
かつらぎ
天竜
勝沼
越谷
館林
上里見
愛西
牛久
佐久間
宇和島
酒田
美濃
前橋
茂原
鳩山
豊中
大月
鶴岡
名古屋
```

# 13. col1.txtとcol2.txtをマージ
>12で作ったcol1.txtとcol2.txtを結合し，元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ．確認にはpasteコマンドを用いよ．

``` ruby:Ruby
prefectures = File.readlines("col1.txt").map(&:chomp)
cities = File.readlines("col2.txt").map(&:chomp)

pref_cities = [prefectures, cities].transpose.map{ |row| row.join("\t") }

File.open("pref_cities.txt", "w") do |file|
  file.puts pref_cities
end
```
``` shell:shell
paste -d "\t"  col1.txt col2.txt
```
``` shell:結果
高知県	江川崎
埼玉県	熊谷
岐阜県	多治見
山形県	山形
山梨県	甲府
和歌山県	かつらぎ
静岡県	天竜
山梨県	勝沼
埼玉県	越谷
群馬県	館林
群馬県	上里見
愛知県	愛西
千葉県	牛久
静岡県	佐久間
愛媛県	宇和島
山形県	酒田
岐阜県	美濃
群馬県	前橋
千葉県	茂原
埼玉県	鳩山
大阪府	豊中
山梨県	大月
山形県	鶴岡
愛知県	名古屋
```


UNIXコマンドも勉強しなければ...!
はじめてのxinetd


LPIC 102試験の勉強中。

ftpをsystemdでなくxinetdで起動してみる。

## install ftp
一番ハマったのがftp側の設定。

適当に触ったときに `hoge=NO` を `hoge=NO ` と後ろにスペースを入れたら起動しなくて起動しなくて.... 

古いライブラリはそういう気持ちで付き合いましょう。	

（通信チェックだけなら別にftp loginできなくてもいいので、サービス起動さえしてればよかったりする。悔しかったので。）

まずftpサービスを起動する
	
```py
# install
yum install -y vsftpd ftp

# ftpサーバの設定
vim /etc/vsftpd/vsftpd.conf

# listenを有効にする
listen=YES
#listen=NO

# ipv6コメントアウト
#listen_ipv6=YES

# 一番下にこれを追加
userlist_deny=NO
```

ログインユーザの設定

```py
# rootで使えるようにする
vim /etc/vsftpd/ftpusers

root の行をコメントアウトする

#root

# 起動して試す
systemctl start vsftpd && systemctl status vsftpd
```

ここで起動中のport, processの関係を見ておく

```py
# port状況を確認
[root@cent70 vsftpd]# netstat -na  | grep 21
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN     

# processのリレーションを確認
[root@cent70 vsftpd]# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        └─vsftpd
```

systemdの下にvsftpdが起動しているのがわかる。ここがxinetdでは変わるはず。

次に、ここにftp接続されるとpstreeがどう変わるか見ていく。systemdなftpに接続してみる。

```py
# ftp 接続してみる
ftp localhost
Name: root            # ここで Name: と来ていればftp通信はできてることになる
Password: ***        # rootの普通のpassword, sshで使ったりするやつ

ftp> dir        # ファイル一覧出ればok
```

この接続中のpstreeを別terminalから確認する。

```py
[root@cent70 vsftpd]# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        └─vsftpd───vsftpd───vsftpd
```

`systemd`の下にvsftpdが連なって何個も起動している。


# xinetdを設定していく
こちらを参考にした

> http://d.hatena.ne.jp/sin-j/20080812/1218512584

まずvsftpdを止める

```py
systemctl stop vsftpd

# port が消えたか確認
[root@cent70 vsftpd]# netstat -na  | grep 21
なし
```

vsftpdのlistenを無効にしておく

```py
vim /etc/vsftpd/vsftpd.conf
#listen=YES
listen=NO
```


xinetdにvsftpd用の設定を作る

```py
vim /etc/xinetd.d/vsftpd 

# default: off
# description: The vsftpd FTP server serves FTP connections. It uses \
#       normal, unencrypted usernames and passwords for authentication.
service ftp
{
        socket_type             = stream
        wait                    = no
        user                    = root
        server                  = /usr/sbin/vsftpd
        server_args             = /etc/vsftpd/vsftpd.conf
        nice                    = 10
        disable                 = no
        flags                   = IPv4
}
```


xinetdを起動

```py
systemctl start xinetd && systemctl status xinetd
```

ポートとプロセスをチェク！

```py
[root@cent70 vsftpd]# netstat -na  | grep 21
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN     

[root@cent70 vsftpd]# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        └─xinetd
```

ポートが空いてる & xinetd がプロセスに変わっています！

ではftp接続してftpをxinetd経由で起動してみよう


```py
# ftp 接続してみる
ftp localhost
Name: root            # ここで Name: と来ていればftp通信はできてることになる
Password: ***        # rootの普通のpassword, sshで使ったりするやつ

ftp> dir        # ファイル一覧出ればok
```

接続したままの状態で `pstree` を見てみよう！

```py
[root@cent70 xinetd.d]# pstree
systemd─┬─ModemManager───2*[{ModemManager}]
        └─xinetd───vsftpd───vsftpd
```

ｷﾀ━━━━(ﾟ∀ﾟ)━━━━!! xinetd が親の形でvsftpdが連なっています！


# まとめ

xinetdを使うと vsftpc が単体でlistenしなくてよくなった

でも結局xinetdがport開けっぱなしでlistenするのね。その瞬間だけ開く、とかじゃないのか...

サービス起動なんて大した負荷じゃないし今のサーバだとほんと意味なさそう。。。

inetdをインストールしようとしたらxinetdが入ったのでこれをやった。inetdはどうやってcent7で試すんだろう。。。
gitのエラー　fatal: remote origin already existsの解決方法


## 勉強になったサイト
http://labs.timedia.co.jp/2012/10/git-update-branch-without-checkout.html

# git エラーの内容

```
$ git remote add origin https://github.com/ユーザ名/リポジトリ名.git
fatal: remote origin already exists.
```
なぜこのようなエラーになるのか。ということで検索したら、以下のページを見て解決できた。
http://pyoonn.hatenablog.com/entry/2014/10/29/191744

一度originを削除し、再度originを登録すればよい。

```
$ git remote rm origin
$ git remote add origin git@github.com:ユーザ名/リポジトリ名.git
```

自分の場合は、githubのリモートリポジトリをローカルリポジトリに反映させたかったので、この後に以下の命令を行った。

```
$ git pull origin master
```
UbuntuのGUIで表示されるDNSサーバーと、実際使用しているDNSサーバーが違った



GUIのWIFIアイコンから表示できるPrimaly DNSサーバーには、
`/etc/resolv.conf`の`nameserver `に記載したIPは表示されない。

IPアドレスでウェブサイトにアクセスできるけど、ドメイン名でアクセスできないから、
DNSが原因だと思い、GUIから見ると正しい指定になっていた。
`resolv.conf`で別のDNSサーバーが指定されていたので変更して解決。

GUIにも反映されるものだと思っていた。


<img width="241" alt="スクリーンショット 2018-06-11 22.49.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/162167/d01cace6-c2ef-5cef-6fd5-4ea0eb738358.png">

<img width="300" alt="スクリーンショット 2018-06-11 22.49.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/162167/2801f0f5-8a41-5536-70bf-3f5877c8e145.png">
PostCSSでCSSの中の画像URLのcache busteringを行う方法

CSSの中で背景画像を指定したいとき、次のように書く。

```css
background-image: url('/img/stamp-blank.png');
```

でもこのままだと、例えば画像の配信で何かしらのキャッシュが設定されていた場合（`Cache-Control`のHTTPヘッダーなど）に、画像を変更してもキャッシュが使用されてすぐに変更をクライアント側に反映できない。

そこでcache busteringを行う。URLの末尾に何かしらのクエリーストリングなどを付けて別のURLにすることで、ブラウザーのキャッシュを回避する方法だ。

```css
background-image: url('/img/stamp-blank.png?version=20180611');
```

上のように変更すれば、新しい画像がブラウザーに読み込まれるようになる。

でも画像の変更があるたびにいちいちCSSをいじるのは面倒なので、自動化したい。そこでPostCSSのプラグインである[PostCSS Cachebuster](https://github.com/glebmachine/postcss-cachebuster)を使ってみる。

導入は簡単に `yarn add -D postcss-cachebuster` なり `npm install --save-dev postcss-cachebuster` なりで。

CSSのプリプロセッサーとしてSassを、タスクランナーにgulp.jsを使っている場合の `gulpfile.js` だと、こんな感じになる（例ではautoprefixerも使っている）。webpackなどでも同様の記述が可能。

```js:gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass');
const moduleImporter = require('sass-module-importer');
const postcss = require('gulp-postcss');
const cachebuster = require('postcss-cachebuster');
const autoprefixer = require('autoprefixer');

const paths = {
  sass: ['assets/sass/**/*.scss', 'assets/sass/**/*.sass'],
};

gulp.task('sass', () => {
  gulp.src(paths.sass)
    .pipe(sass({
      outputStyle: 'compressed',
      importer: moduleImporter(),
    }))
    .on('error', (err) => {
      return console.log(err.stack);
    })
    .pipe(postcss([
      cachebuster({
        type: 'checksum',
        imagesPath: '/public',
      }),
      autoprefixer({
        browsers: ['last 2 versions', 'ie >= 11', 'Android >= 4'],
        cascade: false,
        remove: false,
      }),
    ]))
    .pipe(gulp.dest('public/css'));
});
```

実行すると、次のようにCSSとして出力される。

```css
background-image: url("/img/stamp-blank.png?vcf88ba6129bc045a4937410004e6106b");
```

`type` で `checksum` を指定することで、画像ファイルのMD5ハッシュが付加されるようになる（指定しない場合は `mtime` となり、ファイルの更新時刻ベースの文字列が付加される）。

詳しい使い方はリポジトリーのREADMEを読むか、それほど長いコードではないので処理の中身を読んだ方が早いと思う。

- [glebmachine/postcss-cachebuster: Cachebusting all local files in css](https://github.com/glebmachine/postcss-cachebuster)
ホワイトボードでサッとアイデア交換。WEB会議で使えるツール。

Web会議などで、簡単にだれかと一緒にホワイトボードを共有できる、一緒にかけるWebサービスを比較。

●Wimy
・アカウント登録不要
・超シンプル少し機能に物足りなさはある。が、ただのメモ書きなら全然良い。
・他と違って複数ページ作成可能なノート形式がさりげに良い。スペースの工面に困ったり、どこに書いたかわからないということがなく議論しやすい。
・PDFで１ファイルに保存できる
https://wimy.design

●realtimeboard
・アカウント登録必要
・いちいちチームの作成とかだるい
・多機能なUIは簡単なメモ書きには向かない。じっくりきれいな資料を作るには良い。
・ロードが遅い
https://realtimeboard.com/

●deekit
・ほぼrealtimeboardと同じ。シェイプの選択方法などが少し独特で、さらに難しい（初心者殺し）かも。
https://www.deekit.com/

●whiteboardfox
・アカウント登録不要なのは楽でいい
・機能がシンプルで使い勝手は良い
・でかい画像１枚でしか保存できない
・デザインがダサい
https://whiteboardfox.com/

以上。
簡単にすぐだれかと一緒にという筆者の用途ならWimyがおすすめ。
windowsファイル移動して移動先のリンクを残すC#コード

> ファイルサーバがいっぱいで書けなくて困ったので、
使ってなさそうなものを別のとこに移動し
他の人がこまらないように移動先のショートカットを作成するコードを書いた
[リンクの作り方参考ありがとうdobon.net](https://dobon.net/vb/dotnet/file/createshortcut.html)

```cs
/*　
　～自動ファイル移動スクリプト～

	特定フォルダから拡張子指定でのファイルをピックアップし
	ファイルツリーを保持したまま別フォルダに移動する。(コピー後消去）
	移動後はファイル移動先のショートカットを残す。
*/

//--------------------
// 設定
//--------------------

var deleteFile = true;
var createLink = true;

var fitypeTarget = ".zip";
var diTargets = new DirectoryInfo(@"\\fs1\hoge");
var bkupToDiTop = new DirectoryInfo(@"\\fs2\bkup\");

//--------------------
// 処理
//--------------------

//対象ファイル取得
var fiTargets = diTargets
	.EnumerateFiles("*", SearchOption.AllDirectories)
	.Where(t => t.Name.ToLower().EndsWith(fitypeTarget))
	;//.Take(1);

//元ファイルとコピー先を取得
var targets = fiTargets.Select(
	t => new KeyValuePair<FileInfo, FileInfo>(
			t, new FileInfo( Path.Combine(bkupToDiTop.FullName + Regex.Replace(t.FullName, @"^\\\\", @"\")) )
		)
	);

Func<FileInfo, FileInfo, FileInfo> linkFi = (fi, toFi) => {
	try {
		if (createLink) {
			var shortcutPath = fi.FullName + ".lnk";
			var targetPath = toFi.FullName;

			var t = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8"));
			dynamic wsh = Activator.CreateInstance(t);
			var shortcut = wsh.CreateShortcut(shortcutPath);
			shortcut.TargetPath = targetPath;
			shortcut.Save();

			System.Runtime.InteropServices.Marshal.FinalReleaseComObject(shortcut);
			System.Runtime.InteropServices.Marshal.FinalReleaseComObject(wsh);
			return new FileInfo(fi.FullName + ".lnk");
		}
		return new FileInfo(fi.FullName);
	} catch (Exception) {
		return null;
	}
};

Func<FileInfo, FileInfo, FileInfo> copyAndLinkFi = (fi, toFi) => {
	try {
		Console.WriteLine(fi.FullName);
		if(!toFi.Directory.Exists){
			toFi.Directory.Create();
		}
		fi.CopyTo(toFi.FullName, true);
		if (deleteFile) {
			Console.WriteLine("Delete: " + fi.FullName);
			fi.Delete();
		}
		return linkFi(fi, toFi);
	} catch (Exception) {
		return null;
	}
};

var results = targets.AsParallel()
	.Select(t => copyAndLinkFi(t.Key, t.Value))
	.Select(t => t.FullName);

Console.WriteLine( "Finish. linkfile:" + results.Count() );

```
FlutterでSharedPreferences(非同期)の値によって使用するWidgetを切り替える方法

アプリを開発しているとアプリの初回起動時に初期化処理をしたいというユースケースが頻繁にあると思います。
ネイティブの開発ではSharedPreferencesやUserDefaultsで起動するActivityやUIViewControllerを切り替える方法をとってきました。
Flutterも同じ方法でやろうとしたところ、FlutterのSharedPreferencesはインスタンスの取得が非同期だったので、一工夫必要でした。

`build`関数の戻り値を直接Widgetにするのでなく、`FutureBuilder`でラップすることで非同期コードの結果に応じて、使用するWidgetを切り替えることが可能です。
ただし注意点として非同期コードの結果が取得される前の状態(`hasData==null`)の場合のWidgetも返却する必要があります。

アプリ初期化のユースケースを例にしたサンプルコードは次のようになります。

```dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:shared_preferences/shared_preferences.dart';

class App extends StatefulWidget {
  @override
  State createState() => new AppState();
}

class AppState extends State<App> {
  Future<bool>getIsInitialized() async{
    final sharedPreferences = await SharedPreferences.getInstance();
    bool isInitialized = sharedPreferences.getBool("isInitialized");
    if (isInitialized == null) {
      print("isInitialized is null");
      isInitialized = false;
    }
    return isInitialized;
  }
  @override
  Widget build(BuildContext context) {
    // FutureBuilderでラップする
    return new FutureBuilder(
        future: getIsInitialized(),
        builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
          print(snapshot);
          // hasData==nullの場合とはgetIsInitializedのレスポンスを取得できる状態になる前
          // この場合もWidgetの返却がひつようなので、とりあえずインジケーターを設定しておく
          final hasData = snapshot.hasData;
          print("hasData:$hasData");
          if (hasData == false) {
            return CircularProgressIndicator();
          }

          // アプリの初期化状態を取得
          final isInitialized = snapshot.data;
          print("isInitialized:$isInitialized");
          var homeWidget;
          if (isInitialized) {
            homeWidget = MainScreenWidget(); // 初期化済みならメインスクリーンを表示
          } else {
            homeWidget = InitializeScreenWidget(); // 初期化スクリーンを表示
          }
          var app = new MaterialApp(
            title: "Couple Todo",
            home: homeWidget,
          );
          return app;
        });
  }
}
```
Windowsのコマンドプロンプトをcmderに置き換えて使いやすくした

コマンドプロンプトが使いづらいので、cmderを導入し、コマンドも変更して使いやすくした。

## インストール
[公式サイト](http://cmder.net/)からcmderをダウンロード。

## コマンドの置き換え
1.現状の設定を確認

```cmder
doskey /macros
```

2.aliasを設定

```cmder
doskey pwd = dir
doskey ls = dir
doskey mkdir = md $*
doskey mv = move $*
doskey rm = del $*
doskey mv = move $*
doskey cp = copy $*
doskey rm = del $*
doskey cat = type $*
```

3.macros.txtファイルに書き出し

```cmder
doskey /macros > %USERPROFILE%\macros.txt
```

4.cmderの起動時パラメータとして以下を設定

```
& doskey /macrofile=%USERPROFILE%\macros.txt
```

## 参考
[参考サイト](https://qiita.com/little_hand_s/items/91d6bcb680eba10da835)
数値計算は expr より awk  の方が速いみたい。

## 記事を書いた背景 ##
サーバーの運用などしていると昔の担当者が書いたであろうスクリプトやバッチの改善を余儀なくされる場合があります。

過去にやった改善ではインプットとアウトプットを変更せず、処理速度を改善してほしいというものがあり、各処理ごとにどれぐらい時間がかかっているかデバッグしながら効果的なものに対して対策を打ちました。

検討した対策としては、

  * for　文の処理を違う表現にしてみる
    * for　文で一行ずつ読んでいた表現を　read　で読み込むように変更する
    * expr で計算していた処理を　awk　で書き直す
  * シーケンシャルになっている処理を分散して処理できるように書き直す

ここでは、expr を awk に書き直して状況が改善されたため、それを紹介します。
結論だけ言えば、expr を awk に書き直すだけで5000倍近く速くなりました。

## サンプルデータの作成と確認 ##
適当な数字が書かれた1000行のファイルを用意します。

```
$ for i in `seq 0 999`; do echo $RANDOM >> foo.txt ; done

$ wc -l foo.txt 
    1000 foo.txt

$ head foo.txt
17376
21053
22754
20430
27812
5486
19801
27289
6166
15766

```

## 一行ずつ数値を読み取り合算するスクリプトを書いてみる ##
### bash ###
```
#!/bin/bash
date +"%Y/%m/%d %p %I:%M:%S"
FILE="foo.txt"
SUM=0
while read line;
do
   SUM=`expr $SUM + $line`
done < $FILE

echo "合計: ${SUM}"
date +"%Y/%m/%d %p %I:%M:%S"
```

### awk ###
```
#!/bin/bash
date +"%Y/%m/%d %p %I:%M:%S"
FILE="foo.txt"

awk '{s += $1} END {print "合計: " s}' < $FILE

date +"%Y/%m/%d %p %I:%M:%S"
```

## 実行結果1　##
expr では13秒ぐらいかかる処理が　awk で計算したら1秒かからず処理が完了しました。

```
$ ./bash.sh 
2018/06/11 PM 09:15:07
合計: 16637437
2018/06/11 PM 09:15:20

$ ./awk.sh 
2018/06/11 PM 09:15:36
合計: 16637437
2018/06/11 PM 09:15:36
```
## 実行結果2 ##
本番環境では1000行で済むようなログなどはないと思うので思い切って、10000000行のランダムな数値のファイルを作成し、awk で計算してみました。

```
$ for i in `seq 0 9999999`; do echo $RANDOM >> hoge.txt ; done;

$ wc -l hoge.txt 
 10000000 hoge.txt

$ ls -lh hoge.txt 
-rw-r--r--  1 XXXXXX  XXXXXX    54M  6 11 20:00 hoge.txt

$ head hoge.txt 
21202
1033
21589
5015
19402
31833
14415
15814
26142
32752

$ cat awk2.sh
#!/bin/bash
date +"%Y/%m/%d %p %I:%M:%S"
FILE="hoge.txt"

awk '{s += $1} END {print "合計: " s}' < $FILE

date +"%Y/%m/%d %p %I:%M:%S"
```

だいたい54MBのファイルに対して7秒ぐらいで処理が完了しました。
昔作られたスクリプトで不用意に expr が使われている場合は awk に処理を書き換えた方が速いかもしれません。

```
$ ./awk2.sh 
2018/06/11 PM 09:47:34
合計: 163856314744
2018/06/11 PM 09:47:41
```
C#でdiffしたい（データ差分を抽出したい）


データの更新処理で、データがたくさんあるので差分を抽出して処理時間を節約したい
⇒ コレクションオブジェクトの差分を抽出する

※diffをしたいと言ったが、本物のdiffのようなデータの場所が変わっても追跡するようなものは求めていない
今回は単純に配列の変更前後のdiffが取れればよい。可変配列ではなく固定配列の比較である。

## LinqのExceptメソッド
> 2つのシーケンスの差集合を返すメソッド
> 差分は取れるが、インデックスがないので、どこのデータが変わったかわからない

```cs
var refer  = new object[]{1,  "b", "c","d",  null};
var target = new object[]{"a","b",true,"D","hoge"};

var exp = target.Except(refer)
	.Dump("Except");
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/145884/19d51fe2-9c75-919c-f123-2d3e49f30d1e.png)


## LinqでIndex付きSelectしてEqualする

```cs
var refer  = new object[]{1,  "b", "c","d",  null};
var target = new object[]{"a","b",true,"D","hoge"};

var dif = target
	.Select( (v,idx) => v.Equals(refer[idx]) ? "" : v)　//差分なしは何を返せばいいのか? nullは嫌だ
	.Dump("myDiff");
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/145884/58979375-bce3-89da-2bfc-8ed898e3a2f3.png)

---
**c# diff** でググったら自分のゴミ記事がトップに出る（汗
というわけでまじめにdiffする方法を追記する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145884/ab816b07-8529-0934-5f88-c93e055b874b.png)

もちろん自前ではできないのでgoogle先生が作ってくれたライブラリ *diff-match-patch* を使う
https://github.com/google/diff-match-patch/wiki/Language:-C%23
nugetで取れる（pocketberserkerさん　ありがとう）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145884/6e6f0ec6-c8d3-1a63-e1d4-e6f8c3f237ea.png)
https://github.com/pocketberserker/Diff.Match.Patch

## diff-match-patchの使い方
> 比較したいテキストを２つ与えるだけでOK

```csharp
	var dmp = DiffMatchPatchModule.Default;
	var diffs = dmp.DiffMain(text1,text2);
	var html = dmp.DiffPrettyHtml(diffs);
```

## LINQPadで使ってみた

>　3Dプリンタtrinus向けのgcodeをレーザー出力に変えたい
※gcode改造はまだ完成していない。差分が見たいなと思ってググったら自分の記事がトップに・・・


### 使ってみた結果は以下
* 差分を可視化したHTMLがもらえる
* 比較結果のリストがもらえる（Delete,Equal,Insert)
* パッチももらえる（試してない）
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145884/2c984dff-2ddb-bae7-29a3-54b6971277ab.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145884/314f3b9e-018c-a31b-da2d-325dfca56656.png)

### LINQPadの実行コード

```csharp
Func<string[], IEnumerable<string>> throwDontNeeds = (ss) => {

	var needs = ss.ToList().FindAll(f =>
	!f.StartsWith(";   ", StringComparison.Ordinal)
	&& !f.StartsWith("M106", StringComparison.Ordinal)
	&& !f.StartsWith("M140", StringComparison.Ordinal)
	&& !f.StartsWith("M190", StringComparison.Ordinal)
	&& !f.StartsWith("M104", StringComparison.Ordinal)
	&& !f.StartsWith("M109", StringComparison.Ordinal)
	&& !f.StartsWith("G1 E", StringComparison.Ordinal)
	);

	var reps = needs.Select(s =>
		Regex.Replace(s, "E.*|F.*", "")
		+ (s.StartsWith("G1")?"E60":"")
	);

	var dmp = DiffMatchPatchModule.Default;
	var diffs = dmp.DiffMain(string.Join(Environment.NewLine, needs), string.Join(Environment.NewLine, reps));
	var html = dmp.DiffPrettyHtml(diffs);

	diffs.Dump();
	Util.RawHtml(html).Dump();

	return reps;
};

var gcodes = throwDontNeeds(
	File.ReadAllLines(@"C:\Users\wato\Documents\_work\eda\ex127.gcode")
).Dump();
```
はじめてのGAS - Slackにファイルを送る

Google Apps Script(以後、GAS)から、Slackのチャンネルにファイルを送る方法です。

ここでは以下の説明は省略します。（別記事を書く予定）
- [GASプロジェクトの作成方法](https://qiita.com/RyutaKojima/items/a526176ecd2f810e578a)
- GAS環境変数の設定方法
- Slackの操作方法
- Slack Appの登録方法

# ソースコード

```javascript
/**
 * 呼び出しテスト
*/
function testFile() {
  const channel = "xxxxxxxx";
  const content = "ファイルの中身だよー\nほげほげー";
  
  postFileToSlackChannel(channel, content);
}

/* 
 * FileをSlackチャンネルにポストする関数
 */
function postFileToSlackChannel(channel, content){
  var payload = {
    "token" : PropertiesService.getScriptProperties().getProperty('SlackOAuthAccessToken'),
    "channels" : channel,
    'content' : content,
    'filename':"sample.txt",
    'initial_comment': "ファイルにつけるコメント",
    'title': "Slack上でのファイルのタイトル"
  };
  var options = {
    "method" : "post",
    'contentType': 'application/x-www-form-urlencoded',
    "payload" : payload
  };
  
  var response = UrlFetchApp.fetch("https://slack.com/api/files.upload", options);
  Logger.log(response);
}
```

↓`SlackOAuthAccessToken` はココに表示されている値です。
![ã__ã_£ã__ã__ã_£.png](https://qiita-image-store.s3.amazonaws.com/0/87995/c21d1705-1652-3f8f-8565-39cfb9dd7368.png)


# 設定

OAuth & Permissions > Scopes から、以下の権限追加が必要
`files:write:user`

# 参考リンク

- [GAS - UrlFetchApp.fetch](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app)
- [Slack - files.upload](https://api.slack.com/methods/files.upload)
【Java】リストの要素がnullもしくは空であることをチェックしたい【CollectionUtils】

最近、ソースレビューばっかりやってるんですが、リストのnull・空チェックを頑張ってくれている子が立て続けに出たので、「もしかして意外と知らないのかも？」と思い、まとめてみました。

## 解答１）頑張ったやり方
最近よく私がレビュー指摘を入れた「頑張ったチェック」はこんな感じ:arrow_down:

```java:頑張った処理
List<String> strList = new ArrayList<String>();
// strListがどこかで定義されていたりメソッドの引数で入ってきたりしているとして・・・

if (strList == null || strList.size() == 0) {
  return true;
}
```

うん、あってる。
null＆サイズチェックが出来れば、とりあえずつまらないnullPointerExceptionは回避できる。
4～6月ごろの新人研修だと、この書き方ができれば合格 :white_flower: 

## 解答２）スマートなやり方

Javaには（Javaに限らずプログラミング言語にはたいてい）便利な外部ライブラリがたくさん揃ってます。
有名ドコだと「org.apache.commons」とか。
今回はorg.apache.commonsを使ってスマートに書いてみます。

```java:スマートな処理
import org.apache.commons.collections4.*

List<String> strList = new ArrayList<String>();
// strListがどこかで定義されていたりメソッドの引数で入ってきたりしているとして・・・

if (CollectionUtils.isEmpty(strList)) {
  return true;
}
```

注目すべきはif文の中:exclamation:
外部ライブラリの１つである「Apache Commons Collections」を使いました。
※2018/06/11時点での最新のドキュメントはこちら :arrow_right: から[Apache Commons Collections 4.1 API](http://commons.apache.org/proper/commons-collections/javadocs/api-release/index.html)

Apache Commons CollectionsはJavaのCollection系を便利に扱うライブラリで、この中にnullチェックとサイズ０チェックをまとめてやってくれる```CollectionUtils.isEmpty()```があるのです！

# 注意！
外部ファイルなので、Javaを普通にインストールしただけでは使えません:cry:
ダウンロードして読み込ませる必要があります。

eclipseだと、CollectionUtilsを入力補完したときにimport候補に```org.apache.commons.collections4.*```が出てくれば、読み込み済みと判断できます。
ただ、たいていのJava案件ではほぼ導入されてます、多分。

# まとめ
Listのnull・空チェックは、```CollectionUtils.isEmpty()```使うとすっきり書ける :pencil2:
ただし、Apache Commons Collectionsを事前に読み込んでいることが条件です。
Javaで簡易htmlspecialchars

# Javaで文字コードを考えてないhtmlspecialcharsを作る

外部ライブラリが使えない環境下でエスケープ処理をする必要が出てきたので書いた。環境はWindowsでJava10

javaにはデフォルト引数が使えないので、`ENT_QUOTES`とかを文字列の引数で受け取ることに、今後文字コード等を考えていくならオーバーロードして作るのがよさそう。

```java:function

public class Escape{

	
	/**
		& to &amp;
		" to &quot; if flag.equals("ENT_COMPAT") flag.equals("ENT_QUOTES")
		' to &apos;	if flag.equals("ENT_QUOTES")
		< to &lt;
		> to &gt;
	*/
	public static String htmlspecialchars(String s, String flag){
		String ret = s.replace("&","&amp;").replace("<","&lt;").replace(">","&gt;");
		if(flag.equals("ENT_COMPAT")){
			return ret.replace("\"", "&quot;");
		}else if(flag.equals("ENT_QUOTES")){
			return ret.replace("'", "&apos;").replace("\"","&quot;");
		}else if(flag.equals("ENT_NOQUOTES")){
			return ret;
		}
		return ret;
	}
}
```

あんまりきれいじゃない、`ENT_COMPAT`と`ENT_QUOTES`指定されてなければ`return ret;`でいい気がした。

```java:main
public static void main(String[] args){
		System.out.println(htmlspecialchars("<script>alert(\"1\");</script>","ENT_COMPAT"));
		System.out.println(htmlspecialchars("<script>alert(\"1\");</script>","ENT_NOQUOTES"));
		System.out.println(htmlspecialchars("<script>alert('1');</script>","ENT_QUOTES"));
	}
```

```sh:結果
>java Escape
&lt;script&gt;alert(&quot;1&quot;);&lt;/script&gt;
&lt;script&gt;alert("1");&lt;/script&gt;
&lt;script&gt;alert(&apos;1&apos;);&lt;/script&gt;
```
dotfileを作成する

# 概要

パソコン(Mac)を買い替えたいという情熱を元にdotfilesを作ってみることにした。
ただし、installなどを行うたびにもっと楽になる方法ないかなと考えて仕組みを考える。
しかしながら、まだまだ途中。

# 管理するものリスト

- HomeBrewでinstallしたもの
- HomeBrewCaskでinstallしたもの
- Atomでinstallしているパッケージ
- .zshrc => bashからzshへの書き換えも行う
- .zpreztorc(preztoの環境設定全般)

# 最低限入れておきたいアプリケーション群

## brew caskで入れる

- Docker for Mac
- Vagrant
- Sequel Pro
- Virtual Box
- iterm2
etc...


# これだけ諦めるか？？？

- Xcode

アプリを開発しない限りあんまり必要とはしないので、必要になったらinstallすることにした。

# 注意

シンボリックリンクを張り替えないと.zshrcなどを移動することができない

# 必要な事前準備

1. brew fileでbrewでinstallしたものをgithubにpushしておく
2. Atomのpackageを同期するためのpackageを入れておく
3. .zshrcの読み先をdotfilesのシンボリックリンクを貼る
4. .zshpreztoも読み先をdotfilesのシンボリックリンクを貼る
5. その他必要なシンボリックリンクがあれば、随時追加

# 実際実行することになったら

1. gitcloneでローカルに落とす
2. install.shを実行する


# 今後やりたいこと

- .vimrc => vimも使うことがあるため、入れておきたい
- vimrcが編集された時にadd, commit, pushまでやる
- phpなどのバージョン管理用のパッケージ => PATHの書き換えも行う

## installのたびに更新するの面倒くさい

1. brew installが走るたびにbrew fileのupdateも行うようにしておく
2. apm install が行われた際にapm starもやっておくようにする

cronを使ってバックグラウンドでよしなにやっとく。
または、コマンドを実行するたびにdotfilesをupdateしたものをpushするようにしておく。
Photoshopのオーバーレイマスクカラーを３〜6種トグルするJavaScript

クイックマスクや、レイヤーマスクをオーバーレイ表示したときのオーバーレイカラーを好きなように切り替えます。
実行するたびに、HSBのHに+60〜120して色を変えます。

▼画像に合わせて適宜変えてやるとオーバーレイ（＝選択範囲・マスク）が見やすくなります。
![246557315122.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35477/da98bde5-dbc1-e248-7105-2809c877ff1d.jpeg)


```javascript:ChangeMaskColor.jsx
/*
<javascriptresource>
<name>マスクカラー変更</name>
<category>YPresets</category>
</javascriptresource>
*/

var myRegKey ="myMaskColor"; //実行内容を記録させるキー名

//カラーと不透明度設定
var myDefHSBS = 50; //彩度（〜100）
var myDefHSBB = 100; //輝度（〜100）
var myDefOpacity = 70; //マスクの不透明度（〜100）
var myHSBAngle = 60; //HSBのHに足す数値。120でRGB、60でCMYをプラス

//キーが無い初回起動時作成
try{
    var customActionDescriptor = app.getCustomOptions(myRegKey);
    var myColor = customActionDescriptor.getString(1001);
    }catch(e){
    var myColor = myPutString (0)
    }

//前回実行した記録に基づいてカラー設定
var myColor=Number(myColor)+myHSBAngle;
if(myColor>=360){myColor=0};
myPutString (myColor);

//実行部分
try{
executeChangeColor(myColor);
}catch(e){}

//関数：実行した色合いを記録
function myPutString(myH){
    var desc = new ActionDescriptor();
    desc.putString(1001,myH);
    app.putCustomOptions(myRegKey, desc, true);
    return myH;
    }

//関数：マスクカラー変更
function executeChangeColor(myHSBsH){
var idsetd = charIDToTypeID( 'setd' );
    var desc12 = new ActionDescriptor();
    var idnull = charIDToTypeID( 'null' );
        var ref3 = new ActionReference();
        var idChnl = charIDToTypeID( 'Chnl' );
        var idOrdn = charIDToTypeID( 'Ordn' );
        var idTrgt = charIDToTypeID( 'Trgt' );
        ref3.putEnumerated( idChnl, idOrdn, idTrgt );
    desc12.putReference( idnull, ref3 );
    var idT = charIDToTypeID( 'T   ' );
        var desc13 = new ActionDescriptor();
        var idClr = charIDToTypeID( 'Clr ' );
            var desc14 = new ActionDescriptor();
            var idH = charIDToTypeID( 'H   ' );
            var idAng = charIDToTypeID( '#Ang' );
            desc14.putUnitDouble( idH, idAng, myHSBsH );
            var idStrt = charIDToTypeID( 'Strt' );
            desc14.putDouble( idStrt, myDefHSBS );
            var idBrgh = charIDToTypeID( 'Brgh' );
            desc14.putDouble( idBrgh, myDefHSBB );
            var idHSBC = charIDToTypeID( 'HSBC' );
        desc13.putObject( idClr, idHSBC, desc14 );
        
       //不透明度を自分で変えたい場合はこのブロックを削除する
            var idopacity = charIDToTypeID( "Opct" );
            var idpercentUnit = charIDToTypeID( "#Prc" );
        desc13.putUnitDouble( idopacity, idpercentUnit, myDefOpacity );
        //ここまで不透明度変更ブロック
        
    var idChnl = charIDToTypeID( 'Chnl' );
    desc12.putObject( idT, idChnl, desc13 );
executeAction( idsetd, desc12, DialogModes.NO );
}
```
UnityのRenderTextureのアルファブレンドに苦しんだ話

# はじめに
アルファを含んだRenderTextureを対象のオブジェクトに描いたときに期待どおりをアルファブレンドが行われなかった時のお話

# 問題となった挙動
以下のようなシーンを用意する。
上部のカメラに映ったオブジェクトをRenderTexture焼き付け、下部を白テクスチャに描画するといった簡単なシーン
`テクスチャ1`, `テクスチャ2` はアルファ0.5になっており、`テクスチャ3(黒)`はアルファ1.0に設定してある。
上部のカメラ内のテクスチャ順は最背面が3, 最前面が1となるようになっている。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/263605/4d511f9b-9ead-e43e-9960-6921fc69f28c.png)


## 想定する挙動
再背面に`テクスチャ3`が配置されているので当然テクスチャ3が描画される範囲はアルファ1になり
Unityちゃんロゴが見えることはない
![image.png](https://qiita-image-store.s3.amazonaws.com/0/263605/33c9d739-c484-9b47-b2ff-a5393752c07a.png)


## 実際の挙動
しかし、実際の挙動は違っていて`テクスチャ1`と`テクスチャ2`のアルファ値がなぜか`テクスチャ3`に反映されてしまっている
![image.png](https://qiita-image-store.s3.amazonaws.com/0/263605/1b8a7d01-f34b-bcd2-1341-b9f81b691e36.png)

# 解決方法
先に解決方法を描いてしまうとRenderTextureに焼き付けられるすべてのテクスチャにブレンド`Blend SrcAlpha OneMinusSrcAlpha, Zero OneMinusSrcAlpha`にしたシェーダを設定し、写すカメラのクリアカラー(solidColor)を`#000000FF`にする。
RenderTextureの内容を描くオブジェクト(今回だと下部を白テクスチャ)をブレンド`Blend One SrcAlpha`を設定すれば良い

# 原因
ここからは想像ですがアルファブレンドは通常背面から前面にかけて順番に行われるものですが
RenderTextureに描く場合は先にRenderTexture内のアルファブレンドを行ったあと、実際にフレームバッファに描く際に再度計算が行われるためかと思います。
なので今回の解決方法ではRenderTexture側のクリアカラーのアルファ値を1とし上記のようなアルファブレンド設定にすることで想定するアルファブレンドの式と辻褄を合わせるようしています。
SQLにおけるNULLの扱い方

#対象読者
・SQL初心者の方（SQLにおけるNULLの扱い方を知らない方）

#前提
・Oracle Database 12c
※PostgreSQL, MySQLで使用可能な関数も出てくるのでご安心を！

#NULLを扱うための関数
##NVL
指定した列の状態（NULLかどうか）に応じて結果を返します。
例えば、売上高の合計値を算出したいもののSUM対象のすべてNULLになる可能性がある場合、**SUM(NVL(sales, 0))**と表現すれば結果がNULLになることはありません。

```html
NVL(式1, 式2)
```

|式1|式2|結果|
|:--|:--|:--|
|NULL以外|NULL以外|式1|
|NULL以外|NULL|式1|
|NULL|NULL以外|式2|
|NULL|NULL|NULL|

##NVL2
式1の状態に応じて式2または式3を返します。

```html
NVL(式1, 式2, 式3)
```

|式1|結果|
|:--|:--|
|NULL以外|式1|
|NULL|式2|

##COALESCE
引数の式を左から順に評価し、**最初に見つかったNULL以外の値を返します。**
<font color="red">式リスト内のデータ型はすべて一致している必要があるので注意が必要です。</font>一致していない場合はエラーとなります。

```html
COALESCE(式1, 式2 [, 式n])
```

|式1|式n|結果|
|:--|:--|:--|
|NULL以外|NULL以外|式1|
|NULL以外|NULL|式1|
|NULL|NULL以外|式n|
|NULL|NULL|NULL|

##NVLとCOALESCEの違い

|関数|式リスト|式リストの値の型変換|
|:--|:--|:--|
|NVL, NVL2|固定長|暗黙的な変換|
|COALESCE|可変長|型変換しない|

ちなみに、NVLはOracle独自の関数ですが、COALESCEはPostgreQLでもMySQLでも使えるようです。

#おまけ：ORDER BYでNULLの表示順を指定する
##NULLS FIRST/LAST
ORDER BYでソートする際、NULLを最初に表示させるか、最後に表示させるかを選ぶことができます。ちなみに、PostgreSQLでも同様にNULLS FAST/LASTが使えるそうです。
[PostgreSQLのソートで、nullの位置を制御する](https://qiita.com/hanoopy/items/03f62de8b15bea195208)

```html
ORDER BY 列名 [NULLS FIRST or NULLS LAST]
```

#参考資料
- [NULL を別の値に置換、リストから最初の NULL 以外の値を探す](https://www.shift-the-oracle.com/sql/functions/nvl-coalesce.html)
- [【オラクル認定資格試験対策書】ORACLE MASTER Bronze 12c SQL基礎 (試験番号:1Z0-061)完全詳解+精選問題集(オラクルマスタースタディガイド)](https://www.amazon.co.jp/%E3%80%90%E3%82%AA%E3%83%A9%E3%82%AF%E3%83%AB%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E5%AF%BE%E7%AD%96%E6%9B%B8%E3%80%91ORACLE-MASTER-Bronze-SQL%E5%9F%BA%E7%A4%8E-%E8%A9%A6%E9%A8%93%E7%95%AA%E5%8F%B7/dp/4797375418/)
Node-RED上にTwitterに画像ファイル付きでリプライする処理を作ってみた

# なんでこんなことをしたのか
とあるハッカソンで、あるTwitterのボットに、画像ファイルとつきでリプライする処理が必要になり、それが動いたので、まとめておこうとしています。


# 機能の分解
ここではやろうとした処理を整理しておきます。
必要だった機能は、以下になります。

・画像ファイルを添付して送れるREST APIを用意する
・リクエストに添付されている画像ファイルを変数に組み込み
・特定のTwitterボットにリプライの形でメッセージを送る


# Node-Red上のコード
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135990/d8551501-407c-2d6d-07ec-6f5f5edad09d.png)

これを元に、各機能の詳細を見ていきましょう。

# 画像ファイルを添付して送れるREST APIを用意する
まずは、この部分です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135990/5e54c68f-574d-4462-0e2f-1a707c2e201f.png)

メソッドはPOSTにして、URLを任意のものを入れておしまいです。
こんな感じです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/135990/5bb9a6c5-c12d-ae2e-b899-18365eb2f44a.png)



# リクエストに添付されている画像ファイルを変数に組み込み
次はこの部分です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135990/b70eb0bb-2bcd-18a6-096c-3e1e83050b4e.png)


以下は、リクエストの中身から、画像ファイルを抽出し、Twitterに画像を送るための変数に格納するコードです。ここではjpegのときの抽出の仕方になります。こちらのページを参考にし、Twitterと連携するようにコードを一部修正しています。
[スマホで撮った写真をNode-REDにアップロードする](https://qiita.com/takeyan/items/ccd74797937dc51959f6)

```
var buf = msg.req.body;
var SOI = new Buffer("FFD8","hex");
var EOI = new Buffer("FFD9","hex");
var iSOI = 0;
var file = "";

for (var i=0 ; i<=buf.length ; i++) {
    if(SOI.equals(buf.slice(i,i+2))) {
        iSOI = i;
        }
    if(EOI.equals(buf.slice(i,i+2))) {
        file = buf.slice(iSOI,i+2);
        break;
        }
    }

msg.media = file ;
return msg;
```
msg.mediaに添付画像を格納すればOKです。
以下に、その入れ方の記述があります。
https://flows.nodered.org/node/node-red-node-twitter


# 特定のTwitterボットにリプライの形でメッセージを送る
次はここの部分ですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/135990/6d093ba8-1af4-67cc-4604-81ca2937cd8e.png)

msg.payloadにTwitterに返信するつもりで、@リプライしたいIDを入れてください。
メッセージの内容は任意ですが、IDとメッセージの間にスペースを空けておかないと、リプライしたい人のIDが間違うので、注意が必要です。

```
msg.payload = "@リプライしたいID" +  "　メッセージの内容";
return msg;
```


# テストするために
multiple/form-data形式で、任意の変数名で画像ファイルをアップロードしてください。

# この後は・・・
本当は、この後の処理として、ボットに画像をリプライするとの、そのリプライとして画像を判定した結果をもらえます。しかし、Node-REDのtwitterがストリーム処理のため、欲しい結果だけを拾うことができないでいます。なので、暫定的にcloudantにストリームの結果を格納して、そこから取り出す処理をしてみましたが、いまいち美しくない書き方でした。
何か手をご存知の方がいらっしゃったら、REST APIの一連の処理で、リプライのリプライに対する結果を拾う方法を教えてください。
Nextcloud 13.0.3 と 12.0.8 リリース

# Nextcloud 13.0.3 と 12.0.8 が2018年6月7日にリリースされました。

以下の内容は、以下のURLのページを参考に意訳しています。

URL：
Nextcloud 13.0.3 and 12.0.8 available – The most popular self-hosted file share and collaboration platform
https://nextcloud.com/blog/nextcloud-13.0.3-and-12.0.8-available/

Nextcloudサーバーの新しいバージョンがリリースされました。いくつかのバグによるマイナーアップデートとセキュリティー修正がされています。有償ユーザーは、Nextcloud社のサポートが必要であればサポートを受けつつ、アップグレードすることができます。

このリリースには、GDPR Compliance Kitが導入されました。ログインページでプライバシーポリシーの表示とプライバシーへのリンクができるようになりました。Nextcloud社の [nextcloud.com/gdpr](https://nextcloud.com/gdpr)を確認してください。

この週は更新が多い週となりました。友人Nextcloudからの2年目の誕生日プレゼントとして、iOSクライアントの重要なアップデートを発表しました。また、AndroidとiOSのトークアプリをアップデートして、相互にサーバー経由でチャットができるようになりました。

あと、もう一つ忘れていけないことがあります。[Nextcloud カンファレンスの講演応募](https://nextcloud.com/blog/nextcloud-2018-conference-call-for-papers/)を開始しました。8月の最終週にベルリンで開催されます。

## Version 13 にアップグレードしましょう！
このバージョンはとても安定しているので、アップグレードするのに最適です。
もちろん、企業でミッションクリティカルなネクストクラウドシステムを維持している場合でも、ファイル処理システムが期待どおりに機能していない場合、誰かが責任を負うことになります。

## どこが変わったか
13.0.3 と 12.0.8 は、通常の隔月リリースになります。安定バージョンのバージョンアップでいくつかのマイナー改修が含まれています。Nextcloud 11はオープンソースではEOLになりましたが、[有料サブスクリプション](https://nextcloud.com/enterprise/)ではまだ、メンテナンスアップデート対象です。Nextcloud 12にバージョンアップすることも可能です。

いつも言ってますが、アップグレードを先延ばしにすることは良いことではありません。顧客にも今後のメンテナンスリリースやセキュリティーに関する考慮事項を事前に警告していますが、迅速にアップデートすることこそ、すべてのユーザーにとって最も重要なことです。

**セキュリティーなしにプライバシーは守れません**

このリリースには、以下のような50以上の修正と改修が含まれています。

* IPv6 データベース対応
* OAuth サポートの改善
* ログの改善
* ロックに関する取り扱いの改善
* ワークフローのエラーの改善
* プライバシーポリシーのリンクと表示のサポート
* その他にも多くの修正があります

## アップデーターが警告してきたら？

内蔵のアップデーターが、次のバージョンにアップデートできるようになったら通知があります。段階的にアップデートの通知を出すようにして、影響を確認しています。一部のシステムでは他のシステムよりも少し時間がかかります。

## アップデートは必要ですか？

私たちの考え方としては、メジャーアップデートでは大きな変更が入ります。マイナーリリースには、セキュリティーや機能のバグフィックスが入ります。ユーザーのデータを危険にさらすようなシステムの変更はしないようにしています。さらにコードベースと実運用システムをテスト中のバージョンにアップデートすることにより広範囲なテストを実施しています。マイナーリリースであったとしても、失敗しない安定したアップグレードを保証します。アップデートはバグ修正だけではなく、セキュリティー対応も含まれますので、アップデートしないのは間違っています。

というのは、アプリについても同様のことが言えます。アップデートされている状態を維持することによりセキュリティーのメリットが受けられます。その一方で新機能とバグフィックスが同時に存在するのです。

もし、大規模構成で重要な企業向けシステムを構築していて、アップデートに不安がある方は、Nextcloud GmbHの[スタンバイアップデートサポート](https://nextcloud.com/enterprise/)を受けてください、スムーズなアップデートを保証します。このサポートは、Nextcloudのファイルの同期が取れた状態で最適な状態をキープするために必要なものの1つです。


---------
# 宣伝
Nextcloud Meetup Tokyo #01 を開催します。

Nextcloud Meetup Tokyo #01 - connpass
https://nextcloudjp.connpass.com/event/91014/


セールスマネージャーのFrankさんが来日されNextcloudのお話をお聞かせいただけます。
是非この機会に皆様ご参加ください。
Railsで透過的にカラム暗号化

個人情報を扱うサービスを考えると、どうしても特定のカラムを暗号化する必要が出てくることがある。
いくつかのgemを試してみて、どうもしっくりこなかったので、gemを作ることにした。

既存gemの紹介と、新しい暗号化gemの比較をしてみよう 👀

## [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted)

ActiveRecord + 暗号化 で調べると真っ先に出てくるgemのひとつ
定義をする側はシンプルなのだが、使う時になかなかクセがある。

暗号化したいカラムにつき、2つのカラムが必要になるようだ。

```ruby
class Model < ActiveRecord::Base
  attr_encrypted :field_name, key: ENV["KEY"]
end

# migrationは下記のような定義になる
create_table(:models) do |t|
  t.string(:encrypted_field_name)
  t.string(:encrypted_field_name_iv)
end
```

暗号化自体は、とてもシンプルに扱うことができる。
しかし、 `#changes` の値が分かりづらかったり、 `field_was` で過去の値を取得できないなどの問題がある。

特定のケースでおかしな挙動をするので、正直言うと実用に耐えない。

```ruby
instance = Model.create(field: 'hello')
=> <Model id: 1, encrypted_field: "d9thb/Pvj6gMm2TPLHoola3aHsWy\n", encrypted_field_iv: "UfosEdeGJJmIBUHs\n">

instance.field   
=> "hello"

# changes や _was など
instance.field = "hello world"

instance.changes_to_save
=> {"encrypted_field"=>["d9thb/Pvj6gMm2TPLHoola3aHsWy\n", "RxJTGKPG3PMi1NA0LY/tSu9r16sMWfalAFRc\n"],
 "encrypted_field_iv"=>["UfosEdeGJJmIBUHs\n", "1lMAgBaLBrqQUPUU\n"],
 "field"=>[nil, nil]}

instance.field_changed? #=> true
instance.field_was      #=> nil
```

## [crypt_keeper](https://github.com/jmazzi/crypt_keeper)

透過的暗号化を謳う暗号化gemだ。
`serialize`の機能を活用して、内部実装はかなりシンプルにできている。

```ruby 
class MyModel < ApplicationRecord
  crypt_keeper :field, encryptor: :active_support, key: ENV['KEY'], salt: ENV['SALT']
end

create_table(:models) do |t|
  t.binary(:field)
end
```

そして、透過的暗号化を謳っているだけあって挙動もシンプル!!
`#changes` などの挙動も正しく、問題なさそうである。

暗号形式の拡張も柔軟にできるため、通常使う分には十分実用に耐えうると感じた。

```ruby
instance = Model.new(field: 'hello')
instance.save
instance         #=> <Model id: 1, field: "hello">

instance.field   #=> "hello"

instance.field = 'hello world'

instance.changes
# => {"field"=>["hello world", "hello new world"]}
```

## [active_record_encryption](https://github.com/alpaca-tc/active_record_encryption)

今回作成した新しい暗号化gemである。
このgemの特徴は、Attribute APIを使っており、好きな型を扱えるようになった点である。
他のgemは、string型しか扱えない。

下記の通り、第二引数にて、好きな型を指定することができる。
また、 `default:`引数でデフォルト値を設定することも用意である！！

```ruby 
class Model < ApplicationRecord
  encrypted_attribute :field, :date 
  encrypted_attribute :field_2, Money.new
  encrypted_attribute :field_3, :string, default: 'default value'
end
```

実際に使ってみると分かるのだが、だいたい他の挙動については、`crypt_keeper`と同等に透過的である。
`serialize` なども使える分、 `crypt_keeper` よりも透過的かもしれない。

```
instance = Model.new(field: '2000/01/01', field_2: 100)
instance.field_1 #=> Sat, 01 Jan 2000
instance.field_2 #=> <Money value: 100>
instance.field_3 #=> 'default value'
```

## まとめ

`attr_encrypted` はあまりにも使いにくすぎるので、いずれのケースからも選択肢からは外れそうだ。 
さようなら :pray:

String型のみ暗号化する場合は `crypt_keeper`を使うだろう。
そして、様々な型のデータを暗号化したいケースの場合は、`active_record_encryption`を使うといいだろう :smile: :+1:
MacBook Airのお下がりをもらったのでmacOSをクリーンインストールしてみた

Appleのサポートページは見やすかったけど、あっちこっちページを見て回らなければならなかったので、次回慌てないように自分用にメモ。

##背景
夫が新しいPCを買ったので、今まで借りていた夫のPCが私のものになった。
ずっと夫のアカウントで作業（≠業務）していたけど、色々と面倒だったしいい機会なので、クリーンインストールして自分仕様にすることに。

##入れたOSとバージョン
macOS High Sierra 10.13.5

##作業する前に、注意点
予め[作業工程](https://support.apple.com/ja-jp/HT201065)をなるべく細かくどこかに書いておき、確認しながら作業すること。
ハードウェア関係の作業はミスると命取りになることもあるので。
これを飛ばしてAppleの該当してそうなページを見ながら作業を始めてしまったので、夫にめっちゃ怒られた。
（途中でホワイトボードに書き出した）

##作業工程
- バックアップをとる
ローカルには大事なデータがないので、Dropboxにファイルをコピーしたり、ちょっとしたメモをGmailの下書きとかにコピペしたりして完了。


- メッセージアプリ、iTunes, iCloudなどに紐づいているアカウントの連携を解除


- 再起動、[macOS復元](https://support.apple.com/ja-jp/HT201314)
Appleロゴが表示されたとき、私の場合はcommand (⌘) + R を長押しした。
その後MacOSユーティリティウィンドウの中から「ディスクユーテリティ」を選択。

- 起動ディスクを消去
以下[macOS をインストールする方法](https://support.apple.com/ja-jp/HT204904y) の「起動ディスクを消去する (必要な場合)」
より引用。
>1. macOS 復元のユーティリティウインドウで「ディスクユーティリティ」を選択し、「続ける」をクリックします。
>2. ディスクユーティリティのサイドバーで、デバイスまたはボリュームを選択します。 
>3. 「消去」ボタンまたは「消去」タブをクリックします。 
>4. 以下のフィールドに入力します。
>    * 名前：ディスクの名前を入力します (「Macintosh HD」など)。
>    * フォーマット：「Mac OS 拡張 (ジャーナリング)」または「APFS」を選択します。
>    * 方式 (表示される場合)：「GUID パーティションマップ」を選択します。
>
>     >ここのスクショではMac OS 拡張(ジャーナリング)が載っていたが、私の場合はAPFSだったので「方式」は表示されなかった。
若干慌てたので、フォーマットは事前に確認しておくべきだった。
>
> 5. 「消去」をクリックすると、ディスクの消去が始まります。
>
>     > 思ったよりあっさり終わった。
>
>6. 終わったら、ディスクユーティリティを終了し、ユーティリティウインドウに戻ります。これで、macOS をインストールできるようになりました。

- [macOS をインストールする](https://support.apple.com/ja-jp/HT204904#reinstall)

あとは上記ページの言う通りにすると、OSは問題なく起動した。

どんなツールを入れたかはまた別の記事でアップ予定。

##参考にした記事

Appleのサポートサイトたち。

- Mac を売却または譲渡する前に https://support.apple.com/ja-jp/HT201065
- macOS 復元について https://support.apple.com/ja-jp/HT201314
- macOS をインストールする方法 https://support.apple.com/ja-jp/HT204904
webdriverio + appnim で　iOS の試験をしたらシミュレーターが上がりまくった話


今回は短いのですが、私と同じようにうっかりはまってしまう方が居るかもしれませんので一応記事にしておきました。

## 何が起こったか

appnim を使い　mobilesafari で web の試験をしようと思い、新たに環境を構築しました。

- macOS 10.13.5
- iOS   11.4(シミュレーターで実行したiOS)
- Xcode 9.4
- appium 1.8.1
- webdriverio 4.12.0

上記の環境で試したのですが、なぜかシミュレーターがたくさん実行されてしまいました。
試験を実行すると、まずはシミュレーターが１つ上がって来ます。

よしよしと思ってまっていると、２つめが・・・・な感じでした。
そのままほって置くと、３つ４つと起動されてきます。

## 結論

**iOSは11.3**をつかいましよう。

## いろいろ試したのですが

結局、release noteを確認したところ、appium1.8.0 で iOS11.3 に対応した時点のままのようなので、11.4は未対応ということみたいです。

ここにたどり着くまで、appium のログとにらめっこしまくりだったのですが、わかるはずもなく、どうやら appium かんけいなくね？ という境地にたどり着いたとき、やっと 「iOS11.4対応してたっけ？」にたどり着きました。

私のように時間を浪費しないよう、検索に引っかかることをお祈りしています・・・・合掌