それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

サイト内検索を duckduckgo に切り替え

google のサイト内検索がどうもおかしい

記事はあるはずなのに、記事が出て来ない。

これが一定期間をすぎると検索結果から外されるというものでしょうか。

自分の過去記事をアーカイブとして利用しているとどうも、記事が見つからないことが増えてきた。

duckgo に試験的に変えてみる。

duckduck go でサイト内検索を設置するときは次のようにする

<form action="https://duckduckgo.com/">
  <input type="text" name="q">
  <input type="hidden" name="sites" value="example.com/sites">
  <button type="submit">Search</button>
</form>

しばらく様子を見てみたい。

参考資料

https://coderwall.com/p/0euadw/site-search-form-with-duckduckgo

gitでブランチ名を名前変更したい / ローカル branchのrename

git で ローカルブランチをtypo したとき、名前を変えたい。

isssue とか ちょっとした名前のミスであれば、名前の変更をしたい。

また、masterを直接更新 から git checkout -b name でブランチを後付で更新したいときに、名前をミスると、名称の変更が速い時がある。

ローカルのブランチの名前変更(1)

カレントブランチ(今いるブランチ)を変更

git branch -m  新しい名前

ローカルのブランチの名前変更(2)

変更前のブランチと変更後のブランチを指定して変更

git branch -m '古い名前'  '新しい名前'

branch -m / -M

ちなみに -m の m は移動の m です。rename というより コマンドのmv だと思ったほうがいいでしょう。move だと覚えておけば覚えやすいし忘れないです。

       -m, --move
           Move/rename a branch and the corresponding reflog.

       -M
           Shortcut for --move --force.

branch -m がおぼえられないひとむけ

何度やっても - m が覚えれない人は、ショートカットに登録しましょう

~/.gitconfig

[alias]
  rename-branch = branch -m

参考資料

man git-branch

git ブランチ作成と削除(ローカル)

git の使い方

今回は、git branch の操作方法。

ブランチは、もう説明が不要なくらい浸透してて嬉しい。

ブランチの作成と削除という基本概念をメモします。

ブランチ作成

今いるブランチから作成する

git checkout -b ブランチ名

いろいろあるけど、まずこれを覚える。

ブランチ削除

git branch -d ブランチ名

名前を指定して消します。

ブランチの一覧

git branch 

これでブランチ名がわかるので、ここから必要なものを消します。

でもめんどくさいの一括して消したいですよね・・・。

マージ済みのブランチをすべて消す。

git branch --merged | \grep -Ev  '\*|develop|master' | xargs git branch -d

git flow でよく使う maste /dev と、 いまのブランチ名* name だけを除外して全部消す。

alias に登録する。

これらを覚えたら。、一括して削除するコマンドをショートカットに登録する。

[alias]
   delete-merged = "!func () { git branch --merged| egrep -v  '\\*|master|develop' |xargs -I@  -t git branch -d @; }; func;"
git delete-merged

これで瞬殺できるから、お掃除できて楽ちん。

参考

man git branch

gitサーバのgogs を使うことに

github だけがgit webじゃない。

git をWEBで閲覧するのには、github 以外にも git serverとして gitweb でもなんでもある。

gitlab は要求水準が高いし、prometheus がCPU食いまくる、またgitlab は複数のドメインで運用が面倒だ。*1

gitlab を複数インスタンス入れるのも面倒な話だし。マルチドメインをできないのなら、別のgit web を探すことにして。 gogs に目をつけた次第です

gogs インストール

gogs は go で書かれたgit サーバー

packager を使うのが早い

https://packager.io/gh/pkgr/gogs/builds/689/install/ubuntu-16.04

パッケージでインストールする。

wget -qO- https://dl.packager.io/srv/pkgr/gogs/key | sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/gogs.list \
  https://dl.packager.io/srv/pkgr/gogs/pkgr/installer/ubuntu/16.04.repo
sudo apt-get update
sudo apt-get install gogs

設定ファイルが作られる

インストール完了したら、次の設定が作られる。

/etc/gogs/conf/app.ini

適当に設定ファイルを編集。

再起動

systemctl status gogs
systemctl restart gogs
systemctl status gogs

また、すでに起動しているので、インストーラーにアクセスしたいところがだが、MySQLを要求するので、先に作っておく

DB 作成

apt インストールが完了したら、あとは、DB設定とユーザー作成して登録する。

Gogs はMYSQLのDBを要求するので、MYSQLにテーブル作成ようにユーザーとDBスキームを作っておく

takuya@sakura:~$ mycli -u root
mysql root@(none):(none)> create database gogs
mysql root@(none):(none)> create user "gogs-user" identified
mysql root@(none):(none)> create user "gogs-user" identified by "**************";
mysql root@(none):(none)> grant all on gogs.* to 'gogs-user'@'%';
mysql root@(none):(none)>

接続テスト

ローカルホストと通信して、接続を確認する。

curl locahost:6000/install 

リモートなら、SSH の ポートフォワーディングでいいわ

ssh gogs-server -L 8080:localhost:6000
open localhost:8080

インストールして初期ユーザを作ったら準備完了

初回登録ユーザーが「管理者」

「1番目」のユーザーが自動的に管理者になり、2番目以降は通常ユーザーになる。

これは最初「アレレ、管理者設定どこ?」って思って勘違いしてググりまくって苦労した。2番目以降の通常ユーザーに管理者フラグを立てると管理者になれる。

メールの設定とポートとSSL

メール送信の設定とかを入れて、再起動する

あとは他に、ポート指定したり、nginx にSSLのポートなどを設定。起動ウイザードで設定する

最後に、pull / push の sshhttps のNATなしのポートをなどを設定して準備完了。

PAM / LDAP が使える

Gitlab で認証連携のコレらをやろうと思うと有料版など面倒なのだが、ユーザーの管理に PAM(/etc/passwdなど PAM対応してる認証機構ならなんでも) や LDAP(DN) とSMTPが使える。PAM対応してるのが熱い。

PAM対応があると、sshMySQL と共通のID/PWでユーザーを管理できるので、保守性が高くて複数インストールしても苦なく使える。

軽快

とても軽快で使いやすい。もっさり感もなく、要求スペックは高くない。

git の認知に関する愚痴など

「git は使いたいけどgithub はちょっと。」とか「github が導入できないから git 導入に苦労する」とかいう言説はまやかしである。SFTPでもSMB/Cifsやでも使えるのであるから。git は「分散」レポジトリであることを忘れて中央サーバーが必須だと思いこんでる人の多いことといったら。

github にアクセスできなくてもgit は使えるしソースコードの管理もできる。なんなら今回のようなgogs など git server をオンプレで立ち上げてもいい。

github イコール git と思いこんでる言説が多くて困る。

*1: X-Original-Host を見てくれればいいのにな。

Nature Remo mini を買ったのでローカルAPI叩いてリモコンのデータを取得してみる

未来の家に。

我が家も、スマート・ホームへの進化をします。スマートリモコン(学習型IR)で音声操作や外出先から操作するのは、小さい頃からの夢でした。でも一朝一夕で実現するわけでもないので、少しずつ準備をしていました。

Remoがやってきた

買いました。

早速APIを叩いてみます。

API を叩く前に、一通りの初期設定は終わっているものとします。 1. 開封する 2. 接続する 3. 登録する 4 .とりあえずなんかOn/Offは出来てる。

ローカルAPIでできること

  • GET / 最後に受信した、赤外線リモコンの波長(信号)の記憶を取得します。
  • Post / 任意の赤外線信号を指定して、それを発光して送信します。

つまり、これさえあれば、仮にNature Remo の運営会社が今すぐ倒産したとしても、Raspiなどから直接Curlでリモコン信号を叩けるわけです。 iOSのアプリが提供されなくなっても、WebUIからプロセス起動すれば動くわけです、やったね。

購入後、自己責任において、自由に使えるソフトウェアとハードウェアは本当に嬉しい。

ローカルのAPIへアクセスします。

curl  'http://Remo-1XXXXXX/messages' -H 'X-Requested-With: curl  ' -v

まだなにも出てきません。404 になると思います。

Remoに赤外線リモコンを受光させます。

Remoへ向かって赤外線リモコンを発光します、Remoが青色に反応したらOKです。

再度ローカルAPIを取得します。

curl  'http://Remo-1XXXXXX/messages' -H 'X-Requested-With: curl  ' -v

JSONが返ってきます。

返ってきたJSONの構造

次のようなデータが返ってくる。

{
  "format": "us",
  "freq": 37,
  "data": [
    8991,
    4505,
    550,
    1689,.... 
    525
  ]
}

ここで注目するべきは、 data 属性の値。

この値は、毎回同じにならない。たとえ同じリモコンで同じボタンを使って送信しても。同じにならないのだ。これは時間分解能の限界なので仕方がない。

ただ、比率は毎回ほぼおなじになっている。先頭2つは16T/8T ないし、8T/4T の整数倍に近い値になっている。

先頭2つは、その信号の補正でベースとなる波長の時間間隔Tを求めることができる。

リモコンデータをリピートする

取得したリモコンのデータをそのままオウム返ししてあげれば、まぁそのまま使える。

 cat power-on.json | curl-norc -X POST 'http://192.168.2.216/messages' -H 'X-Requested-With: curl' -d @- -vp://

リモコンのデータを解析

日本の家電の多くは、次のような仕様に基づいて、0/1 のバイナリデータ信号のオンオフ時間によって制御している。

先頭2つの時間合計を12で割ってみて、24で割ってみて、誤差を丸めてやり、時間T(変調単位)をもとめて、残りのペアをTの整数倍としてみてみる。

より1:1、1:3の整数値に近い方のTをみつければ、12/24のいずれかででNECとAEHAがわかるはずである。

f:id:takuya_1st:20190722225015p:plain

赤外線リモコンの通信フォーマット

今回、アイリスのLEDリモコンで試してみた。

仕様によれば、先頭の2つから、Tを求めて、あとはその整数倍のペアが出現するはずである。(赤外線の照射時間Tと整数比を測定するわけで、受光器の精度はmsである。機器は所詮整数倍しか見れない精度であろう。とすれば有効桁数は1桁の計測器である。2桁まで除算で計算し、それを整数値に丸めてやる)

import sys
import json

obj_txt = sys.stdin.read()
obj = json.loads(obj_txt)

code = obj['data']
data = ""
t = int((code[0]+code[1])/24)

data = [ [ code[i], code[i+1] ] for i in range( 2, len(code)-1,2) ]
data = [ [ round(code[i]/t), round(code[i+1]/t) ] for i in range( 2, len(code)-1,2) ]

print(data)

実行結果は次のようになった。

[[1, 3], [1, 1], [1, 1], [1, 1], [1, 3], [1, 1], [1, 3], [1, 1], [1, 1], [1, 3], [1, 3], [1, 1],...]

ここで、仕様を見ると、 [1,1] (すなわち [1T,1T] ) は 0 を示し、[1,3] は 1 を示す。 これを使って0/1 にマッピングしてやり、2進数表記を得たら、4ビットずつ16進数表記にしてみた。

import sys
import json

obj_txt = sys.stdin.read()
obj = json.loads(obj_txt)

code = obj['data']
data = ""
t = int((code[0]+code[1])/24)

data = [ [ code[i], code[i+1] ] for i in range( 2, len(code)-1,2) ]
data = [ [ round(code[i]/t), round(code[i+1]/t) ] for i in range( 2, len(code)-1,2) ]
data = [ "1" if e == [1,3] else "0" for e in data ]
data = [ "".join(data[i:i+4]) for i in range(0,len(data)-3,4)  ]
data = [ int(e,2) for e in data  ]
data = [ format(e , 'x') for e in data  ]
data = "".join(data)

print(data)
cat led-on.json | python decode-LED.py
8a6e0800800036

あとは、これをボタンごとに調べてやると、ボタンごとの差異が明確になるはずである。

さらに、ボタンごとの差異から、リモコンでは実装されてないOn/Offが見つかる可能性もある。

さらに、この整数値を時間間隔に書き直してRemo経由で発光してあげれば、照明のリモコンとして動作する。

といってもアイリスのLEDはプリセットに含まれているので、ここまで計算する必要も無い。これ以上は時間の都合上やる意味もないが、もし非対応のリモコンが出てきたときにどうやってデータを取得するかだけメモを残しておく

残念なことに

ローカルAPIでは、リモコンの送受信、つまりGET/POSTしかできないようです。

関連商品

Nature Japan Nature Remo REMO-1W2

Nature Japan Nature Remo REMO-1W2

参考資料

Nature Remoに存在しないボタンを登録する - 暇な女子高専生のブログ

curlコマンドで ~/.curlrc の設定を有効無効を切り替える

curlrc でよく使うオプションを入れておくと便利

curl でよく使う設定をまとめる ~/.curlrc - それマグで!

便利なのですが、ついつい入れすぎてしまって、いざというときに不要なファイルを消せない。

どういうことかというと、~/.curlrc が存在してると最優先でそれを使うので。

解決策 Aliasなどと組み合わせる

alias curl-with-json=curl -q -K ~/.curl-json.conf
alias curl-with-my=curl -q -K ~/.curl-my.conf

その他の解決策

必要のないときだけ、デフォルト値を明示して使う。

alias curl-ddefault=curl -q -K ~/.curl-my.conf

ポイント

curl で curlrc を「使わない」ときは -q を先頭にかいて --config/-K を その次に書く

curl -q --config /dev/null

参考

man curl

すぐわかる標準エラー出力と標準出力の捨て方( /dev/null へリダイレクト

だれですか ' &1' なんてファイルを作ったのは。

サーバーにログインしてみてたら'1' っていうファイルがあるんですね。1という名前のファイルがあるんですよ。

どう考えても、リダイレクトに失敗してますよね。

標準エラー出力を捨てる速攻で覚えるの書き方

command  &> /dev/null

bash ならもうこれだけ覚えてほしい。

個別に指定する場合

個別に指定する方法が一番基本なのでこれをまず覚えてほしい。

commdn  2>/dev/null  >/dev/ null

アンパサンド(&) の指定でミスるなら

もう、アンド使うなといいたい。

DoH:DNS-over-HTTPS なサーバーを作って試す。

DoH サーバーを作って問い合わせをちょっとだけ秘密にする。

DNS によるブロッックングが2019 上半期の一番の話題だったと思う。DNSブロッキングはUKで実際に運用されていたり、法制度化されているので本邦でも導入するべきと言った論調だった。児童ポルノでも一定の成果を上げているしーみたいな?まぁお手本にしたUKや中共ではプライバシー保護の議論は常にあるし、我が国も早晩、プライバシー保護と監視の両立を迫られることになる。その際にブラウザがDoHで問い合わせを保護する方法は重要に担ってくると思う。

DoH DNS over HTTPS を体験してみる

DoH を体験しておけば、問題点や課題が少しでもわかるのではないでしょうか。そうおもって使ってみることにしました。

DoH なサーバーを作る

DoH は中間にめっちゃいろいろ挟まるので、最初に概要だけ書いておきます。

dns-https クライアント → Webサーバー(ssl処理) → dohプロキシ → unbound(DNS問合せ)

DoH プロキシは 今回、python のpip で導入します、多種実装があります。

ブラウザ→WEBサーバのSSLはLetsEnctyptで導入されているものとします。*1

DoHプロキシの準備

インストール先を作って pipenv 環境を整える

target=/var/www/virtualhosts/dns.example.com/doh
mkdir -p   $target
cd  $target
pipenv install 
pipenv run pip install pip --upgrade
pipenv run pip install doh-proxy

pipenv は導入されているものとします。

doh を起動します。

pipenv run doh-httpproxy --level DEBUG \
  --upstream-resolver 192.168.1.1 \
  --listen-address=127.0.0.1 \
  --trusted=127.0.0.1 \
  --port 8053

ここでは、DoH プロキシを起動しています。

--upstream-resolver 192.168.1.1 では、DoHプロキシがDNSの実レコードを問い合わせるリゾルバを指定(ルータとか unbound とか ISP DNSとか public DNSとか)

--listen-address=127.0.0.1 --trusted=127.0.0.1 --port 8053 では、DoHがリッスンするIP/ポート。さらに信頼するHTTP中間プロキシのIPを記述

https する nginx の設定例

httpsTLS通信を nginx に任せることにするので、該当のWEBサーバの記述を作ります。

nginx ではSNIでドメイン名を受け取り、それを先程のDoHサーバーに転送します。

# vim: ft=nginx ts=2 sw=2 sts=2

server {

  server_name  dns.example.com;

  add_header  X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";

  listen 443 ssl http2;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

  if ($scheme = http) {
    return 301 https://$server_name$request_uri;
  }


  location /dns-query {
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect off;
    proxy_buffering off;
    proxy_pass http://127.0.0.1:8053;
  }
}

設定ができたら、リロード再起動

sudo nginx -t && sudo service nginx reload

最後に接続確認

nginx とdoh-プロキシの準備と起動すべてが終わったら。接続してみる

pyenv run doh-client --domain dns.example.biz --qname t.co --qtype a

応答例

2019-07-16 15:10:13,417:    DEBUG: Opening connection to dns.example.biz
2019-07-16 15:10:13,423:    DEBUG: Query parameters: {'dns': 'AAABAAABAAAAAAAAAXQCY28AAAEAAQ'}
2019-07-16 15:10:13,424:    DEBUG: Stream ID: 1 / Total streams: 0
2019-07-16 15:10:13,428:    DEBUG: Response headers: [(':status', '200'), ('server', 'nginx/1.10.3'), ('date', 'Tue, 16 Jul 2019 06:10:13 GMT'), ('content-type', 'application/dns-message'), ('content-length', '293'), ('cache-control', 'max-age=378'), ('x-robots-tag', 'noindex, nofollow, nosnippet, noarchive')]
id 0
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
t.co. IN A
;ANSWER
t.co. 378 IN A 104.244.42.133
t.co. 378 IN A 104.244.42.5
t.co. 378 IN A 104.244.42.69
t.co. 378 IN A 104.244.42.197
;AUTHORITY
t.co. 12577 IN NS ns1.p34.dynect.net.
t.co. 12577 IN NS ns2.p34.dynect.net.
t.co. 12577 IN NS d01-02.ns.twtrdns.net.
t.co. 12577 IN NS c.r06.twtrdns.net.
t.co. 12577 IN NS ns3.p34.dynect.net.
t.co. 12577 IN NS a.r06.twtrdns.net.
t.co. 12577 IN NS b.r06.twtrdns.net.
t.co. 12577 IN NS ns4.p34.dynect.net.
t.co. 12577 IN NS d01-01.ns.twtrdns.net.
t.co. 12577 IN NS d.r06.twtrdns.net.
;ADDITIONAL
2019-07-16 15:10:13,432:    DEBUG: Response trailers: {}

サーバーのログの例

curl 単体接続で見れないの?

専用クライアントを経由して見てますが、curl で問い合わせるには、hexdump して base64エンコードしないとダメなので、そのままでは見られなかった。

curllocalhost:8053 でdoh-proxy と直接通信する例。

 echo -n 'q80BAAABAAAAAAAAA3d3dwZnb29nbGUDY29tAAABAAE=' | base64 -d \
\
 | curl -s -H 'content-type: application/dns-message' \
 'http://localhost:8053/dns-query' \
  -H 'X-Forwarded-For: 127.0.0.1'\
  --data-binary @-| hexdump -C \

ハッキリ言ってめんどくさい。

https://www.secjuice.com/modsecurity-web-application-firewall-dns-over-https/

Firefoxで使ってみる

手早く試すには、Firefox でDoHサーバーを使うのが良いと思います。

わかったこと

443ポートでSNIするから、ポート53が必要なくなる。通常のWEBと同じくHTTPSドメイン名で待ち受ける事ができるので便利。443の用途がまた増えてしまった。

HTTPSをするので改竄やオレオレが難しい。クライアントは安全になる。

DoHプロキシとUnboundの通信は暗号化されないし丸見えで従来どおり。全く今までどおり。

対応クライアントがFirefoxくらいしか無い。iOSが対応したら嬉しいな.

ただし、nginx で待ち受けてるDNSホスト名の名前解決には、従来どおりのDNSが必要。ここで詐称される可能性はあるがHTTPSで改ざん検出は可能かもしれない。しかし証明書の確認のためにCRL引っ張りに行くのもまたDNSが・・・ああエンドレスリピートは変わらない。

一般市民が、public DNS経由でブラウザを使うだけならかなり安全になるかと思う。

2023-06-05

記述ミスを修正

参考資料

https://facebookexperimental.github.io/doh-proxy/tutorials/nginx-dohhttpproxy-unbound-centos7.html

*1:めんどくさければCloudfrontとかのhttpsCDN挟んでください。

amazonの検索結果からボッタクリ価格業者を消す方法 をiOS でも使えるようにショートカット.app にした

iOSブックマークレットの代わりに'ショートカット.app' を使う。

経緯;Amazonガチャにもうヘトヘト

Amazon の商品検索から、中華出品者のゴミを消したい。プライムで返品可能とはいえ、もうAmazon中華ガチャに疲れた。海外サイトで購入するより、返品ができるとの理由でAmazonで買ってガチャを引いていた。 AliexpressやeBay での返品不能のリスクを減らすためにプライムに加入しているが、もう外れ多すぎてガチャ引くのに疲れた。

Amazon 以外の出品者を削除する

Amazon以外の出品者を除外する(つまり、出品者がAmazon JP なものだけに絞ることができる)

次の出品者コードに限定することで実現する。

&emi=AN1VRQENFRJN5

internet.watch.impress.co.jp

iOS で使えないじゃん

世の中にはブックマークレットがあるけど、iOSではBookmarkletが動かないので、iOS の 'Shortcuts.app' にシェアボタンで渡せるようにしました。

Amazonが出品してる商品に絞る←インストールはこちらから

f:id:takuya_1st:20190716142812p:plain:w200

使い方

Amazonを開いて

f:id:takuya_1st:20190716143002p:plain

シェアボタンからショートカットを呼び出し、

f:id:takuya_1st:20190716143008p:plain

該当のショートカットプログラムを起動する

f:id:takuya_1st:20190716143013p:plain

きれいになる!!

f:id:takuya_1st:20190716143021p:plain

おお素晴らしい!!

中身の概要

単純に replace text して、Safariで開き直すだけ。

f:id:takuya_1st:20190716143412p:plain

関連資料

http://n-styles.com/main/archives/2017/04/14-054444.php

https://www.icloud.com/shortcuts/793e333499d4408c8b6ca868af14e330

アレな出品を一括除外? Amazonの検索結果をクリーンにできる「魔法の文字列」が話題に【やじうまWatch】 - INTERNET Watch

https://twitter.com/takuya_1st/status/1150825108925083651

jq コマンドで UTF-8 の文字列をデコードやエンコード(codepoint を元に戻す)

コードポイントなった、日本語を単純に元のUTF-8に戻したり、コードポイントでエスケープして符号にする。

コードポイントになった文字列*1

単純に jq に通せば、日本語になる。

何も考えずに、 jq 通せばコードポイントを読める文字にすることができる・

root@acid:~# cat out | \jq - '.dir'
~/ダウンロード

逆に、コードポイントのママほしい

-a オプションをつけて、ASCIIにエンコードするとちゃんと出てきます。やったね。

root@acid:~# cat out | \jq -a  '.dir'
"~/\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9"

*1:正確にはエンコード・デコードという用語が正しくないかもしれない

jq コマンドなどで、JSONハイフン付のキーを取り出す方法

jq ではハイフンに意味がある

オブジェクトのキー名にハイフンが混じるとエラー

$ cat out | jq - .download-dir
jq: error: dir/0 is not defined at <top-level>, line 1:

なぜ?

だってJSってハイフンは引き算じゃん?

こう書いてしまうと、

obj.config ={".download-dir": "~/Downloads"}

obj.config.download-dir # あ!?

どう考えても、引き算じゃん?

obj.config.download-dir
(obj.config.download - dir)  // え?

なので、JSONにハイフンの引数を入れるのはあまり推奨されないけど、JSONを単なるシリアライズだとか、データ保存形式とか、設定ファイルだと思ってる方々はついついやりがちなのです。

jq ではクォートか、ハッシュアクセスを使う

jq でも同じです。ちゃんとクォートつけるか、「 [] 」 でアクセスする

# cat out | jq -ra '."download-dir"'
~/Downloads
root@acid:~# cat out | jq -ra '.["download-dir"]'
~/Downloads

だめな例

おかしがちなだめな例。

これは、ダブルクォーテーションマークが、Bashに解釈されるときに外されて jq まで届かない。

# cat out | jq -ra ."download-dir"

これは、jq がシェル経由という落としな穴。

JSON は意外な落としな穴がある。

何でもかんでもJSONってやめたほうが良いよまじで。手入力とか設定ファイルにはホント向いてないから。

手作業に向いてないってことはデバッグとかで、データ取り出しが本当に煩雑。

忘れ去られゆくキーボード・ショートカット1 タブキーによる項目移動

キーボードショートカットが日本では忘れ去られようとしている

いつの頃からか、キーボードを使うのは「悪」という監査が蔓延っているようです。キーボードから直接入力することが危険だそうです。

f:id:takuya_1st:20190706170308p:plain ローソン銀行の例

絶滅危惧種のキーボード・ショートカット:タブキー

いまや絶滅危惧種になってしまった。「タブキーを知りません」と「入力時に押したことないです。」という人は、90%を超える(個人調べ)だろう。

自称:情強の情報系学生でも、タブキーを単体で殆ど使っていません。Alt+TabやCtr+Tabだとまだ使われているが、タブキー単体で押す人は殆ど皆無だと思われる。

タブキーはフォーカス移動

タブキーによるフォーカス移動を知らないのである。というかフォーカスを概念として知らない。

タブキーとエンターは組み合わせで使うものなのですが、「マウスカーソルを移動しクリック」だけが正しい操作だと倣っているのでしょう。タブキーをおしてエンターを押せません。

アプリケーションやウェブブラウザの入力項目はタブキーで移動することができます。エンターで選択することができます。

しかし、jQuery などで実装されたモーダルウインドウには「全く」これらのことが配慮されていません。タブでフォーカス移動もできない、Enterでクリック代替をすることもできません。中途半端な実装のモーダルウインドウのライブラリは滅びていいと思います。

また、jQeury で実装されたフォーム項目には対象項目を非表示のママ実装されているものがり、タブ移動ができない入力フォームが数多くあります。残念なことです。

タブキーが実装されている例

Twittertweet フォーム。

f:id:takuya_1st:20190706170827p:plain

f:id:takuya_1st:20190706170810p:plain

タブキーが忘れ去られると困ったことになる。

タブキーは「ハンディキャップ」の人たちにも大変有益だと思う。バリアフリーを声高に叫ぶ割に、身近なキーボードのキーを使わないまま配慮を忘れ去られゆく。

駐車場に車椅子のスペースを作るのと同じくらいWEBサイトや入力フォームにおけるTabキーは重要です。完全に愚痴でしかないが、日本では本当に軽視されていて、できれば政府が主導してガイドラインを定めるべき案件です。日本政府がいかにIT無能かわかるのではないでしょうか。

iOS にはタブキー相当の「入力項目の移動」があります。

iOS を見てみると、タブキーと呼ばずに「上下」の項目移動があります。これがPCのキーボードのタブに相当します。ところがほとんど認知されていません。悲しい限りです。

f:id:takuya_1st:20190706171951p:plain

さらにひどい悲しい事実として知ってほしい。この「入力項目の移動ボタン(タブキー)」が邪魔で消したいという人が後を立ちません。Q&Aサイトではよく質問で上がってきます。利用者からだけでなく、開発者のQ&Aサイトでもクライアントに言われたから消したいとう書き込みを何度か見かけたことがあります。

タブキーという呼び方が「ブラウザのタブ」とかぶる

タブキーという呼称が、残念なことに、ブラウザのタブと同じ音で同じスペリングのために、タブについて調べることが事実上不可能になっています。

また、タブといっても伝わらないので、タブキーと言わないと伝わらないことが多いです。これも希少化に拍車を掛けているのではないでしょうか。

タブはインデントだと思われている

「タブキーはインデント」のためにあると思いこんでいる人も多い。タブといえば、スペースとタブで宗教論になることも多いです。そのためタブで項目移動は忘れ去られゆく。

海外のサービスはWEBでもSPAでも比較的Tabキーを実装している

Slackなどもタブキーで項目移動をきっちり実装してたりします。tabindex を無視するスタイルなのは、日本の大手企業のWEBサイトによく見られます。イオンとかセブンとかローソンとか。

もしかしたら海外ではちゃんとdisabled people に対して配慮しているのか、スピード狂のためにTABキーを実装するのが文化として根付いてるかもしれない。

タブキーによる項目移動の使い方:tabindex

タブキーはフォーカス移動をして使うものです。

TABキーとShift+TABキーがペアで使われます。決定はEnter(またはSpace)を押します。

フォーカスを外したいときはESCです。

タブキーとESCとEnterはペアで使います。

これだけです。

開発者は、フォームの項目にtabindex を入れれば良いのです。入れなくても左上から順番に項目が選ばれます。フォーカスしたくない(ちょっと隠してたりdisabledなinput) なら -1 をいれてタブフォーカスを無効にすれば良いわけです。

このブログを書いているはてなブログでも、編集画面にはタブキーによるtabindex の項目移動は実現できていません。

Windows もTABキーを忘れようとしている。

Windows10から搭載された設定画面とエクスプローラーでは、以前ほどタブキーを使えないことが多いです。彼らもタブキーの存在を忘れてしまったのでしょう。

タブキーの存在

私達は、タブキーによる項目移動とフォーカスという概念を徐々に失っていると思います。

わたしとタブキーの出会い。

私は、タブキーをいつから使っているか思い出せません。パソコンを使い始めたのが2005 年ごろなのでそれ以降であることは間違いないです。ノートPCにして、マウスを捨てたのが2010 年頃なので、多分その頃から本格的に使ってると思います。

いまでは、タブキーで「はい・いいえ」を移動したり、「キャンセル」を押したり、入力フォームを手早く移動したり、無くてはならない存在ですが、徐々に使えない箇所が増えていて悲しい。

タブキーが使えると早いのに

タブキーが使えると入力が圧倒的に早くなります。RPAとかバズワードが飛び交ってますが、自動入力と定形入力の高速化より、まず入力者であり操作者であるわたしたちがタブキーによ入力高速化をしたほうが良いと思う。しかしそうなっていないのが少し残念。

多く人はタブキー忘れてしまったのでしょうか。

Windowsエクスプローラと設定もタブキーで操作しにくくなり、ウェブのjQuery モーダルはタブキーが動かず、iOS では邪魔者扱い。Excel入力でもタブ移動より矢印カーソルやマウスが好まれる。はてなブログでもタブキーで右側メニューを選べない。

このままタブキーによる項目移動は絶滅していく運命にあるのでしょうか。

タブキーめっちゃ使うよ!!って人がいたらコメントくだされば嬉しいです。

メールアドレスの入力が、@マークで分割された場合の簡単入力

誰が考えたか知らないが、謎文化のメアドを区切る文化

f:id:takuya_1st:20190706160501p:plain

入力がかったるくて仕方ない。思考するより速く入力したいスピード狂としてはストレスを感じる

ストレスを感じるより、プログラミングして解決したほうが気持ちがいい。

対策した

そこで、XpathBookmarklet を組み合わせて対処することにした。

(function(){
  maddr = []
  email = window.prompt("メールアドレス?", "");
  maddr = email.split(/@/);
  
  mail_inputs = [];
  ret = document.evaluate("//*[ count(./input[ contains( translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'email') ]) = 2 ]//input", document );
  while ((input = ret.iterateNext())) {
      mail_inputs.push(input)
  }
  mail_inputs.forEach( function(e,i){
    e.value = maddr[i%2]
  } )
})()

実行結果

メアドを貼り付ければ、簡単入力ができる。はー楽。

f:id:takuya_1st:20190706161757p:plain

f:id:takuya_1st:20190706161823p:plain

自動入力という概念がないSI'er世界。

これは愚痴なのですが、日本語の企業サイトには、「自動入力は悪」という概念があるようで。手入力より自動入力のほうが間違いが少ないっていう記述を見かける。 本当に何を考えているのかわからないし。フォームを分割したところで、ヒューリスティックな対処法でしかなく、経験則によりサポートコストが減るというのなら、リーンスタートアップ的にいえばA/Bテストで比較するべきなのである。フォーム項目を増やしても工数が増えるだけだし、RichUIとかUXとか言ってたりフォームをデザインするデザイナは、もっとA/Bテストをプッシュするべきだと思います。

関連記事

謎フォームの入力に苦労したので解決した話など

Xpath の contains で大文字小文字を区別しない(no case / insensitive match)

世の中には、@アットマークで、メアドを区切るという謎文化があります。

「メールアドレスをご入力ください」ただし、アットマークの前後を分けて。フォームの入力がすごくめんどくさいものがあります。

もっと手軽に入力したくてBookmarkletで対処するんだけど。大文字小文字を区別するのがめんどくさい

f:id:takuya_1st:20190706160501p:plain

*1

大文字小文字を区別しない、Xpathの例

$x("//*[ count(./input[ contains( translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'mail') ]) ]//input")

ポイント

ここで、先に大文字小文字を全部小文字にして丸める。

translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')

その後に、マッチさせる。

 contains( translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'mail')

これで、大文字小文字を考えないマッチングができる。

ほんと、Xpathって便利ですね。世間は、もうCSS セレクタばっかり使っってるだろうけど、私は、未だにXpath手放せないや

参考資料

https://stackoverflow.com/questions/8474031/case-insensitive-xpath-contains-possible

*1:こんなことをしてるの、日本語の大手企業のサイトだけで。これやるとIT能力低いことの暴露だと思うんですけど

我々のDNS問い合わせは監視されている。

ACTIVEに基づく通知が来た。

この日、私は実験目的でヤバそうな各種DNSを引いていたのですが、その結果ががこれである。

どのURL(ドメイン)がフィルタリングされたか全くわからないし、ACTIVEの対象ドメインが完全非公開なので怖いなと思った。

フィルタリングされてるかされてないか、比較するためにも各種テクニックは知っておいたほうが良いな

そのうちIPアドレスで停止されるんだろうけど、通信監視とは怖い世の中だ。

f:id:takuya_1st:20190701171753p:plain

f:id:takuya_1st:20190701171756p:plain