2024年2月10日土曜日

講演タイトルと絵文字

「半角カナ」と呼ばれる文字セットがある.JIS X 0201として制定されているカタカナの文字コード集合である.文字コードを8ビットないしは7ビットで表現していた時代,コンピュータの黎明期において日本語をなんとかしてコンピュータで表現しようとした結果の,ひとつの産業遺産である.

翻って現代,日本語はほぼ不自由なくコンピュータで表現できるようになった.文字コードも,JIS,Shift JIS,EUCといった複数のコードが使われることによりときとして文字化けが起こるといった混乱の時代を経て,いまではUnicodeによってほぼそのようなトラブルは回避されている.

いわゆる半角カナは一時期,トラブルの元になるので使わないほうがよいとされていたが,今ではUnicodeに組み込まれているので問題なく利用できる.ただし,コード云々よりも,デザイン上の問題というか,同じ文字なのに全角と半角という2種類の文字が存在すること自体が,根本的な課題であろう.同じことはA-Z(a-z)とA-Z(a-z)にも当てはまる(前者は半角,後者は全角).システムを頑健にするためには入力されたテキストに対し,同一化の処理を施さねばならず,面倒くさいことこのうえない.

この問題はもう,強制的にどちらかを使わないようにするというコンセンサスを共有するしか解決方法がないが,それはなかなか難しいだろう.

ところで,Unicodeで問題が全て解決したかというと,残念ながら,そうでもない.なぜならば,古いシステムを延々と使い続けている人や組織が絶えないからである.ありがちなのが,丸数字と(月)(火)(水)……の文字化け問題である.WindowsのShift JISで①②③という文字を使うと,Mac側では(月)(火)(水)になってしまう,というアレ.令和の世の中でも,ときどき遭遇する.

最近,私が遭遇した出来事は,講演タイトルの変更を余儀なくされたことである.正確には,データベースに登録できないから,登録するタイトルを修正せよ,というもの.当該講演は,こちらである.

飯尾淳, "にこP(大学版)中大 iTL🇯🇵 x KMITL🇹🇭 実施報告," インターネットを用いた海外の高校との協同授業:実践報告シンポジウム 第2回, 東京 市ヶ谷 & オンライン (2022.2.26).

「講演タイトルに絵文字なんて使うなよ!」っていうマジメなご指摘は承るが,遊び心はあってもいいじゃんねーとも思う.まあ,そんな開き直りはともかくとして,この講演の情報を researchmap の講演実績に入れていたら,そこからデータをフィードするようにした研究者DBの管理者から「うちのシステムは絵文字使えないから当該絵文字を削除してください」という連絡が来た.残念な話である.

そもそも講演や論文のタイトルって,もっと自由に付けていいんじゃないかと,常々,悩ましく思っている.同じく2022年の2月には,ヒューマンインタフェース学会の学会誌に,次のような記事を寄稿した.

飯尾淳, "ポストコロナ時代の〇〇コミュニケーション," ヒューマンインタフェース学会学会誌, Vol. 24, No. 1, pp. 4-7, (2022.2).

この記事の校正中に,事務局から「そろそろタイトルきちんと決めてください」と連絡が来た.「〇〇コミュニケーション」の「〇〇」の部分が,仮置きだと思われたらしい.これは,正規表現でいうところのワイルドカード,すなわち,よくある(〇〇には好きな言葉を入れてください)という意味でそのように表記したものだったが,その意図が伝わっていなかった.

このときは丁寧に説明し,当初の意図通り,記事はこのままのタイトルで掲載された.

なお,論文のタイトルは,「システム名: その説明」というようなタイトルを付けることが多い.Proposal of … とか,Research on … ,Development of … みたいな紋切り型のタイトルは面白くないし,タイトルの頭文字が偏ってしまう.AからZまで頭文字が散らばったほうが,多様性の時代に合っている.「システム名: その説明」であれば,その説明部分は好きに書けるという理屈である.

ところで,ここまで書いてふと疑問に思ったのだが,絵文字で始めたら,インデックス作るときにどういう扱いにされるんだろう?こんどやってみようかな(また怒られるかも……)

講演タイトルといえば,心に残っているのは,2004年のWISSにおける大和田さんの発表である.

大和田茂,”切る," WISS第12回インタラクティブシステムとソフトウェアに関するワークショップ, (2004).

3Dモデルのボクセル表現で,どこで切っても断面が表示できる,みたいな発表だったと記憶しているが,なんといってもタイトルが衝撃的である.わずか2文字.これ以上,短い論文タイトルを,私は寡聞にして知らない.



2024年1月23日火曜日

漫才師・山中村「田中角栄」

山中・中村:(上下からそれぞれ登場)どーもー

山中:山中と

中村:中村で,山中村です.よろしくお願いしますー

山中:山中村てね,どこぞの田舎の山んなかにありそうな地名ですけれども.実際,昔は新潟県,石川県,岐阜県,愛知県,広島県,高知県にあったらしいですよ.どの村も合併とか改名とかで今ではぜんぶ消えてなくなってしまいました.

中村:ほんならオレらも消えてなくなるんかいな!不吉な名前だなー.

山中:ま,消えてなくならんように元気出していきましょう.今日はせめて名前だけでも覚えて帰ってください.

中村:ところでね?昔,田中角栄っちゅーオッサンおったでしょ?

山中:あー,ロッキード事件で逮捕されたひとね.

中村:逮捕て,いきなりネガティブな話題から攻めんなよ.いうていまの若い子そんなんよう知らないでしょ.

山中:君もオッサンとか言ってたでしょうが.仮にも一国の総理大臣を務められた方でしょ?娘さんの田中真紀子っていうオバハンも政治家でしたな.

中村:オバハンいうな.あの人も大臣やられた偉い人だよ?ま,それはそれとして,こないだお屋敷が火事になったらしくて.

山中:へー,そうなん?…… 記念マキコ

中村:は?

山中:記念パピコ

中村:記念カキコかよ.ここは2ちゃんねるじゃありませーん.オレらの漫才,2ちゃんねるの便所の落書きと一緒にしちゃダメ!ぜったい.

山中:そういえば田中真紀子さん,久しぶりに表舞台に現れたかと思ったら記者会見でおもくそ政権批判してました.

中村:そうそう.ネットもそれでちょっと炎上してた.

山中:ネットが炎上してお屋敷に延焼……

中村:なわけねーだろ!まあ,政権批判した直後に火事って,ちょっと疑っちゃうよね.怖い世界だ.

山中:で,その田中角栄がどうしたの?

中村:まー,このぅ(田中角栄のモノマネをする)

山中:なんですか,なんですか?まーごめ?

中村:まーごめは大鶴肥満だろうがよぅ.いいんだよそんな小ボケ挟まなくても.

山中:ボケたのお前じゃんかよ.続けろよ.

中村:ボケたわけじゃねーよ!ま,それはそれとして,こないだこんな話を聞いたんだよ.田中角栄ってパーティとかで相手の名前がわからないとき,「ところであなた,お名前なんでしたっけ?」ってズバリ聞いちゃうんだって.

山中:そりゃ失礼だな.

中村:いやそれがね,「え?中村ですけど」って答えたとするじゃん?そうしたら「いやそうじゃないよ,下の名前は何だったっけ?」って重ねるのよ.それで下の名前を聞いたふりをして,「中村さんね……」って話を続けるんだって.

山中:へー,うまいこと考えたな.そりゃ賢いやり方だ.じゃあ中村さん,あなたお名前なんだっけ?

中村:その聞き方じゃダメだろっ!もう中村ってわかってるじゃんよぅ.俺がやってみせるから……(間)…… あなたお名前なんでしたっけ?

山中:田中です.

中村:嘘ついちゃダメでしょ.田中角栄の話してるからって.あなた山中さんでしょうが …… もっかいね.やりなおし.あなたお名前なんでしたっけ?

山中:アツシです.

中村:いやそうじゃなくて……,下の名前は……,アツシさんね.下の名前はアツシさん.たしかに,あんた山中アツシだけど.ダメだよ.下の名前を答えちゃったら続かないじゃん.もういちど.苗字だけで答えてよね.あなたお名前なんでした?

山中:山中です.

中村:いや,下のお名前は?

山中:(もじもじして)えー……,下ですか……,ヨコじゃダメ?

中村:なに照れてるんだよ!変なこと考えてんじゃねーよ.ほんで横の名前ってなんだよ.あなたのお名前な・ん・で・す・か!

山中:My name is Yamanaka.

中村:なんで英語なんだよ!お前いつから外国人になっちゃった?

山中:まだやるの?

中村:こんなグダグダな漫才,SNSで叩かれるよ?炎上しちゃうよ.

山中:えー,うち燃やされちゃうの.

中村:燃やされねーよ!やめさせてもらうわ.

山中・中村:ありがとうございました(ハケる)

2024年1月3日水曜日

岐阜のポーズとiPAQ

2023年末,暮れも押しせまっていた時期に「岐阜のポーズ」が流行っていたのを皆さんご存知だろうか?

岐阜のポーズって何だ?

そもそも岐阜のポーズとは何か.漫画「クレヨンしんちゃん」のひとコマで,しんちゃんが「ぎふのポーズ」としてとっていたポーズが元ネタらしい.後ろを向き,両手を真横に拡げ,四股を踏むような感じで大股を広げたうえで膝を直角まで曲げて踏ん張るというポーズである.

国道417号藤橋根尾交差点岐阜方面ライブカメラの前でこのポーズをとってライブカメラ画像におさまるという悪戯が2023年末にちょっとしたブームになり,また,アクセスが集中してなのか事故を回避するためなのか,当該ライブカメラ映像が見られなくなってしまうなどの影響も出た.

「岐阜のポーズ」というキーワードでネットを漁ると,このような画像がたくさん出てくる.昼夜問わず出てくるので,こんな山奥までまあご苦労さんとしか言いようがないが,なぜかブームになっていたことがわかる.

なぜこんな山奥で岐阜のポーズをとることが流行ったのか,ライブカメラの定点観測が10分おきと比較的更新頻度が高く,自分の画像をライブカメラ画像としてネットに載せるのが容易だったからだとか,そもそも後ろ向きで顔を特定されないので匿名性が高かったからだとか,いろいろ考察されているので,詳しく知りたいむきはそちらを参照していただくとして……

iPAQによるモバイル監視カメラ

私が気になったのは,このようなライブカメラ映像がスマートフォンの小さいデバイスで誰もがいつでもどこでも確認できるようになったんだなあとしみじみ思うと同時に,感慨深く思い出したことがあったからである.

次の画像は,Linux Conference 2002 (LC2002)で発表した予稿から切り出してきた図である.写っているのは,iPAQで観測しているウェブカメラの画像である.リモートに設置されたウェブカメラが,窓の外,首都高の交通状況を動画で撮影し続けている状況を,Wifiで接続されたiPAQで確認している.

皆さんはiPAQなんてご存知ないかもしれない.iPadのパチモンではありませんぞ?

iPAQとは,今はなきCompaqが2000年から発売していた「ハンドヘルドコンピュータ」,今でいうモバイルデバイスで,デジタルアシスタントやポケットPCなどと呼ばれていた,スマートフォンの前身として位置付けられるデバイスである.

このiPAQ,Windows CEという組み込みデバイス向けWindowsがインストールされていたはずだが,Familiar LinuxというWindows CEをまるっと入れ替えて使うためのLinuxが利用でき,さらにXも動いていたので普通のLinuxアプリケーションを開発するように利用できたのである.もっとも,本体で開発はできないので,親機でクロスコンパイルしたソフトウェアをダウンロードして云々と,ちょっとした手間が必要だったのはなんとなく覚えている.

というわけで,今から20年以上前.初代iPhoneが出たのが2007年だから,その5年も前に,こんなことをして遊んでいた.歴史のたらればは語ってもせんないが,2002年のこれといい,その後のストリートビューもどきといい(この件についてはまた機会があれば紹介したい),資金さえあれば億万長者になれそうなアイデアは自分でも若い頃にいろいろと出していたのである.

それを考えると,技術馬鹿ではダメで,口八丁手八丁で資本家を騙くらかす,いや,投資させる能力が,いかに大切かと思わないでもない(まあ,技術馬鹿で育ってきた今の立場も,それなりに悪くはないけれど……)

2024年1月1日月曜日

Rails 7にimportmapのみでBootstrap, jQuery / jQuery-UIを設定する方法

かねてよりRailsをしばしば利用しており,Railsアプリの作り方を教える授業も担当,だいぶ内容が古くなってしまったが書籍も出しているくらいにはRailsを愛用している.しかし,Rails 7になってフロント周りがいろいろと変更されて,ネットの情報がのきなみ信用ならない状況になっていて,どこかで最新の状況を整理しておかねばならないなと感じていた.

なにしろ,jQuery-UIなんかを使ってちょいと気の利いたことをやろうとしても,どうにもうまくいかず,困った状況なのである.そこで,今回,BootstrapとjQuery / jQuery-UI を importmap の仕組みで導入する方法を整理した.最終的に,次図のような状況を実現するところまで解説する.

なお,動作を確認したバージョンは,次のとおりである.

ruby: 3.2.2, rails: 7.0.8, bootstrap: 5.3.2, jQuery: 3.7.1, jQuery-ui: 1.12.1

また,次の記事を参考にした.

前者のBootstrapの導入方法は,一箇所,そのままだとエラーになる箇所があるうえ,若干,記述が曖昧な箇所がある.一方,後者は問題なく実行できた.やはり確実な情報を入手するには英語の文献にあたれ,ということだろうか.

アプリの構築

まず,テストのためのアプリの雛形を構築する.homeコントローラだけを作っておく.

$ rails new Test; cd Test

...

$ bin/rails g controller home index

config/routes.rb は次のようにしておこう.

Rails.application.routes.draw do

  root 'home#index'

end


Bootstrapの導入

Gemfile に次を追加する(bundle add bootstrap を実施でもよい).

# Bootstrap 5

gem "bootstrap", "~> 5.3.0"

また,以下の gem "sassc-rails" と書いてある行のコメントアウトを外す.

# Use Sass to process CSS

# gem "sassc-rails"

これを,次のようにする.

# Use Sass to process CSS

gem "sassc-rails"

Gemfileを書き換えたら,gemをインストールしよう.

$ bundle install

Rails 7.0.8 だとimportmapがインストールされているはずなので,config/importmap.rb には次の2行を追記する(bin/importmap pin bootstrapコマンドでも必要な情報が記入されるが,実行時に大量のエラーが出るという問題がある).

pin "bootstrap", to: "https://ga.jspm.io/npm:bootstrap@5.3.2/dist/js/bootstrap.esm.js"

pin "@popperjs/core", to: "https://ga.jspm.io/npm:@popperjs/core@2.11.8/lib/index.js"

app/javascript/application.js に下記を追記する.

import "./bootstrap"

スタイルシートをscssに変更する.

$ mv app/assets/stylesheets/application.{c,sc}ss 

app/assets/styleseets/application.scss には次のように記述する.デフォルトではコメントが記載されているだけなので,コメントの後に次のように追記すればよい.

@import "bootstrap";

確認のために app/views/layouts/application.html.erb の<body>〜</body>を次のように修正する.localhost:3000にアクセスしたときに,少しインデントされて表示されていれば,Bootstrapが有効になっているはずである.

...

  <body>

    <div class="container">

      <%= yield %>

    </div>

  </body>

</html>


Stimulus JSのセットアップ

さて,次はjQueryとjQuery-UIである.が,その前に,stimulus.js を設定しておく.まず,次のコマンドでstimulus.jsコントローラを作成する.

$ bin/rails g stimulus home

stimulus.jsを利用するために,app/views/home/index.html.erb を次のように記述する.

<div data-controller="home">

  <h1> This is home page</h1>

</div>

さらに,app/javascript/controllers/home_controller.js を次のように記述する.

import { Controller } from "@hotwired/stimulus"


// Connects to data-controller="home"

export default class extends Controller {

  connect() {

    console.log("home controller has been connected");

  }

}

こうしておくと,data-controller="home" が記載されたページが表示されたときにこのJavaScriptが有効になるらしい.localhost:3000にアクセスしてブラウザの開発コンソールをチェックすると,このメッセージが記録されていることを確認できるだろう,

jQueryおよびjQuery-UIの導入

いよいよjQueryとjQuery-UIを導入する.まず,Gemfileに次の記述を追記する.

# Use jquery as the JavaScript library

gem 'jquery-rails'


# Use jquery-ui for pretty UI

gem 'jquery-ui-rails'

忘れずにgemをインストールしておこう.

$ bundle install

app/assets/styleseets/application.scss には次の行を追記する.

@import "jquery-ui.css";

次に,app/javascript/jquery_ui.js というファイルを作り,次を記載する.

//= require jquery-ui

さらに,app/javascript/application.js に次を追記する.

import "jquery"

import "jquery_ujs"

import "./jquery_ui"

あと,もう少し.config/initializers/assets.rb に次の行を追加する.

Rails.application.config.assets.precompile += %w( jquery.min.js jquery_ujs.js )

さらに,config/importmap.rb には次の2行を追記する.

pin "jquery", to: "jquery.min.js", preload: true

pin "jquery_ujs", to: "jquery_ujs.js", preload: true

これで準備OKである.

動作確認

うまく設定できたかどうか,動作確認しよう.

app/views/home/index.html.erb は,次のように書き換える.

<div data-controller="home">

  <h1 class="mt-3"> This is home page</h1>

  <h6> Pick date using jQuery Datepicker </h6>

  <p>Date: <input type="text" id="datepicker"></p>

  <br>

  <hr>

  <h6> JQuery Draggable Element </h6>

  <div id="draggable" class="ui-widget-content">

    <p>Drag me around</p>

  </div>

  <br>

  <hr>

  <h6> Click Event using JQuery </h6>

  <button id="btn-click" class="btn btn-primary"> Click Me </button>

</div>

これらの要素をコントロールするための app/javascript/controllers/home_controller.js も,次のように記述しておこう.

import { Controller } from "@hotwired/stimulus"


// Connects to data-controller="home"

export default class extends Controller {

  connect() {

    console.log("home controller has been connected");

    $("#datepicker").datepicker();


    var initial_val = 0;

    $("#btn-click").click(function (e) {

      e.preventDefault();

      var date_value = $("#datepicker").val();

      alert(`button has been clicked ${initial_val} and date ${date_value} `);

      initial_val+= 1;

    });


    $(function() {

         $("#draggable").draggable();

      });

  }

}

サーバをいったん止め,再起動する.

$ bin/rails s

ブラウザでアクセスして,冒頭に示したような画面が現れれば,OKである.それぞれのアイテムが適切に動作している状況を確認されたい.

以上が,Bootstrap,jQueryおよびjQuery-UIを,Rails 7にNode.jsを使わないで導入する方法である.

おまけ

jQuery-UIに拘っている理由は,とあるプロジェクトでスライダー要素を使いたいからである.スライダーも使えることを,確認しておこう.app/views/home/index.html.erb に次の記述を追記する.どこでもよいが,とりあえずは,ボタンの下くらいに配置しておくことにする.

  <hr>

  <h6> JQuery Slidar Element </h6>

  <div id="slider" class="col-6 ui-widget"></div>

app/javascript/controllers/home_controller.js の修正は次のようにする.9ステップのスライダーを作り,スライダーが弄られたら値をコンソールに,都度,吐き出すというコードである.

...
    
$(
function() {

       $("#draggable").draggable();

       $("#slider").slider({ min: -4, max: 4, step: 1, value: 0,

           slide: function(event, ui) { console.log(ui.value); } });

    });

  }

}

動かして,試してみよう.うまくスライダーを使えるようになっただろうか.

実際には,コンソールに吐くのではなく,jQueryのattr()メソッドなどを使ってフォームのhidden_fieldにでも値をセットするようにすれば,スライダーの値をサーバに送り返すようなインタフェースを作るのは容易であろう.

2023年12月30日土曜日

シミュレーションゲームを使った行動分析

Twineというツールがある.もともとこのツール,「対話的非線形物語(interactive, nonlinear stories)」あるいは「あなた自身の冒険を作成(create-your-own-adventure)」と呼ばれる,オンライン版のテキストアドベンチャーゲームを作成するツールである.

このツールを用いて行動分析できないかと今年の卒研生が考えた.彼らは「避難行動のシミュレーションゲーム」を作成し,いま,その分析をしながら卒論を書いている.

もとより簡単な行動ログを記録する機能が用意されていたが,より簡便かつ確実に,詳細な行動記録を取れるように拡張してみた.本稿ではその概要を説明する.

Snowmanの利用

まず,Twine上で動作させるstory formatとしてSnowmanと呼ばれるものを利用する.Twineでは,いくつかのスクリプティングシステムを切り替えて活用できる.そのスクリプト言語のことをstory formatと呼んでいる.

デフォルトではHarloweと呼ばれるものが組み込まれているが,これを,Snowmanと呼ばれるstory formatに切り替える.Snowmanは,CSSやJavaScriptをある程度理解している人向けに用意されているもので,PHPやERB(Embedded Ruby)のように,<% …… %>や<%= …… %>といったタグを用いてJavaScriptをそのまま埋め込められる.

なお,Snowmanへの切り替えは,Twine編集画面のStoryタブにあるDefaultsメニューから行う.

Story JavaScriptの設定

Story formatをSnowmanに切り替えたら,まず,StoryタブのJavaScriptメニューを開き,Story JavaScriptに以下のコードを記載する.

window.story.state.hash = {};


// create a unique ID

window.story.state.uid = Date.now().toString(16) +

            Math.floor(1000 * Math.random()).toString(16);


$(window).on('sm.passage.shown', 

             function (eventObject, passageObject) {

  window.story.state.

    hash[passageObject.passage.name] = eventObject.timeStamp


  // disable the browser's back button

  history.pushState(null, null, null);

  return;

});


// to show the alert to quit the game

$(window).on('beforeunload', function (event) {

  event.preventDefault();

  return;

});

このコードは,ストーリーが起動されたときに最初に走るJavaScriptのプログラムである.なお,Snowmanでは,JavaScriptの動作スコープは各passage(ページのこと)内に閉じられており,グローバル変数をwindow.story以外に持たない.したがって,ストーリー全体でデータをやりとりしたい場合には,基本的にはwindow.story.state変数にいろいろと付け加えていくしかない.

そのような理由により,まずは,window.story.state.hashという連想配列を用意し,動作状況はそこに記録していくことにする.

なお,もうひとつ,window.story.state.uidというユーザIDを記録する変数も用意し,そこに一意な文字列として作成するIDを格納する.

Snowmanでは,passage(ページ)遷移時にsm.passage.shownというイベントを発火する.各passageのアクセス記録を取りたければ,そのイベントを受けて,先の連想配列に,passage名をキー,その時点でのタイムスタンプ(Unixエポック)をバリューとして,記録するようにしておけばよい.passage名はpassageObject.passage.nameとして,タイムスタンプはeventObject.timestampとして与えられるので,それを連想配列に記録する.

残りのコードは,ブラウザの「戻る」ボタンを無効にしたり,途中でやめようとしたときにアラートを発したりという設定を行うものである.

記録のテスト

簡単なストーリーを用意した.次の図は,四つのpassageから成るストーリーである.Story JavaScriptには先のコードが入れられており,最後のページには,記録されたユーザIDとJSON形式で提示されるアクセス一覧を表示するコードが埋め込まれている.

このストーリーを実行して最後のページ(The last page)まで遷移すると,次の画面が現れる.

一意なユーザIDと,JSON形式で表現されたアクセスログが表示されていることを確認できる.

ところで,ここまで注意深く読んできたひとは,"The last page"が記録されていないじゃないか?ということに気付いただろう.そのとおり.残念ながら最後のページの記録が残らない.これは,どうも,sm.passage.shownというイベントが,ページのレンダリングの「後で」発火するから,という仕様によるものらしい.

なお,ドキュメントにはsm.passage.hideやsm.passage.showというイベントもあると書いてあり,shownではなくshowを使えば最後のページも記録できそうなものだが,現時点で利用できるTwine 2.8.0とSnowman 2.0.2の組合せではsm.passage.shownしか使えなかった.残念だが,致し方ないところである.最後まで記録するためには,最後にもうひとつ,ダミーのページを用意して対処する必要がある.この点には注意しなければならない.

サーバへ送信

さて,ここまで確認できれば,あとは,最後のpassageにサーバへ記録を送信するコードを埋め込み,サーバ側ではその送信を受け取るコードを用意すればよいだけである.

<%

  $.ajax({

    url: 'https://your.server.domain/php/tlog.php',

    type: 'POST',

    data: { 'uid': window.story.state.uid,

            'log': JSON.stringify(window.story.state.hash) },

    dataType: 'json'

  });

%>

このコードはyour.server.domainというサーバに結果を送信するAJAXのコードである.ユーザIDとJSON形式で表現したアクセスログを送っている.

なお,アクセスログのデータは ... 'log': JSON.stringify(window.story.state.hash) }ではなく... 'log': window.story.state.hash }としてもそのままJSONデータとして送信できるが,サーバ側での処理を簡易化するため,この段階で文字列データ化して送信している点に注意.

サーバ側の処理

サーバ側のプログラムは,/var/www/html/php/tlog.phpというファイルにおいて,次のように記述する(サーバ側はUbuntu 20.04, PHP 7.4.3 および SQLite3 3.31.1を使用).

<?php

  $uid = $_POST['uid'];

  $log = $_POST['log'];


  $dbfile = './tlog_data.sqlite3';

  $conn = new PDO('sqlite:' . $dbfile);


  // create table

  $ddl = 'CREATE TABLE IF NOT EXISTS userdata(

             id integer primary key autoincrement, 

             uid string, log text)';

  $conn->query($ddl);


  // insert posted data

  $sql = 'INSERT INTO userdata(uid, log) 

          VALUES (:uid, :log)';

  $stmt = $conn->prepare($sql);

  $stmt->execute(array(':uid' => $uid, ':log' => $log));

?>

以上の比較的単純なコードで,ユーザ行動を記録できる.次のスクリーンショットは,記録の例である.左からID,ユーザID,アクセスログが記録されている状況を確認できよう.

今回は単純な線形のストーリーであるため,全て同じ行動でタイムスタンプが違うだけだが,複雑な非線形ストーリーを用意すれば,全ての選択行動をデータベースに記録でき,その結果を分析すればユーザの判断行動もわかるという仕組みである.

行動分析の例

最後に,行動分析の事例を紹介しておこう.いま卒論に取り組んでいる学生たちが用意したストーリーで得られた,ユーザの選択行動データである.テーマは「避難行動」,大地震に遭遇したときの避難状況において,ユーザはどういった判断をするのかという分析である.

次の図は,アクセスログから解析した行動状況を示すものである.ノードは各passageを示し,ノードに付記されている数値は,そのpassageを通過したユーザの数を表す.また,ノードの色は滞在時間の平均値から計算されたものであり,寒色系は短い時間,暖色系は長い時間を表している.白は誰も通過しなかったノード,および,最後のノードである(最後のノードはそもそも滞在時間を計測できないため).

この図は,アクセスログと,Twineから出力される.tweeファイルに基づき,PythonとGraphvizを用いて作成した.アクセスログだけでなく.tweeファイルも必要な理由は,誰も通過しなかったノードはアクセスログから掘り起こせないからである(なお,その作業を行ったことにより,どこからも参照され得ない不適切なノードの存在も発覚した.そのような不適切なノードは分析作業の対象外として,先の図には表していない).

この結果から,いくつか意義のある分析結果が得られている.ここでは,ひとつの興味深い事例を紹介しよう.


「道が分かれている」というpassageでは,ハザードマップを見たことがあるか否かの質問を投げかけている.「はい」を選んだグループと「いいえ」を選んだグループでは,明らかに,その後に投げかけられた「どの場所を通っていきますか?」という設問の回答に差が出ている.

見ただけで,ハザードマップを見たことがあるグループは大通りを選ぶ傾向がある一方で,見たことがないグループはそうでもないことがわかる.実は,ハザードマップには大通りを選ぶべきであるヒントが記されていた.したがって,素直に解釈すればハザードマップを見たグループは大通りを選ぶ一択になるはずなのである.この結果に対してカイ二乗検定を実施したところ,1%水準で有意差が示された.