macOS SierraでWindows PC風のキーバインド(ショートカット)を設定

問題

そろそろ安定しているから大丈夫だろうとMacBookAireの「OS X El Capitan」から「macOS Sierra」にアップグレードしたところ、他の方と同様にkarabinerが使えないという点でハマりました。

www.apple.com

私はWindowsでの作業も多いので、PC風のキーバインドにしています。(Cntl+Cでコピーだったり、Cntl+Aで全選択だったり、また、FN+左でHome、FN+右でEndなど。)

対策

対策は他の方と同様で、Hammerspoon、キーバインドの変更となりました。

Hammerspoon

www.hammerspoon.org

Hammerspoonは、macOS の操作を自動化できるツールです。 Luaという記法で記載します。

Lua - Wikipedia

Init.luaを次のように記載します。

HammerspoonのConfig (Init.lua)
hs.hotkey.bind({"ctrl"}, "c", nil, function() hs.eventtap.keyStroke({"cmd"}, "c") end) 
hs.hotkey.bind({"ctrl"}, "v", nil, function() hs.eventtap.keyStroke({"cmd"}, "v") end) 
hs.hotkey.bind({"ctrl"}, "w", nil, function() hs.eventtap.keyStroke({"cmd"}, "w") end) 
hs.hotkey.bind({"ctrl"}, "q", nil, function() hs.eventtap.keyStroke({"cmd"}, "q") end) 
hs.hotkey.bind({"ctrl"}, "f", nil, function() hs.eventtap.keyStroke({"cmd"}, "f") end) 
hs.hotkey.bind({"ctrl"}, "a", nil, function() hs.eventtap.keyStroke({"cmd"}, "a") end) 
hs.hotkey.bind({"ctrl"}, "x", nil, function() hs.eventtap.keyStroke({"cmd"}, "x") end) 
hs.hotkey.bind({"ctrl"}, "z", nil, function() hs.eventtap.keyStroke({"cmd"}, "z") end) 
hs.hotkey.bind({"ctrl"}, "s", nil, function() hs.eventtap.keyStroke({"cmd"}, "s") end) 

「コントロール+C」を「コマンド+C」に変換したりしてます。

DefaultKeyBinding.dictで、キーバインド変更

続けて、MacOSキーバインドを変更して、Fnキーと矢印キーの調整します。

qiita.com

DefaultKeyBinding.dictというファイルを作って、キーバインドを設定します。

 mkdir -p ~/Library/KeyBindings
 cd ~/Library/KeyBindings
 touch DefaultKeyBinding.dict
 open -a TextEdit DefaultKeyBinding.dict

エディタが開いたら次のように記述(UTF-8)。

{
     /* home */
    "\UF729"  = "moveToBeginningOfLine:";
    "$\UF729" = "moveToBeginningOfLineAndModifySelection:";

    /* end */
    "\UF72B"  = "moveToEndOfLine:";
    "$\UF72B" = "moveToEndOfLineAndModifySelection:";

    /* page up/down */
    "\UF72C"  = "pageUp:";
    "\UF72D"  = "pageDown:";
}

MACを再起動で反映されます。

だいたい動いたので、しばらくはこれで行こうかと思います。

今後は、karabiner elementsの発展に期待です。

参考

https://groups.google.com/forum/#!topic/osx-karabiner/xkh0oZfY7pk slongwell.github.io

aoki1210.hatenablog.jp

Surfece4キーボードでのAutoHotKey設定メモ(多少 Mac風)

Surface4を快適に使うための個人的なメモ。 AutoHotKeyの設定。

autohotkey.com

;; キーの凡例
;Shift +   Shift
;Ctrl  ^   Control (Ctrl)
;Alt   !   Alt
;Win   #    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Windows10の仮想デスクトップの移動
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CTL+右矢印で次のウィンドウ
^Right::send {LWin down}{LCtrl down}{Right}{LWin up}{LCtrl up}
;; CTL+左矢印で前のウィンドウ
^Left::send {LWin down}{LCtrl down}{Left}{LWin up}{LCtrl up}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; タッチパッドの4本指スワイプで仮想デスクトップの右と左を移動
;; https://www.wptutor.io/misc/windows-virtual-desktop-swipe-gestures
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

swipeDirection := ""

^!Tab::
  swipeDirection := "L"
return

^!+Tab::
  swipeDirection := "R"
return

$Enter::
    if (not swipeDirection) {
        SendInput {Enter}
  } else if (swipeDirection = "L") {
        SendInput ^#{Left}
  } else if (swipeDirection = "R") {
        SendInput ^#{Right}
    }
  swipeDirection := ""
return



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Surface4 Proキーボードでなくなった右FNの代わりに、アプリケーションキーを使用
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; あんまりつかわないので、アプリケーションキー(右クリックメニュー)単体は無効
AppsKey::
AppsKey Up::
  return

; 「FN+←」の代わりに「アプリケーションキー+← 」でHome
AppsKey & Right::
If GetKeyState("shift")
   Send +{End}
else
   Send {End}
Return

; 「FN+→」の代わりに「アプリケーションキー+→ 」でEnd
AppsKey & Left::
If GetKeyState("shift")
    Send, +{Home}
else
    Send, {Home}
Return

;アプリケーションキー+↑でPageUp
AppsKey & Up::Send, {PgUp}
;アプリケーションキー+↓でPageDown
AppsKey & Down::Send, {PgDn}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; その他
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;(Mac風)アプリケーションキーとBackSpaceでデリートボタン
AppsKey & Backspace::Send, {Delete}

;; CTL+Hでバックスペース、CTL+DでDELETE、CTL+Nで下、CTL+Pで上
^h::Send {Backspace}
^d::Send {Delete}
^n::Send {Down}
^p::Send {Up}

;; CTL SPACEで、ALT TAB
LControl & Space::AltTab


;;;;執筆の時だけ使用
;^f::Send {Right}
;^b::Send {Left}
;^a::Send {Home}
;^e::Send {End}


「JavaScript本格入門」の改定新版を読みました

JavaScript本格入門」の改定新版を読みました。6年前の発売以来、3万部発行された書籍の改訂版とのことです。

このエントリーは、WINGSプロジェクトの「[改定新版] JavaScript本格入門」のレビュアーに応募し献本してもらいましたので、その書評となります。

aoki1210.hatenablog.jp

上記の過去エントリーでも改定前の書籍を紹介していますが、JavaScriptをしっかり学ぶ上で非常におすすめの一冊となっています。

というのも、JavaScript深く学ぼうとした場合、構文にしか触れていない入門書か、ディープすぎる分厚い専門書と両極端な書籍が多い状態でした。

この書籍の良いところは、基本的な構文なども含まれている上、実際に本格開発をする場合に必要な情報も含まれていることが挙げられます。 「本格入門」という言葉どおり、入門書と専門書の両方が取り込まれた、非常にバランスの良い本だと思います。

改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで:書籍案内|技術評論社 にある目次を見てみるとわかりますが、基本構文、ブラウザの開発者ツール、ライブラリ、関数、スコープ、DOM、デバッグAjax、Promise、Web Worker、ユニットテスト(Jasmine)、ビルドツール(Grunt)、コーディング規約、といった幅広い内容を網羅しています。

↓書籍の目次(参考)

  • Chapter 1 イントロダクション
  • Chapter 2 基本的な書き方を身につける
    • 2.1 JavaScriptの基本的な記法
    • 2.2 変数/定数
    • 2.3 データ型
    • 2.4 演算子
    • 2.5 制御構文
  • Chapter 3 基本データを操作する - 組み込みオブジェクト -
    • 3.1 オブジェクトとは
    • 3.2 基本データを扱うためのオブジェクト
    • 3.3 値の集合を管理/操作する - Array/Map/Setオブジェクト -
    • 3.4 日付/時刻データを操作する - Dateオブジェクト -
    • 3.5 正規表現で文字を自在に操作する - RegExpオブジェクト -
    • 3.6 すべてのオブジェクトのひな形 - Objectオブジェクト -
    • 3.7 JavaScriptプログラムでよく利用する機能を提供する - Globalオブジェクト -
  • Chapter 4 くり返し利用するコードを1箇所にまとめる - 関数 -
    • 4.1 関数とは
    • 4.2 関数定義における4つの注意点
    • 4.3 変数はどの場所から参照できるか - スコープ -
    • 4.4 引数のさまざまな記法
    • 4.5 ES2015における引数の記法
    • 4.6 関数呼び出しと戻り値
    • 4.7 高度な関数のテーマ
  • Chapter 5 大規模開発でも通用する書き方を身につける - オブジェクト指向構文 -
  • Chapter 6 HTMLやXMLの文書を操作する - DOM(Document Object Model) -
    • 6.1 DOMの基本を押さえる
    • 6.2 クライアントサイドJavaScriptの前提知識
    • 6.3 属性値やテキストを取得/設定する
    • 6.4 フォーム要素にアクセスする
    • 6.5 ノードを追加/置換/削除する
    • 6.6 JavaScriptからスタイルシートを操作する
    • 6.7 より高度なイベント処理
  • Chapter 7 クライアントサイドJavaScript開発を極める
    • 7.1 ブラウザーオブジェクトで知っておきたい基本機能
    • 7.2 デバッグ情報を出力する - Consoleオブジェクト -
    • 7.3 ユーザーデータを保存する - Storageオブジェクト -
    • 7.4 サーバー連携でリッチなUIを実装する - Ajax -
    • 7.5 非同期処理を簡単に表現する - Promiseオブジェクト -
    • 7.6 バックグラウンドでJavaScriptのコードを実行する - Web Worker -
  • Chapter 8 現場で避けて通れない応用知識
    • 8.1 単体テスト - Jasmine -
    • 8.2 ドキュメンテーションコメントでコードの内容をわかりやすくする - JSDoc -
    • 8.3 ビルドツールで定型作業を自動化する - Grunt -
    • 8.4 今すぐECMAScript2015を実践活用したい - Babel -
    • 8.5 読みやすく保守しやすいコードを書く - コーディング規約 -

関数やオブジェクト指向の部分では、他の言語と異なる特徴をわかりやすく書いているため、JavaScriptの特性について理解しやすくなっています。また、最新のECMA Script2015にも対応したということで、最近の方向性についても理解できると思います。

最近のITエンジニアにとってJavaScriptは必須の知識となりつつありますが、この本は独学でも新人教育のような講義スタイルでも役立つ素敵な教材だと思います。

2016 Microsoft MVP アワードを受賞させていただきました

昨年に引き続き Visual Studio and Development Technologies の領域で MVP アワードを受賞させていただきました。

早いもので、Microsoft MVPを初受賞してから10年経ちました。

当時に比べると、IT業界も仕事内容もずいぶん変わりましたが、 Microsoft技術を通して受ける刺激や、素敵な知り合いが増える楽しさは変わらないと思っております。

引き続き情報の発信を継続できればと思います。

これからもよろしくお願いいたします。

受賞カテゴリの変遷
  1. 2006年~2010年:Solutions Architect
  2. 2010年~2011年:Visual C#
  3. 2011年~2015年:ASP.NET/IIS
  4. 2015年~現在:Visual Studio and Development Technologies
初受賞時のブログ(2006年)

aoki1210.hatenablog.jp

Abotでの「対象URL絞り込み」と「クロール毎イベント」

C#でWebサイトをクロールするライブラリの「Abot Web Crawler」の続きです。

aoki1210.hatenablog.jp

基本的な使い方は前回書いた通りですが、この記事では、URLのフィルタ方法とクロール時の基本イベントについて紹介します。

URLによる対象ページの絞り込み(条件設定)

URLを絞り込むには、Abot.DemoのGetCustomBehaviorUsingLambdaWebCrawlerが参考になります。デフォルトでは、呼び出し部分がコメントアウトされているので、呼び出すように設定すると、クロールするURLを条件に応じて絞り込むことができます。

private static IWebCrawler GetCustomBehaviorUsingLambdaWebCrawler()
{
    IWebCrawler crawler = GetDefaultWebCrawler();

    crawler.ShouldCrawlPage((pageToCrawl, crawlContext) =>
    {
        if (!pageToCrawl.Uri.AbsoluteUri.Contains("example.com/japan/"))
            return new CrawlDecision { Allow = false, Reason = "日本以外のページは不要" };

        return new CrawlDecision { Allow = true };
    });
}

クローリング毎のイベントとHTMLの取得

クロール時には、ここのURL毎にイベントを呼び出すことができます。Abotは複数のページを並行して取得することができるため、非同期のイベントとして登録します。

イベント登録
crawler.PageCrawlStartingAsync += crawler_ProcessPageCrawlStarting;
crawler.PageCrawlCompletedAsync += crawler_ProcessPageCrawlCompleted;
crawler.PageCrawlDisallowedAsync += crawler_PageCrawlDisallowed;
crawler.PageLinksCrawlDisallowedAsync += crawler_PageLinksCrawlDisallowed;
イベント毎に呼び出される処理
static void crawler_ProcessPageCrawlStarting(object sender, PageCrawlStartingArgs e)
{
    // クローリング前の処理
}

static void crawler_ProcessPageCrawlCompleted(object sender, PageCrawlCompletedArgs e)
{
    // クロールしてページを読み込んだ後の処理
    PageContent content = e.CrawledPage.Content;
    // 取得したHTMLを出力
    System.Console.WriteLine(content.Text);
}

static void crawler_PageLinksCrawlDisallowed(object sender, PageLinksCrawlDisallowedArgs e)
{
    // クロール対象ページのリンクが読み込めなかった時の処理
}

static void crawler_PageCrawlDisallowed(object sender, PageCrawlDisallowedArgs e)
{
    // クロール対象ページが読み込めなかった時の処理
}

AbotのQ&Aフォーラム

なお、質問は、GoogleGroupのフォーラムで行われています。

https://groups.google.com/forum/#!forum/abot-web-crawler

APIがバージョンごとに異なるので、最新の質問から回答を探したほうが効率的です。

C#のクローラーライブラリ「Abot」

C#でWebサイトをクロールするライブラリの「Abot Web Crawler」というものがありますので、そのメモです。

github.com

Abotとは

Abotはアリゾナ州のStevenさんが開発されているC#によるクローラー用ライブラリです。

商用・個人問わず使えるオープンソース(Apache License)で、早く、カスタマイズ可能で、軽量とのことです。

また、AbotXというサイトでは、プラグインも公開されています。 (プラグイン例:複数サイトをクロールする、Jsで実行、スケジュール実行、スピード調整等)

使い方

基本的には、Config設定を設定して、クラスライブラリを読み出すだけです。

Abotの使い方

1: Nugetを使って、Abotをインストールします。

2: using句で以下の名前空間を追加します。

using Abot.Crawler;
using Abot.Poco;

3(パターン1): コードで設定する場合

public CrawlConfiguration()
{
    MaxConcurrentThreads = 10;
    UserAgentString = "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko";
    RobotsDotTextUserAgentString = "abot";
    MaxPagesToCrawl = 1000;
    DownloadableContentTypes = "text/html";
    ConfigurationExtensions = new Dictionary<string, string>();
    MaxRobotsDotTextCrawlDelayInSeconds = 5;
    HttpRequestMaxAutoRedirects = 7;
    IsHttpRequestAutoRedirectsEnabled = true;
    MaxCrawlDepth = 100;
    HttpServicePointConnectionLimit = 200;
    HttpRequestTimeoutInSeconds = 15;
    IsSslCertificateValidationEnabled = true;
}

3(パターン2): コードではなく、App.config(Web.config)で設定する場合

  <abot>
    <crawlBehavior 
      maxConcurrentThreads="10" 
      maxPagesToCrawl="1000" 
      maxPagesToCrawlPerDomain="0" 
      maxPageSizeInBytes="0"
      userAgentString="Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko" 
      crawlTimeoutSeconds="0" 
      downloadableContentTypes="text/html, text/plain" 
      isUriRecrawlingEnabled="false" 
      isExternalPageCrawlingEnabled="false" 
      isExternalPageLinksCrawlingEnabled="false"
      httpServicePointConnectionLimit="200"  
      httpRequestTimeoutInSeconds="15" 
      httpRequestMaxAutoRedirects="7" 
      isHttpRequestAutoRedirectsEnabled="true" 
      isHttpRequestAutomaticDecompressionEnabled="false"
      isSendingCookiesEnabled="false"
      isSslCertificateValidationEnabled="false"
      isRespectUrlNamedAnchorOrHashbangEnabled="false"
      minAvailableMemoryRequiredInMb="0"
      maxMemoryUsageInMb="0"
      maxMemoryUsageCacheTimeInSeconds="0"
      maxCrawlDepth="1000"
      isForcedLinkParsingEnabled="false"
      maxRetryCount="0"
      minRetryDelayInMilliseconds="0"
      />
    <authorization
      isAlwaysLogin="false"
      loginUser=""
      loginPassword="" />     
    <politeness 
      isRespectRobotsDotTextEnabled="false"
      isRespectMetaRobotsNoFollowEnabled="false"
      isRespectHttpXRobotsTagHeaderNoFollowEnabled="false"
      isRespectAnchorRelNoFollowEnabled="false"
      isIgnoreRobotsDotTextIfRootDisallowedEnabled="false"
      robotsDotTextUserAgentString="abot"
      maxRobotsDotTextCrawlDelayInSeconds="5" 
      minCrawlDelayPerDomainMilliSeconds="0"/>
    <extensionValues>
      <add key="key1" value="value1"/>
      <add key="key2" value="value2"/>
    </extensionValues>
  </abot>  

4: クローリングの実行

//同期実行の場合
CrawlResult result = crawler.Crawl(new Uri("http://localhost:1111/")); 

//エラー制御
if (result.ErrorOccurred)
{
    Console.WriteLine("次のサイト {0} のクロールがエラーで終了しました: {1}", 
        result.RootUri.AbsoluteUri, result.ErrorException.Message);
}
else
{
    Console.WriteLine("次のサイト {0} のクロールが正常終了しました", result.RootUri.AbsoluteUri);
}

Gitから取得できるコードについて

Gitからコードをクローンすると、ライブラリに加え、サンプルソースを入手できます。

f:id:aoki1210:20160418144445p:plain

デモプロジェクトの実行

「Abot.Demo」をスタートアッププロジェクトに設定して実行すると、URLを入力するコマンドプロンプトが表示されます。 URLを入力すると、そのサイトのクロールが行われ、Binフォルダにlog4netのログが出力されます。

参照ライブラリについて

Abotが使用しているライブラリは、以下の通りです。CsQueryとNRobotsPatched は知らないライブラリでしたので、リンクを張っておきます。

Azure WebAppsのKuduでcurlコマンドを実行する

kuduでgzファイルをダウンロードしようと思って、curlコマンドを使ったのですが、エラーでした。 少し調べました。

curl -O http://<ドメイン>/files.7z

がダメでした

github.com

によれば

curl -Ss -O -L http://<ドメイン>/files.7z

であればOKとのこと。確かにOKでした。