OmniAICreator/Qiita-1.07M huggingface dataset:
RailsでBootstrapを使うときにやることリスト

よく忘れるのでメモ。

1. gemを追加
`gem 'bootstrap-sass', '3.3.7'`
（最新バージョンはここで確認できる↓
https://rubygems.org/gems/bootstrap-sass/ ）

2. `bundle install`

3. `touch app/assets/stylesheets/custom.scss`
（CSSを正しい順序で表示させるため）

4. custom.scssに以下を追加
`@import "bootstrap-sprockets";`
`@import "bootstrap";`
Firebase DebugViewの設定方法

## 画面例
Firebaseコンソール→アナリティクス→DbugView
シュミレーターを実行するとリアルタイムにイベントに対して更新されるようになる

![スクリーンショット 2019-03-05 16.03.14.png](https://qiita-image-store.s3.amazonaws.com/0/176479/7b8153e3-1559-57d0-1ecd-ad00f3f1eccf.png)

## ドキュメント
https://firebase.google.com/docs/analytics/ios/events?hl=ja

### Xcode デバッグ コンソールでイベントを表示する

```
詳細ログを有効にして SDK によるイベントのログ記録を監視し、イベントが正しく記録されているかどうかを確認することができます。対象となるのは、自動で記録されるイベントと手動で記録されるイベントの両方です。

詳細ログを有効にするには、次のようにします。

Xcode で [Product]、[Scheme]、[Edit scheme] の順に選択します。
左側のメニューから [Run] を選択します。
[Arguments] タブを選択します。
[Arguments Passed On Launch] セクションで -FIRAnalyticsDebugEnabled を追加します。
以後、アプリを実行すると Xcode のデバッグ コンソールにイベントが表示され、イベントが送信されているかどうかを即座に確認することができます。
```

### 設定例
<img width="899" alt="スクリーンショット 2019-03-05 17.00.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/176479/48b51c46-a5fe-06e9-cf68-ca6736117c94.png">

## Xcodeコンソール上で出てくるログ例

```
2019-03-05 16:25:15.946784+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}] Debug mode is on
2019-03-05 16:25:15.950686+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}]Analytics v.50200000 started
2019-03-05 16:25:15.953470+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}] To disable debug logging set the following application argument: -noFIRAnalyticsDebugEnabled (see http://goo.gl/RfcP7r)
2019-03-05 16:25:15.986549+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}] Debug logging enabled
```

## 躓いたこと
scheme毎にGoogleService-Info.plistわけているからか
なぜかdebugの方のスキーマに、[Arguments Passed On Launch] セクションで -FIRAnalyticsDebugEnabled を追加しても
下記のようなエラーのログがでていた。(現在調査中)

とりあえずリリースビルドの方に[Arguments Passed On Launch] セクションで -FIRAnalyticsDebugEnabledを追加して、本番環境のFirebaseでみることにした

```
2019-03-05 15:50:42.202211+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}]  Analytics requires Google App ID from GoogleService-Info.plist. Your data may be lost. Google App ID has been changed. Original, new ID: {数字}:{数字の列}, {数字}:{数字の列}:ios:{数字の列}
2019-03-05 15:50:42.254265+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}] Analytics v.50200000 started
2019-03-05 15:50:42.254957+0900 {アプリの名前}[{数字の列}:{数字の列}] {バージョン番号} - [Firebase/Analytics][I-{数字の列}] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see http://goo.gl/RfcP7r)
```





## 参考
https://firebase.google.com/docs/analytics/ios/events?hl=ja
https://qiita.com/kazu14m1/items/3da746522ec41a8d5d2c
Photoshopで色収差を除去する

フィルター > Camera Raw フィルター > レンズ補正
フリンジ軽減を調整
<img width="1064" alt="Photoshop_色収差.png" src="https://qiita-image-store.s3.amazonaws.com/0/67955/18b99660-1bc5-27be-a978-45c1132b9793.png">
Serverless Frameworkで独自ドメインを設定する

定番ですが、自分用に改めて覚書。

## serverless-domain-managerプラグイン
https://github.com/amplify-education/serverless-domain-manager

## インストール

```
$ sls create -t aws-nodejs -p domain-test
$ cd domain-test
$ yarn add -D serverless-domain-manager
```

## serverless.yml

```
service:
  name: domain-test

plugins:
  - serverless-domain-manager

provider:
  name: aws
  runtime: nodejs8.10
  stage: development
  logRetentionInDays: 14

custom:
  stage: ${opt:stage, self:provider.stage}
  prune:
    automatic: true
    number: 3
  endpoint:
    production: "api-test.example.com"
    development: "devapi-test.example.com"
    default: "devapi-test.example.com"
  domainDeploy:
    production: true
    development: true
    default: false
  customDomain:
    domainName: ${self:custom.endpoint.${self:custom.stage}, self:custom.endpoint.default}
    stage: ${self:custom.stage}
    basePath: ''
    certificateArn: 'arn:aws:acm:us-east-1:xxxxxxx:certificate/XXXXXXX'
    createRoute53Record: true
    enabled: ${self:custom.domainDeploy.${self:custom.stage}, self:custom.domainDeploy.default}
```

## ドメイン作成

```
# developmentドメイン
$ sls create_domain

# productionドメイン
$ sls create_domain --stage production
```

「つながるまで40分程度かかるかも」ということなので、これだけ先行してやっておくのが良さそう。

## デプロイ

```
$ sls deploy

# productionドメイン
$ sls deploy --stage production
```

## 削除

```
$ sls remove
$ sls delete_domain


$ sls remove --stage production
$ sls delete_domain --stage production
```

## IAM
AWS CLIでadmin権限つけてる環境とかなら特に意識する必要はない。
ただ、CIとか通すなら以下の権限をつけよう。

```
acm:ListCertificates                *
apigateway:GET                      /domainnames/*
apigateway:DELETE                   /domainnames/*
apigateway:POST                     /domainnames
apigateway:POST                     /domainnames/*/basepathmappings
cloudfront:UpdateDistribution       *
route53:ListHostedZones             *
route53:ChangeResourceRecordSets    hostedzone/{HostedZoneId}
route53:GetHostedZone               *
route53:ListResourceRecordSets      *
iam:CreateServiceLinkedRole         arn:aws:iam::${AWS::AccountId}: role/aws-service-role/ops.apigateway.amazonaws.com/AWSServiceRoleForAPIGateway
```
count及びmapの使い方　特定の値を数える。　

下のように「a」が６つ「nil」が4つ文字列があった時
３番目から9番目(m[2..8])にaがいくつあるか。

```ruby
m = [ "a" , "a" , "a" , "a" , "a" , "a" , nil , nil , nil, nil ]
```

```ruby
m[2..8].count("a") => 4
```


##文字列の中に文字列がある場合は

```ruby
m = [[ "a" , "a" , "a" , "a" , "a" , "a" , nil , nil , nil , nil ],
     [ nil , nil , nil , nil , "a" , "a" , "a" , "a" , "a" , "a" ]]
```
```ruby
#上段
m[0][2..8].count("a") => 4
#下段
m[1][2..8].count("a") => 5
```

##＊縦に調べたい場合、同じようにすると間違います。（失敗例）
（m[0][0]とm[0][1]でaの数を調べる）

```ruby
#左から１番目の列
m[0..1][0].count("a") => 6
```
同じようにするとなぜか６になります。（上段のaの数になる）
＊理由を知っている方がいたら教えてください。


###mapを使って一段ずつ呼び出して、今回は一番左の列の情報が欲しいので、i[0]としています。

```ruby
m.map{|i|i[0]}.count("a") => 1
```

#配列の中に条件（i > 4）に当てはまった数を返す。

```ruby
a=[1,2,3,4,5]
a.count{|i|i > 4} => 1
```
もっと良い方法があったり、こういう考え方もあると思った人はコメントしていただけると助かります。
AlexaでSkillを作ってみよう、その１

■Step1：
---
AmazonEchoでスキルを作る覚書
まずは　Alexa Skills Kit にアクセスして、アカウントを作成しよう
https://developer.amazon.com/ja/alexa-skills-kit
![2019-02-01 (2).png](https://qiita-image-store.s3.amazonaws.com/0/122121/1e08361f-60e9-4257-3cd9-abff91d09046.png)

「サインイン」できたら「あなたのAlexaダッシュボード」もしくは「スキル開発を始める」を押してください。
■Step2:スキルを作成
---
![2019-02-01 (4).png](https://qiita-image-store.s3.amazonaws.com/0/122121/e93950fe-5f64-fe55-3b2b-e2a25634f6e0.png)
「スキル作成」ボタンを押して、作成にあたり設定をします。
![2019-02-01 (5).png](https://qiita-image-store.s3.amazonaws.com/0/122121/7fca1eec-1a74-5613-42cc-9b1b3fb60502.png)
今回は　スキル名は「foodTest01」に、デフォルト言語は「日本語（日本）」を設定しています。
スキルに追加するモデルを選択は「カスタム」のままで、「スキル作成」ボタンを押し、作成します。
■Step3:スロット作成
---
スロットとは、言葉の塊を設定するものです。
例　「foods」というスロットには「スイカ」「メロン」...などの食べ物
 ![2019-02-01 (7).png](https://qiita-image-store.s3.amazonaws.com/0/122121/ae7ad205-fb7e-fafb-80d6-836043bceb75.png)
「スロットタイプ（０）」の横の「追加」を押し、「foods」というスロットを作成します。
![2019-02-01 (8).png](https://qiita-image-store.s3.amazonaws.com/0/122121/d8f65534-734a-d31e-8aac-b24ff2dcffc9.png)
「Foods]の中に、食べ物の「ブドウ」を追加します。
![2019-02-01 (10).png](https://qiita-image-store.s3.amazonaws.com/0/122121/78d212e5-8568-612e-eea9-ba60a3769d0a.png)
「ブドウ」の同意語を追加することで、同じ言葉と判断します、今回は「ぶどう」「葡萄」を追加
![2019-02-01 (11).png](https://qiita-image-store.s3.amazonaws.com/0/122121/1dd15439-75ec-8bbd-48cd-2c7d350e96f4.png)
「ブドウ」と同じように「ミカン」「バナナ」「メロン」「スイカ」を「Foods」に追加します。
![2019-02-01 (12).png](https://qiita-image-store.s3.amazonaws.com/0/122121/c8217613-05f5-f141-dbe4-a194d8d1373e.png)
「foods」の他に「feels」のスロットを追加し、「好き」「嫌い」を設定していきます。
■Step4:インテントの追加
---
![2019-02-01 (13).png](https://qiita-image-store.s3.amazonaws.com/0/122121/f2e8d5aa-69fb-ffe7-6303-9fba5124713f.png)
「インテント（４）」の横の「追加」を押し「commandProc」というカスタムインテントを作成します。（図では文字が一部見えなくなっています）
![2019-02-01 (15).png](https://qiita-image-store.s3.amazonaws.com/0/122121/5889b18f-ec21-1725-311d-ae0862ba34b6.png)
「インテント/commnmadProc」のインテントスロットに「food」「feel」を追加します。
![2019-02-01 (17).png](https://qiita-image-store.s3.amazonaws.com/0/122121/f16b0207-f5f2-18ae-f743-e5f657b582cc.png)
「food」のスロットタイプには「foods」を「feel」のスロットタイプには「feels」を設定
![2019-02-01 (18).png](https://qiita-image-store.s3.amazonaws.com/0/122121/026bf09c-3a14-a7be-b06d-a170c2c898f0.png)
サンプル会はに「[food}が{feel}です」を追加します。
![2019-02-01 (19).png](https://qiita-image-store.s3.amazonaws.com/0/122121/00e266ba-c771-ed73-a593-d700173305ad.png)
追加が終わるとこんな感じ
■Step5：呼び出し名の設定
---
![2019-02-01 (23).png](https://qiita-image-store.s3.amazonaws.com/0/122121/d8ede154-c961-01ae-6f87-013c17d6e37c.png)
「呼び出し名」を選択し、スキルの呼び出し名を設定します。
今回は「食べ物」をせていして「モデルを保存」を押します。
![2019-02-01 (24).png](https://qiita-image-store.s3.amazonaws.com/0/122121/84dfc47a-170c-f3de-1a13-9d9683360ab0.png)
保存に成功したあとに「モデルをビルド」してください・
![2019-03-05 (1).png](https://qiita-image-store.s3.amazonaws.com/0/122121/1b731bec-727b-6575-c83b-0ceb5213ca54.png)
この画面が右下にでれば成功です。

■今回はここまで
----
「AlexaでSkillを作ってみよう、その2」でサーバとの連携を書きますので、そこで動作するようになります。
https://qiita.com/sanoh/items/e2e9927d3a56c16b070d
Railsで出力したcsvファイルをexcelで開いても文字化けしない方法

## 発生事象

RailsアプリケーションでCSV出力をしたファイルをExcelで開くと文字化ける。
理由はExcelがUTF-8のファイルをSJISで開こうとしてしまうため。
￼

```文字a化け.rb
def to_csv
  csv_column_name = %w(id 名前 メール)
  CSV.generate do |csv|
    csv << csv_column_name
    all.each do |user|
      csv << user.csv_column_values
    end
  end
end
```

## 方法1 BOM付きUTF-8でcsv出力する

bom付きにするとexcelがUTF-8で開く。
UTF-8のファイルをUTF-8として開くから文字化けない。

```bom+utf8の方法.rb
def to_csv
  bom = "\uFEFF"
  csv_column_name = %w(id 名前 メール)
  CSV.generate(bom) do |csv|
    csv << csv_column_name
    all.each do |user|
      csv << user.csv_column_values
    end
  end
end
```
```この部分.rb
bom = "\uFEFF"
```
```この部分.rb
CSV.generate(bom) do |csv|
```

## 方法2 SJISにエンコードして出力する

```sjisの方法.rb
def to_csv
  csv_column_name = %w(id 名前 メール)
  CSV.generate(encoding: Encoding::SJIS, row_sep: "\r\n", force_quotes: true) do |csv|
    csv << csv_column_name
    all.each do |user|
      csv << user.csv_column_values
    end
  end
end
```
```この部分.rb
CSV.generate(encoding: Encoding::SJIS, row_sep: "\r\n", force_quotes: true) do |csv|
```

## 参考

https://qiita.com/wada811/items/8b73f633f77c0466e9da
https://qiita.com/ngron/items/60915083cb2bc3622c79
環境作るのだよ（インストールまで）

# クライアントの環境
クライアントはパッケージング開発したいので、VS Code + Salesforce CLI + Gitで。

1. Salesforce CLI入れる
インストールとか設定はこのページを参考。
https://developer.salesforce.com/docs/atlas.ja-jp.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm

2. VS Code入れる
インストールとか設定はこのページを参考。
https://azure.microsoft.com/ja-jp/products/visual-studio-code/

3. VS Codeに拡張機能入れる
インストールとか設定はこのページを参考。
https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode

4. Git入れる
このページ。オプションはよく読んでいれてくださいな。
https://qiita.com/toshi-click/items/dcf3dd48fdc74c91b409

5. VS Codeを日本語化する
「Japanese Language Pack for Visual Studio Code」というlanguage packをいれると日本語になる。
VS Codeの拡張機能をクリックして（１）、検索ボックスに"japanese"と入れると一番上に出てくるのでインストールしてやる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/356061/4e0c9df9-a3b3-cf48-9418-829d5e8f8ab6.png)
設定は、これ。
「インストールが完了したら、Japanese Language Pack を読み込むために locale.json 内で "locale": "ja" を設定します。locale.json を編集するには Ctrl+Shift+P を押してコマンド パレットを表示させ、"config" と入力し、利用できるコマンドのリストをフィルター処理してから Configure Language コマンドを選択します。」

6. APEX PMDをいれる
5と同じように拡張機能から"APEX PMD"をいれる。
PMDは静的にAPEXのチェックしてくれる有難い拡張機能。

7. JDKも入れる
OracleからJDKをダウンロードしていれる
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
JDK 8あたりが無難。 
かならず64bit版をいれること、Windows x64ね。

8. Java homeを設定する
まずWindowsのJAVA HOMEを設定する
https://www.javadrive.jp/start/install/index4.html
間違っても動かないだけなのでビビらずに設定する。

9. VS CodeのJava Homeも設定する
　1. VS Codeのメニューから「ファイル」＞「基本設定」＞「設定」とクリックして設定画面出す。
　2. 設定の検索ボックスに"salesforcedx-vscode-apex.java.home"と入力したら、設定が出るので「setteing.jsonで編集」リンクをクリック。
　3. setteing.jsonファイルが開くので"salesforcedx-vscode-apex.java.home"に6で設定したJAVA HOMEを設定する、こんな感じ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/356061/5b103b85-ec97-1828-4bb8-348889d1b2be.png)
ちなみに、設定はこんな感じ。
{
    "salesforcedx-vscode-apex.java.home": "C:/Program Files/Java/jdk1.8.0_201",
    "apexPMD.enableCache": true,
    "terminal.integrated.shell.windows": "C:\\windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    "workbench.colorTheme": "Monokai",
    "npm.enableScriptExplorer": true
}
 * salesforcedx-vscode-apex.java.home:VS CodeのJAVA_HOME、ないと色々不都合
 * apexPMD.enableCache：よくしらない、PMD関係
 * terminal.integrated.shell.windows：シェルの設定だと思う、PowerShell指定
 * workbench.colorTheme：テーマカラー、Monokaiが好きなので
 * npm.enableScriptExplorer：npmの設定だと思うけど、わかんない
Pythonでオブジェクト指向プログラミング

# Introduction

Pythonでは「全てがオブジェクト」というのは広く知られていますが、それを自分でも理解できていませんでした。ということで、この記事ではオブジェクト指向とはどのようなものか、その概要をPythonを使って解説します(と、見栄を張ってはみましたが、もし間違いなどありましたら、どしどしコメントください)。

# よくある車の例ではさっぱり理解できない...

昔からある、古典的なオブジェクト指向プログラミングの説明書きを掲載します。


>普通車を例にしましょう。普通やの動作原理を知らなくても、運転の仕方さえわかっていれば、走る。普通車の設計書さえ持っていれば、スポーツカーやトラックなどを開発するときにも、ゼロから構築せずに、普通車の設計書を元に組み立てることができる。それがオブジェクト指向プログラミング。

...正直に申し上げると、この一文だけでは自分は理解ができませんでした。

# そもそもオブジェクトとは？

![スクリーンショット 2019-03-05 15.50.39.png](https://qiita-image-store.s3.amazonaws.com/0/335400/b568c5cb-e17c-7c0e-5bb4-2b7fc0795201.png)

今度は上図のように犬を例にしてみましょう。
この犬は「黒い毛」「つぶらな瞳」「~歳で体重10kg」などの状態を持っています。この状態を**データ**と呼びます。
犬はある規則に従って行動します。それが「4足歩行」「ワンとなく」「歩くと棒に当たる」などの振る舞いです。この振る舞いを**処理**と呼びます。
この状態(データ)と振る舞い(処理)の2つをまとめたものがオブジェクトと呼ばれるものです。

# ではクラスやインスタンスとかいう専門用語は？

![スクリーンショット 2019-03-05 15.54.57.png](https://qiita-image-store.s3.amazonaws.com/0/335400/3f7221ae-226b-b39a-35b3-bbfc874c4818.png)

## クラス

クラスは犬を作るための設計書、生物学でいうところのDNAに相当します。

## プロパティ

このDNAには「犬はこのような状態で生まれ成長する」という、データを司る部分が刻み込まれています。これをプロパティと呼びます。

## メソッド

さらにこのDNAには「犬はこのような振る舞いをする動物である」という処理を司る部分が刻み込まれています。これをメソッドと呼びます。

## インスタンス

プロパティ・メソッドの2つが刻み込まれたDNAという設計書通りに作られた「犬本体」をインスタンスと呼びます。

# オブジェクト指向の利点

コードの中身を知らなくても、使い方さえ知っていれば、スクリプトを動かすことができるところが大きな点です。上述の犬の例で言えば、犬のDNA構造を知ってさえいれば、ゴールデン・レトリーバやシェトランド・シープドッグなど、様々な種類の犬を作ることができるのです。

# 実感がわかないので、具体的なコード例を見てみよう

```python:dog.py
'''
    dog.py
'''

class Dog:
    def __init__(self):
        print('I am a dog.')

    def legs(self):
        print('The number of legs is 4.')

    def bark(self):
        print('BowWow!')
```

スクリプトの詳細はさておき、一度、このような犬のDNAを作ってしまえば、例えばゴールデン・レトリーバがほしいときには

```python
golden_retriever = Dog()
```

の一行だけで、「私は犬です」「４本足です」「ワンワン！」の3つのデータ・処理を行うゴールデン・レトリーバが作れます。シェトランド・シープドッグがほしければ

```python
shetland_sheepdog = Dog()
```

とするだけで、同様のものを得ることができます。

# 実はオブジェクト指向害悪説も...

ここまでで、オブジェクト指向の良さやその例を掲載してきましたが、デメリットも当然あるようです。

[オブジェクト指向の問題点](https://blog.goo.ne.jp/viscuit/e/8ea0ce6d1d3aab0f95d92fd42c473558)
[オブジェクト指向の現実](http://www.aerith.net/design/demerit-merit-j.html)

私自身、完全理解にはほど遠い身。ですが、なんとなくの概念を整理したくて、この記事を書きました。
Google スプレッドシートを python3 で読む

こちらで行ったのと同様のことを python3 で行います。
[Google スプレッドシートを curl で読む](https://qiita.com/ekzemplaro/items/83f225b08bc4ee9739aa)

```py:sheet_read.py
#! /usr/bin/python
#
#	sheet_read.py
#
#				   Mar/05/2019
#
# ------------------------------------------------------------------
import  sys
import  json
import  requests
# ------------------------------------------------------------------
sys.stderr.write("*** 開始 ***\n")
#
access_token="******"
spreadsheet_id="******"
#
url_sheets="https://sheets.googleapis.com/v4/spreadsheets/"
range="Sheet1!A1:E3"
url = url_sheets + spreadsheet_id + '/values/' + range
#
headers = {'Authorization': 'OAuth ' + access_token}
rr=requests.get(url,headers=headers)
dict_data = json.loads(rr.text)
#
print(dict_data)
print()
print(dict_data['values'])
#
sys.stderr.write("*** 終了 ***\n")
# ------------------------------------------------------------------
```

実行結果

```text
$ ./sheet_read.py 
*** 開始 ***
{'range': 'Sheet1!A1:E3', 'majorDimension': 'ROWS', 'values': [['t2001', '小山', '91345', 'FALSE', '2017-3-19'], ['t2002', '下野', '31845', 'FALSE', '2018-9-19'], ['t2003', '栃木', '93726', 'FALSE', '2014-3-22']]}

[['t2001', '小山', '91345', 'FALSE', '2017-3-19'], ['t2002', '下野', '31845', 'FALSE', '2018-9-19'], ['t2003', '栃木', '93726', 'FALSE', '2014-3-22']]
*** 終了 ***
```

requests の使い方
[Quickstart - Rquests](http://docs.python-requests.org/en/master/user/quickstart/)

次のバージョンで確認しました。

```text
$ python --version
Python 3.12.7
```
Azure for Mariadbで、複数にシャーディングされたDBを１台にまとめてみた

#まず、注意事項から

- ~~2019/03/05時点では、Azure Database for MariaDB はpreviewです。~~
   - １２月にはGAされているみたいです。@cherubim1111 さんありがとうございます！
       - https://blogs.technet.microsoft.com/mssvrpmj/2018/12/21/announcing-the-general-availability-of-azure-database-for-mariadb/
   - ただ、サポートリクエストを作る画面から見るとpreviewと表記されています...
- ドキュメントには記載がないので出来なくなるかもしれません...orz
   - 正式にサポートされると正直嬉しい。

## "multi source replication" について

通常レプリケーションと聞くと、master１台/slaveN台といった構成を思い浮かべると思いますが
"multi source replication" はmasterN台/slave１台といった、逆の構成を取ることが可能になります。
**※ざっくり説明ですみません**

![スクリーンショット 2019-03-05 15.29.14.png](https://qiita-image-store.s3.amazonaws.com/0/52922/35c309d6-86c0-ec98-819a-73c111909d2e.png)

スキーマやデータによりますが、idをhash振り分けしていればシャーディングされたDBでもデータをマージすることが可能です。

## 設定方法
- **!!MariaDBとMySQLでは設定方法が違うので注意してください!!**
- 設定的にAuzre Database for MySQLではマルチソースは動かないと思います。

### 通常の方法

```
MySQL [(none)]> SET @@default_master_connection='SERVER_NAME';
MySQL [(none)]> CHANGE MASTER TO 
  MASTER_HOST='xxx.xxx.xxx.xxx', 
  MASTER_PORT=3306, 
  MASTER_USER='repl', 
  MASTER_PASSWORD='password', 
  MASTER_LOG_FILE='mysql-bin.000001', 
  MASTER_LOG_POS=xxxxxx;
```

MariaDBでは
　`SET @@default_master_connection='SERVER_NAME';`
この設定が大事です。
これが無いと普通のレプリケーションになってしまいます。

### Azure上での方法

```
MySQL [(none)]> SET @@default_master_connection='SERVER_NAME';
MySQL [(none)]> CALL mysql.az_replication_change_master('xxx.xxx.xxx.xxx', 'repl', 'password', 3306, 'mysql-bin.000001', xxxxxx, '');
MySQL [(none)]> CALL mysql.az_replication_start;
```

Azure上では、通常の方法ではレプリケーションが出来ないのでAzure側が用意しているプロシージャを呼び出します。

- Azure上でのレプリケーション設定方法については以下から
    - https://docs.microsoft.com/ja-jp/azure/mariadb/howto-data-in-replication

#### !!!注意!!!
- インスタンスの再起動を実行するとレプリケーションが止まってしまいます。
    - 正確には、複数動いているレプリケーションスレッドのうち１本だけは動きます。
    - stopしてstartしてもレプリケーションは再開されません。removeして再度登録して直してください。
- レプリケーションが止まった時点のポジションを控えて再度レプリケーションを組むと再開できます。


## 所感
~~まだpreviewですが~~マルチソースが利用できるだけでもAzure Database for MariaDBを選択する余地はある気がします。また、他のクラウド上ではMariaDBをPaaSとして提供できていなくて今はAzure一択なので、OSSライクな人々のために使える機能はそのまま残してほしいなぁ...っと、祈っております( ˘ω˘)
`jq` コマンドで、JSONの配列内のオブジェクトから必要なキーのみを指定してJSONを出力する

`jq` コマンドを久々に使ったら、下記の入力 JSON を出力 JSON のように出力したい時に、ちょっと迷ったので、メモ。結局、公式？の[チュートリアル](https://stedolan.github.io/jq/tutorial/)に普通にあったんだけど。


入力 JSON

```
[
  {
    "id": "xx1",
    "name": "hoge",
    "age": 20
  },
  {
    "id": "xx2",
    "name": "fuga",
    "age": 30
  },
  {
    "id": "xx3",
    "name": "piyo",
    "age": 40
  }
]
```

出力 JSON

```
[
  {
    "id": "xx1",
    "name": "hoge"
  },
  {
    "id": "xx2",
    "name": "fuga"
  },
  {
    "id": "xx3",
    "name": "piyo"
  }
]
```

コマンド

```
echo '[{"id":"xx1","name":"hoge","age":20},{"id":"xx2","name":"fuga","age":30},{"id":"xx3","name":"piyo","age":40}]' | jq '[.[] | {id: .id, name: .name}]'
```

`jq '.[] | {id: .id, name: .name}'` の jq のパラメータを `[]` で囲んだだけ。
Jupyter notebookで遊んでいたら「Connecting kernel」のままkernelが起動しなかったので解決方法をメモ

※2019/09/28現在、pipenv環境内の下記バージョンで発生せず。たぶんjupyterを最新版にすればOK。

```shell_session
$ python -V
Python 3.7.4
$ jupyter --version
jupyter core     : 4.5.0
jupyter-notebook : 6.0.1
qtconsole        : 4.5.5
ipython          : 7.8.0
ipykernel        : 5.1.2
jupyter client   : 5.3.3
jupyter lab      : not installed
nbconvert        : 5.6.0
ipywidgets       : 7.5.1
nbformat         : 4.4.0
traitlets        : 4.3.2
```

参考にしたGitHubのissueもclose済のようですが、一応解決法は残しておきます。


# 症状

```sh
pipenv install jupyter
pipenv run jupyter notebook
```

とやると、Jupyter Notebookは起動するが、
Notebookを作成してみると、左上に"Connecting kernel"と出たまま実行できない。

（pipでjupyterを最新版にupdateした場合もおそらく同様）

# 解決方法
ググっていたら下記にぶち当たったのでこれで解決した。
[juipiter notebook server "connecting to kernel" problem #2664](https://github.com/jupyter/notebook/issues/2664)

tornado をダウングレードすれば解決。

```sh
pipenv uninstall tornado
pipenv install tornado==5.1.1
```

pipenvじゃなくてpipを使っている場合は

```sh
pip uninstall tornado
pip install tornado==5.1.1
```

# 原因
4日前くらいにjupyterの依存ライブラリのtornadoにアップデートがあった模様。
[What’s new in Tornado 6.0](https://www.tornadoweb.org/en/stable/releases/v6.0.0.html)
おそらくこれが原因？
[Tips] UITextViewの行数などを取得する

<img width="822" alt="スクリーンショット 2019-03-05 16.34.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/69002/96899f9a-bbb1-55bf-6a89-8bbe1d53d08e.png">

# 概要
UITextviewの表示状況取得のためのTips。ちなみに設定系は、[[Tips] UITextviewをUILabelっぽく使う](https://qiita.com/ShoichiKuraoka/items/5b4c40936e1467406878)で。

# ０，取得タイミングについて
同じtextでも表示領域がちがえば行数も変わってくるわけで、例えば表示前に情報を取得しようと思ってもうまくいかないことが多い。AutoLayoutがベースになっているなら、UIViewControllerライフサイクルの`viewWillLayoutSubViews`タイミングで取得するのをオススメ。

# １，行数を取得する
```swift:UITextViewの行数を取得する
extension UITextView {
    var numberOfLines: Int {
        // prepare
        var computingLineIndex = 0
        var computingGlyphIndex = 0
        // compute
        while computingGlyphIndex < layoutManager.numberOfGlyphs {
            var lineRange = NSRange()
            layoutManager.lineFragmentRect(forGlyphAt: computingGlyphIndex, effectiveRange: &lineRange)
            computingGlyphIndex = NSMaxRange(lineRange)
            computingLineIndex += 1
        }
        // return
        if textContainer.maximumNumberOfLines > 0 {
            return min(textContainer.maximumNumberOfLines, computingLineIndex)
        } else {
            return computingLineIndex
        }
    }
}
```

Apple公式ドキュメントに方法(Objective-C!!!)がでていたのでこれを参考に実装。ただし、素直に実装してみると、「最大行数設定しているのに改行の入り方によってはそれよりも大きい数が返ってきてしまう」という不具合があったため、上記のように返り値に少し工夫をした。

参考：[Apple: Text Layout Programming Guide: Counting Lines of Text](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextLayout/Tasks/CountLines.html)

# ２，表示省略されているかを取得する
```swift:UITextViewの表示省略されているか
extension UITextView {
    var isTruncated: Bool {
        // prepare
        let lineMax = textContainer.maximumNumberOfLines > 0 ? textContainer.maximumNumberOfLines : Int.max
        var computingLineIndex = 0
        var computingGlyphIndex = 0
        // compute & return
        while computingGlyphIndex < layoutManager.numberOfGlyphs {
            // analyze line
            let overLineMax = computingLineIndex > lineMax
            let existsTruncatedGlyph: Bool = {
                let truncatedGlyphRange = layoutManager.truncatedGlyphRange(inLineFragmentForGlyphAt: computingGlyphIndex)
                return truncatedGlyphRange.location != NSNotFound
            }()
            // guard
            guard !overLineMax, !existsTruncatedGlyph else {
                return true
            }
            // prepare for next
            var lineRange = NSRange()
            self.layoutManager.lineFragmentRect(forGlyphAt: computingGlyphIndex, effectiveRange: &lineRange)
            computingGlyphIndex = NSMaxRange(lineRange)
            computingLineIndex += 1
        }
        return false
    }
}
```

１の応用。指定行の省略文字位置を取得するファンクション`truncatedGlyphRange(inLineFragmentForGlyphAt:)`がlayoutManagerにあるためこれを用いる。

ちなみに、設定系の話だが、`.textContainer.lineBreakMode = .byTruncatingTail`とかの設定をしないと3点リーダー等の省略文字は出ない。

# 備考
（特になし）
Googleドライブ上のファイル名をPython経由で変更する

Googleドライブ上のファイルを自動で一括変更したかったので少し調べてやってみました。

## 実行環境
* macOS Mojave
* Python 3.7.2

まず，Googleドライブのファイルを操作するためのAPIですが，Googleの公式のAPI「Google Drive API」を使います。
[QuickStart](https://developers.google.com/drive/api/v3/quickstart/python)を参考にインストールします。（執筆時点でのAPIのバージョンは3です。） 
QuickStartでは`credentials.json`がワークディレクトリにある想定になっています。ダウンロードして配置します。

## スコープについて
Googleドライブのファイル名を変更するには，デフォルトの「`https://www.googleapis.com/auth/drive.metadata.readonly`」
では権限が足りないので[ここ](https://developers.google.com/identity/protocols/googlescopes)を参考にして「`https://www.googleapis.com/auth/drive`」に変更します。

## ファイル名の変更
QuickStartにはファイル名の変更に関する情報がなかったので，Drive API v2を使ってやっている[サイト](https://bits.mdminhazulhaque.io/python/rename-list-of-files-in-google-drive-using-python.html)とDrive APIの[ページ](https://developers.google.com/resources/api-libraries/documentation/drive/v3/python/latest/index.html)を参考にしました。
以下，QuickStartの一部を改変したコードを示します。

```python
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/drive']

def main():
    """Shows basic usage of the Drive v3 API.
    Prints the names and ids of the first 10 files the user has access to.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server()
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('drive', 'v3', credentials=creds)
    # Call the Drive v3 API
    results = service.files().list(
        pageSize=10, fields="nextPageToken, files(id, name)", q="name contains 'ファイル名'").execute()
    #q=で指定したファイル名のファイルを検索できます。
    items = results.get('files', [])
    if not items:
        print('No files found.')
    else:
        print('Files:')
        for item in items:
            #このまま実行するとitems内のファイルが全て変更されるので注意
            new_name = '変更後の名前'
            file = {'name': new_name}
            service.files().update(
                fileId=item['id'],
                body=file).execute()
if __name__ == '__main__':
    main()
    
```
ファイル名を変更しているのは` service.files().update()`の部分です。
`fileId`にはもともとのファイルの`fileId`を`body`には変更後のファイル名を入れた辞書型のオブジェクトを渡します。
とりあえずこれで動きましたがやり方があってるかは不明です。
Nuxt.jsでグローバルSass変数を使いたい

# 概要

Nuxt.jsでUIフレームワークを使ってるときにフレームワークの標準のカラーテーマを上書きして、上書きした値をSass変数にしてコンポーネント内で使いたい、なんてことありませんか？

今回はbootstrap-vueとbuefyを例にその方法を紹介したいと思います。

# bootstrap-vue

bootstrap-vueが既にインストールされている前提で話します。
まだインストールしていない人はcreate-nuxt-appでbootstrap-vueを選ぶか、公式ドキュメントでインストール方法を調べましょう。

まずSassが使えるようにします。

```shell
npm i node-sass sass-loader
```

次にassets内にbootstrap-vue内の変数上書き用のSassファイルを作ります。上書きするためにここでbootstrapとbootstrap-vueのscssファイルをインポートします。

```sass:assets/style/_override.scss
$primary: red;

@import 'bootstrap/scss/bootstrap.scss';
@import 'bootstrap-vue/src/index.scss';
```

次にNuxt.jsを以下のように

```js:nuxt.config.js

export default {
  css: ['@/assets/style/_override.scss'],

  modules: [
    'bootstrap-vue/nuxt',
  ],

  // _override.scssで既に読み込んでいるのでここはfalseにする
  bootstrapVue: {
    bootstrapCSS: false, // or `css`
    bootstrapVueCSS: false // or `bvCSS`
  },
}
```

これでbootstrap-vue内の$primaryがredになります。
variantプロップスでprimaryを選んだ場合も赤になります。

しかしこれではコンポーネント内のstyleブロックで$primaryを呼んだらエラーになります。

$primaryをグローバルにするためにもうひと工夫します。
先日書いた[Nuxt.jsでグローバルSass変数を使いたいんじゃ](https://qiita.com/yusuke_ten/items/1d4f26f2abc44271219a)を使うとうまくいきます。

とりあえず@nuxtjs/style-resourcesをインストールします。

```shell
npm
npm i @nuxtjs/style-resources
```
次にグローバルにしたいSass変数を記入します


```sass:assets/style/_variables.scss
$primary: red;
```

最終的にNuxt.config.jsが以下のようになります。

```js:nuxt.config.js

export default {
  css: ['@/assets/style/_override.scss'],

  modules: [
    'bootstrap-vue/nuxt',
    '@nuxtjs/style-resources'
  ],

  // _override.scssで既に読み込んでいるのでここはfalseにする
  bootstrapVue: {
    bootstrapCSS: false, // or `css`
    bootstrapVueCSS: false // or `bvCSS`
  },

  styleResources: {
    scss: ['@/assets/style/_variables.scss']
  },
}
```
量子ゲート回路っぽいタイトル描きたくない？

![image(1).png](https://qiita-image-store.s3.amazonaws.com/0/252893/e1b8e6c9-72a4-225e-b8cf-156d6abfbfa3.png)

## [●ここでつくれます](https://qease.herokuapp.com/bloch/draw/)
昨日の帰りの電車で思いついたものをつくってみました．量子ゲート回路っぽいタイトルのpng画像が作成できます．
思ったより量子ゲートっぽくないとかそんなこと言わないでください．

## 遊び方
[こちらの動画](https://drive.google.com/file/d/1K40u6dlr8-I1TAU0HvTQaanfYlh-Ohv7/view?usp=sharing)を見ていただけると一発でわかると思います．

#### こんなかんじです
<img width="1437" alt="スクリーンショット 2019-03-05 15.30.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/252893/3b64f3b8-d62b-b631-5718-3e5a6141f1ea.png">

- **ソースコードは[こちら](https://github.com/nisuikiba/Q-ease)**
- PC,フルスクリーン表示推奨です
- Internet Explorerはdownload属性に対応していないため，画像の保存ができません(詳しくは[こちら](https://developer.mozilla.org/ja/docs/Web/HTML/Element/a#Browser_compatibility))

## 作品集
つくってみたものをいくつか載せます．
チュートリアルビデオで作成したもの((スペルミスには目をつぶってください))↓
![image (2).png](https://qiita-image-store.s3.amazonaws.com/0/252893/7a769b30-392a-2fd2-cc75-542b73df9db4.png)
真面目に量子ゲート描くとこんなかんじです↓
![image.png](https://qiita-image-store.s3.amazonaws.com/0/252893/fe4353de-d88c-fe3e-a319-2c55e56e8ed7.png)
これかわいくて好きです↓
![image (1).png](https://qiita-image-store.s3.amazonaws.com/0/252893/ccec2870-69c8-3604-c8ed-93c176fa52dd.png)
難しい漢字もこんなにポップに↓
![image (3).png](https://qiita-image-store.s3.amazonaws.com/0/252893/0801132a-f35e-ea6c-e629-cbeff53f0470.png)
一色縛りもなかなかかわいい↓
![image (5).png](https://qiita-image-store.s3.amazonaws.com/0/252893/2828fd8d-81b8-b1b3-3c51-fa51e2b3bcc4.png)

なかなか楽しいです．いろんな使い方ができそう．
SSH じゃないポートフォワーディング

localhost のあるポートを別のホストのポートにリダイレクトしたい場合、よくやるのは以下のように SSH ポートフォワーディングする方法。

``` console
$ ssh example.com -N -L 8080:localhost:80
```

この例だと、localhost のポート 8080 にアクセスすると example.com のポート 80 に繋がる。

しかしこの方法では、ホスト (この例でいうと `example.com`) に SSH 接続できないとポートフォワーディングできない。
もし対象ホストの対象ポートが外向けに公開されているのであれば、 `socat` を使って以下のようにしても同じことができる。

``` console
$ socat TCP4-LISTEN:8080,fork TCP4:example.com:80
```

ポートフォワーディングと言うより、TCP リレーとか TCP リダイレクトと言う方が正確かもしれない。
pyenv環境でpip install --upgrade pipがSSLエラーしたときの簡潔な対処法

# THE結論

```
$ curl https://bootstrap.pypa.io/get-pip.py | python
```
を実行で解決

# 以下顛末
pyenvとvirtualenvで新しく環境を作り、必要なパッケージをインストールしようとしたら`Could not find a version that satisfies the requirement`。
pipバージョンの問題だとおもうのでいつもの`pip install --upgrade pip`すると

```
$ pip install --upgrade pip
Could not fetch URL https://pypi.python.org/simple/pip/: There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590) - skipping
Requirement already up-to-date: pip in ./lib/python2.7/site-packages
```

となりSSLエラー発生。
OpenSSLの再設定、trusted-hostをホワイトリスト形式で設定、などの手があるようだけど未検証。
拡張子を偽るPNGファイルを見破るfileコマンド

世の中には拡張子を変更すれば中身も変わると思っている人がいるらしく、
.pngなのに中身はjpegファイルだったり、.jpgなのに中身はpngファイルだったりってファイルによく遭遇する。
画像まわりで処理が何故かエラーになったり、挙動がおかしくなったりするのは６割方これのせい。


# 偽の `image.png` ファイルを調べる
`image.jpg` というjpegファイルから、ファイル名変更で拡張子だけを変更した `image.png` を `file` コマンドで実行するだけ

```
$ file /tmp/image.png
/tmp/image.png: JPEG image data, JFIF standard 1.02, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 500x500, frames 3
```

`JPEG image data` と表示される



## 本物のPNGファイルだとこんな表示

```
$ file /tmp/image.png
/tmp/image.png: PNG image data, 500 x 500, 8-bit/color RGBA, non-interlaced
```

ピクセル数、何bitなど他の情報も取得できる


## fileコマンドは画像ファイル以外にも使える

```
$ file /tmp/image.psd
/tmp/image.psd: Adobe Photoshop Image, 500 x 500, RGB, 3x 8-bit channels
```

```
$ file /tmp/image.zip
image.zip: Zip archive data, at least v2.0 to extract
```

軽い情報はここから読み取れるので、CUIで操作してるとき多少便利かも
フォント関係のCORS

#備忘録
まだちゃんと設定していないのでおそらくこんな感じだろう。
##はじめに
バケットのダッシュボード、概要から*クロスソースリソース共有 (CORS)*の「設定」を選択。
おそらく設定はデフォで「無効」になっている。

##ルールの作成
「ルールの作成」からアクセスを許可するドメイン、とGETにチェック。他はオプションだから一旦無視。

##完成
これでOKな気がする。実際にやったら詳しく書きます。
今まで勘違いしていたPythonのrange()

# range()
恥ずかしながら、今までrange()はリストを返すものだと勘違いしていました。

## Python 2系
私が開発環境として準備したPython 2.7でrange()を試してみました。以下にそれを示します。

```python
>>> a = range(0, 10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> type(a)
<type 'list'>
```

このようにPython 2系では、range()はlist型を返してきます。これがPython 3系でも同様に成り立っていると勘違いしていました。

## Python 3系

では私がメインの開発環境として使用しているPython 3.7で同様のことを実行してみましょう。

```python
>>> a = range(0, 10)
>>> a
range(0, 10)
>>> type(a)
<class 'range'>
```

このように**Python 3系ではrange()はrange型という、イテラブルなオブジェクトを返します**。[0, 1, ..., 9]のような戻り値をどうしても取り出したい場合は、forループで取り出すか、リストなどのシーケンスに変換する必要があります。

```python
>>> list(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> tuple(a)
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
```

## 勘違いの原因: len()

len()は引数にリスト型などのシーケンスをとると思っていたのです。ところが

```python
>>> a = range(0, 10)
>>> len(a)
10
```

のようにrangeオブジェクトの長さも平気で計算して返してきます。しかし、よくよく調べてみれば(というよりもすでに私自身、意識せずとも使っていたのですが)、**len()は様々なオブジェクトのサイズを返すことができる万能な関数**だったのです。

当たり前のようにforループで使っていましたが、まさかこんな落とし穴があったとは...まだまだPythonの奥深さを勉強していく必要がありそうです。

# 追記: rangeオブジェクトの要素へのアクセス

なんとこのrangeオブジェクトは要素へのアクセスも可能でした。これも私の勘違いに拍車をかけた要因でした。

```python
>>> a = range(0, 5)
>>> a[0]
0
```

ただし、スライスを行うと以下のようにrangeオブジェクトのまま返ってきます。

```python
>>> a[1:3]
range(1, 3)
```
電子証明書ファイル(p12)の内容確認

##やりたかったこと
会社でリリースしているアプリに組み込んだ電子証明書の有効期限が確認したい
（windows7)

##やったこと
###1.openSSL for windowsの入手
下記リンクより、openSSL for windowsを入手
https://slproweb.com/products/Win32OpenSSL.html

![image.png](https://qiita-image-store.s3.amazonaws.com/0/126315/ade74e16-5c48-eecf-ce8e-91f629619a7f.png)
(デフォルトでセットされる内容のまま次へ次へ進む)


###2.openssl.exeにパスを設定
「システムのプロパティ」-「環境変数」の[path]にopensslの格納場所を設定。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/126315/dddf3e8e-311c-2238-2cdc-be760c94043b.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/126315/19870e5d-7e7f-08e1-e527-bf5939e9800b.png)


###3.openssl.exeの動作確認 on コマンドプロンプト
コマンドプロンプトで「openssl version」と入力

![image.png](https://qiita-image-store.s3.amazonaws.com/0/126315/5289f3fb-0c8c-165b-c5f5-c63b91dc83fe.png)

バージョン情報が確認できたため、無事opensslの導入は完了。

※何度か「序数●●●がダイナミックライブラリ●●●.dllから見つからなかったため～」というポップアップが表示されてコマンドが受け付けられないことがありましたが、都度そのdllファイルをwebから取得してやれば解決しました。

###4.証明書ファイルの内容を確認(x509コマンド)
下記コマンドを入力して、証明書ファイルの有効期限を確認

```
openssl x509 -in output.pem -startdate -enddate -noout
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/126315/d18d0f32-339e-b3c2-6d57-f78924d29ca2.png)


※もともと持っていたのが#pkcs12形式だったので、事前にp12→pemに変換しています。

```
openssl pkcs12 -in input.p12 -out output.pem
```
Eclipse/Che 6 の IDE を初めて触るときの tips いくつか

# はじめに

Eclipse/Che を初めて触ったときに tips を、いくつか書き記します。

Eclipse/Che は、エディタを差し替えることができ、Version 7 (Che 7)からは、[Eclipse/Theia](https://www.theia-ide.org/) ベースのものに変更になります。
本稿で取り上げるのは Version 6.x (Che 6) のものです。Che 7 以降も、GWT-IDE という名前でエディタ自身は残るようなので、何らか役には立つと思います。

# ワークスペースを広く使いたい

モバイル環境では、画面が狭いので、少しでも邪魔なものは隠したいものです。
ワークスペース一覧を表示している左サイドバーは、編集中は使わないので邪魔です。

サイドバー上部右側にあるオレンジ色の部分をクリックすることで、サイドバーは隠せます。

![ink (3).png](https://qiita-image-store.s3.amazonaws.com/0/5414/affc39af-49f5-01eb-1b29-016e54976474.png)

# 明るいカラーのテーマを使いたい

ダークテーマが最近の流行りのようですが、伝統的な Eclipse IDE の明るい画面を好む方もいらっしゃると思います。

メニューバーから `Profile` - `Preferences` でダイアログを表示し、`IDE` - `General` をクリックすると、テーマを変更するドロップダウンリストが見つかります。

![Screenshot 2019-03-05 at 14.07.15 - Display 1.png](https://qiita-image-store.s3.amazonaws.com/0/5414/fbe62326-7c2d-56ff-ef1c-201722a4018f.png)

反映するには、変更後、ダイアログを閉じ、ブラウザ画面をリロードする必要があります。

# コマンドラインが恋しい

ウインドウ下部のペインに、Teminal というタブがあるはずです。選ぶとコマンドプロンプトが表示されます。

![Screenshot 2019-03-05 at 14.06.26 - Display 1.png](https://qiita-image-store.s3.amazonaws.com/0/5414/cce1f036-c387-588b-4a70-d8176e21bca0.png)

Docker コンテナで仮想化された Linux で、たいてい sudo も使えます。(使えるかどうかは、使っている docker コンテナの作られ方次第)
C#のNullable型で三項演算子を使うときの注意

# はじめに
C#のNullable型で三項演算子を使おうと思ったらコンパイルエラーになったので、備忘録としてメモを残しておく。
ちなみに三項演算子を使いたかった理由は、三項演算子の方が可読性が高まるケースがあっためです。
（本記事は三項演算子の良し悪しについて議論したいわけではありません）

# エラー内容
以下のコードはコンパイルエラーになります。

```csharp
int? num = true ? 1 : null;
```

`error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'int' and '<null>'`

エラーメッセージを意訳すると、

**三項演算子の第二オペランドの型と第三オペランドの型が異なるうえに、nullはintに暗黙的な型変換ができないよ**

とのこと。

そもそも三項演算子は第二オペランドと第三オペランドを同じ型にする必要があります。
そのうえで、さらにnullはintに暗黙的な型変換ができないので、上記のように怒られているようですね。

# 解決策１
nullからNullable\<int\>へ明示的に型変換すれば、Nullable\<int\>からintへは暗黙的に型変換してくれるので実行可能になります。

```csharp
int? num = true ? 1 : (int?)null;
```

# 解決策２
そもそも三項演算子にこだわらずifで書けば、もちろん問題ないですね。

```csharp
int? num = null;
if (true) {
    num = 1;
}
```

# 参考リンク
https://blog.xin9le.net/entry/2013/02/11/035809
WSL+Dockerで便利に使えそうなwsl-terminalを使ってみた

[WSL+Dockerで便利に使えそうなwsl-terminalを使ってみた](https://xn--v6q832hwdkvom.com/post/wsl+docker%E3%81%A7%E4%BE%BF%E5%88%A9%E3%81%AB%E4%BD%BF%E3%81%88%E3%81%9D%E3%81%86%E3%81%AAwsl-terminal%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F/)の抜粋版です

## WSL+Dockerで困っていること

* WSL環境を毎回「管理者として実行」で起動しなければならない
* マウスで選択してコピー、右クリックでペーストをしたい

なければなくても構わないけれど、地味に面倒なことばかり

## 設定メモ

### wsl-terminalのreleasesページからダウンロード

[wsl-terminal：releases](https://github.com/goreliu/wsl-terminal/releases)

今回は`v0.8.12`をダウンロードした

[wsl-terminal-0.8.12.zip](https://github.com/goreliu/wsl-terminal/releases/download/v0.8.12/wsl-terminal-0.8.12.zip)


### ダウンロードしたzipファイルを解凍してフォルダに移動させた

今回は`C:\Application\wsl-terminal`に置くことにした  
`open-wsl.exe`をダブルクリックすると`wsl-terminal`が起動する

### お困りごと1：WSL環境を毎回「管理者として実行」で起動しなければならない

* デスクトップに`open-wsl.exe`のショートカットを作成する
* ショートカットのプロパティの「互換性」タブの「設定」の「管理者としてこのプログラムを実行する」にチェックを入れる

![02.png](https://qiita-image-store.s3.amazonaws.com/0/89027/d377d5d3-ef8e-28fa-b9b8-b42009d532b2.png)

### お困りごと2：マウスで選択してコピー、右クリックでペーストをしたい

* `wsl-terminal`ウィンドウの左上のアイコンを右クリックして「オプション」を選択する
* 「マウス」の「選択時にコピー」にチェックを入れ、「クリック動作」の「右マウスボタン」の「ペースト」を選択する

![03.png](https://qiita-image-store.s3.amazonaws.com/0/89027/135204af-b656-3c87-746f-dd5525cc5247.png)

### 起動時のカレントディレクトリを変更したい

`open-wsl.exe`を起動すると`open-wsl.exe`の場所がカレントカレントディレクトリとして起動する  
任意のディレクトリをカレントディレクトリとするには`-C`オプションでカレントディレクトリのパスを渡してあげればよさそうだ

* 作成したショートカットを右クリックして「プロパティ」を選択する
* 「ショートカット」の「リンク先」に`-C`オプションをつけてカレントディレクトリを設定する  
`C:\Application\wsl-terminal\open-wsl.exe -C /home/wsluser`

![04.png](https://qiita-image-store.s3.amazonaws.com/0/89027/ddad957a-9c6c-a592-e61e-28413e82fdd0.png)
最近シンボルについて結構わかってきたのでまとめてみる

Rubyにはシンボルがありますが、ほぼ文字列ど同じだし、なんのためにあるの？？？ってずっと思ってました。

そこで色々と勉強していくうちにシンボルの存在理由がわかったので、ここにまとめてみようと思います。

## シンボルは文字列より処理が早く、数字よりも読みやすい

結論から言ってしまうと、
**ハッシュのキーとしてシンボルを使う理由は、
文字列より処理が早く、数字よりも読みやすいから**です。

## ハッシュのキーは、文字列でもいいしハッシュでもいい。なんなら数字でもいい

そもそもですが、ハッシュのキーはシンボル以外でも全く問題なく動きます。
文字列でもいいですし、数字でもいいです。もちろんシンボルでもいいです。

以下ではハッシュのキーとして、
文字列、数字、シンボルを比較して説明していきます。

## シンボルの方が文字列よりも処理が早い理由

簡単にいうと、
シンボルはメモリ番地が変わらないのに対し、
文字列はメモリ番地が毎回変わるからです。

文字列はメモリ番地が変わるので、文字列を探すためのコストがかかります。
それに対しシンボルはメモリ番地は変わりません。

シンボルでは探すコストがかからないので、文字列よりも早く処理ができます。

"メモリ番地が変わらない"という点で言えば、数字とシンボルは似ています。

**シンボルは数字と文字列のいいとこ取りをしている**とも言えますね。

## シンボルの方が数字よりも読みやすい理由

流れ的に章を分けましたが、これは自明ですね。

キーに数字を使うなら配列でいいじゃんって話です。

## まとめ

**ハッシュのキーとしてシンボルを使う理由は、
文字列より処理が早く、数字よりも読みやすいから。**

**シンボルは数字のようにメモリ番地が変わらないので、文字列よりも処理が早い**

**シンボルは数字と文字列のいいとこ取り**

以上の3つを抑えてからはシンボルの存在意義を問うことはくなりました。

シンボルで悩める人の参考になれば幸いです。
Linuxファイルシステム基礎

おはようございます、こんちには、こんばんは！

ファイルシステムとはファイルとしてデータを扱う仕組みです。

#1、ext2　ext3

限界ファイルサイズ2TiB、最大容量(ボリュームサイズ)16TiB、ジャーナルには非対応となっているので、使うのは避けたほうがよいです。
ジャーナルに非対応なため、一度クラッシュすると復旧に時間がかかる、このファイルシステムは旧式なので「ext4」の使用をおすすめします。

#2、ext4

の拡張であり、現在のlinuxファイルシステムのデファクトスタンダードです。

最大ファイルサイズは16TiBと拡張され、最大ボリューム サイズも1EiBとなっています。
また日付範囲も1901年12月14日から2514年4月25日までと拡張されており、下位互換もたもたれています。
ext3としてマウントすることも可能です。

#3ＪＦＳ
2019年3月7日以降はGoogle+ APIが使えない / rails + omniauth-google-oauth2でgoogleログインができなくなったら

## Google+ API のサービス終了について

`2019 年 3 月 7 日をもって、すべての Google+ API はサービスが終了します。` とのことです。

参考URL) https://developers.google.com/+/api-shutdown

これにより、Googleアカウントでログインしているサービスにも影響が出るようです。

## 対応方法

利用するAPIをこちらに差し替えると良いという記述がありました。
`https://www.googleapis.com/oauth2/v2/userinfo`

参考URL) https://github.com/zquestz/omniauth-google-oauth2/issues/340

ruby gemの `omniauth-google-oauth2` のversion 0.6.0 では既に対応済みとのことです。

railsで既に導入している場合は、以下のようにgemをアップデートすると解消するかと思います。

```bash
bundle update 'omniauth-google-oauth2'
```

## 確認方法

Google APIsのダッシュボードから、Google+ APIを無効化した状態でもGoogleアカウントでログインできれば成功です。
`omniauth-google-oauth2` の旧バージョンでは、Google+ API用のendpointを参照しているようですので、これで確認OKだと思います。

Google APIs) https://console.developers.google.com/apis/dashboard

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106949/7fc47cd7-ef49-eb68-fab7-d6e02712136f.png)

## 参考URL

https://www.wazalab.com/2019/01/31/rails%E3%81%A7google%E3%82%B7%E3%83%A3%E3%83%83%E3%83%88%E3%83%80%E3%82%A6%E3%83%B3%E3%81%AB%E4%BC%B4%E3%81%86google-sign-in%E5%AF%BE%E5%BF%9C/
deviseでパスワードの最低文字数を変更する方法。

パスワードを変更するには2種類の方法があります。

###1 railsアプリのルートディレクトリ直下の~/configディレクトリにあるファイルを編集する方法です。

~/config/initializers/devise.rbにアクセスしてください。

```
config.password_length = 6..128
```
上記の部分がファイルの真ん中らへんにあるので、数値の部分を変更してください。

###2 deviseを使用するモデルに直接記述する方法です。

例えば、user.rbに

```
devise :validatable, password_length: 10..128
```
このようにpassword_length: で指定してあげましょう。

##最後に
自分でモデルにvalidates :password, length: { maximum: 8 }みたいに指定するとエラーの元になるのでやめましょう。僕はこれで１時間くらい溶かしました。



**参考文献**
https://github.com/plataformatec/devise/wiki/Customize-minimum-password-length
UICollectionViewFlowLayoutのestimatedItemSizeを指定するとiOS12で表示がおかしい

## 問題

UICollectionViewFlowLayoutのestimatedItemSizeに以下を設定する。

```swift
        if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.estimatedItemSize = CGSize(width: 1, height: 1)
        }
```

もしくは

```swift
        if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        }
```

本来有効になるUICollectionViewCellのSelf-Sizing CellsがiOS12未満だと問題ないが、iOS12ではうまく動かない。

## 対応

```swift
class CollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak internal var label: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        
        self.contentView.translatesAutoresizingMaskIntoConstraints = false

        let leftConstraint = self.contentView.leftAnchor.constraint(equalTo: self.leftAnchor)
        let rightConstraint = self.contentView.rightAnchor.constraint(equalTo: self.rightAnchor)
        let topConstraint = self.contentView.topAnchor.constraint(equalTo: self.topAnchor)
        let bottomConstraint = self.contentView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
        NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
    }

}
```

UICollectionViewCellのawakeFromNib()で上記の設定を行うことでうまく動作するようになる。

参考： [UICollectionViewFlowLayout estimatedItemSize does not work properly with iOS12 though it works fine with iOS 11.*](https://stackoverflow.com/questions/51718787/uicollectionviewflowlayout-estimateditemsize-does-not-work-properly-with-ios12-t)
データを理解する・分析する　（ビジネス理解）

データを理解する・分析するとはかなり広い概念になります。

私のデータに対する思いは、以下のような思考から来ています。
１．ビジネス
　なんの為にデータを理解し分析しているかというと、ビジネスを成長させるため。ここが原点です。

２．オペレーション（業務）
　ビジネスには何らかのオペレーションが発生しています。人がマニュアルで行っていたり、自動化されていたり様々な形があります。
　データの発生源と言える場所で、データのフィードバックをすべき場所。
　ここでどのようなデータを取得または作成するかが重要。そもそもないデータは分析できません。また、重要な要素を含むデータがしっかり取得できているかが重要です。
　取得したデータがどう重要かは分析の結果わかりますが、重要なデータを取得できているかはビジネスとオペレーションを理解していないとわからなかったりします。

３．データの理解
　ここでデータの理解をします。データの意味、取得方法、関係性などを理解しています。
　当初予定していた保存すべきデータが、現場では別な意味で利用されていたりすることもよくあること。
　また、取得方法もエンドユーザーが一度切りの入力で行ったものや、業務スタッフが毎日入力しているもの、自動で生成されるものなど、それぞれ信頼性が違います。

４．データの分析
　ここからは様々な分析手法が存在していて、必要に応じた情報は取得できると思うので省略。

５．分析結果に応じた対応
　分析しているだけではビジネスは成長しません。分析結果を用いて、ビジネスモデル、顧客のターゲット層、オペレーションなどに反映させる。特にオペレーションを管理していた事も多かったので、オペレーションの効率化、スタッフのモチベーション管理など様々なことに活用できます。
　分析結果を理解してもらう為にも、ビジネスやオペレーションを理解していないと対応できなかったりします。
　単に分析だけをして理解してくださいではなく、そこから何をすべきかが見えるものであるべきと思います。
　また、オペレーションの現場での改善だけでは対応できないことは、しっかりと経営側で対応しないといけません。

このような思考を持っていたのですが、しっかりと可視化、手法としていたのがあったのでご紹介をします。
恥ずかしながら今まで知りませんでした。

https://en.wikipedia.org/wiki/Cross-industry_standard_process_for_data_mining

CRISP-DM
Cross-industry standard process for data mining

これで私の頭もすっきりまとまりました。
【Maven】Eclipseから動かすビルドバッチ

# はじめに

eclipseでコーディングしていますが、
mvnコマンドがパパッと実行できるようにバッチを作りました。

右クリック～とか、
実行構成～とか、
ヒストリの～とかしなくてよくなります。


# 環境

windows
eclipse


# バッチファイルの内容

```bat
@echo off

cd %~d0%~p0
call mvn package -DskipTests=true

pause
```

これをプロジェクトフォルダ直下(pom.xml)があるフォルダに置いておけば、
ダブルクリックで maven し放題です。

mvnコマンドを call で呼び出さないと pause が効きません。

以上
Lambda×puppeteerでクロールしようとしたらゾンビプロセスの沼に浸かった記録（解決済）

headless chromeを使ってサーバーレスでいい感じにクローリングするプログラムを作ろうとしたら沼に浸かりました。
うまいこと動くテンプレートをgithubで公開しています。
https://github.com/inatomitk/lambda-puppeteer-template

# 環境
 - [puppeteer](https://github.com/GoogleChrome/puppeteer) ※headless chromeのNode.jsのAPI
 - AWS Lambda
 - Node.js

# 沼りポイント
## headless chromeのバイナリがLambdaにアップロードできない
Lambdaには一つのfunctionあたり50MBまでのファイルしかアップロードできないという制限があります。
普通の処理ならその制限を気にする必要もない（まず、そんな大きいファイルにならない）です。が、headless chromeはサイズが大きい（50MB弱くらい）なので、その他諸々のパッケージを含めるとアップロードできない可能性が高いです。

なので、Lambdaのlayerを使用しました。layerを使用することで関連するパッケージを関数とは別でアップロード・使用することが可能です。
[serverless](https://serverless.com/)というLambdaにアップロードするための便利なツールがlayerにも対応しています。

ちなみに、serverlessでアップロードする際に、素直に`serverless deploy`をすると毎回layerもアップロードされるのであまりよろしくないです。

```

$ serverless deploy function -f [関数名]
```
と実行すると、該当の関数だけアップロードされます。

## puppeteerが動かない
様々な記事を参考にさせていただいたのですが、バージョンの相性のせいなのか、うまくheadless chromeが起動せずうまく動きませんでした。


https://github.com/RafalWilinski/serverless-puppeteer-layers
試行錯誤を重ね、遂に、↑を参考に構築したところ、無事クローラーが動きました。

**だが、しかし、、、**

## ゾンビプロセスが溜まりクラッシュする
数回の実行ではまったく問題なかったのですが、短い時間に連続で何度も実行するとクラッシュしてしまう。。
メモリを観察すると、実行毎にメモリが圧迫されていたことがわかりました。そして限度を超えるとクラッシュする。

そこでプロセスを出力してみると、ゾンビプロセス（メモリ０のプロセス）が実行の度に溜まっていることがわかりました。

```
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
486 989 0.0 0.0 0 0 ? Z 07:56 0:00 [headless_shell] <defunct>
486 937 0.0 0.0 0 0 ? Z 07:50 0:00 [headless_shell] <defunct>
486 888 0.0 0.0 0 0 ? Z 07:50 0:00 [headless_shell] <defunct>
486 840 0.0 0.0 0 0 ? Z 07:50 0:00 [headless_shell] <defunct>
486 793 0.0 0.0 0 0 ? Z 07:50 0:00 [headless_shell] <defunct>
486 748 0.0 0.0 0 0 ? Z 07:49 0:00 [headless_shell] <defunct>
486 694 0.0 0.0 0 0 ? Z 07:49 0:00 [headless_shell] <defunct>
486 645 0.0 0.0 0 0 ? Z 07:49 0:00 [headless_shell] <defunct>
486 62 0.0 0.0 0 0 ? Z 07:45 0:00 [headless_shell] <defunct>
486 596 0.0 0.0 0 0 ? Z 07:49 0:00 [headless_shell] <defunct>
486 548 0.0 0.0 0 0 ? Z 07:49 0:00 [headless_shell] <defunct>
486 500 0.0 0.0 0 0 ? Z 07:48 0:00 [headless_shell] <defunct>
486 451 0.0 0.0 0 0 ? Z 07:48 0:00 [headless_shell] <defunct>
```

※「あれ？Lambdaってサーバレスだから毎回プロセスを破棄するんじゃないの？」と思ってましたが、そんなことはないようです。
https://qiita.com/koshigoe/items/afa3368352020660a220

ここからスーパー試行錯誤しました。
一定時間待ったり、クローラ実行用のchild processを作ってchild process毎killしたり、あらゆる手でプロセスの終了を試みました。

が、**解決しなかった**。

※該当のissueも存在します。執筆時点でまだopenになっている。
https://github.com/GoogleChrome/puppeteer/issues/1825

バージョンのせいなのか、人によってkillするだけで上手くいったと報告してる人もいるのが難しいところでした。
私の場合は、`puppeteer.launch`時点で孤立したゾンビプロセスが生成され、消せなかった。。
ライブラリ依存の問題であろうことはわかってたので、Lambdaを辞めるという選択肢も含めて諦めかけていました。
もういっそこの際レポジトリにコントリビュートしてやろうかなと思っていたところ、意外な形で解決しました。

**headless chromeの新バージョンが出た**

https://github.com/alixaxel/chrome-aws-lambda
最新のheadless chromeに追従してくれるこのライブラリをベースにlaunch部分を書き直したら動きました。

今回のトラブルを活かして↑のレポジトリをlayerにしてserverlessで使えるようにテンプレート化したレポジトリを公開しています。
https://github.com/inatomitk/lambda-puppeteer-template

# 結論
バージョンアップは偉大