ffmpegで4:3のアスペクト比を16:9に変換する in Mac

昔に撮影した映像を再生すると、4:3のアスペクト比なのに16:9に引き伸ばされて再生された。

どうにか4:3にしたい。

VLCで16:9で再生するのではなく、どこでも4:3で表示できるようにした。

環境

ffmpeg version 4.0.1

Mac OS X 10.13.6

方法

ffmpegコマンドでできるらしい

ffpmegはbrew install ffmpeg でインストール済み

ffmpeg -i my_video.mp4  -c copy -aspect 4:3 new_my_video.mp4

一瞬で出来た!

ffmpegがあればコンバーターソフトなんていらんなー

Androidでの非同期処理の8つの方法

Androidでの非同期処理の8つの方法

この記事は自分の勉強のため以下リンクの日本語訳しました。
8 ways to do asynchronous processing in Android and counting https://android.jlelse.eu/8-ways-to-do-asynchronous-processing-in-android-and-counting-f634dc6fae4e


Androidには、非同期処理を行うためのAPIがいくつか用意されています。これらのAPIJavaが提供するAPIを組み合わせて、非同期タスクを実行する方法は数多くあります。

JavaスレッドやAndroid AsyncTasksは、よく知られていて、あなたが望むことができるため、すべてのものに使用する傾向があります。ただし、すべてのAPIが同じではないため、要件に適したメソッドを選択すると、コードが安定して、よりクリーンで、読みやすく、直感的になります。

それで、Androidで非同期ジョブを実行する7つの方法に飛びついてみましょう。オプションは、最初にAndroid APIまたはJavaの一部としてソートされ、次にそれらが遭遇したり使用された頻度によってソートされます。

8つの方法

  • AsyncTask
  • IntentService
  • Loader
  • JobScheduler and GcmNetworkManager
  • CountDownTimer
  • Java Threads or Android HandlerThread
  • FutureTask
  • Java Timer / ScheduledThreadPoolExecutor

AsyncTask

おそらく最もよく知られている非同期APIのAsyncTaskは実装が簡単で、メインスレッドで結果を返します。 AsyncTaskにはいくつかの問題があります。たとえば、アクティビティやフラグメントのライフサイクルを認識していないため、アクティビティが破棄されたときにAsyncTasksの動作を処理するのはプログラマの責任です。つまり、長時間実行する操作に最適なオプションではなく、アプリがバックグラウンドにあり、アプリがAndroidによって終了された場合、バックグラウンド処理も終了します。

new AsyncTask<URL, Integer, Long>() {
  protected Long doInBackground(URL... urls) {
    int count = urls.length;
    long totalSize = 0;
    for (int i = 0; i < count; i++) {
      totalSize += Downloader.downloadFile(urls[i]);
      publishProgress((int) ((i / (float) count) * 100));
      // Escape early if cancel() is called
      if (isCancelled()) break;
    }
    return totalSize;
  }

  protected void onProgressUpdate(Integer... progress) {
    setProgressPercent(progress[0]);
  }

  protected void onPostExecute(Long result) {
    showDialog("Downloaded " + result + " bytes");
  }
}.execute(url1, url2, url3);
// Modified Code from google Android API

IntentService

これは、Androidで長時間実行される処理のためのデファクトの選択です。 大きなファイルをアップロードまたはダウンロードするのがよい例です。ユーザーがアプリを終了してもアップロードとダウンロードが続行され、これらのタスクが実行されている間にユーザーがアプリを使用できないようにすることはできません。

public class RSSPullService extends IntentService {
  @Override
  protected void onHandleIntent(Intent workIntent) {
  // Gets data from the incoming Intent
  String dataString = workIntent.getDataString();
  ...
  // Do work here, based on the contents of dataString
  ...
  }
}
// AndroidManifest.xml
<application
  android:icon="@drawable/icon"
  android:label="@string/app_name">
  ...
  <!--
  Because android:exported is set to "false",
  the service is only available to this app.
  -->
  <service
  android:name=".RSSPullService"
  android:exported="false"/>
  ...
<application/>

Loader

ローダーは複雑なトピックですが、ローダーの単一の実装であれば、おそらくそれ自身のためにすべての投稿に値するでしょう。今のところ、ローダーがAndroid Honeycombに導入され、互換性ライブラリの一部であることを指摘する価値はあります。彼らは、フラグメントとアクティビティのライフサイクルを認識しており、ロードされたデータをキャッシュすることさえできます。

私は、AsyncTaskLoadersがAsyncTaskに内在する多くの問題を解決するので、AsyncTaskLoadersに注意を向けたいと思います。Android Design Patternsにはローダーに関するすばらしい記事があります。ローダーの詳細を理解するために読むことをお勧めします。 https://www.androiddesignpatterns.com/2012/08/implementing-loaders.html

JobScheduler と GcmNetworkManager

私がこれら2つを一緒に束ねている理由は、効果的に似ているからです。JobSchedulerはAPI 21でリリースされましたが、まだGoogleから公式の互換性のバージョンはありません(Evan TatarkaはJobSchedulerCompatを無効にしています)。しかし、Google Play 7.5の一部としてバンドルされているGcmNetworkManagerは、似たようなものですが、特にネットワーク操作用です。

JobSchedulerの使用は少し複雑です。幸いなことに、GoogleのJobSchedulerの使い方のサンプルがあります。効果的には、サービスを作成し、JobInfo.Builderを使用してジョブを作成する必要があります。これは、サービスの実行基準を指定します。計測されていないネットワーク上にある場合や、アプリが充電中の場合などです。これらの条件が満たされるとすぐにコードが実行されるという保証や実行の順序は保証されません。以下は、Googleのコードからジョブをスケジュールする方法の抜粋です。

JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent);
String delay = mDelayEditText.getText().toString();
if (delay != null && !TextUtils.isEmpty(delay)) {
  builder.setMinimumLatency(Long.valueOf(delay) * 1000);
}
String deadline = mDeadlineEditText.getText().toString();
if (deadline != null && !TextUtils.isEmpty(deadline)) {
  builder.setOverrideDeadline(Long.valueOf(deadline) * 1000);
}
boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked();
boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked();
if (requiresUnmetered) {
  builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
} else if (requiresAnyConnectivity) {
  builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
}
builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked());
builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked());
mTestService.scheduleJob(builder.build());

// CANCEL JOBS
JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.cancelAll();

GcmNetworkManagerページで、その使用方法のコード例を見ていきます。
https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager

一般的な概念は、特定の基準が満たされたときにサービスを実行するようスケジュールする必要がある場合に似ています。
スケジュールされたタスクはワンオフまたは定期的にすることができます。
https://developers.google.com/cloud-messaging/network-manager#schedule_tasks

カウントダウンタイマー

これが何のために使われているかを推測する賞はありません。これは非常に使いやすいですが、コンテキストに依存しますので、アクティビティやフラグメントを終了する場合は、キャンセルすることでこれをクリーンアップする必要があります。明確にするために、CountDownTimerについては非同期的なものはありません。あなたがそれを見たらそれはHandlerに遅延メッセージを投稿するだけです。つまり、起動したスレッドでonTick()とonFinish()が実行され、CountDownTimerを実行しているスレッドで実行され、UIの更新を実行できます。このため、ToTick()やonFinish()で重い操作をしないことも重要です。CountDownTimerがリストに含まれている理由は、このクラスを使用しても、CountDownTimerがメインスレッドから初期化されても、ユーザーがアプリを使用できないようにすることができず、効果的に非同期効果が得られるからです。また、更新間隔が小さく、処理に時間がかかる場合は、バックプレッシャーの問題が発生し、実行スレッドがブロックされる可能性があります。

new CountDownTimer() {
  @Override
  public void onFinish() {
  }
  @Override
  public void onTick(long millisUntilFinished) {
  }
}.start();

JavaスレッドまたはAndroid HandlerThread

Javaスレッドは実装するのがかなり簡単です。ただし、Androidではこれを避けるのが最善です。私はそれらがすべての種類のインスタンスで使用されているのを見てきましたが、Androidは実際にはバックグラウンドスレッドでUIアップデートを許可していないため、制限しています。より良いオプションは、AsyncTaskを使用することです。

new Thread(new Runnable(){
  public void run() {
    // do something here
  }
}).start();

Android HandlerThreadは、バックグラウンドスレッドのメッセージを処理するために使用できます。メッセージ処理は処理ではなくリダイレ​​クトを行う傾向があるため、これはかなり制限されていますが、バックグラウンドスレッドでいくつかのタスクを実行する方法を提供しています。使用可能なのは、バックグラウンドスレッドでサービスを実行することです。

public class TickTockService extends Service {
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    mThread = new HandlerThread("ServiceArguments",
    Process.THREAD_PRIORITY_BACKGROUND);
    mThread.start();
    // Get the HandlerThread's Looper and use it for our Handler
    mServiceLooper = mThread.getLooper();
    mServiceHandler = new Handler(mServiceLooper);
  }
}

FutureTask

FutureTaskは非同期処理を実行しますが、結果がまだ準備できていないか処理が完了していない場合は、get()を呼び出すとスレッドがブロックされます。

驚いたことに私はこれを数回使用しました。場合によっては、Google Volleyでリクエストをブロックする方法があります。以下は、これを行う方法の例です。これを行う場合は、UIスレッドをブロックしていないことを確認してください。

RequestFuture<JSONObject> future = RequestFuture.newFuture();
JsonObjectRequest request = new JsonObjectRequest(URL, null, future, future);
requestQueue.add(request);

それは常にあなたがを使用することをブロックします。 future.get(30、TimeUnit.SECONDS) その時間が過ぎると、無期限に待つのではなくタイムアウト例外がスローされます

try {
  JSONObject response = future.get(); // this will block (forever)
} catch (InterruptedException e) {
  // exception handling
} catch (ExecutionException e) {
  // exception handling
}

Java Timer / ScheduledThreadPoolExecutor

Java Timerを使って5秒後に何かをする例 これらは、バックグラウンドスレッドでいくつかの処理をスケジュールするために使用できます。Androidで同じことを処理する他の方法がありますが、postDelayedまたはHandler with HandMessageDelayed()を使用してHandlerを使用し、上のようにバックグラウンドスレッドでハンドラを実行できます。また、このAPIAndroidのライフサイクルを認識していないため、アクティビティ、フラグメント、またはビューへのハードリファレンスは、メモリリークの可能性があります。

Timer timer = new Timer();
timer.schedule(new TimerTask(){
  public void run() {
    // time ran out.
    timer.cancel();
  }
}, 5000);

From Java API

特定の遅延の後に実行するコマンド、または定期的に実行するコマンドをさらにスケジュールできるThreadPoolExecutor。このクラスは、複数のワーカースレッドが必要な場合、または(このクラスが拡張する)ThreadPoolExecutorの追加の柔軟性や機能が必要な場合に、Timerよりも優れています。遅延されたタスクは、有効にされるよりも早く実行されますが、有効にされた後に開始されるリアルタイムの保証はありません。まったく同じ実行時間にスケジューリングされたタスクは、先入れ先出し(FIFO)の提出順で有効になります。

public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
   static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
   protected <V> RunnableScheduledFuture<V> decorateTask(
                Runnable r, RunnableScheduledFuture<V> task) {
       return new CustomTask<V>(r, task);
   }
   protected <V> RunnableScheduledFuture<V> decorateTask(
                Callable<V> c, RunnableScheduledFuture<V> task) {
       return new CustomTask<V>(c, task);
   }
   // ... add constructors, etc.
 }
// Code from Java API

ScheduledThreadPoolExecutorは、TimerやJava Threadsと同じようにAndroidで多くの問題を抱えています。UIを更新する必要がある場合は、メッセージをUIスレッドに投稿するか、リスナーを渡すためにハンドラを使用する必要があります。ScheduledThreadPoolExecutorはJavaの一部であり、ActivityまたはFragmentのライフサイクルを認識していないため、メモリリークを防ぐためにListenerを手動でクリーンアップまたは置き換える必要があります。

まとめ

Androidで非同期処理するとき - UIを反映するなら AsyncTask - 長時間通信してアプリ終了しても実行させたいなら IntentService - 処理データをキャッシュしたいなら Loader - API21以降でで条件付きで実行するなら JobScheduler - 遅延付きでUIを更新したいなら CountDownTimer

JavaのThreadは使うな、UIが更新できない、ASyncTaskを使え

FutureTaskはUIスレッドをブロックするから使わない方が良い

Android Studioで ExecutionException: java.lang.OutOfMemoryError: GC overhead limit exceeded

環境

Android Studio 3.0.1
Build #AI-171.4443003, built on November 10, 2017
JRE: 1.8.0_152-release-915-b08 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Mac OS X 10.12.6

Java 8

現象

とあるプロジェクトにライブラリ追加したりコード書いたりしてビルドしたら以下のエラーが出てビルドできなくなった。

Information:Gradle tasks [clean, :app:assembleStaging]
Error:Uncaught translation error: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: GC overhead limit exceeded
Error:Uncaught translation error: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: GC overhead limit exceeded
Error:Uncaught translation error: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: GC overhead limit exceeded
Error:Uncaught translation error: java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: GC overhead limit exceeded
Error:4 errors; aborting
Error:Execution failed for task ':app:transformClassesWithDexForStaging'.
> com.android.build.api.transform.TransformException: com.android.ide.common.process.ProcessException: java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException: Error while executing java process with main class com.android.dx.command.Main with arguments {--dex --num-threads=4 --multi-dex --main-dex-list /Users/xxxxxx/dev/xxxxxxx/app/build/intermediates/multi-dex/staging/maindexlist.txt --output /Users/xxxxxxxxxxxxx/app/build/intermediates/transforms/dex/staging/folders/1000/1f/main /Users/xxxxx/dev/xxxxxxxx/app/build/intermediates/transforms/jarMerging/staging/jars/1/1f/combined.jar}
Information:BUILD FAILED in 2m 25s
Information:6 errors
Information:0 warnings
Information:See complete output in console

ビルドで OutOfMemoryError だと...?

そんな重いことしてないはず。

RxJava, RxAndroid, Retrofitライブラリを追加しただけなのに!

ググる

情報でた

stackoverflow.com

解決方法

app/build.gradleに以下を追加してメモリを抑える

android {

    dexOptions {
        javaMaxHeapSize "4g"
    }
}

ビルドしてみると、、、ビルド通った!

ビルド完了!!

めでたしめでたし

PM2でnodejsアプリを動かす

foreverは使ったことあるが、pm2の方が高機能という話を聞いたので使ってみる。

PM2のインストール

グローバルインストールする

npm i -g pm2

pm2コマンドが認識されていればインストールOK

PM2を使う

開始するだけなら

pm2 start jsファイル

--nameで名前つきでスクリプトを起動すると便利

というか、名前がないと操作が不便すぎるので必須だと思う

slack-botという名前で起動する

$ pm2 start main.js --name slack-bot

[PM2] Starting /home/pi/dev/slack-bot/main.js in fork_mode (1 instance)
[PM2] Done.
┌───────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name  │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
├───────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ slack-bot │ 0  │ fork │ 1432 │ online │ 0       │ 0s     │ 12% │ 20.0 MB   │ pi   │ disabled │
└───────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘

再起動

pm2 restart アプリ名

$ pm2 restart slack-bot
Use --update-env to update environment variables
[PM2] Applying action restartProcessId on app [slack-bot](ids: 0)
[PM2] [slack-bot](0) ✓
┌───────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name  │ id │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
├───────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ slack-bot │ 0  │ fork │ 1480 │ online │ 1       │ 0s     │ 66% │ 15.1 MB   │ pi   │ disabled │
└───────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

いけたっぽい

停止する

pm2 stop アプリ名

$ pm2 stop slack-bot
[PM2] Applying action stopProcessId on app [slack-bot](ids: 0)
[PM2] [slack-bot](0) ✓
┌───────────┬────┬──────┬─────┬─────────┬─────────┬────────┬─────┬────────┬──────┬──────────┐
│ App name  │ id │ mode │ pid │ status  │ restart │ uptime │ cpu │ mem    │ user │ watching │
├───────────┼────┼──────┼─────┼─────────┼─────────┼────────┼─────┼────────┼──────┼──────────┤
│ slack-bot │ 0  │ fork │ 0   │ stopped │ 1       │ 0      │ 0%  │ 0 B    │ pi   │ disabled │
└───────────┴────┴──────┴─────┴─────────┴─────────┴────────┴─────┴────────┴──────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app

stoppedになってる

ログを見る

pm2 logs アプリ名

 $ pm2 logs slack-bot
[TAILING] Tailing last 15 lines for [slack-bot] process (change the value with --lines option)
/home/pi/.pm2/logs/slack-bot-error-0.log last 15 lines:
...

モニタリング

起動しているアプリのログやプロセスの確認ができる。

pm2 monit

見やすくて少しカッコいい

スクリーンショット 2018-04-27 18.41.53.png

設定ファイルを用いた起動指定

YamlJsonで起動オプションを設定ファイルに定義できる。

今回はYamlで作成してみる。

# ファイル名:pm2config.yml(ファイル名は自由です)

name: slack-bot                        # アプリ名
script: main.js                        # スクリプトファイルパス
watch: true                            # フォルダやサブフォルダ内のファイルが変更された場合、アプリは再読み込みされます
log-date-format: "YYYY-MM-DD HH:mm Z"  # ログに日付を追加

設定ファイルで使える項目は以下リンク http://pm2.keymetrics.io/docs/usage/application-declaration/#attributes-available

設定ファイルで起動する

pm2 start pm2.yml
pm2 stop pm2.yml
pm2 restart pm2.yml

参考にしたリンク

「アイデアは考えるな」を読んだ感想

書籍

アイデアは考えるな
面白法人カヤック代表 柳澤大輔
http://amzn.asia/eyJUrs7
  • 会社の本棚にあったので何気なく読んだら、すごく面白くて一気に読み切ってしまった。
  • PM、エンジニア、デザイナー問わず読める本。

イデアは質より量

  • すごいアイデアは誰にでも出せるわけではない、まずはすごくないアイデアをたくさん出そう。
  • すごいアイデアを1つ出すのではなく、すごくないアイデアを10出そう
  • すごくないアイデアを出していけばだんだんとポジティブになり、アイデア出しが面白くなってくる、そこが狙い

なんでも乗っかれ

  • なんでもとにかく目の前に現れたものに悩ますに乗っかろう、自分の判断はあてにならない、自分フィルターを外そう。
  • 乗っかったら面白がれるポイントを探そう(ポジティブに)、視点を変えよう、それが意外な発見につながり、斬新なアイデアに繋がる。
  • ポジティブでなければアイデアはたくさん出せない。
  • イデアとは既存の要素の組み合わせ以外何ものでもない
  • 乗っかるからこそヒントを得てヒットを生み出せる
  • イデアを出すと気には締め切りは絶対に必要、締め切りとは人間の力を目一杯引き出す装置。
  • 情報を集めたほうが格段にアイデアを出しやすい、情報を集めるなら本を読む、ネットで集める、人に会って聞くなど自分にあった方法を見つけろ。

発想法

  • 結果逆算法
    • イデアを出す前に、まず結果をイメージしてどういうアイデアだったらそうなるのかを逆算する、普通の人もぶっとんだアイデアを思いつく
  • マンダラチャート
    • 3*3のマスを使ってアイデアを出していく、アイデア出しの練習にかなり有効
  • イデアの公式
    • 既存のアイデア要素を分割して組み合わせ新しくパターンを作っていく

1人でアイデア出しの練習にはマンダラチャートが良い

ブレスト

  1. とにかくアイデアの量を出す
  2. とにかく相手を否定しない
  3. とにかく相手の意見に乗っかる

ブレストの人数は5〜7人くらいがちょうどいい、それ以上だと発言の量などによる効率が悪い

Android Studio 3.1.1でSyncエラー Data Binding annotation processor version needs to match the Android Gradle Plugin version. You can remove the kapt dependency com.android.databinding:compiler:3.1.0 and Android Gradle Plugin will inject the right version.

タイトルが長すぎるけど気にしない。

Android Studio 3.1.1にアプデしたらSyncエラーが出た。

Data Binding annotation processor version needs to match the Android Gradle Plugin version. You can remove the kapt dependency com.android.databinding:compiler:3.1.0 and Android Gradle Plugin will inject the right version.

日本語訳

データバインディングアノテーションプロセッサのバージョンは、Android Gradle Pluginのバージョンと一致する必要があります。 あなたはkapt依存関係com.android.databinding:compiler:3.1.0を削除することができ、Android Gradle Pluginは適切なバージョンを注入します。

修正方法

メッセージ内容を読むと分かる通り、
以下のapp/build.gradeにあるandroid.databinding:compilerのバージョンをAndroid Gradle PluginのGradleバージョンと合わせれば直る。

Android Gradle PluginのGradleバージョン

    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.1'

3.1.1だね

app/build.gradeにあるandroid.databinding:compiler

kapt 'com.android.databinding:compiler:3.1.0' <- 古い!!

3.1.0かー、ちょっと古いね

こいつを3.1.1にあげよう

kapt 'com.android.databinding:compiler:3.1.1'

これでSyncもビルドも通った。

でも今までkaptもandroid.databinding:compilerもなんとなく使ってきたので、こいつらは一体なんなのか軽く調べた。

kaptとは?

KotlinからJavaのコードを利用可能にするモノらしい。

qiita.com

android.databinding:compilerとは?

以下リンクを見ると、コンパイル時にLayout xmlからBindingのコードを吐き出すものらしい。

sys1yagi.hatenablog.com

つまり?

kapt 'com.android.databinding:compiler とは

DataBindingが定義されたLayout XMLコンパイル時に生成されるコードを、Kotlinで利用可能にするモノのようだ

Androidで処理時間を計測するならSystem#currentTimeMillisよりもSystemClock#uptimeMillis

タイトルまんまの内容。

メソッドの処理時間を計測したかった

Androidで処理時間を計測しようとSystem.currentTimeMillis()を使ってたら、SystemClock.uptimeMillis()のがいいよとアドバイスをもらった。

なぜか?

System.currentTimeMillis()の場合、端末時間をユーザーが変更できたりOSの時刻補正によって現在時間がかわる恐れがあるため

SystemClock.uptimeMillis()は端末ブートしてからの時間を記録してるので、時間に変更が入る心配がない

ただし、SystemClock.uptimeMillis()はディープスリープに入ると止まるため、長い計測を行う場合には注意が必要だ。

参考リンク

Yukiの枝折: 経過時間を求める方法 http://yuki312.blogspot.jp/2011/11/blog-post_30.html