Raspberry PiでIoTなシステム開発:ハードウェアPWM

Raspberry Pi歴3年目にして今頃ですがハードウェアPWMが備わっていることに気づきました。今までWiringPiのソフトウェアPWMを無理して使っていて音程のズレとか雑音に悩まされていたのですが、これで一挙解決できそうです。参考にしたのはこちら。RaspberryPiとWiringPiでサーボを動かす – Qiitaたしかに本家の記述は簡潔すぎてわかりにくいですね。百分率で設定する方が比率がわかりやすいのでRangeを100に決め打ちすると、周波数計算は以下の通りとなります。

clock = 192000 / freq

早速コードを書いてみます。

#include #include #include #include void setSignal(int p_signame);void signalHandler(int p_signame);int main(void){    setSignal(SIGINT);    wiringPiSetup();    pinMode(1,PWM_OUTPUT);    //    pwmSetMode (PWM_MODE_BAL);    pwmSetMode (PWM_MODE_MS);    pwmSetRange(100);//百分率がわかりやすいので100    pwmSetClock(218);//Rangeが100の場合、192,000÷目標の周波数    int i = 0;    while(1){        for(i=0;i<=100;i++)        {            pwmWrite(1,i);            usleep(30000);        }        /*        for(i=100;i>0;i--)        {            pwmWrite(1,i);            usleep(100000);        }*/    }}//シグナルの設定void setSignal(int p_signame){    if (signal(p_signame, signalHandler) == SIG_ERR) {    //エラー        printf(""Could not set signal handler\n"");        exit(1);    }    return;}//シグナル受信/処理void signalHandler(int p_signame){    printf(""I got signal. Number is %d.\n"", p_signame);    pinMode(1,INPUT);    exit(0);}

最初はpwmSetMode (PWM_MODE_BAL);を使っていたのですが、これだとpwmWriteをしたときに周波数まで変わってしまいました。設定する基準が違うのだと思います。12VのLEDをFETを介して駆動してみました。ストレスをかけても波形が乱れません。“””

Raspberry PiでIoTなシステム開発:圧電スピーカーを昇圧ドライブするときの最適なインダクタとパルス幅の選定

Raspberry PiでハードウェアPWMができることが分かったところで、本格的に昇圧ドライブの実験をする事にします。今回の主役はこちら。千石電商で買ったチョークコイル達です。50mHでそれなりの音量が得られたので、ここは他のインダクタンスの実験をしたいと思います。防犯ブザーを買ってきて中のコイルを引っこ抜く方が安いと思いますが、インダクタンスが分からないので、ここは素直に購入しました。先日の回路を使い、それぞれのチョークコイルに差し替えて、音量、消費電流を測定します。音量測定に使用したのはiPhoneのアプリ。正確では無いと思いますが、そもそもそれほどの正確性が必要な訳では無いので、これでよしとします。測定条件を揃えるため、iPhoneの裏にペンを貼り付けてスピーカーとマイクの距離を揃えました。測定の結果は以下の通り。50mH  26.5mA/440Hz 61.4mA/880Hz 80-84db100mH  19.1mA/440Hz 27.1mA/880Hz 82db200mH  7.2mA/440Hz 9.9mA/880Hz 77-78db500mH  1.9mA/440Hz 8.8mA/880Hz 69-74db意外ですがインダクタンスが低い方が音量が大きいという結果になりました。磁力を蓄積できる量よりも、電流量の影響が大きいということでしょうか。そういえばラジコンのモーターもターン数が小さい方がパワーが出ますね。この結果からすると100mHが電流と出力とのバランスが良いので、これを使うことにします。次はパルス幅を変えて実験します。ハードウェアPWMなので細かく設定できるのが良いです。コードはこちら。

#include #include #include #include void setSignal(int p_signame);void signalHandler(int p_signame);int main(void){    setSignal(SIGINT);    wiringPiSetup();    pinMode(1,PWM_OUTPUT);    //    pwmSetMode (PWM_MODE_BAL);    pwmSetMode (PWM_MODE_MS);    pwmSetRange(100);//百分率がわかりやすいので100    int i = 0;    pwmSetClock(436);//Rangeが100の場合、192,000÷目標の周波数    while(1){        for(i=1;i<=9;i++){            pwmWrite(1,i*10);            printf(""now %d%%\n"",i*10);            usleep(3000000);        }    }}//シグナルの設定void setSignal(int p_signame){    if (signal(p_signame, signalHandler) == SIG_ERR) {    //エラー        printf(""Could not set signal handler\n"");        exit(1);    }    return;}//シグナル受信/処理void signalHandler(int p_signame){    printf(""I got signal. Number is %d.\n"", p_signame);    pinMode(1,INPUT);    exit(0);}

10%ずつパルス幅を大きくしていって、何処が一番音量が大きくなるかを確かめます。ちなみに耳が痛いのでスピーカーの穴にはセロテープを貼っています。汚い部屋が見えていますがそこはご愛敬ということで。Macの画面が見えていませんが、音が鳴り出した最初が10%、そこから10%ずつ増えていきます。最初は電流の増加に応じて音量が上がりますが、60%のところで音量は頭打ちになりました。43mA以上は流しても無駄ですね。ちなみにこのコイルの仕様は以下の通り。仕様ぎりぎりまでまだ余裕があります。オーバードライブしていると、ピエゾはそれほどダメージは大きくなさそうなのですが、コイルが結構熱を持つので気を遣います。別に実験したのですが、パルス幅は1%だと側でも聞いていられる程度の音量になりました。なので1%、10%、60%とソフトウェアからパルス幅を操作して音量を操作できるようになりました。実装部品を増やさずに音量調整ができるのは良いことだと思います。      """

Announcing Ionic Framework 2 Beta | The Official Ionic Blogionic2が無事ベータリリースになったようなので、チュートリアルを体験してみました。が、英語なのとionic1やAngularが分かっていないと戸惑う部分が多いように思われました。そこでチュートリアルの流れを日本語で解説し、本家で触れられていない点についていくつか補足します。なおハイブリットアプリをWindowsで作る人はそういないと思いますのでMacが前提です。

読み方

チュートリアルそのものとは関係が無いのですが、ionicは「イオニック」ではなく、「アイオニック」です。ゴルフをやっていたときのグリップの影響か、今でもついイオニックと呼んでしまいますが。

Node.jsのインストール

公式通りに進めてください。ただし必ず4系を使うこと。ES6の事もあるのでそのうちNode5に対応するのだとは思いますが、今のところnumber of issesが発生するようです。

ionic 2のインストール

nodeをインストーラーを使ってインストールした場合には、npmコマンドが一緒にインストールされています。npmコマンドはnode.jsのパッケージ管理に使うコマンドです。ionicはnpmを使用してインストールします。Macだと-gオプション(グローバルインストール:どのユーザーでも使えるようにする)を使うにはsudoが必要です。コマンド実行時に管理者権限のあるユーザーで実行してパスワードを入力してください。

$ sudo npm install -g ionic@beta

これによりionicコマンドがインストールされます。ionicを引数なしで実行するとコマンドのマニュアルが表示されます。私が使っているのはbeta17のようです。

kawauchiyasuo-no-MacBook-Pro:project2 yasuo$ ionic  _             _      (_)           (_)       _  ___  _ __  _  ___  | |/ _ \| '_ \| |/ __| | | (_) | | | | | (__  |_|\___/|_| |_|_|\___|  CLI v2.0.0-beta.17Usage: ionic task args=======================Available tasks: (use --help or -h for more info)   start  ..........  Starts a new Ionic project in the specified PATH   serve  ..........  Start a local development server for app dev/testing   platform  .......  Add platform target for building an Ionic app   run  ............  Run an Ionic project on a connected device   emulate  ........  Emulate an Ionic project on a simulator or emulator   build  ..........  Build (prepare + compile) an Ionic project for a given platform.   plugin  .........  Add a Cordova plugin   resources  ......  Automatically create icon and splash screen resources (beta)"

ionic2でハイブリッドなアプリ開発:チュートリアルをチュートリアル:チュートリアル用テンプレートで入門

ionic2でハイブリッドなアプリ開発:チュートリアルをチュートリアル:サンプルプロジェクトを導入して実機で実行するまでこの記事の通りですが、とりあえずionic2のサンプルをそのままならば実行できる状態になりました。が、もちろんそれでは何も面白くありませんので、チュートリアルの本編を敷衍して、アプリ開発の流れを俯瞰します。なお可能であれば以下のionicチームによるAngular2の解説を読んでおくと、よりスムーズに理解できると思います。が、たぶん読まなくても何とかなります。Learn Angular 2 · Learn Angular 2

プロジェクトフォルダの作成

まずプロジェクトのフォルダを作成します。前回、紛らわしいのは避けるようにと書いたくせに、project2と付けてしまいました。tutorialとなっている引数は、プロジェクトのテンプレートを指定する部分です。tutorialは公式が提供しているionic2のチュートリアルのためのテンプレートです。何も指定しない場合には、tabs starterテンプレートが使用されます。

$ ionic start project2 tutorial --v2

このとき–tsオプションを付けるとTypeScript用の構成となります。typingsフォルダがあったり、tsconfig.jsonの中身が違ったりと、若干構成が変わるようです。プロジェクトフォルダに移動してionic serveするとブラウザでテンプレートの動作を確認できます。

$ cd project2$ ionic serve

ちなみにですが、ionicには公式IDEは無いようですが、オススメ環境はあるようです。Ionic 2 Resources | Editors and IDEs – Ionic 2 Developer Preview – Ionic Framework私はもともとatomを使っていたのですが、さらにオススメとあれば使わない手はありません。atomで環境を構築する事にします。コードハイライタや補完機能はもともと備わっているので、とりあえずbrowser-plusを入れて、全画面表示でコードとブラウザの両方を同時に見られるようにしてみました。Terminal-Plusも入れているので、ターミナルも同一画面内で操作できます。これでmonacaのcloudIDEっぽくなりました。

フォルダ・ファイル構成

ionic startを実行してできあがるフォルダツリーはCordovaの標準的な構成らしいです。そのためCordvaプラグインをインストールすることができますし、プラットフォーム特有のファイルを置くこともできます。www/index.htmlがアプリの一応のエントリポイントです。

アプリに必要となるスクリプトをこのHTMLから読み込みます。ですが、このファイルはcssを読み込んだり、bootstrapを読み込んだりするためだけのものに過ぎません。ionicの開発でこのファイルをいじることは少ないようで、実際にはapp/app.jsをエントリポイントとして扱います。ionic開発ではこのappフォルダにコンパイル前のコードが収蔵されていて、作業の中心的な場所になります。このフォルダ内のコードはionic serveの実行時にトランスパイルされるので、appフォルダではES6やTypescriptが使用できます。app.jsのMyAppクラスには以下のデコレーターが付いています。すべてのionicアプリケーションはルートになるコンポーネントを持ちますが、Appデコレーターを付けるとルートと扱われます。指定されているtemplateUrlがbuildフォルダになっていますが、このファイルはapp/app.htmlがビルド時にコンパイルされたものなので、編集する際にはapp/app.htmlを編集します。

@App({  templateUrl: 'build/app.html',  config: {} // http://ionicframework.com/docs/v2/api/config/Config/})

app.htmlテンプレートの構成

このファイルには、ion-menuタグとion-navがあります。コード量ではion-menuの占める割合が大きいですが、これはハンバーガーアイコンをクリックして引き出されるメニューを記述しています。そのためion-menuの記述内容は最初は一切画面に表示されていません。

      Pages              

id属性で指定されている名前は、後でこのコンポーネント(ion-menuとかion-navのひとまとまり)をgetComponent関数で指定するために使用します。

Menus

起動直後の画面では、Menusを使っています。Menus : ionic 2 Components – Ionic 2 Developer Preview – Ionic FrameworkMenusでメニューを記述するためにはion-menuを、メニューからナビゲートされるページにはion-navを指定します。ion-menuにはcontent属性があります。これはどのコンテンツで画面がドラッグされたときに、メニューを開閉させるかを指定するところです(メニューにとってのメインコンテンツはどれか)。両方contentなのでややこしいですが、左側のオレンジのcontentがion-menuの属性です。[]で囲むと、Angular2の機能によってバインディングされ、代入された内容に追随するようになります。代入されているcontentはローカル変数です。ion-navの方に#contentと指定されているのが分かると思いますが、これはAngular2におけるローカル変数の指定で、ローカル変数であるcontentにion-navが代入されたことになります。結果、ion-menuのcontentにはこのコードの下部のion-navが代入された事になります。*ng-forはAngular2のディレクティブで配列をイテレートします。ここではpages配列を順番にpに代入しながら配列の最初から最後まで繰り返しを行います。(click)もAngular2のディレクティブで、要素がクリックされたときに指定された関数を実行します。app.js内にopenPage関数が定義されていて、開いているメニューを閉じてからsetRootでnavのページを変更しています。{{p.title}}はDIによって変数がレンダリングされる部分です。これは後で解説します。

ion-nav

ページ本文がion-navの方です。中身が無いのは、root属性で指定されたページがロードされるからです。Navigation : Ionic 2 Components – Ionic 2 Developer Preview – Ionic Framework[root]もバインディングでrootPageが指定されています。これはapp.jsのthis.rootPage変数です。この変数にはHelloIonicPageが代入されています。

import {HelloIonicPage} from './pages/hello-ionic/hello-ionic';

HelloIonicPageには冒頭部で./pages/hello-ionic/hello-ionicがインポートされています。インポートしているのはhello-ionic.jsです。

@Page({  templateUrl: 'build/pages/hello-ionic/hello-ionic.html'})export class HelloIonicPage {  constructor() {  }}

すべてのページはこのようにクラスとコンパイル後のテンプレートで構成されます。build/pages/hello-ionic/hello-ionic.htmlの実体はapp/pages/hello-ionic/hello-ionic.htmlなのでここにページの内容が記述されています。tutorialのapp以下のフォルダ・ファイル構成は、フォルダ名と同名のhtml/js/cssとなっています。これはionicにとって必須のものでは無いものの、ファイルをきちんと整理する観点から推奨されるとのことです。

Page

Pageデコレーターはインポート元であるnode_modules/ionic-framework/decorators/page.jsに実装されています。ここはフレームワーク部分ですからユーザーが触ることはありません。Page – Function in module – Ionic FrameworkPageデコレーターが付けられると、Angularのビューとして構成されるので、セレクタを使わなくても動的に内容が変更できるページになります。PageはNavControllerによりナビゲーションをさせることができます。

    Hello I test

Welcome to your first Ionic app!

This starter project is our way of helping you get a functional app running in record time.

Follow along on the tutorial section of the Ionic docs!

一見して、ブラウザに最初表示された内容であることがわかると思います。上部の表示が変なのは私がコードを適当にいじったからです。ただ適当にいじったとおりに表示が変わっているのが分かると思います。Pageのテンプレートはデコレータのところで直接記述することもできます。が、ビューの分離や可読性の向上の観点からすると分離をすべきでしょう。

Live reload

ここでコードを書き換えてみます。この変更をして保存をした後、5秒ほどすると、ブラウザが自動的にリロードされ、ブラウザに表示されている内容が書き換わっています。ターミナルのionic serveが作動していることが条件ですので、上手く変更されない場合には、ターミナルの動作状況を確認してください。変更時にはionic serveが変更を捕捉したことがターミナルに出力されています。

ionic $ ∆ Copying HTML√ Matching patterns: app/**/*.html√ HTML copied to www/buildHTML changed: www/build/pages/hello-ionic/hello-ionic.html

ion-navbar

hello-ionic.htmlの下記の部分(ion-navbar)は、画面上部に表示されているハンバーガーアイコンとタイトルを記述しています。この中にion-nav-itemsやion-titleを記述して、その時々に応じたバーを表示させます。

    Hello ionic

この中の「*navbar」は現状効能が不明です。削除してもサンプルはそのまま動作しました。buttonにmenuToggleというキーワードが入っています。これはionicが備えているディレクティブで、ボタンにメニューをトグルする機能を持たせることができます。MenuToggle – Class in module – Ionic Frameworkion-contentが本文部分ですが、この中のbuttonもmenuToggleが記述されているのでメニューをトグルします。

NavController

サイドメニューでMy First Listをタップするとpagesのcomponentで指定されているListPageに遷移します。ListPageは./pages/list/listからインポートされていますので./pages/list/list.jsのクラスです。

import {Page, NavController, NavParams} from 'ionic/ionic';import {ItemDetailsPage} from '../item-details/item-details';@Page({  templateUrl: 'build/pages/list/list.html'})export class ListPage {  constructor(nav: NavController, navParams: NavParams) {    this.nav = nav;    // If we navigated to this page, we will have an item available as a nav param    this.selectedItem = navParams.get('item');    this.icons = ['flask', 'wifi', 'beer', 'football', 'basketball', 'paper-plane',    'american-football', 'boat', 'bluetooth', 'build'];    this.items = [];    for(let i = 1; i < 11; i++) {      this.items.push({        title: 'Item ' + i,        note: 'This is item #' + i,        icon: this.icons[Math.floor(Math.random() * this.icons.length)]      });    }  }  itemTapped(event, item ,index) {     this.nav.push(ItemDetailsPage, {       item: item   });  }}

ionicのNavigationはページ間に親子関係があるページナビゲーションを実現するためのコンポーネントです。NavControllerをコンストラクタで変数にバインドすれば、コード内でNavControllerを使用できるようになります。Navigation : Ionic 2 Components – Ionic 2 Developer Preview – Ionic Frameworkページ同士の関係はスタックになっているので、NavControllerでpushすればページを追加して遷移、popをすれば今のページを取り除いて下のページに戻ります。list.htmlのbuttonのclickにitemTapped関数が指定されています。クリックするとItemDetailsPageにpushされて遷移します。コンストラクタの中はhtmlで使用するitem配列を作成しています。乱数で生成されているので、このコンストラクタが呼ばれる度(ページに来る度)にアイコンが変わります。なおこのコードには下記の下線部のコードがありますが、使用していません。次のコードの関係でゴミが残ってしまったのでしょう。

DIを体験してみる

せっかくなのでここでDIの実験をしてみたいと思います。list.htmlの10行目の以下の様に書き換えます。ngforの実行時に変数iにインデックス番号を代入し、クリック時に実行される関数にインデックス番号を引数として渡します。

    

list.jsの28行目以降を以下の様に書き換えます。もともとのpushをコメントアウトして、items配列の要素のtitleを書き換えます。

  itemTapped(event, item ,index) {      this.items[index].title = 'pushed';    /*      this.nav.push(ItemDetailsPage, {          item: item      });*/  }

これによりタップしたリストアイテムのtitle部分がpushedに書き換わりました。ポイントはjsのロジック上は、ビューの要素を変更する処理を行っていないということです。ただitemsの各要素はリストの要素にバインドされているので、itemsの個別の変数を変更すれば、それによって作られたリストの中身が自動的に変更されます。

NavParams

ItemDetailsPageは../item-details/item-detailsからインポートされていますので、中身はitem-details.jsです。

import {Page, NavController, NavParams} from 'ionic/ionic';@Page({  templateUrl: 'build/pages/item-details/item-details.html'})export class ItemDetailsPage {  constructor(nav: NavController, navParams: NavParams) {    this.nav = nav;    // If we navigated to this page, we will have an item available as a nav param    this.selectedItem = navParams.get('item');  }}

ここでのポイントはNavParamsです。NavParamsはデータを保持できるオブジェクトです。NavParams – Class in module – Ionic Framework一つ前のlist.jsのitemTapped関数内のpushでitemという引数を渡しています。pushはページを移動するだけで無く移動先のページに対して、パラメーターを渡すことができます。NavController – Class in module – Ionic Frameworkこの場合でいくとlist.js内のitemをitemというラベルを付けて、次のページに渡すということです。そして次のページではNavParamsを使って、navParams.get(‘item’)と指定することで渡されたデータを取得できます。this.nav = nav;は無意味な記載でコメントアウトしてもちゃんと動作します。

    Item Details
{{selectedItem.title}}

You navigated here from {{selectedItem.title}}

取得されたデータはselectedItemに代入されており、まず*ngIfでの表示のコントロールに使用されています。当然selectedItemは中身があるのでdivが表示され、タイトルがレンダリングされます。

チュートリアル完了

チュートリアルはここで完了です。今後は以下のコンテンツを参照して欲しいとのこと。Platform sectionとDeveloper resources section へのリンクもありましたが、リンク切れでした。Ionic 2 Components – Ionic 2 Developer Preview – Ionic FrameworkIonic Forum #ionic2 #初心者 #入門 #チュートリアル #解説 #TypeScript #Angular2″””

Ionic 2でハイブリッドなアプリ開発:デバッグのサクサク感・monacaとの比較

ハイブリッドアプリでシステム開発:JSでボタンへのイベント登録はloadの後じゃ無いとだめ | 法務ネット:弁護士 川内康雄先日Monacaも軽く触っていたのですが、感想はデバッガが良くできているなというところでした。そこでIonicとMonacaの開発の私的なサクサク感を比較してみたいと思います。ちなみに比較対象のMonacaはフリー版です。CLIが使えるGold以上だとまた印象が変わってくるのかも知れません。ionicもMonacaも、「HTML5+JavaScriptハイブリッドアプリ」という点では同じですので、ブラウザで開発中のアプリの実行結果を確認できます。Monacaの場合はクラウドIDEですのでクラウド環境での実行、ionicはionic serveコマンドでサーバーを作ってローカルで実行という違いはあります。が、レスポンスに特段の差は無く、デバッグのサクサク感はそれほど変わらないと思いました。ChromeのJavaScriptコンソールによるデバッグ情報の表示も、どちらの環境も同じように行えます。強いて言うとバグやconsole.logの実行行の特定が、ionicの方が若干楽という程度でしょうか。app.bundle.jsがエディタ上で簡単に見えるので、対象行の発見が楽です。が、Monacaにしてもchromeからソースを追えば発見可能です。一方、実機上でデバッグを行う場合には、両者の使用感には差があります。 Monacaの場合は、クラウドIDEでの開発内容をMonacaアプリにダウンロードして実行します。もともとIDEがクラウド上にありますから、ビルドする度にアップロードをするという手間がかかりません。またビルドも自動的に実行されるので、コードを保存したらすぐにMonacaアプリで結果を確認できます。そしてconsole.logの内容は、アプリのフローティングメニューからたどれる表示画面で内容を確認できます。更にネットワーク経由で送信されているようで、少し遅れますがクラウドIDEに情報が表示されます。ionic viewはmonnacaデバッガーにぱっと見は似ていますが、・コードを変える都度ビルドしてアップロードするという手間をかけないと変更が反映されない・これ自体にデバッグ出力を持っていないのでconsole.logを確認できないという制限があります。そのためがんがんコードを書き換えながら実機で確認するという用途には余り向いていません。How to debug on Ionic View [not the question, here’s the answer!]この方法でconsole.logを確認することもできそうですが、出自の分からないサービスだと継続性やセキュリティの問題がありますので、簡単に頼ることもできないと思います。ただしionicにはライブプレビューという機能があります。これは、母艦にAndroidを有線で接続している場合には、ionic runを-lオプション付きで起動すると、ソースを変更する度に自動的にAndroid実機に反映されるという仕組みです。-cオプションを付けている場合には、ionic runを起動したコンソールにログが出力されます。そんなわけでデバッグ環境の充実度、使いやすさはionicよりもMonacaが一歩リードしていると感じました。次は実際にコードを書いてみて、開発しやすさを比較してみたいと思います。”””

損害賠償無しのシステム開発な日常:システム開発での瑕疵担保・契約解除・損害賠償

(20160222版)システム開発における瑕疵担保・契約解除・損害賠償 私の日常業務の中では、IT・情報システム・インターネットに関連する法律問題の比率が非常に多いです。そのためシステム開発での瑕疵担保・契約解除・損害賠償に関する御相談をよくお受けします。 ユーザー側からの御相談も、ベンダー側からの御相談も多いのですが、色々な御相談をお受けしていると、法律家(弁護士・裁判官)の考え方と、開発の現場の方の感覚がかなり違っているなと思われる部分が多いです。そこで、・瑕疵担保の請求をしたい/瑕疵担保の請求をされた・契約解除をしたい/契約解除をされた・損害賠償を請求したい/損害賠償を請求されたという時に、まず調査・検討してもらいたいことをメモしておきます。私に限らず、トラブルが発生して弁護士に相談に行く前には、あらかじめこれらの事項を検討しておくと、相談がスムーズに進み、より有意義なアドバイスを受けやすくなると思います。

仕様

瑕疵担保や損害賠償が問題になるときには、仕様の中身が問題になることが多いです。というのも、ユーザーサイドとしては、自分の要望通りにシステムが動作しないことをシステムの欠陥として扱うことが多く、そうすると仕様にその要望が含まれている事が、瑕疵かどうか、損害賠償の原因となるかどうかが決まるからです。ここでの仕様とは、ユーザーとベンダーがどのようなシステムを作るかを合意した内容です。ただ多くのシステム開発では、仕様が抽象的なことが多く、ユーザー側の要望が、仕様内なのか、仕様外なのかがすぐには判断できないことがあります。ここでベンダー側の論理としては、「仕様に明示的に書かれていないものは無い」ということでユーザーを納得させていることが多いのではないでしょうか。法的に見ても、「ある要望に応じた機能を作ってくれ」というのはユーザーの権利の問題で、権利が存在することの立証は権利を主張する側が行わないといけません。つまりユーザーが仕様の範囲内にあると立証できない限りは、ベンダー側の論理が通ることになります。ただここで気をつけて欲しいのは、紙である仕様書にかかれていない要件でも、要件になり得ることがあり得るということです。たとえば同種のシステムであれば通常持っている機能、例えば住所録システムであいうえお順に並べ替えるといった機能は、仕様に明示されていなくても、要件に含まれているという「解釈」がされる可能性があります。 いわゆる性能的要件についても、明示が無ければパフォーマンスが低くてもよいということではなく、そのシステムを利用するにあたって支障が無い程度の性能が出ている必要があります。もちろんパフォーマンスが低いことを仕様に明示していた場合は別ですが。そして仕様がはっきりしない場合には、仕様書以外の、メール、企画書、見積書、議事録等のすべての資料が、その要望が契約に含まれるかどうかの判断資料となります。そのため関係する可能性があるすべての資料は保管し、弁護士に見せないといけません。 つまりユーザー側からすれば、仕様に無いからといって泣き寝入りをする必要があるわけでは無いけれども、仕様に無い部分の対応責任を求めようとすると、・業界における標準水準を立証しなればいけない・やりとりのすべてを立証しなければいけないという負担を負わないといけないことにあります。 同じ事はベンダー側からすれば、仕様に明記されていなくても、ユーザー側が上記の立証に成功するのであれば、責任を負う可能性があるということです。

検収

ユーザー・ベンダーのよくある誤解として、「検収は終わっているから瑕疵担保の請求はできない」があります。そもそも瑕疵担保という制度は納品が終わってからの仕事の成果に対する責任の問題ですから、検収をしているかどうかと、瑕疵担保責任が無くなるかどうかは関係がありません。法的には商事の売買であれば検収によって責任の程度は大きく変わりますが、瑕疵担保はそうでは無いということです。ただ検収を経た場合、仕様の不確定さの問題については、ベンダー側に有利に働きます。というのも成果としてのシステムの状態を認めたということですので、その内容に納得したという形を残すことになるからです。ユーザーとしてシステムの内容に文句がある状態の場合で、それでも諸般の事情により検収をしないといけない場合には、留保付きの研修であることの明示をしないといけません。そして紛争になった際には、その留保がなされていることの記録が重要になってきます。

解除

契約を遡ってなしにするということを言いたい場合、日本の場合は、「キャンセル」という言葉をつかうことが多いと思います。このキャンセルのことを法的には解除と呼びます。システム開発でも、契約をキャンセルしたいという話しはよく聞きます。ユーザー側からすると、システムの納品が遅いだとか、品質が低いといった理由が多いでしょう。システムの納品が遅い場合は、十分な催告期間(いついつまでに完成させないと解除するとという通知における「いついつ」までの期間)をおいて通知をすれば、解除できるケースが多いでしょう。一方、品質が低いという理由では、解除が認められるとは限りません。というのも法律上、瑕疵を原因とする解除は、「契約の目的を達することができない」という条件があるからです。システムの本来的な動作に関係の無い小さいバグがいくつかあったとしても、それのみを原因として解除する事はできないということです。その上、裁判例上システム開発の解除は要件が加算されています。「バグが発生してもそれがすぐに修補されたのであればそのバグを原因としての解除はできない」という考え方です。情報システムの性質上、どれだけ注意を払っても、一定数のバグは避けられないという現状があります。バグを一切許さないということになると、最初からシステム開発を行ってはいけないことと同じになってしまいます。そこで裁判所はこの現実を見て、ちゃんと修補される場合には、それを原因に契約を解除するまではできないとしました。そうするとユーザー側としてシステム開発契約を解除できるのは、・システムの利用目的が達成できなくなるバグが発生し・ベンダーがそれを修補できない状況が続いている場合となります。ベンダー側からは、ユーザーの要望が余りにもきついので、お金を返すからこの契約から離れたいという相談を受けることがあります。しかしこれは法的には困難で、契約上ユーザーの要望が義務の範囲外である場合には、それをきちんと伝えて要望を断るしかありません。

アジャイル開発

日本の場合、発注側の体質から、本来のアジャイル開発を実施する事は難しいことが多いです。というのも一般企業でも国・地方公共団体でも、システムに対して「いくらで完成するのか」という予算枠を予め設定して、その予算内で開発することが至上命題となっています。そうすると必要な部分から順に完成させる、いつの時点を完成とするかはその時の判断で決めるというアジャイル的なシステム開発とは前提が異なることになってしまいます。しかしシステム開発業界で「アジャイル開発」がバズワードのように扱われ、ユーザー側も、「古い体質が払拭された新しい開発手法」というイメージが先行し、「なんとなくアジャイル」でプロジェクトに着手してしまっているケースが多いように思います。仕様の確定が苦手な日本のユーザー・ベンダーの逃げ・問題先送りの正当化文句として「アジャイル開発」が使われているだけという状態です。こういった「なんちゃってアジャイル」は、ベンダーとユーザーとの関係が良好である限りはよいのですが、ひとたび関係が悪化すると、先の「仕様は何か」問題が発生することになります。この場合は結局、ベンダー、ユーザー両方が仕様の確定のための立証の負担をしなければいけません。そしてその準備にはかなりの時間がかかります。

賠償金額

裁判で損害賠償というと、莫大な賠償金を取れる、取られると誤解されることが多いです。しかし日本の損害賠償制度は、実損を回復させるためだけにしか機能しません。たとえばアメリカであれば懲罰的な賠償として、悪質性の高い加害者に最高で300%の賠償を命じることがあります。しかし日本の損害賠償制度では、実際に発生した損害分だけです。そしてその実損分を「金銭として評価した場合にいくらか」という考え方をしますから、金銭に評価できないような損害、たとえば信用毀損とかは、法的には損害として評価されず、実際には賠償されないことが多いです。ユーザーサイドとしては「もしこのシステムがちゃんと完成していたならこれだけの利益が発生していたはずだ」という、いわゆる逸失利益を請求したいことがあります。

弁護士を活用するために

最近はシステム開発の現場に詳しい弁護士が増えてきていますので、紛争の実体を捉えた紛争処理が行える事が多くなってきていると思います。ただ弁護士は、依頼者から情報に基づいて最大限を尽くして戦うことはできるのですが、依頼者から必要な情報が出てこない限りは、実際の所ほとんど何もできません。どんな情報が必要なのかは遠慮せず弁護士に尋ねればいいと思います。システム開発に詳しい弁護士なら、ポイントを押させて示唆をくれるはずです。あとはそのヒントを元に、勝つための情報を社内で徹底的に探索することです。無いものは無いことは仕方ありませんが、担当者の気合いが満ちていれば、いろいろな情報が出てくることが多いと感じます。

ionic2でハイブリッドなアプリ開発:ionic2でCORS対策のためにプロキシを使うときはionic.projectではなくてionic.config.jsに記述する

ionicのローカルテスト環境はブラウザ上で動いているので、ブラウザのCORS制限に引っかかります。別にプロキシをインストールする方法もあるようですが、ionic CLI自体にプロキシ機能が備わっているようなので、これを使うことに。How to fix CORS issues, revisitedHandling CORS issues in Ionicが、ここらへんに書かれている設定をいじってもウンともスンとも反応しません。404になるだけです。 というか、ionic.projectを消してしまってもブラウザ環境でプログラムが走ります。この設定ファイルってそもそも関係無いのではと悩んでいて、フォーラムに質問を投げたら回答をしてくれる人がいました。Proxy Problems with Ionic 2設定を記述する場所がionic2で変わったようで、ionic.projectではなくてionic.config.jsに記述するとのこと。 早速実行してみると、ブラウザからローカルのプロキシのポートにアクセスしても、ちゃんと目標の所に転送(というか代わって取得)してくれました。スクリプトからもOKです。こういう人柱的なところがあるのはベータ版を使う際の悩みですね。”””

Raspberry PiでIoTなシステム開発:nodeのインストールが楽になった

Raspberry PiでIoTなシステム開発: Raspberry Pi にバイナリでNode.jsをインストールしばらく前に公式サイトからnodeのARM用バイナリが提供されなくなり、ネットでバイナリを探してインスト−ルをしていました。が、遂に公式でのARM用バイナリの配布が再開されたようです。それもv6/v7/v8も、4系も5系もとう大盤振る舞い。Download | Node.jsせっかくなのでこれを使ってインストールできるか試してみることにします。公式でのディレクションはcurlで直接nodeをインストールしていますが、まだ4系、5系のどちらを使うか決めていないので、nvmを使ってインストールして、後からバージョンを切り替えられるようにします。Jessieだとcurlはあえてインストールしなくても最初から使えました。

pi@raspberrypi:~ $ curlcurl: try 'curl --help' or 'curl --manual' for more informationpi@raspberrypi:~ $ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.0/install.sh | bash  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                 Dload  Upload   Total   Spent    Left  Speed100  7766  100  7766    0     0   3738      0  0:00:02  0:00:02 --:--:--  3740=> Downloading nvm from git to '/home/pi/.nvm'=> Cloning into '/home/pi/.nvm'...remote: Counting objects: 4402, done.remote: Compressing objects: 100% (3/3), done.remote: Total 4402 (delta 0), reused 0 (delta 0), pack-reused 4399Receiving objects: 100% (4402/4402), 1.10 MiB | 562.00 KiB/s, done.Resolving deltas: 100% (2582/2582), done.Checking connectivity... done.* (detached from v0.31.0)  master=> Appending source string to /home/pi/.bashrc=> Close and reopen your terminal to start using nvmpi@raspberrypi:~ $ nvm-bash: nvm: command not found

パスが反映されていないようで、そのままだと実行できません。sourceすればいいと思いますが、ここはログインしなおしました。

pi@raspberrypi:~ $ nvmNode Version ManagerNote:  refers to any version-like string nvm understands. This includes:  - full or partial version numbers, starting with an optional ""v"" (0.10, v0.1.2, v1)  - default (built-in) aliases: node, stable, unstable, iojs, system  - custom aliases you define with `nvm alias foo`Usage:  nvm help                                  Show this message  nvm --version                             Print out the latest released version of nvm  nvm install [-s]                 Download and install a , [-s] from source. Uses .nvmrc if available    --reinstall-packages-from=     When installing, reinstall packages installed in <node|iojs|node version="" number="">  nvm uninstall                    Uninstall a version  nvm use [--silent]               Modify PATH to use . Uses .nvmrc if available  nvm exec [--silent]  [] Run  on . Uses .nvmrc if available  nvm run [--silent]  []     Run `node` on  with  as arguments. Uses .nvmrc if available  nvm current                               Display currently activated version  nvm ls                                    List installed versions  nvm ls                           List versions matching a given description  nvm ls-remote                             List remote versions available for install  nvm version                      Resolve the given description to a single local version  nvm version-remote               Resolve the given description to a single remote version  nvm deactivate                            Undo effects of `nvm` on current shell  nvm alias []                     Show all aliases beginning with   nvm alias                  Set an alias named  pointing to   nvm unalias                         Deletes the alias named   nvm reinstall-packages           Reinstall global `npm` packages contained in  to current version  nvm unload                                Unload `nvm` from shell  nvm which []                     Display path to installed node version. Uses .nvmrc if availableExample:  nvm install v0.10.32                  Install a specific version number  nvm use 0.10                          Use the latest available 0.10.x release  nvm run 0.10.32 app.js                Run app.js using node v0.10.32  nvm exec 0.10.32 node app.js          Run `node app.js` with the PATH pointing to node v0.10.32  nvm alias default 0.10.32             Set default node version on a shellNote:  to remove, delete, or uninstall nvm - just remove the `$NVM_DIR` folder (usually `~/.nvm`)pi@raspberrypi:~ $ nvm --version0.31.0</node|iojs|node>

バージョンもヘルプも表示されます。さっそくnvmを使ってnodeをインストールします。「5系の最新」という指定の方法が分かりませんでしたのでバージョン番号を指定しました。ヘルプからするとv5と指定するだけでよかったんでしょうか。

pi@raspberrypi:~ $ nvm install v5.7.1Downloading https://nodejs.org/dist/v5.7.1/node-v5.7.1-linux-armv7l.tar.xz...######################################################################## 100.0%Now using node v5.7.1 (npm v3.6.0)Creating default alias: default -> v5.7.1pi@raspberrypi:~ $ node> (To exit, press ^C again or type .exit)> pi@raspberrypi:~ $ node -vv5.7.1

コンソールから実行してみます。

pi@raspberrypi:~ $ node > console.log(""hello world"");hello worldundefined> (To exit, press ^C again or type .exit)>

ちゃんとJavascriptを解釈してくれたようです。インストールパスを知りたかったのですが、nvmのコマンドでは分からないようでした。findして実体を探してみると、piでインストールしているのでpiのホームに入るのですね。当たり前か。

pi@raspberrypi:~ $ nvm ls->       v5.7.1default -> v5.7.1node -> stable (-> v5.7.1) (default)stable -> 5.7 (-> v5.7.1) (default)iojs -> N/A (default)pi@raspberrypi:~ $ find ~/ -name ""node"" -ls125874    4 drwxr-xr-x   2 pi       pi           4096 Mar  4 09:40 /home/pi/.nvm/test/installation/node129143    4 drwxr-xr-x   3 pi       pi           4096 Mar  4 09:43 /home/pi/.nvm/versions/node128984    4 drwxr-xr-x   2 pi       pi           4096 Mar  3 07:16 /home/pi/.nvm/versions/node/v5.7.1/share/doc/node128988 22080 -rwxr-xr-x   1 pi       pi       22608862 Mar  3 07:16 /home/pi/.nvm/versions/node/v5.7.1/bin/node128992    4 drwxr-xr-x   4 pi       pi           4096 Mar  3 07:17 /home/pi/.nvm/versions/node/v5.7.1/include/nodepi@raspberrypi:~ $ find ~/ -name ""nvm.sh"" -ls124544   72 -rwxr-xr-x   1 pi       pi          72916 Mar  4 09:40 /home/pi/.nvm/nvm.sh

よし、次はnpmのインストールだ!と意気込んだのですが、既にインストール済みでした。nodeと一緒に入るのですね。osxでインストーラーを実行した時みたい。

pi@raspberrypi:~ $ npmUsage: npm where  is one of:    access, add-user, adduser, apihelp, author, bin, bugs, c,    cache, completion, config, ddp, dedupe, deprecate, dist-tag,    dist-tags, docs, edit, explore, faq, find, find-dupes, get,    help, help-search, home, i, info, init, install,    install-test, issues, it, la, link, list, ll, ln, login,    logout, ls, outdated, owner, pack, ping, prefix, prune,    publish, r, rb, rebuild, remove, repo, restart, rm, root,    run-script, s, se, search, set, show, shrinkwrap, star,    stars, start, stop, t, tag, team, test, tst, un, uninstall,    unlink, unpublish, unstar, up, update, upgrade, v, verison,    version, view, whoaminpm  -h     quick help on npm -l           display full usage infonpm faq          commonly asked questionsnpm help   search for help on npm help npm     involved overviewSpecify configs in the ini-formatted file:    /home/pi/.npmrcor on the command line via: npm  --key valueConfig info can be viewed via: npm help confignpm@3.6.0 /home/pi/.nvm/versions/node/v5.7.1/lib/node_modules/npmpi@raspberrypi:~ $ npm --version3.6.0

あまりにもすんなり行きすぎて何か寂しい感じがします。もっと苦戦しないと記事にする意味がないなー。(2016/03/05追記)早速ですが困ったことが発生してくれました(??)ので、追記です。上記の方法でインストールすると、nvmが/home/piにインストールされて、nodeはその配下にインストールされます。が、これだとsudoで使用する事ができません。これができないとハードウェアアクセスが必要なモジュールを使ったり、ウェルノウンポートをリスンさせられなくなります。

pi@raspberrypi:~ $ sudo nvmsudo: nvm: command not found

スーパーユーザーの環境変数にpiへのパスを追加してもいいのだと思いますが、非特権ユーザーへのパスを通すのもなんだかおかしな感じです。そこでグローバルにnvmをインストールしてみることにしました。同じ事を考える人はいるもので、パッケージ化してくれています。GitHub – xtuple/nvm: Easily setup NVM globally for rooted, multi-user, or CI environments

pi@raspberrypi:~ $ wget -qO- https://raw.githubusercontent.com/xtuple/nvm/master/install.sh | sudo bashCloning into '/usr/local/nvm'...remote: Counting objects: 826, done.remote: Total 826 (delta 0), reused 0 (delta 0), pack-reused 826Receiving objects: 100% (826/826), 141.80 KiB | 26.00 KiB/s, done.Resolving deltas: 100% (387/387), done.Checking connectivity... done.NVM installedpi@raspberrypi:~ $ sudo nvmNode Version ManagerUsage:    nvm help                    Show this message    nvm install [-s]   Download and install a     nvm uninstall      Uninstall a version    nvm use            Modify PATH to use     nvm run  []  Run  with  as arguments    nvm ls                      List installed versions    nvm ls             List versions matching a given description    nvm ls-remote               List remote versions available for install    nvm deactivate              Undo effects of NVM on current shell    nvm alias []       Show all aliases beginning with     nvm alias    Set an alias named  pointing to     nvm unalias           Deletes the alias named     nvm copy-packages  Install global NPM packages contained in  to current versionExample:    nvm install v0.4.12         Install a specific version number    nvm use 0.2                 Use the latest available 0.2.x release    nvm run 0.4.12 myApp.js     Run myApp.js using node v0.4.12    nvm alias default 0.4       Auto use the latest installed v0.4.x version

早速これを使ってインストール。sudoでnode呼べました。

pi@raspberrypi:~ $ sudo nvm install v5######################################################################## 100.0%Checksums emptyNow using node v5.7.1pi@raspberrypi:~ $ lsinit-functions  kt  node_modules  ts  wiringPipi@raspberrypi:~ $ ls -laFtotal 100drwxr-xr-x   8 pi   pi    4096 Mar  5 09:10 ./drwxr-xr-x   3 root root  4096 Feb  2 20:52 ../-rw-------   1 pi   pi   20462 Mar  5 09:05 .bash_history-rw-r--r--   1 pi   pi     220 Mar  4 17:42 .bash_logout-rw-r--r--   1 pi   pi    3610 Mar  4 17:42 .bashrcdrwx------   3 pi   pi    4096 Mar  5 08:43 .config/-rw-r--r--   1 pi   pi    6148 Mar  5 07:19 .DS_Store-rw-r--r--   1 pi   pi     362 Mar  4 17:42 .ftpconfig-rwxr-xr-x   1 pi   pi   11506 Mar  4 17:44 init-functions*drwxr-xr-x   3 pi   pi    4096 Feb 11 22:54 kt/drwxr-xr-x   2 pi   pi    4096 Mar  5 08:38 node_modules/-rw-r--r--   1 pi   pi      27 Mar  4 17:42 .node_repl_historydrwxr-xr-x 253 pi   pi   12288 Mar  5 08:42 .npm/-rw-r--r--   1 pi   pi     675 Mar  4 17:44 .profiledrwxr-xr-x   4 pi   pi    4096 Mar  5 08:46 ts/drwxr-xr-x  10 pi   pi    4096 Feb 11 11:43 wiringPi/pi@raspberrypi:~ $ node -vv5.7.1pi@raspberrypi:~ $ sudo node -vv5.7.1

(2016/03/05 更に問題発生で更に追記)npmでインストールしたコマンド(ここではtypings)を実行しようとしたら、not foundになりました。ユーザー領域にインストールした場合には最初からパスが通っていたのですが、グローバルインストールだと自分で設定しないといけないようです。piのために設定する場合はこのとおり。

pi@raspberrypi:~ $ export PATH=$PATH:`npm bin -g`(not in PATH env variable)pi@raspberrypi:~ $ echo $PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/usr/local/nvm/v5.7.1/binpi@raspberrypi:~ $ typingsUsage: typings Commands:    bundle, i, in, init, install, la, list, ll, ls, r, remove, rm, search,    uninstalltypings  -h            Get help for typings  --no-insight  Disable insights for typings --version               Print the CLI versiontypings --cache                 Print the path to the cache directorytypings@0.6.9 /usr/local/nvm/v5.7.1/lib/node_modules/typings

ただこれだとログアウトする度に消えてしまうので、/etc/profileに追記します。

pi@raspberrypi:~ $ sudo nano /etc/profile

途中の所のパスの設定部分でもいいと思いますが、追記したことがわかりやすいように末尾にしました。

PATH=$PATH:/usr/local/nvm/v5.7.1/binexport PATH

root用はこちら。exportで追加する方法が分かりませんでした。visudoでnanoが起動するので追記します。

pi@raspberrypi:~ $ sudo visudopi@raspberrypi:~ $ sudo sh -c 'echo $PATH'/usr/local/nvm/v5.7.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binpi@raspberrypi:~ $ sudo typingsUsage: typings Commands:    bundle, i, in, init, install, la, list, ll, ls, r, remove, rm, search,    uninstalltypings  -h            Get help for typings  --no-insight  Disable insights for typings --version               Print the CLI versiontypings --cache                 Print the path to the cache directorytypings@0.6.9 /usr/local/nvm/v5.7.1/lib/node_modules/typings

visudoではsecure_pathのところにパスを追記しています。

## This file MUST be edited with the 'visudo' command as root.## Please consider adding local content in /etc/sudoers.d/ instead of# directly modifying this file.## See the man page for details on how to write a sudoers file.#Defaults        env_resetDefaults        mail_badpassDefaults        secure_path=""/usr/local/nvm/v5.7.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin""

“””

TypeScriptのコンパイル(トランスパイル)が爆裂に遅いことの対策を考える

Raspberry Pi上でTypescriptのコンパイルをやってみようと思い、tscを実行してみたところ、コマンドラインにもどって来ません。あれ、コンパイラが壊れているのかなと思っていたら、その後で戻ってきます。単に時間がかかっていただけのようです。tscには計測機能がついているのでコンパイル時間を計ってみるとこの通り。

pi@raspberrypi:~/ts $ tsc --diagnostics st.tsFiles:               2Lines:           17319Nodes:           77389Identifiers:     29814Symbols:         44284Types:            4340Memory used:    32591KI/O read:        0.02sI/O write:       0.00sParse time:      2.20sBind time:       1.37sCheck time:      6.05sEmit time:       0.23sTotal time:      9.86s

なにか凄いコードをコンパイルしたとか言うわけでは無く、公式のこの5行のコードを食わせただけです。

function greeter(person: string) {    return ""Hello, "" + person;}var user = ""Jane User"";document.body.innerHTML = greeter(user);

どうもlib.d.tsというTypeScriptのライブラリのパースとチェックに時間がかかっている模様。tsc is slow to process lib.d.ts · Issue #3298 · Microsoft/TypeScript · GitHubたしかに先の結果でも対象行が凄い量になっています。ライブラリをくっつけずにコンパイルするとこの通り大分と早くなります。

pi@raspberrypi:~/ts $ tsc --nolib --diagnostics st.tserror TS2318: Cannot find global type 'Array'.error TS2318: Cannot find global type 'Boolean'.error TS2318: Cannot find global type 'Function'.error TS2318: Cannot find global type 'IArguments'.error TS2318: Cannot find global type 'Number'.error TS2318: Cannot find global type 'Object'.error TS2318: Cannot find global type 'RegExp'.error TS2318: Cannot find global type 'String'.Files:               1Lines:              10Nodes:              32Identifiers:         9Symbols:             7Types:              15Memory used:     9694KI/O read:        0.00sI/O write:       0.00sParse time:      0.12sBind time:       0.04sCheck time:      0.14sEmit time:       0.23sTotal time:      0.53s

ただライブラリを付けないと意味が無いので、ライブラリ部分のチェックだけ外してみると最初よりは大分と早くなっています。ただ開発していてストレスがかかるレベルですね。rpi2でこれなのでrpi1とかだとどうなるんだろう。

pi@raspberrypi:~/ts $ tsc --skipDefaultLibCheck --diagnostics st.tsFiles:               2Lines:           17319Nodes:           77389Identifiers:     29814Symbols:         44111Types:              36Memory used:    21564KI/O read:        0.02sI/O write:       0.00sParse time:      2.19sBind time:       1.34sCheck time:      0.17sEmit time:       0.23sTotal time:      3.94s

で、これではお話にならないので対策を考えることにします。rpi2に入れたnodeで動かしたいので最初からちゃんとリモートで動く環境を作りたいんです。そもそもライブラリをチェックしたりコンパイルする必要も無いのだから、プリコンパイルしてリンクの時だけくっつけたらいいのでは無いかと思い検索したら同じ事を考えている人がいました。How to use compiler API to hold lib.d.ts in precompiled form · Issue #2030 · Microsoft/TypeScript · GitHubが、この方法だとソースの中身をいじる必要がありそうなのでパス。自分はそもそも今からTypeScriptを覚えようとしている段階なので、覚える前にソースをいじらないといけないというのでは順序が逆なので。次に考えたのが、atom-typescriptにはtsの保存と同時にjsを生成する機能があるので、それを使えばいいというソリューション。自分はRemote-FTPパッケージを使っているので、もともとリモートファイルをローカルファイルの様に編集できているので、リモートのtsを編集して保存すると同時にjsができれば簡単です。が、Remote-FTPがリモートのファイルを更新してくれるのは、エディタ画面上で保存ボタンを押したときのみで、atom-typescriptが自動生成するファイルをリモートに保存してくれる訳ではありませんでした。この延長線上で考えたのがRemote-FTPにはローカルとリモートを同期させる機能があるので、これを使うという手。しかしファイルを更新する都度syncを実行するのは面倒です。それをやっている間に3.94秒経ちそう。でもって次に考えたのがローカルのファイル変更を検出して自動的にリモートにアップロードするという方法。調べてみるとOSXならOS標準の機能だけで実行できそうです。OSXのLaunchAgentでホストOSのファイル監視してリモートサーバーにrsyncして同期する方法 – Qiitaが、設定ファイルを見て気が重くなったのと、ファイル変更を検知するプロセスが常駐するというのはマシンの負荷が増えそうなのが気になります。この設定をした直後はいいんですが、開発が終わったらこの設定をしたことを忘れてしまって、OSを再インストールするまで常駐しそう。で、結局採用したのが、リモートのフォルダをそのままマウントする方法。一番ありきたりな手段に落ち着きました。SSHFS (SSH Filesystem) – Raspberry Pi Documentation使い方はなんてことはなくてこの通り実行するだけ。最初リモートでsshfsというサーバーが稼働するのかと思い、piの方でapt-getを実行してしまいました。これはクライアントサイドでsshをラップしてリモートをマウントしているように見せるためのものですね。マウントするとローカルのマウントポイントの名前とアイコンが変わりました。マウントしてローカルのatomでtsファイルを更新したら(5行目のgreeterを康雄にしました)、リモートのjsが更新されています。マルチバイト文字でも問題なし。とりあえずこれでTypeScriptの学習を進めます。”””

if (divider !== 0 && (divider & (divider – 1)) !== 0)

nodeはnpmで提供されているパッケージが豊富なのが魅力ですが、メンテされていなくて現状では使えないものも多いです。GPIO割り込みとハードウェアPWMも対応を謳っているパッケージがそれぞれいくつかあります。が、いろいろ試して見ていずれも事実上一択状態でした。GPIO割り込みが使えそうなのは、pidriver、onoff、rpi-gpioです。試して見たところ、pidriverはコンパイル失敗、rpi-gpioは動くには動くけれどもドキュメントが意味不明でした。onoffはちゃんと動作するし、ドキュメントもわかりやすいです。APIも使いやすそうなのでこれで行こうと思います。onoffハードウェアPWMが使えそうなパッケージは沢山ありましたが、インストールできた、サンプルコードで動いたのがrpioのみでした。WiringPiの設定を踏襲しているので、CでWiringPiを使った経験があるのであれば、移行もスムーズだと思います。rpioちなみにClockDividerの設定で2の累乗以外を設定すると怒られるのですが、WiringPiで使用していた時に2の累乗以外でもちゃんと動いていて、正確な周波数になっていました。圧電ブザーの発振に使いたいので、正確な音程を出すためには中途半端な数を設定したいです。そこでrpioのコードを修正して、引数のチェックを外しました。node_modules/rpio/lib/rpio.jsの516行目あたりです。

rpio.prototype.pwmSetClockDivider = function (divider){/*"