銀の弾丸

プログラミングに関して、いろいろ書き残していければと思っております。

mouseenterとmouseoverの違いなどDOMイベントの発生状況を可視化して調べてみたよ

f:id:takamints:20180507065734p:plain

HTML5のDOMイベントに、mouseentermouseoverという、よく似たマウスイベントがあります。ここには、その違いについて調べたことを書いておきます。

どちらもマウスポインターが要素の上に入ってきた時に発生するイベントで、それぞれに対応する「マウスポインタ―が要素から外れた」時のイベントとして mouseleavemouseout もありますね(mouseenter には mouseleavemouseover には mouseout が対応します)。

この2種類のイベント間には、発生要因や伝播(バブリング/プロパゲーション)に関する違いがあります。

私は最近まで、この違いを意識しておらず「歴史的理由による別名?」かと思っていて、その場で適当に思いついた方を使っていました。 先日ふと疑問に思ってMDNで調べてみたら、どうやら上記のように明確な違いがあると知ったのですが、はっきりイメージがつかみきれなかったので確認用に作ってみたのが以下のものです。

マウスイベントを可視化する

以下、4つのDOM要素が入れ子になっていて、各要素が拾ったマウスイベントを表示します(前述の4つのイベントだけ調べるつもりでしたが、せっかくなので他のイベントもListenしました)。要素の上でマウスを動かせば各インジケータがビカビカします(ちょっとうるさいですが目立つと思って)。

各要素には、preventDefaultstopPropagationというチェックボックスがあります。 それぞれチェックを付けると、その要素のイベント処理で event.preventDefault()event.stopPropagation() を実行します。 例えば、‘#Div4‘の上でマウスを動かすとmousemoveが全要素に発生しますが、stopPropagationにチェックを入れた要素の親へは伝播しません (preventDefaultはこれらのイベントに関して変化がなさそうなのですが、とりあえず残しています)。

マウスポインタが要素の「外側から内側」へ移動するとき

全てのstopPropagationのチェックを外した状態で、#Div1の左右または下の外側から*1#Div4の内側までマウスポインタ―を動かしていったとき、以下のことが観察されます(実際にやってみてください)。

*1 - マウスポインターが各要素の上側を通過すると情報を表示している要素の境目でイベントが発生してしまうので避けるべき。

マウスポインタが要素の「内側から外側」へ移動するとき

次に、#Div4 の内側から、左右または下に向かって、#Div1 の外側までマウスポインタ―を動かすと、以下のことが観察できます(全てのstopPropagationのチェックは外したままです)。

各イベントの伝播を確認

上と同じく、全てのstopPropagationのチェックを外したままで、各イベントが発生した場合、

  • mouseovermouseout は親要素へ伝播しますが、
  • mouseentermouseleave は伝播しません。

そして、伝播を抑制するには、イベントハンドラーの中で event.stopPropagation() を呼び出します。

MDNに書いてあること

MDNのmouseenterには、以下のように書かれています。

With deep hierarchies, the amount of mouseenter events sent can be quite huge and cause significant performance problems. In such cases, it is better to listen for mouseover events.

翻訳すると「深い階層では、送信される mouseenter イベントが大量になる可能性があり、重大なパフォーマンスの問題の原因になり得る。その場合は mouseoverイベントを使うといい」とのことですが、これって上で見たことと少し雰囲気が違ってないか?と。 mouseover が全ての親に伝播していて、たくさん発生しているように見えましたけど?

「逆じゃないの?」って、かなりMDNを疑ってみたのですが、しかし、これはこれでどうやら間違いではないみたい。 すべての要素でイベントをListenしているので、大量の mouseover が発生していましたが、通常そんなことはしませんね。 イベントはaddEventListenerしている要素に発生して後は親要素に向かって伝播するだけ。 イベントを処理すべき要素だけにハンドラを設定しておけばなんら問題がないはず。

一方「mouseenterが大量に発生して」という部分はよくわかりません。 そのようなケースが今のところ想定できないのですが。 mouseenterは、そもそも親要素に伝播しないし、論理的な自要素の領域内にあればmouseleaveは発生しないので、必要なところでListenしておけば問題ないような気がするし、そもそも用途が違うんじゃないのか?と。

ちょっとモヤモヤしてますが、とりあえず・・・。

リンク

Heroku CLI 7.0.2? のエラーを修正

f:id:takamints:20180422144244p:plain

Git for Windowsから最新版の Heroku CLI を起動するとエラーが発生。バージョンは下に書いてますけど、そもそもエラーが出るので確認できない。Power Shellからなら大丈夫。32ビット版でも64ビット版でも同様ですね。未確認ですが、MSYS とか Cygwinでも同じ現象が起きるんじゃないかなと思います。

とりあえずはインストールされたシェルスクリプトに1文字追加すれば治ります。

直接的な原因が分かったところでGitHubにはIssueを上げてひと安心。「さてIssueも上げたしForkしてCommitしてプルリクしてどや顔するかな相手は天下のセールスフォースドットコム・・・」と、ヤケに日曜朝から心拍数を上げたのですが(おちつけ自分)、結局どこを直せばよいのかわからなくてWatchだけして、そっとGitHubを閉じました。 が、なんと4時間後にはこの問題が改修されててIssueもClose。素早い対応ありがとうございますー。

クラウド開発徹底攻略 (WEB+DB PRESS plus)
菅原 元気 磯辺 和彦 山口 与力 澤登 亨彦 内田 誠悟 小林 明大 石村 真吾 相澤 歩 柴田 博志 伊藤 直也 登尾 徳誠
技術評論社
売り上げランキング: 88,620

インストール直後にエラー

Windows用Heroku CLIの最新版をインストールしてGit Bashから実行すると以下のエラーが発生しました。

$ heroku
sed: -e expression #1, char 7: unterminated `s' command
/c/Program Files/heroku/bin/heroku: line 4: ./../client/bin/heroku.cmd: No such file or directory

sedのsコマンドが終わってない」と言っている。

原因究明

コマンドはC:\Program Files\heroku\bin\herokuという名のシェルスクリプトなので中身を見てみると。

#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\,/,g')")

"$basedir/../client/bin/heroku.cmd" "$@"
ret=$?
exit $ret

2行目で、sedでバックスラッシュ(円記号)をスラッシュに変換しようとしているが、バックスラッシュがエスケープされていませんね。

応急対策

これエスケープするだけで動くんじゃないかね?と

f:id:takamints:20180422095556p:plain

Git Bashを管理者権限で開いてvimで編集したところ、ホントにこれだけで正しく動くようになりました。 (Program Files 以下を変更するには管理者権限が必要)

バージョンは 7.0.2、、、ん?

バージョンは以下のように7.0.2だったのですが、これってホントにリリースバージョンなんですかね。 GitHubリポジトリでは現時点でv6.16.16です。Windows用は別管理ってことはないと思うんだけど。

これ、ダウンロードページから公開しちゃいけないものを公開しちゃっているとかではないのかな。 よくわからなくなってきました。

$ heroku --version
heroku-cli/7.0.2 win32-x64 node-v9.11.1

とりあえずIssueはポスト

しかしまあ、しばしGoogle翻訳と格闘してから、とりあえずIssueをポストしておいた。

で、現在のリポジトリ内の /resources/exe/heroku が問題のスクリプトなんだけど、不思議なことに半年前に追加されたときから、きちんとエスケープされている。 ということで、どこを直せばよいのかわかりません。インストーラを作るところか動作上の問題なのか。

まあ偉い人が直してくれるんだろう。なにしろ天下のセールスフォースドットコムだし。

追記)この記事書いた時点で既にIssueがクローズされていました。早っ! 修正箇所はやっぱりresources/exe/herokuで。バックスラッシュが4つになっていましたわ。 二重にエスケープしなきゃなんなかったのかー。

関連リンク

devcenter.heroku.com

github.com

github.com

ES6に対応した「grunt-contrib-uglify-es」を使用する

grunt-contrib-uglifyのES6対応版がgrunt-contrib-uglify-esという名で別途公開されてましたというお話。

f:id:takamints:20180322202444p:plain

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター! 速習シリーズ
WINGSプロジェクト (2015-08-28)
売り上げランキング: 1,828

JavaScriptのタスクランナーGruntからUglify-Jsを使用してスクリプトを圧縮・難読化する grunt-contrib-uglify なんですが、ES6に対応していなくて困ってました。 ES6の「アロー関数」や「 letによるブロックスコープの変数宣言」は、うっかりミスの防止に役立ちますから今後なるべく使いたい。 この手のバグは見つけにくいので手を焼きますから。

「しかし uglify でコケるから・・・」ってのはまさに本末転倒。ということで、本腰入れて「どうにかならんか?」と調べてみたら Stack Overflow に、

「grunt-contrib-uglify の harmony ブランチが使えるぜ!」という情報がありました。 このブランチで(その名の通り)ES6対応しているようです(完全ではないとも書いてありますが)。 で、GitHub から特定ブランチをnpmでインストールするには以下のようにすれば良いらしい。

$ npm install git://github.com/gruntjs/grunt-contrib-uglify.git#harmony --save-dev

これを実行すると grunt-contrib-uglify-es というモジュールがインストールされたので、まさかと思って npm で grunt-contrib-uglify-es を検索すると、なんとそのものズバリが公開されているじゃありませんか。てことで、GitHubから取ってこなくても、以下の普通なnpmでよかったみたい。

$ npm install grunt-contrib-uglify-es --save-dev

加えてモジュール名が変わったので、 Gruntfile.js のタスクロード部分も書き換えが必要ですね。

Gruntfile.js

    ~
    grunt.loadNpmTasks('grunt-contrib-uglify-es');
    ~

これでめでたくアロー関数とletが使えるようになりました。

元々入ってた grunt-contrib-uglify は、残しておいても問題なさそうですが、 まあ、使わないならアンインストールしておくべきでしょう。

参考サイト

AdSense「自動広告」の破壊力!~ゲームのルールが変わったかもね?全部おまかせでよいのかな?

f:id:takamints:20180307110302j:plain
photo credit: vinayaketx Top 12 Tips To INCREASE ADSENSE REVENUE | Adsense Optimization 2018 via photopin (license)


最近AdSenseで「自動広告」なるものが使えるようになりました。 とても便利でお手軽で、素晴らしいソリューションだと感動しました。 しかし「AIが人々の仕事を奪っちゃう!」とまでは行きませんが、少し危機感も感じてます(後述)・・・。

てことで、ちょっとホットなAdSenseの「自動広告」について(遅ればせながら)書いておきます。

まずは「AdSenseアドセンス)ってなに?」って所から

(ここはAdSenseのアカウントを持ってる人は読み飛ばしてもらって結構です)

AdSenseGoogleの広告配信サービスです。自社製品やサービスを宣伝したい広告主と、ブログやWebサイトをインターネットに公開している人(=サイト運営者)をAdSenseが結びつけ、広告主の広告をサイト運営者のサイトへ表示します。

サイト運営者は自分のサイトの広告を表示したい場所に、広告ユニットというAdSenseが提供するHTML要素(SCRIPTとDIV)を貼り付けます。広告ユニットはAdSenseの管理画面で、サイズや種類を指定して自分で作る必要がありますよ。この広告ユニットをサイトを訪れた人(=サイト来訪者)が見たり、クリックしたりすると、サイト運営者に収入が発生するのです。

AdSense自体の収入源は広告主から出される広告の掲載料金(出稿料)なのですが、そこから運営者のサイト内で実際に広告が表示された回数(=PV:ページビュー)や、サイト来訪者が興味を示した度合い(≒クリック数)に応じて、サイト運営者に一定の金額が還元されます(=サイト運営者の収益額、もしくは見積もり収益額)。

サイト運営者の収益額は、広告が表示された回数とクリックされた回数にほぼ比例しているのですが、実際には表示された広告や世の中の動きによって細かく変動します。 しかし、少なくともある一定期間内の平均として、PVに対する収益の指標は存在していますので、サイト運営者が効率よく収益を上げるには、自サイトのPVを上げることと、PVに対して効率よく収益を上げること(=たくさんクリックしてもらうこと)です。

「自動広告」の便利なところ・凄いところ

さて本題。「自動広告」の便利なところですが、簡単に言ってしまえば、広告の表示位置やサイズをあれこれ考える必要がないところ。

専門知識が不要です

既にAdSenseを利用している方たちならおわかりでしょう。 広告ユニットの表示位置やサイズには流行りあって、そのとき「どう選択するか?」は、それなりのテクニックやノウハウだったと思います。

でも自動広告では考える必要がなくなりました。 ブログやWEBサイトに所定のスクリプトを貼り付ければ、Googleさんがサイト内の最適な表示位置とサイズを決定して、広告ユニットを表示してくれるのです。 つまりサイトの運営者は「サイト来訪者に最高に訴求する広告は、どこにどれぐらいのサイズだろうか?」などと頭をひねる必要がありません。

加えて、

レイアウトをいじらなくて済みますね

多くの(特に無料の)ブログシステムでは、レイアウトへのアクセスに制限がかかっている場合や、編集しづらい場合がありますね。

そのため自分で「最適だ」と考えた位置に広告を表示できなかったり、特定のプログラミングスキル(JavaScript, HTML, DOM, CSS)を習得しなければならなかったりしていました。あたしはそこは、それなりに専門なので問題ありませんけれど、おしゃれで小粋な次世代ブロガー全員が、その方面に明るいわけではありません。

しかし繰り返しになりますが、自動広告ではグーグルさんが最適な位置に表示してくれるので、まったく問題になりません。

だから参入障壁がなくなった

広告のレイアウトを一度決めたら、あとからあまり変更しないとは思いますが、AdSenseへの参入障壁にはなっていたような気もします。

しかし、これから始めようという人にとって「自動広告」で敷居は下がった、もしくは敷居がなくなった。

これはおそらくすごいことだと思うんですよ。

さらに端末種類を選ばない

AdSenseには、以前からモバイル用のページ単位の広告というのがあり、所定のスクリプトを貼るだけで、モバイルの画面に広告を表示してくれるというものでした。ページ遷移時に画面全面の広告だったり、コンテンツの上部や下部に表示してくれたりするものでした。しかし今回利用可能になった自動広告はすべての端末に有効なんです。

当面は収入アップを見込めるかも?

グーグルさんにとってAdSenseの売上は収入の大きな柱ですよね。 そしてこれまでの20年近くでWebサイトと広告に関するビッグデータを持っています。 さらに人工知能で先頭を走る大企業ですから、広告を妙なところに貼っちゃうはずがないのです(多分)。

実際に、今回手前のブログやWEBサイトで使ってみたのですが、広告ユニットの表示回数が多くなって見積収益額も上昇傾向にあるような気がします。まだあくまでも「感覚的に」の域ですが。

ということで、

AdSenseのコードをコピー

AdSenseへ行って、

f:id:takamints:20180309090909p:plain

左上の ≡ をクリックするとメニューが開きます。

f:id:takamints:20180309091218p:plain

メニューの [広告の設定]/[自動広告] をポイントすると、自動広告の設定画面が表示されますね。

f:id:takamints:20180309091801p:plain

ここで右上の「自動広告を設定」をクリックすると、以下のように、ヘッダーに貼り付けるコードが表示されます。 下に表示されている「コードスニペットをコピー」して、HEADに貼り付けるとヨロシイ。

f:id:takamints:20180309091333p:plain

はてなブログでHEADにコードを貼り付ける

ダッシュボードの左のメニューから「設定」をクリックし、右側に表示された「詳細」タブページの真ん中から少し下辺りの 「検索エンジン最適化」というブロックに「headに要素を追加」というテキストボックスがあるでしょう。

そこの最初か最後にAdSenseの自動広告の設定でコピーしたコードをペーストすれば良い。マジこれだけです。

HEADじゃなくてもいいみたい

はてなブログではHEADに貼り付けられますが、それができないブログもあります(ココログBasicとかね)。

でも大丈夫。

AdSenseの設定画面では「HEADに貼り付ける」と指示されていますが、実際には別な場所(例えばサイドメニューのリストとか) でもかまわないようです(Chromeだけで確認しました)。

なのでHEADの内容にアクセス出来ないようなブログシステムでも、自動広告は使えるようです。

ただし、非公式な使い方ではあるので自己責任で。

どこに危機感を感じているのか?

これまで読んでいただいた方は「そんな嬉しいお話なのに何に危機感を感じているの?」と思われてるかもしれません。

それはまあ、非常にせこい話なのですが、参入障壁が下がって、みんなが使い始めたらクリック単価が下がるんじゃないの?(涙)ってことなんですね(=死活問題)。

「薦めておいて何言ってる!(書かなきゃいいのに!)」との、お叱りの言葉もなく、ご清聴ありがとうございました!

いやマジで、ゲームのルールが変わった気がするんですよねえ。

Gitでアリバイ工作するスクリプトはコチラです

f:id:takamints:20180217200222p:plain
[Defi] Master and Servant by Franck Mahon, on Flickr


あなたはとある事件の容疑者だ。 悪いことに、事件当日の居場所を証明できないでいる。

というか、ここだけの話ホントはアナタが真犯人。だからこの際アリバイ工作するしか無いようだ・・・

そこであなたは、Gitのコミット日時を書き換える(え?)・・・

(という設定で以下進行ってなんだそりゃ?)

コミット日時を偽装する

ってな時に、Gitのコミット日時を偽装して、簡単にアリバイ工作(?)できるスクリプトが、これ(↓)ですね。

git-giso

#!/bin/sh
if [ "$1" = "" ]; then
    echo "Error: datetime need to be specified"
    exit 1
fi
echo git commit --amend -C HEAD --date="$1" && \
git commit --amend -C HEAD --date="$1" && \
echo && \
echo git rebase HEAD~ --committer-date-is-author-date && \
git rebase HEAD~ --committer-date-is-author-date

このファイルに実行属性を付けてPATHの通った所へINSTALL。

実行例

実行すると以下のようになりますよ(極秘情報は伏せてある)。

$ git-giso '2018-02-17 20:26:45'
git commit --amend -C HEAD --date='2018-02-17 20:26:45'
[working-branch abcdefg] #$%S&Gys7&%$#
 Date: #$$ Feb %& $%#2#$$%&'(&%%%
 n file changed, 4 insertions(+)

git rebase HEAD~ --committer-date-is-author-date
Current branch working-branch is up to date, rebase forced.
First, rewinding head to replay your work on top of it...
Applying: %&%S$%S&&D'F/??./

それは、ヒ・ミ・ツ

理由は明かせないけれど、コミット日時を書き換えたいときがあります(よね?)。あるんです。

絡み合う2つの日時・・・

  1. Gitのコミットには author-datecommitter-dateという2つの日付がありまして、最初にコミットした時、両方同時刻に設定されます。
  2. でも、git commit --amend した時には、committer-date しか書き換わらないの・・・
  3. てことで、git commit --amend -C HEAD --date='<datetime>' として author-date を書き換える。
  4. しかし、committer-date が、その時の時刻になってしまっているので、
  5. git rebase HEAD~ --committer-date-is-author-datecommitter-dateauthor-dateに一致させるというわけです。

ふう・・・

masterブランチでやっちゃダメ

これ、amendしてrebaseするので、ワーキングブランチでやりましょう。

masterブランチでコレやって、push -f とかしちゃったら、市中引き回しの上獄門ですから気をつけて。


なんで縄文・・・