Archive for 2月, 2013

2013/02/28 Safariでさくらインターネットのサーバーホスティング管理画面にログインしてディスク使用量を取得する

Safariでさくらインターネットのサーバーホスティングの管理画面にログインして、ディスク使用量を取得して、計算を行い、計算内容をダイアログに表示するAppleScriptです。Safari 6.0.3+OS X 10.8.2で動作検証しています。

Webコンテンツに対してDOMアクセス……だけでなく、GUI Scripting経由でもコントロールしています(面倒だったので)。そのため、実行前にシステム環境設定の「アクセシビリティ」で「補助装置にアクセスできるようにする」にチェックを入れておく必要があります。

sakura1.png

この管理画面をオープンして、プログラム中にユーザー名とパスワード(適宜、ご自分の契約しているアカウントの情報を設定してください)を書いておいて(このあたり、池袋の喫茶店で奥方様と待ち合わせをしている間に書いたのでいいかげん。実際には、パスワードを入力させるようにして、キーチェーンから設定情報を取得するようにすべき)実行すると、管理画面にログインしてディスク使用量を取得して計算してクリップボードに計算データを転送したのち、計算式をダイアログ表示します。

昔作ったページのローディング待ちサブルーチンを引っ張り出してきましたが、いまひとつ期待したとおりに動いていない感じがします。そのため、ページローディング待ちをdelay文で時間待ちしてごまかしている状態で、インターネット接続回線の太さを考慮してdelayの数値を増減させてください。ちなみに、掲載リストは有線LANでつないでいる場合の(自分の)設定値です。

sakura2.png

いったん管理画面にログインしたのちに本Scriptを実行すると、一定時間はログイン動作が継続されていますので、何の因果かこのScriptを連続操作するような場合には明示的に「ログアウト」の操作を行ってください。

スクリプト名:Safariで管理画面にログインしてディスク使用量を取得する
set aUsername to “username” –ユーザー名(ドメイン名)
set aPassword to “password” —パスワード

–さくらインターネットのインターネットサーバコントロールパネルのログイン画面
set serverAdminURL to “https://secure.sakura.ad.jp/rscontrol/ms/”

tell application “Safari”
  activate
  
close every window
  
  
open location serverAdminURL
  
  
  
–ページのローディングを待つ
  
delay 2 –適当に変更してください
  
  
set pRes to page_loaded(30) of me
  
if pRes = false then
    display dialog “ページローディングエラー” buttons {“OK”} default button 1
    
return
  end if
  
  
do JavaScript “document.forms[0].elements[’domain’].value=’” & aUsername & “‘” in document 1
  
do JavaScript “document.forms[0].elements[’password’].value=’” & aPassword & “‘” in document 1
  
end tell

–送信ボタンを押してログイン
set cRes to clickSend() of me
if cRes = false then
  display dialog “ページローディングエラー” buttons {“OK”} default button 1
  
return
end if

delay 2 –適当に変更してください

set pRes to page_loaded(30) of me
if pRes = false then
  display dialog “ページローディングエラー” buttons {“OK”} default button 1
  
return
end if

activate application “Safari”
tell application “System Events”
  tell process “Safari”
    –GUI Scripting経由で管理画面の所定の情報を取得する(使用ディスク容量)
    
set a to value of static text 1 of group 8 of UI element 1 of scroll area 1 of group 1 of group 1 of group 2 of window 1 –Web/Mail
    
set b to value of static text 1 of group 10 of UI element 1 of scroll area 1 of group 1 of group 1 of group 2 of window 1 –Database
  end tell
end tell

–ここから下、作っておいた「クリップボードに入っている複数行の数字を足してクリップボードに転送」Scriptをほぼ使い回し

set aList to {a, b}
set outList to {}

repeat with i in aList
  set outItem to “”
  
  
set j to contents of i
  
  
set outItem to retNumChar(j) of me
  
  
if outItem is not equal to “” then
    set the end of outList to outItem
  end if
  
end repeat

if outList = {} then
  display dialog “何も計算する内容はありません” buttons {“OK”} default button 1
  
return
end if

set aSum to 0
repeat with i in outList
  set aSum to aSum + i
end repeat

set dispStr to retArrowText(outList, “ + ”) of me & ” = “ & (aSum as string)
set the clipboard to (aSum as string)

tell application “Safari”
  display dialog dispStr buttons {“OK”} default button 1
end tell

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on retNumChar(testText)
  –AN文字列
  
set ankChar to {“0″, “1″, “2″, “3″, “4″, “5″, “6″, “7″, “8″, “9″, “.”}
  
  
set _testChar to characters of (testText as Unicode text)
  
set outStr to “”
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is in ankChar then
        set outStr to outStr & j
      end if
    end repeat
  end ignoring
  
  
return outStr
end retNumChar

on getTitleOfURL(aURL)
  tell application “Safari”
    if not (exists document 1) then
      make new document at the beginning of documents
    end if
    
set the URL of the front document to aURL –ローカルあるいはインターネット上のURL
    
    
page_loaded(10) of me
    
set a to do JavaScript “document.title” in document 1
    
return a
  end tell
end getTitleOfURL

on page_loaded(timeout_value)
  delay 2
  
repeat with i from 1 to the timeout_value
    tell application “Safari”
      if (do JavaScript “document.readyState” in document 1) is “complete” then
        return true
      else if i is the timeout_value then
        return false
      else
        delay 1
      end if
    end tell
  end repeat
  
return false
end page_loaded

–フォームの送信ボタンを押す
on clickSend()
  activate application “Safari”
  
tell application “System Events”
    tell process “Safari”
      try
        click button 1 of UI element 1 of row 3 of table 1 of UI element 1 of scroll area 1 of group 1 of group 1 of group 2 of window 1
        
return true
      on error
        return false
      end try
    end tell
  end tell
end clickSend

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/28 クリップボードに入っている複数行の数字を足してクリップボードに転送

毎日やっている、雑多な作業をAppleScriptでちょっとだけ便利にしてみました。

Webホスティングサービスの管理画面で、HDD使用量の数値を電卓で加算して増減値を記録していたのですが、計算するのが面倒なために……AppleScriptで(ちょっとだけ)楽にしてみました。

管理画面で容量まわりのところを選択してコピーして……

safari1.png

本AppleScriptを実行すると、コピー内容(クリップボード内容)から数字以外の文字を除去して、行ごとに数値として評価して加算します。

加算した結果をクリップボードに入れて、計算内容をダイアログで表示します。

safari2.png

本当は、Webブラウザを起動して指定のURLをオープンして、ユーザー名とパスワードを自動入力し、管理画面に移行したら指定のDOMに該当する要素を取得して計算してWebブラウザをクローズする……という処理にしたかったのですが、そこまでやる時間がなかったのが……技術的には難しくないだけに残念です(該当ノードのDOMのパスの調査がめんどくさい。SafariのWebインスペクタでさくっと調べられるといいのに、、、)。

スクリプト名:クリップボードに入っている複数行の数字を足してクリップボードに転送
set aText to the clipboard
set aList to paragraphs of aText

set outList to {}

repeat with i in aList
  set outItem to “”
  
  
set j to contents of i
  
  
set outItem to retNumChar(j) of me
  
  
if outItem is not equal to “” then
    set the end of outList to outItem
  end if
  
end repeat

if outList = {} then
  display dialog “何も計算する内容はありません” buttons {“OK”} default button 1
  
return
end if

set aSum to 0
repeat with i in outList
  set aSum to aSum + i
end repeat

set dispStr to retArrowText(outList, “ + ”) of me & ” = “ & (aSum as string)
set the clipboard to (aSum as string)

display dialog dispStr buttons {“OK”} default button 1

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on retNumChar(testText)
  –AN文字列
  
set ankChar to {“0″, “1″, “2″, “3″, “4″, “5″, “6″, “7″, “8″, “9″, “.”}
  
  
set _testChar to characters of (testText as Unicode text)
  
set outStr to “”
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is in ankChar then
        set outStr to outStr & j
      end if
    end repeat
  end ignoring
  
  
return outStr
end retNumChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 リストを任意のデリミタ付きでテキストに v2

リストに入っているデータ(例:{”hiyoko”, “Unagi”, “Fujiyama”, “Kobe Beef”})を指定デリミタ(区切り文字)を間に入れつつ、テキストにするサブルーチンです。

ほぼ、本Blogがスタートした当初に掲載したたぐいのサブルーチンであり、使用頻度もきわめて高いものですが……最初に掲載したスタイルがよろしくなく、Blogから検索してリスト下部にある「AppleScriptリンク」(けっこう知らない人がいるらしい)をクリックしてAppleScriptエディタに転送するたびに、「なんでこんな仕様にしたんだ?」とぼやきつつ、毎回もれなく書き換えて使っていました。

書き換えたバージョンは多数のAppleScriptのプログラムに使ってはいるものの、キーワード検索するとコレがいちいちヒットしてくるので、面倒でたまりません。

そこで、仕方なく書き換えたものを掲載しておくことにしました。

スクリプト名:リストを任意のデリミタ付きでテキストに v2
set aList to {1, 2, 3, 4}
retArrowText(aList, “->”) of me
–> “1->2->3->4″

retArrowText(aList, ASCII character 10) of me
–>
(*
“1
2
3
4″
*)

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v5

ルールにのっとったコード全生成サブルーチン v4の改良版です。このv5でひとまずの完成を見ています。

本バージョンでは、コードルールから「初期値」を求める機能を追加し、これでルールのリストだけ与えれば、該当するすべてのパターンのコードを生成できるようになりました。

こうして、最初のv1から見直してみると……ずいぶんとコンパクトになりました。当初は持っていなかった汎用性を獲得し、だいたいこんな感じではないか、という自己満足に到達することはできました。

もっと難しいかと思っていたのですが、段階的に進化させていくことで「あっけなくできた」感じがします。最初から高機能なものを作ろうとせずに、動作が確認できる程度の簡単なものを作って、徐々に機能を向上させていくというやりかたは、実に強力です。

スクリプト名:指定のコード体系の全パターンのコードを生成 v5
–v5 外部からプロパティで与えられたルールから、初期値となる「最小値」を自前で計算するように変更
–v4 桁ごとにサブルーチンを設けるのではなく、再帰処理で1つのルーチンを多重呼び出しするように変更
–v3 コードのルールを外部供給する構成にした(処理ロジックとルールの分離が完了)
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}} –各桁の{最小値, 最大値}ペアのリスト
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {} –initilaize

set initNum to getMinNum() of me –本ルール下における最小値

set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit(aNum, 1) of me
  
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–与えられたルール下における最小値をルールリストから求める
on getMinNum()
  –桁数が合っているだけのダミー数字を、適切な桁数作成する(例:11111)
  
set tmpNumStr to “”
  
repeat (aRuleLen of spd) times
    set tmpNumStr to tmpNumStr & “1″
  end repeat
  
  
set tmpNum to tmpNumStr as integer
  
  
–ルールから各桁の最小値を取り出して、各桁に設定する
  
repeat with i from 1 to (aRuleLen of spd)
    set aDigNum to item 1 of item i of (aRuleList of spd)
    
set tmpNum to setDigit(tmpNum, i, aDigNum) of me
  end repeat
  
  
return tmpNum
  
end getMinNum

–繰り上がり処理(再帰呼び出しで使用)
on incDigit(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    
    
if aDigit = (aRuleLen of spd) then
      –オーバーフロー(桁あふれ)エラーを返す
      
return false
    end if
    
    
set bNum to incDigit(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
    
  else
    
    
set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
    
  end if
  
  
return bNum
  
end incDigit

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v4

ルールにのっとったコード全生成サブルーチン v3の改良版です。このバージョンでは、これまで各桁ごとに専用のサブルーチンを設けて使っていたところを、全桁共通サブルーチンとして、コードの桁数を変更可能にしました。

いちおう、目指していた機能はすべて実現できた「完成版」といえます。

ただ……実際に作ってみないと気付かない点はあるもので、このプログラム……ルールで与えたコード体系の「最小値」を初期値として与えてあげないとダメなのですが、これを人間がパラメータとして書いてあげる必要があります。これはいただけません。

この初期値をルールから自動で生成するようにして、はじめてルールとロジックの分離が完了するといえるでしょう。

スクリプト名:指定のコード体系の全パターンのコードを生成 v4
–v4 桁ごとにサブルーチンを設けるのではなく、再帰処理で1つのルーチンを多重呼び出しするように変更
–v3 コードのルールを外部供給する構成にした(処理ロジックとルールの分離が完了)
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}} –各桁の{最小値, 最大値}ペアのリスト
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {}
set initNum to 11011 –本ルール下における最小値。この値も本来は計算から求めるべき
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit(aNum, 1) of me
  
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–繰り上がり処理(再帰呼び出しで使用)
on incDigit(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    
    
if aDigit = (aRuleLen of spd) then
      –オーバーフロー(桁あふれ)エラーを返す
      
return false
    end if
    
    
set bNum to incDigit(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
    
  else
    
    
set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
    
  end if
  
  
return bNum
  
end incDigit

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v3

ルールにのっとったコード全生成サブルーチン v2の改良版です。このバージョンでは、処理ロジックとデータの分離が完了しています。

プロパティに {最小値, 最大値} のペアを桁数分だけ書いておくと、そのルールにもとづいて数値コードを生成します。この最小値/最大値には1桁の数値を指定することを想定しています。

このあたり……前提条件を無視して2桁以上の数値を指定したりすると、正しく動作しないと思います。また、10進数専用で考えています。このあたりの前提条件はこのコード生成シリーズで共通の仕様です。

スクリプト名:指定のコード体系の全パターンのコードを生成 v3
–v3 コードのルールを外部供給する構成にした(処理ロジックとルールの分離が完了)
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}}
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {}
set initNum to 11011
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit1(aNum, 1) of me
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–1桁目の繰り上がり処理
on incDigit1(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit2(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit1

–2桁目の繰り上がり処理
on incDigit2(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit3(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit2

–3桁目の繰り上がり処理
on incDigit3(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit4(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit3

–4桁目の繰り上がり処理
on incDigit4(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit5(aNum, aDigit + 1) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, aDigit, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit4

–5桁目の繰り上がり処理
on incDigit5(aNum, aDigit)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - aDigit + 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, aDigit) of me
  
  
if aTarget = thisMax then
    –ここでfalseを返すとこれ以下の桁でもすべてfalseを返し、処理終了とみなす。大事な処理
    
return false
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, aDigit, aTarget) of me
  end if
  
  
return bNum
  
end incDigit5

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v2

ルールにのっとったコード全生成サブルーチン v1の改良版です。まずは、処理ロジックとルールの分離をテストする意味で、ルールの書き方をテストし、各サブルーチンから参照できているかどうか、テストを行いました。

ここまで書いてみると、各桁のインクリメントを受け持つサブルーチンを共通化できそうな感じがしてきました。最初から、その方向に進化させるつもりで書き出したものですが、これならいけそうだという感触を得るには実際に書いてみないと。

スクリプト名:指定のコード体系の全パターンのコードを生成 v2
–v2 各桁の最大値と最小値をプロパティで持たせるテスト
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
  
property aRuleList : {{1, 2}, {1, 3}, {0, 1}, {1, 4}, {1, 8}}
  
property aRuleLen : length of aRuleList
end script

set aList of spd to {}
set initNum to 11011
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit1(aNum) of me
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–1桁目の繰り上がり処理
on incDigit1(aNum)
  
  
set {thisMin, thisMax} to item (aRuleLen of spd) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 1) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit2(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 1, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 1, aTarget) of me
  end if
  
  
return bNum
  
end incDigit1

–2桁目の繰り上がり処理
on incDigit2(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 1) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 2) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit3(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 2, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 2, aTarget) of me
  end if
  
  
return bNum
  
end incDigit2

–3桁目の繰り上がり処理
on incDigit3(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 2) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 3) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit4(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 3, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 3, aTarget) of me
  end if
  
  
return bNum
  
end incDigit3

–4桁目の繰り上がり処理
on incDigit4(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 3) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 4) of me
  
  
if aTarget = thisMax then
    set bNum to incDigit5(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 4, thisMin) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 4, aTarget) of me
  end if
  
  
return bNum
  
end incDigit4

–5桁目の繰り上がり処理
on incDigit5(aNum)
  
  
set {thisMin, thisMax} to item ((aRuleLen of spd) - 4) of (aRuleList of spd)
  
  
set aTarget to getDigit(aNum, 5) of me
  
  
if aTarget = thisMax then
    –ここでfalseを返すとこれ以下の桁でもすべてfalseを返し、処理終了とみなす。大事な処理
    
return false
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 5, aTarget) of me
  end if
  
  
return bNum
  
end incDigit5

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/27 指定のコード体系の全パターンのコードを生成 v1

製品コードやテストパターンを反映させたファイル名を作成するような場合に、ルールに基づいてコードチェックをするようなAppleScriptのサブルーチンは作っていました。

→ コードのチェック
→ 簡易マクロ展開つきのコードチェック v1

とりあえず、何も考えずに当該桁数の数値を(数十万個とか)すべて作成しておいて、ルールに合致するものだけをフィルタリングして残す……みたいな、あまり考えずにマシンパワーに依存して「ルールに基づいたコードの全生成」をやっていたのですが、いつも恥ずかしく思っていました。

そこで、ルールに基づいたコード(だけ)を全パターン生成するサブルーチンを作ることを決意。

最初に、各桁のコード生成ルールを各桁ごとの専用のサブルーチンで扱うようにして、繰り上がりが発生したら上位桁のインクリメント(+1)ルーチンを呼ぶようにしてみました。

きちんと、目的を達してくれますし……後に登場する高機能ルーチンよりも高速です(とはいえ、みんな実行に1秒もかかっていないのですが)。想定しているパターンのコード番号をすべて生成してくれます。

生成例:
–> {11011, 11012, 11013, 11014, 11015, 11016, 11017, 11018, 11021, 11022, 11023, 11024, 11025, 11026, 11027, 11028, 11031, 11032, 11033, 11034, 11035, 11036, 11037, 11038, 11041, 11042, 11043, 11044, 11045, 11046, 11047, 11048, 11111, 11112, 11113, 11114, 11115, 11116, 11117, 11118, 11121, 11122, 11123, 11124, 11125, 11126, 11127, 11128, 11131, 11132, 11133, 11134, 11135, 11136, 11137, 11138, 11141, 11142, 11143, 11144, 11145, 11146, 11147, 11148, 12011, 12012, 12013, 12014, 12015, 12016, 12017, 12018, 12021, 12022, 12023, 12024, 12025, 12026, 12027, 12028, 12031, 12032, 12033, 12034, 12035, 12036, 12037, 12038, 12041, 12042, 12043, 12044, 12045, 12046, 12047, 12048, 12111, 12112, 12113, 12114, 12115, 12116, 12117, 12118, 12121, 12122, 12123, 12124, 12125, 12126, 12127, 12128, 12131, 12132, 12133, 12134, 12135, 12136, 12137, 12138, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 13011, 13012, 13013, 13014, 13015, 13016, 13017, 13018, 13021, 13022, 13023, 13024, 13025, 13026, 13027, 13028, 13031, 13032, 13033, 13034, 13035, 13036, 13037, 13038, 13041, 13042, 13043, 13044, 13045, 13046, 13047, 13048, 13111, 13112, 13113, 13114, 13115, 13116, 13117, 13118, 13121, 13122, 13123, 13124, 13125, 13126, 13127, 13128, 13131, 13132, 13133, 13134, 13135, 13136, 13137, 13138, 13141, 13142, 13143, 13144, 13145, 13146, 13147, 13148, 21011, 21012, 21013, 21014, 21015, 21016, 21017, 21018, 21021, 21022, 21023, 21024, 21025, 21026, 21027, 21028, 21031, 21032, 21033, 21034, 21035, 21036, 21037, 21038, 21041, 21042, 21043, 21044, 21045, 21046, 21047, 21048, 21111, 21112, 21113, 21114, 21115, 21116, 21117, 21118, 21121, 21122, 21123, 21124, 21125, 21126, 21127, 21128, 21131, 21132, 21133, 21134, 21135, 21136, 21137, 21138, 21141, 21142, 21143, 21144, 21145, 21146, 21147, 21148, 22011, 22012, 22013, 22014, 22015, 22016, 22017, 22018, 22021, 22022, 22023, 22024, 22025, 22026, 22027, 22028, 22031, 22032, 22033, 22034, 22035, 22036, 22037, 22038, 22041, 22042, 22043, 22044, 22045, 22046, 22047, 22048, 22111, 22112, 22113, 22114, 22115, 22116, 22117, 22118, 22121, 22122, 22123, 22124, 22125, 22126, 22127, 22128, 22131, 22132, 22133, 22134, 22135, 22136, 22137, 22138, 22141, 22142, 22143, 22144, 22145, 22146, 22147, 22148, 23011, 23012, 23013, 23014, 23015, 23016, 23017, 23018, 23021, 23022, 23023, 23024, 23025, 23026, 23027, 23028, 23031, 23032, 23033, 23034, 23035, 23036, 23037, 23038, 23041, 23042, 23043, 23044, 23045, 23046, 23047, 23048, 23111, 23112, 23113, 23114, 23115, 23116, 23117, 23118, 23121, 23122, 23123, 23124, 23125, 23126, 23127, 23128, 23131, 23132, 23133, 23134, 23135, 23136, 23137, 23138, 23141, 23142, 23143, 23144, 23145, 23146, 23147, 23148}

ただ、このままだとぜんぜん汎用性がないので……このレベルに安住していてはいけません。

スクリプト名:指定のコード体系の全パターンのコードを生成 v1
–v1 各桁のインクリメント用のサブルーチンを作成し、ルールを各サブルーチン側でハードコーディングする(正しく動く)

script spd
  property aList : {}
end script

set aList of spd to {}
set initNum to 11011
set the end of aList of spd to initNum

copy initNum to aNum

repeat
  set aRes to incDigit1(aNum) of me
  
if aRes = false then
    exit repeat
  end if
  
  
set the end of aList of spd to aRes
  
  
copy aRes to aNum
  
end repeat

return (aList of spd)

–1桁目の繰り上がり処理
on incDigit1(aNum)
  
  
set aTarget to getDigit(aNum, 1) of me
  
  
if aTarget = 8 then
    set bNum to incDigit2(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 1, 1) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 1, aTarget) of me
  end if
  
  
return bNum
  
end incDigit1

–2桁目の繰り上がり処理
on incDigit2(aNum)
  
  
set aTarget to getDigit(aNum, 2) of me
  
  
if aTarget = 4 then
    set bNum to incDigit3(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 2, 1) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 2, aTarget) of me
  end if
  
  
return bNum
  
end incDigit2

–3桁目の繰り上がり処理
on incDigit3(aNum)
  
  
set aTarget to getDigit(aNum, 3) of me
  
  
if aTarget = 1 then
    set bNum to incDigit4(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 3, 0) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 3, aTarget) of me
  end if
  
  
return bNum
  
end incDigit3

–4桁目の繰り上がり処理
on incDigit4(aNum)
  
  
set aTarget to getDigit(aNum, 4) of me
  
  
if aTarget = 3 then
    set bNum to incDigit5(aNum) of me
    
    
if bNum = false then return false
    
    
set bNum to setDigit(bNum, 4, 1) of me
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 4, aTarget) of me
  end if
  
  
return bNum
  
end incDigit4

–5桁目の繰り上がり処理
on incDigit5(aNum)
  
  
set aTarget to getDigit(aNum, 5) of me
  
  
if aTarget = 2 then
    –ここでfalseを返すとこれ以下の桁でもすべてfalseを返し、処理終了とみなす。大事な処理
    
return false
  else
    set aTarget to aTarget + 1
    
set bNum to setDigit(aNum, 5, aTarget) of me
  end if
  
  
return bNum
  
end incDigit5

–指定数値のうち指定桁の数字を返す
on getDigit(aNum, aDigit)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set tStr to character (aLen - aDigit + 1) of aStr
  
return tStr as integer
  
end getDigit

–指定数値のうち指定桁の数字を返す
on setDigit(aNum, aDigit, newNum)
  
  
set aStr to aNum as string
  
set aLen to length of aStr
  
if aLen < aDigit then
    return false –エラー
  end if
  
  
set aList to characters of aStr
  
  
set item (aLen - aDigit + 1) of aList to (newNum as string)
  
set aaStr to aList as string
  
  
return aaStr as integer
  
end setDigit

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/23 iOSアプリ「iBooks」に謎のsdefファイルが見つかった

Twitterで、

sdef1.png

という情報があったので、以前作っておいた「iOSアプリの内容をすべて展開する」AppleScriptでApple純正のiOSアプリのうちAppStoreからダウンロード可能なもの(iTunesにダウンロードしてこれるもの)をテストしてみました。

sdef10.png

sdef11.png

すると、iBooks.appにのみsdef(AppleScript命令定義)ファイルが存在していました。

sdef2.png

OS X 10.8上で、このsdefファイルをAppleScriptエディタにドラッグ&ドロップしてオープンしてみると……

sdef3.png

普通にひらけます。「ユーザーをからかうための、Appleエンジニアのジョーク」という線も考えられないではないですが、存在することは事実です。

iBooksはiBooks.appであり、MobileStore.appではありません。このMobileStore.appというのは……Googleで検索してみると、iOS上のiTunes Music Store.appのことであり、iTunes Music Store.appの中にMobileStore.sdefファイルが含まれているという情報が大量に見つかりました。

一体なぜ? いろいろ考えてしまうものですが、リリース前のテスト用だけに使っている可能性もあるので、「これで(リリース版の)iOSでAppleScriptが使えるようになるに違いない」といった証拠にはならないと思います。

以前に、某カリフォルニアの企業がiOSのテスティングエンジニアの求人条件に「AppleScriptが使えること」という採用条件を出していたので、リリース前OSやアプリの動作テスト用にAppleScriptを使っているのかもしれない、と思っていました。

先日AppleStore, Ginzaの店頭でiPadのデモンストレーションプログラムを眺めていたところ、通常のプリインストールされているアプリケーションを自動で動かしまくっていて、しかもそれがムービーに見えなかったので、案外デモ用にそうした自動操作機能が用意されているのかもしれない、などとも考えないではないです。

いずれにしても、2つのApple製アプリにsdefファイルが入っている以上の、確たる証拠はありません。

2013/02/21 指定フォルダ中のファイル名が拡張子を外すと衝突するかどうかチェック

指定フォルダ中のファイルから拡張子を外した状態で名称が衝突するかどうかチェックするAppleScriptです。

あるフォルダ(InDesign書類のパッケージ化したフォルダ中にあるLinksフォルダ)の中に入っている雑多な画像ファイル(EPSとかPhotoshopとかIllustrator書類とかいろいろ)をすべてJPEG画像に書き出すプログラムをさくっと作った……まではよかったのですが、処理を行うとエラー表示も出ないのに処理前の画像数と処理後の画像数が合わないという状態に。

さっそく、フォルダ内のファイル名一覧を取得して、Excelのシート上にペーストして見比べて……………「ファイル名が同じで拡張子だけが違う」というやっかいなファイルが存在していることに(自分以外の人が)気付きました。

folder1.png

前述の「処理前のファイル数と処理後のファイル数が合わない」という問題は、拡張子の部分以外のファイル名が重複しているファイルの両方ともが順次JPEGに変換されて、上書きされて先に処理したファイルが消されたために生じたものでした。

対処方法は「処理前に検出する」ことと「ファイルを書き込むときに迂回処理を行う」ことの2つ。

……簡単そうなのは前者だったので、作ってみたら割とすごいことに。すでにどこかで使ったルーチンのオンパレードですが、それなりの長さに。

# ファイル名の衝突迂回プログラムは実は作ってあったのですが……その存在を忘れていました。OS側がやっているのと同じく、存在確認しつつファイル名に子番号を(インクリメンタルに)付けていくというものです

指定フォルダ内のファイル名一覧を取得し、全ファイル名から拡張子を外した名称リストを作成。名称リスト内で重複がないかどうかをチェックします。

重複が存在していた場合には、

folder2.png

のように、どのファイルの組み合わせに問題があるかを一覧表示して終了します。

スクリプト名:指定フォルダ中のファイル名が拡張子を外すと衝突するかどうかチェック
set aFol to choose folder with prompt “フォルダを選択してください。”

set aFolStr to aFol as string

tell application “Finder”
  tell folder aFolStr
    set aList to name of every file
  end tell
end tell

–指定フォルダ内のファイル名の(拡張子を外した部分の)衝突判定を行う
set aRes to chkFileNameDuplicatesWithoutExtension(aList) of detectDupKit
if aRes is not equal to {} then
  
  
set dupList to {}
  
  
repeat with i in aRes
    set j to contents of i
    
tell application “Finder”
      tell folder aFolStr
        set aList to (name of every file whose name begins with j)
      end tell
    end tell
    
    
set the end of dupList to aList
    
  end repeat
  
  
set dup2List to FlattenList(dupList) of me
  
set firstItem to contents of first item of dup2List
  
choose from list dup2List default items {firstItem} with prompt “指定フォルダ中の以下のファイルは拡張子以外が同じため、後の処理でファイル名の衝突が起こります。
  
あらかじめどちらか一方を削除するか、片方の名前を変更するなどしておいてください。” with title “ファイル名の重複エラー”
  
  
return –終了
  
end if

script detectDupKit
  
  
–ファイル名リストをリスト型変数で渡すと、拡張子を外した名前で重複検出を行う
  
on chkFileNameDuplicatesWithoutExtension(aList)
    –拡張子を外す  
    
set aNList to {}
    
repeat with i in aList
      set j to contents of i
      
set the end of aNList to retFileNameWithoutExt(j) of me
    end repeat
    
    
–重複検出
    
set dupList to detectDuplicates(aNList) of me
    
if dupList = {} then return {}
    
    
–重複情報を単純なリストにして返す
    
set d2List to {}
    
repeat with i in dupList
      set j to contents of first item of i
      
set the end of d2List to j
    end repeat
    
    
return d2List
    
  end chkFileNameDuplicatesWithoutExtension
  
  
on removeDuplicates(aList)
    set newList to {}
    
repeat with i from 1 to (length of aList)
      set anItem to item 1 of aList
      
set aList to rest of aList
      
if {anItem} is not in aList then set end of newList to anItem
    end repeat
    
return newList
  end removeDuplicates
  
  
–ファイル名から拡張子を外す
  
on retFileNameWithoutExt(fileNameStr)
    set fLen to length of fileNameStr
    
set revText to (reverse of (characters of fileNameStr)) as string –逆順テキストを作成
    
set anOffset to offset of “.” in revText
    
set fRes to text 1 thru (fLen - anOffset) of fileNameStr
    
return fRes
  end retFileNameWithoutExt
  
end script

–与えられたリストの中で重複しているものをピックアップ。アルファベットの大文字小文字の違いを無視
on detectDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set tmpList to {}
    
    
–あえてアルファベットの大文字小文字の違いを無視(というよりも、同一視)
    
ignoring case
      set anItem to item 1 of aList
      
set aList to rest of aList
      
if {anItem} is in aList then set end of tmpList to anItem
      
repeat with j in aList
        set jj to contents of j
        
if jj = anItem then
          set end of tmpList to jj
          
exit repeat –重複は基本的にABC-abcのように1対のみという前提。フォルダ名の衝突回避が目的なので
        end if
      end repeat
    end ignoring
    
    
if tmpList is not equal to {} then
      set the end of newList to tmpList
    end if
  end repeat
  
return newList
end detectDuplicates

–By Paul Berkowitz
–2009年1月27日 2:24:08:JST
–Re: Flattening Nested Lists
on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {“????”}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/20 ログファイルから時間帯ごとの度数分布を計算

ログファイルから日時のフィールドのみテキストに書き出し、各時ごとに度数分布を計算するAppleScriptです。ログの集計を行うために、即興で作りました。

UTF-8で改行コードがCRのデータを処理しました。実際のログの内容は、こんな感じです。

2013-02-05 06:28:55
2013-02-05 06:30:04
2013-02-05 06:42:51
2013-02-05 06:53:54
2013-02-05 06:54:04

とくに見るべき点(技術的にスゴい点)はないですが、度数分布の集計はありがちな処理なので、活躍する場面は多いことでしょう。

ちなみに、1万7,000行ぐらいのテキストを度数分布処理するのに、MacBook Pro Retina 15インチ(2.66GHz Core i7)で14秒です。

スクリプト名:時間帯ごとの度数分布を計算
script spd
  property dList : {}
  
property c : {}
  
property b : “”
end script

set c of spd to {}
set b of spd to {}

set dList of spd to {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

set a to choose file

set b of spd to read a
set c of spd to paragraphs of b of spd

repeat with i in c of spd
  
  
set j to contents of i
  
  
if j is not equal to “” then
    set aDate to date j
    
    
set aH to hours of aDate
    
set aH to aH + 1
    
    
set aTmp to contents of item aH of dList of spd
    
set aTmp to aTmp + 1
    
    
set item aH of dList of spd to aTmp
    
  end if
  
end repeat

dList of spd

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/16 AppleScriptObjCとメモリ管理

「AppleScriptObjCのプロジェクトではGarbage Collection必須」などといいながら、先週書いたあとに「本当か?」と思い直し(思い当たるフシが多々あり)、自分で掲載していたサンプルを調べてみたら、どこにもGCの設定が…………ありません(^ー^;;;。

macosxautomation.comの記事を調べたら、すぐさまShane Stanleyによる「Garbage Collection, ARC, and managing memory」なる記事に行き当たりました。

結論からいえば、10.8上ではGCの設定は必要なし。ただし、ビルドしたアプリケーションの10.6/10.7上での動作の互換性を保つためには、GCの設定が必要。GCの設定をしないと盛大にメモリリークする、といった話でした。

asoc_memory.png

実際に、仕事でAppleScriptObjCとObjective-Cの混成プロジェクトをObjCの開発者とチームを組んで作っていますが、10.6/10.7との互換性維持のためこちらはGC設定ありでビルドしています。

2013/02/11 AppleScriptObjCでMyriad Helpersの三角関数を使ってWindowを円運動

AppleScriptObjCで、三角関数を使ってWindowを円運動させるサンプルです。

三角関数を使ってWindowを円軌道(純粋な円運動だと見栄えがしないので楕円にしていますが)で動かすという、きわめて基礎的な処理です。

curculwin.png

Objective-Cのプログラム内ではsin/cos/tanを使えるものの、AppleScriptObjCプログラム内ではこれらの関数は使えません。

Shane StanleyによるAppleScriptObjCのバイブル「AppleScriptObjC Explored」に、AppleScriptObjCから使うと便利な……逆をいえばAppleScriptObjCの弱点を補うためのObjective-Cのコード「Myriad Helpers」が含まれています。dateの変換や取得、alias→URL変換、そしてこの三角関数(sin/cos/tan/asin/acos/atan/sinh/cosh/tanh/asinh/acosh/atanh/log/log10)の呼び出しなどがそれです。

この「Myriad Helpers」のv2.0がmacosxautomation.comのサイト上からダウンロードできるようになっています

Sal SoghoianとShane Stanleyの合作によるとおぼしきこのAppleScript情報サイト「macosxautomation.com」、本来「AppleScriptObjC Explored」を買わないと入手できない「Myriad Helpers」をなぜフリーでダウンロードできるようにしてあるのか、どういう取引が2者の間で行われたかをいろいろ考えてしまうものですが……フリーで配布しているので、これを使ったサンプルプロジェクトを公開しても問題はないということに。

興味深いのは、この「Myriad Helpers v2.0」がgarbage-collectedなプロジェクトでもAutomatic Reference Countingが有効になっているプロジェクトに組み込んでもビルドできること(正確にいえば、それをわざわざ明記してあること)。

次のOS X 10.9で提供されるAppleScriptObjCの処理系はAutomatic Reference Countingが有効になっているプロジェクトが前提になるだろう、ということが伺われます。ただ、Mac OS X 10.6までさかのぼってその変更が反映されるかどうか……といったところでしょうか。実際問題、AppleScriptObJCのプロジェクトにさまざまなObjective-Cのプログラムを突っ込んで利用するような場合に、garbage-collectedな設定でビルドできないフレームワークなどもあったりして、解決してほしい問題の筆頭であることも事実です。

最初のサンプルは、clicked_ハンドラで連続してウィンドウを円運動させるもの。ウィンドウ上のテキストフィールド上に入れた数値を半径とした円運動を行わせます。ただし、1回だけ。

 Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– circulateWin

– Created by Takaaki Naganoya on 2013/02/11.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property aWin : missing value
  
  property ObjWithF : missing value
  
property aStrF : missing value
  
  on applicationWillFinishLaunching_(aNotification)
    – Insert code here to initialize your application before any files are opened
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  on clicked_(sender)
    
    –set {origin:{x:n, y:m}, |size|:{|width|:n2, height:m2}} to (aWin’s frame()) as record
    
    set aNum to aStrF’s doubleValue()
    
set aNum to aNum as number
    
    
    repeat with i from 1 to 360 by 1
      
      set aSin to ObjWithF’s fordTrig_({“sin”, i, true})
      
set aCos to ObjWithF’s fordTrig_({“cos”, i, true})
      
      set x to ((aNum * aSin) + aNum) * 2
      
set y to (aNum * aCos) + aNum
      
      aWin’s setFrame_display_animate_({{x, y}, {200, 200}}, true, true)
      
      
    end repeat
    
  end clicked_
  
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

もうひとつは、0.1秒ごとのタイマー割り込みで円運動させるもの。割り込みで処理するので、それなりのCPUパワーとそれなりのGPUを積んでいれば、マシンに対する負荷もそれほど大きくないでしょう。

 Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– circulateWin

– Created by Takaaki Naganoya on 2013/02/11.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property aWin : missing value
  
  property ObjWithF : missing value
  
property aStrF : missing value
  
  property NSTimer : class “NSTimer”
  
property aDegree : 1
  
  
  property aNum : 0
  
  on applicationWillFinishLaunching_(aNotification)
    
    set aDegree to 1
    
    
  end applicationWillFinishLaunching_
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  on clicked_(sender)
    
    –set {origin:{x:n, y:m}, |size|:{|width|:n2, height:m2}} to (aWin’s frame()) as record
    
    set aNum to aStrF’s doubleValue()
    
set aNum to aNum as number
    
    NSTimer’s scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(0.1, me, “timer1Fired:”, “Whatever”, true)
    
    
  end clicked_
  
  
  
  on timer1Fired_(sender)
    
    set aDegree to incrementDegree_(aDegree)
    
    set aSin to ObjWithF’s fordTrig_({“sin”, aDegree, true})
    
set aCos to ObjWithF’s fordTrig_({“cos”, aDegree, true})
    
    set x to ((aNum * aSin) + aNum) * 2
    
set y to (aNum * aCos) + aNum + 100
    
    aWin’s setFrame_display_animate_({{x, y}, {200, 200}}, true, true)
    
    
  end timer1Fired_
  
  
  on incrementDegree_(aDeg)
    if aDeg > 360 then
      set aDeg to 1
    else
      return (aDeg + 1)
    end if
  end incrementDegree_
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/09 AppleScriptObjCでPDFViewを使ってPDFをプレビュー(3)

AppleScriptObjCでPDFをプレビューするテストプログラムをその後進展させたものです。

1作目で、PDFのプレビューができるようになり
2作目で、表示中のPDFの選択中のページ(label)が取得できるようになり
この3作目では、PDFに設定されているリンクのクリックを無視するようになりました。

結局、PDFViewのオンラインマニュアルを端から端まで探しても、リンクの無効化などの機能は存在していないようだったので、上位クラスであるNSViewのオンラインマニュアルを探してみました。すると、

nsview1.png

のように、hitTest:でnill(false)を返せばViewへのクリックを無視できることがわかったので、以下のようにPDFViewを継承したクラスを宣言し、Interface Builder上でPDFViewのクラスをこの「clicThPDFView」に変更してみました。

→ Xcodeプロジェクトのダウンロード

AppleScriptObjCファイル名:clickThroughPDFView.applescript
script clicThPDFView
  
  property parent : class “PDFView”
  
  on hitTest_(aPoint)
    
    return false
    
  end hitTest_
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

pdfv1.png

すると……

pdfv2.png

このような、目次から各章へのリンクが張られまくっているPDFをオープンして、PDFViewで目次をクリックしても……

pdfv3.png

リンク先には飛ばなくなりました!!! PDFViewへのマウスクリックを無効化することで、PDF内のリンクが反応することを防げるようになったわけです。

ただし、以前心配していたとおり、ページ数の取得にPage(0からはじまるページ数)ではなくlabelを取得しているために、目次ページなどPDFドキュメント制作時にアラビア数字ではないページ数が割り振られている箇所では、そのようなページ数が表示されることが判明。

PDF上のリンクが反応しないようにはできたものの、ページ数の取得については依然として問題を抱えていることがわかりました。PDFのプレビューとページ数設定のUser Interfaceとして利用するためにはあと一歩の改良が必要といったところです。

2013/02/06 AppleScriptObjCでPDFViewを使ってPDFをプレビュー(2)

AppleScriptObjCでPDFをプレビューするテストプログラムをその後進展させたものです。

本コードについては、PDFのファイルを選択した後で、プレビューしつつ対象ページを選ばせて他のアプリケーション(たぶんPhotoshop)に渡してレンダリングさせる……という目論見があったものの、プレビュー対象のページの取得方法が分らずに、時間がなかったのでその時には実戦投入することをあきらめました。

そして、時間のあるときに調べてみて、選択・プレビュー中のページをなんとか取得する方法にたどり着いたので、修正してみました。

pdfprev1.png

–> “Page 0; label = 1\n media (0.0, 0.0) [612.0, 792.0]\n crop (0.0, 0.0) [612.0, 792.0]\n rot 0\n ‘A Adobe\U00ae RGB (1998) Color Imag…’\n”

pdfprev2.png

–> “Page 1; label = 2\n media (0.0, 0.0) [612.0, 792.0]\n crop (0.0, 0.0) [612.0, 792.0]\n rot 0\n ‘A Adobe RGB (1998) Color Image…’\n”

まだ、実用上は問題があります。PDFViewに表示されたPDF上のリンクが生きており、PDF書類内のリンクや外部のWebサイトに張られたリンクが反応してしまうからです。これらをDisableにしてはじめて、プレビュー/処理対象ページ選択用のUIとして使えるのですが…………。

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– pdftest2

– Created by Takaaki Naganoya on 2012/10/23.
– Copyright (c) 2012年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
property nsurl : class “NSURL”
  
property PDFDocument : class “PDFDocument”
  
  
  property pdfPreviewWin : missing value
  
property pdfView : missing value
  
property pdfThumb : missing value
  
  property pdfPageText : missing value
  
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    pdfView’s setAllowsDragging_(false)
    
pdfView’s setDelegate_(me)
    
    
    pdfThumb’s setMaximumNumberOfColumns_(2)
    
pdfThumb’s setAllowsMultipleSelection_(false)
    
    –書類が変更になった(オープンされた場合)
    
set noter1 to current application’s NSNotificationCenter’s defaultCenter()
    
noter1’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewDocumentChangedNotification, missing value)
    
    –ページが変更になった
    
set noter2 to current application’s NSNotificationCenter’s defaultCenter()
    
noter2’s addObserver_selector_name_object_(me, “pdfChange:”, current application’s PDFViewPageChangedNotification, missing value)
    
    
    –ファイルを選択
    
set aFile to choose file of type “com.adobe.pdf”
    
set aFileString to aFile as Unicode text
    
dispPDFWithHFSpath_(aFileString)
    
    
  end applicationWillFinishLaunching_
  
  
  
  –プレビューウィンドウをセンタリング(見た目以外にとくに意味なし)
  
on applicationDidFinishLaunching_(aNotification)
    
    pdfPreviewWin’s |center|()
    
  end applicationDidFinishLaunching_
  
  
  
  –HFSパスの文字列を渡すとPDFViewに表示する
  
on dispPDFWithHFSpath_(aFileString)
    
    set aFileString to aFileString as Unicode text
    
    tell application “Finder”
      set aFileURL to (URL of file aFileString)
    end tell
    
    set aFileURL to aFileURL as Unicode text
    
set theURL to nsurl’s URLWithString_(aFileURL)
    
    set aPDFdoc to PDFDocument’s alloc()’s initWithURL_(theURL) –allocわすれてた、、、
    
pdfView’s setDocument_(aPDFdoc)
    
  end dispPDFWithHFSpath_
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  (*
–PDF内のURLなどのリンクをクリックした場合の動作??? これを無視させたかったのだが、、、、
on PDFViewOpenPDF_forRemoteGoToAction_(sender)

return false

end PDFViewOpenPDF_forRemoteGoToAction_
*)

  
  –ファイルの新規オープン、および表示ページが変更になった場合にnotificationでこちらを呼び出している
  
–ここで、選択中のページのノンブルを取得したい(まだできていない)
  
on pdfChange_(sender)
    set curPage to pdfView’s currentPage
    
–set curPageNum to curPage’s indexForPage
    
    set curPage2 to pdfThumb’s selectedPages
    
    set anItem to first item of curPage2
    
    log {anItem}
    
–> “Page 0; label = 1\n media (0.0, 0.0) [612.0, 792.0]\n crop (0.0, 0.0) [612.0, 792.0]\n rot 0\n ‘A Adobe\U00ae RGB (1998) Color Imag…’\n”
    
    set bItem to label of anItem –本当はPage(0からはじまるIndex)を取得したかったのだが、できなかった。なんでだろうねぇ
    
    pdfPageText’s setStringValue_(bItem as string)
    
  end pdfChange_
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/03 MacTech Magazine 01 2013でAppleScript/AppleScriptObjC関連記事

MacTech Magazine 01 2013でAppleScript関連の記事が掲載されています。MachTech Magazineは印刷された本を購入することができるほか、iPad/iPad mini上の無料アプリでオンライン購読できます(1冊あたり450円)。

mtech1.png

今回のAppleScript関連記事は2本。

AppleScriptObjCでPreferences(初期設定)を保存する方法について解説した記事、

 「Preferences with AppleScript」

および、AppleScriptでシステム環境設定をコントロールする記事、

 「AppleScripting System Preferences」

の2本です。

2013/02/03 miで文字置換

国産テキストエディタ「mi」でAppleScript経由で文字置換を行うサンプルです。

miのAppleScript用語辞書をAppleScriptエディタでひらいて見ると、とても特徴的な内容であることが見てとれます。

miの用語辞書には、WindowやDocument、そしてその下部構造であるparagraphやwordを読み書きしたり、選択中の箇所を読み書きするためのオブジェクトしか定義されていません。コマンドの定義はほとんどありません。

mi3.png

AppleScriptをよく知らない方が、miで文字置換を行うために、GUI Scriptingで延々とメニューから置換コマンドを呼び出して置換している例を見たことがありますが、そこまで努力しても残念なことに他のMac上では動かなかったとか。ダイアログの座標などを決め打ちで指定していたので、別のマシン上では動かないのは当然のことでしょう。

miのAppleScript用語辞書からいえることは、「置換は自分でやってね」ということ。値の取り出しと格納はできるので、あとは好きに処理してほしいということです。中途半端にダメダメな用語辞書を載せて使い物になっていないXcodeなどよりも、ずっと潔いと思います。

当然、AppleScriptによる文字置換ルーチンなどは当たり前のように作って日常的に使っていますので、ただそれを使うだけです。他の言語処理系を呼び出して処理してもよいでしょう。

実際、テキストエディタでわざわざ文字置換処理を行う必要などほとんどないのですが(AppleScript単独でファイルをオープンして置換して保存すればいい)、文字コードが不明な大量のテキストファイルをオープンして決められた文字コードで保存するため「だけ」に必要だといわれます。

だとすれば、オープンソースのテキストエディタの文字コード判定部分だけもってきて、AppleScriptObjCで機能を呼び出して使えばいいんじゃないかと思うのですが……。あとは、文字コード判定を行ってくれるOSAXを見つけてきて、OSAXの命令を使ってファイルの読み書きをするとか。

mi1.png

▲実行前の状態

mi2.png

▲実行後の状態

スクリプト名:miで文字置換
script spd
  property inList : missing value
  
property outList : missing value
end script

set targStr to “ぴよ” –置換対象文字列
set repStr to “ぷよ” –置換後文字列

set inList of spd to {}
set outList of spd to {}

–最前面のドキュメントから本文を取得
tell application “mi”
  tell document 1
    set (inList of spd) to every paragraph
  end tell
end tell

–置換処理
repeat with i in (inList of spd)
  set j to contents of i
  
set jj to repChar(j, targStr, repStr) of me
  
set the end of (outList of spd) to jj
end repeat

–最前面のドキュメント本文に置換結果を戻す
tell application “mi”
  tell document 1
    set pCount to count every paragraph
    
repeat with i from 1 to pCount
      set j to content of item i of (outList of spd)
      
set content of paragraph i to j
    end repeat
  end tell
end tell

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/02 AppleScriptObjCでボタンを動的に生成(縦と横に複数作成)

AppleScriptObjCでボタンを動的に生成するプログラムの続編です。複数のボタンを横に動的に生成できるようになったら、次には縦にも連続して複数のボタンを作成したくなります。

butt3.png

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– dynaButton

– Created by Takaaki Naganoya on 2013/01/30.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class "NSObject"
  
  property aWin : missing value
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    set aCount to 1
    
repeat with ii from 0 to 400 by 40
      repeat with i from 0 to 400 by 50
        
        generateAButtonX1_Y1_X2_Y2_aTitle_aTag_(i, ii, 50, 40, aCount as string, aCount as string)
        
set aCount to aCount + 1
        
      end repeat
    end repeat
    
  end applicationWillFinishLaunching_
  
  
  –動的にボタンを生成する
  
on generateAButtonX1_Y1_X2_Y2_aTitle_aTag_(x1, y1, x2, y2, aTitle, aTag)
    
    set aButton to current application’s NSButton’s alloc()’s initWithFrame_(current application’s NSMakeRect(x1, y1, x2, y2))
    
aButton’s setButtonType_(current application’s NSRegularSquareBezelStyle)
    
aButton’s setFont_(current application’s NSFont’s fontWithName_size_("HiraMinPro-W3", 12)) –ヒラギノ明朝Pro W3
    
aButton’s setTitle_(aTitle)
    
aButton’s setAction_("clicked:")
    
–aButton’s setTarget_(me)–いらない?
    
aButton’s setTag_(aTag)
    
    –ウィンドウ上に追加
    
aWin’s contentView()’s addSubview_(aButton)
    
–aButton’s setNeedsDisplay_(true)–いらなかった
    
    set aButton to missing value
    
  end generateAButtonX1_Y1_X2_Y2_aTitle_aTag_
  
  
  
  on applicationShouldTerminate_(sender)
    return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  on clicked_(sender)
    
    set aTag to tag of sender
    
set aTag to aTag as string
    
display dialog aTag
    
  end clicked_
  
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/02 AppleScriptObjCでボタンを動的に生成(横に複数作成)

AppleScriptObjCでボタンを動的に生成するプログラムの続編です。1つのボタンを動的に生成できるようになったら、次には横に連続して複数のボタンを作成したくなります。

ここでの最大の問題は、ダイナミックに(動的に)生成したオブジェクトの後始末です。作ったあとにどうしたらよいのか? 放っておいていいのか? いろいろためしてみましたが、とりあえず放っておいてよさそうな。

butt2.png

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– dynaButton

– Created by Takaaki Naganoya on 2013/01/30.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class "NSObject"
  
  property aWin : missing value
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    set aCount to 1
    
    repeat with i from 0 to 400 by 50
      
      generateAButtonX1_Y1_X2_Y2_aTitle_aTag_(i, 0, 50, 40, aCount as string, aCount as string)
      
set aCount to aCount + 1
      
    end repeat
    
  end applicationWillFinishLaunching_
  
  
  –動的にボタンを生成する
  
on generateAButtonX1_Y1_X2_Y2_aTitle_aTag_(x1, y1, x2, y2, aTitle, aTag)
    
    set aButton to current application’s NSButton’s alloc()’s initWithFrame_(current application’s NSMakeRect(x1, y1, x2, y2))
    
aButton’s setButtonType_(current application’s NSRegularSquareBezelStyle)
    
aButton’s setFont_(current application’s NSFont’s fontWithName_size_("HiraMinPro-W3", 12)) –ヒラギノ明朝Pro W3
    
aButton’s setTitle_(aTitle)
    
aButton’s setAction_("clicked:")
    
–aButton’s setTarget_(me)–いらない?
    
aButton’s setTag_(aTag)
    
–aButton’s autoRelease()
    
    –ウィンドウ上に追加
    
aWin’s contentView()’s addSubview_(aButton)
    
–aButton’s setNeedsDisplay_(true)–いらなかった
    
    set aButton to missing value
    
  end generateAButtonX1_Y1_X2_Y2_aTitle_aTag_
  
  
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  on clicked_(sender)
    
    –display dialog "おされたよ"
    
    
    set aTag to tag of sender
    
set aTag to aTag as string
    
display dialog aTag
    
  end clicked_
  
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/02 AppleScriptObjCでボタンを動的に生成

AppleScript StudioからAppleScriptObjCに移行した際に大きな違いは、Appleからの公式ドキュメントやサンプルがほとんどなくて困ったという負の側面もありましたが、動的にオブジェクトを生成する方法が提供されている、というプラスの側面もあります。

苦労してAppleScript StudioからAppleScriptObjCに移行した(ほんとーに苦労しました)のですから、Notificationやオブジェクトの動的生成は使わないと損です。

そこで、ボタンを1つ動的に生成するというささやかなサンプルを作ってみました。このレベルは海外のwww.macscripter.netなどを参考にしつつ試行錯誤しました。

ボタンを生成して、生成したボタンからイベントを受け取れるようにできないと意味がありませんし、「どのボタンが押されたか」を識別するために、ボタンにタグを付けておく必要もあります。そして、ボタンのタイトルやら見た目・大きさの変更などひととおり行える必要があります。

butt1.png

AppleScriptObjCファイル名:AppDelegate.applescript

– AppDelegate.applescript
– dynaButton

– Created by Takaaki Naganoya on 2013/01/30.
– Copyright (c) 2013年 Takaaki Naganoya. All rights reserved.


script AppDelegate
  property parent : class “NSObject”
  
  property aWin : missing value
  
  
  on applicationWillFinishLaunching_(aNotification)
    
    –動的にボタンを生成する
    
set aButton to current application’s NSButton’s alloc()’s initWithFrame_(current application’s NSMakeRect(0, 0, 200, 64))
    
aButton’s setButtonType_(current application’s NSRegularSquareBezelStyle)
    
aButton’s setFont_(current application’s NSFont’s fontWithName_size_(“HiraMinPro-W3″, 18)) –ヒラギノ明朝Pro W3
    
aButton’s setTitle_(“ぴよ〜ぴよ〜”)
    
aButton’s setAction_(“clicked:”)
    
aButton’s setTarget_(me) –いらない?
    
aButton’s setTag_(“100″)
    
    –ウィンドウ上に追加
    
aWin’s contentView()’s addSubview_(aButton)
    
aButton’s setNeedsDisplay_(true)
    
  end applicationWillFinishLaunching_
  
  
  on applicationShouldTerminate_(sender)
    – Insert code here to do any housekeeping before your application quits
    
return current application’s NSTerminateNow
  end applicationShouldTerminate_
  
  on clicked_(sender)
    
    display dialog “おされたよ”
    
    
    set aTag to tag of sender
    
set aTag to aTag as string
    
display dialog aTag
    
  end clicked_
  
  
end script

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2013/02/02 USBメモリやネットワーク上のサーバーなどをアンマウント

USBメモリやネットワーク上のサーバーなどをアンマウントするAppleScriptです。

ファイルやディスクなどFinder上のオブジェクトに対してさまざまな操作をAppleScriptから行おうとしたら、「Finderというアプリケーション」に対して命令を出すことになります。

となると、当然のことながら「Finder」のAppleScript用語辞書を調べる必要があります。

finder1.png

AppleScriptエディタのツールバーで、「包含階層を表示」ボタンをクリック。

finder2.png

Applicationの下にdiskオブジェクトがあることが分ります。

finder3.png

とりあえず、ネットワーク上のサーバーやUSBメモリーを実際にマウントしてみて、プロパティを取得するなどアプリケーションと「対話」して調べてみましょう。ここでは、「3bai」という名前のUSBメモリーをマウント、そのプロパティを取得。

スクリプト名:3baiのプロパティを取得
tell application “Finder”
  properties of disk “3bai”
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

結果はこのようなものが得られました。

finder4.png

「ejectable」属性を見て、USBメモリーは判断できそうです。また、ネットワーク上のドライブ(ファイルサーバーとか、NASとか)であれば、「local volume」属性を見れば判定は可能です。

なので、おもむろに………

スクリプト名:USBメモリやネットワーク上のサーバーなどをアンマウント
tell application “Finder”
  eject (every disk whose ejectable is true) –外付けHDD, USBメモリー
  
eject (every disk whose local volume is false) –ネットワーク上のドライブ
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

こんな感じで、とくにエラートラップやタイムアウト時間の延長などは行っていませんが、素直に書くことができました。

ただし、これら外付けドライブ上のファイルをオープンしているアプリケーションが存在している場合に、ドライブのアンマウントが中断されてしまいますので、そのあたりは別の対策が必要になると思います。