きっと何者にもなれないSEの記録帳

日々で得たIT技術を記録していきます。

Electronでデスクトップを録画するアプリが簡単に作れました

ElectronはAtomに使われていたり、VSCodeに使われていたりとPCネイティブなアプリを作るために最近よく使われているライブラリです。
今まで使ったことがなかったので使ってみました。今回作ったアプリのリポジトリこちらです。
アプリ作成のポイントを紹介します。

題材

デスクトップのウィンドウやスクリーンを録画するアプリを作ります。

作り方

環境構築

Electronアプリを作るにあたってのテンプレートにはelectron-vueを使用します。
導入 · electron-vue

コマンド操作だけでElectron製のアプリを起動するところまで準備してくれます。

デスクトップの録画処理

Electronに用意されているAPIであるdesktopCapturerを使用すると、ウィンドウやスクリーンの動画を取得することができます。
desktopCapturer | Electron

// In the renderer process.
const {desktopCapturer} = require('electron')

desktopCapturer.getSources({types: ['window', 'screen']}, (error, sources) => {
  if (error) throw error
  for (let i = 0; i < sources.length; ++i) {
    if (sources[i].name === 'Electron') {
      navigator.mediaDevices.getUserMedia({
        audio: false,
        video: {
          mandatory: {
            chromeMediaSource: 'desktop',
            chromeMediaSourceId: sources[i].id,
            minWidth: 1280,
            maxWidth: 1280,
            minHeight: 720,
            maxHeight: 720
          }
        }
      }, handleStream)
      return
    }
  }
})

function handleStream (stream) {
  document.querySelector('video').src = URL.createObjectURL(stream)
}

desktopCapturer.getSourcesでウィンドウやスクリーンを取得することができます。
navigator.mediaDevices.getUserMediachromeMediaSourceIdに取得したsourceのidを指定することで各ウィンドウやスクリーンのStreamデータを取得することができます。
minWidthmaxWidthminHeightmaxHeightを変更することで動画のサイズを変更することができます。
maxWidthmaxHeightに指定した値のサイズまでの動画になります。

動画の保存にはWeb標準APIのMediaStream Recording APIを使用します。
MediaStream Recording API - Web APIs | MDN

<a id="download">Download</a>
<script>
  const downloadLink = document.getElementById('download');
  var handleSuccess = function(stream) {
    const options = {mimeType: 'video/webm'};
    const recordedChunks = [];
    const mediaRecorder = new MediaRecorder(stream, options);
    mediaRecorder.ondataavailable = (e) => {
      recordedChunks.push(e.data);
    };
    mediaRecorder.onstop = (e) => {
      downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
      downloadLink.download = 'video.webm';
    };
    mediaRecorder.start();
  };
  navigator.mediaDevices.getUserMedia({ audio: true, video: true })
      .then(handleSuccess);
</script>

navigator.mediaDevices.getUserMediaで取得したStreamデータでMediaRecorderインスタンスを作成することで、Streamデータを動画として保存することができます。

工夫したところ

録画開始や録画停止の際にショートカットキーを使えるようにしました。

Electronでは、ショートカットキーの設定にいくつかのアプローチがあります。
Keyboard Shortcuts | Electron

今回は、Local ShortcutsとGlobal Shortcutsを使いました。

Local Shortcuts

アプリのメニューを作り、メニュー項目を実行するショートカットキーを設定する方法です。
まずはメニューを作る必要があります。
Menu | Electron

メニューを作る場合、通常はMain processというElectronアプリのエントリーポイントとなるプロセスでメニューを作成する必要があります。
今回はメニュー項目の設定変更を画面描画を担当するプロセスであるRender process上で行う必要があったため、Render processでメニューを作成しました。
Electronのremoteモジュールを使用することでRender processでもメニューを作成することができます。

// In the renderer process.
import * as electron from 'electron'
const {Menu} = electron.remote

const template = [
  {
    label: '画面',
    submenu: [
      {
        label: '画面収録を開始',
        accelerator: 'CmdOrCtrl+P',
        click: function (menuItem, browserWindow, event) {
          browserWindow.webContents.send('startRecord')
        }
      }
    ]
  }
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

メニューの作成は、buildFromTemplateメソッドを使用すると簡単です。
メニューの仕様に準拠したJavaScriptオブジェクトを渡すことで、オブジェクトの値に応じたメニューを作成してくれます。

acceleratorプロパティでショートカットキーを設定することができます。
Accelerator | Electron

clickプロパティでメニュー項目が選択された時の動作を記述することができます。
引数のbrowserWindowがRender processが動作するウィンドウなので、browserWindow.webContentsを介することで、Render processに処理を渡すことができます。
webContents | Electron

アプリのウィンドウがスクリーン上に存在しない場合、browserWindownullになるため注意が必要です。
今回のアプリでは、browserWindownullの場合、Main processからRender processに処理が流れるようにしています。
ElectronではIPCのAPIでプロセス間の通信を行うことが可能です。
ipcMain | Electron

Global Shortcuts

ショートカットキーのみを設定する方法です。アプリにフォーカスがなくても機能します。
Keyboard Shortcuts | Electron

// In the main process.
import { BrowserWindow, globalShortcut } from 'electron'
let mainWindow = new BrowserWindow({
  height: 563,
  useContentSize: true,
  width: 1000
})
globalShortcut.register('CommandOrControl+E', () => {
  mainWindow.webContents.send('stopRecord')
})

globalShortcutでショートカットキーを設定することができます。

感想

Webの技術でPCネイティブなアプリを作ることができました。
Webの技術でネイティブなアプリというとモバイル向けのCordovaが思い浮かびます。
Cordovaは複雑というイメージだったので、Electronもそんな感じかなというイメージでした。
触ってみると、Electronはシンプルで分かりやすかったですし、electron-vueのファイル構成もそんな感じでした。
Electronを使うとメニューを作るといったネイティブな機能が簡単に実現できるのが驚きでした。

アプリを使って実際に録画した動画です。
youtu.be

参考

MediaStream Recording APIの使い方を参考にしました
Recording Video from the User  |  Web  |  Google Developers

アプリの画面デザインを参考にしました
デスクトップを録画するアプリを書いた - Qiita

2017年で学んだ技術

今年を振り返る的な投稿です。
 今どきのソフトウェア開発ってなんだろうということに取り組んだ2017年でした。とりあえず新しい技術と言われるものを触れば何か見えてくるものがあるかもしれないと考えました。
 かの有名な石黒浩先生の講演を聴く機会があり、その影響です。なぜ一線級で研究ができているのかという問いに先生は、今の最先端の技術で何ができるかを知ることからスタートすると言っていました。そうしないと、新しいものは生み出せない。何が新しいか分からないから。自分もそういうところからスタートすべく取り組んでいます。

Azure(クラウド

機械学習

  • H2O.aiを使った機械学習モデルの作成
  • データ処理関連の講義を受講(データ蓄積、データ分析、データ可視化を広く学習)

IoT

  • ラズパイにセンサーつけて、データ収集して、クラウド上にデータを保持して、データを可視化する

Serverless

来年のテクノロジ・トレンドがガートナーから発表されていました。 enterprisezine.jp

ブロックチェーンとか、ARとかも押さえておいた方が良さそうです。来年の宿題にすることにします。

Trelloに登録したタスクの内容を知るAlexaスキルを作った

Amazon Echo Dotが我が家にも届いたので、Alexaスキルを作ってみました。
作ったのは、Trelloに登録したタスクの内容を知るスキルです。
なお、Alexaスキルは他ユーザに利用してもらうためにスキルを公開することもできますが、今回は個人用途で使用できればよかったので、Amazon Echo Dotでのテストまでを行なっています。

Alexaスキルを作成する

Amazonの開発者コンソールでAlexaスキルを作成する必要があります。
https://developer.amazon.com/home.html

ALEXA > Alexa Skills Kit > 新しいスキルを追加する を選びます。

スキル情報

まずは、スキル情報を設定します。

  • スキルの種類:カスタム対話モデル
  • 言語:Japanese
  • スキル名:スキルを特定する名称 ※ここではTrello
  • 呼び出し名:スキルを呼び出すときの名称 ※ここではトレロ
  • グローバルフィールドは全ていいえ

f:id:hi1280:20171209234029p:plain

対話モデル

次に対話モデルを設定します。

今回はスキルビルダーを使います。

f:id:hi1280:20171209234858p:plain

キルビルダーでは、作成するスキルで実行したい処理を呼び出す際にインテントという形で定義します。
インテントはブラウザ上で作成することができます。
一度インテントを作成すれば、JSON形式で記録されるので、再利用が可能です。
今回のインテントの定義は以下です。
https://github.com/hi1280/skill-sample-nodejs-trello/blob/master/InteractionModel.json

Code EditorのメニューからJSONファイルをインポートすることができます。

インテントを作成したら、保存及びビルドします。

f:id:hi1280:20171209235411p:plain

設定

次に設定画面が表示されます。

スキルが実行された時に呼び出すAWS Lambdaの関数を指定します。AWS Lambdaの関数の内容については後述します。

エンドポイントとして、AWS Lambda の ARN (Amazonリソースネーム)を指定します。

Lambda関数のトリガーとして、「Alexa Skills Kit」が指定されていないと、エラーになってしまいます。

f:id:hi1280:20171210000536p:plain

AWS Lambdaを作成する

Node.jsで下記のLambda関数を作りました。
GitHub - hi1280/skill-sample-nodejs-trello: AlexaスキルでTrelloのAPIを実行するサンプル

process.env.ALEXA_APP_IDはAlexaスキルのIDになります。
スキル情報のメニューで確認できます。

TrelloのAPI呼び出しにはnode-trelloというnpmモジュールを利用しています。
https://github.com/adunkman/node-trello

コードの解説

Alexaスキルを制御するコードの部分です。

const handlers = {
  'LaunchRequest': function() {
    this.emit('GetTrello');
  },
  'GetTrello': function() {
    callDoingTasks().then((result) => {
      this.response.speak(result);
      this.emit(':responseReady');
    }).catch((err) => {
      this.response.speak('失敗しました');
      this.emit(':responseReady');
    });
  },
  'AMAZON.HelpIntent': function() {
    const speechOutput = '利用するには、「トレロのタスクを教えて」と言ってください';
    const reprompt = 'どうしますか?';
    this.response.speak(speechOutput).listen(reprompt);
    this.emit(':responseReady');
  },
  'AMAZON.CancelIntent': function() {
    this.response.speak('終了します');
    this.emit(':responseReady');
  },
  'AMAZON.StopIntent': function() {
    this.response.speak('終了します');
    this.emit(':responseReady');
  },
};

GetTrelloがスキルビルダーで新たに作成したインテントの名前に対応しています。
該当のインテントのコマンドが呼ばれた場合に対応したJavaScriptの関数の処理が呼ばれます。

LaunchRequestはコマンドを指定しないでスキルを起動した場合のリクエストになります。
ここでは、GetTrelloと同じ処理を行なっています。

以下のインテントはビルトインのインテントです。

  • AMAZON.HelpIntent
  • AMAZON.CancelIntent
  • AMAZON.StopIntent

スキルの使い方を教えたり、スキルの実行を止めたりするインテントはあらかじめ定義されてます。
該当のインテントに対応する処理を記述します。

Amazon Echo Dotでのテスト

youtu.be

参考情報

公式ドキュメント
Alexa Skills Kitによるスキルの作成 | ASK

Node.js向けAlexaスキル作成用SDK
https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs

注意事項

作成したスキルがAlexaアプリのスキル画面に表示されない場合、以下を疑った方が良いです。

開発したAlexa Skillが日本語版に出てこない場合 - Qiita

感想

今回のような単純にLambda関数を声で呼び出すのであれば簡単です。
対話を考慮したスキルになると難しそうです。
タイミングとかで声をうまく認識しないことが多々あります。

Amazon Echo Dot (Newモデル)、ブラック

Amazon Echo Dot (Newモデル)、ブラック

AngularFireでRealtime DatabaseからCloud Firestoreに変更した

AngularFIreを使用してアプリを作っていたのですが、最近のAngularFireのアップデートでRealtime DatabaseからCloud Firestore推しな雰囲気を感じたので、Cloud Firestoreに変更してみました。
AngularFireを使用する上でのRealtime DatabaseとFirestoreとの違いについて書きます。

データ構造

Choose a Database: Cloud Firestore or Realtime Database  |  Firebase

Cloud Firestore Data Model  |  Firebase

Firebaseのページに比較とFirestoreのデータモデルについての情報があります。
開発の際の注意点としては、データ構造を変更しないといけない可能性があります。
Realtime DatabaseではJSONに乗っ取っていれば、データを保存できました。
Firestoreになるとコレクション、ドキュメントという構造に合わせてデータを保存する必要があります。

例えば、以下のような例です。

FireStore

db.collection('objects').doc('object').set(data);

コレクション、ドキュメントという構造に準拠しないといけないです。

Realtime Database

db.object('object').update(data);

Realtime Databaseだと、JSONであればそのまま保存可能でした。

クエリ

angularfire2/querying-collections.md at master · angular/angularfire2 · GitHub

FIrestoreでは、クエリ表現が変わっています。
ページングのためにorderByを使用していたのですが、影響がありました。
Realtime DatabaseではorderByKeyというメソッドでkey順で並べ替えることができました。
Firestoreだと、それに相当するメソッドはなく、orderByというメソッドに並べ替えの機能は集約されています。
orderByメソッドでkey順(Firestoreだとid順)に並べるには特殊な指定が必要でした。

以下の通りです。

Firestoreでkey順に並べ替えるやり方

import { firestore } from 'firebase';
// 中略
db.collection('items', ref => ref.orderBy(firestore.FieldPath.documentId()));

firebaseのnpmモジュールにあるFieldPathクラスを利用をする必要があります。

ただし、keyの命名方法が変わっているので、どのように並び替えたいかによってはそもそもやり方を変える必要がありそうです。
Realtime Databaseの場合、データの作成順に順番に命名されるような形でした。
なので、key順で並べ替えれば、結果として、データを作成した順番に並べ替えができました。
Firestoreの場合、keyの命名は順番に関係なくランダムなようなので、データを作成した順番に並べ替えが必要であれば、データ内に作成日時を付与して、そのフィールドで並べ替えるといった工夫が必要と思われます。

まとめ

上記につまづいたくらいで、そのほかはメソッド名を変更するくらいで比較的簡単にRealtime DatabaseからCloud Firestoreに変更できました。
Firebaseのドキュメントを見てみると、今後はCloud Firestoreがスタンダードになりそうな雰囲気なので、今後はこちらを使っていくようにしたいと思います。

MCP70-532:「Microsoft Azure ソリューションの開発」の試験に合格しました

試験 70-532: Microsoft Azure ソリューションの開発に833点で合格しました。備忘録的に合格までの過程を残したいと思います。
問題や解答は持ち帰れないので、記憶にあるうちにです。

試験の内容

試験時間:150分
問題数:30問
合格点:700点以上
試験問題の形式:

※問題数はうろ覚えなので、若干異なる可能性があります

ケーススタディ形式は、ある企業のシステム開発の状況が問題の条件として与えられていて、各問題に答える形式です。C#のコードの穴埋めを択一問題形式で答える問題が多かったです。

二者択一形式は、前提条件は共通で、各問題でYESかNOかで答える形式です。

C#のコードの問題がケーススタディ形式でほぼ出題されて、そのほかはAzureのサービスに関しての知識を答える問題というような感じでした。workerロールとか、Service Busとかマイナーなイメージがある問題が結構出たりして、試験内容が古いのかなと思いました。

全体的に、択一問題形式でも二択になっているものもあり、まぐれで当たる可能性が大いにある試験だと思いました。
試験時間は150分ありますが、問題数が30問しかないので時間はかなり余ると思います。
私の場合、100分くらいで試験を終えました。

試験勉強の方法

以下のコンテンツを活用しました。

Udemyのコンテンツは試験の範囲を網羅しているので、初学には向いていると思います。英語なのが難点ですが、動画なので、Azureを実際に使いながら見てみると分かりやすいかと思います。
注意点として、この講座自体は最新の試験を反映していて、日本版の試験は遅れています。なので、古い内容で勉強しておく必要があります。具体的にはネットワーク関連の問題は最新だと省かれているようですが、日本版の試験だと出題されていました。

MeasureUpの練習テストは公式の練習テストということですが、本番では練習テストにはない二者択一形式の問題が出題されたり、本番よりも難易度が高いと思われる問題があるなど、ちょっと微妙かもしれません。
練習テストの問題が分かるレベルが必要と思ってしまうと、実はそんなことなかったというのが実際のところです。
練習テストが難しいと思っても、案外なんとかなるような気がします。
PowerShellのコードの穴埋め問題が結構あったのですが、本番では、ほぼ出題されませんでした。

最終的にはAzureの公式ドキュメントのチュートリアルを実践しながら学習しました。実際にAzureを触りながら学習すると理解が深まると思います。

Raspberry Pi3で赤外線リモコンを作る

よく耳にするけどラズパイを使ったことがなく、ふとラズパイで何か作ってみようと思い立ち。
そこそこ実用的であろう赤外線リモコンに挑戦してみました。
電子工作とは無縁な初心者向けの内容になります。

f:id:hi1280:20171015094557j:plain:w300

用意したもの

全てamazonで購入しました。

よく分からなかったので、初心者向けの電子工作キットを購入していますが、最終的に以下があれば良かったです。

  • ラズパイ3
  • ラズパイ用電源
  • microSDカード
  • ブレッドボード
  • ジャンパワイヤ
  • 赤外線受信モジュール
  • 赤外線LED
  • 200 Ω 抵抗

赤外線受信をする

配線

工作キットの提供サイトの情報をそのまま利用します。
Raspberry Piで赤外線レシーバーを作動する « osoyoo.com

LIRCのインストール

LIRCとはLinuxで赤外線を操作可能にするパッケージです。

sudo apt-get install lirc
ラズパイでLIRCを利用するための設定

/boot/config.txtを以下のように修正します。
ラズパイが赤外線のデバイスを認識する為に必要なようです。

修正前

# dtoverlay=lirc-rpi

修正後

dtoverlay=lirc-rpi,gpio_in_pin=18,gpio_out_pin=17

GPIO18が赤外線受信PINになり、GPIO17が赤外線送信PINになります。

ラズパイを再起動します。

sudo reboot
LIRCの起動

/etc/lirc/lirc_options.confを以下のように修正します。

[lircd]
nodaemon = False
driver   = default
device   = /dev/lirc0

lircdを再起動します。
lircdは赤外線の送受信を行うプログラムです。

sudo systemctl restart lircd.service
赤外線受信のテスト

以下のコマンドを実行することで、赤外線を受信できているかを確認できます。
受信モジュールに向かって赤外線を送信するとコンソール上にコードが出力されます。

mode2 -d /dev/lirc0 --driver default

f:id:hi1280:20171015151854p:plain

赤外線受信内容の記録

以下のコマンドを実行することで赤外線受信の内容を記録することができます。

irrecord -f -d /dev/lirc0 --driver default  ~/lircd.conf

プログラムの案内に従い、赤外線の内容を記録します。
何の操作なのか分かる名前を設定して、赤外線を受信させるということを繰り返します。
lircdの設定ファイルが作成されます。

設定ファイルをLIRCの設定に追加します。

sudo cp ~/lircd.conf /etc/lirc/lircd.conf

赤外線送信をする

配線

工作キットの提供サイトのLED点灯の配線を参考にして、赤外線LEDの配線をします。
Raspberry Pi GPIOピンからLEDへ制御信号を出力する « osoyoo.com

GPIO17が赤外線送信のピンなので、そこだけ変更します。

赤外線送信をする

赤外線送信の設定を以下のコマンドで確認します。

$ irsend LIST "" ""

TV
$ irsend LIST TV ""

0000000000000001 KEY_PLAY

赤外線の送信を以下のコマンドで行います。

irsend SEND_ONCE TV KEY_PLAY

感想

一連の流れを書くと何のことはない感じですが、systemdとか知らずにコマンド実行レベルで悪戦苦闘してました。
そこらへんが事前に分かっていれば、すんなり行ったはずです。
これでTVのON/OFFがリモートでできるようになりました。

参考情報

Raspberry Piで赤外線レシーバーを作動する « osoyoo.com

Raspberry Pi GPIOピンからLEDへ制御信号を出力する « osoyoo.com

LIRC - Linux Infrared Remote Control

RaspberryPi3でlircを使ってリモコン化する時の注意事項まとめ - Qiita

XP祭り2017に参加しました

XP祭り2017に初参加しました。

登壇者の方々、エクストリームでした。
2002年から開催されているイベントということで、XPの精神が根付いているんだなぁと感じました。

【基調対談】ワークスタイル改革を実践者する二人が、働き方の本質を語る (青野 慶久さん、倉貫 義人さん)

お二人ともパーカースタイルというラフな感じが印象的でした。

働いている人たちに本当に良いと思ったことをやっていたら、社員が活き活きと働く会社になっていたという話で、青野さんが言っていた社員が出ていくような会社は魅力がないので、会社をやめるということが印象的でした。

副業をしたり、コミュニティに参加したりして、自分の見聞を広げることが今の活動に繋がっているというのも印象的でした。外の世界には活き活きと仕事をしている人たちがいることを知れたことが良い経験になったということで、そういう人たちから学ぶことができると良い方向に向かっていくのだなぁと感じました。

また、IT活用が進んでいく中で、旧来の仕事のスタイルからの変革が起こっているという話も印象的で、例えば、事務をやっていた人がkintoneを使って自分たちの業務が楽になるシステムを作ってしまったという話がありました。
ITの世界だと今までできなかったことがアイデア次第ではできるようになってきているので、今までの仕事の価値がいつの間にかなくなることもあるんだろうなと感じました。

DevOps時代のプロジェクトマネジメントを考えよう (森實 繁樹さん)

プロジェクトマネージャーのあり方は今後変わっていくのだろうと確信する発表内容でした。
今までの決められたことを作るだけのプロジェクトから売れるものを作らないといけないプロジェクトになりつつあるというのがその背景で。
従来のプロジェクトマネージャーはプロダクトをマネージメントすることに注力する必要があるということでした。これは大きな変革だと思いました。求められるスキルも全然違うので。

その分、チームメンバーはお互いにセルフマネージメントが必要になるので、自分のような開発者の立場からするとマネージメントのスキルを身につけていく必要があるなぁと感じました。

全ては Fearless Change から学んだ,開発組織の変革を支えた実践的アプローチ (吉田 慶章さん)

軽快なトークで聞いていて面白いなぁと感じる発表でした。
組織変革には興味があるので、実践的な内容で非常に参考になりました。
「達人を味方に」のパターンは、あまり周りに達人っぽい人がいない環境なので、勇気が入るなと個人的には思いましたが、やれたらすごい効果的なんだろうなとも思いました。機会を作ってやってみたいと思いました。
前セッションの開発者の立場でもマネージメントが必要という中で、参考になる内容でした。

xUTPから学ぶ、記述性の高いユニットテスト (高橋 陽太郎さん)

日本語のメソッド名にしてテストケース名を分かりやすくするというテクニックは使ってましたが、データ初期化メソッドも日本語名にするというのは思いつきませんでした。テストコードの可読性を高めるには色々やり方があるなーと感じました。
JUnit5も出たので、これを機にテストコードを再考してみたいと思いました。

シンプルデザインについて (渋川 よしきさん)

最近、ソフトウェアパターンを学んでいるので、渋川さんのパターンに対する見解は興味深かったです。
パターンはそれ単体というより、組み合わせてランゲージにすることによって、より他者との共通理解を生むものなので、それを意識してパターン化できればと思いました。 フォースはその時の状況に左右されるので、一般化するには弊害があるという意見が斬新でした。そのパターンがどの文脈で使われるかを意識してパターン化できると良いのだなぁと思いました。

濃い質疑応答のススメ ~質問には質問で返してみよう~ (和田 憲明さん)

f:id:hi1280:20170916164225j:plain ワークショップ形式で体験しました。
質問を質問で返すことによって、質問者の気づきを促すことができるというのが本質だと思いました。
命令型のリーダーではなく、サーバントリーダーのような支援型のリーダーに有効なテクニックだなと思いました。
何かを伝える時にその人の納得感が得られる形で伝えられる良い方法だと思いました。

LT祭り&クロージング

LT祭りは面白かったに尽きます。これは現場にいないと分からないと思います。
XP祭りの名物コーナーということで、何か完成された盛り上がりがありました。
本当にエクストリームでした。

初参加枠ということで、XP祭りへの寄贈本をいただきました。
ありがとうございます。