OmniAICreator/Qiita-1.07M huggingface dataset:
docker-compose.ymlで相対パスを使いたい & 日本語環境postgresコンテナのメモ

# ここに書いていること
プロジェクトのディレクトリ内にボリュームディレクトリを作りたかった
=> でも名前付きvolumeの宣言で相対パスって記述できるの・・・？
=> **docker-composeでも$PWDが使える！**

# 環境
- MacOS Mojave version 10.14.6
- Docker version 19.03.2
- docker-compose version 1.24.1

# 相対パスを使いたい
まず ./ で動くかなと試してみました。

```yaml:docker-compose.yml
volumes:
  pg-volume:
    driver_opts:
      type: none
      device: ./docker/postgres/data
      o: bind
```
docker-compose up -d したら案の定ERROR


```bash

Creating postgresql_6543 ... error

ERROR: for postgresql_6543  Cannot create container for service postgresql: 
failed to mount local volume: mount ./docker/postgres/data:/var/lib/docker/volumes/blog_pg-volume/_data, 
flags: 0x1000: no such file or directory

ERROR: for postgresql  Cannot create container for service postgresql: 
failed to mount local volume: mount ./docker/postgres/data:/var/lib/docker/volumes/blog_pg-volume/_data, 
flags: 0x1000: no such file or directory
```


#$PWD = カレントディレクトリ
調べてみると、docker-composeのファイル内でも$PWDが解釈されるようです。
言うまでもありませんが、$PWDはカレントディレクトリです。
環境を共有しやすいのがdockerの大きな利点の一つなのに、絶対パスは書きたくないですよね。  

例えば /home/myname/app がgitで管理しているアプリケーションのディレクトリの場合

```yaml
      device: /home/myname/app/docker/postgres/data # これを
      device: $PWD/docker/postgres/data             # こうしておく
```

これでgit clone後、 docker-compose up -d を叩くだけで良くなりました。
ちなみにWindowsやWSLでは動かないようです。。。:cry:(そりゃそうか)

# Dockerfile
メモも兼ねて書いておきます。

```dockerfile:./docker/postgres/Dockerfile

FROM postgres:10.5
RUN localedef -i ja_JP -c -f UTF-8 -A /usr/share/locale/locale.alias ja_JP.UTF-8
```

```yaml:docker-compose.yml

version: "3"

services:
  postgresql:
    build:
      context: .
      dockerfile: ./docker/postgres/
    container_name: postgresql_6543
    ports:
      - 6543:5432
    volumes:
      - ./docker/postgres/init:/docker-entrypoint-initdb.d
      - pg-volume:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: root
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
      LANG: ja_JP.utf8
    hostname: postgres
    restart: always
    user: root

volumes:
  pg-volume:
    driver_opts:
      type: none
      device: $PWD/docker/postgres/data
      o: bind
```
mac Rails6 アプリ作成時エラーとサーバスタート時のエラーまとめ

# 目的

- 筆者が最近Rails6の環境構築で詰まった部分をまとめる。

# エラー内容

```
Traceback (most recent call last):
        3: from bin/rails:8:in `<main>'
        2: from bin/rails:8:in `require_relative'
        1: from /Users/admin/Documents/study/ruby_on_rails/org/aquariumPlanning/config/boot.rb:4:in `<top (required)>'
/Users/admin/Documents/study/ruby_on_rails/org/aquariumPlanning/config/boot.rb:4:in `require': cannot load such file -- bootsnap/setup (LoadError)
```

# コマンド$rails serverで前述のエラーが出たら？

### 解決方法

- 下記コマンドを実行

```terminal
$ brew install yarn
$ bundle exec rails webpacker:install
$ rails server
```

# コマンド$rails newで前述のエラーが出たら？

- コマンド`$ bundle exec rails new アプリ名`や`$ rails new アプリ名`などで前述のエラーが出る可能性あり。

### 解決方法

- 下記コマンドを実行

```terminal
$ cd アプリ名
$ brew install yarn
$ bundle exec rails webpacker:install
$ rails server
```
お名前.comで管理してるドメインをConoHaのVPSに設定する手順

題名の通り
お名前.comで管理してるドメインを
ConoHaのVPSに設定する手順です。

## お名前.com側の設定
1.お名前.comにログイン後、ドメイン一覧から対象のドメイン詳細を開く
2.ネームサーバー情報の「変更する」ボタンを押す
![スクリーンショット 2019-10-31 00.25.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258211/b7f35ddb-d4e0-3359-5acb-c9ee880a4113.png)
3.「その他のネームサーバーを利用」を選択
![スクリーンショット 2019-10-31 00.27.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258211/0949e76b-a26e-f548-33f7-9ade2fbacfb2.png)
4.いったんこの状態で開いたままにし、ConoHaの設定画面に移動する

## ConoHa側の設定
1.ConoHaのVPSにログイン後、左のメニューからDNSを選択
![スクリーンショット 2019-10-31 00.31.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258211/35ff235b-3df0-c462-2a03-bc702058cd7e.png)
2.お名前.comで取得したドメイン名を追加し、保存する
![スクリーンショット 2019-10-31 00.31.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258211/c5ce88c8-83cd-c00a-9e7c-b1b4998e3a86.png)
3.作成したドメインを開き下記のレコードを追加し、保存する

| タイプ | 名称 | TTL | 値 |
|:--|:--|:--|:--|
| A(通常) | @ | 3600 | 対象サーバーのIPアドレス |
| A(通常) | www | 3600 | 対象サーバーのIPアドレス |

対象サーバーのIPアドレスは対象のVPSのネットワーク情報に記載されています。

4.タイプNSの値をコピーし、お名前.com側の設定に戻り、1プライマリネームサーバーにペーストし、保存。

下記のような感じになると思います。
![スクリーンショット 2019-10-31 00.42.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258211/6f9bf207-9f08-edd9-71be-8f42837ab2fc.png)


以上で設定完了です😄
伝播に時間がかかることがあるようなので気長に待ちましょう！(だいたい30分〜1時間程度で使えるようになる印象です)
draw.ioの全てのタブを一括で画像出力する

![thumbnail](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135313/73dd70dd-f1da-0f5c-115e-2631c357d387.jpeg)

# はじめに

最近、[draw.io](https://about.draw.io/)という無料で使える強力な描画ツールを使ってフローチャートばかり書いている筆者です。 

draw.ioで規模の大きいグラフを描いていると複数のタブに分ける場合があります。現時点(2019/10/30)では、全てのタブの図形を一発で画像出力する機能はdraw.ioには用意されていません。そこで今回はできるだけ自動で楽に画像出力できるよう、少し工夫してみたのでまとめます。

# 問題点

上でも述べたように、 **draw.ioでは全てのタブをまとめて画像出力する機能がありません。各タブに対して、画像エクスポートの処理をする必要があります。**

自分の場合、担当するシステムの処理をフローチャートに起こしていたらいつの間にかタブが40個を超えました。

![ 2019-10-30 15.24.29_filtered.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135313/b1a92868-2a6a-4885-dd4c-50e010d83c9b.jpeg)
![ 2019-10-30 15.24.39_filtered.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135313/5761f2a3-ab71-2a50-9235-284b9fd74439.jpeg)


**1つ1つのタブに対して画像エクスポートをやっていたら非常に手間です**。出力フォーマットがPDFの場合のみ全てのタブを1つのPDFに出力できますが、図が1ページのサイズを超える場合は問答無用で分割されてしまいます。

そもそも「1つのタブの中で図を描画すればいいのでは？」という意見もあるかともいます。ただしそれだと図の規模が大きくなるにつれ、見にくかったり、編集がしずらくなるデメリットがありました。あとdraw.ioにはリンク機能があり、ブロックとタブを紐付けてジャンプすることが可能です。そのため処理を大まかにタブで分けても、処理フローをジャンプしながら追うことができます。

# 解決策

Mac版の**draw.ioデスクトップアプリに含まれるコマンドラインツールとシェルスクリプトを組み合わせました**。

コマンドラインツールの使い方は以下のドキュメントにまとめられています。
<https://j2r2b.github.io/2019/08/06/drawio-cli.html>

複数のdrawioファイルに対してエクスポート処理できる機能や、出力先やレイアウトのオプションも用意されています。

あとはこのコマンドラインツールを使い、シェルスクリプトで全てのタブに対して画像エクスポートする繰り返し処理を実装しました。以下のコードは即席で作ったものなのであくまでも参考程度に。

```bash:export-all-tabs.sh
#!/bin/bash
# 
# 2019/10/30
# Haruyuki Ichino <mail@icchi.me>
# Version 0.0.1
#
# Description:
# Export all tabs for draw.io
#
# Usage:
#   $ export-all-tabs.sh <draw.io file>
#   Example) $ export-all-tabs.sh ./example.drawio
#
# Ref:
# https://j2r2b.github.io/2019/08/06/drawio-cli.html


############################################################
# consts
############################################################
# files
DRAWIO_BIN="/Applications/draw.io.app/Contents/MacOS/draw.io"
DRAWIO_FILE=$1
OUTPUT_DIR="./output"
# options
FORMAT="png"
MARGIN=32
IDX_START=0
IDX_END=40

############################################################
# main
############################################################
# check input/output
if [ ! -e $OUTPUT_DIR ]; then
    mkdir $OUTPUT_DIR
    echo "Created output directory"
fi

# input filename
INPUT_FILENAME=$(basename $DRAWIO_FILE)
INPUT_FILENAME=${INPUT_FILENAME%.*} # remove ext

for ((i=$IDX_START; i <= $IDX_END; i++)); do
  # echo $INPUT_FILENAME
  OUTPUT=$OUTPUT_DIR"/"$INPUT_FILENAME"_tab"$i"."$FORMAT
  echo $OUTPUT

  # export command
  $DRAWIO_BIN -x -f $FORMAT -o $OUTPUT -p $i -b $MARGIN $DRAWIO_FILE
done
```

出力するタブのインデックス(または個数)を指定し以下のような感じでスクリプトを実行すると、出力ディレクトリに各タブのpng画像が出力されます。

```bash
$ bash ./export-all-tabs.sh <draw.io file>
```

# まとめ

* 現時点では、`drawio`ファイルに含まれる全てのタブの図を一括で画像にエクスポートできない
* Macのdraw.ioのクライアントアプリにはコマンドラインツールが内包されている
* それとシェルスクリプトを使って、`drawio`ファイルに含まれる全てのタブを画像に一括エクスポートできた
draw.ioは神
エンジニアスタンプラリー～フロントエンド編＃15

## 企画主旨
[Frontend Developer Roadmap](https://roadmap.sh/frontend)をひたすら巡回する企画 
詳しくは[こちら](https://qiita.com/tonchan1216/items/8d5f072cf769dfe1bc4f)

## 今回の実施内容
デスクトップアプリ

## Desktop Applications

#### Electron
[ようこそ！Electron入門](https://qiita.com/umamichi/items/6ce4f46c1458e89c4cfc)を参考にさせていただいた。
main.jsの参照先として、いままでReactをビルドしたファイル([v12](https://github.com/tonchan1216/WDR-frontend/tree/v12))を指定する。

```javascript:main.js
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;
app.on('ready', () => {
  mainWindow = new BrowserWindow({width: 1280, height: 720});
  mainWindow.loadURL('file://' + __dirname + '/dist/index.html');

  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});
```


## 成果物
意外と簡単！！
https://github.com/tonchan1216/WDR-frontend/tree/v15
Typescript:  X is Declared, But Never Usedの解決方法メモ

## X is Declared, But Never Usedというエラーが出ることがある。

以下のような例だ。

```ts
export const onChange = (val: string, index: number) => {  
  index + 1
}

// val is Declared, But Never Used
```

## 回避するには、変数の代わりに空のオブジェクトを使えば良い。

```ts
export const onChange = ({}, index: number) => {  
  index + 1
}
```

エラーが消えるはずだ。

この方法は可読性を高めてくれるので、気に入った。
完

参考
https://www.triplet.fi/blog/typescript-getting-rid-of-error-x-is-declared-but-never-used/
楽天証券からお気に入り登録している銘柄の情報をスクレイピングする

はじめまして。この度、初投稿になります。
最近、データ分析や機械学習を学んでいるため、自分で何か課題を設定してデータ収集や分析のスキルを磨こうと思ったので投稿のきっかけです。

普段は放送関係のエンジニアをしているのですが、投資が好きなので株価取得からまずははじめてみました。

## 前提条件
取得したいデータは日本の個別株ですが、無料でデータを提供しているサイトが非常に限られていることと、以下の問題があることから証券会社から取得する方針にしました。

* サービス終了の恐れがある（過去にも普通にありました）
* 欲しい情報を取得出来ない（出来高がないとか）

また、証券会社はログインしないとサービスが利用出来ず、スクレイピング対策も厳しいため、Seleniumでデータを取得する方針にしました。

## Seleniumの実装
### （１）Chromeドライバを使ってサイトにアクセス
webドライバの使い方は他にもたくさん記事があるのでここでは省略します。

```python
import time
from selenium import webdriver
import csv
import datetime

# 仮想ブラウザ起動、URL先のサイトにアクセス
driver = webdriver.Chrome()
driver.get('https://www.rakuten-sec.co.jp/')
time.sleep(1)
```

### （２）楽天証券にログイン
ログインIDとパスワードのフォームにname属性が付与されているので、それを利用してID・パスワードを入力します。ログインはJavaScriptの実行ではなくフォームのsubmitでOKでした。

```python
# ログイン
el = driver.find_element_by_name("loginid")
el.clear()
el.send_keys('****')
el = driver.find_element_by_name("passwd")
el.send_keys('****')
el = driver.find_element_by_name("loginform")
el.submit()
time.sleep(1)
```

## （３）お気に入りページから銘柄情報を取得する
まずはお気に入り銘柄のページまで遷移します。

```python
# お気に入り銘柄ページに遷移
el = driver.find_element_by_id("gmenu_domestic_stock")
el.click()
el = driver.find_element_by_id("jp-stk-top-btn-info-prc-reg-lst")
el.click()
```

お気に入り銘柄ページで初期表示されている１ページ目の株価情報を取得してから、10ページ目までページ遷移しながら各ページの株価情報を取得します。
（データの登録有無に関わらずページ数は10固定です）

```python
# 銘柄情報を取得
dataList = []

pageCount = driver.find_elements_by_class_name("number")
for pn in range(0,len(pageCount)):
    pageElem = driver.find_elements_by_class_name("number")
    pageElem[pn].click()
    # テーブル内容取得
    try:
        tableElem = driver.find_element_by_class_name("tbl-data-01")
        trs = tableElem.find_elements_by_tag_name("tr")

        # ヘッダ行は除いて取得
        for i in range(1,len(trs)):
            tds = trs[i].find_elements_by_tag_name("td")
            line = []
            for j in range(0,len(tds)):
                line.append(tds[j].text)
            dataList.append(line)
    # お気に入り登録がないページはスキップ
    except Exception:
        print("要素が見つかりませんでした")
```
## （４）取得したデータをファイル（tsv）に出力
最後に取得したデータをファイルに出力します。Pythonでコードを組むのがはじめてなので、コードで拙い部分があってもご容赦ください。

```python
# ファイル名で使用する日付情報を取得
now = datetime.datetime.now()
YYYY = str(now.year)
MM = str(now.month)
DD = str(now.day)

# 追加モードでファイルをオープンし、1行ずつ書き込み（下記はタブ区切り）
with open('{}'+YYYY+MM+DD+'-BrandList.csv', 'a') as f:
    writer = csv.writer(f, delimiter='\t')
    writer.writerows(dataList)

# ファイルクローズ
f.close()
```

## 最後に
データを取得する実装は以上で終了です。
取得したデータを溜めて出来高分析（3σを超えた銘柄を検知）したいと思って本処理を用意したのですが、一旦保留して次はIRやtwitterの自然言語処理に挑戦してみようと考えています。
SwiftのURLクラスでファイル名の拡張子を抽出する

Swiftでファイル名の拡張子を抽出する場面があり、Swiftの組み込みクラスを利用して実施したので、そのメモ

# 結論
対象文字列を`URL`クラスの`fileURLWithPath()`メソッドでインスタンス化し、`pathExtension`変数で取り出す
小文字にしたい場合は、`String`の`lowercased()`メソッドを併用する

# 挙動確認
`pathExtension()`は、最後に出てくる"."から後ろを抽出してくれる模様

挙動確認として、正常にパスするテストコードを以下に記載する
解釈する際は、`XCTAssertEqual(getExtension("入力文字列"), "出力文字列")`のように読み替える

```swift
import XCTest
@testable import OpenUrlTest

class OpenUrlTestTests: XCTestCase {

    func testSingleFileName() {
        XCTAssertEqual(getExtension("test-contents.PDF"), "pdf")
        XCTAssertEqual(getExtension("テストコンテンツ.xlsx"), "xlsx")
        XCTAssertEqual(getExtension("テストコンテンツ.PdF.xLsX"), "xlsx")
        XCTAssertEqual(getExtension("test-contents.テスト"), "テスト")
        XCTAssertEqual(getExtension("test-contents"), "")
    }

    func testFileNameWithPath() {
        XCTAssertEqual(getExtension("/var/www/html/test-contents.PDF"), "pdf")
        XCTAssertEqual(getExtension("/var/www/html/テストコンテンツ.xlsx"), "xlsx")
        XCTAssertEqual(getExtension("/var/www/html/テストコンテンツ.PdF.xLsX"), "xlsx")
        XCTAssertEqual(getExtension("/var/www/html/test-contents.テスト"), "テスト")
        XCTAssertEqual(getExtension("/var/www/html/test-contents"), "")
    }

    func testWithParameters() {
        XCTAssertEqual(
            getExtension("/var/www/html/test-contents.pdf?user=hoge&password=fuga#test"),
            "pdf?user=hoge&password=fuga#test"
        )
        XCTAssertEqual(
            getExtension("/var/www/html/test-contents.pdf?user=test.user&password=fuga#test"),
            "user&password=fuga#test"
        )
    }

    private func getExtension(_ filePath: String) -> String {
        let url = URL(fileURLWithPath: filePath)
        let ext = url.pathExtension
        return ext.lowercased()
    }
}
```
AWS/GCP/OCIサービス比較


# AWS、GCP、OCI(Oracle Cloud Infrastructure)の主なサービス比較

|カテゴリ|AWS|GCP|OCI|
|:----|:----|:----|:----|
|リージョン|AZ(アベイラビリティ・ゾーン)|ゾーン|AD(Availability Domain(可用性ドメイン))|
|ネットワークおよびコンテンツ配信|VPC|VPC|VCN(Virtual Cloud Network)|
|ネットワークおよびコンテンツ配信|ELB(Elastic Load Balancing)	|Cloud Load Balancing|Load Balancing|
|ネットワークおよびコンテンツ配信|DX(Direct Connect)|Cloud Interconnect|FastConnect|
|ネットワークおよびコンテンツ配信|サブネット|サブネット|サブネット|
|ネットワークおよびコンテンツ配信|ルートテーブル|ルート|ルートテーブル|
|ネットワークおよびコンテンツ配信|IGW(Internet Gateway)|IGW(Internet Gateway)|IGW(Internet Gateway)|
|ネットワークおよびコンテンツ配信|VGW(Virtual Private Gateway)|Cloud Router、VPN Gateway|DRG(Dynamic Routing Gateway)|
|ネットワークおよびコンテンツ配信|CloudFront|Cloud CDN|-|
|Compute|EC2|Compute Engine|Virtual Machines|
|Compute|EC2(I3.metal)|-|Bare Metal|
|Compute|EC2(P2、P3、G3インスタンス)|Google GPU|GPU|
|Compute|ECS(Elastic Compute Cloud Container Service)|Kubernetes Engine|Container Engine for Kubernetes|
|Compute|ECR(EC2 Container Registry)|Container Registry|Container Registry|
|Compute|Lambda|Cloud Functions|Oracle Functions (準備中)|
|ストレージ|EBS(Elastic Block Store)|Compute Engine永続ディスク|Block Volumes|
|ストレージ|EFS(Elastic File System)|ZFS / Avere、Cloud Filestore (ベータ)|File Storage|
|ストレージ|S3|Cloud Storage、Cloud Storage Nearline|Object Storage|
|ストレージ|Glacier|Cloud Storage Coldline|アーカイブ・ストレージ|
|ストレージ|Import/Export Disk、Import/Export Snowball、Import/Export Snowmobile|Transfer Appliance、Transfer Service|Data Transfer Service|
|ストレージ|Storage Gateway|ZFS / Avere|Storage Gateway|
|セキュリティ、アイデンティティおよびコンプライアンス|IAM、AWS Organizations|IAM(Cloud Identity & Access Management)|IAM(Identity and Access Management)|
|セキュリティ、アイデンティティおよびコンプライアンス|KMS(Key Management Service)|KMS(Cloud Key Management Service)|KMS(Key Management Service)|
|セキュリティ、アイデンティティおよびコンプライアンス|CloudTrail|Cloud Audit Logging|Audit|
|セキュリティ、アイデンティティおよびコンプライアンス|SG(セキュリティグループ)、NACL(ネットワークACL)|ファイヤーウォールルール|セキュリティリスト、ネットワーク・セキュリティ・グループ|
|Database|RDS|Cloud SQL (MySQL、Postgres)、Cloud Spanner|Database Cloud Service|
|Database|Aurora|Cloud SQL、Cloud Spanner|Autonomous Transaction Processing|
|Database| Redshift|BQ(BigQuery)|Autonomous Data Warehouse|
|Database| DynamoDB|Cloud Datastore、Cloud Bigtable|NoSQL|
|エッジ|Route53|Cloud DNS|DNS|
|エッジ|SES|-|Email Delivery|
|エッジ|WAF(Web Application Firewall)|-|WAF(Web Application Firewall)|
|エッジ| Shield|Cloud Armor|DDoS Protection|

# 参考
[Oracle Cloud Infrastructure Serviceマッピング](https://cloud.oracle.com/ja_JP/iaas/cloud-service-mapping)
[AWS プロフェッショナルのための Google Cloud Platform](https://cloud.google.com/docs/compare/aws/?hl=ja)
ABC 087 B - Coins 解説

# はじめに
https://atcoder.jp/contests/abc087/tasks/
の提出済みの優秀な方(kyunaさん)のコードを解説。

# 問題
**【問題概要】**
500 円玉を $A$ 枚、100 円玉を $B$ 枚、50 円玉を $C$ 枚持っています。これらの硬貨の中から何枚かを選び、合計金額をちょうど $X$ 円にする方法は何通りあるでしょうか？

**【制約】**

+ $0 \le A, B, C \le 50$
+ $A + B + C \ge 1$
+ $50 \le X \le 20000$
+ $A, B, C$ は整数である
+ $X$ は $50$ の倍数である

**【数値例】**
1)
　$A = 2$
　$B = 2$
　$C = 2$
　$X = 100$
　答え: $2$

条件を満たす選び方は以下の 2 通りです。

+ 500 円玉を 0 枚、100 円玉を 1 枚、50 円玉を 0 枚選ぶ
+ 500 円玉を 0 枚、100 円玉を 0 枚、50 円玉を 2 枚選ぶ

# 完成コード
お手本として、kyunaさんのコードがコチラ

```python
a,b,c,x=map(int,open(0))
print(sum(500*i+100*j+50*k==x for i in range(a+1)for j in range(b+1)for k in range(c+1)))
```

一方、自分が最初に書いたコードがコチラ。ちょっと恥ずかしい。。。
愚直な感じで書き起こしました感が出てる。

```python
a = int(input())
b = int(input())
c = int(input())
x = int(input())
count = 0

for i in range(a+1):
  for j in range(b+1):
    for k in range(c+1):
      if i*500 + j*100 + k*50 == x:
        count+=1

print(count)
```

# メモ
見た目がだいぶ異なるけど、やってることは同じことに気付く。
自分が書いたのは単純にfor文入れ子で書いてるのに対して、お手本は「リスト内包表記」を使っているという違いがもっと大きな違い。

お手本は不要なインデントや改行や省略できるところは極力省いているけど真面目にそれらを付け加えるとこんな感じになって少しは読みやすくなる。

```python
a,b,c,x=map(int,open(0))
print(
  sum(
    [500*i+100*j+50*k==x
       for i in range(a+1)
       for j in range(b+1)
       for k in range(c+1)]
   )
)
```
解説を加えるとi, j, kのループを回した際に500*i+100*j+50*kがxになる場合Trueをリストに格納し、そうでなければFalseを格納する。
で、sum()でTrueの数をカウントしてその結果をprint()する。
…といった感じ。

一応実際にリストの中身はどんなのかをみるためにsum()を外したもので実際に試してみるとこんな感じになる

```python
a,b,c,x=map(int,open(0))
print(
    [500*i+100*j+50*k==x
       for i in range(a+1)
       for j in range(b+1)
       for k in range(c+1)]
)
```

　-----
入力
2
2
2
100
の場合
　-----
出力
[False, False, True, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False
とまぁ、こんな感じになる。

内包表記は可読性が下がるので何となく好きになれないけど、AtCoderでは重宝されることはよくわかった。

ちなみに、itertools.productを使えばforのネストを使わずにすむそうで一瞬「それ最高じゃん！」と思ったけど、引数はリスト型に限られるので
今回のケースではうまくはまらないのと、そもそもitertools.productは遅いそうで、それはそれでAtCoderでは歓迎されないようだ。なるほど。ケースバイケースってやつですね。
hyper-v仮想環境下においてWindows updateの際にネットワーク接続が切れるトラブルについて

##概要
hyper-v使用環境下で此度のWindows updateを行ったところゲストOSのWifi接続ができなくなった。備忘録。対処法として外部ネットワーク接続を追加してみたところホストOSまでもがネットワークに接続できなくなった。
##対処法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510676/b1929aaf-233f-58cd-6e71-8a92289295ad.png)
このアダプターのオプションを変更するを選択してネットワークブリッジを削除した。その後もう一度外部ネットワークをつくってやることでホストOS、およびゲストOSともにネットワーク接続を回復することができた。
１つのテーブルの複数のカラムに外部キー制約をかける書き方　Rails 5.2

備忘録のために書きます。
（こんなケースほとんど無いだろうけど）

１つのテーブルの複数のカラムに外部キー制約をかけようとしてReferences を使おうとしたらRake abotedされました。
References を１つだけに絞ると通ったので、add_reference で強引に追加しました。


# エラーがでるパターン
```
class CreateLikes < ActiveRecord::Migration[5.2]
  def change
    create_table :likes do |t|
      t.references :user, foreign_key: true
      t.references :item, foreign_key: true
      t.timestamps
    end
  end
end
```

# 出ないパターン
```
class CreateLikes < ActiveRecord::Migration[5.2]
  def change
    create_table :likes do |t|
      t.references :user, foreign_key: true
      t.timestamps
    end
    add_reference :likes, :item, foreign_key: true
  end
end
```

そもそも外部キーを複数つけるのがあまり良く無いのでは無いだろうか・・・
windows10,MAMPでeccube4ロカール環境構築手順

# ローカル環境
windows10 
MAMP 4.1.1
# MAMPインストール
インストール手順は省きます。 
MAMPのphp初期バージョン(7.3.7)だとなぜかapacheが起動しないので7.2.14に変更（MAMPの設定から可能）

# データベースの用意
apacheが無事起動したらlocalhost/MAMPにアクセスしてTools→phpMyAdminからeccubeで使用するデータベースを作成 
データベース名は任意、文字コードはutf8_general_ci

# eccube4ダウンロード・インストール
ダウンロード手順は省きます。 
ダウンロードしてきたファイルを解凍し解凍したフォルダをMAMPのDocumentRootに設定（MAMPの設定から可能） 
loclhostでアクセスして無事eccubeのインストール画面表示されれば成功 
必須ライブラリの警告がでる場合はphp.iniを編集し必要なライブラリを読み込み 
MAMPのphp.iniは`MAMOROOT/conf/使用しているphpバージョン`の内容が反映される 
intlはシステム環境変数のPATHにMAMPのphpを通さないと読み込まれない`MAMOROOT/bin/php/使用しているphpバージョン`（これで結構はまった...）
警告がなくなれば手順にそって上記で作成したデータベースを設定してインストール

# その他、おまけ
## ログインURLを忘れた場合
.envファイルのECCUBE_ADMIN_ROUTEを確認

## デバックモード
.envファイルの以下の値を変更 
APP_ENV=dev 
→開発時に設定(画面下にSymfonyツールバーが表示される,キャッシュが残さない) 
APP_ENV=prod 
→本番時に設定(キャッシュ等が有効になる) 

APP_DEBUG=1 
→debugモードが有効(エラー発生時に画面上に詳細なログが表示) 
APP_DEBUG=0 
→debugモードが無効(詳細なログは表示されない)
GitHub Actions 上で clang-format を動かして勝手にリファクタリングしてもらう

2020/08/10 actions/checkout@v1 について書きます

# 目的

1. ユーザが master に push する
2. GitHub Actions が反応して、インスタンスが起動
3. clang-format が動いて、リポジトリ上のコードがフォーマットされる
4. GitHub Actions が master に push する

# 手段

## install clang-format

環境は `ubuntu-18.04` を選択したとします。

`sudo apt install clang-format` やるだけに見えるのですが、実際にこれを叩くと、
以下のようなエラーがでて失敗します。

```
 The following packages have unmet dependencies:
 clang-format : Depends: clang-format-6.0 (>= 6.0~) but it is not going to be installed
E: Unable to correct problems, you have held broken packages.
```

なので、`add-apt-repository` で repository を追加する必要があります。
repository は、https://apt.llvm.org/ から見つけることができます。

これで、`clang-format` がインストール出来るようになります。

## clang-format

`clang-format` がインストールされていますので、普段どおりコマンドを叩くだけです。

## git commit

素の状態ではgit等使いにくいので、 `actions/checkout@v1` を使います。
使い方は、`uses: actions/checkout@v1` するだけです。
コミット前に名前とメールアドレスを `git config` で設定することを忘れずに。

## git push

market place に素晴らしいツールがあるので、これを使うだけです。

https://github.com/marketplace/actions/github-push

```yaml
    - name: push
    - uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
```

`secrets.GITHUB_TOKEN` とは、GitHub の機能を使うための鍵のようです。
Issue を立てたり、Pull Request を作ったりするために使います。

https://help.github.com/ja/github/automating-your-workflow-with-github-actions/virtual-environments-for-github-actions

# 成果物

```yaml
name: clang-format

on:
  push:
    branches:
    - master

jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
    - uses: actions/checkout@v1
    - name: install tools
      run: |
        sudo add-apt-repository 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main'
        sudo apt update
        sudo apt install clang-format
        git config --global user.email "octocat@example.com"
        git config --global user.name "octocat"
    - name: refactor
      run: |
        clang-format -i -style=file main.cpp
        git add .
        git commit -m 'refactor by Github Actions'
    - uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
```

# 補足

## actions/checkout@v2 について

上記の成果物は、actions/checkout@v1を使っていましたが、その後、v2が出たようです。

自分のケースでは、`actions/checkout@v2` に token を渡すことで `git push` まで出来てしまいました…[^1]

[^1]: actions/checkout@v2 の README.md の git push サンプルに token が書かれていないのが最大の罠だと思います。また、README.md によると、private repository の場合は、ユーザアカウント設定ページのDeveloper Settings から作成できる personal access token(PAT) を指定する必要があるらしいです。

```yaml
jobs:
  build:
    runs-on: ubuntu-18.04
    steps:
    - uses: actions/checkout@v2
      with:
        token: ${{ secrets.GITHUB_TOKEN }}
    - name: install tools
      run: |
        echo "install"
        git config --global user.email "octocat@example.com"
        git config --global user.name "octocat"
    - name: refactor
      run: |
        echo "refactor"
    - name: push
      run: |
        git push origin
```
Lookerで日付フィルタを設定する場合は、Date型→String型へ変換しよう


Lookerで日付のFILTERを設定しようとしたら、型エラーが出ることがありますのでその場合の対策をメモしておきます。

## 発生イメージ
下図のように、**データ型が異なる為、抽出出来ません**的なエラーメッセージが発生。
![スクリーンショット 2019-10-30 23.06.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/d6694071-ef38-b070-6cf3-e65a58bc2900.png)

## データ型をみて見ると
日付（DATE）型で定義されているので、型をStringに変換しないとダメそう。
![スクリーンショット 2019-10-30 23.12.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/3c4c5f63-95d1-b7e2-233a-6d8a70cb9ecd.png)


## 対策方法(LookMLの修正）
LookMLを開くと、sql部分のコードは以下のように初期設定されている。

```yaml

  dimension_group: Date {
    type: time
    timeframes: [
      raw,
      date,
      week,
      month,
      quarter,
      year
    ]
    convert_tz: no
    datatype: date
    sql: ${TABLE}.Date ;;  ## この部分でCAST（データの型変換）してあげれば行けそう
  }
```


## 修正後
sqlのところにCASTのコードを追加して保存する。

```yaml

  dimension_group: Date {
    type: time
    timeframes: [
      raw,
      date,
      week,
      month,
      quarter,
      year
    ]
    convert_tz: no
    datatype: date
    sql: CAST(${TABLE}.Date AS string) ;;  ## CASTで型変換してString型に
  }
```

## FILTER使えるように
上記手順でデータ型を変換することで、以下のようにFILTER機能が使えるように。

![スクリーンショット 2019-10-30 23.39.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242038/7e4bb562-0674-297b-80af-3ed9ac4533e1.png)

## まとめ
**Looker上で型エラーが出た場合　→　LookMLで型変換すれば大体なんとかなる！**

しかし、型変換の部分はいい感じに自動解釈して変換してくれるとありがたいのですが、その場合、型が異なることでFILTERが誤って変換されるリスクもあるかもしれない。。。と考えると、これはこれで良いのか。と思います。
Flutterの自作ライブラリを作って公開する方法

[loading_text](https://pub.dev/packages/loading_text)なるライブラリを公開したので、そのときに得た知識を残しておきます。

# Flutterライブラリの作成

```sh
$ flutter create --template=package <name>
```

でFlutterライブラリのプロジェクトを作ることができます。
このコマンドで作られるプロジェクトは`lib`のみで、`android`、`ios`などプラットフォーム非依存のdartコードだけ書けます。

```sh
$ flutter create --template=plugin <name>
```

でプラットフォームのコードも書けるようですが、今回は試していません。

# 公開の手順

まずは以下のコマンドでプロジェクトに不備がないかチェックします。

```sh
$ pub publish --dry-run
```

私の環境では、`pubspec.yml`にhomepageとauthorの項目が足りないことで、
怒られました。

修正したら、以下のコマンドで公開です。

```sh
$ pub publish
```

途中、Googleアカウントでログインが求められるので、URLにアクセスしてログインしましょう。
しばらくすると、公開が完了します。

# 注意点

公開したパッケージは削除することはできないみたいです。


> Publishing is forever
Keep in mind that publishing is forever. As soon as you publish your package, users can depend on it. Once they start doing that, removing the package would break theirs. To avoid that, pub strongly discourages deleting packages. You can always upload new versions of your package, but old ones will continue to be available for users that aren’t ready to upgrade yet.

適当翻訳では、「削除できてしまうとそのパッケージを使っているユーザーが困っちゃうから、させないようにしているよ。」です。
バージョンを上げて、上記コマンドを打ち直せば、新しいバージョンをアップロードできますが、古いものも残り続けるようです。

非公開にすべき情報を上げないように注意しましょう。
年末まで毎日webサイトを作り続ける大学生 〜12日目 オブジェクト指向に触れる〜

##はじめに
初めまして。
年末まで毎日webサイトを作っている者です。
今日もMDNを見て勉強していたんですが、とうとう中級編に突入しました。
そして出ましたオブジェクト指向！
扱う技術レベルは低いですが、同じように悩んでる初心者の方を勇気付けられれば幸いです。
今日は12日目。(2019/10/30)
よろしくお願いします。

##サイトURL
https://sin2cos21.github.io/day12.html

##やったこと
テキスト入力欄に名前と趣味を書いたら、内部でオブジェクトを作って反応するようにしました。
作り方だけ学んで実装したので、もしかしたら、オブジェクトの使い方間違っている可能性がありますがご了承ください。

では動作から↓

![test.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/ed3b8253-8b62-2c78-2536-ef521a62602e.gif)

内部はこうなっています↓

```javascript
 <script>
        let createClick = document.getElementById('createHuman');
        createClick.addEventListener('click', createHuman);



        function Person(first, last, interest1, interest2) {
            this.name = {
                first: first,
                last: last
            };
            this.interest = {
                interest1: interest1,
                interest2: interest2
            };
        }


        function createHuman() {
            let lastName = document.forms.form1.lastName.value;
            let firstName = document.forms.form1.firstName.value;
            let interest1 = document.forms.form1.interest1.value;
            let interest2 = document.forms.form1.interest2.value;

            let test22 = new Person(firstName, lastName, interest1, interest2);
            let talk = '私の名前は' + test22.name.last + ' ' + test22.name.first + 'です。趣味は' + test22.interest.interest1 + 'と' + test22.interest.interest2 + 'です。';
            let human = document.getElementById('human');
            human.textContent = talk;
            let myNotification = new Notification('私の名前は' + test22.name.last + ' ' + test22.name.first + 'です。');
            myNotification;
        }

    </script>
```
function Personはコンストラクターです。これを使えば簡単にオブジェクトが生成されます。
ボタンを押したらcreateHumanが実行されます。
使い方間違ってる気しかしない。オブジェクトってこんなんじゃないよな・・・？コメントお待ちしています！

##ちなみに

ちなみに、
> let myNotification = new Notification('私の名前は' + test22.name.last + ' ' + test22.name.first + 'です。');
            myNotification;

この2行でボタンが押されると通知を出すようにしています
組み込みAPIなんですが、newでインスタンスを生成しないと使えない珍しいタイプのものらしいです↓

![スクリーンショット 2019-10-30 23.23.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516248/024ecc71-62ea-67b1-1b72-bbe41ded97a2.png)


##感想
オブジェクト指向・・・。手ごわいだけにマスターすれば一気に効率が上がる予感がする。
目標のオセロアプリを作るためにもここは頑張らなければ。
そしてJavaScriptはまだまだ奥が深いのだろうか・・・？

最後までお読みいただきありがとうございます。
明日も投稿しますのでよろしくお願いします。

##参考
1. JavaScript オブジェクトの基本 - Web 開発を学ぶ | MDN  (https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics)

参考になりました！ありがとうございます！
バッチファイルで競馬をちょっとだけ便利に

最近バッチファイルを職場で書く機会があったので趣味の競馬に利用してみた。

#競馬予想する時皆さんどうしてます？
情報が氾濫する現代。PCで色んなサイトを引っ張て来ては、厩舎情報やら調教やら馬柱だとかとにらめっこする人は少なくないはず。ところで・・・

#毎回見るサイトを開くのめんどくない？
大体使う競馬サイトは決まっているが、複数ある。
これらをいちいちブックマークから持ってくることはめんどくさい。
ワンクリックで、いっぺんに普段予想に使うサイトを開きたい。

#startを使えばOK

メモ帳などのテキストエディタに以下の記述をして、拡張子を.batにして実行するだけ。

```
@echo off

start https://race.netkeiba.com/?rf=navi
start https://www.keibalab.jp/index.html
start http://www.jra.go.jp/
start https://bfkeiba.com/
start https://www.smartrc.jp/v3/
```

startの後ろに開きたいURLを書けばOK
自分はネット競馬・競馬ラボ・JRA・血統フェスティバル・スマート出馬表を必ず開いているので、
これらのURLを貼る。

#終わりに
出来る人たちにとっちゃたわいもない事かもしれないが、
作業の効率化についてより意識するきっかけとなった。
エンジニアなんだから、積極的にラクしよう。
バッチファイル　基礎編　ディレクトリ移動(dir・cd)

#①dir
dirを打てば、カレントディレクトリ内のファイルやフォルダがズラッと表示されます。

カレントディレクトリなんですが、
コマンドプロンプトで
**C:\Users\[username]\Desktop\>**
てな感じで表示されていると思いますが、
**「C:\Users\[username]\Desktop\」**

これが**カレントディレクトリ**です。
現在のディレクトリがここですよってことを示しています。
※[username]の箇所はそれぞれのPC設定によって変わります。

なので、例えば上の状態で「dir」と打ち込んでEnterキーを押すと
Desktopにあるフォルダやファイルがずらーっと出てきます。

#②cd
cdはカレントディレクトリの略です。
なので、「cd」のみ打ち込んでEnterキーを押せば、
カレントディレクトリが表示されます。

例えば、
**C:\Users\[username]\Desktop\>**
と表示されている中、cdコマンドを打てば、当然
**「C:\Users\[username]\Desktop\」**
と表示されます。

だから、カレントディレクトリってどこ？
となった場合は「cd」と打てばわかります。

このcdコマンドですが、
cdの後にパス名を打てば、
そのパスをカレントディレクトリにすることができます。

例えば、Desktopにhogeというフォルダを作成します。
コマンドプロンプトで
「cd C:\Users\[username]\Desktop\hoge」
と打ち込めば、
カレントディレクトリは
「C:\Users\[username]\Desktop\hoge」
に移動します。

ほかにもcdコマンドは

cd ../　→　一つ上のディレクトリに移動
cd \ → ルートディレクトリに移動
cd [パス名] → パスのディレクトリに移動

などできます。
cd .. →　カレントディレクトリの親フォルダ(一つ上のディレクトリ)を表示
がcd ../と似ていてややこしいですが、/なしは表示、/ありは移動で異なります。
macOSでLaravelの環境構築でハマってしまった

使用環境
MacOS Catalina
php Version 7.3.8
composer version 1.9.0
Laravel installer 1.3.3

＜起こった問題＞
composerインストール後
$cd Desktop(デスクトップに移動)
＄laravel new laravelapp(laravelappという名のプロジェクトを作成)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503464/b2f1ef89-3308-4be1-4d3c-10fdffdb7dec.png)
というエラー出現！

composerでLaravelをインストールし、Laravelでプロジェクトを作成しようとするとZIPがありませんとエラーが出る
（PHPのzipの拡張機能をインストールしてくださいということみたい）

＜やったこと＞
zip PHP extensionはComposerではインストールできないためhomebrewでpeclをインストールしpeclをつかってZIPをインストールしようとしたが次はphpize failedのエラーになった
peclでのインストールを諦め
コマンドではインストールできなかったため手動でここでzipをインストールし解凍した。
![スクリーンショット 2019-10-30 21.18.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/503464/8201adab-4026-6af2-472c-aebcda94f1cb.png)

＜分からないこと＞
まず、手動でインストールし解凍したファイルをどこに置いていいのか分からない（zip）
再度コマンドでLaravel new laravelappを作ろうとしたが同じエラーが出てしまいどうしていいか分からなくなりました。

この問題で今日一日潰れています。せっかくLaravel始められると思ったのに導入するのにこんなに大変だとは思っていませんでした。
いい解決方法がないでしょうか。
エンジニアスタンプラリー～フロントエンド編＃14

## 企画主旨
[Frontend Developer Roadmap](https://roadmap.sh/frontend)をひたすら巡回する企画 
詳しくは[こちら](https://qiita.com/tonchan1216/items/8d5f072cf769dfe1bc4f)

## 今回の実施内容
静的サイトジェネレータ(Static Site Generator, SSG)
SSRとごっちゃになるヤツ

## Static Site Generators

#### GatsbyJS
[Quick Start | GatsbyJS](https://www.gatsbyjs.org/docs/quick-start/)を参考にすると、一瞬でひな形が作成される。。。
が、今まで作ってきた構成は失わせたくないので、
[gatsby-starter-mobx](https://www.gatsbyjs.org/starters/borekb/gatsby-starter-mobx/)をベースに作成。

```jsx:index.js
import React from "react"
import { Provider } from 'mobx-react';

import App from '../components/App';
import SkillStore from '../stores/SkillStore';
import '../main.scss';
import 'bootstrap/dist/css/bootstrap.min.css';

const store = new SkillStore();

const IndexPage = () => (
  <Provider store={store}>
    <App />
  </Provider>
)

export default IndexPage
```


## 成果物
結局静的サイトとは何だったのか。
https://github.com/tonchan1216/WDR-frontend/tree/v14
グラフデータベース 入門


## 初めに
とあるインターンでグラフデータベースを触ったのでシェアしたいなと思います。

私自身、SQLが少し書けるくらいでグラフデータベースは愚か、データベース自体ちゃんと触った事がありませんでした。しかし、グラフデータベースは直感的でわかりやすく、比較的短い時間で実装まで移ることができました。

## グラフデータベースってなに？
関係性を表すことができるNoSQLなデータベース。
SNSの「知り合いかも？」やECサイトの「おすすめ」など、レコメンデーション機能に適している。

####メリットとデメリット
繋がりを表すのがめちゃくちゃ速い。

例えば、「Aさんの友達の友達の友達」を知りたい場合。一見シンプルそうだが、SQLなデータベースだと結構しんどいのが想像できると思います。

一方で、データ全体の統計分析などは苦手。


####構成要素
グラフデータベースはノード、エッジ、プロパティの三つから構成されます。ノードのことを頂点、エッジのことを端なんて呼んだりします。

下記の図にて解説します。

<img width="544" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401901/5a3ab77f-297a-dc86-bd3a-756c8a0a7469.png">

ここではノードであるUser同士がFriendというエッジにより結ばれています。エッジはグラフデータベースの最も重要な要素であり、これがあることでノード同士の**関係性**が表せます。

また、プロパティとしてそれぞれの情報を追加する事ができます。例えば、年齢や日付などなど。プロパティはノードのみならず、エッジにも同様に追加する事が可能です。


## 最後に
今後、実装の仕方やQueryの書き方なども追加していけたらと思ってます。
間違いや分かりづらいところなどがありましたら、ご教授ください。
別サーバーのApache設定を移行してきたらsystemctlが戻ってこない

# 遭遇した事象

- CentOS 6 から 7 へのサーバー引っ越し作業
- CentOS 7 に yum で httpd をインストール (httpd-2.4.6)
- この時点でsystemctlでの起動・停止は確認
- 古いサーバーで動いていたApacheの設定一式 (conf, conf.d, conf.modules.d) を /etc/httpd 以下に置き換え。 元々あったディレクトリは `.org` をつけてリネーム
- `/usr/sbin/apachectl configtest` で設定に問題が起こらなくなるようにコンテンツ配置
- 再度 `systemctl restart httpd` を実行するが、このコマンドが戻ってこず、タイムアウトして正常に起動しない
- `/usr/sbin/apachectl` で動作を確認した場合は正常に動く

# 理由

結論だけ述べると `00-systemd.conf` というファイルを `conf.modules.d` に戻してやると正常に動作しました。
その後、この事象を元に検索するとまさにコレという説明記事を見つけることができました。

[CentOS 7 で自分でビルドした apache を使うと systemctl start が戻ってこない](https://blog.cles.jp/item/9413) 


上記記事で説明されている通り、移行元の `conf.modules.d` に `00-systemd.conf` がなく、systemd 用に用意されたモジュール `mod_systemd.so` が読み込まれていないので systemd が httpd 完了の通知を受け取ることができず、タイムアウトエラーとなっていました。 


# おわりに

systemd がない環境から systemd での管理に移る場合、systemd 特有の事情がある（拡張さえある）という事を頭に入れておくべきと学びました。
2019年 #HTML #PDF 変換の情勢とは？ ( phantomjs -> wkhtmlpdf -> headless Chrome + #node + puppeteer )

https://www.paperplane.app/blog/modern-html-to-pdf-conversion-2019/

# 古い手法とは

PhantomJSのかわりにwkhtmltopdfが重宝されてきたけどモダンブラウザの仕組み、 HTML5やjsに対応しきれてないよーって書かれてる気がする。

>The traditional approaches
>Until 2017, there were two common ways to convert HTML to PDF. The first was to use wkhtmltopdf — an open source command line tool specifically designed for the task. A second alternative was PhantomJS, an open source “headless” web browser which can be controlled with JavaScript.

>Although these tools have served many people extremely well, they do have some downsides. Support for the latest HTML5 and JavaScript features lags a long way behind the modern browsers we’re used to such as Chrome, Firefox or Safari.

# Chrome を直接利用する

凝ったことをやろうとすると、色々大変だよって書いてるような気がする。

>Using the Chrome devtools API
>If you’d like to use Chrome directly yourself, you can get started by using the “print-to-pdf” command line option, but for more control over the PDF you’ll need to communicate with Chrome’s devtools API.

# Puppeteer

Chrome / chromium と dev-tool を上手に使うための仕組み、 node の  Puppeteer が良さげって書かれているような気がする。

>Controlling Chrome with Puppeteer

>You could use Puppeteer to automate a Headless Chrome browser instance in almost any way. Here we’ll just be focusing on how it can be used to create PDFs.

# Google cloud function

サーバーレスで使う方法があるらしい。

>Using Puppeteer via Google Cloud Functions
>One interesting new option is the ability to run headless Chrome on Google Cloud’s “serverless” platform — Cloud Functions. This feature was added to Cloud Functions in August 2018 and should provide a low-cost and highly scalable way of generating PDFs. Google’s announcement post has a good walk-through that explains how to set it all up.

# 比較

headless Chrome がエクセレント！

![image](https://user-images.githubusercontent.com/13635059/67850145-24cc5280-fb4b-11e9-8b3f-80bc5772a579.png)

typesettingってなんだろうな

# 参考

強い！

>仕組み
>puppeteerは、WebdriverIOのようなクロスブラウザ対応のツールとは異なり、Chrome DevTools Protocol2 を利用してNode.jsからChromeの開発者ツールへ接続して操作を行います。

>puppeteerがこれらのライブラリと一線を画すのは、なんと言っても本家ChromeのDevTool開発チームが作成・メンテナンスしている、という点でしょう。

[--headless時代の本命？ Chrome を Node.jsから操作するライブラリ puppeteer について - Qiita](https://qiita.com/Quramy/items/26058e83e898ec2ec078)

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2642








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
エックスサーバーで運用するLaravelからメール送信の後、バウンスメールを確認する

# PHPでバウンスチェックなんて出来る訳ない？？
困るんです。受信ボックスで1件1件確認して、不着のメールを確認して、除外するなんてやってられない。

PHPであれ、Laravelであれ、メール送信した後に、リターンメールでエラーでメールが戻ってきたら、確認する方法はありますか？？

→無い！

そんな事が沢山のQ&Aで書かれてますが、エックスサーバーに限っては、メールのディレクトリを知っていればできるでしょう。

Laravelをエックスサーバーで使っている方、いるんじゃないですしょうか。

# エックスサーバーのメールはどうなっている？
/home/あなたのエックスサーバーID/ドメイン
フォルダをFTPなりで見てみてください。
/mailというフォルダあります。

サーバパネルで、メールアドレスを作成すると、mailフォルダの中に作成したメールアドレスのフォルダが構成されます。
/mail/ドメイン名/メールアドレス/

何かそのアドレスにメールを送ってみてください。
/mail/ドメイン名/メールアドレス/cur にメールのファイルが入ります。
中身はテキストデータです。

#どうやって、リターンメールをハックする？
こうです。
ユーザーテーブルに、以下があるとします。
id | email | name | password | error

そして、チェックする機能を作っておき、使う時に呼び出せば良いです。
このコードの場合は、リターンメールを見つけたら、errorフラグをerrorカラムにいれていきます。
errorコードは、db内を初期化してから、入れています。

コードの流れは、指定のメールのディレクトリにあるメールから、エラーメールを見つけて、アドレスを探し、dbに有るメールアドレスと一致したら、エラーフラグを入れるというものです。バウンスメールを受信するアドレスを専用に作っておけば、処理は重くならないでしょう。

    public function checkErrorMail(){
        //メール確認
        $Users = User::all();
        if(count($Users)>0){
            foreach ($Users as $User){
                $User->error = '';
                $User->save();
            }
        }
        $mailPath = '/home/xxxx/ドメイン名/mail/ドメイン名/example@yourdomain.jp/cur/*';
        foreach(glob($mailPath) as $filePath){
            if(is_file($filePath)){
                $Undelivered = false;
                $fp = fopen($filePath, "r");
                if($fp){
                    while (!feof($fp)){
                        $string = fgets($fp);
                        if(strpos($string,'Undelivered') !== false){
                            //'Undelivered'が含まれている場合
                            $Undelivered = true;
                        }
                        if($Undelivered){
                            if(strpos($string,'Original-Recipient') !== false){
                                //'Original-Recipient'が含まれている場合、メールアドレスを取得
                                if(preg_match_all("/(\w+[-+\w.]+@[-\w.]+\.\w{2,5})/",$string,$addr)){
                                    $addr=array_unique($addr[0],SORT_STRING);
                                    $Users = User::where('email', $addr[0])->get();
                                    if(count($Users)>0){
                                        foreach ($Users as $User){
                                            $User->error = 'Error';
                                            $User->save();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                /* ファイルポインタをクローズ */
                fclose($fp);
            }
        }
        return back();
    }

こんな感じで、あかんメールアドレスを探し当てて、処理していけば良いかと思います。
メールボックスが大量になる場合は、ファイル名を管理して、処理する対象を限定するなど、
工夫していけば良いですよ。


#おわり
エックスサーバーでバウンスメールを処理したいです。できませんか？
→これなら、できますよね！

あくまで、参考の実装方法ですので、サーバに負荷をかけすぎて、迷惑がかからないように、用途に応じて、設計をしっかり考えて、ちゃんと実装しましょうね。
それでは、ゴキゲンヨー。
コマンドプロンプトからfirewallのオン・オフ、状態の確認をする

コマンドプロンプトからfirewallを操作

firewallのステータスを確認する

```
netsh advfirewall show allprofiles state
```

firewallの設定をすべてオフにする

```
netsh advfirewall set allprofiles state off
```

firewallの設定をすべてオンにする

```
netsh advfirewall set allprofiles state on
```
自分用


```css:
&copy: //文字実体参照//
&#169: //数字実体参照//
```

```css:
@import url('https://fonts.googleapis.com/css?family=Sriracha&display=swap');
```
//Googleフォントから好みのフォントを選べる。ウェブフォントを使うと、表現が豊かになる代わりに、重くなるデメリットがある。使いたい場所を決めて使う。//

複数のデバイスに合わせたレイアウトを作る
RWD(レスポンシブWebデザイン)

```css:
@media only screen and (条件)
```
//メディアクエリー//

```html:
<a href="#"><img src=…</a>
```
//イメージにリンクを貼れる。#はダミーリンク//

```css:
クラス名 img:hover ｛
           Opacity: .5
       ｝
```
//画像にカーソルを合わせると白くなる(リンクが貼られてると分かる)。opacityとは透明度//

```css:
transition-property: opacity;
//アニメーションを実行する対象のプロパティを設定する//
    transition-duration: 1s;
//アニメーションを何秒かけて行うか設定する//
transition-timing-function: ease;
//アニメーションに演出をかける//
transition-delay: 0s;
//何秒かけて遅らせるか設定する//
```

```css:
transition--function: ease;
transition-timing-function: linear;
transition-timing-function: ease-in;
transition-timing-function: ease-out;
transition-timing-function: ease-in-out;
```
//この５つが使える、専門的な知識が必要//
Codewars の Reversing a Process を Kotlin で解いてみた

[Reversing a Process](https://www.codewars.com/kata/5dad6e5264e25a001918a1fc)

記事「[文字⇔数字を扱う](https://qiita.com/A_SAK/items/7d8e104b1ea5baf6caf5)」で面白そうだったので、Kotlin で解いてみた。

```Kotlin
private const val IMPOSSIBLE_TO_DECODE = "Impossible to decode"

fun decode(r: String): String {
    return "([0-9]+)([a-z]+)"
        .toRegex()
        .matchEntire(r)
        ?.takeIf { it.groupValues.size == 3 }
        ?.let {
            val number = it.groupValues[1].toIntOrNull()
            val string = it.groupValues[2]

            if (number == null) null
            else decode(string, number)
        }
        ?: IMPOSSIBLE_TO_DECODE
}

fun code(s: String, num: Int): String {
    return s
        .map { code(it, num) }
        .joinToString("")
        .let { "$num$it" }
}

fun decode(r: String, num: Int): String? {
    return r
        .map {
            decode(it, num)
                ?: return null
        }
        .joinToString("")
}

fun code(c: Char, num: Int): Char {
    return c
        .let { it - 'a' }
        .let { it * num % 26 }
        .let { 'a' + it }
}

fun decode(ch: Char, num: Int): Char? {
    return ('a'..'z')
        .asSequence()
        .map { code(it, num) }
        .filter { it == ch }
        .singleOrNull()
}
```

- `"Impossible to decode"` になるケースでは `null` を返すようにして、  
  最後に `"Impossible to decode"` にしている。
    - 関数 `code` と `decode` とで、引数と返値型が同じで対称性がある形になった。（ただし返値型は `code` では non-null、 `decode` では nullable となっている。）
- キレイなコードを書けたと思う。
    - `decode(String, Int)` において `map` の中で `return` しているのだけが心残り。
- `decode(Char, Int)` で総当たりしているのはどうにかできないものか。
UITableViewをコードから選択した場合、セルの解除のメソッドが呼ばれない場合の対処方法

<h1>はじめに</h1>
UITableViewの初期値としてセルにチェックマークを入れるため、コードからセルを選択する必要がありました
しかし、次のセルに選択が移った時、初期値に入れておいたチェックマークが外れなかったのです。
![例１.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259778/691308b5-471d-0abd-5678-794d3b62ec29.gif)


<h1>コードからセルを選択するとセルの解除が呼ばれない</h1>
コードからセルを選択をすると、解除のメソッドが呼ばれないようですね
<a href="https://developer.apple.com/documentation/uikit/uitableview/1614989-deselectrow" rel="nofollow noopener" target="_blank">deselectRow(at:animated:)</a> や <a href="https://developer.apple.com/documentation/uikit/uitableview/1614875-selectrow" rel="nofollow noopener" target="_blank">selectRow(at:animated:scrollPosition:)</a>
※ Apple Reference<blockquote>Calling this method does not cause the delegate to receive a tableView(_:willDeselectRowAt:) or tableView(_:didDeselectRowAt:) message, nor does it send selectionDidChangeNotification notifications to observers.
</blockquote>




<h1>対処方法</h1>
UITableViewのデリゲートメソッド、[tableView(_:willSelectRowAt:)](https://developer.apple.com/documentation/uikit/uitableviewdelegate/1614943-tableview)に注目して解決しました

```swift:UITableViewController.swift
// セルを選択するその直前に呼ばれるメソッド
    override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        //まだ、この時は次のセルに選択が移っていない、選択中のセルのインデックスパスを取得する。
        if let selectedRow = tableView.indexPathForSelectedRow {　
            tableView.cellForRow(at: selectedRow)?.accessoryType = .none
        }
        //このindexPathが次に選択されたセルのインデックスパスになる
        return indexPath
    }

// セルを選択した時に呼ばれるメソッド
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
    }

```
willSelectRowAtの中では、まだ次のセルにインデックスパスが移っていないため、
tableView.indexPathForSelectedRowにて取得ができる。
ということで、コードで選択した場合であっても選択していたセルのインデックスパスが取得できました。
![例２.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259778/67bf60c3-34de-dc7c-f6d9-014ac3566c96.gif)




<h1>参考にさせていただいた記事</h1>
[UITableViewをプログラムから選択する実装について(チェックマークが表示・非表示されない問題)](https://qiita.com/KikurageChan/items/f2bebb027f2353a6cd22)
[UITableView Apple Reference](https://developer.apple.com/documentation/uikit/uitableview)
毎日ブログ三日目

只今の時刻21:09分

今日も書いていきますか

今日やったこと

①Progate HTML/CSS上級道場

2回目ということもあり、前回よりかはできるようになりました。
しかしながら、ヘッダーとメインが難しい。
スマホとかタブレットのことを考えると、避けては通れない道なんですよね。

・学んだこと
メニューアイコンを消す方法
HTMLにfa fa-bars これをspanタグの中にクラスづける。このfaとかはどっかのサイトに載っているみたい。

このままだとPC画面にも表示されるので、display:none;で消します。

その代わりにスマホ用の所で、display:block;で表示させます。

あ、でも、元々あったヘッダーをスマホでは消す必要がある。

clearの使い方はよく分かりませんでした。
これを使わないと、四つの画像が上手く表示されないことや、文字が画像の方に入り混んでいたりしたので使うみたい。
clearで空タグを挟み込む感じかな。
それでバランスを取る感じ。

②ドットインストール
Boostrap4 15～22 この単元終了

まず、これの復習の前に

あるブログを読んでいたら、Boostrapは必要なくて、学ぶだけ時間の無駄みたいなこと言っている人がいて、「ええええええ！！！！まじかよっ！」って思いました。それみたせいで、やる気がガクーンって下がりました。ブログがあることはいいことなんですけど、時にはモチベーションを下げるもんだなと学びましたね。

・学んだこと
テーブルタグを使うことにより、行と列みたいに分けられるんですね。

テキスト　アライン　センターはテキスト　センターでいける。

activeにするのは対応するタグにつけること。

角○の消し方、rounded-0

消すボタンの付け方は、alertを使って消すみたい。


今回やったところは、なんかやり方を納得する感じかな。知らないことばっかであんまりなあって感じっだった。
正直今回はやる気が下がっていたこともある、イマイチ身が入らなかった。でも、何となく概要は理解したので調べながらやればいけそう。

本当に無駄なのかな。。。


話は変わり、今日は二郎系ラーメンを昼に食べに行ったので夜ご飯は食てべません。二郎系は夜には食べず昼に食べることで、食費を浮かせられるのでかなりおすすめです。

また、話は変わり、富士山転落のニュースはとてもいたたまれない気持ちになりました。お悔やみ申し上げます。

明日のTo　Do List
・Progte　jQuery　初級編
・Progte　FlexBox　終わらす
・模写　一番簡単そうなの


やることがよくわかんなくなってきたけど、模写はした方が良さそうなのでしたいと思います。そもそも画像ってどこから持ってくるのか書いて無くてわかりません。

他の人のブログをみていると、役に立つことは確かにあるけど、自分でどの情報を取捨選択する必要がありそうですね。今の世の中情報があふれすぎていて、三ヶ月で上達しますみたいに謳っていることが多いけど情報に振り回されず、こつこつやることが大事なんじゃないかなと思う今日この頃。

書き終えた時刻、22:13分

約１時間かかりました。どうも、cとxが打ちずらくてしょうがないですね。あと「。」打つのも大変。

明日は一限なので、朝しっかり起きないと、、
明日も一日頑張りましょう！！！！
Object.assign()を用いてイミュータブルな変更を行う

## 概要

 `Object.assign()` を用いてイミュータブルな変更を行う。

## ミュータブル(mutable)な変更

例えば、太郎君の毎日の献立が、以下のようになっているとします。

```js
const gohan = { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
```

これだと炭水化物のメニューばかりなので、夕食はサラダにする別の献立を考えました。
その際、毎日の献立を元に夕食だけ変更するので、以下のように記述します。

```js
const healthyGohan = gohan
healthyGohan.dinner = "サラダ"
console.log(healthyGohan) // { morning:"パン", lunch:"カレー", dinner:"サラダ" }
```

これで、無事 `healthyGohan` の夕食はサラダになりました。しかしこの時、問題が発生しました。

```js
console.log(gohan) // { morning:"パン", lunch:"カレー", dinner:"サラダ" }
```

なんと毎日の献立が `helthyGohan` と同じように「サラダ」に変更されてしまいました。

このような変更を`オブジェクトの状態が変わる` `ミュータブルな変更`といいます。

JavaScriptでは、オブジェクトが格納されている変数を他の変数にコピーすると、そのオブジェクトへの参照がコピーされます。したがって、`healthyGohan`が変更されたら、その参照元の`gohan`までもが変更されます。

`等価演算子(==)`で確認すると、`healthyGohan` と　`gohan` は同じオブジェクトだということが分かります。

```js
healthyGohan == gohan // true
```

## イミュータブル(mutable)な変更

### Object.assign()

参照元を変更したくない場合は、`オブジェクトの状態が変わらない` `イミュータブル`な変更をする必要があります。
イミュータブルな変更を行う方法の一つに、`Object.assign()` があります。

```js
Object.assign(target, ...sources)
```
target: コピー先オブジェクト
sources: コピー元オブジェクト

`空のオブジェクト` をコピー先オブジェクトにすることで、イミュータブルなオブジェクトのコピーができます。

今回の例だと以下のようにしてオブジェクトをコピーします。

```js
const healthyGohan2 = Object.assign({}, gohan) // {}は空のオブジェクト
console.log(healthyGohan2) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
```

これで、`healthyGohan2` は`gohan`をコピーしました。しかし、`等価演算子(==)`で確認すると、見た目は同じでも違うオブジェクトだということがわかります。

```js
healthyGohan2 == gohan // false
```
イミュータブルな変更なので、夕食をサラダに変更しても参照元の`gohan`は変更されません。

```js
healthyGohan2.dinner = "サラダ"
console.log(healthyGohan2) // { morning:"パン", lunch:"カレー", dinner:"サラダ" }
console.log(gohan) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" } // dinnerはラーメンのまま
```

Object.assign()はオブジェクト同士の結合も可能です。寝る前にプロテインを摂るとします。

```js
const midnight = {midnight:"プロテイン"}
Object.assign(healthyGohan2, midnight)
console.log(healthyGohan2) // { morning:"パン", lunch:"カレー", dinner:"サラダ", midnight:"プロテイン" }
```

イミュータブルな変更なので、参照元の`gohan`は変更されません。

```js
console.log(gohan) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
```

### スプレッド演算子

`スプレッド演算子`を使うことで、Object.assign()と同じように、オブジェクトをイミュータブルに扱うことができます。

```js
const healthyGohan3 = {...gohan}
console.log(healthyGohan3) // { morning:"パン", lunch:"カレー", dinner:"ラーメン" }
healthyGohan3 == gohan // false
```
以上、ミュータブルな変更とイミュータブルな変更に関して、説明させていただきました。

何か間違っていることや意見等ありましたら、コメントいただけると助かります！

## 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

https://developer.mozilla.org/ja/docs/Glossary/Mutable

https://developer.mozilla.org/ja/docs/Glossary/Immutable