ページ

2014-12-14

LibreOffice用カラーテーブルの12色版を作った

以前の「LibreOffice用カラーテーブルを作った」のテーブルが、LibreOfficeの新しいバージョンで12色になったことによってまだらになってしまったことを教えて頂いていたのだが、ようやく対応したバージョンを作った。

ダウンロードはこちらから: https://github.com/sunnyone/locolor/raw/master/munsell.soc

今回からmunsell.socにした。使い方は前回の記事参照。


 今回選択したのは、この色達。12色になったことによって、マンセルの各色相の代表色の「5 XX」(10色)が選べるようになったので選んで、それに「10Y」と「10PB」を加えた。



今回更新したのは、「VyOS 1.1のファイルシステム階層を図にした」で使いたかったからなのだけど、どうやって使ったかを参考になればと思って書いておく。
  • 全体の背景は白、文字は黒。
  • 原則箱の塗りつぶしは[1]のトーン(上から1番目)、文字は[8]のトーン、枠線は[5]のトーン。
  • 隣り合う色はできるだけ色相差があるように、各要素別に色相を選択。
なお、LibreOffice 4.4でまだら現象は解消されるらしい。前よりはずっとよくなってる。しかし、好みの問題もあると思うけど、この色はちょっとチカチカして使いにくいなと思うので、きっとこのmunsell.socを使い続けると思う。

ちなみに、前回の「機械的に計算するならHSVのほうがいいんじゃ?」 のやつを実際にやってみたらこうなった。RGBで色相を等分割して、彩度/明度のパーセンテージを決めて割り当てたんだけど、4.4のと似たような結果になる。かなりの調整が要りそうなのでやめた。

2014-12-12

RからMongoDBにアクセスする2つのライブラリ

これは、R Advent Calendar 2014 12日目および MongoDB Advent Calendar 2014 12日目の記事です。

---
すでにJSONファイルがたくさんあるデータをRに食わせようと思って、CSVに変換しようとしたのだけど「こういうときはMongoDBをハブに使えばいいんじゃね?」ということを思いつき、いまさらながらR × MongoDBを試してみた記録である。

データは「Vue.jsを使ってBloggerの最新記事一覧を表示する」の記事にでてくるJSON結果のfeedのentryをバラしてcollectionに入れた。なお、どちらのライブラリもinsertする機能がついているが、その部分は試していない。

rmongodb

インストール

install.packages('rmongodb')

使い方

rmongodbは、RからMongoDBにアクセスするためのライブラリのひとつ。mongodbのCライブラリのラッパーらしい。短い使いかたはこんなかんじ。

mongodb.create で接続を作り、mongodb.findで検索し、cursorで処理する。この場合の処理はmongo.cursor.to.data.frame

data.frameになる前に加工が必要だという場合は、こんな感じ。




Webを見ていると、クエリの組み立てにbson.*を呼んでいたりとかする例が多いのだけど、JSON文字列を渡せたり、listで渡せたりもするので、もうちょっと高レベルな関数ないかなと探してみるのもいいかもしれない。

参考


RMongo

もうひとつRからMongoDBを使うライブラリにRMongoというのがある。こちらはJavaが必要。

インストール

install.packages('RMongo')

使い方





ネストされたところがJSON文字列というのがちょっと。。。

参考

テストケースがわかりやすい。

感想

rmongodbは低レベル操作が目につくのに対し、RMongoのほうはそうでもないので、だいたいうまくやってくれるのかなーと思いきや、ネストされた構造の処理が(より)いまいちなので、rmongodbを使っていればいいのかなという感じだった。

ただ、Rにあまり慣れていないせいもあると思うが、ちょっとでも加工が必要になってくると、かえって冗長な感じになってしまうので、データ構造によってはMongoDB->MongoDBでも、MongoDB->CSVででも、事前処理したほうがさくっと終わりそうだなという印象を受けた。


付録: データ取り込み

RubyでMongoDBに入れた。MongoDBは$始まりのキーは許してくれないので、hash keyを変換するいまいちなコード入り。



2014-12-08

Linux/WindowsがUEFIでブートしているか調べる

この記事は、UEFI Advent Calendar 2014の記事です。ライトですが書けそうなので書きます。
---

Linuxの場合

Linuxの場合は、/sys/firmware/efiの存在を確認する(Ubuntu 14.04で確認)。
$ ls -al /sys/firmware/efi
total 0
drwxr-xr-x  4 root root    0 Dec  2 23:54 .
drwxr-xr-x  5 root root    0 Dec  2 23:54 ..
drwxr-xr-x  2 root root    0 Dec  2 23:54 efivars
-r--------  1 root root 4096 Dec  2 23:54 systab
drwxr-xr-x 27 root root    0 Dec  2 23:55 vars

Macの場合は違うことがあるようだが、未検証。詳しくはArch Wikiをどうぞ。

Windows8 の場合

GUIで調べる

Windows8以降の場合、コントロールパネル>管理ツール>システム情報の「システムの要約」に「BIOSモード」という項目があり、これが「UEFI」か「レガシ」かで判断することが可能。



コマンドラインで調べる

PowerShellの「Get-SecureBootUEFI」コマンドレットの結果を見ることで確認できる(要管理者権限)

BIOSの場合、サポートされていない旨が表示される:
PS C:> Get-SecureBootUEFI -Name SetupMode
Get-SecureBootUEFI : このプラットフォームではサポートされていないコマンドレット: 0xC0000002
発生場所 行:1 文字:1
+ Get-SecureBootUEFI -Name SetupMode
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : NotImplemented: (Microsoft.Secur...BootUefiCommand:GetSecureBootUefiCommand) [Get-SecureBootUEFI], PlatformNotSupportedException
+ FullyQualifiedErrorId : GetFWVarFailed,Microsoft.SecureBoot.Commands.GetSecureBootUefiCommand

UEFIの場合、変数の値に関するメッセージ、あるいは値そのものが表示される:
(値が定義されていない場合)
PS C:> Get-SecureBootUEFI -Name SecureBoot
Get-SecureBootUEFI : 変数は現在定義されていません: 0xC0000100
発生場所 行:1 文字:1
+ Get-SecureBootUEFI -Name SecureBoot
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ResourceUnavailable: (Microsoft.Secur...BootUefiCommand:GetSecureBootUefiCommand) [Get-SecureBootUEFI], StatusException
+ FullyQualifiedErrorId : GetFWVarFailed,Microsoft.SecureBoot.Commands.GetSecureBootUefiCommand

(値が定義されている場合)
PS C:> Get-SecureBootUEFI -Name SetupMode

Name                                    Bytes                                   Attributes
----                                    -----                                   ----------
SetupMode                               {0}                                     BOOTSERVICE ACCESS...

Windows7の場合

いまどきWindows7で調べるか、という感じがするのであまり調べてないが、コントロールパネル>管理ツール>システム情報も、Get-SecureBootUEFIもないので、別の方法を使う必要がある。

次のいずれかの方法を使って、Windows が正しいファームウェア モードでインストールされたことを確かめる
に記述されている「GetFirmwareEnvironmentVariable」関数を呼ぶPowerShellスクリプトがScript Centerにある。

Determine UEFI or Legacy BIOS from PowerShell (Three methods)


bcdeditを実行して、ブートローダーのpathに.efiのファイルがあるかどうか確認する方法も恐らく使える。
(Windows7/BIOS)
C:\>bcdedit | find "path"
path                    \Windows\system32\winload.exe

(以下はWindows8.1/UEFIの出力だが、似たような感じになるのではないかと)
C:\2>bcdedit | find "path"
path                    \EFI\Microsoft\Boot\bootmgfw.efi
path                    \Windows\system32\winload.efi

なお、Webで検索すると、パーティションテーブルがGPTかどうかを確認する方法がよく見つかるが、WindowsでもGPT + BIOSができるようなので、あまり正確でないのでは?と思うが未検証。
Windows 7: Boot Windows 7/8 from GPT on BIOS system : No hybrid MBRs or DUET!




2014-12-07

VyOS 1.1のファイルシステム階層を図にした

この記事は、VyOS Advent Calendar 2014の記事です。
---

VyOSは、ネットワーク機器のように利用できるLinux distribution。Ciscoルータのようにコマンドで設定し、コンフィグを保持して動作する(JunOSと似ているといわれているが、使ったことがないのでわからない)。Brocadeに買収され、公開されなくなってしまったVyattaをコミュニティで保守している。

ファイルシステム階層

このVyOSは、アップグレード等がしやすいように、ディスクにインストールする際も、イメージでインストール(install image)することが推奨されている。install imageでインストールすると、通常の/とswapがあって、必要に応じて/usrや/homeが切れらてて、といったようなパーティションの分割はされず、CDブートするような形になっている。そのため、構造がわからなかったので、追いかけてまとめたのが、以下の図である。


VyOSのファイルシステム階層のまとめ

まとめると、以下のようになる。
  • Read-Onlyのsda1:/boot/1.1.0/1.1.0.squashfsをベースに、Copy-On-Writeでsda1:/boot/1.1.0/live-rwの領域を使うoverlayfsのマウントが基本になっている。
  • 揮発性の/opt/vyatta/configと、永続化される/opt/vyatta/etc/config (/config)がある。
  • /live以下は、このoverlayfsを構成・管理するためにマウントされた領域で、通常は気にしなくて良い。
  • /boot以下もほぼ同様に、live環境と通常環境のつじつまを合わせるためにマウントされている。

各領域の解説

各領域を個別に解説していくと、以下の通りになる。/sysとか/procとかは他と一緒なので省略する。
/live
overlayfsによってCopy-On-Writeが構成されている前の生の領域をつつくためのディレクトリをマウントするディレクトリ。
/live/image
Copy-On-Write領域を含むパーティションをマウントするところ。
/live/cow
Copy-On-Write領域の生のファイル群。
/opt/vyatta/config
揮発性のVyOSの設定を書き込むところ。Ciscoでいうrunning-configのイメージ。
/opt/vyatta/etc/config (=/config)
永続化されるVyOSの設定を書き込むところ。Ciscoでいうstartup-configのイメージ。結果的に/configと同じ。ただし、どの環境でも/configを使えるように、というようなことを言っているので、/configを使うほうがベターか?
/boot
/bootはCopy-On-Writeの構成の前のタイミングから必要なので、別枠で管理される。そのため、個別にマウントされている。
/boot/grub
/bootはイメージ名別だが、grubはブート単位で共通なのでさらにマウントされている。

Debian Liveをベースにしているようなので、おそらくDebian Liveと近いのではないかと思う。

ブートプロセス

上述の説明を作るのに、/proc/mountsを読めばわかるかなーと思っていたが、読んでもわからなかったので、ブートプロセスを追うことになってしまった。もしかしたら参考になる人がいるかもしれないので、マウントに関連する部分について読んだメモを残しておく。
(分割されていないメモのほうが見やすいかもしれないのでここに置いておく)

ブートプロセスのマウント関連部分の概略

  • Grubからinitrdが立ち上がる。
  • initrd内で必要なイメージや領域を探し出し、いくつか「/なんとか」にマウント後、本ブートに必要な分を「/root」以下にぶら下げる(このため、ブート後には見えない謎の/cowとか/live-rw-backingが残る)。
  • 通常のsysvrcのinit処理に移り、/opt/vyatta/configなど、後からでも間に合う分をマウントする。

以下は各処理。

Grubでブート

まずGrubでブートする。/boot/grub/grub.cfgのデフォルトエントリが以下の通りになっているので、initrd=/boot/1.1.0/initrd.imgが起動する。「boot=live」「vyatta-union=/boot/1.1.0」がポイント。

menuentry "VyOS 1.1.0 linux (KVM console)" {
 linux /boot/1.1.0/vmlinuz boot=live quiet vyatta-union=/boot/1.1.0  console=ttyS0,9600 console=tty0
 initrd /boot/1.1.0/initrd.img
}

initrdのinit起動

initrd内のinitスクリプトが起動する。カーネルパラメータbootがBOOT環境変数に入っているため、
. /scripts/${BOOT}    #L215
ではscripts/liveがdot sourceされ、
mountroot   #L218
で、mountroot関数が呼ばれる。

scripts/liveのmountroot関数によるmount処理

必要なイメージを探したりしながら、ブートに必要な部分がマウントされていく。カーネルパラメータvyatta-union=の分岐で必要なパラメータがセットされているのがポイント。
説明しているとしんどいので呼んだと考えられるコマンドと、呼んだ箇所のメモを記載する。

#Lxxxは特に記述がなければscripts/liveのもの。括弧書きはブート後の/proc/mountsの対応行。

mount -t ext4 -o ro,noatime /dev/sda1 /live/image

-> livefs_root=$(find_livefs ${i})
  # $i: 0...60 (timeoutカウンタ)
  -> check_dev "${dev}" # L1546
    # $dev: "/dev/sda1"  #L1531,L1533,L1544の結果からおそらく
    -> mount -t ${fstype} -o ro,noatime "${devname}" ${mountpoint}  #L1449
       # $fstype: "ext4"  #L1445のget_fstypeの結果からおそらく
       # $devname: "/dev/sda1"  #L1423の結果からおそらく
       # $mountpoint: "/live/image" #L10
       ===> mount -t ext4 -o ro,noatime /dev/sda1 /live/image (後の/dev/sda1 /live/image ext4 rw,relatime,data=ordered 0 0)
  # livefs_rootには/live/imageが入る

mount -t squashfs -o ro,noatime /dev/loop0 /1.1.0.squashfs

-> mount_images_in_directory "${livefs_root}" "${rootmnt}" "${mac}"                    # L1700
  -> setup_unionfs "${directory}/${LIVE_MEDIA_PATH}" "${rootmnt}" "${adddirectory}"     # L609
     # $directory: $livefs_root
     # $LIVE_MEDIA_PATH: "live" #L11
    -> mount -t "${fstype}" -o ro,noatime "${backdev}" "${croot}/${imagename}"          # L1178
       # $backdev: backdev=$(get_backing_device "${image}" "-r") #L1161
           # $(setup_loop "${1}" "loop" "/sys/block/loop*" '0' "${LIVE_MEDIA_ENCRYPTION}" "${2}") #L569
       # $croot: "/" #L1071
       # $imagename: imagename=$(basename "${image}") #L1142
       ===> mount -t squashfs -o ro,noatime /dev/loop0 /1.1.0.squashfs  (/dev/loop0 /1.1.0.squashfs squashfs ro,noatime 0 0)

mount -o remount,rw /dev/sda1 /live/image

-> # cowprobe=$(find_cow_device "${root_persistence}") #L1223
         # $root_persistence: "live-rw" #L13
         -> find_cow_device  #scripts/live-helpers:L333
            -> if ! try_mount "${devname}" "${cow_backing}" "rw"
               # $cow_backing: cow_backing="/${pers_label}-backing" #script/live-helpers:L339
               # $pers_label: $root_persistence  #script/live-helpers:L338
               # つまり、$cow_backingは"/live-rw-backing"
               # $devname: 探索の結果から/dev/sda1 (のはず)
               -> mount -o remount,"${opts}" "${dev}" "${old_mountp}"
                   # $opts: "rw" #L291
                   # $dev: "/dev/sda" #L289
                   # $old_mountp: "/live/image"
                   ===> mount -o remount,rw /dev/sda1 /live/image (後の/dev/sda1 /live/cow ext4 rw,relatime,data=ordered 0 0)

mount -o bind /live/image /live-rw-backing

-> mount -o bind "${old_mountp}" "${mountp}" #script/live-helpers:L314
                   # $old_mountp: おそらく"/live/image" #L294
                   # $mountp: /live-rw-backing
                   ===> mount -o bind /live/image /live-rw-backing
                        (/dev/sda1 /live-rw-backing ext4 rw,relatime,data=ordered 0 0)
            ## find_cow_deviceはecho "${pers_fpath}"を返す #script/live-helpers:L389
               # $pers_fpath: ${cow_backing}/${PERSISTENT_PATH}/${pers_label}  #script/live-helpers:L346
                 # $PERSISTENT_PATH: "$LIVE_MEDIA_PATH" #L482
                   # $LIVE_MEDIA_PATH: "${ARGUMENT#vyatta-union=}" #L481
                   #  grubのvyatta-union=は/boot/1.1.0
                 # すなわち、$pers_fpathは"/live-rw-backing/boot/1.1.0/live-rw"
            # find_cow_deviceは${cow_backing}/${PERSISTENT_PATH}/${pers_label}である
            #    "/live-rw-backing/boot/1.1.0/live-rw" を返している

mount -o bind /live-rw-backing/boot/1.1.0/live-rw /cow

-> mount -o bind ${cowdevice} /cow #L1297
       ===> mount -o bind /live-rw-backing/boot/1.1.0/live-rw /cow (後の/dev/sda1 /live/cow ext4 rw,relatime,data=ordered 0 0)
       # $cowdevice: ${cowprobe}  #L1249

mount -t overlayfs -o noatime,lowerdir=//1.1.0.squashfs,upperdir=/cow overlayfs /root

-> mount -t ${UNIONTYPE} -o noatime,lowerdir=${rofsstring},upperdir=/cow overlayfs "${rootmnt}" #L1345
        # $UNIONTYPE: "overlayfs" #/etc/live.conf
        # $rofsstring: "${croot}/${imagename}${roopt}:${rofsstring}" #L1178
           #  $croot: "/" #L1071
           #  $imagename: imagename=$(basename "${image}") #L1142
           #  $roopt: ""  #L1087
           #  $rofsstring: "" #L1074
           # rofsstring=${rofsstring%:} #L1183
        # $rootmnt: "/root"  #L62, #init:L51
        ==> mount -t overlayfs -o noatime,lowerdir=//1.1.0.squashfs,upperdir=/cow overlayfs /root
            (overlayfs / overlayfs rw,relatime,lowerdir=//1.1.0.squashfs,upperdir=/cow 0 0)

mount -t tmpfs tmpfs /root/live

-> mount -t tmpfs tmpfs ${rootmnt}/live #L1364
        ==> mount -t tmpfs tmpfs /root/live  (tmpfs /live tmpfs rw,relatime 0 0)

mount -o move /cow /root/live/cow

-> mount -o move /cow "${rootmnt}/live/cow" #L1411
        ==> mount -o move /cow /root/live/cow (/dev/sda1 /live/cow ext4 rw,relatime,data=ordered 0 0)

mount --move /live/image /root/live/image

run_scripts /scripts/live-bottom  #L1708
-> live-bottom/05mountpoints  https://github.com/vyos/live-initramfs/blob/47cb65a9b94ca48696e8e0255c921167ddcfb49b/scripts/live-bottom/05mountpoints
  -> mount --move /live/image /root/live/image  #scripts/live-bottom/05mountpoints:L33
    ===> mount --move /live/image /root/live/image (/dev/sda1 /live/image ext4 rw,relatime,data=ordered 0 0)

mount -o bind /root/live/cow/config /root/opt/vyatta/etc/config

-> live-bottom/50vyatta
https://github.com/vyos/build-iso/blob/4ddda254c76d2bfb807ed7c2c5ea992037638bf7/livecd/config.vyatta/chroot_local-includes/usr/share/initramfs-tools/scripts/live-bottom/50vyatta
    -> mount -o bind /root/live/cow/config /root/opt/vyatta/etc/config  #L51
    ===> mount -o bind /root/live/cow/config /root/opt/vyatta/etc/config (/dev/sda1 /opt/vyatta/etc/config ext4 rw,relatime,data=ordered 0 0)

あとは、以下で通常のinit処理が起動する。
exec run-init ${rootmnt} ${init} "$@" <${rootmnt}/dev/console >${rootmnt}/dev/console #L303

/etc/init.d/vyatta-router

ここでもマウント処理がある。

mount -o nosuid,nodev,mode=775,nr_inodes=0 -t tmpfs none /opt/vyatta/config

-> start #L159
  -> mount -o $tmpfs_opts -t tmpfs none ${vyatta_configdir} #L169
    # $tmpfs_opts: nosuid,nodev,mode=775,nr_inodes=0  #L168
    # $vyatta_configdir: "/opt/vyatta/config"  # /etc/default/vyattaより
    ===> mount -o nosuid,nodev,mode=775,nr_inodes=0 -t tmpfs none /opt/vyatta/config (none /opt/vyatta/config tmpfs rw,nosuid,nodev,relatime,nr_inodes=0,mode=775 0 0)

(mount --bind /opt/vyatta/etc/config /config)

if文で結果的に走ってないのだけど、VyOS的に大事な行なので。
-> mount_slashconfig #L175
    -> mount --bind /opt/vyatta/etc/config /config #L154
    ===> このbind mountはlive環境でもそうでないときでも/configが存在するようにという配慮らしい(L139)

mount --bind /live/image/boot/$image_name /boot

-> bind_mount_boot #L193   #ツール類が正しく操作できるようにという配慮(L112)
    -> mount --bind /live/image/boot/$image_name /boot  #L123
    ===> mount --bind /live/image/boot/1.1.0 /boot (/dev/sda1 /boot ext4 rw,relatime,data=ordered 0 0)

mount --bind /live/image/boot/grub /boot/grub

-> mount --bind /live/image/boot/grub /boot/grub    #L130
    ===> mount --bind /live/image/boot/grub /boot/grub (/dev/sda1 /boot/grub ext4 rw,relatime,data=ordered 0 0)

感想

/proc/mountsと/etc/mtabを追えばわかるだろうなと思って始めたけど、それだけじゃ全然わからなかった。ディスクを読むのに使ってたSystemRescueCdも似たような/livemntがあるので、LiveCD系は似たような構成なんだろうなと思う。そういう意味でLiveブートの構造がわかったのはよかった。

2014-12-04

Vue.jsを使ってBloggerの最新記事一覧を表示する

これは、Vue.js Advent Calendar 2014の記事です。

---
Webサイトのトップページだとかに、ブログの最新記事一覧へのリンクを表示することがある。今回はGoogleのブログサービスである「Blogger」で記事を書いていた場合に、その一覧を、データバインディングを行うJavaScriptライブラリであるVue.jsを使って表示する方法を説明する。

サンプル

実際のコードを見るほうが簡単なので、このブログを表示する例を出すと、以下の通りとなる。

動作例:http://jsfiddle.net/zvrakxuv/

短く書けるのがわかると思う。

解説

さて、以下で解説していく。

BloggerのAPIからのJSONの取得

まずデータを得るが、BloggerにはJSONPで記事の情報を返すURLがあるので、これを利用する。具体的には、このようなURLにアクセスすればよい。
http://blogname.blogspot.com/feeds/posts/default?alt=json-in-script&callback=myFunc
(参考: Simple example of retrieving JSON feeds from Blogger Data API)

すると、以下のようなデータが返ってくるので、JSONPの要領でデータを読み込めばよい(データはあまりにも多いので、jqコマンドで整形後適宜省略)。
myFunc({
  "feed": {
    "entry": [
      {(略)
        "published": {
          "$t": "2014-11-11T22:14:00.000+09:00"
        }, (略)
        "title": {
          "$t": "「アセットを抽出」の出力は油断するとボケる (Photoshop CC 2014)",
          "type": "text"
        }, (略)
        "link": [
          (4つ省略),
          {
            "title": "「アセットを抽出」の出力は油断するとボケる (Photoshop CC 2014)",
            "href": "http://d.sunnyone.org/2014/11/photoshop-cc-2014_67.html",
            "type": "text/html",
            "rel": "alternate"
          }
        ],
        "author": [(略)]
      },(略)});
詳しくは実際に叩いてみるか「Using JSON in the Google Data Protocol」を参照。

この他にも、サムネイルのURLや本文など、いろいろ入っているので、他にも状況に応じて使える。ただ、その分ブラウザに返すデータ量が多い。この時点でmax-results=5のように指定して数を限定するのがおすすめである。

Vue.jsによるデータバインディング

あとはcallbackに指定した関数でデータを受けて表示すればよいので、jQueryなんかで書いてももちろんよいが、ここではVue.jsを使う。

Vue.jsは、データバインディングを行うライブラリで、他のメジャーどころで言えばKnockout.jsの立ち位置に近いが、DSLがもう少し簡略化されており、さらっと書けるので、今回のようなケースには向いていると思う。(基盤に徹するBackbone.jsや、詰め込みまくりなAngular.jsとは異なる。)

バインド対象となる要素の記述

まずテンプレートとなる要素を記述する。今回の例は以下。


今回のポイントとなるのは以下の通り。

バインド対象となるidの記述

あとでCSSセレクタ記法で指示するので書き方はなんでもよいのだが、なんらかわかるように印をつける。今回はidとした。

繰り返しを意味するv-repeat

Vue.jsでは、各種v-なんとか(デフォルトではv-だが、data-vのように変更も可能)という属性(Directiveと呼ぶらしい)が用意されている。

このDirectiveのうち、まずはv-repeatを利用する。このv-repeat属性に「変数名: 対象」としておくと、対象を回して要素の中身を繰り返してくれる。

なお、dtとddをセットにしたいのでtemplate要素を利用したが、ul/liだったらliにv-repeatをつける感じになる。templateは、非対応ブラウザを考慮してdisplay: noneをつけたほうがいいかもしれない。

v-シリーズの指定方法は、概ねKnockout inspiredな感じである。詳しくは、Guideの「Directives」およびAPI Referenceの「Directives」を参照。

属性をセットするv-attr

v-attrに「属性名: 式」と記述するとその値を要素の属性にセットできる。

属性にも後述の{{ }}の記法が使えるのだが、テンプレートの段階でブラウザに解釈されると悲しい属性(imgのsrc)があるので、属性には基本的にこのv-attrを使うほうがベターだと思う。

値を出力する{{ }}記法

mustacheテンプレートライクな (Angularライクというべきか) {{ }}記法を使うと、値を記述することができる。
.でたどることもできるし、[n]も使える。| を使うとFilterを呼び出すこともできる。

フィルタ関数の定義

| に使うフィルタはカスタムに定義することができる。

定義するには、値と引数を受け取り、値を返す関数を用意し、Vue.filter()で設定する。
Vue.filter('first', function(value, length) {
  return value.substr(0, length);
});

フィルタについては、Guideの「Filters」およびAPI Referenceの「Filters」を参照。

データバインドの適用

あとは、先ほどcallback=に指定した関数でデータを受け取り、Vueオブジェクトを生成するだけ。今回は、elにバインド対象を、dataにバインドするデータを渡している。
function showFeedArticles(json) {
  new Vue({
    el: '#feed-article-list',
    data: json
  });
}

今回のケースではこれでおしまい。あとは、Guide をさらっと読めば一通り使えるようになると思う。