まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2016/02

JavaScript の似て非なる2つの関数: setTimeout と setInterval。この2つの違いは分かりますか?

まず、どちらの関数も第一引数が実行する関数、第二引数が実行までの時間(ミリ秒)、という同じようなパラメータで使います:
<!-- setTimeout の場合 -->
<html>
<head>
<title>setTimeout</title>
<script>
var cnt = 0;
function func(){
  cnt ++;
  console.log( "cnt = " + cnt );
  setTimeout( "func()", 1000 );
}
</script>
</head>
<body load="func()">
</body>
</html>
<!-- setInterval の場合 -->
<html>
<head>
<title>setInterval</title>
<script>
var cnt = 0;
function func(){
  cnt ++;
  console.log( "cnt = " + cnt );
  setInterval( "func()", 1000 );
}
</script>
</head>
<body load="func()">
</body>
</html>

上記2つのページの違いは事実上一箇所です。上は <body> のロード時に setTimeout を、下は <body> のロード時に setInterval を実行しています(そして繰り返し呼ばれます)。この2つがどのような挙動の違いになるか、わかりますか?

説明しやすいのは上の setTimeout を使った場合です。こちらは最初のロード時にまず func() 関数が呼ばれ、 その中で setTimeout を使って1秒にもう一度 func() 関数が呼ばれ、・・・ という具合に、1秒おきに func() 関数が呼ばれるような処理になります:
2016202901


一方、ちょっとわかりにくいのは下の setInterval を使った場合です。こちらは最初のロード時にまず func() 関数が呼ばれ(ここまでは同じ)、その中で setInterval を使って1秒に func() 関数が呼ばれるよう指定されています。そして1秒後に func() 関数が呼ばれると、再度1秒毎に func() 関数を呼ぶよう指定されます。そのため更に1秒経過すると、最初に指定された1秒おきの func() と、2回目に指定された1秒おきの func() と、都合2回 func() 関数が(ほぼ同時に)呼び出されることになります。そして2つそれぞれの func() の中で更に1秒毎に func() 関数を呼ぶよう指定されます。ということは更に1秒経過すると、最初に指定された1秒おきの func() と、2回目に指定された1秒おきの func() と、3回目に指定された1秒おきの func() が2回、都合4回 func() 関数がほぼ同時に呼び出されることになります:
2016202902


この違い分かりますか?つまり setTimeout は次の1回の実行タイミングを指定しているのに対して、setInterval は何秒おきに実行するのかを指定している、ということになります。既に何秒おきに実行するのか設定されている状態で上書きしても、その前の指定がキャンセルされるわけではなく上書き(マルチスレッドのスレッドが1つ増える感じ)で実行タイミングがセットされるので、上記コードのようにループの中で何度も setInterval を実行すると、どんどん実行回数が増えていくことになる、という点に注意してください。

なお、setInterval を停止するには clearInterval 関数を実行します。


※(注)最初にお断りしておきます。マジメぶって書いてますが馬鹿エントリです。


全てのきっかけは最近たまにみかけるこういった記事でした:

人工知能やコグニティブエンジンと呼ばれる技術の発達により、これまで人間の脳でないと判断できなかったようなことをコンピュータができるようになり、人間の仕事がより低コストな人工知能やそれらを搭載したロボットによって奪われてしまう時代がくる、という啓発記事です。

個人的にはそこまでそんな時代が身近に迫ってきているとは思っていません。ただし、その一方で企業間の競争が働いたこともあり、ここ数年における人工知能分野の発展はすさまじいものがあります。静止画像や個人の機械認識率はぐんと上がり、各社が API を公開している背景も手伝って、人工知能に触れる機会がより身近な世界になりつつあるのも事実だと思っています。以下は個人的見解ですが、クリエイティブな仕事(例えば小説を書く、など)を学習させるのはまだ難しいにせよ、脳を使わない単純作業や、ルーチン化された業務などは意外と早い段階で人間の効率を追い抜く日がやってくるかもしれない(そうなると作業コストで勝てるわけがないので、本当に仕事を失う日がやってくるかもしれない)、と思っています。

例えばお客様とお話ししていて、ただ頷いて聞いているだけ。お客様が話し終わったらすかさず相槌を打つ、そんなフローチャートのような業務では近い将来に職を奪われてしまうかもしれないのです!
(注 実在する誰かのことではありません)
2015022305


さて話は変わって、先日秋葉原でこのような部品を買ってしまいました:

2015022300



この SEN02281P はいわゆる「音センサー」です。画像左上にある大きな丸い部分がマイクになっていて、ここで音を拾って、その情報を電気回路を通じて外部に知らせることができる、というものです。買った後で知ったのですが、Arduino に接続したり、Raspberry PiGrovePi という拡張モジュールを取り付けて簡単に使う方法がネットなどで紹介されていました。

・・・ん、もしかすると、この SEN02281P と(例えばラズベリーパイとかの)演算機能を使えば、上記のような簡単なデータフローが実現できてしまうんじゃないだろうか? つまり「誰かが喋っている時は頷き、喋り終わったら相槌を入れる、という仕組みは、このセンサーとアルゴリズムを実装するプログラムだけで実現できてしまうんじゃないだろうか?」ということに気付いてしまったのです! というわけで、よく調べずにとりあえず買ってしまいました。


自分は「ラズベリーパイならメジャーだからまあ繋がるだろう、その方法もネットで見つかるだろう」とタカを括っていたのですが、これが意外と苦戦しました。結論からいうと GrovePi を使わない方法(ラズベリーパイの GPIO に直接繋げる方法)を見つけることができませんでした。えーマジで!?自分で調べるしかないの??電子回路は苦手なんだよなあ。。まあ挑戦してみました。以下、やってみたことのおさらいの意味で書いてます。当方こっち方面はド素人なので、間違いを見つけたり、こうするともっといいよ、という方法があればウェルカム、というか教えてください。

・・・改めてパーツを眺めてみました。接続端子はこの↓画面上部の白い四角の中に生えた4つの突起部分です:
Loudness_101020063_01

これを裏返すとこんな感じ(上図とは左右が逆になった状態):
2015022301


拡大するとこんな感じ。ちょっと見難いのですが、この画面の左から順に(反対から見た場合は右から順に) SIG / NC / VCC / GND と書かれています:
2015022302


GND はアース(Ground)、VCC は電圧、これは(他の部品とほぼ共通なので)分かる。上記の商品ページを見ると、このパーツの動作電圧は 5V(3.5~10V) と書かれているので、とりあえず 5V の電圧ピンにジャンパケーブルを繋いであればいいかな。そして SIG はシグナル、つまりここを GPIO27 とかに繋げて音の信号を受け取るんだろうな・・・ で、NC ?なんだこれ、見たことないぞ・・・

で、ここだけ調べて分かったのは NC = Not Connected 、つまり「どことも繋がない」という端子らしい。そうなんだ。。じゃ、なんで存在してるんだろ?? うーん・・・まあ、いいやw

というわけで、ジャンパケーブルを使ってこんな感じで自分のラズベリーパイの GPIO に接続しました:
2015022303

これで 5V の電源を供給し、アースも備え、SEN02281P が感知した音を取り込む仕組みが動くはずです。実際の写真はこんな感じです(メス-メスのジャンパーケーブルがあればもっと綺麗に接続できたのに・・・):
2016022400


そして、ラズベリーパイ側にはこのような Python プログラムを導入しました:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# SEN02281P ----- RaspberryPi GPIO
# =SIG ---------- 13
# =NC
# =VCC ---------- 2
# =GND ---------- 20

import paho.mqtt.client as mqtt
import time
import RPi.GPIO as GPIO

def on_connect(client,userdata,flags,rc):
	print( "Connection with result code " + str(rc) )
	client.subscribe( "sen02281p" )

def on_message(client,userdata,msg):
	print( msg.topic + " " + str(msg.payload) )

def reading(sensor):
	sum = -1 
	if sensor == 0:
		sum = 0
		for i in range(0,20):
			time.sleep(0.1)
			a = GPIO.input(SIG)
			sum += a
	else:
		print "Incorrect function."

	return sum

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
SIG = 13
GPIO.setup(SIG,GPIO.IN)

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.connect( "iot.eclipse.org", 1883 )
while client.loop() == 0:
	msg = reading(0);
	client.publish( "sen02281p", msg, 0, True )
	pass

GPIO.cleanup()
※事前に pip install paho-mqtt をして、Paho の Python ライブラリを導入済みです。

ちなみに上記ソースファイル(sen02281p.py)はこちらからダウンロードできます:
https://raw.githubusercontent.com/dotnsf/sen02281p/master/sen02281p.py


GPIO の(SEN02281P の SIG 端子とつながっている)13番ピンからのインプット情報を 0.1 秒ごとに20回(つまり2秒間)取得し、その20回中音が確認できた回数を MQTT ブローカー(iot.eclipse.org)に投げる、というものです。つまり MQTT ブローカーに対しては2秒おきにどれくらい音が識別できたかを 0 から 20 の整数値でパブリッシュする、というものです。トピックは上記例では "sen02281p" と指定していますが、皆さんがもしこのソースを使う場合は少し変えていただけると嬉しいです。

次に Bluemix 上の NodeRED 環境を使って、このパブリッシュされたメッセージを取り出す仕組みを用意します。MQTT インプットノードを用意し、ホスト名に上記の MQTT ブローカーホスト(iot.eclipse.org:1883)、トピックに "sen02281p" を指定しています。このノードからは2秒に1回、ラズベリーパイの接続された SEN02281P のマイクから拾った音の頻度が渡されてくる、という仕組みとなります。また、その取り出した結果を /ws/unzk_sensor というパスの WebSocket に出力しています:
2015022304


後はこの /ws/unzk_sensor からリアルタイムにデータを取り出して動く WebSocket アプリケーションを用意してあげればマイクで拾った音の頻度をリアルタイムに可視化するようなアプリケーションを作ることができる、ということになります。そのサンプルアプリ(やその中で使う画像)も合わせてこちらで公開しておきます:
https://github.com/dotnsf/sen02281p


このアプリを上記の NodeRED 環境にデプロイしてアプリケーション(hoho.html)を開くと、このような画面になります:
2016022401


ひたすら「頷いている」画面になっています。何もデータが送られていないとただ頷いているだけですが、一応この画面が出ればデプロイには成功していることになります。

ではラズベリーパイ側のアプリも起動します。ネットに接続されたラズベリーパイ上で先程の MQTT パブリッシャーアプリを実行します:
# python sen02281p.py

そして先程の頷き画面をリロードすると・・・ ラズベリーパイに接続されたマイクが音を拾っている間は頷き、音が途切れたと判断した時に「ほほー」と相槌を売ってくれるようになります!
2016022402


この「音を拾っているか」「音が途切れたか」の判断がまだ少し甘いところがあるかもしれませんが、一応それっぽく動いていることが確認できました。これで忙しい営業さんに変わってお客様のお話しを上手に引き出してくれるロボットができました(笑)。


実際に動いている動画を Ustream に上げておきます:

Live streaming video by Ustream




IBM Bluemix から提供されているウェブの統合開発環境である IBM DevOps サービス。ウェブ上に用意されたソースコードエディタを使ってソースコードを編集したり、バージョン管理を行うことができるので、手元のクライアント環境に依存せずにアジャイルなソースコード管理を行うことができます。

ソースコードエディタ単体として見ると、専用のクライアントアプリケーションと比較しての使い勝手ではやはりネイティブアプリケーションの方が使いやすいと感じることもあります。とはいえ、ちょっとしたソースコードの変更を行う必要が生じた際に、わざわざ cf ツールを用意することなくデプロイまで行うことができる環境、というメリットもあります。ケース・バイ・ケースで使い分けることになると思っています。

そんな DevOps サービスを使って Liberty for Java ランタイムとして Bluemix 上に作成したプロジェクトのソースコードを編集しようとすると、その初期ディレクトリ構成が少し特殊で、戸惑うことがあります。例えば Bluemix 環境から Liberty for Java のランタイムを作成し、「Git の追加」をすると DevOps サービスが起動してソースコードのローカルリポジトリがウェブ上に作成されます:
2016022301


作成されたリポジトリにアクセスするには「コードの編集」をクリックします:
2016022302


以下は初期状態のまま何も変更を加えていない状態でのソースコードのディレクトリ構成です:
2016022303


ここに外部ファイル(例えば MySQL コネクターの JAR ファイル)を追加しようとした時にどこに追加すればいいか、すぐに分かりますか?

正解と、そのための手順は以下の通りです。まず src/main/webapp フォルダを右クリックし、ポップアップメニューから「新規」-「フォルダー」を選択します:
2016022309


新規にフォルダが作成されます。フォルダ名の入力が求められたら "WEB-INF" と(半角大文字で)入力します:
2016022301


更に、今作成した WEB-INF フォルダを右クリックして、同様に新規フォルダ "lib" をこの下に作成します。:
2016022303


これで src/main/webapp/WEB-INF/lib フォルダが作成されました。このフォルダの中に JAR ファイルを入れておけば自動的にロードしてくれるようになります:
2016022304


実際に JAR ファイルをアップロードしてみましょう。lib フォルダを右クリックし、ポップアップメニューで今度は「インポート」-「ファイルまたはアーカイブ」を選択します:
2016022305


ファイルのアップロードダイアログが表示されるので、ローカルファイルシステムからアップロードしたい JAR ファイルを選択します(この例では MySQL JDBC Connector の JAR ファイルを選択しています):
2016022306


選択するとアップロードが開始されます。アップロード状況がプログレスバーで確認できます:
2016022307


アップロードが完了すると、プロジェクト内のファイルとして参照できるようになります。これでこのプロジェクト内で MySQL JDBC Connector を使うことができるようになりました:
2016022308


試しに JSP を追加して動作確認してみます。src/main/webapp フォルダを右クリックして「新規作成」-「ファイル」を選んで、MySQL.jsp という名前のファイルを新規に作成します:
2016022311


ファイルはこの画面から中身を編集できるので、以下の様な内容にしました:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ page import="java.sql.*" %>
<html>
<body>
<%
  Connection conn = null;


  //. DB Access information
  String dbclass = "com.mysql.jdbc.Driver";
  String dbhost = "(MySQLサーバー名)";
  String dbname = "(データベース名)", dbusername = "(ユーザー名)", dbpassword = "(パスワード)";
  int dbport = 3306;
  String dburi = "mysql://" + dbhost + "/" + dbname;

  try{
    Class.forName( dbclass );
    conn = DriverManager.getConnection( "jdbc:" + dburi, dbusername, dbpassword );
  }catch( Exception e ){
    e.printStackTrace();
  }
%>
<h2>conn = <%= conn %></h2>
</body>
</html>


MySQL サーバー名、データベース名、ユーザー名、パスワードを指定してコネクションを貼り、その貼ったコネクション変数を無理やり(文字列化して)表示する、というものです。

実際に動かそうとすると MySQL サーバーが必要です。もし自由に使える MySQL サーバーが手元にない場合はこちらのデモ用サーバーをお使いいただく方法もあります:
StrongLoop のデモ用 MySQL サーバー

このソースを追加して(サーバー名、データベース名、ユーザー名、パスワードを変更して)コミット&プッシュ&ビルド&デプロイ後にアクセスすると、このような画面になるはずです。わかりにくいかもしれませんが、コネクション変数(conn)を無理やり文字列化した結果が表示されています。少なくとも MySQL の JDBC Connector は正しく動いている(つまり追加した JAR ファイルが読み込まれている)、ということがわかりますね:
2016022312




 

先週、IBM BluemixObject Storage サービスがベータを卒業して正式サービスになりました:
2015022101


SoftLayer 上に用意された Swift と呼ばれる標準的なオブジェクトストレージ機能を Bluemix を通じて提供するものです。5GB であれば無料サービスとして利用できます:
2015022102


では、この Bluemix 上の Object Storage サービスをクライアントから使う方法を紹介します。


1. Swift ツールの導入

このサービスを Linux(CentOS) から実際に利用するまでの手順を紹介します。このサービスを使うには swift と呼ばれるツール(swiftclient)が必要です。まずはこのツールを導入しましょう。

swift の導入は pip を使って行います。最初にこの pip を導入する必要がありますが、pip の導入に必要なライブラリをあらかじめまとめて導入しておきます:
# yum install fuse fuse-libs fuse-devel libattr-devel gcc gcc-c++ kernel-devel libxslt-devel

ここで導入した fuse ライブラリを読み込んでおきます:
# modprobe fuse

次に pip の導入に必要な Python 3 を導入します。Python 3 は yum ではインストールできないため、PUIAS から導入します。まずはそのための GPG Key をインストールします:
# cd /etc/pki/rpm-gpg/
# wget -q http://springdale.math.ias.edu/data/puias/6/x86_64/os/RPM-GPG-KEY-puias
# rpm --import RPM-GPG-KEY-puias

次に /etc/yum.repos.d/puias-computational.repo ファイルを以下の内容で作成します:
# vi /etc/yum.repos.d/puias-computational.repo

(以下を作成して保存)
[PUIAS_6_computational] name=PUIAS Computational Base mirrorlist=http://puias.math.ias.edu/data/puias/computational/$releasever/$basearch/mirrorlist gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puias

作成したリポジトリファイルを使って yum で Python 3 一式をインストールします:
# yum install python3 python3-devel python3-libs python3-setuptools

Python 3 がインストールできていれば pip がインストールできます:
# wget -O - https://bootstrap.pypa.io/get-pip.py | python3

これでやっと pip の導入ができました。ではこの pip を使って keystoneclient と swiftclient をインストールします:
# pip install python-swiftclient
# pip install python-keystoneclient

ここまでの手順で swift コマンドが使えるようになっているはずです。


2. Object Storage サービスの追加と、環境変数の設定

Bluemix 上で Object Storage サービスを追加し、その資格情報を確認します:
2015022103


環境変数 VCAP_SERVICES の内容は以下の様な JSON 形式のテキストになっているはずです。これらのうち、赤字部分をメモしておきます(後で使います):
{
  "Object-Storage": [
    {
      "name": "Object Storage-7d",
      "label": "Object-Storage",
      "plan": "Free",
      "credentials": {
        "auth_url": "https://identity.open.softlayer.com",
        "project": "object_storage_(project)",
        "projectId": "(projectId)",
        "region": "dallas",
        "userId": "(userId)",
        "username": "Admin_(username)",
        "password": "(password)",
        "domainId": "(domainId)",
        "domainName": "(domainName)"
      }
    }
  ]
}

ここで取得した接続情報を Swift クライアント(Linux)の環境変数に(例えば /etc/bashrc などに)設定します:
export OS_USER_ID=(userId)
export OS_PASSWORD=(password)
export OS_PROJECT_ID=(projectId)
export OS_AUTH_URL=https://identity.open.softlayer.com/v3
export OS_REGION_NAME=dallas
export OS_IDENTITY_API_VERSION=3
export OS_AUTH_VERSION=3

↑上の赤字部分は接続情報のものを使い、青字部分は接続情報には含まれていないのですが、上記のように書き足してください。/etc/bashrc に書いた場合は再ログインするなどして、この環境変数が有効になった状態にしてください。これで swift を使う準備が整いました。


3. swift コマンドを実際に使ってみる

Object Storage はコンテナと呼ばれるフォルダ単位で利用します。現在のコンテナ一覧を確認してみましょう。以下のコマンドを実行します:
# swift list

初めて実行した時には(コンテナが存在していないので)何も表示されないはずです。コンテナを作成するにはコンテナ名を指定して post コマンドを実行します。以下の例では dotnsf-container というコンテナを作成しています:
# swift post dotnsf-container

このコマンド実行後に再度コンテナ一覧を確認すると、作成した dotnsf-container が表示されるはずです(緑字が出力結果):
# swift list
dotnsf-container

次にコンテナの中身を確認します:
# swift list dotnsf-container

これもコンテナ作成直後に実行した段階では(中身がないので)何も表示されないはずです。 ではこのコンテナにローカルファイル(以下の例ではカレントディレクトリの abc.txt を指定してアップロードしてみます:
# swift upload dotnsf-container abc.txt

この後に再度コンテナの中身を確認すると、アップロードしたファイルが追加されていることが確認できます:
# swift list dotnsf-container
abc.txt

コンテナ内のファイルは以下のコマンドでカレントディレクトリにダウンロードできます:
# swift download dotnsf-container abc.txt

コンテナ内のファイルが不要になった場合、以下のコマンドでコンテナから削除できます:
# swift delete dotnsf-container abc.txt
abc.txt

一通りのコンテナ/ファイル操作コマンドが利用できそうです。



(参考)
https://www.ng.bluemix.net/docs/services/ObjectStorage/index.html





自分は学生時代に初めてパソコンを購入しました。NEC PC-9801 DA です。Intel の CPU が 32bit に対応した直後のモデルでした。

当時からプログラミングはしていました。が、どちらかというとまだ「授業で使うため」「単位を取るため」という理由でした。でもそれが20数年後の今の自分の礎になっているのかと思うと感慨深いです。

さて、その当時に流行っていたテキストエディタの1つが MIFES (マイフェス)でした。1985年にメガソフト株式会社から PC-9801 の MS-DOS 環境向けに発売されたこのテキストエディタは強力な検索機能と、マクロ言語によるカスタマイズ性の高さが特徴でした。

と、偉そうなことを言ってますが、実は自分自身は友人の環境を触らせて使わせてもらっていたのでした。本音としては「当時は値段が高くて学生身分の自分には手が出せなかった」のでした。当時のテキストエディタの2大勢力の、もう1方であった Vz (こっちも1万円近くした記憶が・・・)を愛用しており、実は今でも PC-DOS の仮想環境では使っていたりします。

さて、Vz は Windows 環境では Wz エディタとなって進化を続けていますが、MIFES もずっと進化を続けてきました。MIFES の現在の最新バージョンは10で、先日30周年を迎えたようです。おめでとうございます。

そして、なんと MIFES の体験版がダウンロードして使えること、しかも Linux 版が存在していたことを、恥ずかしながらつい先日知りました。この Linux 環境で使えるテキストエディタという意味では Vz/Wz にはなかった環境です。さっそく試してみました。

まずはここから MIFES for Linux をダウンロードします。自分が試した時は milinux-103.tar.gz というアーカイブファイルがダウンロードできました:
http://www.megasoft.co.jp/cgi-bin/try/milinux/cgi/form.pl


なお、動作環境ページに制約事項が書かれています。自分が以下で試した環境は 64bit の CentOS 6.6 で、「64 bit OS の動作保証はしていない」と書かれていますが、一応以下の手順で動いていました、ということを記載しておきます。

この MIFES for Linux を 64bit 環境下で動かすには ld-linux.so2 ライブラリが必要でした。なので、こいつをあらかじめインストールしておきます:
# yum install ld-linux.so.2

で、その後にダウンロードしたファイルを展開すると mifes というフォルダが作られ、その中に一式のファイルが含まれています。これでインストール完了です:
# cp milinux-103.tar.gz /opt
# cd /opt
# tar xzvf milinux-103.tar.gz
# mifes

ここで1点注意が必要です。MIFES for Linux がサポートする日本語エンコードは EUC のみ、ということです。なのでログインに利用している端末(例えば PuTTY や TeraTerm)の日本語設定を EUC に変更する必要があります。以下は TeraTerm の場合の変更内容です(メニューから「設定」-「端末」で、この画面で文字コードを EUC にしています):
2016022001


ここまでの設定をした上で MIFES for Linux を起動します。コマンドは mi で、ファイル名を引数に指定してもいいのですが、とりあえずそのまま起動してみます:
# ./mi

すると DOS 時代の懐かしいテキストエディタインターフェースが Linux の端末上で再現されます。まずはファイル選択画面が開きます:
2016022002


ここで矢印キーを使ってディレクトリを変更しながらファイルを選択します。例えば mi と同じディレクトリにある license.txt を選びました。このファイルを開くには選んだ後に Enter を押します:
2016022003


MIFES 独特の、青い背景に灰色文字で選択したファイルを開くことができました。当時のユーザーには死ぬほど懐かしい「ダイヤモンドカーソルキー(Ctrl+E,S,D,X がそれぞれ矢印キーの上、左、右、下に対応して、ホームポジションに指を置いたままカーソル移動ができるショートカット)」も再現されています。使っていると指が思い出してくれます:
2016022000


メインメニューは F1 キーで、そこから別のファイルを開いたり、終了したり・・・といったオペレーションが可能でした。


唯一気になった点を上げるとすると、やはり UTF-8 エンコードに対応していない、という所でしょうか。今自分の手元にあるソースコードファイルはほぼ UTF-8 で作られており、それらが読み込めないというのはやはり痛いです。とはいえ、今後 MIFES for Linux の進化が期待できるかというと・・・ まあ難しいということを理解しないといけないのだと思っています。

しかし学生時代を含めても、自分の環境下に MIFES をインストールしたのは数えるくらいしかなかったし、それを Linux で行える日がやってくるとは思っていませんでした。

このページのトップヘ