OmniAICreator/Qiita-1.07M huggingface dataset:
docker-composeでrails開発時のA server is already running. Check xxxx/tmp/pids/server.pid. 対応

```yml:docker-compose.yml
version: '3.7'

services:
  backend:
    tty: true
    stdin_open: true
    build:
      context: ./backend
    working_dir: /usr/src/app
    environment:
      BUNDLE_JOBS: 4
      DB_HOST: db
      AUTODOC: $AUTODOC
    command: bin/rails s
    volumes:
      - ./backend:/usr/src/app
      - bundle:/usr/local/bundle
      - /usr/src/app/.bundle
      - /usr/src/app/tmp/pids
    tmpfs:
      - /usr/src/app/tmp/pids
```

tmpfsに乗っけることで、停止時に消えてくれるはず。
rake task でridgepole 実行

[こちら](https://qiita.com/lhside/items/0dcad79d9b801e34bc7c)の記事を参考に以下を修正しました。(ほぼ同じ)
- Rails.envを考慮
- annotateを実行
- 出力をsplit
- rspecの前に流す

```ruby:lib/tasks/ridgepole.rake
# frozen_string_literal: true

# see https://qiita.com/lhside/items/0dcad79d9b801e34bc7c
namespace :ridgepole do
  desc 'Apply database schema'
  task apply: :environment do
    ridgepole('--apply', "-E #{Rails.env}", "--file #{schema_file}")
    Rake::Task['db:schema:dump'].invoke if Rails.env.development?
    Rake::Task['annotate_models'].invoke if Rails.env.development?
  end

  desc 'Export database schema'
  task export: :environment do
    ridgepole('--export', "-E #{Rails.env}", '--split', "--output #{schema_file}")
  end

  private def schema_file
    Rails.root.join('db/schema/Schemafile') # rubocop:disable Rails/FilePath
  end

  private def config_file
    Rails.root.join('config/database.yml') # rubocop:disable Rails/FilePath
  end

  private def ridgepole(*options)
    command = ['bundle exec ridgepole', "--config #{config_file}"]
    system [command + options].join(' ')
  end
end

```

```ruby:spec/spec_helper.rb
# frozen_string_literal: true

require 'rake'

## ~~~~略~~~~
RSpec.configure do |config|
  config.before(:suite) do
    Rails.application.load_tasks
    Rake.application['ridgepole:apply'].invoke
## ~~~~略~~~~
```
Gsonはデフォルトではnullなフィールドをシリアライズしない

調べたのでメモ。  
題名の通り、GsonはオブジェクトをJSONに変換する際、デフォルトではnullのフィールドをシリアライズしない。  
nullのフィールドをシリアライズしたい場合、 `GsonBuilder#serializeNulls()` を使用する。

# サンプルコード

```MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val data = Data("nonnull", "nullable", null)

        val gson1 = Gson()
        val json1 = gson1.toJson(data)
        Log.d(TAG, json1)
        // => {"nonNullProp":"nonnull","nullableProp1":"nullable"}

        val gson2 = GsonBuilder().serializeNulls().create()
        val json2 = gson2.toJson(data)
        Log.d(TAG, json2)
        // => {"nonNullProp":"nonnull","nullableProp1":"nullable","nullableProp2":null}
    }

    data class Data(
        val nonNullProp: String,
        val nullableProp1: String?,
        val nullableProp2: String?
    )

    companion object {
        private const val TAG = "MainActivity"
    }
}
```

# 参考URL
- [Gson User Guide - Null Object Support](https://github.com/google/gson/blob/master/UserGuide.md#TOC-Null-Object-Support)
DDコマンドでイメージをコピーしたUSBメモリをフォーマットする方法

USBメモリにDDでOSイメージをコピーしてオンプレにインストールしたものの、
WindowsでUSBメモリをフォーマットできず、復旧方法が謎だったので試行錯誤した備忘録。

以下サイトの情報でほぼうまくいったが、Windowsでのdiskpart cleanにて`アクセスが拒否されました`といったエラーが出てしまった。
https://www.softel.co.jp/blogs/tech/archives/5608

```
DISKPART> clean

DiskPart にエラーが発生しました: アクセスが拒否されました。
詳細については、システム イベント ログを参照してください。
```

## まずはCentOSにUSBを挿してparted

```
(parted) mklabel
新しいディスクラベル? msdos                                               
警告: いま存在している /dev/sdb のディスクラベルは破壊され、このディスクの全データが失われます。続行しますか？
はい(Y)/Yes/いいえ(N)/No? yes                                             
(parted) mkpart                                                           
パーティションの種類?  primary/プライマリ/extended/拡張? primary          
ファイルシステムの種類?  [ext2]?                                          
開始? 0G                                                                  
終了? 31G                                                                 
(parted) p                                                                
モデル: UFD 3.0 Silicon-Power32G (scsi)
ディスク /dev/sdb: 31.0GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ: 

番号  開始    終了    サイズ  タイプ   ファイルシステム  フラグ
 1    1049kB  31.0GB  31.0GB  primary

(parted)                                                                  
(parted) quit 
```

## あとはWindowsでdisk part

```
C:\WINDOWS\system32>diskpart

Microsoft DiskPart バージョン 10.0.17134.1

Copyright (C) Microsoft Corporation.
コンピューター: DESKTOP-JTBSUGH

DISKPART> list disk

  ディスク      状態           サイズ   空き   ダイナ GPT
  ###                                          ミック
  ------------  -------------  -------  -------  ---  ---
  ディスク 0    オンライン           238 GB      0 B        *
  ディスク 1    オンライン            28 GB      0 B

DISKPART> select disk 1

ディスク 1 が選択されました。

DISKPART> list disk

  ディスク      状態           サイズ   空き   ダイナ GPT
  ###                                          ミック
  ------------  -------------  -------  -------  ---  ---
  ディスク 0    オンライン           238 GB      0 B        *
* ディスク 1    オンライン            28 GB      0 B

DISKPART> clean

DiskPart はディスクを正常にクリーンな状態にしました。

DISKPART> create partition primary

DiskPart は指定したパーティションの作成に成功しました。

DISKPART>
```

## それでもエクスプローラに表示されない！

1. ディスクの管理を開く
2. 当該ディスクを右クリックしてフォーマットする
3. ドライブレターを振る

おわり
npm onchangeをWindowsで利用する際の注意

## npm onchangeが変更を全然検知してくれなかった件

onchange
https://www.npmjs.com/package/onchange

ファイルの変更を検知してコマンドを実行してくれる便利なモジュールです。
Readmeに書いてあるのですが、Windowsで使う際にはダブルクォーテーションを使わないとダメなのだそうです。

> NOTE: Windows users may need to use double quotes rather than single quotes. If used in an npm script, remember to escape the double quotes.

ちゃんと書いてあることを読もうという反省を込めてここに残しておきます。

```json:package.json(ダメな例)
    "start": "onchange 'index.js' -- node index.js"
```

```json:package.json(良い例)
    "start": "onchange \"index.js\" -- node index.js"
```
GASでGmailをDiscordに転送できるようにした

## はじめに
皆さん、Gmail、使ってますか？
結構な方が使ってると思うのですが、中にはメールチェックをさぼりがちで、ついつい重要な連絡を見過ごしてしまう、という人もいると思います。僕もその一人です。
と、言うわけでそれを解決するソリューション(言ってみたかった)として、Gmailの内容を普段使っているチャットツールに転送出来たらチェック漏れが減るのではないか、と思いGASを使って実際にやってみました。
今回は、その知見をまとめていきたいと思います。

## DiscordのWebhookを取得する
まず、今回はDiscordを使用したいので、メールを転送するためのDiscordサーバーをさくっと作ります。
そうしたら次に、メールを受け取るためのチャンネルを用意して、下の設定マークのボタンから設定画面に入ります。

![](https://i.imgur.com/E9XIFEK.png)

Webhooksという項目があるのでそこをクリックして

![](https://i.imgur.com/JDrejvY.png)

Webhookを作成をクリックします。
僕は既にGmailという名前で作っているので一個表示されていますね。

![](https://i.imgur.com/zleajbq.png)

出てくる画面で任意の名前を付けると、WebhookのURLが発行されるので保管しておきます。後で使います。

また、このURLにアクセスするとTokenが手に入るのでブラウザでアクセスして取得しておきます。

## GASを書く
念のために説明をしておきますと、GASとは `Google Apps Script` の略で、JavaScriptと似たような言語を使ってGoogleのサービスと連携したりしたツールを作れます。
Googleのサービスと連携するので、当然Gmailも呼び出すことができるわけです。
これはスプレッドシートから編集することができます。
ここのツールというボタンを押して、スクリプトエディタを選択すればスクリプトの編集画面に行きます。

![](https://i.imgur.com/x5RmUZq.png)

![](https://i.imgur.com/tr26KO0.png)

基本は任意の関数を置いて、指定のトリガーでその関数を起動させるという感じです。
では実際にコードを書いていきます。

まずDiscordのWebhookにメッセージをPOSTする関数を作ります。

```javascript

function discord(postMsg){
  const webhooks = '取得したURL'
  const token = '取得したToken';
  const channel = 'Discordで投稿するチャンネル名';
  const userName = 'Discordで表示する名前';
  const parse = 'full';
  const methods = 'post';
  
  const payload = {
    'token': token,
    'channel': '#mails',
    'content' : postMsg,
    'parse': parse,
  };
  
  const params = {
    'method': methods,
    'payload' : payload,
    'muteHttpExceptions': true,
  };
  response = UrlFetchApp.fetch(webhooks, params);
}
```

次に、Gmailの情報を一定間隔で取得してその内容をDiscord関数に渡して実行する関数を作ります。

```javascript

function mails(){
  var searchQuery = "Gmailで取得したい検索クエリ(例:to(me@gmail.com))";
  var dt = new Date();
  
  //メールをチェックする頻度を指定します。短すぎるとGmailの制限に引っかかります。
  const checkSpanMinute = 30;
  dt.setMinutes(dt.getMinutes() - checkSpanMinute);

  var threads = GmailApp.search(searchQuery);

  var msgs = GmailApp.getMessagesForThreads(threads);
  for(var i = 0; i < msgs.length; i++) {
    var lastMsgDt = threads[i].getLastMessageDate();

    if(lastMsgDt.getTime() < dt.getTime()) {
      break;
    }

    for(var j = 0; j < msgs[i].length; j++) {
      var msgDate = msgs[i][j].getDate();
      var msgBody = msgs[i][j].getPlainBody();
      var msgFrom = msgs[i][j].getFrom();
      var matches = msgFrom.match(/"(.+)".*<(.+)>/)
      {
        var subject = msgs[i][j].getSubject();
       //取得したデータを最終的に受け取りたいフォーマットに整えます。Discordでは[```]を引用符として使えるので前後に着けています。
        var postMsg = "```" + "\n" +
          Utilities.formatDate(msgDate, 'Asia/Tokyo', 'yyyy/MM/dd hh:mm:ss') + "\n" +
              "件名:" + subject + "\n" +
              "[hr]" +
               msgBody + 
            "```";
 
        discord(postMsg);

      }
    }
  }
}

```

こんな感じのスクリプトを書いてあげます。

完成したら一度実行->関数を指定して実行、でmails関数を実行して問題ないか確かめましょう。

## トリガーを設定する

編集->現在のプロジェクトのトリガーからトリガーの設定画面に入れます。
トリガーを追加から時間主導型で `checkSpanMinute` で設定したスパンでmails関数を実行するように設定します。

これであとはGoogleのサーバーでスクリプトを自動的に実行してくれるようになります。

## まとめ
これで、よく使うツールでGmailを取得できるようになりました。
実際に運用してからかなりメールの確認漏れが減りました。
何より、メールの連絡と普段の連絡を同じツールで管理できるというのがQOL高くていい感じです。
皆さんもGASを使って身の回りを少し便利にしてみてはいかがでしょうか？
demo.twilio.comで使える静的リソースを調べてみた

# はじめに

Twilioのドキュメントを読んでみると、ちょいちょい
`demo.twilio.com`でホスティングされた静的ファイルを見かけます。

一番よく見るのは`voice.xml`ですね。
https://www.twilio.com/docs/voice/make-calls#specify-a-url-parameter

```js
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = require('twilio')(accountSid, authToken);

client.calls
      .create({
         url: 'http://demo.twilio.com/docs/voice.xml',
         to: '+14155551212',
         from: '+15017122661'
       })
      .then(call => console.log(call.sid));
```

これ系がきっと他にも沢山あって、サクッと試したい時に便利に使えるんじゃないかと思って調べてみました。

注意）勝手に調べて載せた非公式情報なので、予期せず変更される可能性は十分あります。あんまり参考にしない方がいいかもしれませんw

# 調査方法

試しに上位PATHにアクセスしてもindexなんか出ずに、当然Forbideenですw
https://demo.twilio.com/docs/
ドメインルートにアクセスすると、メインのサイトにリダイレクトされました。
https://demo.twilio.com/ → https://www.twilio.com/ja/

なので、ひたすらそれっぽいURL入れてGoogle検索しましたw

# 調査結果

## 拡張子xml
静的にTwimlが返ってくるURLです。

https://demo.twilio.com/docs/voice.xml
女性が喋ってから、音楽（後述のclassic.mp3）が流れる

https://demo.twilio.com/docs/sms.xml
SMS送信

## 拡張子mp3
https://demo.twilio.com/docs/classic.mp3
3分間の音楽が流れる。
曲は[Rick Astleyの「Never Gonna Give You Up」](https://www.youtube.com/watch?v=dQw4w9WgXcQ)ですね。Twilioの中の人がファンなのかな？どう聴いても「クラシック」ではないと思ったけど、「懐メロ」的な意味なのかもｗ


https://demo.twilio.com/hellomonkey/monkey.mp3
おさるのジョージの声が聞こえる

## 拡張子png
https://demo.twilio.com/owl.png
https://demo.twilio.com/logo.png
フクロウの画像とTwilioのロゴ。

なぜTwilioで画像ファイル？って思ったら、MMSで使うんですね。
https://jp.twilio.com/docs/sms/twiml/message#examples-2


```js
const MessagingResponse = require('twilio').twiml.MessagingResponse;


const response = new MessagingResponse();
const message = response.message();
message.body('Store Location: 123 Easy St.');
message.media('https://demo.twilio.com/owl.png');

console.log(response.toString());
```

## 拡張子なし
https://demo.twilio.com/welcome/
https://demo.twilio.com/welcome/voice/
https://demo.twilio.com/welcome/voice/ja/
https://demo.twilio.com/welcome/sms/
https://demo.twilio.com/welcome/sms/reply/
階層構造になってて、それぞれのPATHで違ったTwimlが返ってきます。
`/welcome/`と`/welcome/voice/`は同じでした。
これ、隠されたPATHがまだありそうだなー。

# おわりに
前も[Google DriveのフォルダID命名規則](https://qiita.com/the_red/items/f0bbf542ed910f96e30d)の記事なんか書きましたが、たまにこんなしょーもない調査したくなるんです :joy:
そんなに沢山は見つからなかったですが、開発段階でうまいこと使えそうなシーンあったら使ってみてください。

他にも似たようなの見つけたら、教えてくださいねー。
Ubuntu on Rock64でapt-get updateができないときの対処法

# 環境
```
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"
Linux rock64 4.4.132-1072-rockchip-ayufan-ga1d27dba5a2e #1 SMP Sat Jul 21 20:18:03 UTC 2018 aarch64 aarch64 aarch64 GNU/Linux
```
# 問題
```
sudo apt-get update
```
をすると

```
[...]
E: Repository 'http://deb.ayufan.eu/orgs/ayufan-rock64/releases  InRelease' changed its 'Origin' value from '' to 'GITHUB-AYUFAN-DEB-ayufan-rock64'
N: This must be accepted explicitly before updates for this repository can be applied. See apt-secure(8) manpage for details
```
と表示されて更新できない

# 解決法
```
sudo apt update
```
で治る

# 参考
https://forum.pine64.org/showthread.php?tid=6309
https://qiita.com/SUZUKI_Masaya/items/1fd9489e631c78e5b007
TypeScriptでランタイム型チェックを行う「io-ts」の軽い紹介

# TypeScriptのランタイム型チェック
TypeScriptにはランタイム型チェック機能がありません。
次のようなコードも正常にコンパイルされエラーが発生することなく動作します。

```ts
const x: string = JSON.parse("1");
```

これはパフォーマンスなどとのトレードオフなので仕方ないのですが、部分的に動的な型チェックをしたいときもあります。
このような時の解決策として`io-ts`を紹介します。

# io-tsのメリット
`JSON Schema`などは型とスキーマを2つ書く必要があり大変です。
また大変なだけでなく型とスキーマが異なるといったバグを型システムでチェックすることが出来ません。
コードジェネレーターを使うことで解決できますが、TypeScript上で完結しないのでめんどくさいです。
このような問題は`io-ts`を使うことで解決します。
ただし再帰型については型推論の関係で型とスキーマを2回書く必要がありますが、型チェックでスキーマと型が違っていればコンパイルエラーが発生します。

# 基本的な使い方
```ts
import * as t from "io-ts";

const hoge = t.type({
  tag: t.literal("Hoge"),
  x: t.string,
  y: t.union([t.number, t.null]),
});

type Hoge = t.TypeOf<typeof hoge>;
/*
type Hoge = {
  tag: "Hoge",
  x: string,
  y: number | null,
};
*/

hoge.is(JSON.parse(str));
```

もっと詳しい使い方は`io-ts`のREADMEを見ればすぐ分かるのでこっちを見て下さい。
https://github.com/gcanti/io-ts

# どうやって実現しているのか
※ここから先はライブラリを使う分にはあまり知らなくていい情報です。

TSはデコレーターという例外を除いて、型情報から値を生成することは出来ません。
しかし、`typeof`を使うことで値から型を生成することは出来ます。
そこでスキーマ情報をなるべく具象型で(例えば単にSchemeのような型ではなくSchemeの構造を完全に持っている型)持つように型推論を制御して、`typeof`で値から型を作ることでこのような事が可能になります。
ちなみにTS3.4で`as const`が入ったので今までより具象型で持つのが楽になりました。
これはio-tsに限らずTSを使う時に知っておくと役に立つ考え方です。

ちなみに作者のgcanti氏は`fp-ts`の作者でもあり、他にもTSの型システムを最大限活用したライブラリを多数公開しているので見てみると面白いかもしれません。
git merge squash と rebase

# merge の形式(メモ代わり)
 merge pr の時、選択は三つあります

- 普通の merge
- rebase merge
- squash merge

この三つ何か違うのは、ローカルブランチ使って説明していきます

##masterブランチモデル
例えばこのブランチに幾つのcommitあったとして
<img width="839" alt="5332460-f04ea0e936855609.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/320164/9e9ddf0f-bcb0-635f-51c1-198fd443f95c.jpeg">

そして、また新しいブランチを作って、開発し幾つのコミットをします、そうすると、全体図はこういうふうになります
<img width="875" alt="5332460-5783bb63684fafcb.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/320164/25b168c2-9250-7a1c-74af-04ff1f92ee84.jpeg">

## 普通の Merge
ブランチを合併する時、よくあるのは以下の操作になります

masterブランチにcheckoutして,合併
`：git merge devel`
そして用済みのブランチを削除
`：git branch -D devel`
リモートブランチへpush
`：git push origin master`

一見何の問題もないけど、でも実際どんな結果になったのでしょうか,合併前のブランチは以下の様です
<img width="875" alt="5332460-5783bb63684fafcb.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/320164/a09d7d92-3852-5de1-1e8d-7062f45a69d8.jpeg">
操作後は
<img width="856" alt="5332460-589ec8b823f545ee.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/320164/242116ae-4883-830d-b3e5-77905b89481c.jpeg">

一見悪くない、真っ直ぐなcommitラインになってます,develブランチ内のコミットも**全部**masterブランチに記録されている、でも、果たしてこんなに多くのコミット記録する必要があったのでしょうか
例えば数十人も参加するおおきなプロジェクトがあったとして、一つ修正のために、ちょっとしたミスで数十個のコミットをPRしてしまい、しかもmergeされました,その時、このプロジェクトのヒストリーにどうでもいいcommit数十個増えてしまう、マネージャーそれを見ると困惑するでしょ、しかも何回も繰り返しをすれば、rollbackも大変な作業になるでしょ

## squash merge
複数のcommitを一つに合併する時、 git commit --amend，使えば 自分のcommit履歴が確認出来,pick で選び，squash 合併など。同様に，merge の時も出来ます、手順は二つだけ

ブランチを切り替え`：git checkout master`

squash 形式でmerge `merge：git merge --squash devel`

この時masterブランチで未提出のcommitが出てきます、注意すべきのは、それが自分のcommitであること,つまりcommitのauthorを変えた、結果、以下の様になります
<img width="850" alt="5332460-c7ff7af5ba03d268.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/d35bd269-de7e-4ed8-be83-e92b26ef69ed.jpeg">
普通のmergeよりはいい、今commitは一つになった,サブブランチでいくらcommitしたとしてもここは一つしかない!

## rebase merge
もし合併して更に作者のデータを残したければ、rebaseを使ってみましょう


まず devel ブランチへcheckout：`git checkout devel`

リベース：`git rebase -i master`

master ブランチへ戻る `：git checkout master`

合併`: git merge devel`

二番目の操作は、develでmasterを参照にリベース、リベースはつまり、ふたつのブランチの共通の先祖に移動して、現在のブランチで先祖から今までのcommitを合併,なので二番目の操作ではこのcommitたちの処理方法が選べる、この時masterにmergeしても、commit記録は一つしか残らない、以下の様に

<img width="854" alt="5332460-3f1336dea5fe04ac.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/d9cfe889-b4e4-b39f-df85-ebcf95f1fb9b.jpeg">

現在のcommit historyはよくなったが、注意すべき点は元のcommit historyを変換したければブランチの開発者は自分でリベースしなければならない

### この三つの方式を比較すれば、いくつの結論が得られます:

- rebase masterを綺麗な状態にし、author の識別もしやすい
- squash もmasterを綺麗な状態にたもてるが,masterのauthorは全部maintainerであって、元のownerではない
- merge masterの履歴汚しますが、全てのcommit historyが記録された
Markdown記法をバックログ記法に変換するスクリプトを作った

## ポインタ

このスクリプトは自分でもプロジェクトが変わって最近あんまり使ってないし、技術的に１億倍くらい素晴らしいものがネットにはあるのでポインタを貼っておきます。

- [Markdown記法をBacklog記法に変換するものを作った](https://dev.classmethod.jp/articles/markdown-to-backlog-tool/)
    - クラスメソッドさんのブログ記事。マークダウンをASTに分解したりしててすごい。
- [MarkdownをBacklogのwikiに変換するPWA](https://www.slideshare.net/ssuser91429f/markdownbacklogwikipwa)
    - リアルタイムプレビューできるしクリップボードコピーできるし超便利です。スライドの最後にアプリURLが公開されてます。

今となってはここから下は読む価値ほぼありません。ログとして残しておくのみ。

---

[Backlog](https://backlog.com/ja/)は、以前はデフォルトの記法がバックログ記法という謎の記法だったため、プロジェクト管理者がWiki作成とかに興味ない人だとバックログ記法が設定されてしまい、その上に数々のドキュメントが溜まってしまい、いまさらプロジェクトの記法を変更できない。。。という状態になっている方もいらっしゃるのではないかと思います。

また、開発チームメンバーに設定変更の権限がなく、記法を変更することができないという方も多いと思います。私がそうです。

でもローカルPC内ではバックログ記法などという謎の記法でメモ書きたくない。。マークダウンに手が慣れてるし。。

と思ったので、マークダウンで書いたメモなどをバックログ記法に変換するスクリプトを作成しました。

https://github.com/newnakashima/md2bl

大したものではないですが、マークダウンで長いのを書いてしまったときなどにはまあまあ役に立ちます。Perlで書きました。

## 使い方

```shell
$ git clone https://github.com/newnakashima/md2bl.git
$ cd md2bl
$ ./md2bl ~/my-markdown-file.md
```

標準入力にわたすこともできます。

```shell
$ echo "# 見出し" | ./md2bl
* 見出し
```

画像の記法には対応してないのでよろしくおねがいします。

## なんでPerlなのか

Perl書いてみたかったからです。awkっぽかったりphpっぽかったり()して楽しかったです。
Perlでわかんないことぐぐると昔のブログとかが沢山出てきてあったかい気持ちになったりもしました。
fastTextをpipインストールしてはいけない話（2019/4/11現在、pyenv環境)

# これは何？
自然言語処理で使用する、facebookの研究者の開発した打倒word2vecかもしれない、単語ベクトルを得るためのライブラリのFastTextの話です。
Pythonを利用するときpipはよく使うと思います。fastTextもpipに登録されているので後述の通りインストールできるのですが、インストールしてもプログラムからimportできないという症状が出ました。

次のサイトにたどり着いて解決しました。
https://github.com/facebookresearch/fastText/issues/474

**一か月前にも全く同じ症状で苦しんでいたのですが、歳とは恐ろしいもので、そのことをすっかり忘れて前回と同じサイトで解決した自分にあきれて投稿します。備忘録って大切ですね！**

2019年4月11日現在の内容です。
近いうちに改善されると思います。
影響があるか未調査ですがpyenv環境での話です。

fastTextについてはこのへんを参照
https://qiita.com/icoxfog417/items/42a95b279c0b7ad26589

# 【解決策】Githubからソースをダウンロードして手動で入れよう！

このように

```{shell}
git clone https://github.com/facebookresearch/fastText.git
cd fastText
pip install .
```

以上

# 【失敗例】普通にpip installでインストールしても、import できない

普通にpipに存在するので、pip installでインストールで行けそうな気がします。依存等のエラーがでますが、簡単そうなので逆にのりのりでトラブルシュートしてしまいます。

```{shell}
pip install fastText
```

怒られる

```{shell}
ModuleNotFoundError: No module named 'Cython'
```

Cython直してもう一度

```{shell}
pip install --upgrade cython
pip install fastText
```

また怒られる

```{shell}
gcc: error trying to exec 'cc1plus': execvp: No such file or directory
```

gcc-c++ をインストールしてもう一度

```{shell}
yum install gcc-c++
pip install fastText
```

すると、ちゃんとインストールされる。やった！
けれど、プログラムを走らせると、、、

```{shell}
$ python app.py
ModuleNotFoundError: No module named 'fastText'
```

**インストール成功と出て、site-packagesにもちゃんとフォルダがあるのに、なぜかimportされない病**
小一時間pythonpathなど弄るも解決しない、、、
DataSpiderでOutOfMemoryErrorがでたら勝手に再起動してみる

Javaアプリケーション永遠のライバル、「OutOfMemoryError」(以下OOME)。
油断すると簡単に出るもので一見見落としがちなんですが、Exception(例外)ではなくエラーなんですよね。
[Javadoc](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Error.html) によると、Errorは「<b>絶対に起きてはならない異常な状態である</b>」だそうです。

OutOfMemoryErrorが発生した時点で JVM の中はいっぱいいっぱいになっており、状況は不定です。たとえそれが何らかの処理中であっても、その処理が正しいデータを出力する保証はなく、ただちに停止するべきであると考えられます。

ということで、OOMEが出たら再起動するようにしてみます。

今回は Windows 環境を対象としています。Linuxの場合、再起動用のコマンドなどが異なりますのでご注意ください。

# 再起動用バッチを作成する

まず、再起動を行うためのバッチを作成します。
たとえば、次のようなバッチファイルです。

```
TASKKILL /IM DataSpiderServer.exe /T
cmd /c start DataSpiderServer.exe
exit
```

TASKKILLコマンドで「DataSpiderServer.exe」のプロセスをkillします。
その後、DataSpiderServer.exe を実行します。

OutOfMemoryError発生時には、DataSpiderServerの状態は不定となり、終了コマンドを受け付けられないケースも考えられます。
そのため、Shutdown.exe ではなく TASKKILLコマンドを使います。

Windowsサービスに登録している場合は次のようなバッチファイルでも良いでしょう。

```
net stop "DataSpiderServer"
net start "DataSpiderServer"
```

バッチファイル単体で再起動が行えることを確認します。
コマンドによっては管理者権限が必要な場合もありますので、権限には注意してください。

作成したバッチファイルは $DATASPIDER_HOME/server/bin に配置しておきます。
名前はなんでも良いですが、今回は reboot.bat とします。

# OnOutOfMemoryErrorオプションを使う

JVMのオプションである `-XX:OnOutOfMemoryError` を利用します。
[http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html:title]

`-XX:OnOutOfMemoryError` オプションはOutOfMemoryError発生時に指定したコマンドを実行するオプションです。
これに再起動コマンドを設定しておくことでOutOfMemoryError発生時に再起動が可能です。

# -XX:OnOutOfMemoryError を設定する。

DataSpiderでは、$DATASPIDER_HOME/server/DataSpiderServer.lax の `lax.nl.java.option.additional` にJVM引数を設定できます。
lax.nl.java.option.additional に次の引数を追加します。

```
-XX:OnOutOfMemoryError="cmd /c start reboot.bat"
```

単にreboot.batで良いんじゃないかと思うんですが、taskkillコマンドで自分自身をkillすることはできないため、startコマンドでjava.exeとreboot.batのプロセスを分けてからkillします。
サービスの再起動コマンドならreboot.batのみでいける可能性もあります。

### 設定できたら再起動確認する

1. DataSpiderServerのヒープを128MB程度にして、OutOfMemoryErrorが発生しやすい状況を作ります。
1. DataSpiderServerとStudioを起動して、サイズの大きいファイルを読み取るスクリプトを作成します。
1. スクリプトを通常実行(ショートカットキー Ctrl+F5) で実行します。
1. ファイルサイズが大きければ実行中に OutOfMemoryError が発生します。そのタイミングで設定したバッチファイルが実行され、DataSpiderServer が再起動されれば設定成功です。
Linuxにpython3実行環境を構築した話

「pipてなに？エレキバン？」
というレベルの私がpython3/pip/pythonのモジュールが動く環境を構築した時のメモ。

## 入れるもの入れまくる
### python3
-> yum で

```bash:bash
yum search python36
sudo yum install rh-python36.x86_64
```

PATHが通っていないので、python2に向いているシンボリックリンクをpython3に向くように作り直し
※追記：これはやらないほうがよいかも。yumなどがpythonリンクを参照しpython2で動くようになっている場合

```bash:bash
# pythonコマンドのありかを確認
which python

# ↑で確認したパスに移動
cd /usr/bin

# すでにシンボリックリンクがあるので削除
sudo rm python

# python3に向くリンクを作成
sudo ln -s /usr/local/python/bin/python python
```

### pip
-> yum で

```bash:bash
yum search pip
sudo yum install rh-python36-python-pip.noarch
```
※追記：pythonのリンクをpython3に向けてしまうとyumがエラーになる。yumの行頭をpython2に書き換え。（#!/usr/bin/python2）


### モジュール類
-> pip で
--> 後で知ったのですがpipコマンドのオプションでインストール先を指定できる模様。コマンドのヘルプを参照。

```bash:bash
sudo pip install numpy
```
適当なモジュールを入れようとすると

```bash:bash
You are using pip version 9.0.1, however version 19.0.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
```

pipのバージョンが古くて怒られる。自らをバージョンアップ。

```bash:bash
sudo pip install --upgrade pip
```



## 動確

テストスクリプトをこちらから拝借
[Pythonを使えるNumPyのインストール方法や基本的な使…｜Udemy メディア](https://udemy.benesse.co.jp/ai/python-numpy.html)


```python:test.py
#! /usr/bin/python
import numpy as np

#配列(ndarray)
test1 = np.array([1,2,3,4,5])

#配列のから条件が満たされた要素番号を取得する
test2 = np.where(test1>=3)
print(test2[0])
```

成功例

```bash:bash
./test.py
[2 3 4]
```


## モジュールがないよエラーになる場合

```bash:bash
./test.py
（略）
ModuleNotFoundError: No module named 'numpy'
```
モジュール検索のパスが違うらしい

モジュール検索のパス設定確認
pythonコンソールログイン

```python:python(console)
import sys
print(sys.path)
```
結果を記憶①

インストールしたモジュールがどこに置かれちゃったか確認

```bash:bash
find / -name numpy
```
結果を記憶②



対応方法としては下記のどちらか
１）②を①に mv する
２）②のパスを①に追加する


１）だとモジュール追加するたびにmvしないといけなさそうなので２）のほうがよいかもしれない。
【PHP8.0】short_open_tagにさよなら、しないかも？

[Deprecate PHP Short open tags](https://wiki.php.net/rfc/deprecate_php_short_tags)というRFCが投票フェーズに入りました。
投票期間は2019/04/10から2019/04/24、採択には投票数の2/3+1の賛成が必要です。


# Deprecate PHP Short open tags

## Short open tagsとは

PHPの開始を示すタグは`<?php`、もしくは`<?=`です。
後者は`<?php echo`とほぼ同じであり、今回のRFCでは一切影響を受けません。

php.iniの設定で[short_open_tag](https://www.php.net/manual/ja/ini.core.php#ini.short-open-tag)を有効にすると、PHPの開始タグを`<?`と省略して書けるようになります。

```php
// 通常
<?php
	echo 'hoge';

// short_open_tag=1ならこう書ける
<?
	echo 'hoge';
```

## Short open tagsのデフォルト値

PHP7.3時点では`1`、つまり初期設定で有効になっている。
ただし、多くの実装系(XAMPPとか)では0と無効にされているようだ。

## Short open tagsの問題点

うっかりXMLをコピペすると死ぬ。

```php
<?xml version="1.0"?>
<?php
	echo 'XMLの中身';
```

このコードは、short_open_tagが有効な場合syntax errorのE_PARSEになります。
short_open_tagが無効であれば普通にXMLが出力されます。

このように、設定によって動作が根本的に変わってしまうので、あまりよろしくありません。

## Remove alternative PHP tags

PHP5時代は、これ以外にも`<%`や`<script language="php">`といった記述でPHPに入ることが可能でした。
それらはPHP7移行の際に、[Remove alternative PHP tags](https://wiki.php.net/rfc/remove_alternative_php_tags)のRFCで削除されました。

が、なぜか`<?`だけは残ったままでした。

## RFC

`<?`をPHP7.4でDeprecatedにし、PHP8で削除しよう、という提案です。
これによってPHPの開始タグは`<?php`と`<?=`の2種類だけになり、とてもすっきりします。


## プルリク

[PHP7.4](https://github.com/php/php-src/pull/3972)ではshort_open_tagのデフォルト値を1から0に変更します。
また有効にすると`Directive 'short_open_tag' is deprecated`のE_DEPRECATEDが発生するようになります。

[PHP8](https://github.com/php/php-src/pull/3975)では設定項目そのものが削除され、有効にすることができなくなります。

## internal

「え？short_open_tag削除して常に有効になるんじゃないの？」
「わざわざ削除するメリットが見当たらない」
「今PHP7で書いてる人はほぼ影響受けないだろうけど、未だにPHP5の人はアプデの障壁がさらに高くなるよ。」
「Facebookでアンケ取ってみたら96%が削除賛成だったよ」
「`<?=`が削除されないんだったらかまわない」

## 投票

2019/04/12時点では、PHP7.4でのDeprecateは賛成17反対9で、このままだと却下されます。
PHP8でのRemoveは賛成19反対9で、このままだと受理されます。


# 感想

PHP7.4でのDeprecateが却下され、かつPHP8でのRemoveが受理されると、それまで使えてたのにPHP8でいきなり削除ってなるんだけどどうなんだろう。
その場合はPHP8でDeprecateになるのかな？

個人的には`<?`は全く使ってないので消してもらって全くかまわないんだけど、その結果vendor配下からDeprecatedが大量発生ってなったりすると困りますね。
かつてPEARでも`Assigning the return value of new by reference is deprecated`が[湧き潰しできず死ぬ](http://yuubiseiharukana.blog.shinobi.jp/Entry/291/)という事件がありましたが、それの再来にならないことを祈りましょう。
拡張索引圧縮（"HIGH"）を試してみたら、クセが強かった

# はじめに

Oracle12cR2でインデックスの圧縮機能として拡張索引圧縮のHIGHレベルが追加されました。
LOWレベルよりも圧縮率が高いということで使ってみようかと調べていたら、以下の記事を見つけました。

- [12.2 Index Advanced Compression “High” Part IV (The Width of a Circle)](https://richardfoote.wordpress.com/2017/03/10/12-2-index-advanced-compression-high-part-iv-the-width-of-a-circle/)

記事を見るとINSERTとUPDATEの性能が大幅に落ちています。どうも圧縮率とSELECTの性能は高いが、INSERTとUPDATE時は厳しいようです。
自分の環境でも同じ結果となるか試してみます。
※翻訳記事ではないので、解説は元の記事を参照してください。


# 非圧縮の場合

まずは非圧縮で試してみます。

```console
SQL> create table bowie (id number, code number, name varchar2(42));

表が作成されました。

SQL>  create index bowie_code_idx on bowie(code) nocompress;

索引が作成されました。

SQL> insert into bowie select rownum, rownum, 'ZIGGY STARDUST'
from dual connect by level <= 1000000;

1000000行が作成されました。

経過: 00:00:02.42

SQL>  commit;

SQL> update bowie set code = 42 where id between 250000 and 499999;

250000行が更新されました。

経過: 00:00:03.34
```

100万行のINSERTに2.42秒、25万行のUPDATEに3.34秒かかりました。


# 拡張索引圧縮のHIGHレベルの場合

次に拡張索引圧縮のHIGHレベルで試してみます。

```console
SQL> create table bowie (id number, code number, name varchar2(42));

表が作成されました。

SQL>  create index bowie_code_idx on bowie(code) compress advanced high;

索引が作成されました。

SQL>  insert into bowie select rownum, rownum, 'ZIGGY STARDUST' from dual connect by level <= 1000000;

1000000行が作成されました。

経過: 00:00:12.82

SQL>  commit;

コミットが完了しました。

SQL>  update bowie set code = 42 where id between 250000 and 499999;
 
250000行が更新されました。

経過: 00:00:12.47
```

100万行のINSERTに12.82秒、25万行のUPDATEに12.47秒かかりました。
非圧縮の場合は100万行のINSERTに2.42秒、25万行のUPDATEに3.34秒だったので、大幅に時間がかかっています。

# 拡張索引圧縮のLOWレベルの場合

参照した記事では試していなかったのですが、拡張索引圧縮のLOWレベルでも試してみます。

```console
SQL> create table bowie (id number, code number, name varchar2(42));

表が作成されました。

SQL> create index bowie_code_idx on bowie(code) compress advanced low;

索引が作成されました。

SQL> insert into bowie select rownum, rownum, 'ZIGGY STARDUST' from dual connect by level <= 1000000;

1000000行が作成されました。

経過: 00:00:02.61

SQL> commit;

コミットが完了しました。

SQL> update bowie set code = 42 where id between 250000 and 499999;

250000行が更新されました。

経過: 00:00:03.80
```

100万行のINSERTに2.61秒、25万行のUPDATEに3.8秒かかりました。
非圧縮の場合は100万行のINSERTに2.42秒、25万行のUPDATEに3.34秒だったので、大きな差はないですね。
※この結果になったのは圧縮がほとんどかからないインデックスだったからかもしれません。
※そもそも複数列のインデックスじゃないと駄目だったような・・・


# 最後に

拡張索引圧縮のHIGHレベルではINSERTとUPDATEの性能が大幅に悪化していましたが、これはHIGHレベルが使えないということではありません（念のため）。
機能の特性をよく理解して、適切な使い方をしないといけないということです。

ちなみにリーフブロック数はそれぞれ以下のようになりました。

無圧縮：2862
LOW：2788
HIGH：1509

今回は勉強になりました。
おわり。
Java(OkHttp)でHTTP通信するときのメモ

##目的
・Javaで実装された処理から、外部APIとHTTPでやり取りしたい
・bodyにXMLを詰めたい
・実装がなるべく簡単なものがいい

##JavaのHTTPクライアントって・・・何を使ったらいいんだろう
ネット上の記事を参考に、
OkHttp(https://square.github.io/okhttp/)
というライブラリを使いました。

```xml
<!-- http client -->
<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp</artifactId>
  <version>3.7.0</version>
</dependency>
```

##実装
例ではXMLをbodyに詰めてAPIをコールし、
APIから返却されるXMLのStringを受け取ってreturnします。

```java
public String callSomething(String xml) throws IOException {
    return new OkHttpClient().newCall(
                new Request.Builder()
                    .url("【通信先URL】")
                    // basic authentication
                    .header("Authorization",
                            Credentials.basic(
                                    "【basic認証user】",
                                    "【basic認証password】"))
                    .post(RequestBody.create(MediaType.parse("text/xml"), xml))
                    .build()
            ).execute()
            .body()
            .string();
}
```

##参考
JavaのHTTPクライアントはどれがいいのか？
https://qiita.com/alt_yamamoto/items/0d72276c80589493ceb4

##追記(2019/08/13)
・都度newするのはよくなさげ
・環境によりタイムアウト時間等を適切に設定する必要性
という点を踏まえて修正しました。

```java
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MyService {

    private OkHttpClient client;

    @PostConstruct
    public void init() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(150, TimeUnit.SECONDS);
        builder.readTimeout(150, TimeUnit.SECONDS);
        builder.writeTimeout(150, TimeUnit.SECONDS);
        client = builder.build();
    }

    public String callSomething(String xml) throws IOException {
        try (Response res = client.newCall(
                new Request.Builder()
                    .url("【通信先URL】")
                    .header("Authorization",
                        Credentials.basic(
                            "【basic認証user】",
                            "【basic認証password】"))
                    .post(RequestBody.create(MediaType.parse("text/xml"), xml))
                .build()).execute()) {
            return res.body().string();
        }
    }
}
```
WPF > 発行バージョンを取得



System.Deploymentを参照して、

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49910/836f9ee4-daba-52ec-68b5-d95139f4a8a6.png)

以下

```csharp
using System;
using System.Deployment.Application;


/// <summary>
/// バージョン番号取得。ClickOnceで実行した時だけ取得される
/// </summary>
/// <returns></returns>
public static string GetClickOnceVersion()
{
    if (!ApplicationDeployment.IsNetworkDeployed) return String.Empty;

    var version = ApplicationDeployment.CurrentDeployment.CurrentVersion;
    return string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build, version.Revision);
}
```
XSLTで平成と令和をソートする

# XML

```
<xml>
 <date>令和2年7月1日</date>
 <date>令和元年3月13日</date>
 <date>平成31年1月1日</date>
</xml>
```

# XSLT
xsltは一文字ずつしか置換できない・・・

```
<xsl:sort select="substring-after(translate(translate(translate(
substring-before(./date,'年'),'和','3'),'元','1'),'令','成'),'成')" />
```

平成と比べるには令和に30足せばよいので、和の字を3にする⇒元の字を1にする。
年と成で切り取れればいいので、令を成に変更する。

```
令和2年　⇒　令32年　⇒　成32年
令和元年　⇒　令3元年　⇒　令31年　⇒　成31年
平成31年
```
年の前の文字、成の後の文字で切り取る。
iOS + Angular + PWA + Firebase storage の環境で画像をアップロードするとエラーになる

表題の環境で、モバイルから写真をStorageにアップするとStorageから下記のエラーが返される。

```
Client uploaded to the wrong offset (262144 instead of 0)
```

これを解消するには、`ngsw-worker.js`の、`onFetch(event)`に下記を追加する。

```
if (event.request.url.indexOf('firebasestorage.googleapis.com') !== -1) { return; }
```

つまり、こんな感じになる

```
        /**
         * The handler for fetch events.
         *
         * This is the transition point between the synchronous event handler and the
         * asynchronous execution that eventually resolves for respondWith() and waitUntil().
         */
        onFetch(event) {
          if (event.request.url.indexOf('firebasestorage.googleapis.com') !== -1) { return; }
```

これで、Storageにアップできるようになった。
DellのNotePCのメモリ増設作業記録

DELL Inspion 15 8GB仕様を買って、8GB増設メモリを買った。
失敗だった。
4GB仕様を買って、8GB増設メモリを買えば良かった。

増設の仕方もよくわからなかった。
課題と成果を記録する。

# 課題１　プラスチックの何？
必要な道具
＋ドライバ（小）
プラスチックのヘラ

Seriaで購入。どっちか迷った。大人買いで両方買った。
<img width="598" alt="ヘラ.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/2a2726c6-e7dd-4207-aeb6-94e65a357de0.png">

結果として、Seriaで買った、プラスチックのねんどへらで間に合った。
平で、幅が狭いものが一番必要。そういうものがあれば、このねんどヘラでなくてもよい。

#課題２　力の入れ具合

恐る恐るやるしかない。

オプティカルドライブの取り外し


ベースカバーの取り外し


バッテリーの取り外し

キーボードの取り外し

<img width="600" alt="note.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/04826258-4c69-f026-71fd-edc4870aaa91.png">

へらで２箇所差し込んで、少しづつてこの原理でこじあける。３箇所目で、半分開いた。
8GBモデルは、4GBメモリが２枚刺さっている。１枚を抜かないと8GBメモリが刺せない。

<img width="599" alt="key2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/f565e6ed-dea2-1d9d-1813-d288686340cf.png">



キーボードを外すと、２つのケーブルがつながっているのが見える。
<img width="597" alt="key3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51423/31e728cf-e130-2ceb-55a9-10df0dda05e9.png">



メモリモジュールの取り外し




メモリモジュールの取り付け

起動した。

ACアダプタは、純正を使っているのに、
知らないと画面に出た。
BIOS Setupをしろとのこと。

メモリを増設したので、BIOS Setupが必要になるかもと思っていたので大人しくBIOS Setup

BIOSSetupを終了してもACアダプタがunknownのまま

検査を起動

数分で終了。

もう一度、検査を起動

数時間かかると表示。

終了。

音声案内で初期設定。

ネットワークのWi-Fiを調べる。

有線でつないだら、ネットワーク設定完了

新機能紹介。

法的確認。

同意。

Microsoft アカウントでサインイン

PINを作成します。
>秒単位で作成できて、高速かつ安全なサインインを可能にするものは何でしょう。Windows Hello PINです。これはご使用のデバイスでのみ機能するもので、Webからは切り離されています。

PINの作成

英字を含めるかどうか選択できる。

iPhone, androi連携

電話番号入力

SMSで送信。アプリのURLが到着。

One Driveでのファイルの保護。

Cortana

アクティビティの履歴を利用してデバイス間でより多くのことを行う

デバイスのプライバシー設定の選択
　広告識別子　いいえ
　オンライン音声認識
　位置情報
　診断データ
　デバイスの検索
　手書き入力とタイプ入力
　エクスペリエンス調整　いいえ

MacaFee
　Yes

# 参考資料(reference)
今朝、Windows 10が起動しませんでした。
https://qiita.com/kaizen_nagoya/items/7abd326181d1458c2832

#文書履歴(document history)
ver. 0.01 初稿 20190411
ver. 0.02 参考資料追記 20190507
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
####  Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
<a href="http://b.hatena.ne.jp/entry/s/qiita.com/kaizen_nagoya/items/2dc00c1e79c740a16869" class="hatena-bookmark-button" data-hatena-bookmark-layout="basic-label-counter" data-hatena-bookmark-lang="ja" title="このエントリーをはてなブックマークに追加"><img src="https://b.st-hatena.com/images/v4/public/entry-button/button-only@2x.png" alt="このエントリーをはてなブックマークに追加" width="20" height="20" style="border: none;" /></a><script type="text/javascript" src="https://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script>
http://b.hatena.ne.jp/guide/bbutton
CSS/JavaScriptでダークテーマに対応する方法 (2019/9更新)

(2019/9/27追記)

iOS13のアップデートにより、ついにiOS Safariにおいてテーマの取得が可能になりました。

---
macOS Mojaveで画面を目に優しい黒基調にしてくれる「ダークテーマ」が導入されました。
それ以降、設定したテーマに色調を追従させるようなアプリが続々と出てますね。
こうなるとWebアプリやWebサイトもテーマに合わせたくなります。
今回、開発しているWebアプリ（テーマ切り替え機能自体は導入済み）でmacOSテーマに追従しようとして方法を調べたのでまとめます。

## CSS Media Queryで取得する方法

Media Queryで利用できるメディア特性として、`prefers-color-scheme`というものがあります。
これはユーザーが明色か暗色のどちらを求めているかを教えてくれます。
つい先日リリースされたSafari 12.1からデフォルトで有効になっており、Firefoxは67から対応となっています。
Chromeは実装作業中のようです。

実際にCSSで表示を切り替えたい場合は以下のようにすれば良いです。

```css
@media (prefers-color-scheme: light) {
  body {
    background-color: white;
    color: black;
  }
}

@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
}
```

実際はこんな感じでCSS変数にまとめると各所の色を一括して変更できるのでおすすめです。

```css
@media (prefers-color-scheme: light) {
  html {
    --primary-color: black;
    --background-color: white;
  }
}

@media (prefers-color-scheme: dark) {
  html {
    --primary-color: white;
    --background-color: black;
  }
}

html {
  color: var(--primary-color);
  background-color: var(--background-color);
}
```

## JavaScriptで変更を検知する方法

初めてテーマを導入する場合は上記のCSSによる切り替えでいいと思います。
ただJavaScriptによるテーマの切り替えと同時に実装したい場合は、現在の状態をJavaScript側で取得する必要があります。
Media Queryでスタイルを切り替えて`window.getComputedStyle`を使って状態を取得する、という方法でも良いです。
が、OSテーマの切り替え時に即座に反応するためにはポーリングしなくてはならなくなり非効率です。

そこでテーマの切り替えをイベントで取得するために`window.matchMedia`を使います。
`window.matchMedia`に通常のMedia Queryの文字列をそのまま渡すと`MediaQueryList`オブジェクトが手に入ります。

```javascript
const mql = window.matchMedia('(prefers-color-scheme: dark)')
```

`MediaQueryList`オブジェクトの`matches`プロパティがMedia Queryがマッチしたかどうかを真偽値で持っているので、

```javascript
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  /* ダークテーマの時 */
} else {
  /* ライトテーマの時 */
}
```

とりあえずこれで状態の取得が可能です。

イベントを受け取るためには次のようにします。

```javascript
// ダークテーマの時にマッチするMediaQueryListオブジェクト
const isDark = window.matchMedia('(prefers-color-scheme: dark)')

// コールバック関数はMediaQueryListオブジェクトを受け取る
function toggleTheme (mql) {
  if (mql.matches) {
    /* ダークテーマの時 */
  } else {
    /* ライトテーマの時 */
  }
}

// イベントリスナーを追加
isDark.addListener(toggleTheme)
```

テーマを切り替えるたびに`toggleTheme`関数が呼ばれ、マッチ状態に応じてテーマの切り替え処理を実行することができます。

今回私が書いた環境のVue.js+Vuexだとこんな感じです。


```javascript
export default {
  name: 'app',
  methods: {
    toggleTheme(mql) {
      if (mql.matches) {
        this.$store.commit('updateTheme', 'dark')
      } else {
        this.$store.commit('updateTheme', 'light')
      }
    }
  },
  mounted() {
    this.$nextTick(() => {
      const isDark = window.matchMedia('(prefers-color-scheme: dark)')
      isDark.addListener(this.toggleTheme)
    })
  }
}
```

これでどんな感じのテーマ機能が実装できるか置いておきます。
左下の月のアイコンがテーマのトグルボタンですが、JavaScript側にも状態が反映されていることがわかると思います。
![CleanShot 2019-04-11 at 20.36.36.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254115/6bfe9635-f78e-6cdd-c305-c89d5b35e832.gif)
Web系開発中に発生した問題の調査方法（初心者向け）

2017年まで商流最底辺の方の客先常駐やってたのにいきなりWEB系自社サービス開発になりました。
開発中の問題調査でよく躓くので調査観点をまとめてみます。
## サーバーログを見てエラー発生個所を調査
まずはサーバーログの確認。
分かりやすくExceptionが発生しているものなら何かしらログがあります。
同じオペレーションでも発生がまちまちだったらアクセスログをみながらレプリケーションが関係しているか切り分けます。
デバッグログを足してクラスやメソッドがどこまで動作していたのかを確認していく。
クラスの開始と終了が分かるようなロガーを設定しておくと調査しやすいです。
## ブラウザの検証ツールを使って通信がどこまで行われてるのか確認する
ChromeだとF12を押すと出てくるアレです。
ネットワークタブを開いて操作をすると通信がどこまで到達しているかとHTTPステータスが確認できます。
また、キャッシュを無効にしてJSなど静的資材を都度読み直すこともできるのでフロントエンドの開発でも使えます。
## 通常とシークレットウィンドウで動作が違うか確認する
セッション情報をクリアな状態にして同じ操作をしてみて違いがあるか比較。
## HttpsとHttpで動作が違うか確認する
使っていたフレームワークのバグでHttpsだと静的資材が読み込めずExceptionが発生するというバグがあったので、プロトコルで違いが出るか見てみるのもあり。
## 開発元のフォーラムでissueが上がってないか調べる
PayaraやJSF等のOSやフレームワークのバグならフォーラムにIssueが上がっているはずです。
ここに同じ事象で困っている人がいないか確認してみましょう。
英語が苦手でもChromeはアドレスバーや右クリックメニューに翻訳機能があるので大まかな内容を知るのに役立ちます。

## 英語のサイトもチェック
↑でも言いましたが日本語記事だけじゃなくて自動翻訳を使って英語のサイトも見てみましょう。
Web開発に限った話じゃないですが日本語だと出てこない情報が結構あります。
（特にStackOverflow。かなりお世話になってます。。）
## その他
他の方も言われてますがなるべく一次情報（開発・制作元のドキュメント、Javadoc等）に一度目を通しましょう。
誰かが意訳した2次情報だと間違っていたり欠けている情報があったりします。
[備忘録]Vueファイル+Prettier(vscode)

# VueファイルをPrettierで綺麗にしたい
.Vueファイルを保存した時に、Prettierでいい感じに整えてほしい

# まずESLintを設定する
setting.json

```
{
  "editor.formatOnSave": true,
  "eslint.validate": ["javascript", { "autoFix": true, "language": "vue" }]
}
```
インストール

```
npm add --dev eslint eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
npm add --dev eslint-plugin-vue
```

`.eslintrc.js`作成

```
module.exports = {
  root: true,
  extends: ['standard', 'plugin:vue/essential'],
  plugins: ['vue'],
}
```


vueファイルでエラーめっちゃ出た
![image.png](https://qiita-image-store.s3.amazonaws.com/0/331389/bdbcef01-2af3-b33a-abc1-380368bd4ed5.png)


:coffee: :coffee: :coffee:


# エラー消すべくPrettierを適応

今エラーが出ている個所をなおしてもらいますー

ESLint のフォーマット機能を Prettier に変更するといいらしい
インストール

```
npm add --dev prettier eslint-config-prettier eslint-plugin-prettier
```

.eslintrc.jsの変更

```
module.exports = {
  root: true,
  extends: ['standard', 'plugin:vue/essential', 'plugin:prettier/recommended'],
  plugins: ['vue'],
  rules: {
    'prettier/prettier': [
      'error',
      {
        semi: false,
        singleQuote: true,
        trailingComma: 'es5',
      },
    ],
  },
};

```

ここまででの設定でESLintとPrettierが競合している・・・？？？
Prettierで直してもsaveしたら元に戻るという事態が発生

setting.jsonに以下追加したらうまくいったよ

```
"prettier.eslintIntegration": true,
"eslint.autoFixOnSave": true,
```

#### (参考)
https://t-kojima.github.io/2018/06/22/0018-using-eslint-prettier-in-vue/
[備忘録]vue-cli3でVue.js

# vue.js
学習コストが低いらしいのでやってみた
個人的にtypescriptでやるのむずくない？？と思いました

# vue-cli3でプロジェクト作る
まずインストールするよ(2.xが入ってる場合はアンインストールしてからインストールする)

```
npm install -g @vue/cli
```
作るよ

```
vue create vue-test-project
```

Manualを選択して作る（全部選択）

```
Vue CLI v3.5.5
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Linter, Unit, E2E
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with node-sass)
? Pick a linter / formatter config: Prettier
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save, Lint and fix on commit
? Pick a unit testing solution: Jest
? Pick a E2E testing solution: Nightwatch
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In package.json
? Save this as a preset for future projects? No
```

雰囲気でやった:ghost:

typescriptやるなら`Use class-style component syntax? Yes`
`ESLint`もtsに対応してるぽい
node-sassを使う場合にはnode.jsに依存するので注意が必要
Swiftのイニシャライザ

久しぶりにSwiftのイニシャライザを復習したので、そのときに思ったことや新たに知ったことを、**つれづれなるままに**書いていきます。つれづれなるままなので「〜思います」系の表現があります。
環境はSwift5.0です。

#2つのクラスに継承関係があるとき、サブクラスのinitでは、親のinitを呼ぶ前に自分のところで定義したものを初期化するのはなぜか

```swift
class A1 {
	var name: String
	
	init() {
		print("super")
		name = "unknown"
	}
}

class B1: A1 {
	var age: Int

	override init() {
		print("sub")
		super.init() //エラー Property 'self.age' not initialized at super.init call
		age = 0
	}
}
```
上の例ではB1のageが初期化されていないとエラーが出ます。初めてこの仕様を見たときは不思議な感じがしました。親を固めて（初期化して）から子を固めるべき、そう感じたからです。
しかし、B1のageが初期化されていない使い方が許されると、次の例ではサブクラスが固まってないのにサブクラスのsomeFunction()が呼び出されてしまうので、こういうのを防ぐ理由もあるかなと気が付きました。

```swift
class A1 {
	var name: String
	
	init() {
		print("super")
		name = "unknown"
		someFunction()
	}
	
	func someFunction() {
		print("super someFunction")
	}
}

class B1: A1 {
	var age: Int
	
	override init() {
		print("sub")
		super.init()
		age = 0
	}
	
	override func someFunction() {
		print("sub someFunction")
		super.someFunction()
	}
}
```

#2つのクラスに継承関係があるとき、親のコンビニエンスinitと同じ引数のinitをサブクラスで指定initとして定義するときの挙動

今回いろいろ調べていてわかったことがあります。誤解を恐れずに書くと
2つのクラスに継承関係があって親が指定initとコンビニエンスinitを持つときに、サブクラスで親と同じ指定initを定義しないで、サブクラスでその指定initが自動生成されると同時に親クラスのコンビニエンスinitも自動生成される条件が整った状況で、親クラスのコンビニエンスinitと同じ引数のinitをサブクラスで指定initとして定義すると、例えばoverrideをつけるように催促するエラーが出ることもなく、コンパイルが通る
です。

```swift
class A2 {
	var name: String
	
	init(name: String) {
		print("super 1")
		self.name = name
	}
	
	convenience init() {
		print("super 2")
		self.init(name: "unknown")
	}
}

class B2: A2 {
	
	init() {
		print("sub")
		super.init(name: "unknown")
	}
}

var b2 = B2()
//出力
//sub
//super 1
```

#2つのクラスに継承関係があって親の指定initが2つあるとき、サブクラスでその片方をコンビニエンスinitとして定義するときの挙動

わかったことの2つめは
2つのクラスに継承関係があって親クラスが指定initを2つ持つときに、その片方と同じ引数のinitをサブクラスでコンビニエンスinitとして定義すると、もう片方の指定initは自動生成されて、サブクラスで定義したコンビニエンスinitはoverrideをつけるように催促され、overrideをつけるとそのコンビニエンスinitからself.init()で自動生成された指定initが呼び出せる
です。

```swift
class A2 {
	var name: String
	
	init(name: String) {
		print("super 1")
		self.name = name
	}
	
	init() {
		print("super 2")
		self.name = "unknown"
	}
}

class B2: A2 {
	
	convenience override init() {
		print("sub")
		self.init(name: "unknown")
	}
}

var b2 = B2()
//出力
//sub
//super 1
```

#おわりに
*** で詳しく書いてあります。などの情報があれば、よろしくおねがいします。
ogr2ogrでRFC 8142 準拠のGeoJSONSeqを出力する

[RFC 8142 をベクトルストリームのワイヤフォーマットに使う理由](https://qiita.com/hfu/items/8e88561788063ec3624a)を受けて、その生産方法を考えました。

ogr2ogr 2.3 以前の場合 ( jq がインストール済みであること)

```
ogr2ogr -f geojson /vsistdout/ 入力 | jq -c ".features[]" | sed 's/{"type":"Feature"/\x1e{"type":"Feature"/g' > 出力.rfc8142
```

やっていることは見てのとおり

GeoJSONにして
改行区切りGeoJSON Feature (いわゆるndjson)にして
フィーチャーオブジェクトの直前にRSコードを付与


ogr2ogr 2.4 以降であればRFC 8142準拠のGeoJSONSeqに直接対応しているので

```
ogr2ogr 出力.geojsons 入力
```

だけでよい。ogr2ogrはRFC 8142準拠のGeoJSONSeqの拡張子は .geojsons であるとする立場のようです。
別の拡張子にしたいなら

```
ogr2ogr -f geojsonseq -lco RS=YES 出力.rfc8142 入力
```

-lco RS=YES がないと、RSコードのない改行区切りGeoJSON Feature、いわゆるndjsonになります。
プログラミング学習記録54〜確率〜

##今日やったこと
今日は昨日の続きをやりました。

条件付き確率について学びました。
条件付き確率の問題を解いたのは、高校の時以来だったのですが、やっているうちに思い出せてよかったです。

もともと数学の中でも確率の分野が好きだということもあり、楽しくできました。
講義内で取り上げられている問題がよかったです。

「ある病気の感染者の割合は全人口の１％で、検査キットの誤判定率（感染しているのに陰性と誤判定する確率２％、感染していないのに陽性と誤判定する確率３％）という前提で陽性と判定された人の内、本当に感染している確率は何％ですか？」

という問題です。

事象Aを感染者である、事象Bを検査判定「陽性」であるとして、ベン図を書いて整理するとわかりやすいです。

感染している人の中で陽性の人、陰性の人がどれくらいいるのかを考えます。

そして、感染していない人の割合（100%-1%=99%)を出して、非感染者の中でも陽性の人、陰性の人がどれくらいいるのかを考えることで、本当に感染している確率が求められます。

答えは約25%となります。

この答えを見て「意外と低いな〜」と思いました。

誤判定の確率が２、３％しかないにも関わらず、「陽性と判定されたうちの４人に１人」しか実際に感染している人はいないということです。

なんとなくでしか誤判定の確率を見ていなかったら、陽性と判定された時点で「ああ、感染してしまったんだな〜」と尚早に判断してしまうのかなと思います。

数字は物事を客観的に判断するにはもってこいのものですが、この例のような表面の数字には現れないものをありうることを考えると、なんとなくで判断しないほうがいいこともあるんだなと思いました。

<br>
しばらくプログラミングとはちょっと離れたことについて学んでいますが、一通り済んだらまたプログラミング学習に戻りたいと思います。

おわり
Watson NLUサンプルアプリ紹介

# はじめに
久しぶりにWatson APIの記事です。
Watson NLU(Natural Language Understanding)のデモをしようと思い、[サンプルアプリケーション](https://cloud.ibm.com/docs/services/natural-language-understanding?topic=natural-language-understanding-sample-apps#sample-apps)のページを見ました。
いろいろ面白そうなものが並んでいる中、自分で動かしてみようと選んだのが、上から2つめの[構造化データと非構造化データをリンクしてお勧めを生成する](https://developer.ibm.com/patterns/generate-insights-from-multiple-data-formats-using-watson-services/)でした。
IBM Code Pattarnは面白いものが多いのはいいのですが、コードが古くて動かなくなっているものがあるのが玉に瑕です。
このサンプルもその例に漏れず、何カ所かトラップがありました。そのトラップを乗り越え、最後まで動くコードを作りましたので、コメントを日本語に変えた上で連携します。
(しかし結果が合っていないのでどこかにまだバグがあるようです)

修正後のNotebookはこちら[NLU-demo-matching.ipynb](https://github.com/makaishi2/sample-data/blob/master/notebooks/NLU-demo-matching.ipynb)です。
以下では、サンプルを動かすための手順を簡単にご紹介します。

[2020-04-25] セットアップ手順修正

# 手順
基盤的準備

(1) Watson StudioでJupyter Notebookが動く環境を作ります。
手順は
[無料でなんでも試せる! Watson Studioセットアップガイド](https://qiita.com/makaishi2/items/b666f847a98c2e42dfbb)
を参照して下さい。

(2) NLUのインスタンスを作ります。
認証情報はしらべておいて、テキストエディタにコピペしておきます。

(3)以下のgitリポジトリをcloneかzipダウンロードします。
[https://github.com/IBM/generate-insights-from-data-formats-with-watson](https://github.com/IBM/generate-insights-from-data-formats-with-watson)

(4) ダウンロードしたファイルのうち、data配下の3つのファイル(``sample_config.txt, Data.csv, data_files.zip``)をStudioのData Assetとしてアップロードします。

(5) Jupyter NotebookのファイルをURLリンク[https://raw.githubusercontent.com/makaishi2/sample-data/master/notebooks/NLU-demo-matching.ipynb](https://raw.githubusercontent.com/makaishi2/sample-data/master/notebooks/NLU-demo-matching.ipynb)から作ります。

(6) Notebookファイルに修正を加えます。
3箇所のセル自動生成と書かれているところは、下の図のように修正先セルにカーソルがある状態で、対象のデータアセットから右ボタンクリックでコード生成を行います。修正が必要な箇所は、都度指示に従ってコードを修正します。

![スクリーンショット 2019-04-11 18.02.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/03d76649-8eb3-0177-f0b5-5c76c4fa53eb.png)

![スクリーンショット 2019-04-11 18.05.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/45ea5528-902f-4522-52c4-cec5b6adae7a.png)

![スクリーンショット 2019-04-11 18.08.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/c38326e5-041a-a626-beb8-75d7b3b4845e.png)


NLUの認証情報を設定するセルは、事前のコピーしたapikeyの値を``iam_apikey``の値として指定します。

後は、セルを上から順番に実行していけば、サンプルアプリが動くはずです。実行結果の画面の一部を下にアップしておきます。

![スクリーンショット 2019-04-11 20.06.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/08d02e89-f8c0-894b-61ae-2612aee4c65e.png)

![スクリーンショット 2019-04-11 20.07.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/08af73d7-b30f-8a85-249f-c45a9fecda49.png)
windowsでPythonを使ってローカルサーバーを立ち上げる

こんにちは
[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)
でインターンをしているodattiです。

Pythonを勉強を始めたところです。
ローカルサーバーを立ち上げることは初心者にはとても難しく、そもそも**「何が分からないのかが分からない」**という方も多いのではないでしょうか。

そこで、ローカルサーバーを立ち上げる方法について、復習がてら書いておきます。
使用しているパソコンは、windows10、64bitのレッツノートです。

#準備
[Python](https://www.python.org/downloads/release/python-373/)をダウンロードします。
ご自身が使っているパソコンの種類に合わせて適切なものをダウンロードしましょう。
(Pythonのセットアップに関しては省略させていただきます)

#Powershellを立ち上げる
windowsにはpowershellが入っていると思います。
パソコンで検索して、起動しましょう。
ちなみにpowershellとは、簡単に言うとパソコンに命令を送るツールです。

#Pythonが入っていることの確認
ここからはpowershellを使っていきます。
Pythonが正しくインストールされているかの確認を行います。
(Pythonを起動してprint(~)を実行する方法とは別)

```powershell
 
python -V 
```
上のように打って実行し、ダウンロードしたPythonのバージョンが表示されればOK！
(ちなみに、Vはversionの略)

#以下のコマンドを入力
次のようにコマンドを入力します。
###mkdir
```
mkdir
```

mkdirとはmake directoryの略です。
ディレクトリ(パソコン上のファイルや管理情報のこと)
を作りなさいっていうコマンドです。

###cd

```
cd web
```
change directoryの略。
ディレクトリを移動しなさいという意味。


最後に


```
python -m  ~~.server
```
このコードの解釈がわかりません。。
例えば~~の部分にhttpを入れればhttpサーバーを起動するということだと思います。
(ほかの例がわからないので、教えていただけると嬉しいです。)

これでローカルホストのサーバーを立ち上げられたかと思います。

#終わりに
間違っている部分や表現も多々あるかと思います。
ご指摘をいただけると嬉しいです。
すぐに修正します。