ひらい ぶらり Hi-Library

ぷろぐらみんぐについて。ときどきどうでもいいことについて。

エレコムの5ボタンマウスをMacで使う

マジックトラックパッドやら色々つかって一周回って安物5ボタンマウスにもどってきました。 エレコムのマウスには「エレコム マウスアシスタント」というユーティリティがあり、これで5つあるボタンに機能を割り当てられます。 親指の位置に当たる、ボタン4,ボタン5にはブラウザの「戻る」と「進む」を割り当てたのですが、これが上手く動作しない。

Cmd+[ と Cmd+] を割り当てようとしているのが Cmd + / Cmd + [ と割り当てられてしまっているようだ。

あー・・・JISキーボードが前提なのかぁ・・・

ということで、任意キーを割り当てるようにして、ボタン4に Cmd + @、ボタン5に Cmd + [ を割り当てることで解決。 英字キーボードでもちゃんと対応してほしいなぁ

Trelloが日本語変換確定のEnterでカードが作成されてしまう対策

※ 2019/05/10 追記 直ったようです

原因はよくわかっていないけれど、MacWebKit系のブラウザで表題のような現象が起きている。
(つまりChromeSafariFirefoxなら平気)
デスクトップアプリ も大丈夫なようです。コメントで教えていただきました。(2019/05/08追記)
※ デスクトップアプリも同様の現象が発生するようになってしまったようです・・・。
正確にはカードが作成されるのではなく、Enterイベントが発火してしまうっぽい。詳細画面のタイトルや、チェックリストアイテム欄とかでも同様のことが起きる。(なぜかチェックリスト作成では平気)
underscore.js のイベントのうち、いくつかをremoveしてみると発生しないので該当のイベントだけ消してみようかとしたけど別なところでやっぱり不具合が起きるので断念。
結局、window.keydown で 日本語入力のキーコード(229)の場合は全てのイベントを殺すことで回避するというパワープレイで解決(?)。
userscriptでやろうとしたら、該当ページのjqueryオブジェクトやイベントにアクセス出来なかったので、tampermonkey経由で実行。

一応手順を残しておくけれども、もし使う人がいたらゴリゴリのパワープレイなので自己責任でお願いいたします。
(Trello側の修正が入ったら、このScriptは無効にすることをおすすめします)

  1. tampermonkeyをダウンロード
    chrome.google.com
  2. 以下のスクリプトを追加
// ==UserScript==
// @name         FixTrello
// @namespace    http://shinbashi.hatenablog.com/
// @version      0.1
// @description  Fix trello enter bug
// @author       shinbashi
// @include    https://trello.com/*
// @grant        none
// ==/UserScript==

$(function(){
    window.addEventListener('keydown', (e) => {
        if (e.keyCode === 229) {
            e.stopPropagation();
            e.preventDefault();
        }
    }, true);
});

3 Trello開いてたらリロード

Scootman S8 と V6 レビュー

Scootman V6 を愛用して1年とちょい位通勤に使っていたのだけれども、いい感じにトラックにドツかれて公道はしれなくなったので修理に出すことに。 結果、修理に出すまでの間に充電を怠っていたのが災いして、バッテリーがおしゃかに。その他の修理費用を合計するといい感じにお値段になってしまった。 そんな中、修理を依頼してScootmanJapanは諸々コミコミで値段を抑えたS8のオファーを出してくれたのでそれに乗っかることに。 バッテリーが空輸できないので船便になったり、クリスマスや年末年始で関税で止まったり、運送業者と連絡がつかず通関後のステータスが不明になりましたがようやく届きました。

AK-1がな!

AK-1とは、ScootmanのOEM元のマシンで、CHANSONという会社が製造している。 それのエンブレムとステッカーを差し替えて日本向きにはScootman S8として売ってるわけなんですが おもくそ CHANSON AK-1 ってエンブレムのままでした。

まぁ、走行には影響ないのでいいんですけど。 バッテリーが不良なのか、最高速度が20km/hしかでてないのは困ってます。 リチウムイオンバッテリーは活性化させる必要がないし、ギア(単純な速度制限機能?)による変速も一定の割合で減速してるので、なんかどこかに抵抗が挟まてってる感じ。 最高速度30km/hの原付きにスピードリミッターが付いてる気もしないし、原因はなんじゃろ・・・。 追記:スピードリミッターがついていたので、ニッパーで切ったら30km/h弱でるようになりました。ただ30km/hはでないんだよなぁ・・・( ˘ω˘)

そんなわけで、V6とS8両方に乗ってみて、せっかくなのでそれぞれ所感をば。

V6

タイヤ:S8に比べると太め。安定感あり。 ハンドル:折りたたみ時に真横にするため、90度まで曲がる。狭い場所だとこのありえない角度のハンドリングが便利だったりする。 足置き:かなり後方にあるので、ちょっと変な角度で乗ることになる 折りたたみ:手動。自立するけど、ちょっとぶつかったり強風で倒れかねないレベルの安定感。 充電:取り外し不可。折りたたみ時充電不可。 全長:S8よりは短い。 ミラー:しょぼい。調整し辛い。ネジで止まっているため、転倒でもしようものなら1撃でネジ穴が馬鹿になる。 ナンバープレート:よく緩む。一回走行中に外れたことに気づかずナンバーをなくした。 見た目:不思議 鍵:物理+リモコン

という感じで、不満点はいろいろあったけど便利は便利でした。

S8

タイヤ:細くなった。怖い。 ハンドル:45度くらいまで?90度曲がらなくなった。普通になったといえば普通になった。 足置き:いい感じの場所にある。 折りたたみ:自動。安定感あり。ただし、うるさいし遅い。当然バッテリーが装着されてないと折り畳めない。そして折りたたむとバッテリーは外せない。手動でよかったんだけどなぁ。 充電:取り外し可。ただし、フックの部分がしょぼいのでそのうち折れそう。折りたたみ中は充電も取り外しもできない。不便。 全長:V6より少し長くなった。ハンドル幅も長くなったので、運転中はいいけどしまうとき邪魔。 ミラー:いい感じ。調整しやすい。 ナンバープレート:きちんとロックできるようになった。安心。 見た目:オサレ 鍵:リモコンのみ

とまぁ、改善された点もあったけど、そのままでよかったのに・・・という点も変わってしまった感じ。 目下最高速度が20km/hというのが不具合なのかどうかが一番の問題。 自転車に抜かれる悲しさ。 バッテリー外せる!これで置き場所が選べる! と思ったけど、これが電動自電車のように気軽に外せる感じではなく、結構慎重かつ力を込める必要があるので結構だるい。 あとほんとタイヤ細い。怖い。 なにより、物理キーが無くなってしまったので、電源を切る度に「ピュイピュイ!」ってけたたましい音がなる。 近所迷惑なので勘弁してほしい。

設定ボタンとギア変更ボタンを同時に長押しすると謎のモードに入って項目が20個位変更できたけど、マニュアルがないと何の項目なのかわからない。 いじりたい気持ちでいっぱいだけど壊すのもあれなので現在検討中。

3週間で届く、と言われたものが2ヶ月近くかかったり、ScootmanじゃなくてAK-1だったり、関税のことが後出しだったりと 丁寧ではあったけど対応がガバガバだった。 おかしな点を聞けばきちんと対応策を教えてくれるけど最初からやっておいてほしかった感はある。 市場の価格よりは遥かに安いオファーだったので仕方ないといえば仕方ない。

おわり

Illustraorで出力したSVGがTCPDFでスタイルが正しく反映されない

おはよーこんちわーこんばんわーおやすみーおきてー! しんばしです。

結論:出力時に「スタイル属性」を指定して、インラインでスタイル属性を埋め込めばよさそう

以下経過

タイトルの通り、Illustraorで出力されたSVGをTCPDFでPDFに埋め込んだところ 「画像が潰れて、全部真っ黒になっちゃうんだけど」 とのこと。 調べてみたトコロ、パスは正しく出力されているので、どうもスタイルが反映されずに白色の指定が無視されてしまって真っ黒になっている模様。

手持ちの「Graphics」で貰ったSVGを再出力したところ正しくPDFに埋め込まれたので、2つのSVGを比較したところ

  • 失敗する方のSVG
    • style要素でcssが指定され、classで参照していた
  • 成功する方のSVG
    • 各要素にインラインでcssが指定されていた

という違いを発見。どうもTCPDFはclassの参照がうまくできていないっぽい

そんなわけで、Illustraorでどんな設定にしているのか見てみた。 スタイルの項目をみたところ「スタイル要素」になっていて、ここを「スタイル属性」に変えるとインラインで出力される模様。

以上。とてもニッチな内容でした。

AWS SDK for PHP 3.x のS3のCopyObjectで署名エラー

getObjectとかlistObjectは特に問題なく動作しているのに、CopyObjectの時だけ署名エラーがでる。

SignatureDoesNotMatch

はい。 色々検証してみた結果、CopySourceの項目に日本語が使われているとエラーになるようだ。 Keyには使用しても問題ない。

仕方ないので以下のようにしてエラーを回避することにした。

<?php
$info = pathinfo($content['Key']); // listObjectとかで取ってきたデータだと思いねぇ

$s3client->copyObject([
    'Bucket' => $bucket,
    'Key' => $key,
    'CopySource' => $bucket . '/' . $info['dirname'] . '/' . rawurlencode($info['filename']) . '.' . $info['extension'],
]);

はい。日本語が使われているファイル名の部分だけURLエンコードしておけばとりあえず大丈夫。

IAMとかでS3のarnを指定するときも同じようにURLエンコードすればイケるかと思ったけどダメだった。 日本語を使わない方が健全な気もするけど、そうも行かないのが悲しいところですよね。 終わり。

AndroidTestCaseでsetUpが呼ばれた後にApplicationクラスが生成されてハマった

解決策:InstrumentationTestCaseにして、setUpメソッドsuper.setUp した後にgetInstrumentation.waitForIdleSync() を呼ぶべし

期待していた動き

- Appicationクラスが生成される
- TestクラスのsetUpメソッドが呼ばれる
- Testクラスのtestメソッドが呼ばれる
- TestクラスのtearDownメソッドが呼ばれる
- TestクラスのsetUpメソッドが呼ばれる
- Testクラスのtestメソッドが呼ばれる
- TestクラスのtearDownメソッドが呼ばれる

実際の動き

- TestクラスのsetUpメソッドが呼ばれる
- Appicationクラスが生成される <------
- Testクラスのtestメソッドが呼ばれる
- TestクラスのtearDownメソッドが呼ばれる
- TestクラスのsetUpメソッドが呼ばれる
- Testクラスのtestメソッドが呼ばれる
- TestクラスのtearDownメソッドが呼ばれる

何が困ったかと言うと、Singletonなクラスの初期化処理をsetUpメソッド内で行っているわけだけれども Applicationクラスの中でも初期化処理をしている。その為テスト用の初期化処理が、通常のアプリケーション で使う初期化処理に上書きされてしまい、テストがコケた。

d.hatena.ne.jp

Thread.sleep で対処したという話もあったけど、setUpの度にスリープされるのは嫌だし、sleepしたところで 環境に依ってはsleepが足りなくて結局コケたりする(実際ローカルではうまく動いたけど、Travis CI上ではコケた)

stackoverflow.com

どうやら InstrumentationTestCase で取得できる Instrumentation には waitForIdleSync なるメソッドがあるらしい。

Instrumentation | Android Developers

Synchronously wait for the application to be idle. Can not be called from the main application thread -- use start() to execute instrumentation in its own thread.

なるほど、わからん。 英語読めないなりに呼んでみると、「アプリケーションと同期するために待つよ。だからメインスレッドじゃ呼べないよ(メインスレッドを待ってるわけだから)。startメソッドを実行したらInstrumentationが実行されるよ」 ということだろうか。わからん。特に後半わからん。 本来の使い方はtestメソッド内で、runOnUiThread の実行が完了するのを待つために使っているので、多分looperが空になるのを待つっていう認識で良い・・・ハズ。多分。

実際に試してみたところ、setUpメソッド内で superを呼んだ直後にwaitForIdleSyncを実行するように書いたところapplicationクラスが生成されて一通りの処理が終わってから処理が再開された。 ローカルでテストして見たところ、期待通りの動作をしてくれたので、TraviceCI上でも試してみたところうまくどうさしているっぽい。

Singletonなんかにしているからテストで苦労するんだ、なんて言われそうな気もするけどSingletonはSingletonで便利な場面もあるので実に悩ましい話でした まる

FragmentStatePagerAdapterを使えと言ったな、あれは嘘だ

第二の結論

  • データの更新をしようなんて考えない。FragmentStatePagerAdapterごと作りなおす。

注意

  • FragmentPagerAdapterではAdapter作りなおしても意味がない

チラ裏

必ずしもFragmentStatePagerAdapterを使えば、notifyDataSetChangedで期待通りに変わるかと言われればそうじゃない場合も全然あるということに気付いた。

パターンが多すぎて具体的に書けないので、あと眠いので細かい説明は端折るがAdapter内で生成されるFragmentには必ずsetInitialSavedStateでsavedStateが渡されるため、データが更新されても必ず1回は更新される前のsavedStateが渡される。

つまり、Fragmentがまともに実装されていれば一度attacheされたFragmentは一回だけ更新前のデータで表示されてしまうということになる。

なので、データだけ入れ替えてnotifyDataSetChangedしても、savedStateが残っている限り完全に更新はされない。savedStateを消すメソッドもないので、Adapterごと作りなおしてViewPagerにセットし直すのが良さそう。notifyDataSetChangedなんてなかった。っていうかnotifyDataSetChanged送ったらAdapterのメンバ変数全部クリアしてほしい。

余談だけど、FragmentPagerAdapterを作り直すじゃダメなの?と思うかもですが、FragmentPagerAdapterはfragmentManagerにFragmentを保持させているのでAdapterを作りなおしてもfragmentManagerがfragmentを保持している為作りなおされない。 FragmentStatePagerAdapterはメンバ変数にFragmentのリストを保持しているのでAdapterを作りなおせば消える。

ん?てことは新しいAdapterを作った時に渡すデータのリストが、前のデータリストよりも短くなった場合かつ、Adapterによって削除されていない場合はFragmentはManagerに残り続けることになるのか・・・。きちんと消すならdestoryAllItem的なメソッドを実装して、adapterをセットし直す前に消すのが行儀良さそう。おわり。