ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

iOS 版 Chrome の <input type="date">

解決策とかわかったら書きますが、なんなんでしょうかこれ?

iOSChrome の input type="date" 入力時、何かの条件を満たすと Picker から「消去」が消える


ScreenRecording 07 03 2018 01 51 23

  • iOS 11.4
  • Google Chrome: 67.0.3396.87 (Official Build) stable (64 ビット)

WebAssembly って?

ブラウザからアセンブリ言語を実行できる仕組みが WebAssembly という理解です (雑魚)。

とりあえず、動かしてみます。

Emscripten

C/C++ から WebAssembly で実行可能なアセンブリコンパイルするツールだそうです。C/C++ に特に思い入れはなく、仕事で使ったことはないですが、例えば C/C++ で書かれたライブラリを JavaScript ライブラリに変換するとかできるのかなーと思います。

C/C++からWebAssemblyにコンパイルする を参考に emscripten をインストールします。(すっごい時間かかりますね)

使う

適当な cpp ファイル (main.cpp) を作成します (これ c といってもいいのでは)

#include <stdio.h>
#include <emscripten/emscripten.h>

extern "C" {
  int main()
  {
    puts("Hello, World");
  }

  int myFunction(int x)
  {
    return ++x;
  }
}

em++ main.cpp -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']" -s EXPORTED_FUNCTIONS="['_main', '_myFunction']" を実行します。ここでは

  • クライアント側から関数を呼び出す Module.ccall を使用するために EXTRA_EXPORTED_RUNTIME_METHODSccall を指定します。
  • 呼び出せる関数を EXPORTED_FUNCTIONS で指定します。関数名に _ プレフィックスをつけなければいけないそうです。

以下のファイルが生成されました。

  • a.out.js
  • a.out.wasm
  • main.cpp

index.html を作成してそこから a.out.js を読み込みます。

<html>
  <head>
    <script src="a.out.js"></script>
    <script>
      function callMyFunction() {
        var count = document.getElementById('count')
        var nextCount = Module.ccall('myFunction', 'number', ['number'], [count.innerText])
        count.innerText = nextCount
      }
    </script>
  </head>
  <body>
    <p>Count: <span id="count">0</span></p>
    <button onclick="callMyFunction()">Call C++ Function</button>
  </body>
</html>

しかしこれでは動きません。http 経由で配信しなければいけないそうです。express で配信するようにします。yarn init && yarn add express でサーバーを準備します。index.js を以下のように記述しました。

var express = require('express');
var app = express();

app.use(express.static('public'));

app.get('/', function(req, res) {
  res.sendFile(__dirname + '/public/hello.html');
});

app.listen(3000);

またディレクトリ構造を少し変えます。コンパイルしたものは public 以下に放置しています。

.
├── index.js
├── node_modules
├── package.json
├── public
│   ├── a.out.js
│   ├── a.out.wasm
│   ├── index.html
│   └── main.cpp
└── yarn.lock

サーバーを node index.js で起動すると localhost:3000 でアクセスできるようになます。

f:id:ushumpei:20180619104114g:plain

感想

また何かに入門だけしているやつです

Pro Git 2nd Edition 読んでる

最近手が痛くてプログラミング時間を少々減してて、久しぶりに本でも読もうかという気分になっています。

git ちゃんとわかっていなかったので、 Pro Git 2nd Edition を読み始めました。ちょっと面白いことがあったのでメモします。

前提: git は差分ではなくファイルのスナップショットを保持している

git が既存の VCS (Version Control System) と大きく異なった点として、ファイル変更履歴の管理方法が 変更されたファイルの差分ではなく変更されたファイル全体のスナップショット であることだと書かれています。自分の理解だと、ファイル容量などを考えると変更差分を保持していた方がいいと思いますが、ぶっちゃけテキストファイルが主だしまあスナップショットでも大丈夫なんだろうなー、くらいの軽い感じでした。しかしこのことが結構重要で、 git がめちゃくちゃ速い理由につながっているようです。

リポジトリ内のファイル全体のスナップショットが作成されるのは commit 時で、次の要素が .git/objects 以下にファイルとして作成されます。ファイル形式は blob でファイル名はそのデータのハッシュ値です。

  • blob オブジェクト: 変更後のファイル
  • tree オブジェクト: ディレクトリツリー。変更対象のファイルを持っていたディレクトリに対して、ツリーのノードの参照先 (tree, blob オブジェクトのハッシュ値) を書き換えた tree オブジェクトが作成される。(毎回リポジトリルートの tree は更新される)
  • commit オブジェクト: 新しく作成されたリポジトリルートの tree への参照と、parent commit オブジェクトへの参照と作成者情報やコミットメッセージ。

言葉だとややこしいですが実物は以下のようになります(ハッシュ値は適当です)。

blob オブジェクト: .git/objects/f5/83c304ea36b6fa554eb01381e781b04e45477f

# Pro Git

URL: [https://git-scm.com/book/ja/v2](https://git-scm.com/book/ja/v2)

tree オブジェクト: .git/objects/20/4bfe00b89a265e7c16e8688a90dfb86e52c5eb

100644 blob f583c304ea36b6fa554eb01381e781b04e45477f README.md

commit オブジェクト: .git/objects/31/ba323616cc8cbc543882c5a4eef6aa95eef803

tree 204bfe00b89a265e7c16e8688a90dfb86e52c5eb
author ushumpei <mail@example.com> 1528220889 +0900
committer ushumpei <mail@example.com> 1528220889 +0900

Initial commit.

(.git/objects 以下のファイルは git cat-file コマンドに -p オプションをつけてハッシュ値の頭から 6 文字を引数にして実行すると、中身を閲覧することができます: .git/objects/f5/83c304ea36b6fa554eb01381e781b04e45477f なら git cat-file -p f583c3)

要するに?

要するに私が面白いと感じたのは、特定のコミットに入っているファイルを取り出したいときは、commit オブジェクトのハッシュを使って、

commit オブジェクト -> tree オブジェクト -> (ツリーの探索) -> blob オブジェクト

という風に取り出してくれるので、めっちゃ速い、すげー、ということです。これは過去のコミットでも、分岐してある程度進んだブランチのコミットでも同じように行われます。(多分)

感想

「git 速い」って何と比較して、というと svn なのですが、ベンチマークとか取っていないので (どう比較するか謎ですが) 怒られそうですね。「考え方の変化で処理が変わった」ということにテンションが上がっただけです。

React 360 で vnc クライアントを作って Oculus Go のブラウザから自分のPCを見る (未完成)

注意: チラシの裏です

こんにちは

Oculus Go に Mac 用のリモートデスクトップがなかったので (現在: 2018/05/31) なんとかできないかと思って色々やっています。理想的には HMD つけながら無線キーボードでお布団に入りながらコーディングしたいという思いがあります。

でも全然完成までの道のりが見えないので、現状の整理のためのメモを書きます。

(これ以降進展なし)

なんで作ってるんですか?

Oculus Go で使える Mac 用のリモートデスクトップアプリが見つからなかったためです (有料のやつある?)。ブラウザで画面共有できる Web サービスもあるのですが、仕事のコードとか書くことを考えるとローカルネットワークで完結するのが気分的に一番良いんじゃないか?と思ったため作り始めました。(自作すること自体はそれはそれでリスクですが)

Mac にはデフォルトで「vnc」と呼ばれる (?) リモートデスクトップのサーバーが入っているため、それ用にクライアントのコード書いたら良いんじゃないか、ということで vnc 周りを調べつつ作っています。

なんで React 360 なんですか?

  • Android studioAndroid Mobile SDK: C++ 混じってて読めなかった
  • Unity: 入ってるけど使ったことない
  • React 360: 既存の知識使ってできる

という消極的な理由からです。 1 週間くらいで終わらせたかったのでがっつり学習する必要があるものは避けました(終わってないけど)。今考えると Unity は空間すでにあるし知見も多いため一番良い気がしてます。

どんな感じで作りますか?

  • Mac
    • 8080 port: http で React 360 のページを返すサーバー
    • 5900 port: 標準の vnc サーバー
    • 5901 port: websockify というライブラリを使用して WebSocket の 5901 への接続と、 vnc の 5900 への接続をつなぐ

という構成を元に、

  1. 同じローカルネットワーク内のブラウザから WebSocket で Macvnc サーバーと接続
  2. vnc サーバーから送られてくる画面データを React 360 内の canvas に描画
  3. ブラウザのキー入力やポインター移動イベントをサーバーに通知する

していくように作っています。

できたこと

  • React 360 の平面オブジェクト (Plane) に canvas を貼り付ける
  • RFB 3.8 プロトコル (vncプロトコル) を実装してサーバーとの接続を確立する
  • ブラウザでサーバーから画面データを受信する
  • 受信したデータを canvas に描画する

できてないこと

  • ブラウザのイベントをサーバーに通知する
    • ブラウザ -> サーバー への通信は、初めはいらないと思っていたんですがユーザーのサインインが必要なので、ないとログイン画面を延々とみていなければならなくなります
  • 画面が全更新になっているので差分更新で済むようにしたい

どうします?

  • RFB プロトコルのコードを整理する
    • RFB プロトコルが接続を確立するまでに複数回のやりとりが必要になるのですが、全てのメッセージを長い onmessage で受け取っていろんなフラグで if else と長々と書いているので破綻してる
    • ドメインの知識が増えて来たのでちゃんと書いてみたい
    • Redux を React 以外の文脈で使ってみたい
    • オレオレイベント emitter 消す
  • React 360 を一旦やめる
    • canvas を貼り付けた Plane の取り扱いが不安定すぎるので単純な html として書き直します (PC めちゃくちゃ熱くなるし)
      • React でも良い気がするけど
        • ブラウザ vnc クライアントの vnc.js とかあるっぽいけど

一応リポジトリ: GitHub - ushumpei/VncClient: Vnc client for browser

感想

遊んでないで仕事探す

既存の Laravel プロジェクトに自動構文チェックを軽く入れる

Laravel 始めました。今回はコードの自動構文チェックをすごく軽く入れる話。ゆくゆくは CI に含める予定だけどまだその時間と根回しがないので簡単にやります。

どんな効果を狙っているか?

  • レビューにおいて構文に関する指摘が大半を占めているのでその時間を削減する
  • 構文に関する規約が暗黙知化しているので (レビューで指摘が多く上がる原因のひとつ)、規約を管理できる構成にする
  • 書くのが面白そう!

どんなものを作るか?

  • git のプレコミットフック (git/hooks/pre-commit) で追加/変更したコードの構文チェックをして、違反していたらコミットできなくする (コミットできない、はやりすぎか?)
  • 違反している箇所については構文チェックライブラリのエラーを出す (変更行だけチェックできないか? -> 今回はできなかった...)
  • 緊急時のためにフックを無視する手段も作っておく(すでにプレコミットフックとして仕組みがある? -> --no-verify option)
  • プレコミットフックがない環境に影響を与えない (まあ多分 pre-commit 配置しなければ良いだけと思う)
  • 構文チェックのルールはファイルで管理できるようにする (構文チェックライブラリが標準で備えているはず)
  • とりあえずチェック対象は、jsphp (当面は拡張子によって判定)

準備

使うものとしては以下を考えています

  • phpcs (PHPCodeSniffer)
  • eslint

Laravel と言っていますが、git 使ってれば応用効くと思います。それぞれ composer , npm (or yarn) で開発環境の依存ライブラリとして入れます。

(これらがそもそもグローバルインストールされている状態だとどうなるんだろう…?それも忘れずに確認しなきゃ…)

pre-commit 作ってみる

まずは何も構文チェックライブラリ入れずにフックだけ作成してみます。処理の流れとしては、 git commit を実行した直後に、pre-commit が呼ばれ、スクリプトの戻り値(?) が 0 以外の時に commit が停止されるというものです。

.git/hooks/pre-commit

#!/bin/sh

echo hoge
exit 1

また、スクリプトの実行権限を 755 に変更しておきましょう。

$ touch fuga
$ git add .
$ git commit
hoge

とりあえず commit 時にフックが実行されるのがわかりました。あとは処理を書いていきます。

対象ファイルの抽出

git のコマンドを使用して HEAD との比較で、追加、更新があったファイルを取得します。コードは以下のようになります。

#!/bin/sh

# Get against commit hash to compare.
if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Redirect output to stderr.
exec 1>&2

# Get added and modified files.
files=`git diff-index --cached --name-only --diff-filter=AM ${against}`

echo ${files}

比較結果は files に、スペース区切りの文字列で入ってきます (配列として取り扱うかどうかは悩みましたが、特に必要ないので git diff-index ... の戻り値をそのまま使います。)

ここでは --diff-filter=AM によって追加 (A)、更新 (M) のあったファイルのみを抽出しています。削除やリネームしただけのファイルはチェックしません。 (削除ファイルやリネームファイルのチェックは、自分が書いたわけでも無いファイルの構文を直せということになり、プロジェクトの整理作業に負のモチベーションを与える気がします。)

exec 1>&2 は標準出力をエラー出力にリダイレクトしています。このスクリプトで出力が行われることは、即ちエラーだからです。 (と偉そうにいってますが、この行までは全て .git/hooks/pre-commit.sample から盗んできたものです。)

対象ファイルを拡張子で分類

ここまでくると特別なことはありません。シェルスクリプトを書くだけです。

...
# ↓チェック対象のファイル取得後の処理

# Check syntax.
is_error=0
output=""

php_files=""
js_files=""
for f in ${files}
do
  extension=${f##*.}
  case ${extension} in
    php)
      php_files+="${f} "
    ;;
    js)
      js_files+="${f} "
    ;;
  esac
done

if [ -n "${php_files}" ]
then
  output+=`phpcs ${php_files}`
  is_error+=$?
fi

if [ -n "${js_files}" ]
then
  output+=`eslint ${js_files}`
  is_error+=$?
fi

if [ ${is_error} -gt 0 ]
then
  is_error=1
  echo "${output}" | less
else
  is_error=0
fi

exit ${is_error}

これで一応、複数ファイルに対してまとめて構文チェックを行えるようになりました ( 上のスクリプトは構文チェックコマンド入っていないと動かないですが )。出力が流れてしまうので、構文エラーに関しては less に渡して表示するようにしています。色々思うところは以下かなと思います。

  • 文字列連結の半角スペースがダサいので配列使うべきでは?
  • 拡張子ごとにほぼ同じ処理を書いているので、新しい構文チェック追加時に変更大きいよ?

本当は、構文チェックライブラリに変更対象ファイル全部渡して、そっちでフィルタリングしてほしいという気持ちなので今の所シンプルすぎるくらいがちょうどいいのかなと思います。

phpcs, eslint の設定

phpcs

開発環境の依存パッケージに PHPCodeSniffer を追加します。

composer require --dev 'squizlabs/php_codesniffer'

phpcs./vendor/bin/phpcs に入っているのでスクリプトからはそれを読むことにします。

phpcs は実行時に --standard= オプションで使用するルールや設定ファイルを指定することができます。そのほかにも設定ファイルを phpcs.xml という名前で作成しておけば自動的にそのファイルを読んでくれるようです。(自分ディレクトリから親のディレクトリを順に登って行って phpcs.xml を見つけたら使用してくれるみたいです)

PSR2 を継承しつつ色々調整できるように雛形 phpcs.xml を作成してみました。

<?xml version="1.0"?>
<ruleset name="MyRule">
  <description>Coding standard based on PSR2 with some additions for my project.</description>
    <!--
      You can add your rules below.
      For example, you can include new standard, like that;
      <rule ref="PEAR" />

      If you want to know more about phpcs,
      See: https://github.com/squizlabs/PHP_CodeSniffer/wiki
      See also to know the notation of this file: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml
    -->

  <!-- Include the whole PSR2 standard -->
  <rule ref="PSR2">
    <!--
      You can exclude specific standard by adding exclude_tag and name_attribute here;
      <exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace" />
    -->
  </rule>
</ruleset>

次は .git/hooks/pre-commit で、ローカルのコマンドと、設定ファイルのパスを使うようにスクリプトを修正します。(設定ファイルは存在チェックだけ必要としています)

app_root_path=`git rev-parse --git-dir`/..
phpcs=${app_root_path}/vendor/bin/phpcs
phpcs_config=${app_root_path}/phpcs.xml

## Execute check.
### PHP
if [ -n "${php_files}" ]
then
  # Check installation of phpcs.
  if [ -e "${phpcs}" ]
  then
    # Check existence of cording standard file.
    if [ -e "${phpcs_config}" ]
    then
      # For upgrading rule file, add -s option to display rule's name.
      output+=`${phpcs} -s ${php_files}`
      is_error+=$?
    else
      output+='\nNOTE: phpcs configuration file is not found. going to check based on psr-2'
      output+='\n'
      output+=`${phpcs} --standard=PSR2 ${php_files}`
      is_error+=$?
    fi
  else
    output+='\nNOTE: phpcs is not installed. php syntax checking is skipped.'
  fi
fi

うん、すごく読みにくい気がします。他の構文チェックする前にシェルスクリプトの構文チェックしろよ的なブーメランですね。

phpcs.xml が見つかった時だけ -s オプションを渡してルール名を表示しておいてあげます。ルールファイルの修正の障壁にならないためにも。

ファイルがないときは何もしない、コマンドがないときはお知らせ、設定ファイルあるときはそれで実行、ないときはPSR2で実行という流れです。

eslint

急に疲れてきてしまったのですが、だいたい phpcs と同じになります。こちらのインストールは yarn add --dev eslintnpm install --dev eslint で行います。

開発環境の依存性でインストールされた後は、初期の雛形ファイルを作成します。 Use popular style guide などで適当に js ファイルとして作っておきました。(ファイル形式も pre-commit でみなきゃいけないかもしれないけど今は js 決め打ちで行きます)

$ yarn add --dev eslint
$ ./node_modules/.bin/eslint --init
$ ls .eslint.js
.eslint.js
$ yarn # init 後にもう一回パッケージのダウンロードが必要...

先ほど同様に .git/hooks/pre-commit を修正します。変更内容みたい方いましたら github でご確認ください。 pre-commit (すみません疲れてしまいました)

まとめ

shell じゃなくて php か js で書けばよかったのではと今更ながら思います。特に制御構文の省略記法とかどれを使っていいか悩んでしまい、ものすごくベタに書きました。それこそ構文チェックが必要な気がします。

まあ、ないよりはマシか、、、という気持ちで書きました。最低限動いたら後は使いながら修正していけばいい、という言い訳をしておきます。