課金するなら断然「ふかそうち」がお得

無課金でプレイしている人も多いとは思いますが、「ふかそうち」を買った方が強いポケモンをゲットできます。
と言うのも、孵化させたポケモンはレベルも個体値も高く、最終的には、野生のポケモンを強化するより、強くなるからです。
個体値というのは、ポケモンの隠しパラメーターで攻撃力/防御力/体力がそれぞれ最大15まで設定されています。
個体値はそのポケモンで固定で変更不可能なので、レベルも一緒、技も一緒のポケモンの場合は、最終的に個体値で強さに差が出てきますので、個体値は重要です。
個体値は隠しパラメーターなので普通は確認できないですが、個体値チェッカーなどで確認することができます。
孵化させたポケモンの場合、個体値はそれぞれ10以上が保証されており、レベルも高めです。
強化するにはとてもバランスの取れたポケモンをゲットできます。
野生のポケモンの個体値は完全に0〜15のランダムです。
野生のポケモンの中には、孵化させたポケモンよりレベルが高く、その分CPも高い場合がありますが、大抵個体値が低いので、レベルを上げていくと最終的に孵化したポケモンの方が強くなります。
(ただし、個体値よりも技の方が重要なので、個体値の高低より、技が強い方のポケモンを選びましょう)

なので、強いポケモンをゲットしたければ、なるべく沢山のポケモンを孵化させましょう。
誰でも最初から「むげんふかそうち」を持っているので、1つずつでも孵化させることができますのが、
ポケモンのたまごは最大で9個持てます。
しかし、たまごは捨てることができません。
孵化させるしかたまごを消費することができないのですが、1つずつ孵化させるより9個一辺に孵化させた方が効率が良いでしょう。
そこで、必要になってくるのが「ふかそうち」です。
「ふかそうち」とは、ポケストップなどでゲットできるポケモンのたまごを孵化させる装置です。
ショップで購入でき、3回使えて、150ポケコインします。
たまごを9個孵化させようと思うと、8個の「ふかそうち」総額1200ポケコインが必要ですが、その効果は絶大です。

null
特に注目したいのが、10kmたまご(10km移動すると孵化するたまご)です。
10kmたまごには、ラプラスとカビゴンが含まれています。
ラプラスもカビゴンも最終CP3000前後の最強クラスのポケモンです。
両者ともに、野生でもゲットできますが、出現率が低いうえに、レベルも個体値もランダムのため、弱い可能性があります。
その点、孵化させた場合は、強いことが保証されています。

ただ、10kmたまごも20個に1個ぐらいの確率でしかゲットできないうえに、10kmたまごで生まれるポケモンもランダムな点が難点です。
筆者は今まで478個のたまごを孵化させましたが、ラプラス0匹、カビゴン2匹という状況です。
ただし、2匹のカビゴンはともに生まれたときからCP1800前後(生まれるポケモンのレベルはプレイヤーのレベルによるので参考程度に)で、
ジムバトルでエース級の活躍をしています。

一度ゲットしてしまえば最後まで育て甲斐のあるポケモンがゲットできるので、ぜひ孵化させていきましょう。
そのためには移動する必要があります。
御幣島駅 ポケストップ周回コースなどを回って移動距離を稼ぎましょう。
ポケモンGOは移動してたまごを孵化させること、そして、プレイヤーレベルを上げることが必勝法と言えます。
プレイヤーレベルを上げるためには「しあわせたまご」を使うのが良いでしょう。
いずれ、「しあわせたまご」についても解説します。


0

御幣島駅 ポケストップ周回コース

nishiyodogawa-ku
御幣島周辺でポケストップを最も効率よく周れるコースを紹介します。

自転車でゆっくり周っても10分ぐらいで15箇所のポケストップを周れます。
1周回るとスタート地点に戻ってきます。
ポケストップは5分程度で再びアイテムをゲットできるようになるので、スタート地点に戻った頃にはまたスタート地点のポケストップからアイテムをゲットできます。
数周回れば、かなりの量のアイテムを集めることができるでしょう。
モンスターボールやキズぐすりが足りない場合に回ると良いでしょう。
筆者は1周回っただけで50個ぐらいアイテムをゲットしました。
(ゲットできるアイテム数はプレイヤーのレベルによって違うので参考程度にしてください。)
また、たまごを孵化させるために移動したい場合も、何も無いところを移動するより、周り甲斐があります。
ポケソースも10箇所ぐらい遭遇しますので、ポケモンを捕まえながら回るのも良いでしょう。
このコースの特徴はほとんど信号待ちしなくて良く、車にあまり遭遇しないという点です。
自転車(徒歩も含む)で短時間で移動距離を稼ぎたい、ポケストップを回りたい場合に信号待ちは馬鹿にできないロスタイムになってしまいますので、このコースは重宝します。
梅田や難波などの都心に行けば、いくらでもポケストップの密集地帯はあるでしょうが、御幣島周辺でポケストップの密集地帯はなかなかありません。
このコースをぜひ有効活用しましょう。

コースとしては、JR御幣島駅の地上にある歌島交差点の北東側、西淀川区役所にあるポケストップ大阪市立西淀川図書館からスタートします。
以下、訪れるポケストップの順序を列挙します。
1. 大阪市立西淀川図書館
2. みおつくしの鐘
3. 西淀川区特製マンホール0811150
4. 歌島橋バスターミナル
5. 泰心堂
6. JR御幣島駅3番出口
7. 井上貞治郎(段ボールの生みの親)の石
8. 石灯籠 日本ビルコン
9. 御幣島六地蔵
10. 初代社長石川勝治之像
11. Five Sence Lab
12. 西栄寺本堂
13. 西栄寺
14. キッズスペース
15. 西淀川区役所駐車場


4

ポケモンの巣とポケソース

ポケモンGOプレイヤーなら、ポケモンの巣はよく耳にすると思うので説明不要かも知れませんが、
改めて簡単に説明すると特定のポケモンが沢山出現する場所です。
例えば大阪なら扇町公園はアーボの巣になっていて、扇町公園に行けば、アーボが沢山出現します。
特定のポケモンが沢山出現するのはその場所に複数のポケソースが設定されているからです。
ポケソースというのは耳馴染みが薄いかも知れませんが、一定時間間隔で同じポケモンが出現し続ける場所を言います。
このポケソースが複数設定されているところがポケモンの巣になるわけです。
ポケソースについては下記のリンクが詳しいので詳細は下記のリンクを読んでください。
【ポケモンGO】ポケソースの調べ方と見つけ方

このブログで歌島公園 ブーバーの巣御幣島東公園 スリープの巣を紹介しましたが、
それぞれポケソースが1箇所しか設定されていないので、「巣」と表現するのは大げさかも知れませんが、読者のみなさんに分かりやすく伝えるために、そう呼んでいることをご了承ください。

さて、このポケモンの巣、しいてはポケソースですが、上記のリンクの記事にも書いてある通り、ルアーモジュールとは関係なく時間と場所固定で出現します。
ということは、ポケモンの巣でルアーモジュールを使っても、ポケソースに設定されているポケモンは出現しないということです。
例えば、御幣島東公園 スリープの巣でルアーモジュールを使ったとしても、ルアーモジュール周辺にスリープが出現することはありません。
ポケソースに設定されているポケモンはあくまでその時間にその場所に行ってこそ出現します。
おなじくポケモンを出現させるアイテム「おこう」もありますが、これもポケソースとは関係ありません。
御幣島東公園 スリープの巣で「おこう」を使っても、それによってスリープは出現しません。

ルアーモジュールについてはルアーモジュールの効果を勘違いしていませんか?を参照ください。
「おこう」の効果については別記事で説明したいと思います。


1

御幣島東公園 スリープの巣


(グーグルマップでは御幣島東公園が表示されなかったので代わりに西淀川区民ホールを表示しました。御幣島東公園は西淀川区民ホールの南側にあります)
マップナビおおさかの地図
大阪市西淀川区御幣島3丁目7番

調査日時:2016/08/04 19:37〜20:06の30分
御幣島東公園では定期的にスリープが出現します。
歌島公園を調査中に発見したので、正確な時間を測っては調査していないのですが、30分毎に1体出現する頻度のようです。
調査中には19:37に1体、20:06に1体出現しました。
御幣島東公園の北西部もしくは中央部(ジムの「風見鶏の時計塔」の付近)に出現します。
御幣島東公園周辺で「ちかくのポケモン」にスリープが表示された場合、ここにくれば出現するでしょう。
スリープ目的で近隣を徘徊する場合は、30分毎に1体という低頻度であるため、歌島公園のブーバーなど他のポケモン捕獲も含めて、近隣の公園も一緒に徘徊することをオススメします。


1

歌島公園 ブーバーの巣


大阪府大阪市西淀川区御幣島5丁目7
歌島公園内の南西部でブーバーが定期的に出現します。

調査日時:2016/08/04 17:55〜18:55の一時間

歌島公園の周りの道を一周10分〜15分ほどかけて、4周ぐらい(約1時間)調査した結果、ブーバーが4体も出ました。
17時55分から調査開始し、57分に公園内の南西部(ポケストップのレックスシティ歌島公園、大阪武術太極拳トレーニングセンターが並んでいる方面)でいきなり一体出現、続けて18時ちょうどに南東部(信号のある交差点付近)に一体出現!
18時31分に同じく南東部で一体出現、47分にも南東部で一体出現しました。
南西部で1体、南東部で3体の計4体のブーバーが出現しました。
他に東部でイーブイ3体、西部でナゾノクサ1体も出現(他にポッポ1体、コラッタ4体)
ブーバーの出現する箇所はほぼ南東部に固定されているようです。
歌島公園付近で「近くにいるポケモン」にブーバーが表示されたら歌島公園の南東部に行けば大体出現すると思われます。
歌島公園の北部(グラウンドより北側)はほとんどポケモンが出現しないので、基本的には南部(グラウンドより南側)を探す方が良いでしょう。
またポケモンの出現頻度が15分〜30分と間隔が長いので、他の公園と合わせて周る方が良いでしょう。
(追々、他の公園と合わせた周遊コースを考えてみたいと思います。)


1

angular-fullstackをTypeScriptで書き換えてみよう

AngularJSをTypeScriptで書くと分かりやすいコードが書ける。
それを実証するために、angular-fullstakをTypeScriptで書き換えてみる。

参考文献
AngularJS+TypeScriptを試してみた。

なお、ここで想定している環境は下記の通り。
・Lubuntu(Ubuntu) 14.04
・angular-fullstakでアプリ構築済み
 構築していない場合は下記URLを参考に構築すること
 YEOMANを使ってMEAN(MongoDB+Express+AngularJS+Node.js)を作成しよう
・TypeScript開発環境構築済み
 構築していない場合は下記URLを参考に構築すること
 AtomでTypeScriptの開発環境を構築しよう

1. 型定義ファイルをインストールする

下記コマンドを実行

tsd install angular-ui-router --save
tsd install angular-resource --save
tsd install angular-cookies --save
tsd install lodash --save
tsd install socket.io-client --save

※ 他にも必要なファイルがある場合は、適宜インストールすること

2. TypeScriptのコンパイラーターゲットをES6にする

tsconfig.jsonで、targetをes6に変更する。(すでにangular-fullstackがBabelを使ってES6で書かれているため)

{
  "compilerOptions": {
    "target": "es6",
  }
}

次に、angular-fullstakの元々のコードとTypeScriptに書き換えたコードを列挙していく。

3. controllerを書き換える

例として client/app/main/main.controller.js を書き換える。
元のJavaScriptがすでにES6によるclass化がされているので、変換後のJavaScriptも元のJavaScriptとほとんど変わらない。

元のJavaScriptは下記の通り。

'use strict';

(function() {

class MainController {

  constructor($http, $scope, socket) {
    this.$http = $http;
    this.awesomeThings = [];

    $http.get('/api/things').then(response => {
      this.awesomeThings = response.data;
      socket.syncUpdates('thing', this.awesomeThings);
    });

    $scope.$on('$destroy', function() {
      socket.unsyncUpdates('thing');
    });
  }

  addThing() {
    if (this.newThing) {
      this.$http.post('/api/things', { name: this.newThing });
      this.newThing = '';
    }
  }

  deleteThing(thing) {
    this.$http.delete('/api/things/' + thing._id);
  }
}

angular.module('sampleApp')
  .controller('MainController', MainController);

})();

TypeScriptは下記の通り。
ここでconstructorの引数socketの型がanyであることに注目。
anyというは「何でもあり」を意味し、型を定義していないのと同義なので、TypeScriptにするメリットが得られない。
しかし、socketはangular-fullstackが作成しているので型定義ファイルが無い。
そこでとりあえずはanyとしておき、後でsocketの型を定義することにする。
main.controller.ts

/// <reference path="../../../typings/tsd.d.ts" />

'use strict';

class MainController {
  private awesomeThings: {};
  private newThing: string;

  constructor(private $http: angular.IHttpService, $scope: angular.IScope, socket: any) {
    $http.get('/api/things').then(response => {
      this.awesomeThings = response.data;
      socket.syncUpdates('thing', this.awesomeThings);
    });

    $scope.$on('$destroy', function() {
      socket.unsyncUpdates('thing');
    });
  }

  public addThing(): void {
    if (this.newThing) {
      this.$http.post('/api/things', { name: this.newThing });
      this.newThing = '';
    }
  }

  public deleteThing(thing): void {
    this.$http.delete('/api/things/' + thing._id);
  }
}

angular.module('sampleApp')
  .controller('MainController', MainController);

変換後のJavaScriptは下記の通り。

/// <reference path="../../../typings/tsd.d.ts" />
'use strict';
class MainController {
    constructor($http, $scope, socket) {
        this.$http = $http;
        $http.get('/api/things').then(response => {
            this.awesomeThings = response.data;
            socket.syncUpdates('thing', this.awesomeThings);
        });
        $scope.$on('$destroy', function () {
            socket.unsyncUpdates('thing');
        });
    }
    addThing() {
        if (this.newThing) {
            this.$http.post('/api/things', { name: this.newThing });
            this.newThing = '';
        }
    }
    deleteThing(thing) {
        this.$http.delete('/api/things/' + thing._id);
    }
}
angular.module('sampleApp')
    .controller('MainController', MainController);

4. serviceを書き換える

先ほどanyとしたsocketをclass化して型を定義する。
client/components/socket/socket.service.js

元のJavaScirptは下記の通り。

/* global io */
'use strict';

angular.module('sampleApp')
  .factory('socket', function(socketFactory) {
    // socket.io now auto-configures its connection when we ommit a connection url
    var ioSocket = io('', {
      // Send auth token on connection, you will need to DI the Auth service above
      // 'query': 'token=' + Auth.getToken()
      path: '/socket.io-client'
    });

    var socket = socketFactory({ ioSocket });

    return {
      socket,

      /**
       * Register listeners to sync an array with updates on a model
       *
       * Takes the array we want to sync, the model name that socket updates are sent from,
       * and an optional callback function after new items are updated.
       *
       * @param {String} modelName
       * @param {Array} array
       * @param {Function} cb
       */
      syncUpdates(modelName, array, cb) {
        cb = cb || angular.noop;

        /**
         * Syncs item creation/updates on 'model:save'
         */
        socket.on(modelName + ':save', function (item) {
          var oldItem = _.find(array, {_id: item._id});
          var index = array.indexOf(oldItem);
          var event = 'created';

          // replace oldItem if it exists
          // otherwise just add item to the collection
          if (oldItem) {
            array.splice(index, 1, item);
            event = 'updated';
          } else {
            array.push(item);
          }

          cb(event, item, array);
        });

        /**
         * Syncs removed items on 'model:remove'
         */
        socket.on(modelName + ':remove', function (item) {
          var event = 'deleted';
          _.remove(array, {_id: item._id});
          cb(event, item, array);
        });
      },

      /**
       * Removes listeners for a models updates on the socket
       *
       * @param modelName
       */
      unsyncUpdates(modelName) {
        socket.removeAllListeners(modelName + ':save');
        socket.removeAllListeners(modelName + ':remove');
      }
    };
  });

Socket.syncUpdatesの引数cbにデフォルト引数が付いていることに注目。
呼び出し側でcbを省略したときはangular.noopが適用される。
実際main.controller.tsではcb未設定で呼び出されている。
試しにcbのデフォルト引数を削除するとmain.controller.tsでSocketのエラーになる。
※ 元のコードではunsyncUpdates()でsocket.removeAllListeners()を使っているが、socket.removeListener()の間違いと思われる。(こういう間違いが見つけやすいのがTypeScriptの良いところだろう)
※ Socket.constructor()の引数socketFactoryがanyとなっているのは、angular-socket-ioの.d.tsファイルが無いため、型定義できないためである。
socket.service.ts

/// <reference path="../../../typings/tsd.d.ts" />

/* global io */
'use strict';

class Socket {
  private socket: SocketIOClient.Socket;

  constructor(socketFactory: any) {
    // socket.io now auto-configures its connection when we ommit a connection url
    var ioSocket = io('', {
      // Send auth token on connection, you will need to DI the Auth service above
      // 'query': 'token=' + Auth.getToken()
      path: '/socket.io-client'
    });

    this.socket = socketFactory({ ioSocket });
  }

  /**
   * Register listeners to sync an array with updates on a model
   *
   * Takes the array we want to sync, the model name that socket updates are sent from,
   * and an optional callback function after new items are updated.
   *
   * @param {String} modelName
   * @param {Array} array
   * @param {Function} cb
   */
  public syncUpdates(modelName: string, array: any, cb: Function = angular.noop): void {
    /**
     * Syncs item creation/updates on 'model:save'
     */
    this.socket.on(modelName + ':save', function(item: any): void {
      var oldItem = _.find(array, {_id: item._id});
      var index = array.indexOf(oldItem);
      var event = 'created';

      // replace oldItem if it exists
      // otherwise just add item to the collection
      if (oldItem) {
        array.splice(index, 1, item);
        event = 'updated';
      } else {
        array.push(item);
      }

      cb(event, item, array);
    });

    /**
     * Syncs removed items on 'model:remove'
     */
    this.socket.on(modelName + ':remove', function(item: any): void {
      var event = 'deleted';
      _.remove(array, {_id: item._id});
      cb(event, item, array);
    });
  };

  /**
   * Removes listeners for a models updates on the socket
   *
   * @param modelName
   */
  public unsyncUpdates(modelName: string): void {
    this.socket.removeListener(modelName + ':save');
    this.socket.removeListener(modelName + ':remove');
  };
}

angular.module('sampleApp')
  .service('socket', Socket);

変換後のJavaScriptは下記の通り。

/// <reference path="../../../typings/tsd.d.ts" />
/* global io */
'use strict';
class Socket {
    constructor(socketFactory) {
        // socket.io now auto-configures its connection when we ommit a connection url
        var ioSocket = io('', {
            // Send auth token on connection, you will need to DI the Auth service above
            // 'query': 'token=' + Auth.getToken()
            path: '/socket.io-client'
        });
        this.socket = socketFactory({ ioSocket: ioSocket });
    }
    /**
     * Register listeners to sync an array with updates on a model
     *
     * Takes the array we want to sync, the model name that socket updates are sent from,
     * and an optional callback function after new items are updated.
     *
     * @param {String} modelName
     * @param {Array} array
     * @param {Function} cb
     */
    syncUpdates(modelName, array, cb = angular.noop) {
        /**
         * Syncs item creation/updates on 'model:save'
         */
        this.socket.on(modelName + ':save', function (item) {
            var oldItem = _.find(array, { _id: item._id });
            var index = array.indexOf(oldItem);
            var event = 'created';
            // replace oldItem if it exists
            // otherwise just add item to the collection
            if (oldItem) {
                array.splice(index, 1, item);
                event = 'updated';
            }
            else {
                array.push(item);
            }
            cb(event, item, array);
        });
        /**
         * Syncs removed items on 'model:remove'
         */
        this.socket.on(modelName + ':remove', function (item) {
            var event = 'deleted';
            _.remove(array, { _id: item._id });
            cb(event, item, array);
        });
    }
    /**
     * Removes listeners for a models updates on the socket
     *
     * @param modelName
     */
    unsyncUpdates(modelName) {
        this.socket.removeListener(modelName + ':save');
        this.socket.removeListener(modelName + ':remove');
    }
}
angular.module('sampleApp')
    .service('socket', Socket);

先ほどのmain.controller.tsでsocketの型を定義する。

/// <reference path="../../../typings/tsd.d.ts" />
/// <reference path="../../components/socket/socket.service.ts" />

'use strict';

class MainController {
  private awesomeThings: {};
  private newThing: string;

  constructor(private $http: angular.IHttpService, $scope: angular.IScope, socket: Socket) {

5. directiveを書き換える

client/components/footer/footer.directive.jsを書き換えてみる。

元のJavaScriptは下記の通り。

'use strict';

angular.module('sampleApp')
  .directive('footer', function () {
    return {
      templateUrl: 'components/footer/footer.html',
      restrict: 'E',
      link: function(scope, element) {
        element.addClass('footer');
      }
    };
  });

TypeScriptは下記の通り。
footer.directive.ts

/// <reference path="../../../typings/tsd.d.ts" />
'use strict';

class Footer implements angular.IDirective {
  templateUrl = 'components/footer/footer.html';
  restrict = 'E';
  link(scope: angular.IScope, element: angular.IAugmentedJQuery): void {
    element.addClass('footer');
  }
}

angular.module('sampleApp')
  .directive('footer', () => new Footer());

変換後のJavaScriptは下記の通り。

/// <reference path="../../../typings/tsd.d.ts" />
'use strict';
class Footer {
    constructor() {
        this.templateUrl = 'components/footer/footer.html';
        this.restrict = 'E';
    }
    link(scope, element) {
        element.addClass('footer');
    }
}
angular.module('sampleApp')
    .directive('footer', () => new Footer());

6. angular-resourceを書き換える

最後におまけとしてangular-resourceを使っているclient/components/auth/user.service.jsを書き換えてみる。
angular-resourceは元のJavaScriptから随分違うコードに書き換える必要があるので注意が必要だ。
参考文献: How to use AngularJS ng.resource.IResource with TypeScript.

元のJavaScriptは下記の通り。

'use strict';

(function() {

function UserResource($resource) {
  return $resource('/api/users/:id/:controller', {
    id: '@_id'
  }, {
    changePassword: {
      method: 'PUT',
      params: {
        controller:'password'
      }
    },
    get: {
      method: 'GET',
      params: {
        id:'me'
      }
    }
  });
}

angular.module('sampleApp.auth')
  .factory('User', UserResource);

})();

TypeScriptは下記の通り。
user.service.ts

/// <reference path="../../../typings/tsd.d.ts" />

'use strict';

interface Password {
  oldPassword: string;
  newPassword: string;
}

interface User extends angular.resource.IResource<User> {
  _id: string;
  name: string;
  email: string;
  password: string;
  role: string;
}

interface UserResource extends angular.resource.IResourceClass<User> {
  changePassword(id: any, password: Password, successCallback: any, errorCallback: any): User;
  get(): User;
}

angular.module('sampleApp.auth')
  .factory('User', ($resource: angular.resource.IResourceService) => {
    var changePasswordAnction: angular.resource.IActionDescriptor = {
      method: 'PUT',
      params: {
        controller: 'password'
      }
    };

    var getAction: angular.resource.IActionDescriptor = {
      method: 'GET',
      params: {
        id: 'me'
      }
    };

    return <UserResource>$resource('/api/users/:id/:controller', {
      id: '@_id'
    }, {
      changePassword: changePasswordAnction,
      get: getAction
    });
  }
);

変換後のJavaScriptは下記の通り。

/// <reference path="../../../typings/tsd.d.ts" />
'use strict';
angular.module('sampleApp.atuh')
    .factory('User', ($resource) => {
    var changePasswordAnction = {
        method: 'PUT',
        params: {
            controller: 'password'
        }
    };
    var getAction = {
        method: 'GET',
        params: {
            id: 'me'
        }
    };
    return $resource('/api/users/:id/:controller', {
        id: '@_id'
    }, {
        changePassword: changePasswordAnction,
        get: getAction
    });
});

0

AtomでTypeScriptの開発環境を構築しよう

最近、TypeScriptにハマってます。
TypeScriptでAngularJSを書くと大変読みやすいコードが書けます。
TypeScriptの開発環境はAtomで構築するのが一番だろう。
というわけで、
UbuntuにAtomをインストールして、TypeScriptの開発環境の構築方法を説明する。

なお、ここで想定している環境は下記の通り。
Lubuntu(Ubuntu) 14.04
node.js インストール済み

1. Atomのインストール

参考文献: Ubuntu 14.04 に Atom をインストールして、起動チェックしてから、パッケージ導入するまで

下記のコマンド実行

sudo add-apt-repository ppa:webupd8team/atom
sudo apt-get update
sudo apt-get install atom

インストールが完了したら、スタートメニュー > プログラミング > Atom からAtomを起動できる

2. TypeScriptとtsdのインストール

参考文献: TypeScript の開発環境構築と周辺ツールの紹介

ちなみに、tsdとは型定義ファイルマネージャでTypeScirptの.d.tsファイルを管理するツールである。

下記のコマンド実行

npm install -g typescript
npm install -g tsd

3. AtomにTypeScript開発環境を構築する

下記URL参照
AtomでTypeScriptの環境を構築する

なお、筆者は上記のtsconfig.jsonのうち、下記の設定にカスタマイズしている。

{
  "formatCodeOptions": {
    "indentSize": 2, //自動インデントを2に設定
    "tabSize": 2, //タブサイズを2に設定
  }
}

0

YEOMANを使ってMEAN(MongoDB+Express+AngularJS+Node.js)を作成しよう

YEOMANを使ってMEANを作成する手順と開発チュートリアルを説明する。
MEANとはMongoDB+Express+AngularJS+Node.jsを組み合わせたWebアプリケーションである。
YEOMANとはフレームワークを簡単に作成できるツールで、node.jsのパッケージとして提供されている。
MEANのフレームワークにはangular-fullstakを使う。
※Yeomanで用意されているジェネレーターは沢山有るがMEANを作成できるジェネレーターで一番人気がangular-fullstak
 
ほとんどの手順は下記URLに従う。
YEOMANを使ってMEAN(MongoDB + Express.js + Angular.js + Node.js)のWebアプリケーションを作る
しかし、上記URLはYEOMANのバージョンが古いためか、チュートリアルの内容が現状のバージョンに沿わないため、下記であらためて説明する。
 
なお、ここで想定している開発環境は下記の通り。
Lubuntu(Ubuntu) 14.04
Node.js v4.2.3
yo 1.6.0
MongoDB 3.2.0
※ 上記以外のバージョンではチュートリアルの内容が沿わない場合がある
 

0. 事前準備

まずはangular-fullstakに必要なアプリをインストールする。
 

0.1. Node.jsのインストール

下記URL参照
Ubuntu 14.04 に Node.jsをインストールする
 

0.2. MongoDBのインストール

下記URL参照
Install MongoDB Community Edition on Ubuntu
 

0.3. Rubyとgemのインストール

下記URL参照
UbuntuにRubyGemsをインストールする
※なお、フレームワークにSassを使わない場合はRubyとgemをインストールする必要はない。
 

0.4. Sassのインストール

端末から下記コマンドを実行する

gem install sass

 

0.5. Yeomanのインストール

npm install -g yo grunt-cli bower

※Yeomanとはyo, grunt, bowerを組み合わせたもの
 

0.6. angular-fullstakのインストール

npm install -g generator-angular-fullstack
npm update -g

※yoが1.4.1以上でないとangular-fullstackが動かないのでアップデートすること
 

0.7. node-inspectorのインストール

デバッガを使う場合は下記コマンドを実行する。

npm install -g node-inspector

以上で事前準備は完了した。
次にMEANアプリの開発チュートリアルを説明する。
 

1. MEANアプリの雛形を作成する

yoを使ってMEANアプリを作成する。
アプリを作る場所はユーザーディレクトリの配下にする。
※ちなみにVMWareなどのバーチャルPCでの共有フォルダにはアプリは作れない。アプリ作成時にシンボリックリンクを貼るが、共有フォルダにはシンボリックリンクが貼れないため。
なお、アプリ名はsampleとする。
 

1.1. sampleディレクトリの作成

mkdir sample
cd sample

※ディレクトリ名がそのままアプリ名になる。
 

1.2. MEANアプリを作成する

yo angular-fullstack

なお、アプリの作成はウィザード方式になっており、各設定をダイアログで設定する。
各項目と選択すべき項目を列挙する。(▼が選択すべき項目 ●はチェックボックスの選択状態 ○はチェックボックスの非選択状態)

[?] What would you like to write scripts with? 
▼Babel
 TypeScript

 

[?] What would you like to write makeup with?
▼HTML
 Jade

 

[?] What would you like to write stylesheets with?
 CSS
▼Sass
 Stylus
 Less

※今回のチュートリアルではスタイルシートは弄らないのでSass以外を選んでも問題ない
 

[?] What Angular router would you like to use?
 ngRoute
▼uiRouter

 

[?] Would you like to include Bootstrap? Yes

 

[?] Would you like to include UI Bootstrap? Yes

 

[?] What would you like to use for data modeling?
●Mongoose (MongoDB)
○Sequelize (MySQL, SQLite, MariaDB, PostgreSQL)

 

[?] Would you scaffold out an authentication boilerplate? Yes

 

[?] Would you like to include additional oAuth strategies?
●Google
●Facebook
●Twitter

※今回のチュートリアルでは関係ないので何を選んでも良い
 

[?] Would you like to use socket.io? Yes

 

[?] What would you like to write tests with?
▼Jasmine
 Mocha + Chai + Sinon

 

1.3. 動作確認する

grunt serve

ブラウザが自動的に起動して下図の画面が表示されれば成功である。
yeoman.01.01
 

2. routerを作成する

yoで作られたMEANアプリにメンバー一覧ページを追加するというチュートリアルを説明する。
処理の流れとしては、
1.yoコマンドでrouterの雛形を作成する
2.routerのhtmlを編集する
3.routerのcontrolerを編集する
という流れになる。
 

2.1. ページを追加する

Ctrl + Cでgruntを止めて、下記のコマンドを実行する。

yo angular-fullstack:route member

下記のダイアログは全てデフォルトにする。
[?] Where would you like to create this route? client/app/
[?] What will the url of your route be? member
すると下記のファイルが作成される。
create client/app/member/member.js
create client/app/member/member.controller.js
create client/app/member/member.controller.spec.js
create client/app/member/member.html
create client/app/member/member.scss
 
動作確認する。

grunt serve

http://localhost:9000/memberにアクセスして、下図が表示されれば成功である。
yeoman.01.02
 

2.2. htmlを編集する

client/app/member/member.htmlを下記の通り編集する。

編集前
<div class="col-md-12">
This is the member view.
</div>

 

編集後
<h2>メンバー一覧</h2>
<ul>
  <li ng:repeat="member in members">
    {{member.name}}
  </li>
</ul>

 

2.3. ダミーデータを追加する

メンバーが正しく表示されるかを確認するためにダミーデータを追加する。(ダミーデータを後からmongoDBのデータに置き換える)
client/app/member/member.controller.jsを下記の通り編集する。

編集前
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope) {
    $scope.message = 'Hello';
  });

 

編集後
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope) {
    $scope.members = [{name:'田中'},{name:'鈴木'}];
  });

 

2.4. 動作確認する

http://localhost:9000/memberにアクセスして、下図の通り表示されれば成功である。
yeoman.01.03
 

3. clientからserverをGETする

処理の流れとしては、
1.clientからserverの/api/membersをGETで呼び出し
2.serverはcontroller.index関数へルーティング
3.controller.index関数でMongoDBにアクセス
4.MongoDBがデータを返す
という流れになる。
 

3.1. APIを追加する

Ctrl + Cでgruntを止めて、下記のコマンドを実行する。

yo angular-fullstack:endpoint member

下記のダイアログは全てデフォルトにする。
[?] What will the url of your endponit to be? /api/members
すると下記のファイルが作成される。
create server/api/member/index.js
create server/api/member/member.controller.js
create server/api/member/member.model.js
create server/api/member/member.socket.js
create server/api/member/member.spec.js
 

3.2. スキーマを定義する

メンバー一覧に表示する名前を定義する。
server/api/member/member.model.jsを下記の通り編集する。

編集前
'use strict';

var mongoose = require('bluebird').promisifyAll(require('mongoose'));

var MemberSchema = new mongoose.Schema({
  name: String,
  info: String,
  active: Boolean
});

export default mongoose.model('Member', MemberSchema);

 

編集後
'use strict';

var mongoose = require('bluebird').promisifyAll(require('mongoose'));

var MemberSchema = new mongoose.Schema({
  name: String,
});

export default mongoose.model('Member', MemberSchema);

 

3.3. MongoDBにデータを追加する

MongoDBに初期データを追加する。
server/api/member/member.controller.jsのMember変数定義以降に下記を追加する。

編集前
'use strict';

import _ from 'lodash';
import Member from './member.model';

 

編集後
'use strict';

import _ from 'lodash';
import Member from './member.model';

Member.find({}).remove(function() {
  Member.create({
    name: '田中_2'
  }, {
    name: '鈴木_2'
  }, function(err) {
    console.log('finished populating Members');
  });
});

 

3.4. サーバーにGETが定義されていることを確認する

server/api/member/index.jsに下記の通りgetが定義されていることを確認する。

router.get('/', controller.index);

 
server/api/member/member.controller.jsに下記の通りindex関数が定義されていることを確認する。

// Gets a list of Members
export function index(req, res) {
  Member.findAsync()
    .then(respondWithResult(res))
    .catch(handleError(res));
}

※上記のコードはangular-fullstackによって自動生成される。
 

3.5. APIに接続する

clientからserverのapiを参照する。
client/app/member/member.controller.jsを下記の通り編集する。

編集前
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope) {
    $scope.members = [{name:'田中'},{name:'鈴木'}];
  });

 

編集後
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
    });
  });

 

3.6. 動作確認する

http://localhost:9000/memberにアクセスして、下図の通り表示されれば成功である。
yeoman.01.04
 

4. clientからserverへPOSTする

処理の流れとしては、
1.clientからserverの/api/membersをPOSTで呼び出し
2.serverはcontroller.create関数へルーティング
3.controller.create関数でMongoDBにアクセス
4.MongoDBへデータを保存する
という流れになる。
 

4.1. メンバー登録フォームを追加する

メンバーページからメンバーを登録できるようにする。
client/app/member/member.htmlを下記の通り編集する。

編集前
<h2>メンバー一覧</h2>
<ul>
  <li ng:repeat="member in members">
    {{member.name}}
  </li>
</ul>

 

編集後
<div ng-controller="MemberCtrl">
  <h2>メンバー登録</h2>
  <form >
    <legend>メンバー登録</legend>
    <label>名前</label> 
    <input type="text" id="name" name="name" ng-model="member.name"> 
    <button class="btn btn-primary" ng-click="createMember()">登録</button>
  </form>

  <h2>メンバー一覧</h2>
  <ul>
    <li ng:repeat="member in members">
      {{member.name}}
    </li>
  </ul>
</div>

 

4.2. 登録ボタンのイベントハンドラーを追加する

ボタンが動作するように、イベントハンドラーを追加する。
client/app/member/member.controller.jsを下記の通り編集する。

編集前
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
    });
  });

 

編集後
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
    });

    $scope.createMember = function() {
      if ($scope.member && $scope.member.name) {
        $scope.members.push({
          name: $scope.member.name
        });
        $scope.member.name = '';
      }
    };
  });

 

4.3. 動作確認する

http://localhost:9000/memberにアクセスして、任意の名前(例では佐藤)を入力して登録ボタンを押して、下図の通り表示されれば成功である。
yeoman.01.05
 

4.4. 登録データをPOSTする

このままではサーバーにデータが保存されていないので、データをサーバーへPOSTする。
client/app/member/member.controller.jsを下記の通り編集する。

編集前
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
    });

    $scope.createMember = function() {
      if ($scope.member && $scope.member.name) {
        $scope.members.push({
          name: $scope.member.name
        });
        $scope.member.name = '';
      }
    };
  });

 

編集後
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
    });

    $scope.createMember = function() {
      if ($scope.member && $scope.member.name) {
        $http.post('/api/members', $scope.member).success(function() {
          $scope.members.push({
            name: $scope.member.name
          });
          $scope.member.name = '';
        });
      }
    };
  });

 

4.5. サーバーにPOSTが定義されていることを確認する

server/api/member/index.jsに下記の通りpostが定義されていることを確認する。

router.post('/', controller.create);

 
server/api/member/member.controller.jsに下記の通りcreate関数が定義されていることを確認する。

// Creates a new Member in the DB
export function create(req, res) {
  Member.createAsync(req.body)
    .then(respondWithResult(res, 201))
    .catch(handleError(res));
}

※上記のコードはangular-fullstackによって自動生成される。
 

4.6. 動作確認する

http://localhost:9000/memberにアクセスして、任意の名前(例では佐藤)を入力して登録ボタンを押して、さらにページ更新して、下図の通り表示されれば成功である。
yeoman.01.05
 

5. socket.ioでページを同期させる

angular-fullstackではsocket.ioをページの同期に使っているようなので、それについても説明する。
処理の流れとしては、
1.clientでページ読み込み時(/api/memberをGETする時)にsocket通知によるデータ配列追加/削除処理を登録しておく。(syncUpdates関数)
2.serverではMongoDBにデータを追加した際にMongoDBのポストホック機能(Member.schema.post関数)からホックしている全てのclientへsocket通知を送信する。
3.clientではsocket通知を受け取ったら、データ配列に追加する。(データは$scope内に定義しているので、angularJSにより自動的にページ更新がかかる。)
という流れになる。
 

5.1. socket.syncUpdates()を呼び出す

client/app/member/member.controller.jsを下記の通り編集する。

編集前
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
    });

    $scope.createMember = function() {
      if ($scope.member && $scope.member.name) {
        $http.post('/api/members', $scope.member).success(function() {
          $scope.members.push({
            name: $scope.member.name
          });
          $scope.member.name = '';
        });
      }
    };
  });

 

編集後
'use strict';

angular.module('sampleApp')
  .controller('MemberCtrl', function ($scope, $http, socket) {
    $scope.members = [];

    $http.get('/api/members').success(function(members) {
      $scope.members = members;
      socket.syncUpdates('member', $scope.members);
    });

    $scope.createMember = function() {
      if ($scope.member && $scope.member.name) {
        $http.post('/api/members', $scope.member).success(function() {
          $scope.member.name = '';
        });
      }
    };
  });

変更点は、
・/api/membersのGET時にsocket.syncUpdates呼び出し
・socket.syncUpdatesでメンバー一覧の更新が行われるので、createMember関数でのメンバー追加処理は削除する
 

5.2. socket.syncUpdates()の定義を確認する

/client/components/socket/socket.service.jsにsyncUpdates関数が定義されていることを確認する。

      /**
       * Register listeners to sync an array with updates on a model
       *
       * Takes the array we want to sync, the model name that socket updates are sent from,
       * and an optional callback function after new items are updated.
       *
       * @param {String} modelName
       * @param {Array} array
       * @param {Function} cb
       */
      syncUpdates: function (modelName, array, cb) {
        cb = cb || angular.noop;

        /**
         * Syncs item creation/updates on 'model:save'
         */
        socket.on(modelName + ':save', function (item) {
          var oldItem = _.find(array, {_id: item._id});
          var index = array.indexOf(oldItem);
          var event = 'created';

          // replace oldItem if it exists
          // otherwise just add item to the collection
          if (oldItem) {
            array.splice(index, 1, item);
            event = 'updated';
          } else {
            array.push(item);
          }

          cb(event, item, array);
        });

        /**
         * Syncs removed items on 'model:remove'
         */
        socket.on(modelName + ':remove', function (item) {
          var event = 'deleted';
          _.remove(array, {_id: item._id});
          cb(event, item, array);
        });
      },

※上記のコードはangular-fullstackによって自動生成される。
 

5.3. MongoDBのポストフック機能を使ってsocket通知が呼び出されていることを確認する

server/api/member/member.socket.jsにMongoDBへのデータ追加時にsocketからmember:saveが通知されることを確認する。

/**
 * Broadcast updates to client when the model changes
 */

'use strict';

var MemberEvents = require('./member.events');

// Model events to emit
var events = ['save', 'remove'];

export function register(socket) {
  // Bind model events to socket events
  for (var i = 0, eventsLength = events.length; i < eventsLength; i++) {
    var event = events[i];
    var listener = createListener('member:' + event, socket);

    MemberEvents.on(event, listener);
    socket.on('disconnect', removeListener(event, listener));
  }
}


function createListener(event, socket) {
  return function(doc) {
    socket.emit(event, doc);
  };
}

function removeListener(event, listener) {
  return function() {
    MemberEvents.removeListener(event, listener);
  };
}

※上記のコードはangular-fullstackによって自動生成される。
 

5.4. socket通知の登録処理が呼び出されていることを確認する

server/config/socketio.jsでregistar関数が呼ばれていること確認する。

// When the user connects.. perform this
function onConnect(socket) {
  // When the client emits 'info', this listens and executes
  socket.on('info', data => {
    socket.log(JSON.stringify(data, null, 2));
  });

  // Insert sockets below
  require('../api/member/member.socket').register(socket);
  require('../api/thing/thing.socket').register(socket);

}

※上記のコードはangular-fullstackによって自動生成される。
 

5.5. 動作確認する

ブラウザを2ウィンドウ開き、http://localhost:9000/memberにアクセスして、一方に任意の名前(例では藤原)を入力して登録ボタンを押して、もう一方に登録内容が反映されれば成功である。
yeoman.01.06
 

6. デバッガ(node-inspector)を起動する

デバッガの起動方法を説明しておく。
下記のコマンドを実行する。

grunt serve:debug

するとブラウザが自動起動してnode-inspectorが開く。
‘–debug-brk’オプション付きで起動されるので、必ずサーバー側のソースコードの先頭でブレイクする。

7. gruntでブラウザ指定する

起動するブラウザを変えたい場合、Gruntfile.jsを下記の通り変更する。

通常起動のブラウザを指定する方法(例ではchromium-browserを指定している)

  grunt.initConfig({
  //省略...
    open: {
      server: {
        url: '<%= express.options.domain %>:<%= express.options.port %>',
        app: 'chromium-browser'
      }
    },

デバッガのブラウザを指定する方法(例ではchromium-browserを指定している)

    nodemon: {
    //省略...
      debug: {
      //省略...
        options: {
       //省略...
          callback: function (nodemon) {
            // opens browser on initial server start
            nodemon.on('config:update', function () {
              setTimeout(function () {
                require('open')('http://localhost:8080/debug?port=5858', 'chromium-browser');
              }, 500);
            });
          }
        }
      }
    },

1

C++11でstd::functionとstd::bindとtemplate functionでCallbackを呼び出す

C++11ではstd::functionとstd::bindとtemplate functionを駆使するとCallbackを呼び出せる。
内部のクラス間のやりとりなら、interfaceを使うよりお手軽。

#include <functional>
#include <iostream>

class ClassA
{
public:
    typedef std::function<void(int a, int b)> Func;

    template<typename T>
    static Func BindFunc(void (T::*func)(int a, int b), T *owner)
    {
        return std::bind(func, owner, std::placeholders::_1, std::placeholders::_2);
    }
 
    void SetFunc(const Func &func)
    {
        m_func = func;
    }
 
    void CallFunc(int a, int b) const
    {
        m_func(a, b);
    } 
private:
    Func m_func;
};
 
class ClassB
{
public:
    ClassB(ClassA &classA)
    {
        classA.SetFunc(ClassA::BindFunc(&ClassB::DoFunc, this));
    }

    void DoFunc(int a, int b)
    {
        std::cout << "ClassB a:" << a << ", b:" << b << "\n";
    }
};
 
class ClassC
{
public:
    ClassC(ClassA &classA)
    {
        classA.SetFunc(ClassA::BindFunc(&ClassC::DoFunc, this));
    }

    void DoFunc(int a, int b)
    {
        std::cout << "ClassC a:" << a << ", b:" << b << "\n";
    }
};
 
int main(int argc, char** argv)
{
    ClassA classA;
 
    ClassB classB(classA);
    classA.CallFunc(1, 2);  //ClassB a:1, b:2
 
    ClassC classC(classA);
    classA.CallFunc(3, 4);  //ClassC a:3, b:4
    return 0;
}

0

node.jsをevennodeにデプロイしよう

evennodeはnode.js専用のPaaSなので、使い方は非常に簡単。
ほとんどブラウザから設定できるので迷わないとは思うが、一応使い方を説明しておく。
ローカル環境はCentOS 6.5で、gitはインストール済み、node.jsのソースコードも作成済みとする。
evennodeのサインアップやログインはHPから行える。
ここではサインアップしてログイン後のコントロールパネルからアプリの作成手順を説明する。
 

アプリの作成

コントロールパネルの「APPS」タブを開き、「CREATE NEW APP」をクリックする。
evennode.01
 

プランの選択

好きなプランを選ぶ。とりあえずお試しならFreeで良いだろう。
evennode.02
 

node.jsの設定

Domainでサブドメイン名を設定する。これは他のevennodeのアプリとかぶらない名前にする必要がある。
Server locationはEuropa(Ireland)かUnited States(lowa)かを選べる。(どちらが日本から速いとかは調べていない)
Custom Domainは独自ドメインを使う場合に設定する。
Select app’s platformはNode.jsかio.jsかを選べる。普通はNode.jsで良いだろう。
Node.js varsionはv0.8.6~最新まで指定可能。
Startup commandは自動かカスタムかを選べる。
以上でアプリが作られる。
evennode.03
 

アプリの管理

さらにアプリの詳細設定を行う。
APPタブで作ったアプリをクリックする。
evennode.04
 

Public keysの管理

Manage public keysをクリックする。
evennode.05
 

Public keysの設定

Public keys for GitにGit用の公開鍵を設定してSaveボタンを押す。
evennode.06
 

環境変数の管理

環境変数の設定が必要な場合は、Environment varsをクリックする。
evennode.07
 

環境変数の設定

Nameに環境変数名、Valueに環境変数の値を入れて、Saveボタンを押す。
evennode.08
以上でevennodeでの作業は終了。
 

app.jsの作成

ここからローカル環境での作業になる。
参考文献:Node.js Hello World app
evennodeではどうもルートディレクトリのapp.jsを起動するようになっているようだ。
(package.jsonの”main”や”scripts”: {“start”}で別のソースコードを起動するよう記述しても認識されなかった)
app.js以外から起動したい場合はapp.js内でrequireで呼ぶ。
例えば、server/app.jsを起動したい場合は、ルートディレクトリにapp.jsを作成して下記を記述する。

require('./server/app.js');

 

Gitのリモートリポジトリを登録する

git remote add evennode git@evennode.com:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.git

リポジトリのアドレスはevennodeのコントロールパネルの「Manage app > Git deployment > Repository」に記述してある。
 

デプロイする

gitでプッシュしてデプロイ完了。

git push evennode master

 

その他Tips:bower installが起動しない問題

bower installを起動する術がないので、bower installでインストールされるべきモジュール群もコミットしておく。
 

その他Tips:SSLの設定方法

設定方法は提供されていない。
support@evennode.com にメールしてSSLを設定したい旨を伝えると、SSL certificateとprivate keyを送れと返事が返ってくるので、送ると設定してくれる。
メールは英語でやり取りできる。
 

その他Tips:アプリの削除方法

APPSから削除したいアプリを選び、Settings > DELETE APP から削除できる。
evennode.09


0