動かざることバグの如し

近づきたいよ 君の理想に

Chrome拡張機能で特定のHeaderのときだけブロックする方法

Chrome拡張機能はすごくて、chrome.webRequestのイベントを駆使すると特定の条件のURLをブロックしたり、リダイレクトすることができる

以下はexample.comを含む画像を白紙にするコード 画像かどうかはtypesの「images」で見てる

var pattern = "https://example.com*";

function redirect(details) {
  console.log('blocked', details.url);
  return {cancel: true};
}

chrome.webRequest.onBeforeRequest.addListener(
  redirect,
  {urls:[pattern], types:["image"]},
  ["blocking"]
);

が、↑のようにchrome.webRequest.onBeforeRequest.addListener()は実はURLしか条件に入れることが出来ない だからヘッダーを見て〜のときはブロック、といったことができない

解決策

Headerを見れるchrome.webRequest.onHeadersReceived.addListener()を使う

以下はサイズが1MB以下のJPEG画像をブロックする例

'use strict';
function blockImages(details) {
  var responseHeaders = details.responseHeaders;
  var flag = 0;
  for (var i = 0; i < responseHeaders.length; i++) {
    if (responseHeaders[i].name.toLowerCase() == 'content-length') {
      if(responseHeaders[i].value < 100000) {
        flag++;
      }
    }
  }
  for (var i = 0; i < responseHeaders.length; i++) {
    if (responseHeaders[i].name.toLowerCase() == 'content-type') {
      if(responseHeaders[i].value == 'image/jpeg') {
        flag++;
      }
    }
  }
  if(flag == 2) {
    console.log('blocked', details.url);
    return {cancel: true};
  } else {
    return { responseHeaders: responseHeaders };
  }
}

chrome.webRequest.onHeadersReceived.addListener(
  blockImages,
  {urls: ['https://example.com*']},
  ['responseHeaders', 'blocking']
);

なんでわざわざfor文で回しているかって話だが、responseHeadersはヘッダー名前がそのままKeyになってくれないので何番目かわからない。よって回すしかない。。。

ちなみに監視対象URLをすべてにする場合は

urls: ['<all_urls>'],

とすればいい

Rubyで複数のバージョン(version number)をソートしたい

かなりニッチなニーズかもしれないけどメモ

やりたいこと

例えば以下のようなバージョンの配列があったとして

versions = ["1.1", "2.0", "1.1.4", "1.6", "2.4.1"]

これを古→新順にソートしたいとする

解決策1 ライブラリを使う

探したらあった なんとGithub

irb(main):002:0> versions = ["1.1", "2.0", "1.1.4", "1.6", "2.4.1"]
=> ["1.1", "2.0", "1.1.4", "1.6", "2.4.1"]
irb(main):003:0> VersionSorter.sort(versions)
=> ["1.1", "1.1.4", "1.6", "2.0", "2.4.1"]

ちゃんとソートできている

解決策2 Gem::Versionを使う

どういうこっちゃって話だけど見たほうが早い

irb(main):004:0> versions = ["1.1", "2.0", "1.1.4", "1.6", "2.4.1"]
=> ["1.1", "2.0", "1.1.4", "1.6", "2.4.1"]
irb(main):005:0> versions.sort_by { |v| Gem::Version.new(v) }
=> ["1.1", "1.1.4", "1.6", "2.0", "2.4.1"]

このGemクラスは特にインストールとかしなくても使えるっぽい。

docs.ruby-lang.org

もともとGihtubもRubygemのホスティングしてたっぽいし中身は実は同じなのかもしれない。。。。

NodejsでファイルからMD5ハッシュを取得したい

md5はこういうの

~/tmp $md5 tmp.wav
MD5 (tmp.wav) = a7b3e6a4865d0b5ae39db05371008c2a

をNodejsで求めたい

環境

  • nodejs 8
    • けど見てる感じ4以上なら動きそう 10でも動いたし

コード

const crypto = require("crypto");
const fs = require("fs");

function md5file(filePath) {
    const target = fs.readFileSync(filePath);
    const md5hash = crypto.createHash('md5');
    md5hash.update(target);
    return md5hash.digest("hex");
}

console.log(md5file('./tmp.wav'));
~/tmp $node md5.js
a7b3e6a4865d0b5ae39db05371008c2a

あってるっぽい(当然

参考リンク先でも言及されてるが、〜GB単位のファイルを扱う場合だとfs.readFileSync()が死ぬ(多分メモリに乗せるので

それも考慮した作りにしたい場合はfs.createReadStream()でストリームを扱う(以下リンク先に丸投げ

参考リンク

sedコマンドで正規表現を使う場合は注意が必要

結論

発端

例えば以下のようなテキストファイルがあったとして、

~ $cat /tmp/sample.txt
1a
2b
3c
4a
5b

「a」を含む行を一括削除したいとする。以下のコマンドで可能

~ $sed -e '/a/d' /tmp/sample.txt
2b
3c
5b
  • -e のあとに条件式を書く(省略した場合は第一引数が条件になる)
  • /dは置き換えではなく削除の意味

仕様が変わって、「a」に加えて「b」を含む行も削除したいとする。

するとこうなる。

~ $sed -e '/a/d' /tmp/sample.txt | sed -e '/b/d'
3c

sedコマンドの仕様上、-e を連続して書けば複数条件式を指定できるので、以下のほうが好ましい

sed -e '/a/d' -e '/b/d' /tmp/sample.txt
3c

例なので単純だが、複雑な条件式だった場合正規表現で記述したほうがシンプルな例もあると思う

sed -E '/[a|b]/d' /tmp/sample.txt

だがこのコマンドは動くsedとエラーになるsedがある

どういうこと?

そもそもsedコマンドで確実に使える正規表現は以下のみ(正確にはPOSIX 1003.2で規定されているsed)

で、GNU sedでは↑に加えて以下も利用可能 つまり拡張版ってわけ

拡張対応済み(GNU sed)のバージョンなら動くが、バージョンやビルドオプション等によって動いたり動かなかったりする(実際同じOS,sedコマンドのバージョンでも挙動が違った)

さっきの sed -E '/[a|b]/d' /tmp/sample.txt は拡張側に含まれる正規表現パターンだったのでNGだったわけ

対策

対策1

正規表現を使わないで愚直にいく

対策2

POSIX 1003.2で規定されているsed正規表現パターンのみ使う

のでさっきの例だと

~ $sed -E '/(a|b)/d' /tmp/sample.txt
3c

になる (カッコが[]から()へ変更)

なんかgrepコマンドでも同じ状況にハマった気がするけど、気をつけよう。。。

対策3

自分でsedコマンドをビルドしてmake install

えへへ

参考リンク