050plusの留守番電話設定

仕事用の電話番号が欲しかったので、050plus契約してiPhoneで使ってます。
今のところ3G回線でも一部地域を除き、ほぼ問題なく通話できています。*1
そんな感じで完璧ではないけど、まぁいいかなという感じで契約してから半年くらい使ってます。

つい昨日、最も不便だと思ってた留守電機能が標準で搭載されていることを知ったので慌てて設定しました。*2
初期設定は無効化されているので、アプリの管理メニューから留守番電話設定を行う必要があります。
自分が最適だと思える設定まで持っていくのに少し戸惑ったので、メモしておきます。

留守番電話機能の起動条件

050plusアプリが起動している、またはバックグラウンドで生きている場合は、
留守番電話センターへ繋ぎに行きません。こちらが通話開始するor向こうが切るまで延々コールし続けます。
アプリが起動されていない場合に電話がかかってくると、ワンコールくらいで留守番電話センターへ接続し、メッセージ録音ができます。

通知方法

留守番電話設定の「通知方法」を"全て通知"にします。
そうしないと、メッセージが録音されたときだけ着信案内メールが届くようになってしまいます。
f:id:ham007:20130724232445p:plain

音声ファイル

留守番電話設定の「音声ファイル」を"添付する"にします。
メッセージ(が存在する場合)は着信案内メールを受信するだけでメッセージの確認が行えますし、
留守番電話センターでのメッセージ確認がかなり面倒*3なので、この設定1択じゃないでしょうか。
f:id:ham007:20130724232450p:plain
f:id:ham007:20130724232454p:plain

*1:私の場合だけかもしれませんが、上野周辺は雑音がひどく使い物にならなかった。

*2:留守電機能が無いと思い込んでいた。

*3:センタへ電話する→案内言語をプッシュする(日本語or英語)→自分の050電話番号をプッシュする→暗証番号プッシュする→メッセージの確認

ブログの引っ越し(2回目)

やっぱ自分のデータは自分で管理しなきゃ!ということで、はてなダイアリーからレンタルサーバー上のWordPressへ引っ越ししたものの、日々のメンテナンスに疲れてしまいました。そんな折、はてなブログがいい感じになってきてるということを聞きましたので再度の引っ越しをしました。

心機一転がんばるぞ~

新しい非同期呼び出し(async,wait)を試す

.NET4.5から導入される新しい非同期呼び出し。
こんな感じで使うようです。

  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    //内部で非同期処理を行うメソッドにはasyncをつける
    private async void button1_Click(object sender, EventArgs e)
    {
      //戻り値を返す非同期処理の実行。awaitをつけて非同期処理であることを明示する。
      textbox1.Text = await HeaveyProcess();

      //voidな非同期処理の実行
      StopWatch(5);
    }

    private async Task<string> HeaveyProcess()
    {
      await Task.Delay(TimeSpan.FromSeconds(3.0));
      return "重い処理が完了しました!!";
    }

    private async void StopWatch(int sec)
    {
      Console.WriteLine("開始:{0}", DateTime.Now);
      await Task.Delay(TimeSpan.FromSeconds(sec * 1.0F));
      Console.WriteLine("終了:{0}", DateTime.Now);
    }
  }

複雑なラムダ式

最近、ASP.NETMVCのソースコードを読んでいるのだが、そこでは複雑なラムダ式が多々でてくる。
今回はその一例としてアクションフィルタの処理(ControllerActionInvokerクラスのInvokeActionMethodWithFiltersメソッド)を自分なりに解釈し、コードを起こしたものを載せておく。

いくつか有用そうなテクニックを盗めたし、
ASP.NET MVCソースコードは本当に勉強になります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqSample
{
    public interface IActionParameter
    {
        object GetParameter();
    }

    public class GenericParameter<T> : IActionParameter
    {
        private T val;

        public GenericParameter(T val)
        {
            this.val = val;
        }

        public object GetParameter()
        {
            return val;
        }
    }

    public class ActionResult
    {
        public object Value { get; set; }
    }

    public class ActionContext
    {
        public ActionResult CurrentValue { get; set; }

        public ActionContext()
        {
            CurrentValue = new ActionResult() { Value = "" };
        }
    }

    public static class Action
    {
        public static ActionResult ConcatString(Func<ActionResult> action, IActionParameter param)
        {
            ActionResult current = action();
            var newValue = current.Value.ToString() + param.GetParameter().ToString();
            current.Value = newValue;
            Console.WriteLine(current.Value);
          
            return current;
        }

        public static ActionResult GetMaxValue(Func<ActionResult> action, IActionParameter param)
        {
            int tpResult;

            if (!int.TryParse(param.GetParameter().ToString(), out tpResult))
                throw new ArgumentException("パラメーター不正(param)");

            var current = action();

            if (!int.TryParse(current.Value.ToString(), out tpResult))
                throw new ArgumentException("パラメーター不正(action)");

            var newValue = "";

            if (Convert.ToInt32(current.Value) >= Convert.ToInt32(param.GetParameter()))
                newValue = current.Value.ToString();
            else
                newValue = param.GetParameter().ToString();

            Console.WriteLine("現在値:{0}、比較値:{1}  =>  {2}を適用", current.Value, param.GetParameter(), newValue);
            current.Value = newValue;
            return current;
        }
    }

    public class ActionProcesser
    {
        public void DoAction(Func<ActionResult> acumrator, Func<Func<ActionResult>, IActionParameter, Func<ActionResult>> func)
        {
            var parameters = new List<IActionParameter>();
            parameters.Add(new GenericParameter<int>(10));
            parameters.Add(new GenericParameter<int>(20));
            parameters.Add(new GenericParameter<int>(30));
            parameters.Add(new GenericParameter<int>(40));
            parameters.Add(new GenericParameter<int>(50));
            parameters.Add(new GenericParameter<int>(60));
            parameters.Add(new GenericParameter<int>(70));
            parameters.Add(new GenericParameter<int>(80));
            parameters.Add(new GenericParameter<int>(90));
            parameters.Add(new GenericParameter<int>(100));

            /*
             * 第1引数には、アキュムレーター値を返すFuncデリゲートを指定。
             * 第2引数(アキュムレーター関数)には、アキュムレーターと同タイプのFuncを返すデリゲートを指定。
             * こうすることで各パラメーターを外出しすることが可能になる。
             * 
             * アキュムレーター関数にデリゲートを渡すと即時実行されないようなので、最後に()をつけることでInvokeしている。
             */
            parameters.Aggregate(acumrator, (a, p) => func(a, p))();
        }

        public void DoConcatString()
        {
            /*
             * アキュムレーターが保持する値をアキュムレーター自身が保持できない(デリゲートだから)
             * そこで、値保持用のContextクラスを使用することで対応した。
             * 
             */

            var context = new ActionContext();

            Func<ActionResult> acumrator = () =>
            {
                return context.CurrentValue;
            };

            /*
             * 実際の処理呼び出し。
             * ラムダ式の中で、アキュムレーター関数の実処理を呼んでいる。
             * こうすることで実処理のテスト容易になる。
             * (これが一番の狙いか?)
             */
            DoAction(acumrator, (a, p) => () => Action.ConcatString(a, p));
        }

        public void DoCheckMaxValue()
        {
            var context = new ActionContext();

            Func<ActionResult> acumrator = () =>
            {
                context.CurrentValue.Value = "0";
                return context.CurrentValue;
            };

            DoAction(acumrator, (a, p) => () => Action.GetMaxValue(a, p));
        }
    }
}


Action.ConcatStringのテストコード。

[TestClass()]
public class ActionTest
{
        /// <summary>
        ///ConcatString のテスト
        ///</summary>
        [TestMethod()]
        public void ConcatStringTest()
        {
            Func<ActionResult> action = () => new ActionResult() { Value = "やまだ" };
            IActionParameter param = new GenericParameter<string>("たろう");
            ActionResult expected = new ActionResult() { Value = "やまだたろう" };
            ActionResult actual;
            actual = LinqSample.Action.ConcatString(action, param);
            Assert.AreEqual(expected.Value, actual.Value);
        }

        /// <summary>
        ///GetMaxValue のテスト
        ///</summary>
        [TestMethod()]
        public void GetMaxValueTest()
        {
            Func<ActionResult> action = () => new ActionResult() { Value = "100" };
            IActionParameter param = new GenericParameter<int>(99);
            ActionResult expected = new ActionResult() { Value = "100" };
            ActionResult actual;
            actual = LinqSample.Action.GetMaxValue(action, param);
            Assert.AreEqual(expected.Value, actual.Value);
        }
}

Windows端末でIPルーティングさせる

http://cdn-ak.f.st-hatena.com/images/fotolife/h/ham007/20130717/20130717234448_original.png


上記ネットワークにおいて、
開発端末(VM)(Win7)からサーバー(VM)(XP)へ接続できるようにネットワーク設定した時のメモ

通信の流れ

開発端末(VM)(Win7) → ルーター → ホスト端末(Win7) → ホスト端末(Vista) → サーバー(VM)(XP)

ルーターのルーティングテーブル設定

ルーターに 192.168.1.0/24 は 192.168.111.104へルーティングする設定を追加する

Windows端末で別ネットワーク間のルーティングを有効にする

以下Webページを参照。これで192.168.111.0と192.168.1.0間のルーティングが行えるようになる。
@IT:Windows TIPS -- Tips:IPルーティングを有効にする方法(レジストリ設定編)

ホスト端末(Win7)のルーティング設定

ルーターに 192.168.1.0/24 は 192.168.1.101へルーティングする設定を追加する

javascriptで再帰処理

こんな感じで書きました。

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <title>再帰呼び出しサンプル</title>
  </head>
  <body>
    <p id="msg_aisatu1">おはよう</p>
    <p id="msg_aisatu2">こんにちは</p>
    <p id="msg_aisatu3">おげんきですか</p>
    <p id="msg_aisatu4">調子はどうだい?</p>
  </body>
  <script type="text/javascript">
    var Sample = function(){
      var _getUniqId = function(id){
        //javascriptはvoid関数が無いため、このように対応した
        var result = id;
        var func = function(id, cnt){
          var searchId = id + (cnt ? cnt : 1);
          var tgtEle = document.getElementById(searchId);
          if(tgtEle !== null)
            func(id, cnt ? ++cnt : 1);
          else
            result = searchId;
        }
        func(id);
        return result;
      }
      
      return{ getUniqId : _getUniqId }
    };
  
    var obj1 = new Sample();
    var result = obj1.getUniqId("msg_aisatu");
    
    //検索結果:msg_aisatu5
    console.log("検索結果:" + result);
  </script>
</html>

オブジェクト思考のキモを体感するには

このエントリーを読んで。
突破すると一気に学習が加速する「オブジェクト指向学習の壁」を突破する鍵となる知識を、中学生でも分かるように図解してみた(初学者向け) - @fromdusktildawnの本館

「壁」を突破できたと思ったのは、デコレーターパターンとコマンドパターンを実際に使いこなせる様になった時でしょうか。
対象のエントリーでは、優しく図解していることが逆にややこしくなっている気がする。(矢印大杉)

個人的経験から言うとロギング関係クラスをお題にしてオブジェクト指向を説明すると受け入れてもらえることが多かったです。
たとえば、下記のILoggerを実装するクラスたちは利用方法が統一されているため、実装の詳細関係なくロガーとしては同じように使用することができます。これがポリモーフィズムと呼ばれるものです。また、ILogger型の値として各ロガーを扱うこともできます。
(この話題より前のクラス、オブジェクト、メソッドというのは参考書などを読めば理解できるはず。これが理解できないとお話にならないと言わざる得ない。)

これらをさらに拡張して、ログレベルによるフィルタリングを行うようなデコレーターやスレッドセーフ対応を行うためのデコレーターなどを作ることで
実際に体感できるかなと。

//ロガーインターフェイス
interface ILogger
{
  //ログ書き込みをする際に呼び出すメソッド名とパラメーターを定義
  void WriteLog(string msg);
}

//標準出力へログ出力
class ConsoleLogger : ILogger
{
  void WriteLog(string msg){
    System.Console.WriteLine(msg);
  }
}

//指定ファイルへログ出力
class FileLogger : ILogger
{
  private string filePath;

  public FileLogger(string filePath){
    this.filePath = filePath;
  }

  void WriteLog(string msg){
    //ファイルをオープンし、そこへ書き込む
    using(var fs = new FileStream(filePath)){
      fs.WriteLine(msg);
    }
  }
}

//複数のロガーをまとめて使用する。
class MultiLogger : ILogger
{
  private List<ILogger> loggers = new List<ILogger>();

  public void Add(ILogger logger){
    loggers.Add(logger);
  }

  void WriteLog(string msg){
    for(var i=0;i<loggers.Count;i++){
      loggers[i].WriteLine(msg);
    }
  }
}

//使用方法
class Program
{
  static void Main(string[] args){
    //ConsoleLoggerもFileLoggerもILoggerの実装クラスなため、ILogger型変数に代入することができる。
    //(ただしインターフェイスで定義されている操作のみ呼び出し可能)
    ILogger logger = new ConsoleLogger();
    logger.WriteLog("標準出力へログ出力");
    logger = new FileLogger("c:\access.log");
    logger.WriteLog("ファイルへログ出力");

    //MultiLogger.Addメソッドの引数はILogger型。このインターフェイス実装クラスであれば、
    //実装の詳細関係なくロガーとして引き渡すことができる。
    MultiLogger multiLogger = new MultiLogger();
    multiLogger.Add(new ConsoleLogger());
    multiLogger.Add(new FileLogger("c:\access.log"));
    //ConsoleLogger、FileLoggerに "ログ出力!!!" と出力される。
    mlogger.WriteLog("ログ出力!!!");
  }
}