OmniAICreator/Qiita-1.07M huggingface dataset:
【iOS】よくある横スクロールをStoryboardだけで作る

アプリのチュートリアル的な画面でよく見る、横にページめくりする感じのViewを実装します。

こんな感じのものです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/71cbeb09-19a3-e2e5-badd-1b1b196eb00d.gif" width=300px />

これを__コードを全く書かずに作ります。__サクッと作りたい時におすすめです。

それでは順を追って説明します。

## UIScrollView、UIStackView(Horizontal)を配置
![1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/aa000fc1-d248-354f-ca73-4824c23d65ce.gif)

普通にスクロールビューを置いて制約(画面いっぱい)を設定し、中にスタックを置いています。
横スクロールにしたいのでスタックはHorizontalにし、スクロールビューとスタックビューの高さをあわせます。
(Stackをverticalに、横幅をあわせれば普通に縦スクロールになります。)

UIScrollViewについて詰まったら[(多分)いちばんシンプルなUIScrollViewの実装](https://qiita.com/akaneburyo/items/a65f94c285fec14dc897)も見てみてください。

## Stackの中にUIViewを配置
各ページとなるViewを配置します。
![2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/f22e88f5-f498-43f8-f30b-6b10c0d465ff.gif)


## 配置したViewに制約を設定

![3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/e8ba065d-1581-7782-d9d4-551f7651c0fd.gif)

Viewの横幅を画面サイズ(UIScrollView)と同じにする制約をつけます。
(UIStackViewで高さは決まっているので横だけ決めればOKです。)
ここまでで Viewの個数 × 画面幅分 のスクロールができるようになります。

## UIScrollViewの「Paging Enabled」を有効に

<img width="1084" alt="ぺーじんぐ.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/4a0d3453-1818-f90f-a125-3d658599c890.png">

このままだとただの横スクロールなので、
ページめくりのような動きにするために「Paging Enabled」を有効にします。
バウンス(端までスクロールした時に跳ねる感じのやつ)が不要であれば「Bounce On Scroll」も無効にしましょう。

後は、先程いっぱい置いたViewに適宜部品を置いてチュートリアルを完成させましょう。
(今回は違いがわかるように背景色だけ変更しております。)

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/e9eeb3f1-4727-82ab-6c33-ca826d5ffd14.gif" width=300px>

以上で完成です。

## 余談


少しだけコードを記述すれば、UIPageControllerも追加できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208118/00ef4a78-3b0d-c857-cd08-d81794e0c0c3.gif" width=300px>
こんな感じ。

追加したコードは以下です。
レイアウトにはUIPageControlを追加し、ページ数だけ設定してあります。

```swift
import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var scroll: UIScrollView!
    @IBOutlet weak var pageControl: UIPageControl!

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewWillAppear(_ animated: Bool) {
        self.scroll.delegate = self
    }
}

extension ViewController:UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let index = Int(round(scrollView.contentOffset.x / scrollView.frame.width))
        self.pageControl.currentPage = index
    }
}
```

---
不明点、不足点、改善点等ございましたらお教えいただけますと幸いです。
ありがとうございました。
ファサードの仕組みを簡単にまとめる【Laravel】

## 概要

Laravelの代表的な機能としてファサードがある。これを使うと、staticなメソッドを呼ぶのと同じ要領で、どこからでも簡単にフレームワークの機能を呼び出すことができる。

```php
use Illuminate\Support\Facades\Config;

Route::get('/config', function () {
    return Config::get('key');
});
```

下の例のように、useで名前空間を指定せずとも、グローバル名前空間でアクセスするように書くことも可能。（ちなみにこれが可能なのは`config/app.php`の`aliases`に記述されている対応関係を`class_alias`関数によって結びつけているから。要はエイリアス（別名）をつけて省略的に書けるようにしていると思っておけば良いと思う。たぶん。）

```php
Route::get('/config', function () {
    return \Config::get('key');
});
```

これを一見すると、`Illuminate\Support\Facades\Config`クラスに実装された`get`メソッドを呼んでいるように見えるが、実は`get`メソッドは`Illuminate\Support\Facades\Config`クラスにも、継承元の`Illuminate\Support\Facades\Facade`クラスにも存在していない。実際には、`getFacadeAccessor()`が実装されているのみである。

```Config.php
<?php

namespace Illuminate\Support\Facades;

class Config extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'config';
    }
}
```

この時何が起こっているか、簡単に辿ってみる。

## マジックメソッドと__callStatic()

`Illuminate\Support\Facades\Config`クラスは`get()`を持っていなかった。
実装されていないstaticなメソッドを呼ぼうとするとどうなるかというと、PHPでは`__callStatic()`というマジックメソッドが呼ばれることになる。

>
```php
public static __callStatic ( string $name , array $arguments ) : mixed
```
__callStatic() は、 アクセス不能メソッドを静的コンテキストで実行したときに起動します。
引数 `$name` は、 コールしようとしたメソッドの名前です。 引数 `$arguments`は配列で、メソッド $name に渡そうとしたパラメータが格納されます。

マジックメソッドはPHPにおける特殊な関数であり、開発者が直接指定して呼び出すことはほとんどなく、特定のタイミングで勝手に呼び出される。代表的なものが馴染み深い`__construct()`であり、新たにインスタンスが生成されるタイミングで勝手に呼び出されるマジックメソッドといえる。

## 中身

継承元の`Illuminate\Support\Facades\Facade`クラスには、`__callStatic()`が実装されている。（コメントなどは省略）

```Facade.php
<?php

namespace Illuminate\Support\Facades;

// ...

abstract class Facade
{
    // ...

    public static function getFacadeRoot()
    {
        return static::resolveFacadeInstance(static::getFacadeAccessor());
    }

    protected static function resolveFacadeInstance($name)
    {
        if (is_object($name)) {
            return $name;
        }

        if (isset(static::$resolvedInstance[$name])) {
            return static::$resolvedInstance[$name];
        }

        if (static::$app) {
            return static::$resolvedInstance[$name] = static::$app[$name];
        }
    }

    public static function __callStatic($method, $args)
    {
        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }

        return $instance->$method(...$args);
    }
}
```

上記のPHPマニュアルからの引用の通り、`__callStatic()`の引数`$method`には呼び出そうとしたメソッドの名前、`$args`にはその時に使用した引数が配列の形式で入る。

`getFacadeRoot()`でサービスコンテナ（`$app`）から対象となるインスタンスを取得し、そのインスタンスのメソッドを引数の`$method`によって実行する。

つまり、staticなメソッドを使用しているように見えて、実際には実体となるインスタンスがサービスコンテナから取り出され、指定したメソッドが実行される、という流れになっていることがわかる。
gRPCの通信をgzip圧縮する(go言語)

サーバ・クライアント間でデータをやり取りするとき、ネットワーク帯域がボトルネックになるケースは多いです。
gRPCは[Protocol Buffers](https://developers.google.com/protocol-buffers/docs/overview)によってデータのシリアライズをしており変数名などはタグ化されるし、数値型はちゃんと数値データとして送信されるので、JSONに比べて通信量的に有利です。
しかし所詮はその程度なので、大量のデータをやり取りすることを考えるときちんとデータを圧縮するべきです。

go言語のgRPCパッケージにはgzip圧縮用のライブラリが組み込まれており、少ないコードで通信をgzip圧縮できます。

# サーバ側

```go:server.go
（省略）
import (
	"google.golang.org/grpc"
	_ "google.golang.org/grpc/encoding/gzip"
	：
（省略）
```

***"google.golang.org/grpc/encoding/gzip"をアンダースコア付でインポートする***。それだけです。
こうすると、起動時にinit関数が呼ばれて、gzip圧縮ができるサーバとして動作します。

# クライアント側

```go:client.go
（省略）
import (
	"google.golang.org/grpc"
	"google.golang.org/grpc/encoding/gzip"
	：

（省略）

func main() {
	conn, err := grpc.Dial("localhost:19003", grpc.WithInsecure())
	if err != nil {
		log.Fatal("client connection error:", err)
	}
	defer conn.Close()
	client := hogegrpc.NewHogegrpcClient(conn)
	message := &hogegrpc.GetDataMessage{TargetCode: 0}
	response, err = client.GetData(context.TODO(), message, grpc.UseCompressor(gzip.Name))
（省略）
```

サーバ側と同じくgzip圧縮のパッケージをimportします。こちらはアンダースコア無し。
そしてgRPCで実行する関数の可変引数部分に、***grpc.UseCompressor***を指定してあげます。
こうすると、クライアントからサーバに接続する時に「gzip圧縮できるよ」という情報が渡り、gzip圧縮してデータのやりとりができます。

見ての通り関数呼び出しごとに指定するため、文字列等の圧縮が効きやすいデータはgzip圧縮して通信、メディア等の圧縮済みのデータをやりとりするなら無圧縮、という使い分けが容易です。

# 性能試験
[適当なオープンデータ](https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/0000177182.html)を垂れ流すgRPCサーバを立てて試験しました。
内容は数値半分、文字列半分。1レコードあたり400byte前後のデータになります。

送信するパターンは1レコードずつ送信・全レコード（4,900件）一括送信の2つ。
試験環境はサーバ／クライアントを同一マシン上に置いたパターンと、別マシン上に置いて無線LANで通信させるパターンで測定します。

時間は関数呼び出しの前後で取得し、「クライアントから要求を出して、クライアント上でデータのデシリアライズが終わるまで」を測定します。

### 1レコードずつ送信

1回400byte前後のデータをやりとりします。

| 通信先 | 無圧縮 | gzip圧縮 |
|:--|--:|--:|
| localhost | 0.10 ms | 0.50 ms |
| 無線LAN上 | 1.87 ms | 2.20 ms |

えー、大々的に言ったわりに***gzip圧縮は遅い***。
圧縮・展開にかかるオーバーヘッドがかなり大きいことと、***たかが400byte程度のペイロードでは1パケットに収まってしまう***ので、圧縮しようがしまいが通信量が変わらないことが原因でしょう。

### 全レコード一気に送信

1回1,900Kbyte程度のデータをやりとりします。

| 通信先 | 無圧縮 | gzip圧縮 |
|:--|--:|--:|
| localhost | 15.81 ms | 30.08 ms |
| 無線LAN上 | 190.06 ms | 56.51 ms |

通信量が増えるとgzip圧縮の効果が見えてきます。
localhost上ではさすがにネットワーク帯域がボトルネックにならないので圧縮するだけ不利ですが、***無線LAN上のマシンに対しては3～4倍近い性能差***が出せています。
ちなみにスループットは100Mbps超ぐらい出ており、明らかに無線LANの帯域がボトルネックです。

# まとめ
以下を満たす条件では、gzip圧縮を検討する価値があります。

- ネットワーク帯域がボトルネックだ
- 通信するデータが文字列や数値など、圧縮効果が見込める
- 一度に転送するデータが1パケットに収まらない

gRPCがなんだか遅いな、っていう人は試してみるといいんじゃないでしょうか。
ソフトウェアファースト１

###　SaaSの広がり

従来は、ソフトウェアはパッケージ型として販売していた。
今はクラウド等、インターネットの技術を使って、ダウンロード等、継続利用という形でサービスを提供している。このSaasによって、常に開発者は利用者の満足度を上げ続けていく、改善が必要になった。
そして、根本的な機能から徐々に開発し、ユーザーと一体になって完成を目指す、アジャイル開発などが現在の主流になりつつある。
マイクロソフトのWindowsは従来はパッケージ販売で、リリース間際になると改善が他のシステムにも影響を及ぼす可能性があることから非常に難しいものがあり、リリース後の問題修正もユーザーにアップデートした物を取り入れてもらう必要があった。

サイボウズでは、法人のオフィスのグループウェアなどを扱っており、SaaSが普及し始めるのも怪しい頃にクラウドサービスを取り入れていった。SaaSにより、月額課金をとるだけではなく、ユーザーからのログを取得することによってユーザーの利用状況なども把握できる仕組みを作った。

###　DevOps 開発と運用の一体

DevOpsは、ユーザーの利用状況をWebなどを通して把握し、改善していくために開発と運用が一体になって取り組んでいく、というものである。
昔、パッケージ販売の頃は、開発が終わったら一段落して、あとは開発チームは解散して、運用チームが担当するといったことが主流だったが、これからはSaaS、継続利用サービスのために開発と運用が一体になり、リリースしてからが本番だ、という考えからになっている。
[Vue.js][Jest]コンポーネントの単体テストを実行できるようにする

既存のVueアプリにコンポーネントテストを追加しようとしたときのお話です。

公式にサポートページがあるからそれでやればできるかなと思ったけど、
そのままの手順だといくつか躓いたので自分の対応を残しておきます。
Vueのバージョンが最新じゃないのが原因かもしれない。。

## 環境

| |Version|
|---|---|
|macOS|Mojave 10.14.6|
|vue|2.5.18|
|node|10.5.0|

## セットアップ

### 公式サポート

[Jest を使用した単一ファイルコンポーネントのテスト \| Vue Test Utils](https://vue-test-utils.vuejs.org/ja/guides/testing-single-file-components-with-jest.html)

### jestのインストール

```
yarn add --dev jest @vue/test-utils
```

```diff:package.json
{
  "scripts": {
    ...
+   "test": "jest"
    ...
  }
}
```

### *.vueファイルを処理するための設定

```
yarn add --dev vue-jest
```

```diff:package.json
+ "jest": {
+   "moduleFileExtensions": [
+     "js",
+     "json",
+     "vue"
+   ],
+   "transform": {
+     ".*\\.(vue)$": "vue-jest"
+   }
+ },
```

### webpackのエイリアス設定

```diff:package.json
  "jest": {
    ...
+   "moduleNameMapper": {
+     "^@/(.*)$": "<rootDir>/src/$1"
+   }
  },
```

### Babel設定

```
yarn add --dev babel-jest babel-core
```

```diff:package.json
  "jest": {
    ...
    "transform": {
      ...
+     "^.+\\.js$": "<rootDir>/node_modules/babel-jest"
    },
  },
```

```diff:.babelrc
+ {
+   "presets": [[ "@babel/env", { "modules": false } ]],
+   "env": {
+     "test": {
+       "presets": [[ "@babel/env", { "targets": { "node": "current" } } ]]
+     }
+   }
+ }
```

自分の場合はここまでやるとテストを実行することが出来ました。

## テストの作成

### ディレクトリ構成

ベストプラクティスはわからないけど、srcフォルダと同じ階層となるようにtestフォルダを作成しました。

```
├─src
│  └─Components
│      └─hoge.vue
└─test
    └─Components
        └─hoge.spec.js
```

### テストの記述

```js:hoge.spec.js
import { mount } from '@vue/test-utils'
import hoge from '@/components/hoge.vue'

describe('Component', () => {
  test('is a Vue instance', () => {
    const wrapper = mount(hoge)
    expect(wrapper.element).toMatchSnapshot()
  })
})
```

公式サポートのサンプルを元に作成しています。
(`toMatchSnapshot()`って何をテストしているのだろう。。)

### テストの実行

`yarn test`でテストが実行されます。
問題なく実行されれば下記のようなログが出ます！

```
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        1.749s, estimated 2s
Ran all test suites.
✨  Done in 2.61s.
```

## おわりに

ここまででテストを実行する土台が整いました。
これから実際のコンポーネントテストをどのように書くか学んでアウトプットします！
Rails5 heroku にS3を使ってアップロードしたときに発生するエラー 403 Access denied の対処法

#背景
S3にあるリソースはデフォルトでは外部からアクセスできないようになっている．
Heroku上で動いているアプリで画像をアップロードしても，403 errorではじかれて，表示できない．

#やったこと
##パブリックアクセス設定を一度すべてオフにする
![Screen Shot 2019-11-24 at 4.20.26 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253006/21491002-2a4e-253f-c904-b70f212edc96.png)


##バケットポリシーを作成
アクセス権限→バケットポリシーを選択すると，編集画面になるので，以下の内容を書く．
![Screen Shot 2019-11-24 at 4.25.42 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253006/5e8fc8fb-e32e-54db-51e3-9524a11cefb7.png)

```
{
    "Version": "2012-10-17",
    "Id": "PublicRead",
    "Statement": [
        {
            "Sid": "ReadAccess",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<あなたのAWS１２桁のID>:user/<IAMユーザー名>"
            },
            "Action": "*",
            "Resource": "arn:aws:s3:::<bucketの名前>/*"
        }
    ]
}
```


##パブリックアクセス設定を変えて，新しいバケットポリシーをブロックさせる
念の為．ブロックさせるようにする．
![Screen Shot 2019-11-24 at 4.15.00 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253006/9dca48e7-1b0d-edcf-0c1c-5b9017f12730.png)


#参考
https://qiita.com/rainbow___0/items/0ffeb29afc7865eb65b5
https://teratail.com/questions/170083
OpenposeをAzureのUbuntu環境で使う

#目標
Ubuntu環境下でOpenposeを使えるように環境構築する

#環境
Ubuntu: 18.04
Python: 3.6.8

#まずはPythonで仮想環境の構築
```
# python環境の確認
$ python3 -V
>> Python 3.6.8 → OK!

# pipの確認
$ pip -V
>> Command 'pip' not found → ないからインストール

# pipのインストール
$ apt-get install python3-pip
>> E: Unable to locate package python3-pip → apt-getのupdateが必要らしい

$ sudo apt-get update
$ apt-get install python3-pip
>> 無事インストール完了！

# 仮想環境の構築
$ apt-get install python3-venv
# 環境を構築する階層に移動
$ cd ***
$ sudo python3 -m venv .venv
$ source .venv/bin/activate
>> 仮想環境の起動が成功！
```

#ついにOpenposeのインストール
```
# Openposeの設定
$ apt-get -q -y install swig
$ git clone https://www.github.com/ildoonet/tf-openpose
$ cd tf-openpose
$ pip3 install -r requirements.txt
>> ModuleNotFoundError: No module named 'Cython'

# いくつかのモジュールが足りていないと言われるから、１つ１つpipでインストール
$ pip3 install Cython
$ pip3 install numpy
$ pip3 install wheel
$ pip3 install -r requirements.txt → やっとできたっぽい！

$ cd models/graph/cmu
$ bash download.sh
$ cd ../../../
＄ cd tf_pose/pafprocess
$ swig -python -c++ pafprocess.i && python3 setup.py build_ext --inplace
$ cd ../../../
```
Openposeのインストールが完了した。

#OpenposeのモジュールをimportするPythonのコード

以下のPythonのコードで確認してみる。

```python:tf_import.py
import sys
sys.path.append('tf-openpose')

import tf-pose
```

tf_import.pyを実行してみる

```
# tf_import.pyを実行
>> No module named 'cv2'
$ pip3 install opencv-python

# 再度tf_import.pyを実行
>> ImportError: libSM.so.6: cannot open shared object file: No such file or directory
$ sudo apt install libsm6

# 再再度tf_import.pyを実行
>> ImportError: libXrender.so.1: cannot open shared object file: No such file or directory
$ sudo apt install libxrender1

# そろそろ行ってくれ！
>> ModuleNotFoundError: No module named 'tensorflow'
$ pip3 install tensorflow

# tf_import.pyを実行
>> ついに行けた！！
```
Mint + SwiftFormatで躓いた話

MintはXcodeGenやSwiftFormat、SwiftLintなど便利なコマンドラインツールをまとめてくれるやつです。
https://github.com/yonaskolb/Mint
##Mintのインストール
Homebrewでいけます
`brew install mint`
##Mintfileに必要なツールを記述
```Mintfile
yonaskolb/xcodegen@2.10.1
nicklockwood/SwiftFormat@0.40.14
```
##ツールのインストール
`mint bootstrap`
##ツールの実行
BuildPhasesに新規でRunScriptを追加
bootstrapで入れたので実行には`mint run`を使います

```
mint run swiftformat . 
```
実際にBuildしてみると`Command PhaseScriptExecution failed with a nonzero exit code`が出てしまった、、。
## エラーの原因
https://github.com/yonaskolb/Mint/issues/145
詳しく読んではいないのですが、どうやら
`mint run <repository> <binary> [args]`
こう言う風に書くのが正しいっぽいです。

`mint run swiftformat swiftformat .` 
or
`mint run nicklockwood/SwiftFormat swiftformat .`
と書くと正しく動きます。

リポジトリを指すので混乱を避けるために
`mint run nicklockwood/SwiftFormat swiftformat .`
と書いてあげる方が良さそうです。
【rails】$ rails g model ~ で複数形にし忘れた

#い　つ　も　の
うっかりミスで「あ、model名を複数形にするの忘れた！」って思ってターミナル見直したら、
まさかのrailsが補完して「s」つけてくれていたという


```console
i$ rails g model chapter

Running via Spring preloader in process 65132
      invoke  active_record
      create    db/migrate/20191124065802_create_chapters.rb
      create    app/models/chapter.rb
      invoke    test_unit
      create      test/models/chapter_test.rb
      create      test/fixtures/chapters.yml

```

#おわりに
こんなことまで面倒見てくれてるとは知らなかったです。
rails ありがとう！！
iPadOSのUAにつまずいた

# はじめに
iPadOSのベータ版の頃からじわじわ話題に上がってましたが、iPadOSではUA（ユーザーエージェント）がMacOSと同じになりました。

この記事とか

* [iPadOSのSafariはmacOSのSafariと区別できない可能性が高い](https://qiita.com/m-otoguro/items/00602315724d4a8e580c)

変わることはわかっていたのですが、遊びで作ってたサイトでこのUA変更に見事につまずきました。

# Webサイトのホバー対応でつまずいた
遊びで作ってたサイトのボタンのホバー時のアニメーションをPCとスマホ・タブレットでUA判定して切り替えていたのですが、iPadOSで見事にバグりました...

下記がそのコードです。（前せっかく[CodePenの使い方](https://qiita.com/am10/items/3409c570186f1f87ccf5)について書いたのでCodePenで）
<p class="codepen" data-height="265" data-theme-id="default" data-default-tab="css,result" data-user="am102" data-slug-hash="ZEEZmRZ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="iPadOS-UA">
  <span>See the Pen <a href="https://codepen.io/am102/pen/ZEEZmRZ">
  iPadOS-UA</a> by am10 (<a href="https://codepen.io/am102">@am102</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

今のところ対応はしていません...

## 対応方法
思いついた対応方法です。

1. UA判定はやめてスクリーンサイズで切り替える  
この方法だとPCでウィンドウサイズを縮小された時タブレットと判定されるから嫌だなと思いUA判定にしたのですがあきらめるのも１つの手だと思います。
2. UAの判定方法を変える  
下記の記事では画面の解像度でUAを判定しiPadを判別しているようです。  
[ユーザエージェントでの iPad 判定関数 iOS/iPadOS 対応版](https://qiita.com/mtdune/items/97abb9c0bd926d4c8a13)
3. hoverのアクションをあきめる  
もうレスポンシブ対応する場合は潔くhoverのアクションをあきらめるのも手だと思います。
4. メディアクエリのhoverを使う  
[メディアクエリhover](https://developer.mozilla.org/ja/docs/Web/CSS/@media/hover)こういうのもあるみたいなので利用するのもありかと思います。（IEは対応していません...）

# 小話
## 公式もiPadOSのUAにつまずいた！？
[AppleのMac Proの紹介ページ](https://www.apple.com/jp/mac-pro/)をiPadやiPhoneで見るとARでMac Proを表示する機能があります。この機能がiPadOSのベータ版が出た時はUAで判定を行っていたらしく、iPadでアクセスするとAR機能が表示されないということがあったようです。

（当時手元にiPadOSの端末がなかったので私自身で確認できていません。話半分で流してください。調べると6月頃にTwitterの一部で話題になっていました。）

## Gmailの端末判定
iPadなどでGmailにログインした際は下記のようにセキリティ通知が届きます。

<img width="300" alt="google" src="https://user-images.githubusercontent.com/34936885/69491178-c89fe880-0ed4-11ea-9fbd-ae1de74fd298.png">

ここに「Mac デバイス」など何の端末でログインしたか表示されますが、iPad（第5世代 13.1.3）でログインすると「Apple iPad デバイス」と表示され、iPad Pro(12.9インチ 第3世代 13.2）でログインすると「Mac デバイス」と表示されました。

これはスクリーンサイズとかで判定してるんですかね？もう端末の判定はあきらめた方がいいような気もします...

# おわりに
iPadのUAの変更の影響は、本業（モバイルアプリ開発）の方では特にありませんでした。モバイルアプリでは独自UAを設定していることが多く、WebViewでの表示に影響があってもWebサイトの改修になるので、これといって対応することがありませんでした。

iPadでネットサーフィンをしているとレイアウトが崩れているサイトをちらほら見かけるのでWeb側は多少なり影響を受けたようですね:sweat:
シェルスクリプトのちょっと実用的な数行の関数（日時 #2）

# 日時

[前回](https://qiita.com/3244/items/1d8a195cfca131701902)に引き続きシェルスクリプトのちょっとした関数で、日時の続きです。

## 日時をUNIX時間に変換する

UNIX 時間は、UTC の 1970年1月1日からの経過秒数（エポック秒）です。整数値なので経過時間の計算や比較がしやすくなります。

```Shell:
# $1  日時を表す文字列
function datetime_to_epoch() {
  date -d "${1}" +'%s'
}
```

## 現在の日時をUNIX時間で出力する

「`date +'%s'`」に名前を付けてスクリプトの可読性を良くするための関数です。

```Shell:
function epoch_now() {
  date +'%s'
}
```
### 使用例（タイムアウトの処理）

ループ 1回ごとに現在時刻と制限時刻を比較して継続／終了の判定をする例です。UNIX 時間なので加算と比較が簡単にできます。

```Shell:
TIMEOUT_SECONDS=10  # タイムアウトの秒数

# 現在時刻にタイムアウトの秒数を加算して制限時刻を得る。
limit_time=$(( $(epoch_now) + ${TIMEOUT_SECONDS} ))

# 制限時刻まで処理を続ける。
while (( $(epoch_now) <= ${limit_time} ))
do
  do_something
  sleep 1
done
```

## UNIX時間を日時に変換

逆変換の`@`も忘れがちで、可読性も低いので関数にします。

```Shell:
# $1  日時を表す文字列
# $2  書式指定文字列（省略可 省略時は'yyyy-MM-dd hh:mm:ss'で出力する）
function epoch_to_datetime() {
  date -d "@${1}" +"${2:-%F %T}"
}
```

## 日時の差分計算

前回の[「日時の加算／減算」](https://qiita.com/3244/items/1d8a195cfca131701902#%E6%97%A5%E6%99%82%E3%81%AE%E5%8A%A0%E7%AE%97%E6%B8%9B%E7%AE%97)に対して、今回は 2つの日時の差分を求める関数です。端数は切り捨てられます。

```Shell:
# $1  出力する差分の単位 {day|hour|minute|second}
# $2  日時を表す文字列
# $3  日時を表す文字列 $2 < $3で正の値、$2 > $3で負の値を出力する
function diff_datetime() {
  # UNIX時間に変換して、2つの日時の差分を秒単位で求める。
  local formula=$(( $(datetime_to_epoch "${3}") - $(datetime_to_epoch "${2}") ))

  case "${1}" in
    second  ) ;;
    minute  ) formula+=" / 60" ;;
    hour    ) formula+=" / 3600" ;;
    day     ) formula+=" / ( 3600 * 24 )" ;;
    *       ) return 1 ;;
  esac

  echo "${formula}" | bc
}
```

## 月初の日付

可読性のために、前回の[「日時の書式設定」](https://qiita.com/3244/items/1d8a195cfca131701902#%E6%97%A5%E6%99%82%E3%81%AE%E6%9B%B8%E5%BC%8F%E8%A8%AD%E5%AE%9A)を使用します。
まず書式`'%Y-%m-01'`を使って強制的に 1日の 0時にしてから、指定の書式があればフォーマットして出力します。

```Shell:
# $1  日時を表す文字列
# $2  書式指定文字列（省略可 省略時は'yyyy-MM-dd'で出力する）
function first_day_of_month() {
  local first_day=$(format_datetime "${1}" '%Y-%m-01')
  format_datetime "${first_day}" "${2:-%F}"
}
```

## 月末の日付

前回の[「日時の加算／減算」](https://qiita.com/3244/items/1d8a195cfca131701902#%E6%97%A5%E6%99%82%E3%81%AE%E5%8A%A0%E7%AE%97%E6%B8%9B%E7%AE%97)を使用します。
月末は日が 28 〜 31 の間で変動するので、月初のように日の強制変換ができません。そのためまず翌月の月初を取得してから、その前日を求めて当月の月末にします。

```Shell:
# $1  日時を表す文字列
# $2  書式指定文字列（省略可 省略時は'yyyy-MM-dd'で出力する）
function last_day_of_month() {
  # 月初の1か月後 = 翌月の月初
  local next_1st_day=$(add_datetime "$(first_day_of_month "${1}")" 1 month)

  # 翌月の月初の前日 = 当月の月末
  add_datetime "${next_1st_day}" -1 day "${2:-%F}"
}
```
テンプレートのパイプライン

#パイプラインとは
テンプレート上で引数や関数、メソッドを直列につなげたもの

##例
下記のように書くことで `12.3456` を `printf "%.2f"` の引数に送れる

```go
{{ 12.3456 | printf "%.2f" }}
```
ssh: connect to host github.com port 22: Operation timed out

## SSH接続エラー？
普段からGitHubにアクセスしているMacでコードをアップしようとすると、22番ポートでSSH接続できないとのエラーがでたので対処していく。

```
$ git push -u origin HEAD
ssh: connect to host github.com port 22: Operation timed out
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

## 結論
443番ポートでアクセスする設定で接続することで、接続に成功した。22番ポートで接続できなくなった理由は不明のまま。

```
$ vi ~/.ssh/config
Host github.com
    User git
    Hostname ssh.github.com
    Port 443
    IdentityFile ~/.ssh/id_rsa
```

```
$ git push -u origin HEAD
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 1.45 KiB | 1.45 MiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To github.com:toppy-luna/TodoList-Vuejs.git
 * [new branch]      HEAD -> issue#1_regist_code
Branch issue#1_regist_code set up to track remote branch issue#1_regist_code from origin.
```

## 参考
Githubにport:22 で push できなかった場合の対処法
https://qiita.com/SOJO/items/74b16221580a17296226
超初心者向けMac用開発環境（Apache）の導入

#はじめに
Vue.jsの勉強を始めようとしましたが、httpdがあった方が正確とのことだったので、Mac用の環境をセットアップすることにしました。


#ダウンロード
https://www.mamp.info/en/

Free Download

MAMP & MAMPPRO 5.5をダウンロードします。

#インストール及び設定
インストーラーに沿ってインストールします。

アプリケーションフォルダのなかに、「MAMPフォルダ」と「MAMP PRO」のアイコンができています。

MAPMPフォルダを開くとMAPMアイコンがありますのでクリックして起動です。

下記のような画面が開きます。

Start Serversをクリックします。起動するとWebページが開かれます。

Preferenceを開いて見ましょう。そこのWeb Serverにドキュメントルートが書いてあります。
[Unity][Shader Graph] 乗算matcapシェーダー作った

# LWRP でMatcap Shader 作った

基本構造はこちらの構造を踏襲する。
https://qiita.com/akerusoft/items/d58416d608cb3c76c153

Normal Dir -> Transform (World -> View ) が、Normal Vector (View) だけに纏まっている感じですね。
早くShader Graph 使う人が増えて、情報増えてほしいｗ

![matcap1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231914/211c5e99-ba6c-c9ce-179a-6fb686d53e6d.png)

一応、Lighiting power と称した強度と、White Blance と称した明るさ調整機能も追加してみた。
しかしながら、軽いのが売りのMatcapに余計な計算加えるのは微妙だなぁと思いつつ。

Shader forge だとValueで値を入れるところを、Vecter1で代用するのが正なんだろうか？
挙動的には問題なさそう。

![matcap2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231914/a3b720be-7ed2-413d-19d9-1dd0a8e8a447.png)
![matcap3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231914/17a9a0f8-44d1-dd9a-90bf-3e2c5c81895d.png)

文字が小さすぎてキャプチャに向かない…ｗ

## こういうことになる

輪郭が残念なことになってるのはGif圧縮のせい

![Matcap.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/231914/1552436a-2481-6f8c-2ca8-ff5a9c3164d5.gif)

Matcap Shader で某7つの大罪の映像部分を色々とやったという話も出ているし、
今後需要ありそうですよね。Matcap。

© UTJ/UCL
二部グラフの判定

問題：CODE FESTIVAL 2017 qual B 3steps
https://atcoder.jp/contests/code-festival-2017-qualb/tasks/code_festival_2017_qualb_c

```python

from collections import defaultdict, deque, Counter
import sys
def LI(): return list(map(int, sys.stdin.buffer.readline().split()))


def bipartite_or_not(G, s=0):
    n = len(G)
    global color
    color = [0] * n
    color[s] = 1
    dq = deque([s])
    while dq:
        u = dq.popleft()
        for v in G[u]:
            if color[v] == 0:
                color[v] = -color[u]
                dq += [v]
            else:
                if color[u] == color[v]:
                    return False
    return True


n, m = LI()
G = [[] for _ in range(n)]
for a, b in LIR(m):
    G[a - 1] += [b - 1]
    G[b - 1] += [a - 1]


if bipartite_or_not(G):
    print(color.count(1) * color.count(-1) - m)
else:
    print(n * (n - 1) // 2 - m)

```
koa-routerのせいでKoaのミドルウェアが効かない？

KoaでCORSを有効化しようとしてしばらく悩んだので知見共有

# 前提

```js
const Koa = require("koa")
const Router = require("koa-router")
const bodyParser = require("koa-bodyparser")
const logger = require("koa-logger")
const cors = require("@koa/cors")

const app = new Koa()
const router = new Router()

app.use(bodyParser())
app.use(logger())
app.use(router.routes())
if(process.env.NODE_ENV !== "production") {
	app.use(cors())
}

router.get("/ping", ctx => {
	ctx.body = "pong"
})

app.listen(8081)

```

確かに ```NODE_ENV``` は development になっているのに ```localhost:8080``` にホストしたクライアントからアクセスするとCORSでエラーが出る…


# 原因と解決
koa-routerを使ってるとき、```app.use(router.routes())``` したあとでは ```app.use()``` が効かなくなるようです
代わりに ```router.use()``` を使うと動きます

```js
app.use(router.routes())
app.use(async (ctx, next) => {
	console.log("koa.use()")
	await next()
})
router.use(async (ctx, next) => {
	console.log("router.use()")
	await next()
})
```

```
  <-- GET /
router.use()
  --> GET / 200 11ms 4b
```

もしかして常識…？


どうしても ```app.use()``` しなきゃいけない場合は ```app.use(router.routes())``` する前にしましょう

```js
app.use(async (ctx, next) => {
	console.log("koa.use()")
	await next()
})
router.use(async (ctx, next) => {
	console.log("router.use()")
	await next()
})
app.use(router.routes())
```

```
  <-- GET /
koa.use()
router.use()
  --> GET / 200 11ms 4b
```
Excel でデータ量が多い時の Tips

## その1：大量データの VLOOKUP 高速化

### TL;DR
---
#### 検索範囲をソートして、近似値検索する
---

### 背景

 百万件弱のバッチデータを Excel で付き合わせる必要が出てきた。  
 詳細は以下の通り。

 条件：
 - 今回のデータはデータセット内で一意なキー情報のみ
 - とある回のデータセットには、別の回のデータセットに含まれるデータが大部分（80%以上）含まれる


 やりたい事：
 - 2つの日のデータセット間の差分を検出
 - 増加分／減少分のキー情報を特定

### COUNTIF 関数や VLOOKUP 関数の「完全一致」だと時間がかかる
 COUNTIF 関数を使って 0 or 1 で判断しようとしたら、数十万行分の「Ctrl + d」で、CPU使用率が振り切れてフリーズ。。。
 計算量としては、データ量をn件とすると、検索範囲にある全件との比較を1レコード目からnレコード目まで実行するので、 O(n^2) となる。

 VLOOKUP でも計算に時間がかかり、操作が非常に重くなった。
 線形探索では、一致する値が見つかるまで一件ずつ比較するので、データ量に比例して計算量が増加する。
 平均して全体の半分でヒットすると仮定しても、計算量は O(n) となる。

### VLOOKUP 関数の「近似値検索」を使う
 普段おまじない的に「FALSE」を指定していた **VLOOKUP 関数の第4引数：[検索方法]**
 ザックリ言うと、ここを「**TRUE**」にすると、インデックス検索してくれるイメージ。 
 そのための前提条件として、検索範囲となるデータをソートしておく必要がある。
 すると、得られる結果は、完全一致したものか、インデックスによるとこの辺にあるはず！というところのものを返してくれる。  
 原理的には、検索対象がソートされているので、二分探索（木）が使える。
 そのため、掲載量は O(log n) となり、データ量が増えても計算量はほとんど増えない。

 でも、近似値を使いたいユースケースなどほぼなく、だからこそ今まで使っていなかった。
 そこで、完全一致と同様に使うには、以下の2段階にすればよい。  
 1. 近似値検索で、検索範囲のキー情報を返す。

<img width="434" alt="1.VLookUp_TRUE.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533310/47117649-e251-6206-a1d1-7223aa4e7805.png">


 1. 関数で返された値と関数に渡した検査値（キー情報）が同一かどうか比較し、同じであれば完全一致

<img width="416" alt="2.完全一致.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533310/de9716ed-5bce-c515-f693-d2951f8d64c7.png">

※　この考え方は他の関数（MATCHなど）にも応用できる。

### おまけ（参考サイト）
計算量について：https://archives.aotsuki.org/excel-functions-optimize-lookups/

応用編（並べ替えの注意点なども）：https://excel-ubara.com/excel3/EXCEL019.html   

---
GAE/Go go112 移行 のなにか ニャ

# 何？

苦しい。。。移行だった？ 多分移行のさせ方がひどいと思ったが正しい認識（ユーザー視点）


# やった表

※ **lib change** -> appengine ライブラリから cloud.google.com のものに変更

| 項目 | Code | Local Env | GCP Env |
|------|------|-----------|------|
| Datastore | **lib change**<br><br>・Connection Pool,Namespace周り Configurationした  | Emulatorに切り替え<br><br>・Viewer npm のものを利用中<br>・dev_appserver.py を利用にはpython は gRPCのインストールが必要 | 特にすることなし |
| CloudTask | **lib change** | Local で使えないので、POST するやつ自作対応 | API の認可 | 
| Memcached | 部分的に LRU | 今の所なし | 代替え先サービスを利用していない |
| Logging | 自作 （Log参考リンクから対応） | Stdout 出力 | GCPの仕様に合わせて、出力 |
| app.yaml login required | [google_sign-in](https://cloud.google.com/appengine/docs/standard/go/authenticating-users#google_sign-in) に移行 | 変更なし | APIとサービス＞認証情報＞OAuth2.0 で以下を設定 <br>・承認済みの JavaScript 生成元<br>・承認済みのリダイレクト URI |
| dev_appserver.py | app.yaml を利用しないので、起動時の環境変数とか自前で設定が必要になる。<br>・Localでの静的なファイルのRoutingがなかなか面倒 | realise に変更 | app.yaml 移行箇所編集 runtime, handlers ... |
| gcloud app deploy | .gcloudignore を書く | N/A| gcloud build 使うようになった |
| CloudSQL | 変更なし | 変更なし | unix socket を使ったDSNに変更 |
| PubSub | 変更なし | 変更なし | 変更なし |


# 参考リンク

* Logging
     * [AppEngineの旧Log APIを脱却したい話](https://tech.mercari.com/entry/2019/05/22/122803) 
     * [GAE のログに憧れて](https://medium.com/google-cloud-jp/gae-%E3%81%AE%E3%83%AD%E3%82%B0%E3%81%AB%E6%86%A7%E3%82%8C%E3%81%A6-895ebe927c4)
     * [Echoを使ってGAE/Go1.12(第二世代)でいい感じにログを出す](https://qiita.com/br_branch/items/fa2a53c7b002298fd83d) （自前だとこんな感じ）
不等式での引数の順番

if文の条件の中で不等式を使うことがよくありますが、そのときに引数をどういう順番にするのかという、所感です。


# リーダブルコードでは

「制御フローを読みやすくする」で、下記のような例がでてきます。
https://www.oreilly.com/library/view/the-art-of/9781449318482/ch07.html

```
if (length >= 10)
```

or 

```
if (10 <= length)
```

`length >= 10` の方が良いと、リーダブルコードでは書かれています。
変数やより関心が高いものを左側（先）に書く良いともまとめられています。

これは、 「`length` is greater than or equal to 10」という英文とマッピングしやすくするためなのでしょう。


## 不等式を２つ使うとき

変数の範囲に、最大・最小があるケースです。

リーダブルコードの流儀でいくと、下記にようになります。

```
if (length > 10 && length < 20)
```

実際、こう書かれているコードもよく見かけます。
「`length` is greater than 10 and is less than 20」とマッピングさせるなら、自然です。

## 2つの変数を比較する

この場合、より関心が高い方の変数を左にすることになります。どっちでもいい場合はどう書いていいのでしょう。

「今年の売上が去年の売上より大きいか」というときは、下記のようになるでしょう。

```
if (this_year_sales_amount > last_year_sales_amount)
```

# 不等式を数直線と対応づけるなら

不等式を視覚的に理解するために、数直線がよく使われます。高校の数学で大概の人は習うのではないでしょうか。

>
---10-- length --20 ---> 


この視覚イメージをそのままコードにすると、こうなります。

```
if (10 < length && length < 20)
```

これをルールとするなら、「小さい方を左、大きい方を右」（`小 < 大`） となります。
（不等式を書くときは、このようにした方がよいと、教わった覚えがあります。）


## 数直線と対応づけるメリット

「小さい方を左、大きい方を右」というルールは、意外と便利です。

* 大小関係が視覚的にわかりやすい（読み間違いしにくい）
* 変数や条件の数に左右されない（書き間違いしにくい）
* 仕様書に「0 < x < 1」という不等式で書かれていた場合に、ほぼそのままの形でコーディングできる

小さい順に書くので、不等式の記号は `<` しか使いません。
なので、大小関係に限れば、読み間違いも書き間違いも、ほぼ起きないでしょう。

# まとめ

極論としては、どちらでもいいかなと思います。どちらも一定のメリット・デメリットがあります。
チーム内やプロジェクト内で、どういう方針をとるかが決まっていないと、混在するとちょっと困るというところです。

数直線に対応づけたい人は、リーダブルコードのやり方はやや読みづらく思うでしょうし、逆もそうでしょう。
OAuth 2.0 のシーケンスをまとめてみた  

# はじめに
最近、Vue.js と Flask で API とそれを叩くページを作成しています。
その際、認証周りをどうしようかと悩んで、調べていくと **OAuth** が
いいんじゃないか、という結論に行きつきますが Qiita などを見ながら調べてもよくわかりませんでした。

そんな中、とってもわかりやすい資料を見つけました。
[[Slide Share] 基礎からの OAuth 2.0 - Developers.IO 2017](https://www.slideshare.net/daisuke_m/oauth-20-developersio-2017-20170701?qid=904e9e81-6175-4c37-9f15-3e1fe38cabb0&v=&b=&from_search=5)
しかも何と、YouTube で解説動画もあります。
[[YouTube] DevelopersIO 2017 基礎からの OAuth 2.0 perform by 都元ダイスケ #cmdevio2017](https://www.youtube.com/watch?v=PqW948SFSUM)

この資料の内容を部分的にピックアップしていきます。

# 認証と認可
## 認証 (Authentication)
**通信相手が誰か、確認すること**

* ネットワークやサーバへアクセスする際に、本人性をチェックし、正規の利用者であるかどうかを確認。
* 確認方法は通常、ID/Password で行う。
* HTTP status "401 Unauthorized" に関わる

## 認可 (Authorization)
**リクエストが許可されるかどうかを決めること**

* 認証によって利用者を識別し、その利用者に合ったアクセス権限の制御を行う。(ポリシー)
* HTTP status "403 Forbidden" に関わる

通常、認証 -> 認可 の流れでユーザは与えられた権限内でリソースへのアクセスを行う。

# OAuth 2.0 の登場人物
|キーワード|説明|
|---|---|
|Resource owner (RO)|ユーザ、Client のリソースへのアクセスを認可する|
|Client|アプリ、RS が抱えるユーザリソースへのアクセスを行う張本人|
|Authorization server (AS)|RO/RS の仲介役、Client へ RS へのアクセスのキーとなるアクセストークンを発行する|
|Resource server (RS)|ユーザリソース、アクセストークンがなければアクセスすることができない|

OAuth 2.0 の基本的な流れとしては、RS にあるユーザリソースにアクセスしたい Client が、AS からアクセストークンを発行してもらい、そのアクセストークンを持って Client は RS にアクセスをする。アクセストークンの発行は、 RO が認可をする。

# Client がアクセストークンを取得するフロー
## Client credentials grant
![OAuth 2.0 - client credentials grant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353538/fe05e1e3-c450-6f57-2a5d-8b84dc1d90bd.png)

### ポイント
* Client ID + secret => アクセストークン
* リソースオーナーの認可無しに、AS はアクセストークンを発行
* リソースオーナーがフローに介在しないため、Client は好きなスコープでリソースにアクセスできてしまう

## Resource owner password credentials grant
![OAuth 2.0 - resource owner password grant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353538/78da1795-3cec-9b6a-1061-08a5c14fd077.png)

### ポイント
* User ID + Password => アクセストークン
* Client が リソースオーナーのパスワードを知ってしまう
* 公式 Client 向け

## Implicit grant
![OAuth 2.0 - Implicit grant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353538/48dced83-ae11-c31f-295c-a969d83ccad5.png)

### ポイント
* アクセストークンがユーザやブラウザに見えてしまう
* エンドユーザ支配下にある Client 向け

## Authorization code grant
![OAuth 2.0 - Authorization code grant.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353538/2baeb905-4064-697f-6fa6-bbef76c5180e.png)

### ポイント
* Authorization code (AC) => アクセストークン
* AC はアクセストークンを得るための引換券であり、ユーザやブラウザから見えても問題ない
* サーバサイド Web アプリケーション Client 向け

# 取得したアクセストークンの送信方法
Authorization ヘッダの Bearer スキームを使用
> `Authorization: Bearer <ACCESS TOKEN>`

# おまけ
OAuth の各種フローのシーケンス図は、PlantUML というツールを使用して作成しています。
コードベースで図を作成でき、とてもかんたんです。
ソースコードは、GitHub で公開しておきます。
[[GitHub] guromityan/oauth_plant_uml](https://github.com/guromityan/oauth_plant_uml)
GroovyのDefaultGroovyMethodsとJavaのStream APIの相互変換まとめ

仕事でGroovyのDefaultGroovyMethodsをJavaのStream APIを使った形に書き直すという作業を行ったので、備忘録も兼ねてまとめます。

サンプルコードの動作はそれぞれ以下のバージョンで確認しています。
Java: 11
Groovy: 2.5.8


#DefaultGroovyMethod ⇔ Stream API
##each ⇔ forEach
```groovy:Groovy
def list = ["Java", "Groovy", "Scala"]
list.each { println it }

---結果---
Java
Groovy
Scala
```
```java:Java
List<String> list = List.of("Java", "Groovy", "Scala");
list.forEach(System.out::println);

---結果---
Java
Groovy
Scala
```
##collect ⇔ map + collect
```groovy:Groovy
def lowerCases = ["java", "groovy", "scala"]
def upperCases = lowerCases.collect { it.toUpperCase() } 
println upperCases

---結果---
[JAVA, GROOVY, SCALA]
```
```java:Java
List<String> lowerCases = List.of("java", "groovy", "scala");
List<String> upperCases = lowerCases.stream().map(language -> language.toUpperCase()).collect(Collectors.toList());
System.out.println(upperCases);

---結果---
[JAVA, GROOVY, SCALA]
```
##findAll ⇔ filter + collect
```groovy:Groovy
def numbers = [1, 2, 3, 4, 5] 
def odds = numbers.findAll { it % 2 != 0 } 
println odds

---結果---
[1, 3, 5]
```
```java:Java
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> odds = numbers.stream().filter(number -> number % 2 != 0).collect(Collectors.toList());
System.out.println(odds);

---結果---
[1, 3, 5]
```

##参考資料
###公式リファレンス
List
https://docs.oracle.com/javase/jp/8/docs/api/java/util/List.html
Stream
https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html
Collectors
https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Collectors.html

DefaultGroovyMethods
http://docs.groovy-lang.org/latest/html/api/org/codehaus/groovy/runtime/DefaultGroovyMethods.html

###Qiita記事
Groovyよく使いそうなメソッド（List編）
https://qiita.com/kimromi/items/e326bf9c24220df97ecf
ネットに転がっているC#のサンプルコードがコンパイルできないときの主な要因

※個人の感想です。
千差万別なので解決策は書いていません。というより書けない…

# 1.コードが断片である

## 1-1. `Main`関数がない

`static void Main(string[] args)`とかがない。

## 1-2. `using`ディレクティブがない

`using System.なんとか.かんとか;`がない。不足している。

## 1-3. Visual Studio前提のコード

Visual Studioで作成したコードの一部しか載せていない場合。
`partial class`とか`InitializeComponent`とかを使っているのはこのケースが多い。

# 2. 新しめのC#バージョンの機能を使用している

C#のバージョンごとの機能は、ここが詳しい。
https://ufcpp.net/study/csharp/

古いバージョンへのポーティング手法
https://ufcpp.net/study/csharp/cheatsheet/listfxlangversion/

タプル(`Tuple`)とか`?.`とか`??=`とか`$"{X}"`とか使ってたらバージョンによるものかもしれない。

# 3.コンパイルしていないコードが置かれている

あまりないけど、まれに。
コンパイルしたあとに修正したりして、コンパイル通らなくなったコードになってたり。

# 4.参照設定が必要なのに言及がない / ライブラリのバージョンが合わない

説明が書かれているケースが多いが、環境が違うとハードル高い。

# Appendix. コンパイルはできるが挙動がおかしい場合
環境差によるもの / コード起因のもの
- プログラムの入出力の文字コードがあっていない。
- ソースコードの文字コードがあっていない。
- コンパイルオプションがあっていない。
- <b>64bit / 32bitを考慮していないコードになっている。</b>
- `Main`に`[STAThread]`がついていない。

あたりを疑う。
【Gatsby.js 】チュートリアルでError: Cannot find module 'react'

## 公式チュートリアルなのに
`gatsby-starter-hello-world`のスターターを使用してGatsby.jsを動かしていくのだけども、そのなかのtypographyプラグインを使う箇所で不具合が発生してうまく進められなくなる。

## Error: Cannot find module 'react' :rotating_light: 発生
チュートリアルのchapter3でプラグインをnpm installしたあとに `gatsby develop`すると発生する不具合。

## 解決法
学習が進められるようになるよ :nerd: :nerd: 

### npmを使わない、yarnを使う。
チュートリアルに合わせていうならば
`yarn add gatsby-plugin-typography react-typography typography typography-theme-fairy-gates`をつかう。

## 原因
npm :package: 側の問題。
結構前からこの[issue](https://github.com/gatsbyjs/gatsby/issues/6834)で論議されているけれどまだnpm側が治ってないみたいです。解決策のみ抜粋しましたので、詳しくは前記issueをご覧ください。

なのでGatsbyでのパッケージインストールはyarnを使用するのが良さそうです :nerd:


以上です:nerd: ありがとうございます.
deviseでログイン機能をつくろう！ ❏Rails❏

#【基本】
deviseというgemを使えば、よくあるログイン機能を簡単に作成できます。

#①
Gemfileに

```ruby:Gemfile
gem 'devise'
```
を記述し

```terminal
bundle install
```
を実行

<br>
その後、サーバーを再起動。

```
rails s
```
なぜなら、サーバーを起動した際にgemが反映されるからです。

#②
```
rails g devise:install
```
で設定ファイルを作成。

#③
```
rails g devise user
```
でモデルを作成し

```
rails db:migrate
```
を実行

<br>
自動で追記される↓

```ruby:config/routes.rb
Rails.application.routes.draw do
  devise_for :users
#以下略
```

こいつのおかげで必要なルーティングが一気に生成され、current_userやuser_signed_in?などのヘルパーメソッドが使えるようになる。

#④
```
rails g devise:views
```

でビューファイル作成。

以上！

<br>
#【応用】
###新規登録時にニックネームを登録できるようにする。
デフォルトで登録できる情報は、メールアドレスとパスワードの2つです。
ユーザーのニックネームも登録できるようにしたいものです。
カラムを追加する方法を見ていきましょう。

#①
```
rails g migration AddNicknameToUsers nickname:string
```
でマイグレーションファイルを作成し

```
rails db:migrate
```
を実行

#②
deviseでログイン機能を実装した場合のパラメーターの受け取り方は通常とは異なります。

```ruby:app/controllers/application_controller.rb
 class ApplicationController < ActionController::Base
    before_action :configure_permitted_parameters, if: :devise_controller?

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
    end
  end
```
難しいことが書いてありますが要約すると、
nicknameカラムの情報をパラメータとしてサーバーに送信することを許可します。
ということです。

<br>
これで新規登録時に、ニックネーム・メールアドレス・パスワードの3点が登録できるようになります。

<br>
ではまた！
Amazon Linux （EC2）でdirenvをセットアップする

# direnvとは？
`direnv`とは、ディレクトリごとに環境変数を定義することができるツール（コマンド）です。
つまり、他のディレクトリに影響を及ぼさない変数を定義できるということです。`direnv`によって定められた環境変数はカレントディレクトリ（自分が今いるディレクトリ）でのみ有効になります。

通常の環境変数はプロジェクト全体に作用することが一般的ですが、`direnv`ではディレクトリごとに設定できるので、より細かく環境変数を設定したい場合などに非常に有効です。

今回はAmazon Linux（EC2インスタンス）にデプロイするときに`direnv`コマンドが入っておらず困ったので、そのインストール方法を残しておきます。

お手元のMacOSに`direnv`を入れたい場合などは、他のページをご覧になるとわかりやすいですが、当ページでも基本的にやっていることは同じなので一部参考になさってください。

今回の環境は以下になります。
Amazon Linux
CentOS 6

# direnvのインストール
ローカルのMacOSなどでhomebrewが入っていれば`brew`コマンドを使ってこのように簡単にインストールすることができます。

```
$ brew install direnv
```

Amazon Linuxにhomebrewが入っている場合は上記の方法でインストールすれば良いです。（その方が簡単！）
もし、`brew`が入っていないよ:baby:という方は以下のようにすればhomebrewを入れることなく`direnv`を無事にインストールできます。

```
$ cd /var/www/html
$ sudo git clone https://github.com/direnv/direnv
$ cd direnv
$ sudo make install
```

この `sudo make install`の時点で `bash: go: コマンドが見つかりません`となった場合、それはAmazon Linuxに `go`が入っていないだけですので、`yum`で入れてあげましょう。

```
$ sudo yum install golang
```

これで`go`が入るはずです。バージョンを確認します。

```
$ go version
go version go1.12.8 linux/amd64
```

確かに入っていますね。

これで先ほどの`bash: go: コマンドが見つかりません`のエラーは解消されているはずですので、もう一度試しましょう。

```
$ cd /var/www/html/direnv
$ sudo make install
```

これで `direnv`のインストールができました:santa:
あとは `.bashrc`あるいは`.zshrc`に以下を1行記載しておきましょう。

```
$ sudo vim ~/.bashrc
// 末尾などに記載
eval "$(direnv hook bash)" 
```

あとは`.bashrc`の変更を読み込めばOKです。
`source`コマンドで`.bashrc`の変更を読み込みましょう。

```
$ source ~/.bashrc
```

これで`direnv`が入ります。念のため、バージョンを確認しておきましょう。

```
$ direnv version
2.20.1
```

無事に`direnv`をインストールできました:dancer:
これ以降は `/var/www/html/direnv/*`は不要なディレクトになりますので、削除しても構いません。

```
$ cd /var/www/html
$ sudo rm -r direnv/
```

# `direnv`を実際に使ってみる
`direnv`の一番基本的な使用方法を紹介しておきます。
まず環境変数を定義したいプロジェクト`project`に移動します。
**環境変数はディレクトリごとに定義する**と冒頭で言いましたが、今回は`project`のルートディレクトリ`/`で管理してみます。

```
// 環境変数を定義したいあなたのディレクトリへ移動します。
$ cd /var/www/html/project
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
```

何やら怪しいエラーを吐いていますが、なんてことはありません。エラー文の指示通りに

```
$ direnv allow
```
としてあげましょう。
今後もこういったエラーを吐くことがありますが、その度に`direnv allow`を呪文のように唱えればOKです。

さて、このディレクトリに`.envrc`というファイルを新しく作成して、このファイルに環境変数を定義します。

```
$ echo export ENV_USERNAME=hogehoge >> .envrc
$ echo export ENV_PASSWORD=hugahuga >> .envrc
```

これで`.envrc`に環境変数を定義できているはずです。
`.envrc`ファイルの中身はこのようになっているはずです

```
export ENV_USERNAME=hogehoge
export ENV_PASSWORD=hugahuga
```

また、コマンドラインから`.envrc`の中身を確認することも可能です。

```
$ echo ${ENV_USERNAME-nope}
hogehoge // OK (nopeの場合は設定に不備があります)

$ echo ${ENV_PASSWORD-nope}
hugahuga // OK (nopeの場合は設定に不備があります)
```

上記のようになれば環境変数を定義できています。
実際に、このディレクトリに改めて移動すると、環境変数が有効になっていることが確認できます。

```
$ cd ~
// 環境変数が無効化
direnv: unloading 

$ cd /var/www/html/project
// 環境変数が有効化
direnv: loading .envrc 
direnv: export +ENV_USERNAME +ENV_PASSWORD
```

# `.envrc`は絶対にcommitしない
`.envrc`にはパスワードなどの機密情報を記載することが一般的です。
これはGitないしはGitHubなどを使用する際の汎用的な注意点ですが、 **パスワードなどの情報が記載してあるファイルは絶対にcommitしない** ように注意しましょう。
これを防ぐためには、例えば`.gitignore`に`.envrc`を追記してあげれば良さそうですね。
Centos8をインストールして実施したこと～zabbix serverインストール前～

あくまで自分の環境下での話なので、他で使えるかは検証していません。ご了承ください。
ちょっとCentosにzabbix serverを設定したいので記録です。

◆環境
　・ホスト側
　　　windows 10 pro（1903 build 18362.418）
　　　VMware Workstation 15 Player　（15.5.1 build-15018445）

　・クライアント側
　　　CentOS Linux release 8.0.1905 (Core)
　　　サーバ（GUI）だけでインストールを実施
　　　ネットワーク設定は済ませた

#◆やったこと　※全部管理ユーザーで実行しています
####1.selinuxの無効化
1-1.selinuxが有効であることを確認する

```diff:
　# getenforce
　Enforcing
```

1-2.設定ファイルの修正を実施する

```diff:
　# vi /etc/selinux/config
```

1-2-1.変更点
　・以下の文字列を変更する
　　変更前：SELINUX=enforcing
　　変更後：SELINUX=disabled

1-3.OSを再起動する

1-4.selinuxが無効になっていることを確認する

```diff:
　# getenforce
　Disabled
```

####2.時刻同期設定の変更
2-1.今ちゃんと同期しているか確認する

```diff:
 # chronyc tracking
Reference ID    : D2ADA039 (ntp2.jst.mfeed.ad.jp)
Stratum         : 3
Ref time (UTC)  : Sun Nov 24 05:32:09 2019
System time     : 0.000199137 seconds fast of NTP time
Last offset     : +0.000210001 seconds
RMS offset      : 0.000210001 seconds
Frequency       : 13.926 ppm slow
Residual freq   : -1430.045 ppm
Skew            : 5.729 ppm
Root delay      : 0.094943538 seconds
Root dispersion : 0.064484976 seconds
Update interval : 1.6 seconds
Leap status     : Normal
```

一番下の「Leap status」が「Normal」ならOK

2-2.設定ファイルを修正する

```diff:
　# vi /etc/chrony.conf
```

2-2-1.変更点
　・以下の文字列をコメントアウト。追記する
　　コメントアウトする列：pool 2.centos.pool.ntp.org iburst
　　追記する列：pool ntp.jst.mfeed.ad.jp iburst

2-3.サービスの再起動を行う

```diff:
　# systemctl restart chronyd
```

　エラーが出なければOK
　
2-4.作業後も同期がとれていることの確認を行う

```diff:
　# chronyc tracking
```

　確認内容は2-1と同じ「# chronyc sources」で同期先も確認できる

####3.アップデートの確認と実行する
3-1.アップデートの確認

```diff:
　# dnf check-update
```

すいません見てもわからん

```diff:
　# dnf update
```

確認には「ｙ」で進める。「完了しました！」表示を確認してプロンプトが戻ってきたらOK

####4.MySQLのインストール
4-1.端末から以下のコマンドを実行する

```diff:
　yum -y install mysql-devel
　yum -y install mysql-server
```

　それぞれ「完了しました！」表示であればOK

4-2.ログのタイムゾーンをOSの設定に合わせる

```diff:
vi /etc/my.cnf.d/mysql-server.cnf
```
4-2-1.変更点
以下の内容を追記する

```diff:
log_timestamps=SYSTEM
```
4-3.SQLを開始して接続するrootのパスワード設定・不要ユーザーの削除

```diff:
　#systemctl start mysqld.service

　mysql_secure_installation --use-default

　※パスワードは、8文字以上で英数大文字小文字と記号を含む必要がある。

　Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
　※ここで不要ユーザーとDBが消えるそうです
```

　「All done!」表示であればOK
　「... Failed! Error: Your password does not satisfy the current policy requirements」表示する場合はパスワードの複雑さを再確認すること。

ファイヤーウォールはよくわからんので後で・・・

以下サイトを参考にしました
https://www.rem-system.com/centos8-first-settings/#2_selinux
https://qiita.com/atanaka7/items/837a94b5aad63a96aa1c
Project needs to be cconverted to androidx.* dependencies が出て module が追加できないときの workaround

# はじめに
まだ AndroidX に移行できていない Android の project で、Android Studio （恐らく 3.5 以降）でモジュールを新規追加しようとしたときに、 `Project needs to be cconverted to androidx.* dependencies` が表示されて module が追加できないケースに遭遇しました。
<img width="891" alt="スクリーンショット 2019-11-24 6.47.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9695/331ac429-4999-7678-cb9a-92b3c962d288.png">

AndroidX 対応を推奨しますが、取り急ぎ module を追加できるようにする workaround があったので紹介します。

# Workaround
1. `gradle.properties` に `android.useAndroidX=true` を一旦追加する。
2. Android Studio で module を追加する（追加できる）
<img width="894" alt="スクリーンショット 2019-11-24 6.52.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9695/3235a863-d65e-09b9-6ec1-2722b2a93dea.png">
3. 1. で追加した `android.useAndroidX=true` を差し戻す
4. 追加した module の AndroidX 依存をなくす

です。

## 4. 追加した module の AndroidX 依存をなくす

について、補足します。

project 全体が AndroidX 対応していないにも関わらず、 `android.useAndroidX=true` により AndroidX 対応しているかのように見せかけて module を追加したので、追加された module は AndroidX に対応しています。
しかしながら、project 全体は AndroidX 対応していないので、不整合が発生してしまいます。

例えば、 `testInstrumentationRunner` が既存 module だと `android.support.test.runner.AndroidJUnitRunner` なのに、追加された module は`androidx.test.runner.AndroidJUnitRunner` だったりします。

このような点を既存 module に揃えることで、 `Project needs to be cconverted to androidx.* dependencies` が出て module が追加できない問題は回避することが可能です。

# さいごに
AndroidX に移行しましょう。
HTML <br>タグは乱用するな！

コードレビュー会で
:busts_in_silhouette:<必要なところに＜br＞タグを使うのは良いけど、レイアウトを整えるために＜br＞タグを使うのは良くないよ
とご指摘を受けたので＜br＞タグを使う時の注意点をまとめてみた。

参考サイト→https://tech.pepabo.com/2017/06/22/html-markup-tips-01/

```br_tag.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>brタグの乱用はダメ！</title>
    <link rel="stylesheet" href="css/br_tag.css">
  </head>
<body>
  <!-- brタグで行間を空ける -->
  <div class="container01">
    長い文章で作成したコンテンツの改行。
    <br>
    長い文章で作成したコンテンツの改行。
    <br>
    長い文章で作成したコンテンツの改行。
    <br>
    長い文章で作成したコンテンツの改行。
    <br>
    <br>
    長い文章で作成したコンテンツの改行。
    <br>
  </div>

  <!-- pタグにclass名をつけて行間はCSSで調整 -->
  <div class="container02">
    <p class="br_tag">
      長い文章で作成したコンテンツの改行。
    </p>
    <p class="br_tag">
      長い文章で作成したコンテンツの改行。
    </p>
    <p class="br_tag">
      長い文章で作成したコンテンツの改行。
    </p>
    <p class="br_tag">
      長い文章で作成したコンテンツの改行。
    </p>
    <p class="br_tag">
      長い文章で作成したコンテンツの改行。長い文章で作成したコンテンツの改行。長い文章で作成したコンテンツの改行。長い文章で作成したコンテンツの改行。
      <br>
      長い文章で作成したコンテンツの改行。長い文章で作成したコンテンツの改行。長い文章で作成したコンテンツの改行。長い文章で作成したコンテンツの改行。
    </p>
  </div>
</body>
</html>
```

```br_tag.css
div {
	width: 50%;
	margin: 20px auto;
	text-align: center;
}
.container01 {
	background: rgb(231, 231, 231);
	color: darkblue;
}
.container02 {
	background: rgb(231, 231, 231);
	color: rgb(204, 7, 99);

}
.br_tag {
	margin: 5px 0;
}
```
![20191122_Qiita01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509471/f5e20515-358a-e34a-400f-cecca069f5a1.png)

表示させるとこんな感じ。ちょっと変だけど:sweat_smile:

###影響は？
「行間空けるしbrタグ使おう」と安易な考えでマークアップしたのが青い字。
「きっと行間の調整もあるだろうしメンテナンスしやすい構造にしよう」と考えてマークアップしたのが赤い字。
brタグだけでは後々のメンテナンスが行いにくくなる。**行間の自由が利かない**。
brタグを2つ続けるなんてもっての外！:angry:
pタグ（改行が必要ない文ならspanタグでも良いかも）は段落を作るタグであり、**文章が長く改行が必要なところにだけbrタグを使うべき**。
行間の調整はclass名を付けてCSSで行う。こっちのほうが使い勝手が良く、メンテナンスもしやすい。
C# - Windowsのリンクファイル(.lnk)からリンク先情報を取得する / Drag&Dropサンプル


# サンプルコード

フォームにlnkファイルをDrag&Dropすると、コンソールにlnkファイル自身のパスとリンク先パスを出力します。

```csharp

using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;

class ShortcutTest : Form
{
    public static string GetTargetPath(string fullPath)
    {
        dynamic shell = null;   // IWshRuntimeLibrary.WshShell
        dynamic lnk = null;     // IWshRuntimeLibrary.IWshShortcut
        try {
            var type = Type.GetTypeFromProgID("WScript.Shell");
            shell = Activator.CreateInstance(type);
            lnk = shell.CreateShortcut(fullPath);

            if (string.IsNullOrEmpty(lnk.TargetPath)) {
                return "lnk file does not exists.";
            }

            //lnk.Arguments,
            //lnk.Description,
            //lnk.FullName,
            //lnk.Hotkey,
            //lnk.IconLocation,
            //lnk.TargetPath,
            //lnk.WindowStyle,
            //lnk.WorkingDirectory

            return lnk.TargetPath;
        }
        finally {
            if (lnk != null) Marshal.ReleaseComObject(lnk);
            if (shell != null) Marshal.ReleaseComObject(shell);
        }
    }

    ShortcutTest()
    {
        this.AllowDrop = true;

        this.DragEnter += (sender,e) => {
            // e は DragEventArgs
            if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
                e.Effect = DragDropEffects.Copy;
            }
            else {
                e.Effect = DragDropEffects.None;
            }
        };
        this.DragDrop += (sender,e) => {
            var fileNames = (string[])e.Data.GetData(DataFormats.FileDrop, false);
            if (fileNames != null) {
                foreach(string s in fileNames){
                    if ( s.EndsWith(".lnk", true, null) ) {// Note: 第2引数はignoreCase
                        Console.WriteLine(s);
                        Console.WriteLine(" -> " + GetTargetPath(s));
                    }
                    else {
                        Console.WriteLine(s);
                    }
                }
            }
        };
    }

    [STAThread]
    static void Main(string[] args)
    {
        Application.Run(new ShortcutTest());
    }
}
```

# 実行結果

```

C:\SvnLocal\trunk\LnkFile\Command Prompt.lnk
 -> C:\Windows\system32\cmd.exe
```

# 参考サイト

1. [[C#] ショートカットファイル(.lnk)の内容を取得する](https://note.dokeep.jp/post/csharp-shortcut-file-load/)[^1]
2. [Drag&Dropされたファイルのファイル名を取得する - dobon.net](https://dobon.net/vb/dotnet/control/droppedfile.html)

[^1]: 1のコードは、C#バージョン7で導入されたTupleを使用しているので、そのままだと、デフォルトで入っているcsc.exeではコンパイルできないかもしれません。