OmniAICreator/Qiita-1.07M huggingface dataset:
EBSのI/O クレジットバランスにも注意しよう

## 障害
稼働しているサービスのEC2インスタンスがまれに503エラーを発生させることがあることがわかっていました。障害といっても複数インスタンスで稼働しているため、一時的に繋がらなくなる程度でした。すぐにユーザーは問題なくサービスにアクセスできるようにはなっていたため、対応の優先度はさほど高くはなかったです。

## 調査
サービスのログ、EC２インスタンスのCloudWatchメトリクスをいくら確認しても問題が特定できず、AWSサポートに調査の依頼。

## I/O クレジットバランスが空になっていた
AWSからの回答としては
>事象発生当時、gp2 ボリュームはクレジット枯渇によりベースラインパフォーマンスの 120 IOPS 程度で稼働しておりました。
>当方の見解としましては、ターゲットインスタンスのボリュームタイプが性能不足と見られますので gp2 ボリュームのベースラインパフォーマンスが上がるよう今よりもボリュームサイズを増加して頂くとよろしいものと思われました。

といったものでEBSのクレジットが枯渇したため、リクエストを処理できず、503エラーが発生していました。
変更は[こちらの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/requesting-ebs-volume-modifications.html)のリンクを参考にしてもらえれば簡単に行えました。
AWSコンソールから簡単に変更できます。ダウンタイムも発生しなかったのでサービスにも影響は与えることはほとんどないと思います。
ただ一旦上げると下げられなくなるため、この点は注意が必要です。

EBSのボリュームの種類、性能については[こちらの公式ドキュメント](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ebs-volume-types.html)が参考になります。

EC2のtシリーズにあるクレジットは注意を払っていましたが、EBSに関しては全くわかっておらず、今回の事象が発生しました。
今後は監視対象に加えたいと思います。
質問です

ESP-WROOM-32からgoogle spread sheetに書き込みを試みています。

ESP332からGASへ値の受け渡しができているか確認のため
下記google apps script を実行すると

undefined からプロパティ「parameter」を読み取れません。と表示されます。

```コード.gs
function doGet(e) {
  Logger.log(e);
  var param = e.parameter.param;
  Logger.log(param);
  return ContentService.createTextOutput(param);
}
```


ideのスケッチは下記です。

```
#include <WiFiClientSecure.h> 
WiFiClientSecure client;
float sensor_data1;
//const char* ssid     = "使用しているwifi名";
const char* password = "使用しているwifiのパスワード";  
const char* server = "script.google.com"; 
const char* key = "goolge script IDを記入";
   
void setup() {
  Serial.begin(115200); 
}
void wifi_conect(){
  
WiFiServer server(80);
  Serial.print("Attempting to connect to SSID: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
    server.begin();
  }
  void g_acsess(){
  sensor_data1=100; //testのため値を固定
  String URL="https://script.google.com/macros/s/";
  URL += key;
  URL += "/exec?";
  URL += "1_cell=";

  Serial.println(URL);
  Serial.println("\nStarting connection to server...");
  if (!client.connect(server, 443))
    Serial.println("Connection failed!");
  else {
    Serial.println("Connected to server!\n");
    Serial.println("GET " + URL);//hioki test
    client.println("GET " + URL);
    client.stop();
    Serial.println("finish.");
  } 
}
void loop() {
  delay(10000); 
  wifi_conect();
  g_acsess();   
  WiFi.disconnect();   
}
```

ide arudinoのシリアルモニタに下記表示されています。

```
Attempting to connect to SSID:使用しているwifi名
..Connected to 使用しているwifi名
IP address: 
192.168.20.30
https://script.google.com/macros/s/ここにgoogle script IDを書いています/exec?1_cell=100.00
Starting connection to server...
Connected to server!
GET https://script.google.com/macros/s/**ここにgoogle script IDを書いています**/exec?1_cell=100.00
finish.
```
上記の　「ここにgoogle script IDを書いています」は
GASの　公開→webアプリケーションとして導入→
https://script.google.com/macros/s/この部分/exec　
の「この部分」と合致しています。

doGet(e)のeが空が原因なようですが、どうすればeに値が入るか教えていただけますでしょうか？
【サンプルロボ】ExcelファイルをPDFファイルへ変換する方法

【アルゴリズム】
<img width="556" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/d2b088fb-6e0c-3b0c-f503-cd824b2edba8.png">

【ポイント】
<img width="364" alt="2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/126915e9-f8e6-ac35-a953-83ff5c8ebb9d.png">
上記の感じで入力と出力のファイルを指定

<img width="400" alt="3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556084/ce667cc2-c6ea-5c80-d40f-54127207d3de.png">

このコードで返還するらしい。
パスだけ指定すれば勝手にPDFファイルを生成してくれる
ブラウザを使わずVimでサクッとMarkdownをプレビューする

こんにちわ。ゴリラです。

Vim上でMarkdownをいい感じにプレビューしてくれる[preview-markdown.vim](https://github.com/skanehira/preview-markdown.vim)を作ったので紹介します。
サクッとプレビューしたいときに便利です。

<a href="https://github.com/skanehira/preview-markdown.vim"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/skanehira/preview-markdown.vim.png" width="460px"></a>

# どんな感じ
こんな感じです。

![](https://camo.githubusercontent.com/f663e8497902939568ba34fd8ac432bca6eb5124/68747470733a2f2f692e696d6775722e636f6d2f4d4535484257502e706e67)

# 使い方
markdownを開いた状態で、`:PreviewMarkdown`を実行するだけです。
実行されるとターミナル上でmarkdownがいい感じに表示されます。

# オプション
デフォルトは水平に画面分割されますが、垂直に分割したい方は`let g:preview_markdown_vertical = 1`をvimrcに書いてください。
markdownパーサを変更したいときは`g:preview_markdown_parser = {command}`で変更できます。好きなパーサを使いたいときは設定してください。

# 仕組み
[MichaelMure/mdr](https://github.com/MichaelMure/mdr)というコマンドを使っています。
現在のバッファの中身をファイルに書き出した後に`mdr`でプレビューしています。とてもシンプルです。

```vim
function! preview_markdown#preview() abort
  let tmp = tempname()
  call writefile(getline(1, "$"), tmp)

  if !executable('mdr')
    call s:echo_err('not found mdr, please insatll from https://github.com/MichaelMure/mdr')
    return
  endif

  if !has('terminal')
    call s:echo_err('this version doesn''t support terminal')
    return
  endif

  let opt = {
        \ 'in_io': 'file',
        \ 'in_name': tmp,
        \ 'exit_cb': function('s:remove_tmp', [tmp]),
        \ 'vertical': get(g:, 'preview_markdown_vertical', 0),
        \ 'term_finish': 'close',
        \ }

  call term_start('mdr', opt)
endfunction
```

## 最後に
さくっとターミナルでmarkdownをプレビューしたいときに使えるのでぜひ試してみてください。
オススメAdBlockツールまとめ(Chrome, Android, iOS対応)


広告がうざいならAdBlockツールを入れましょう。
紹介するのは全て私が1年以上使用しているAdBlockツールです。

### Chrome

[uBlock Origin](https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm)

- GPLv3
- 無料で使えます。
- [参考記事](https://qiita.com/AKKYM/items/e09e80bc8c30e189524d)

### Android

[DNS66](https://f-droid.org/en/packages/org.jak_linux.dns66/)

- GPLv3
- 無料で使えます。
- アプリ内の広告を消すことができます。
- [参考記事](https://qiita.com/AKKYM/items/b27046395ef722cdb2d5)

### iPhone

[AdBlock](https://apps.apple.com/jp/app/adblock/id691121579)

- 有料
- アプリ内の広告を消すことができます。

[280Blocker](https://280blocker.net/)

- 有料
- Safariの広告を消すことが出来るし、何も表示されなくなったポップアップみたいなのも消すことができます。

#まとめ

広告をブロックして快適なインターネットライフを。
Oculus Questのハンドトラッキングを使って何かやる（１）

#概要

前回の記事では、Oculus Questの操作をコントローラーからハンドトラッキングへ切り替える方法と、Unityでハンドトラッキングのアプリ開発を行うための設定方法について記載しました。今回は、そのハンドトラッキングの技術を使ってUnityで簡単なアプリを作ったので簡単にご紹介します。
※細かい制作の部分は飛ばしています。

重要なのは何に使えるのかを考えること！！

それを考える上でこの技術でどんなことができるのかを知らなければ話にならないので、アプリを作って学んでいきます。


#開発環境
 + Windows10 HOME
 + Oculus Quest
 + Unity 2019.2.6

#ハンドトラッキングとキーボード
VRで何か文字を入力する場合、空間上に浮かぶキーボードの文字にコントローラーから出ているポインターを合わせてトリガーを引くことが一般的ですが、VR空間上でも物理的なキーボードと同じようにkey入力ができれば寝ながらでも仕事ができる、、、！！　寝ながらでもできる、、、

###シゴトノコウリツカノタメニツクリマス

まずはキーボードを用意。
著者はどうしても無課金でコンテンツの作成をしたかったため、Unityに標準で搭載されているProBuilderを使ってモデルの制作をしました。そして、キーボードの各キーを配置し、手との当たり判定をつけていきます。

###完成

![key.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/440432/6110c082-d9b2-2e9b-3802-cfd5e4905451.jpeg)


#所感
ハンドトラッキングの検出が常時成功していないので、キーボードをタップしたときに2、3回連続でキー入力される時があったり、隣のキーを誤って入力したりと課題が多く残った。
何人か体験もしてもらったが、感想の多くが使いにくいや入力したときに手に何の感触もないことに違和感を感じる人が多かった。一方で可能性は感じるという感想をくれる人もいた！（この感想だけでやっていける、、、）
現代人はキーボードに慣れているためその差異で使いにくいのではないかと感じた。そのため赤ちゃんの頃からVRのキーボードを使わせていたらそっちがスタンダードになって物理的なキーボードの方が使いにくいって言うのかなと考えつつ今回はここまで！！

次回二つ目のアプリに続く
怪奇！ECSのタスクをFargateで実行するとたまに起動失敗する！（ヒント：SubnetSelection）


# TL;DR
CloudFormationにおける `AWS::Events::Rule` - `AwsVpcConfiguration` - `Subnets ` は必須プロパティだが、CDKでは必須ではありません。
CDKで指定しなかった場合、VPC内から適当なサブネットが選択される(私の場合8つ)が、NAT Gatewayがアタッチされているかは考慮されないようです。
ECRのイメージをプルするには、PrivateLinkを使わない場合はインターネットへの接続が必要となるため、イメージが取得できずに起動に失敗していました。

# 事象
CloudWatch Rulesで定期実行に指定しているバッチ処理が3回に1回起動しませんでした。
単に起動しないだけではなく、

 * CloudWatchのメトリクス（TriggeredRules および Invocations）は記録されている
 * CloudTrailで ECSのRunTaskイベントのログを見ると、container のlastStatusは PENDING
 * CloudWatch Logsへのアプリケーションログは記録されていない

と、**CloudWatchからの呼び出しは成功しているのに、アプリケーションは立ち上がらない** 、という状況でした。


# どうやって原因究明したか

ECSタスクのイベントの変更をLambdaでCloudWatchに記録した上で、**証拠が出るまでバッチ処理を走らせました**笑

ECSタスクの記録方法は以下のチュートリアルに従いました。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/ecs_cwet.html

結果、以下のようなログが得られました。

```
...省略
        "containers": [
            {
                "containerArn": "arn:aws:ecs:ap-northeast-1:******:container/******",
                "lastStatus": "STOPPED",
                "name": "web",
                "image": "******.dkr.ecr.ap-northeast-1.amazonaws.com/******:******",
                "reason": "CannotPullContainerError: Error response from daemon: Get https://******.dkr.ecr.ap-northeast-1.amazonaws.com/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)",
                "taskArn": "arn:aws:ecs:ap-northeast-1:******:task/******",
                "networkInterfaces": [
                    {
                        "attachmentId": "******",
                        "privateIpv4Address": "******"
                    }
                ],
                "cpu": "256"
            }
        ],
...
```

はい。ECRからイメージをプルできていませんね。

対応としては、CDKのタスク起動時の定義でSubnetSelectionを明示的に指定しました。

# 反省

* CloudFormation → CDKに移行した環境では、CDKがよしなに処理してくれないこともある
* CDKで作成したリソースのCloudFormationテンプレートは確認しよう
[Python3][SQLite3]レコードを辞書型(dict型)で取得する簡単な方法

pythonからSELECT文でレコードを1行取得すると、タプル(tuple型)(例`(1, 'ABC')`)で返ってくる。それをカラム名をkeyとした辞書型(dict型)(例`{'id': 1, 'name': ABC}`)で取得する方法をまとめる。

具体的には、sqlite3のConnection オブジェクトの`row_factory`属性を変更することで簡単に実現できる。

dict型で取得することで、keyにカラム名を指定して取得したレコードから要素を取り出すことができるようになる。

#そもそも辞書型とは
[とっても便利なPythonの辞書型について覚え書き](https://qiita.com/E_Schaf/items/9ef26c0c514325d69e80)

#環境
- Python 3.7.4

#サンプルプログラムの動作
INTEGER型の'id'と、TEXT型の'name'という2つのカラムを持つテーブルに格納された下表の2件のデータを`{'id': 1, 'name': '加藤'}`や`{'id': 2, 'name': '佐藤'}`のようなdict型で取得する。

| id | name |
|:-:|:-:|
|1|佐藤|
|2|加藤|

#準備: テーブルの作成
テーブルの内容確認のためにSELECT文を発行して1行取得しているが、tuple型で返ってくる。

```python:create_table.py
import sqlite3

dbname = 'database.db'

connection = sqlite3.connect(dbname)
cursor = connection.cursor()

cursor.execute("CREATE TABLE sample (id INTEGER, name TEXT)")
cursor.execute("INSERT INTO sample VALUES (1, '加藤')")
cursor.execute("INSERT INTO sample VALUES (2, '佐藤')")
connection.commit()

#テーブルの内容確認
cursor.execute("SELECT * FROM sample")

# レコードを1行取得
print(cursor.fetchone()) #tuple型
#(1, '加藤')

# レコードを1行取得
print(cursor.fetchone()) #tuple型
#(2, '佐藤')

connection.close()
```

# dict型でのレコード取得
sqlite3のConnection オブジェクトの`row_factory`属性を変更することで、SELECT文を発行して1行取得すると、dict型が返ってくる。

```python:select_table.py
# sqlite3 標準モジュールをインポート
import sqlite3

# データベースファイルのパス
dbpath = 'database.db'


# dict_factoryの定義
def dict_factory(cursor, row):
   d = {}
   for idx, col in enumerate(cursor.description):
       d[col[0]] = row[idx]
   return d


if __name__ == "__main__": 
    # データベース接続
    con = sqlite3.connect(dbpath)

    # row_factoryの変更(dict_factoryに変更)
    con.row_factory = dict_factory

    # カーソル生成
    cur = con.cursor()
    # SETECT文の発行
    cur.execute("SELECT * FROM sample")

    # レコードを1行取得
    print(cur.fetchone()) #dict型
    #{'id': 1, 'name': '加藤'} 

    # レコードを1行取得
    print(cur.fetchone()) #dict型
    #{'id': 2, 'name': '佐藤'} 

    # 接続を閉じる
    con.close()
```

#row_factory属性の変更
sqlite3のConnection オブジェクトのdict_factory関数を定義して、row_factoryを変更することで、取得される1行の形式を変更できる。

dict_factory関数に記述されたcursorオブジェクトの`description属性`は、読み取り専用で、最後に発行されたクエリの結果のカラム名がタプルとして格納されている。また、enumerate関数によりタプルのインデックス番号と要素が同時に取得され、dict型の戻り値が生成されている。

#辞書型で取得できると何が変わるのか？
tuple型で取得されると、取得されたデータにカラム名が含まれないので、取得したレコードから要素を取り出す際に、インデックス番号を指定することになるので、取り出される要素の順番を意識しておく必要がある。

```python
# tuple型のデータからidの要素(value)を取り出す。
print(cursor.fetchone()[0]) #インデックス番号を指定
#1
```

dict型で取得すると、カラム名を含めて取得できるので、keyにカラム名を指定して取得したレコードから要素を取り出すことができるようになる。

```python
# dict型のデータからidの要素(value)を取り出す。
print(cursor.fetchone()['id']) #keyにカラム名を指定
#1
```

#蛇足: keyとvalueのタプルから辞書を作成
レコードの1行をtupule型で取得した後に、dict型に変換することはできるが、カラム数が増えてくるとkeyのタプルを作るのが面倒くさくなる。

```python
keys = ('id', 'name')
values = (1, "ABC")

dic = dict(zip(keys, values)) 
print(dic)
#{'id': 1, 'name': 'ABC'}
```


#参考
[sqlite3 --- SQLite データベースに対する DB-API 2.0 インタフェース](https://docs.python.org/ja/3/library/sqlite3.html)
Next.jsではじめるTypeScript

今回は、Next.jsを利用して、TypeScriptに挑戦しようという記事です
# テーマ

- TypeScriptの第一歩をNext.jsで整えよう


# 対象読者

- JavaScriptわかる
- Reactそこそこわかる
- Next.js触ったことある
- TypeScript初心者

ぐらいを想定です。

# 前提条件

- node.jsインストール済み

# プロジェクト作成

## ディレクトリつくる

```zsh
$ mkdir awesome-pjt && cd awesome-pjt
```

## プロジェクト作成

```zsh
$ npm init -y
```

## ライブラリインストール

```zsh
$ npm install --save next react react-dom
```

## Next.jsのコマンド追加

```zsh
$ vim package.json
```

```json:package.json
{
  ...
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  ...
}
```


## Next.jsのエントリーファイルを作成

```zsh
$ mkdir pages && touch pages/index.js
```

## ファイル編集（JavaScript）

```zsh
$ vim pages/index.jsx
```

```js:index.jsx
import React from 'react';

const Index = () => {
  return (
    <div>Hello, World</div>
  );
};

export default Index;
```

## ローカルサーバ起動

```zsh
$ npm run dev
```

`http://localhost:3000`にアクセスすると、`Hello, World`が表示されます。

ここまでが **Next.js** を **JavaScript** で利用した場合です。
続いて、TypeScriptを利用した場合にしてみましょう。

## ファイル名変更（TypeScript）
```zsh
$ mv pages/index.jsx pages/index.tsx
```

### 型ファイルライブラリをインストール
```zsh
$ npm install --save-dev typescript @types/react @types/node
```

### configファイルを作成
```zsh
$ touch tsconfig.json
```

```json:tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "allowSyntheticDefaultImports": true
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ]
}
```

### エントリーファイルを更新
```zsh
$ vim pages/index.tsx
```
返すコンポーネントに型情報を追加

```js:index.jsx
import React from 'react';

const Index = (): JSX.Element => {
  return (
    <div>Hello, World</div>
  );
};

export default Index;
```

ローカルサーバ再起動し、`http://localhost:3000`で、`Hello, World`が表示されれば、成功です。

---

### （補足）自動生成定義ファイル

`next-env.d.ts` が自動生成されますが、TypeScriptがコンパイル時に生成しているファイルです。
[Next.js](https://github.com/zeit/next.js)で、以下のように書かれています。

> Note: Next.js will create a file named next-env.d.ts in the root of your project. This file ensures Next.js' types are picked up by the TypeScript compiler.
> 
> You cannot remove this file, however, you can edit it (but don't need to).
【WebAR、WebRTC】iOS Safariで3DTouchが動作すると映像が真っ暗になるバグを回避

## 問題

以前8thWallを使用したWebARコンテンツを制作した際、以下のようなスクリーンショット機能を実装しました。

![Dec-13-2019 00-51-43.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163298/5193f7c7-941a-f4a8-f64d-1db0e804cdbf.gif)

ボタンを押すと結果のモーダルが出て、長押しで保存してもらう形です。

画像をダウンロードしてほしいとき、PCではダウンロードボタン(a要素のdownload属性)を置くことが多いですが、スマートフォンではこの方法が主流と思われます。
iOS12以下でdownload属性が、別画面で画像を開く挙動になってしまうためですね。

しかし、
① iOS12以下でimg要素を強く長押しした
② iOS13でimg要素を長押しした
場合に3DTouchが動作すると、**映像が暗くなってしまう課題**があることに気づきました。

![Dec-12-2019 14-53-47.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163298/adeb47c0-9f00-3d49-9126-a62944904ef6.gif)

調査したところ、これは8thWallに限らず、WebRTC全体で発生するバグのようです。

iPhoneをお持ちの方は以下のWebRTCサンプルページで`Open Camera`した後、上にある`WebRTC samples`リンクを3DTouchしてみてください。
https://webrtc.github.io/samples/src/content/getusermedia/gum/















## 解決策
「**3DTouch動作を防ぐことで、無理やり回避できる**」ことがわかりました。

### iOS12以下の場合

@katsuya_U さんの[こちらの記事](https://qiita.com/katsuya_U/items/bd0b044fd986c94b5da6)で解決しました。

以下は引用です。詳しくは上記リンクをご覧ください。

```js
// 全てのimgタグに対して実行
document.querySelectorAll("img").forEach(el => el.addEventListener("touchforcechange", e => {
  if (!e.touches || !e.touches[0]) return

  if (e.touches[0].force > 0.15) {
    e.preventDefault()
  }
}))
```
3DTouchが発動する圧力を超えた時に`preventDefault`するという内容でした。Appleの意表をついた感じの実装でちょっと面白いです。


### iOS13の場合

さて、当記事メインの問題はiOS13です。
iOS13から、[**3D Touchが廃止され、その主要機能が全iOSデバイスで利用可能になりました**](https://iphone-mania.jp/news-249752/)。

これがどういうことかというと...
**圧力に関わらず長く押していると3DTouch的な動きが起きてしまう**
ということです。ややこしい...。

しかし、逆にiOS13から嬉しい仕様が追加されました。それが、iOS12以下では微妙だった**download属性**の挙動変化です。
img要素を以下のようにa要素で囲ってみてください。

```slim
// pug
a.screenshot-link
    img.screenshot-img
```
```js
// js
const $download = document.querySelector('.screenshot-link');
const $img = document.querySelector('.screenshot-img');

// 保存された画像ソースのパスを登録
const srcPath = 'data:image/jpeg;base64,xxxxx...';
$download.setAttribute('href', srcPath);
$img.setAttribute('src', srcPath);

// a要素にdownload属性追加
//上書き保存しないように、スクショごとに変わる名前が望ましい
$download.setAttribute('download', `hoge${date.now()}.jpg`);
```

タップすると画像ダウンロードできます。

![Dec-12-2019 19-03-02.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163298/a26eae02-802f-5b1e-6676-d95220441b5a.gif)


**注意点**
初期設定ではカメラロールではなく**ファイルアプリのダウンロードフォルダ**に保存されるようです。
iOSユーザーには馴染みなく、「保存されていないじゃん！」という誤解を招くこともありました。

しばらくは、iOS13だけカメラ機能を切ってしまうという選択肢も視野に入れると良いかなと思います。


## Android(おまけ)

img要素単体だろうがa要素で囲おうが、長押しで画像保存をすることができます。

ただし、img要素単体ですと`ダウンロード.jpg`のように勝手に名前がつけられた挙句上書き保存されてしまいます。iOS13と同様の実装で、download要素で名前をつけてあげるのが親切かもしれません。
Laravel Excelで式の計算結果をインポートする

サンプル通りに値を読み込むと、その列に数式が入っていた場合は「=L51&M51」みたいな文字列が取得されます。

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        foreach ($rows as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

これを「山田(L51)太郎(M51)」のような計算結果として取得したい場合は、以下のように追加します。

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithCalculatedFormulas; // 追加

class UsersImport implements ToCollection, WithCalculatedFormulas // 追加
{
    public function collection(Collection $rows)
    {
        foreach ($rows as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

これだけ！

情報元はこちらのIssue → [How can I import calculated values?](https://github.com/Maatwebsite/Laravel-Excel/issues/1871)
CentOS 8のサービス及びログに関して

## CentOS 8のサービスの起動・停止・自動起動について

下記にWEBサービスに必要なデーモンなどを紹介します。

### デーモンとは
・「UNIX系OS（MacとかLinuxとか）における常駐プログラムの呼び名」
・メモリ上でお仕事が来るのをぼーっと待っていて、お仕事が来るとささっと実行し、終わるとまた待機状態に戻ります。
・常に戦闘態勢を維持することが求められているプログラムです。

### httpdとは
・Linuxとかにおける常駐プログラム（デーモン）のひとつ
・Webサーバとしてのお仕事をしているデーモンが「httpd」です。

### telnetとは
・「ネットワークを経由して他のコンピュータ（主にサーバ）に接続し、遠隔操作するための仕組み」です。
・SSHは「パワーアップしたtelnet」です。
・telnetは通信途中の内容が暗号化されませんが、SSHは、通信内容が暗号化されてやり取りされます。

### sshdとは
・Linuxとかにおける常駐プログラム（デーモン）のひとつ
・SSHで接続されるのを待ち受けて、接続してきたらその相手をしてやるのがお仕事のデーモン

### mysqldとは
・Linuxとかにおける常駐プログラム（デーモン）のひとつ
・MySQLとしてのお仕事をしているデーモン
・MySQLというデータベースマネジメントシステムにおいて、データを入れておく箱を管理している代理プログラムがmysqldです。

### サービスの起動・停止・自動起動 コマンド

![スクリーンショット 2020-01-08 17.47.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/d926c386-44ed-9e55-489b-f3854043c758.png)


## CentOS 8のログ    (root_drectory : /home/public_html/)
WEBサービスが正常に動作しない場合、下記のログで原因調査が可能です。
![スクリーンショット 2020-01-08 17.52.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274686/5bab07e7-6549-c532-26ce-ce78b75b1378.png)
pythonのastroqueryを用いて検索し、skyviewでfits画像を取得する方法

# astroquery で検索し、fits画像を保存したい

## astroquery 

手始めにastroqueryで自分の欲しいデータや天体を調べる。使い方は [python の astroquery を用いた宇宙天文カタログの検索と銀河を用いた簡単なプロット方法](https://qiita.com/yamadasuzaku/items/5b83350ae0d2c1e7e278) を参照。

### 名前の変更

Skyviewは NGC は "N" だけでは判別できないのであるが、カタログによっては、NGCは省略してNだけの場合も多い。下記では、NをNGC, IをICに変更して名前のリストを生成している。

## skyview 

astroquery の skyview は、https://astroquery.readthedocs.io/en/latest/skyview/skyview.html にある画像を提供している。ここでは、X線はRosatのHRIの画像、可視はDSSの画像をダウンロードして、fitsに保存する例を示す。

## サンプルコード
ここでは、http://vizier.u-strasbg.fr/viz-bin/VizieR-3?-source=J/ApJS/80/531/gxfluxes にあるAn X-ray catalog and atlas of galaxies. (Fabbiano+, 1992) を参考例として示す。

``` python:
#!/usr/bin/env python

from astroquery.vizier import Vizier 
v = Vizier(catalog="J/ApJS/80/531/gxfluxes",columns=['Name',"logLx","Bmag","dist","type"],row_limit=-1)
data = v.query_constraints()
sname = data[0]["Name"] 
namelist = []

olist=["HRI","DSS"]

def save(p,name,obs):
    for onep,oneo in zip(p,obs):
        onep.writeto(name+"_"+oneo+".fits",overwrite=True)

for one in sname:
    name=one.strip().split()[0]
    name=name.replace("N","NGC").replace("I","IC")
    namelist.append(name)

from astroquery.skyview import SkyView
for i,name in enumerate(namelist):
    print(i,name)
    try:
        paths = SkyView.get_images(position=name, survey=olist)
        save(paths,name,olist)
    except:
        print("..... ERROR ",i,name)


```


## プロット方法

こうしてダウンロードしたfits画像をプロットする方法は、
[pythonを用いて銀経銀緯で複数のfits画像を並べてプロットする方法](https://qiita.com/yamadasuzaku/items/35a95f36144fecd4ad2b) にまとめた。ds9などの天文ツールでもよいが、バッチ処理はds9だと面倒なことが多い。

# 応用編 

## 超新星残骸のイメージを取得する方法

データベースは、https://vizier.u-strasbg.fr/viz-bin/VizieR?-source=VII/272 の A catalogue of Galactic supernova remnants (Green, 2014) A catalogue of Galactic supernova remnants (Green, 2014) が最新のようなので、これを用いる。

### コードと注意点

基本的に上と同じであるが、SkyView の positon に与える名前はSIMBADかNEDで認識される名前である必要があるため、例えば、 G016.2-02.7 だけではダメで、その前に SNR をつけないといけない。

そのほかは、遠方銀河のX線と可視光の場合は、視直径がだいたい揃っているが、超新星残骸は系内天体なので、視直径のばらつきが大きいので、下記のままでは最適なイメージの自動取得とは言えない(どこかで改定予定。)。


``` python:
#!/usr/bin/env python

from astroquery.vizier import Vizier 

v = Vizier(catalog="VII/272/snrs",columns=["SNR","type","S","Names"],row_limit=-1)
#https://vizier.u-strasbg.fr/viz-bin/VizieR?-source=VII/272
#A catalogue of Galactic supernova remnants (Green, 2014) A catalogue of Galactic supernova remnants (Green, 2014)
data = v.query_constraints()

sname = data[0]["SNR"] 
namelist = []

olist=["HRI","DSS","Fermi 5"]

def save(p,name,obs):
    for onep,oneo in zip(p,obs):
        onep.writeto(name+"_"+oneo+".fits",overwrite=True)

for one in sname:
    name=one.strip().split()[0]
    namelist.append(name)

from astroquery.skyview import SkyView
for i,name in enumerate(namelist):
    print(i,name)
    try:
        paths = SkyView.get_images(position="SNR " + name, survey=olist)

```
gnuplot: アスキーアートで描画する

近頃gnuplotは触らなくなっちゃったのですが、
未だに使うgnuplotの便利な機能を紹介しておきます。

それは、**アスキーアートで描画する**というものです。

例えば、とあるサーバーで数値計算を走らせていて、計算途中の結果を確認したいとします。
こういう時って、図を作ってダウンロードするのは面倒くさいし、Xwindowも使えないことがほとんどです。こんな時にアスキーアートで描画すればさくっと結果を確認できます。




###やり方
#### 1.　`dumb`というterminalを使います。 

```
set term dumb
```
サイズを大きくしたい時は、`set term dumb 150 30`といった具合に、使用pixel数(横)、使用pixel数(縦)を指定します。


#### 2.　お好きに描画してください。
こんな具合に表示してくれます。
<img width="1058" alt="スクリーンショット 2020-01-08 17.37.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278171/a0d17b8d-1fe0-70d8-d95a-4a4c944a761a.png">

うん。めっちゃ便利ですよね。
確かに解像度は全然ないですが、計算結果をその場で確認するだけなら十分です。

ぜひお役立てください。
docker-compose サービス名の一覧を取得する

## docker-compose サービス名の一覧

```shell-session
$ docker-compose config --service
app
web
db
db-testing
node
redis
mail
```

## 備考

`--service` オプションを指定しない場合は [docker-compose.yml](https://github.com/ucan-lab/docker-laravel/blob/master/docker-compose.yml) の内容が変数などすべて展開された状態で表示されます。

```shell-session
$ docker-compose config
services:
  app:
    build:
      args:
        TZ: Asia/Tokyo
      context: /Users/ucan/work/docker-laravel/docker/php
    environment:
      CACHE_DRIVER: redis
      DB_CONNECTION: mysql
      DB_DATABASE: homestead
      DB_HOST: db
      DB_PASSWORD: secret
      DB_USERNAME: homestead
      MAIL_HOST: mail
      MAIL_PORT: '1025'
      QUEUE_DRIVER: redis
      REDIS_HOST: redis
      SESSION_DRIVER: redis
      TZ: Asia/Tokyo
    ports:
    - 18000:8000/tcp
    volumes:
    - /Users/ucan/work/docker-laravel/src:/work:rw
    - /Users/ucan/work/docker-laravel/docker/ash:/etc/profile.d:rw
    - /Users/ucan/work/docker-laravel/docker/php/psysh:/root/.config/psysh:rw
    - /Users/ucan/work/docker-laravel/logs:/var/log/php:rw
    - /Users/ucan/work/docker-laravel/docker/php/php.ini:/usr/local/etc/php/php.ini:rw
    working_dir: /work
  db:
    environment:
      MYSQL_DATABASE: homestead
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_USER: homestead
      TZ: Asia/Tokyo
    image: mysql:8.0
    ports:
    - 13306:3306/tcp
    volumes:
    - db-store:/var/lib/mysql:rw
    - /Users/ucan/work/docker-laravel/logs:/var/log/mysql:rw
    - /Users/ucan/work/docker-laravel/docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf:rw
  db-testing:
    environment:
      MYSQL_DATABASE: homestead
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_USER: homestead
      TZ: Asia/Tokyo
    image: mysql:8.0
    ports:
    - 13307:3306/tcp
    tmpfs:
    - /var/lib/mysql
    - /var/log/mysql
    volumes:
    - /Users/ucan/work/docker-laravel/docker/mysql/my.cnf:/etc/mysql/conf.d/my.cnf:rw
  mail:
    image: mailhog/mailhog
    ports:
    - 18025:8025/tcp
  node:
    image: node:12.14-alpine
    tty: true
    volumes:
    - /Users/ucan/work/docker-laravel/src:/work:rw
    working_dir: /work
  redis:
    image: redis:5.0-alpine
    volumes:
    - redis-store:/data:rw
  web:
    depends_on:
    - app
    environment:
      TZ: Asia/Tokyo
    image: nginx:1.17-alpine
    ports:
    - 10080:80/tcp
    volumes:
    - /Users/ucan/work/docker-laravel/src:/work:rw
    - /Users/ucan/work/docker-laravel/logs:/var/log/nginx:rw
    - /Users/ucan/work/docker-laravel/docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:rw
version: '3.0'
volumes:
  db-store: {}
  redis-store: {}
```

## 参考

- https://docs.docker.com/compose/reference/config/
- https://github.com/ucan-lab/docker-laravel
OAuthまとめ

# 認証と認可
## 認証
誰であるかをチェックすること = 本人確認

## 認可
誰が*1 誰に*2 何の権限を与えるか

*1) 「誰が」は主に「ユーザーが」
*2) 「誰に」は主に「クライアントアプリに」

認可の「誰が」は認証処理（本人確認）になる。
つまり、**認可処理**の中に**認証処理**が含まれている。ややこしや。


# OAuthのしくみ
OAuthの流れを図式化
![oauth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120480/e3916ea8-e88c-6a54-8e5a-64ad2955894c.png)

赤く囲まれたところが、アクセストークンの要求とその応答を表している。
**アクセストークンの要求と応答を標準化したもの = OAuth2.0**

つまり、OAuthは**認可**の仕組みのこと。
モバイルアプリの障害対応の流れって？

業務系システムのインフラ運用から、Web系のアプリ開発に移って、今日はクラッシュ調査をしていました。
ふと、「そういえば障害対応どうしてたっけ？　会社変わったけどやり方なんか使えるものあんのかな？」と思ったので、障害対応について書いてみます。

# 業務系システムの障害対応の流れ
## 初動
- 関係者に報告する
    - 報・連・相
- 影響を調べる
    - 必要があれば緊急対応
- 情報共有担当の人がいると捗る
    - ホワイトボードに時系列で起こったことを書くとか
    - これをやると、遅れて来た人が状況を把握できて、戦力になる

## 原因調査
- ログを調べる
    - エラーメッセージ特定
- エラーメッセージで過去の障害事例を検索する
    - ググる、または社内イントラを検索
- ロジックを追うorダンプを読む
    - ダンプ読むのはあんまない？
- OSやプロダクトの問題と特定できたら、ベンダーに質問を投げる

## 対応検討（原因が特定できた前提）
- 復旧対応を行う
    - 止めていたバッチ処理を再開する、壊れたDBをなおす、など
- 恒久対応策を検討する
    - 発生確率が極めて低いわりに対応コストが高かったら、リスクを許容する判断もアリ
- ここまでできたら解散！

# 障害対応の難しさ
エラーメッセージの逆引きで原因を突き止めないといけないのが難しさだと思います。
類似事例が見つかればよいですが、調査が難航すると、テスト環境でひたすら条件そろえて再現テストすることもありました。
数日に渡って終電まで調査することも😱

# で、モバイルアプリでは
Web系でも、基本的な対応の流れは一緒なのかなと思っています。
インフラだったらほぼ一緒かな？
DevOps体制でやっているので、保守部門が障害対応マニュアル引き継いでひたすら対応みたいな世界ではないです。
「できる人がやる」みたいな雰囲気は、障害対応のときは前職でもあって、
やむを得ないところもあんのかな〜と思いましたが、Web系だとより強い気がします。

モバイルだと、障害対応という言葉自体あまり使わない気がします。
対応するとしても、ストアにアップデートする必要があるので、業務系のシステム屋さんみたいな即対応が仕組み上できない面があります。
firebaseのCrashlyticsなど、アプリがクラッシュした情報を収集できるツールを入れて、
クラッシュ数が多いエラーを調査していって、次回のアップデートに盛り込んでいくスタイルになるかと。
障害対応というよりかは、バグ対応・クラッシュ対策という名前がつくみたいですね。

業務系と比べると、リスク許容度が高いです。
また、ユーザーの実行環境が多種多様であり、Android/iOSの内部仕様もDeveloperは知らないので、影響が小さければ無視するという選択は結構とられます。
（たとえばiPhone 3GS使っているユーザーの動作まで保証していられません。
どこまでサポート対象にするか、線引は微妙ですが）

エラーメッセージの逆引きから問題を特定する、という思考プロセスは同じです。
情報共有が活発なので、社内イントラよりもQiitaやStack Overflowが役立ちます。
英語情報が多いので、語学力があると有利です。
できなければ、Google翻訳が最近はだいぶ優秀なので、割り切っておまかせでもいいと思います。
paddingのある親要素と同じwidth100%の要素を入れる

# よくある作り

<p class="codepen" data-height="298" data-theme-id="default" data-default-tab="html,result" data-user="key055" data-slug-hash="ExaQLKr" style="height: 298px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="paddingのある親要素と同じwidth100%の要素を入れる">
  <span>See the Pen <a href="https://codepen.io/key055/pen/ExaQLKr">
  paddingのある親要素と同じwidth100%の要素を入れる</a> by nozomi (<a href="https://codepen.io/key055">@key055</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

```css
#mainContent {
  width: 600px;
  min-height: 100vh;
  background-color: #fff;
  margin: 0 auto;
  padding: 40px;
  box-sizing: border-box;
}
.haba100 {
  background-color: #29292e;
  color: #fff;
  width: 600px;
  margin-left: -40px;
  box-sizing: border-box;
  padding: 10px 40px;
  font-size: 14px;
}
```

widthを親と同じにして、親のpaddingの分だけmarginでマイナスに良い。

簡単だった。
今まで頭硬かったなぁ。
`@babel/preset-env` を useBuiltIns: 'usage' でコンパイルしたjsをAndroid5で見ると React 内部の Map, Set が undefined になる

# 何が起きたか

- Android 5 の標準ブラウザでReact動かそうとしたら`Map` `Set` がないと言われて動かなかった。
- `@babel/preset-env` で polyfill してるから Map, Set はあるはずなのになぜ‥

```js:babel.config.js
  ...
  presets: [
    [require('@babel/preset-env').default,
      {
        forceAllTransforms: true,
        targets: {
          ie: '11',
          android: '5'
        },
        debug: true,
        useBuiltIns: 'usage',
        corejs: 3,
        modules: false
      },
      ...
```

# 原因

- `@babel/preset-env` の `useBuiltIns: 'usage'` はコードを解析して必要なpolyfillのみを読み込んでくれる。
- babel 7 はデフォルトで node_modules 以下をコンパイルの対象外としてる
- これにより、React 内部で使われてる `Map`、 `Set` が polyfill されずに例外になってた。

https://babeljs.io/docs/en/v7-migration-api#config-changes

>We also exclude `node_modules` by default and only look in the root unless you opt-in to setting an array of the `.babelrcRoots` option such as `"babelrcRoots": [".", "node_modules/pkgA"]`

# 対応1


```js:babel.config.js
  ...
  useBuiltIns: 'entry'
  ...
```
にして、エントリーポイントで

```js:index.jsなど
import "core-js/stable";
import "regenerator-runtime/runtime";
```
する。問題としてはファイルサイズがでかくなる。

# 対応2


```js:babel.config.js
  ...
  useBuiltIns: 'usage'
  ...
```
のまま、エントリーポイントで

```js:index.jsなど
import "core-js/modules/es.map";
import "core-js/modules/es.set";
```
する。問題としてはほかにnode_modulesでpolyfillが必要なものが使われてたら例外になるので怖い。

# 対応3

node_modules もコンパイルする
csvから取得した値を１件ずつ処理して出力


```PHP
<?php 
    $lines = file('readfile.csv');

    $cnt = count($lines);//レコード数
    $i = 0;
    
    $fp = fopen('php://temp', 'w');//一時ファイル
    
    while($i<$cnt){
        $data = explode(',',$lines[$i]);

        //ここで色々な処理

        mb_convert_variables('SJIS-win', 'UTF-8', $data);//文字コード変換
        fputcsv($fp, array_values($data));//一時ファイルに１件書き出し

        ++$i;
    }

    rewind($fp);//ファイルポインタを先頭に戻す
	file_put_contents("outputfile.csv", stream_get_contents($fp));//出力
    fclose($fp);
 ?>
```

参考
[PHPでCSVファイルの書き込みを行う方法](https://uxmilk.jp/15020)
[PHPで容量の大きいデータをCSV出力するときに工夫したこと](https://qiita.com/shosho/items/1a83ee7df82acca2274d)
JavaScriptで2次元配列のindexを取得する

いきなりですがタイトル詐欺です。JavaScriptに多次元配列は定義されていませんが他に良い表現方法が見つからなかったのでこのような表記にしました。

```javascript:サンプルコード
var hoge = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

hoge.forEach( (row, i) => {
    row.forEach( (element, j) => {
        if(element === 6) {
            console.log(i, j)  // 1,2
        }
    })
});
```

もうちょっとマシなタイトルがあればコメントください。
Android Studio Gradle でYou are currently using Java 6. の解決法


# 起きたこと

Android Studio で古いプロジェクトを開いてGradleビルドしようとしたらエラー


```
Error:Gradle 3.3 requires Java 7 or later to run. You are currently using Java 6.
```


JDK 1.8 (8) はインストール済みだしプロジェクトのJDK設定もしている。
が、この上のエラーが消えない。


# 環境
Android Studio 1.5
MacOSX Yosemite 10.10.5


# 試したこと

Mac にJDK1.8 (8) は入っているし、環境変数`JAVA_HOME` もJDK1.8のpathに指定されている。
(再起動などもしてみた)

しかしエラーが取れなかった。


試しにGradle のバージョンをあげてみると、


```
Error:Failed to complete Gradle execution.

Cause:
Received fatal alert: protocol_version
```

Java 実行時に以下オプションで解決できるようだけど
通らず。
`JAVA_TOOL_OPTIONS="-Dhttps.protocols=TLSv1.2"`


# 解決策

というか回避策。

Gradle のバージョンを上げると、タイトルの通り`Java 6` ではだめとなり、
なので、**Java6でビルドが通る範囲でぎりぎりまでバージョンを下げて**みる。

## Java6 で実行する

`Gradle` とAndroid Studioのpluginである`Gradle build tools`
が関係しているようで

試してみると、Java6 で実行できるのは、
Gradle 2.x系 (<= `Gradle 2.14.1`) までのようで、
`Gradle 2.14.1` を実行可能な Gradle build toolsのバージョンは =< `Gradle 2.1.3` とのこと。


## Java6 でGradleビルドする環境
つまり、
`Java6` でビルド可能な最新バージョンの組み合わせは
`Gradle 2.14.1`
`Gradle build tools 2.1.3`


### プロジェクトのGradle のバージョンを下げる

Projectのrootディレクトリで`./gradlew` を実行すると

``` bash:
$ chmod 755 gradlew
$ ./gradlew tasks
...
FAILURE: Build failed with an exception.

* Where:
Build file '/Users/user/AndroidStudio1.5Projects/RepeatingLocalNotifications/app/build.gradle' line: 1

* What went wrong:
A problem occurred evaluating project ':app'.
> Failed to apply plugin [id 'com.android.application']
   > Gradle version 2.14 is required. Current version is 3.3. If using the gradle wrapper, try editing the distributionUrl in /Users/user/AndroidStudio1.5Projects/RepeatingLocalNotifications/gradle/wrapper/gradle-wrapper.properties to gradle-2.2-all.zip
```

Gradle 2.14がrequiredとのこと。実際に2.14.+ だと通る。

``` bash:./gradle/wrapper/gradle-wrapper.properties
# 以下に変更
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
```

``` java:./app/build.gradle

buildscript {
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.3'
    }
}
```


## repositoryを追加

(Java6とは関係ないが、依存ライブラリのためビルドを通すため。)

``` java:./build.gradle

allprojects {
    repositories {
        ...
        maven {
            url 'https://maven.google.com'
        }
    }
}
```



# 結論


いちおう通った。
(根本的な対処ではないが。)
古いMac (Yosemite 10.10.5) の環境のため、内部ライブラリ(Xcode build tools)の問題の可能性あり。


# 参考

https://stackoverflow.com/questions/51090914/received-fatal-alert-protocol-version-build-failure-gradle-maven


https://stackoverflow.com/questions/43133857/gradle-3-3-error-need-java-7-or-later-unsolved

https://stackoverflow.com/questions/45989687/gradle-3-3-requires-java-7-or-later-to-run-you-are-currently-using-java-6

https://stackoverflow.com/questions/52535842/gradle-4-10-2-requires-java-7-or-later-to-run-you-are-currently-using-java-6-wh
Wekaでメモリが足りなかったときの対処方法

Wekaで学習させていると、次のような警告が表示されることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309048/92ca06db-7457-f53f-9523-5735f0109f3e.png)

これは、学習を行うのに十分なメモリがないよ、と警告されているので、以下の手順でWekaが扱えるメモリの量を増やしてあげます。

```sh
$ cd /Applications/weka-3-8-0-oracle-jvm.app/Contents/
$ vi Info.plist
```

Info.plistの中から

```
\<string\>-Xmx1024M\</string\>
```

となっている行を探し

```
\<string\>-Xmx2048M\</string\>
```

のように書き換えます。
これでエラー回避されるようになります。
VSCode+Live Shareで共同編集を行う

# Live Shareによるオンラインでの共同作業
VSCode上で複数人で共同編集ができます．
Overleafでは，GitHub連携が有料なのでLaTeXで原稿書くのはこっちの方が使い勝手がいい(?)

## 導入
Live ShareとLive Share Chatを導入します．
Live Share Chatは編集者とチャットが行える拡張機能で入れておいて損はないと思います．
Live Share Audioといって音声通話出来るものもありますが，今は入れません．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/960cbd12-b94c-5f6d-ab49-6dffe1eb3b5b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/3af01bae-c103-dff3-e80d-d0730ae0231c.png)

## ログインとInvite URLの発行

インストール出来たら左にLive Shareタブができ，左下にLive Shareのアイコンが出来ます．(下図赤枠)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/006538a1-2c9c-50a6-3294-b71786484fe0.png)

左下のアイコンをクリックすると，初回はログインタブが上に出てきます．
今回はGitHubアカウントでログインします．
`Sign in with GitHub`をクリックすると認証ページに飛ばされるので諸々行うと，Live ShareとGitHubの連携が完了しログインできます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/8d420974-2622-290d-7d25-54d3eba30c83.png)

ログイン後，再び左下のアイコンをクリックすると下のようなタブが出てきます．
`Invite Others (Copy Link)`から，リンクが発行されるのでこれを共同編集者に送りつけます．
**※現在開いているワークスペースの共同編集リンクが発行されるので，予め共同編集を行いたいフォルダを開いておく必要があります．**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/ff713a3c-4b00-97e6-b0a1-7e9b5a4e0466.png)

## 参加者側

参加者側も同様にVSCodeにLive ShareとLive Share Chatを導入しログインします．
左下のLive Shareアイコンの左に自分のユーザIDが表示されていると思うのでそれをクリックすると下のようなタブが出ます．
`Join Collaboration Session`を選択し，先ほど送られてきたURLを貼り付け参加完了です．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/14a1f0b9-ba84-711b-9209-071fa58918c1.png)

LaTeXの編集を行っている画面です．
現在作業を行っているユーザ名が表示され，リアルタイムに更新されます．また，Live Share Chatでやり取りもできます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/848f944a-a0f1-2ce3-df6b-eae41e56069e.png)

灰色の縦線部分から行単位でのコメントもできます．（これが一番感動した）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228086/374a52c9-6076-82f1-bdac-70a0d0c88a59.png)
Local by Freewheelを使うことになって、MAMP FreeとMAMP Proの違いについて調べて見た

#ざっくりと

MAMPはFREE。
MAMP PROは有料。

いくらするのか調べて見たところ・・・・
![スクリーンショット 2020-01-08 16.44.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524422/915381c6-2c98-aa02-7059-e87320f6ab28.png)

MAPM PROってそんなすんのかい。
フルバージョンならなんとこのお値段・・・。
それにしてもMAMPバージョンが上がってから値上がりしている気がする。

無料で使えるローカル開発環境あるよ！
↓
https://qiita.com/Himekichi/items/44ddcaaf2f9a6a9fdcea
これがLocal by Freewheel.


>#MAMPとMAMP PROとの違い
1.ホスト毎にPHPのバージョンを変更
2.複数の仮想サーバーの設定が出来る
3.WordPress、Drupal等をワンクリックインストール出来る
4.ダイナミックDNSに対応
5.メールサーバーの機能を使える
6.ApacheのモジュールをGUIで切り替え出来る


引用
https://t-shimohara.com/pc/mamp
https://www.mamp.info/en/mamp-pro/
【備忘録】PythonでPostgreSQLからデータを取得する

毎回調べるのが面倒なので書き残しておきます。

```Python
import psycopg2


# 任意で変更する
postgre_user_name = "user_name"
postgre_user_password = "user_password"
postgre_server = "server"
postgre_server_port = "server_port"
postgre_database_name = "database_name"
postgre_table_name = "table_name"

conn = psycopg2.connect("postgresql://"
                        + postgre_user_name
                        + ":" 
                        + postgre_user_password
                        + "@"
                        + postgre_server
                        + ":"
                        + postgre_server_port 
                        + "/" 
                        + postgre_database_name)
cur = conn.cursor()
sql_sentence = "select count(*) from " + postgre_table_name + ";"
cur.execute(sql_sentence)
cur.fetchall()
```

接続先は以下のように変換される

```
postgresql://user_name:user_password@server:server_port/database_name
```

sql文は以下のように変換される。

```
select count(*) from table_name;
```
bash関数での再帰呼び出しサンプル（多重ループの代用→転じて多重xxx）

# はじめに

諸々の事情があり、bashで動的な多重ループ処理（~~←ちょっと何言ってるかわからない~~）を書かねばならないことに。

```shell
$ ./xxx.sh 5
```

なんてやったら、5回の多重ループを実施する。という要件です。

**bashでそんなことできんのかよ**
と思ったんですがあっさり実現できました。ので共有します。

# 本編

## 仕様

**指定桁数分、すべての数値の組み合わせを求め、出力します。**
具体的には

```shell
$ ./xxx.sh 3
```

とした場合、3桁の000～999、計1000個の数値をコンソール出力します[^1]。

[^1]: コメントいただいたように、本仕様であれば``seq``コマンドで簡単に実現できますが、あくまで再帰呼び出しの例ということで

## コード

以下参照ください（ご使用は自己責任でお願いします）。

```shell
$ cat recursive_loop.sh
#!/bin/bash

SOURCE_CHARS="0123456789"
LENGTH=${#SOURCE_CHARS}

# 結果文字列と最大の深さ（初期値は1）
result_str=""
depth_max=1

# 再帰関数本体
function loop_func () {
    # 明示的にローカル変数を使う
    local _count=${1}
    local _i=0
    local _before=""

    for ((_i=0; _i<${LENGTH}; _i++))
    do
        # 終端に1文字を連結
        _before=${result_str}
        result_str=${result_str}${SOURCE_CHARS:${_i}:1}

        # 深さが最大となったら結果出力
        # _countは0始まりなので、depth_maxから1を引いている
        if [ ${_count} -ge $((${depth_max}-1)) ]; then
            echo ${result_str}
        # 最大でなければ再帰呼び出し
        else
            loop_func $((${_count}+1))
        fi

        # if/elseいずれの場合も文字列は連結前に戻す
        result_str=${_before}
    done
}

# パラメータで深さを受け取る
if [ ${#} -ge 1 ]; then
    if [ ${1} -ge 1 ]; then
        depth_max=${1}
    fi
fi

# 再帰呼び出し開始
loop_func 0
```

## 実行結果

```shell
$ ./recursive_loop.sh
0
（略）
9
$ ./recursive_loop.sh 2
00
（略）
99
$ ./recursive_loop.sh 3
000
（略）
999
$ ./recursive_test.sh 3 | wc -l
1000
```

## 汎用化

多重化するのがループだとごちゃつくので、汎用的に「多重xxx」とするなら以下。

```shell
$ cat recursive_xxx.sh
#!/bin/bash

# 最大の深さ（初期値は1）
depth_max=1

# 再帰関数本体
# xxxに応じた処理は暫定でechoにしてある
function xxx_func () {
    # 明示的にローカル変数を使う
    local _count=${1}

    # 深さが最大となったら終了
    # _countは0始まりなので、depth_maxから1を引いている
    if [ ${_count} -ge $((${depth_max}-1)) ]; then
        echo "[${_count}] FINISH (Depth=${depth_max})"
    # 最大でなければ再帰呼び出し
    else
        echo "[${_count}] --->"
        xxx_func $((${_count}+1))
        echo "[${_count}] <---"
    fi
}

# パラメータで深さを受け取る
if [ ${#} -ge 1 ]; then
    if [ ${1} -ge 1 ]; then
        depth_max=${1}
    fi
fi

# 再帰呼び出し開始
xxx_func 0

user@user-VirtualBox:~/zip$ ./recursive_xxx.sh 3
[0] --->
[1] --->
[2] FINISH (Depth=3)
[1] <---
[0] <---
```

## 技術？ポイント

- 関数が書ける
- その関数でローカル変数が使える

言語仕様的にこれらを満たすため、再帰呼び出しも可能なのでした。

~~アルゴリズム的には、頭が混乱しそうでしたが何とかなった~~

# おわりに

## 感想

bashもやればできる！笑

## 確認環境

- Ubuntu 18.04 LTS
pybatfishの向き先batfishサーバを変更する

# はじめに
windowsでbatfishを使うpythonプログラムを開発する際
 *windows上にDocker環境は構築せずに* Linuxサーバ上に構築済みのBatfishをwindowsから使いたかった。

サーバ: Dockerイメージ[batfish/batfish](https://hub.docker.com/r/batfish/batfish/)でコンテナ起動
ローカルPC: [batfish/pybatfish](https://github.com/batfish/pybatfish#2-python-client)を使ってサーバ上のbatfishを利用


# 実現方法
 **pybatfish/client/options.py に記載のhostを変更する** のみ！

(windows venv上にpybatfishをインストールしている場合)
venvディレクトリ/Lib/site-packages/pybatfish/client/options.py

(ついでにlinux venvの場合)
venvディレクトリ/lib/python3.6/site-packages/pybatfish/client/options.py



```python:options.py
class Options(object):
     
    # coordinatior_host = "localhost"  # type: str
    coordinatior_host = "<サーバのIPアドレス>"  # type: str
```

のように変更。

これで例えば

```python:
from pybatfish.client.commands import *
from pybatfish.question.question import load_questions, list_questions
from pybatfish.question import bfq

load_questions()
bf_init_snapshot(<zip file or directory>) 
``` 
をwindows上で実行するとサーバのdocker上にsnapshotファイルが作成されます。
OpenCVを使って紙に押した印鑑を電子化してみた

# Motive
Excelのシートかwordで自分の印鑑を押印する箇所があったりします。少し大事な書類であれば市役所に登録されている印鑑証明と同一のものを使いたい時があるのですが、以前は一度コンビニで紙を印刷して押印し、再度スキャンでpdf化して提出をしていました。

結構なアナログな処理をしていた訳ですが、印鑑をイメージ化してシートに貼り付けることができればコンビニへ行く手間がなくなっていいかなと思い方法を考えてみました。

最初は印鑑を撮影して、PowerPointかフリーの画像編集ツールを使って背景色を透過しようとしたのですが紙質によって全てを変換することは出来ずに断念してしまいました。

それで、試行錯誤して結局OpenCVで画像処理を数行書いて問題を解決をしたので備忘録として残しておきます。

# Dataset
[アクセア](https://www.accea.co.jp/hanko/pj_hanko.html)にあった印鑑サンプルを使いました。
![ieyasu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/4a55735a-4813-bc73-0151-fcaa72f113e9.jpeg)

# Method

1. 二値化＋画像反転
2. 元画像と1の画像でマスキング
3. 背景画像を透過(α値100%)


# Development

```Python
import cv2
import sys
import numpy as np

if __name__ == '__main__':

	if len(sys.argv) != 2:
		sys.exit()

	window_name = "sample"
	img_path = sys.argv[1]

	mat = cv2.imread(img_path)
	gray = cv2.cvtColor(mat, cv2.COLOR_BGR2GRAY)
	cv2.imwrite("gray.png", gray)

	#二値化
	ret2, mono = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY_INV) 
	cv2.imwrite("mono.png", mono)

	#マスキング処理
	dst = cv2.bitwise_and(mat,mat,mask=mono)
	cv2.imwrite("dst.png", dst)

	#channelを3 -> 4に変更
	alpha = cv2.cvtColor(dst, cv2.COLOR_BGR2BGRA)

	#背景が黒い部分のみ透過
	for i,col in enumerate(dst):
		for j,row in enumerate(col):
			color = dst[i][j]
			if (color == np.array([0,0,0])).all():
				alpha[i][j][3] = 0

	cv2.imshow(window_name, alpha)
	cv2.imwrite("out.png", alpha)
	cv2.waitKey(0)
	cv2.destroyWindow(window_name)

```

今回は途中まで処理した画像データも出力しています。


# Result

| 処理フロー | output |
|:-----------------|:------------------:|
|元データ|![ieyasu.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/231c1cdd-e0a8-5c5f-7e75-f1b0270b92f8.jpeg)|
|白黒|![gray.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/9a531348-0897-c35c-f9e5-bb528730e077.png)|
|二値化+反転|![mono.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/fbf47704-52fa-d044-77f3-a4ed52c11831.png)| 
|マスキング|![dst.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/1c46baac-581f-f574-8359-2ffe5def0ef4.png)| 
|背景色透過 <br>(処理終了)|![out.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/288206/795e2f6f-2dcf-a800-e01a-a8c4ce582eca.png)| 


# Future
`cv2.bitwise_and`を利用すれば背景透過は簡単に作成はできます。
ツールを使って時間がかかりそうだったらこっちの方が良さそうです。

# Reference
-  [python+Opencvによる画像処理5（画像結合とマスク）](http://tatabox.hatenablog.com/entry/2013/07/15/200232)
-  [Python, OpenCV, NumPyで画像のアルファブレンドとマスク処理](https://note.nkmk.me/python-opencv-numpy-alpha-blend-mask/)
- [アクセア](https://www.accea.co.jp/hanko/pj_hanko.html)
    -  印鑑に使った元のデータセット
【python】if文

# if文
何かを基準に処理を分けたい場合に、if文を用いる。
記述方法は**if 条件式 :**である。
条件式がTrueの時に、if文内の処理が実行される。
（条件式がTrueとは、例えば５＞３など。一方でFalseになるときは５＜３の時など）

```python:if.py
a=1
b=3
if a>2 : #条件式が満たされない
   print("a")
if b>2 : #条件式が満たさる
   print("b")
>>>b
```

#elif文
上記のようにif文だけで条件を分岐することは可能であるが、
例えば、Aかどうか、AでないならBなのか、それ以外なのか
といった場合に、上のif文のみで記述すると以下になる。

```python:if.py
m=3
if m==A : # mがAであるかどうか
   print("a")
if m!=A and m==B: # mがAでなく、mがBであるか
   print("b")
if m!=A and m!=B: # mがAでなく、mがBでもない
   print("c")
```
ただ、この条件分岐は一番最初にAかどうかで判断してるにもかかわらず、
次の条件式にもAでないという事の条件が入ってくる。（二度手間）

これを改善するのが**elif**である。
**elif**はifとセットで使われる。**決してelif単体で使用されることはない。**
**ifではじかれた条件に対して次の条件を適用する**のが、elifである。

elifは一つのifに対して複数回記述することが出来るが、あるところで条件を満たした場合
それ以降のelif文(else文も含めて)は評価されない。

**記述方法はelif 条件式 :である**

```python:if.py
m=3
if m==A : # mがAであるかどうか
   print("a")
elif m==B: # mがAでなく、mがBであるか
   print("b")
elif m!=B: # mがAでなく、mがBでもない
   print("c")
```
#else文
先の例で、最後の判定を考える。
最後の判定はAでもBでもない場合に出力される。
要するに、すべての条件の外にある＝その他の場合に出力される結果と考えることが出来る。

このような、ある条件を満たさないもの全てに対して処理を行いたい場合に**else**を使う。
**記述方法はelif :である。**

先の例をこれを使って書き換えると以下になる。

```python:if.py
m=3
if m==A : # mがAであるかどうか
   print("a")
elif m==B: # mがAでなく、mがBであるか
   print("b")
else: # mがAでなく、mがBでもない → その他の場合
   print("c")
```
メモ　VB.Netの勉強で役に立ったサイト２

https://ameblo.jp/tetsuya-staff/entry-10157130800.html

http://rucio.a.la9.jp/main/VBdotNet/Database/Database4.html

http://masa49406.blogspot.com/2013/11/vbnetdatatable.html

https://qiita.com/nskydiving/items/c9c47c1e48ea365f8995

https://teratail.com/questions/31726

https://qiita.com/MakotoIshikawa/items/298d748d6dc43d441fb7

https://qiita.com/akabei/items/00123fdcf8c2d01290dd

http://yan-note.blogspot.com/2008/12/datatable_17.html
Volto をディプロイする


# 注意

このドキュメントは記載途中です。テスト・検証前のドキュメントのみを見て書いています。

# 前提

- Plone 5.2 on Python 3
- plone.restapi 最新版
- Volto 4 (alpha)
- pm2 でディプロイ


# Ploneのセットアップ

ここでは詳しく書きません。必要な項目のみを記載

## Ploneインスタンス

Ploneインスタンスを作る (id: `Plone` とする方が良いかな？)

## plone.restapi

- インストールバージョン Version 5.0.2 以降(なるべく最新版がいい)
- アドオン(add-on) でplone.restapiで有効化

## nginxの設定

TBD


# Node環境の設定


## NVM

lts/erbium をインストール

```
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
$ nvm install --lts  
$ nvm use lts/erbium
```

## yarn

```
$ curl -o- -L https://yarnpkg.com/install.sh | bash
```

## enable nvvm and yarn

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

# Voltoのbuild

## パッケージを取得

独自のレポジトリから、Voltoのアプリをgit cloneする

## build

```
$ nvm use lts/erbium
$ yarn
$ yarn build
```

参考: https://github.com/plone/volto-starter-kit

# pm2で動作


参考: https://github.com/plone/volto/blob/deployment-docs/docs/source/07-deploying/02-pm2.md
参考2: https://community.plone.org/t/volto-deployment-options/7458/8

## server.config.json

```server.config.json
module.exports = {
  apps: [
      {
        script: './build/server.js',
        "env": {
            NODE_ENV: 'production',
        },
        name: 'volto',
        cwd: './',

      },
      {
        script: '/srv/plone/zinstance/bin/instance',
        args: 'console',
        name: 'plone-api',
        cwd: '/srv/plone/zinstance',
        interpreter: '/srv/plone/zinstance/bin/python',
      },
  ],
};
```

- 20200307 `NODE_ENV` を追加(pm2で実行時にstyled-componentが新しいclassを付けるのを防ぐ)



## pm2インストール

```
$ npm install -g pm2
```

## pm2起動

```
$ pm2 start server.config.js
```

## 環境変数(env)

`.env` ファイルを作成

```.env
RAZZLE_API_PATH=http://PLONE_HOST/api
```

## 環境変数の有効化

```
$ yarn build
$ pm2 restart all
```
MAMP PROが高いので、Local by Flywheelを使うことになったので、Local by Flywheelのメリットを調べて見た

#本当はMAMP PROを使う予定だったけれど予定変更!

MAMP freeは過去に少しだけ触ったことがあるので、「んじゃ今回はMAMP PROを使おうか。」となったけれど、値段が高い高い。ちょっとしか使わないだろうにあんなにするとは驚きでした。

そんなこんなで無料でいいのがある！とオススメされたのが今回のタイトルにもなった**Local by Flywheel**

##だだっとLocal by Flywheelを使うメリットをあげていく

1.Local by Flywheel MAMPと違い、サイトを二つ作れたりする。
私はとりあえず二つ作って見たけれど、まだ欄が空いてるのでもっと作れたりすると思う。

2.UIがわかりやすい。
適当にこのボタンで動くんじゃないか予測で動いてくれる優れもの。

3.SSH接続が簡単にできる。

4.とにかく説明書（ググったやつ）されているように、それの通り操作すれば動かせる。

5.超初心者も使いやすい。

6.PHPのバージョンが見られる。MAMP FREEプランでは見られなかった(気がする)。

7.Webサーバーの種類（nginxかApacheを選べます）

8.MySQLのバージョンが見られる

9.live link enableを押すだけでngrokが起動する！！楽。
オフにしたいときはまたボタンを押せばいい。

![スクリーンショット 2020-01-08 16.30.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524422/ee777f6b-b93e-f521-b0a9-0a85ed16ca07.png)


10.adminを押すと、ワードプレスのログインページに飛んでくれる。
いつもログインページがなかなか探し出せないので、とってもありがたい。





参考にしたサイト
https://www.vektor-inc.co.jp/post/local-by-flywheel/
https://qiita.com/mitixx/items/245674893bd649fee697
https://localbyflywheel.com/