きみはねこみたいなにゃんにゃんなまほう

ねこもスクリプトをかくなり

Adobe ExtendScript Debuggerを使ってみる

アートボードを100枚以上含むファイルがあり、各アートボードのテキストボックスの内容をまとめてテキストファイルとして取得したくなったので、久しぶりにAdobe ExtendScriptスクリプトを書きました。やりたいことの要件は以下の通りです。

  • 各アートボードはそれぞれ1つのテキストボックスを持つ
    • もしくは対象の1つ以外のテキストボックスはレイヤーのロックなどで選択できないようにしておく
  • 各テキストボックスの内容が1行ごとに書かれたファイルを出力する

本物のデータは載せられないので、簡略化した例で示すと

f:id:lightbulbcat:20211226224228p:plain

のようなIllustratorのファイルに対して

テキストA
テキストB
テキストC
...

というデータが書き込まれたファイルを出力してくれるスクリプトが欲しい、ということになります。

開発環境はVS Codeを使い、途中でデバッグが辛くなったのでAdobe謹製のExtendScript Debuggerという拡張機能を入れました。 最終的に完成したスクリプトは以下のものです。

var CONFIG = {
    outFile: '~/Desktop/descs.txt',
}

function map(items, fn) {
    var res = []
    for (var i = 0; i < items.length; i++) res[i] = fn(items[i], i)
    return res
}

function filter(items, fn) {
    var res = []
    for (var i = 0; i < items.length; i++) {
        if (fn(items[i], i)) res.push(items[i])
    }
    return res
}

function log(input) {
    var now = new Date();
    var output = now.toTimeString() + ": " + input;
    $.writeln(output)
}

try {
    var texts = []
    log('Start script')
    for (var i = 0; i < app.activeDocument.artboards.length; i++) {
        app.activeDocument.selection = null;
        app.activeDocument.artboards.setActiveArtboardIndex(i);
        app.activeDocument.selectObjectsOnActiveArtboard();

        var textFrames = filter(app.activeDocument.selection, function(item) {
            return item instanceof TextFrame
        })

        texts.concat(map(textFrames, function(tf) {
            log('Artboard' + i + ': ' + tf.contents)
            return tf.contents
        }))
    }
    log('Detect ' + texts.length + ' textFrames total')

    texts = map(texts, function(text) {
        return text.replace(/\r\n|\r|\n/g, '\\n')
    })

    var output = texts.join('\n')
    var f = new File(CONFIG.outFile)
    f.encoding = 'UTF-8'
    f.lineFeed = 'Unix'
    f.open('w')
    f.write(output)
    f.close()

} catch (e) {
    alert('Error: ' + e)
}

始めはこのスクリプトデバッグを、ログメッセージをファイル出力して行なっていたのですが、 ファイルに何も書き込まれないという事象(原因は後述)に陥ったため、ExtendScript Debuggerの導入に踏み切りました。 ファイル出力を行う処理のデバッグ用のログをファイル出力で行なったため、結果として混乱が増大しました。 デバッグ専用の情報出力チャネルの存在は大切ですね。

ExtendScript Debuggerの使い方

使い方と言っても基本的には公式のドキュメントに従えば問題なく使えます。

ExtendScript Debugger - Visual Studio Marketplace

VS Codeデバッグ機能を使ったことがないと分かりづらいのは、デバッグ対象のプログラム (今回の場合はスクリプトを動作させるプログラムを指すのでAdobe Illustrator) を指定してやらないと Can’t start a session without an active target and engine. Select an active target and engine before trying again. と表示されて失敗するところです。意図するところは、どこでデバッグ対象のスクリプトを動かすか指定する必要があるということです。

f:id:lightbulbcat:20211226020254p:plain

これを解決するにはデバッグを実行する前に、下のステータスバーで対象プログラムを指定します。

f:id:lightbulbcat:20211226020229p:plain

Select the target application と表示されているところを選択すると選択モードになるので Adobe Illustrator を選択します。

f:id:lightbulbcat:20211226020234p:plain

デバッグの実行に成功すると $.write() で指定したメッセージがコンソールに流れます。

f:id:lightbulbcat:20211226020249p:plain

その他

毎回デバッグ対象のプログラムを指定したくない

${command:AskForScriptName} を固定文字列にすれば毎回ダイアログで入力せずにすみます。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "extendscript-debug",
            "request": "launch",
            "name": "Ask for script name",
            // "program": "${workspaceFolder}/${command:AskForScriptName}",
            "program": "${workspaceFolder}/copy-textbox.jsx",
            "stopOnEntry": false
        }
    ]
}

それにしてもこの program っていう表現、デバッグ対象のスクリプトなのか、ランタイムを指すのか、何を指しているか曖昧で分かりづらいですね。

ファイル出力ではまったところ

はまったところは2点。

  • join('\n') で結合した文字列の改行文字が fileObj.write() 時に \r になる
    • f.lineFeed = 'Unix' で期待通りになった
  • 日本語が出力されない
    • f.encoding = 'UTF-8' で改善された。

ちなみに File クラスのリファレンスは Illustrator_Scripting_Guide_cc.pdf ではなく JavaScriptToolsGuide_CS5.pdf にあります。 共にAdobeサイト内の検索に引っかからないのもあり非常に探しづらい。

AdobeはもっとExtendScriptのリファレンスを整備してほしい。なんでPDFでしか提供されていないんだよ。 というか公式リファレンスくらいちゃんとアクセスできるところに置いてほしい。AdobeExtendScriptを捨てたいんだろうか。

LinuxからAirPort Time Capsuleをマウントする

AirPort Time Capsule からデータをLinuxにコピーしたくて調べた。初めは多少速度は落ちるだろうけれどmacOS経由で移動すればいいやと考えていたが、何度やっても途中でコピーが止まるしキャンセルもできない状態になるので直接移行先であるLinuxからTime Capsuleの共有ディレクトリをマウントする方法を探した。

f:id:lightbulbcat:20211219145854p:plain
途中でコピーが止まる

手元のAirPort Time Capsule10.0.1.1 で動作しており Data という名前で共有ディレクトリを提供している。

sudo mkdir -p /mnt/tc
sudo mount.cifs //10.0.1.1/Data /mnt/tc -o user="USERNAME",password="PASSWORD",sec=ntlm,vers=1.0
ls /mnt/tc # Data の中身が表示される

で行けた。dmesg でエラーを表示しながら試行錯誤した。

# vers=1.0 を指定しない
sudo mount.cifs //10.0.1.1/Data /mnt/tc -o user="USERNAME",password="PASSWORD"
# No dialect specified on mount. Default has changed to a more secure dialect,
# SMB2.1 or later (e.g. SMB3), from CIFS (SMB1).
# To use the less secure SMB1 dialect to access old servers which do not support SMB3 (or SMB2.1) specify vers=1.0 on mount.

# sec=ntlm を指定しない
sudo mount.cifs //10.0.1.1/Data /mnt/tc -o user="USERNAME",password="PASSWORD",vers=1.0
# Status code returned 0xc000006d NT_STATUS_LOGON_FAILURE

参考

Adobe Illustrator単体+フォトプランをコンプリートプランに変更・統合した

私は普段から Adobe Illustrator をメインで利用しているが、コンプリートプランに含まれるほとんどのアプリは使わないので、通常はIllustrator単体プランと、値段の安さからフォトプランを合わせて利用している。 ただし、たまにコンプリートプランの40%オフのオファーがくるのでその際はコンプリートプランに変更することがある。

そういう利用の仕方をしていると発生するのが、複数のプランを統合してコンプリートプランに変更するという作業になる。 それで、結論だけ言ってしまうと、複数のプランを1つのプランに統合するにはカスタマーサポートへの問い合わせが必要になるらしい。

実際の操作ややりとりは以下の流れで行った。時間にして10分程度だった。

  1. web上でIllustrator単体プランをコンプリートプランに変更
  2. フォトプランが残っているので解約しようとするが違約金が発生する
  3. 違約金をなくせないかカスタマーサポートに相談 → 違約金なしで解約してもらえた
  4. ついでにプランを統合する際の手順を教えてもらう → 要カスタマーサポートとのこと

次回からは直接カスタマーサポートに相談しようと思う。

ただ、コンプリートプランを安く使う方法なんていくらでもあるので、いい加減そちらを検討したほうがいいのかもしれない。

iMac 2015の起動用の外付けSSDを選ぶ

lightbulbcat.hatenablog.com

で書いたように6年間使ってきたiMacのFusion Driveが分離されてしまった。起動ディスクをSSDに作ろうとしたところ失敗したため、仕方なくHDDから起動しているがとても遅い。Fusion Driveの分離もSSDの不具合が原因なのではと睨んでいる。現在iMacの新型狙いのため、何か適当に誤魔化しながら今のiMacを運用できる手段はないかと探したところ、外付けSSDを起動ディスクにできることを知った。

使用しているiMacのスペックを確認する

今までSSDを選んだことも普段使っているマシンのディスクのスペックを意識したこともなく、いい機会なので今自分が使っているiMacについて調べることにする。公式のスペックと

iMac (Retina 5K, 27-inch, Late 2015) - Technical Specifications

システムレポートを見ながら関係ありそうなものをピックアップしていく。 ついでに内蔵SSDとHDDの実測値も適当なサイトから拾ってきた。

2015年だとThunderbolt 2なんだ古いなとか、USB3はもうあったんだなとか、自分の持っている過去の認識とズレがあって感慨深い。

内蔵SSDとHDDだとSequential Readで7-8倍、Sequential Writeで5倍、Random Seek Read Write では100倍近い差がついている。 起動ディスクをHDDにすると遅くなるわけだ。HDDはSequential Read/Writeならある程度の速度は出るという先入観を持っていたため、この数値の差には驚いた。SSDは早い。

外付けインタフェースの選択肢としてはThunderbolt 2とUSB 3.0がある。 Thunderbolt 2の20 Gb/sは換算すると2.5 GBytes/sなので安価なSSDでは頭打ち要因にはならないだろう。 ただしThunderbolt 2に接続するSSDやら変換ケーブルやらを安価に揃えようとすると悩むことになりそうだ。 対してUSB 3.1の5 Gb/sは625 MBytes/sになるのでReadは頭打ちされそうだが、インタフェースの簡便さとしてはこちらが勝つ。

とりあえずBUFFALO SSD-PG240U3-BA 250GBを買ってみる

とりあえず次モデルまでの繋ぎを想定しているので、安価なUSB 3接続のSSDを購入してみた。

BUFFALO SSD-PG240U3-BA 250GB

Writeで320 MBytes/sは出るみたいなのでHDDよりはマシだろう。 Random Seekもそれなりには出てくれるんじゃないかと期待して、とりあえず4000円くらいで買えるこれで様子を見ることにする。

やっぱりCrucial X6 500GBにした

やっぱり後から見つけた500 MByte/sが出るらしいこちらのモデルにした。8000円程度。

Crucial X6 500GB

容量も倍なのでそこまで割高感はない。速度が上のBuffaloのものと比べると1.5倍になるので起動速度もそれなりに変わるだろう。 内蔵SSDの半分程度の速度は出る計算だけど、これでも遅くなるのは避けられなさそうだ。

使えるならthunderbolt 2ポートの2.5 GBytes/sを使ってみたいけどThunderbolt 2対応のSSDとかあんまり見ないし、変換ケーブルを噛ませたりするのも相性問題でドツボにハマりそうなのでやりたくない。

なんて思っているうちに早く新しいiMacが出たりしないものかと待ち侘びる。

届いたのでインストールして速度を測ってみる

Crucial X6が届いたのでmacOSをインストールしてみる。 OSやアプリケーションの起動速度は確かに向上した。

ReadとWriteで両方400 MBytes/s程度出ている。

f:id:lightbulbcat:20211119165852p:plain

内蔵HDDだと200MBytes/sも出ていないので2.5倍程度の速度にはなっている。

f:id:lightbulbcat:20211119170003p:plain

ちなみに内臓SSDだとRead 1963 MBytes/s、Write 698 MBytes/s出ており圧倒的。 ただし計測中の数回目のReadでエラーが発生したため、やっぱり一連の不具合は内蔵SSDが原因だったんだろう。

f:id:lightbulbcat:20211119170052p:plain

この速度を見て改めて失ったものの大きさを感じる。内蔵SSD早いな。 どうせ下取りに出しても二束三文にしかならないのだから、内蔵SSDを換装してもいいのかもしれない。

ところで体感速度で言うとFusion Driveで使っていた頃よりもむしろ向上した感がある。 もちろん現在クリーンインストールした状態であるため、時間の経過とともに体感速度も落ち着くのかもしれない。 それから、Readの実測値でなお4倍程度の差があるため、やっぱり一度Fusion Driveを解除した純粋な内蔵SSDから起動した場合の速度を体感したかったなという気持ちが残る。

Fusion DriveのiMacが起動しなくなったのでクリーンインストールした

まとめの追記

結論から言うとiMac 2015 lateでFusion Driveを組んでいる内蔵SSDで、Readが失敗するようになった事によりFusion Driveが分離し、macOSが起動しなくなった。SSDが原因ということに気づかず、SSDを起動ディスクにしようと四苦八苦した際の症状をまとめておく。

  • SSDのフォーマットで失敗することがある
    • MS-DOS (FAT)だと成功しやすい
  • SSDのフォーマットに成功してもマウント/アンマウントで失敗することがある
  • macOSSSDにインストールしている最中で必ず失敗する
    • タイミングは残り12分であることが多かった
    • エラーの内容は「an error occurred loading the update」(言語が日本語だと何になるんだろう)
    • エラーの意味的にネットワーク関係かと思いきや、切り分けの結果関係なさそう
  • diskutil verifyVolume は特に何も出力しなかった
  • smartmontoolsの smartctl を使ったところ Error 65535 occurred at disk power-on lifetime のような表示が何項目か出たが関係あるかは未確認
  • Apple Diagnosticsは特に異常を検知しなかった
  • diskutil activity でイベントをモニタリングしたところエラーが出たタイミングでディスクがdisapperになった
  • BlackMagic のディスクスピードテストを行なっている最中にSSDからReadが行えなくなるエラーが出た
    • これが症状としては一番わかりやすい

diskutil verifyVolumeApple Dianosticsで検出されないのは意外だったが、スピードテストでエラーが出たのでSSDが原因と見ていいだろう。 データは諦めるとして、再びmacOSを使えるようにするために取りうる選択肢としては

  • 内蔵HDDは正常なのでHDDを起動ディスクとしてインストールする
  • 内蔵SSDを換装する(面倒)
  • 外部SSDを起動ディスクとする

がある。HDDを起動ディスクにしたところ重くなったので、その後外部SSDをUSB 3.1 gen2接続して起動ディスクとして利用している。 その選定作業は以下のエントリで記録として残した。

lightbulbcat.hatenablog.com

以上、まとめとして事後的に追記した。以下、元のエントリの内容につづく。

発端

ある日普段つけっぱなしにしているiMacの画面にぽつんと進入禁止のマークのようなものが表示されるようになっていた。 どうやら起動に失敗しているようで、再起動しても改善しなかった。 復旧モードで起動し、ディスクユーティリティを見たところ、普段は見かけないHDDとSSDの表示があり、どうやらFusion Driveが解除されているようだった。 ネット上の記事を一通り検索して、元に戻すのは難しそうだと判断。データは諦めることにしてmacOSクリーンインストールすることにした。

ところがディスクのフォーマットがうまく行かない。 何度か試行錯誤した結果、どうやら一度MS-FATでフォーマットした後であればAPFSでフォーマットできるようになることがわかった。 APFSで連続フォーマットができない、という症状だった。なぜか再マウントするあたりの処理で失敗しているようだった。

これで一応まっさらなSSDのボリュームが用意できるようになったが、今度はmacOSのインストールに失敗する。 起動を早くしたいものだから、起動ディスクはSSDにしたかったのだが、これが常に残り12分のあたりで決まって「an error occurred loading the update」と出てインストールに失敗する。

f:id:lightbulbcat:20211119032210p:plain

言葉通りネットワークの問題なのかと思いWi-Fiと有線の両方試したが、両方で同様にエラーが出た。 ネットで探してもこれといった情報が見つからなかった。 仕方なくHDDにインストールすることにしたところ成功した。

なんとなくASPFでフォーマットしたSSDのマウント周りで失敗していたように思えるが、インストーラは細かいログを出してくれないので、切り分けはできない。もしかしたらSSDに不調が発生した結果Fusion Driveが壊れてしまい、起動しなくなったのかもしれない。

ところで何度も起動を繰り返して試行錯誤している最中の「ジャーン」という音には「いいかげんにしろ」と言いたくなる。 あなた今、私が手間暇かけて復旧しようとしているんですよと。 macは好きだけれどこれはいただけない。

その後

あれから色々試して、結局うまくいかなかったので外部SSDから起動することにした。

諦めるまでにSSDのいろんなフォーマットでOSインストールを試した。

  • GTPではなくMBPにしてみたところ起動ディスクはGTPの必要があるとインストーラに言われる
  • MS-DOS (FAT)ならいけるのではと試したところAPFSかMac OS Extendedでなければならないとインストーラに言われる
  • マウント/アンマウントのところでコケているのではと思い、インストーラを実行する前に何度かディスクユーティルでマウント/アンマウントを行えることを試してから実行したが失敗した
    • 結局同じエラー「an error occurred loading the update」になった
  • たまにフォーマット中にもマウントできずにエラーになることがあった

f:id:lightbulbcat:20211119032332p:plain

  • タイミングや処理のこけ方によっては再フォーマットするためにOSの再起動をする必要があったりととにかく面倒だった
  • 一応ネットワークも怪しんでテザリング回線で実行してみたが改善せず
  • diskutil verifyVolume は特に何も出力しなかった
  • smartmontoolsの smartctl を使ったところ Error 65535 occurred at disk power-on lifetime のような表示が何項目か出たのでこれが何か関係あるのだろうか
  • Apple Diagnosticsは特に異常を検知しなかった
  • diskutil activityでイベントをモニタリングしたところエラーが出たタイミングでディスクがdisapperになっていたので、インストール中の書き込み処理が原因か、それともアンマウント/マウントの処理に失敗したのかで、ディスクが認識できなくなったらしい

これにて私は諦めた。SSDが悪いと思うのだけれど、その確証となる何かコマンド出力が無いかなと、まだ若干後ろ髪を引かれている。

さらにその後

ディスクスピードテストを行なっている最中にSSDからReadが行えなくなるエラーが出たのでやっぱりSSDのせいだったのだろう。

Magic Trackpad のフィードバック機能が不安定だったので結局新しいものを買った

5年ほど使い続けていた Apple Magic Trackpad の Haptic Feedback 機能が不安定になったので結局新品を買ったところ問題なく動作するようになった。 当然と言えば当然なのだが、以前 Bluetooth 接続が不安になった際に iMac 本体側のNVRAMリセットで回復した経験があったので、今ひとつ Trackpad 側が悪いと言う確証を持てなかった。 結果を見れば Trackpad 側の問題だったのだが。 症状としては以下のようなものだった。

  • たまに Haptic Feedback 機能が反応しなくなる
    • iMac を起動した直後は反応するが 1分もたたないうちに反応しなくなる
    • 電源を切って、Trackpad を充電させると反応が戻ることがあるが、これも長くはもたない
  • さらに症状が進むと、たまにクリックすら反応しなくなる

という、動いたり動かなかったりする不安定な状態が2ヶ月くらい続いていた。 個人的な感覚ではバッテリーの経年劣化的なことが起こって、十分にフィードバックを動作させる電力を得られなくなっているのではと想像している。 もしそうだとしたら、初代の Magic Trackpad で採用されていたダイビングボード方式の物理的なクリック機構の方が長期的に見ればよいのかもしれない。 ただバッテリーの問題なのであれば、バッテリーを交換できればまた使えるようになるのであまり変わらないかもしれない。 まぁ交換できないのだけれど。

使用感で言えば支点と作用点間の距離が近づくと力が必要になるダイビングボード方式よりも、板全体が横滑りする Haptic Feedback の方が断然良い。 とても良いテクノロジーだとは思うし、長年使っているので愛着もあるのだが、それにしても、こんなことがあって改めて Haptic Feedback とは迂遠なテクノロジーだと思わされた。

我々はわざわざ電力を消費してクリック感をご提供いただいているんだよ。 それを起こすための物理的な力は今でも変わらず与えているはずなんだけどな。 力を感知してクリックだと判断して電力を消費してクリック感を再現しているんだ。 おい最初の力を感知するところの力、どうにか使えないのか。 頭がどうにかなりそうだ。