Archive for 3月, 2012

2012/03/27 Safari 5.1.5でAppleScript用語辞書に変更なし

本日ソフトウェア・アップデートから配布されたSafari 5.1.5のAppleScript用語辞書を確認したところ、とくに前バージョンとの差異は検出されませんでした。

………………………………Safari 5.1.5で「www.apple.co.jp」を表示させると、ちゃんと「www.apple.com/jp」にリダイレクトされるようですが……目の錯覚でしょうか。それとも、サーバーの転送設定が修正されたのでしょうか。

2012/03/24 AppleScriptレコードのラベルのリストを作成

レコードのラベルのリストを作成するAppleScriptです。

穴だらけで冗談みたいな処理内容ですが、とりあえず10分ぐらいで作ってみました。

AppleScriptのレコードを、とりあえず「卑怯な手段」でテキストに変換(技術もへったくりもない)。変換したら、適当にデリミタで分解して、分解されて出来上がったリストから、適宜内容を取り出すというものです。

レコードのデータの中に「:」を含む文字列が入っていない場合にのみ利用が可能です。そんな状況を保証できるわけもないので、ものすごく利用できるシーンは少ないと思います。

あとは、AppleScriptエディタ自体を操作して、AppleScriptエディタの構文色分け機能を使って超強引にラベル要素を取り出すという手段が残されていますが………………何もそこまで頑張る必要はないでしょう。

海外でその手のOSAXは存在していそうな感じはしますし、AppleScriptObjCを併用すると、もっとスマートに実現できるかもしれません。

昔、高校生の頃にアセンブラで組んでいたプログラムが本棚の奥から出てきましたが、もっとまともで真面目なプログラムを組んでいたような気が……。少なくとも、こんな極悪プログラムを組んではいなかったと思います。

ただ、できることは今の方が数万倍多いので、そういうものなのでしょう。

スクリプト名:AppleScript レコードのラベルのリストを作成
–AppleScript レコードのラベルのリストを作成

set aRec to {hogehoge:“abc”, hugahuga:“def”}
set aText to recToStr(aRec) of me

set a1Text to repChar(aText, “{”, “, “) of me
set a2Text to repChar(a1Text, “}”, “,”) of me

set curDelim to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to {“, “, “:”}
set aList to text items of a2Text
set AppleScript’s text item delimiters to curDelim

set bList to items 2 thru -2 of aList
set aLen to length of bList

set resList to {}

repeat with i from 1 to aLen by 2
  set the end of resList to contents of item i of bList
end repeat

resList
–> {”hogehoge”, “hugahuga”}

–レコードをテキストに変換
on recToStr(aRec)
  –エラートラップを使って、わざとエラーを発生させ、エラーメッセージからレコードをstringに変換する
  
try
    set a to aRec as string
  on error aMsg
    set a to aMsg
  end try
  
  
set b to repChar(a, “のタイプを string に変換できません。”, “”)
  
–> “{aData:1, bData:2} “
  
return b
  
end recToStr

–文字置換ルーチン
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

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

2012/03/24 インストールされているアプリのAS辞書を書き出すv2

2012/03/14 Safari 5.1.4 AppleScript用語辞書に変更なし

Safariの5.1.4アップデートがリリースされましたが、AppleScript用語辞書に変更はありませんでした。

2012/03/12 Find same file name with different extension in same directory

This is a simple AppleScript to find same file name with different extension in same directory.

Sample Data:
finder1.jpg

Output Data:
–> {{”D120_a.jpg”, “D120_a.png”}, {”D120_c.gif”, “D120_c.jpg”, “D120_c.png”, “D120_c.txt”}}

スクリプト名:find same file name with different extension in same directory
–Speed up technic
script aRef
  property aList : {} –every file name of user selected folder ( work)
  
property bList : {} – every file name list (without duplicates) (work)
  
property cList : {} –duplicated file name list (work)
  
property dList : {} –output duplicated file names with different extensions
end script

–Initialize variables
set aList of aRef to {}
set bList of aRef to {}
set cList of aRef to {}
set dList of aRef to {}

set a to choose folder with prompt “Choose check Folder”

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

–make pure file name list(without extension) to cList
repeat with i in aList of aRef
  set j to contents of i
  
set jj to retFileNameWithoutExt(j) of me
  
  
if jj is in bList of aRef then
    –duplicated file name & does not exist in cList
    
if jj is not in cList of aRef then
      set the end of cList of aRef to jj
    end if
    
    
set tmpName to jj & “.”
    
    
tell application “Finder”
      tell folder a
        –set dList of aRef to dList of aRef & (name of every file whose name starts with tmpName)
        
set the end of dList of aRef to (name of every file whose name starts with tmpName)
      end tell
    end tell
    
  end if
  
  
set the end of bList of aRef to jj
end repeat

–Remove duplicates from List
set aRes to removeDuplicates(dList of aRef) of me

–> {{”D120_a.jpg”, “D120_a.png”}, {”D120_c.gif”, “D120_c.jpg”, “D120_c.png”, “D120_c.txt”}}

–Remove Duplicated Item from List
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

–delete extension from file name
on retFileNameWithoutExt(fileNameStr)
  set fLen to length of fileNameStr
  
set revText to (reverse of (characters of fileNameStr)) as string –make reversed string
  
set anOffset to offset of “.” in revText
  
set fRes to text 1 thru (fLen - anOffset) of fileNameStr
  
return fRes
end retFileNameWithoutExt

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

2012/03/11 NSTextViewからのテキストデータ取得、テキスト設定サンプル

NSTextViewへのデータ設定、データ取得を行うAppleScriptObjCのサンプルです。

AppleScript Studioで作ってあったOpenSSLのユーティリティをAppleScriptObjCで作り直そうとしたときに、どうも一定文字以上のデータのエンコード時に文字化けが発生。その問題検証のために作成したサンプルです。

実際に試してみて、NSTextViewからの値の取得/設定時にはとくに問題がないことがはっきりしました。やはり、実際に組んで試してみないと。

tv1.jpg

→ プロジェクトのダウンロード(Xcode 4.1 on Mac OS X 10.6.8で検証)

AppleScriptObjCファイル名:textview1AppDelegate.applescript

– textview1AppDelegate.applescript
– textview1

– Created by 長野谷 隆昌 on 12/01/13.
– Copyright 2012 Piyomaru Software. All rights reserved.

script textview1AppDelegate
  
property parent : class “NSObject”
  
  
property aTV : missing value
  
property bTV : 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 textStorage to (my aTV’s textStorage())
    
set theText to textStorage’s |string|()
    
display dialog (theText as string)
    
  
end clicked_
  
  
on clicked2_(sender)
    
    
    
set textStorage to (my aTV’s textStorage())
    
set theText to textStorage’s |string|()
    
    
set theText to theText as Unicode text
    
    
my bTV’s setString_(theText)
    
  
end clicked2_
  
  
on clicked3_(sender)
    
    
set textStorage to (my aTV’s textStorage())
    
set theTextA to textStorage’s |string|()
    
set theTextA to theTextA as Unicode text
    
    
set textStorage to (my bTV’s textStorage())
    
set theTextB to textStorage’s |string|()
    
set theTextB to theTextB as Unicode text
    
    
if theTextA = theTextB then
      
display dialog “左右のテキスト内容はイコールです”
    
else
      
display dialog “左右のテキスト内容は合っていません”
    
end if
    
  
end clicked3_
  
end script

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

2012/03/10 シェルソート高速化比較(さらに改良)

先日投稿していただいたshell sortに、若干の改良を加えてさらに高速化したAppleScriptです。

tsuki3さんから投稿していただいたshell sortのコメントに、

ちなみに私の経験上、リストの要素数を得る場合は “lenth of ~” を使うよりも
“count ~” を用いた方が速いはずです。また、私のスクリプトでは 複数の要素を纏めて set しておりますが、
これを別個にすればより速くなるはずです。

とあったので、すべて試してみました。

sort2.jpg

MacBook Pro 2010 Core i7 2.66GHz, RAM 8GB, Mac OS X 10.6.8の環境で改良版の「shellSort5」を試してみたところ、shellSort4で5秒かかっていた3万件のソートが4秒に。正直、こんなに速くなるとは思ってもみませんでした。ループ回数が多いので、わずかなスピードアップの集積が大きいんでしょうね。

Classic Mac OSの時代には、サードパーティのOSAX(スクリプティング機能拡張)の機能を呼び出してハードウェア制御(キーボードLEDの点灯制御、シリアルポート経由の機器制御)を行ったり、高度な命令を利用することを目指していました。最終的には200個ぐらいのOSAXをシステムにインストールして使っていたほど。

ソートに関しても、サードパーティのOSAXで提供されるソート命令を利用することが多かったのですが、Mac OS Xの時代になってMac OS X対応できない(or しない)OSAXが多数あったため、OSAXへの依存度を下げることが必要になってきました。のちに、Universal Binary対応や64ビット対応など、さまざまなハードルがあってOSAX側の対応が後手後手に回る中、Mac OS Xへの移行当初からOSAXへの依存度を下げる努力をしてきたため、自分はあまり影響を受けませんでした。また、このOSAX依存度軽減の努力は、AppleScript StudioによるGUIベースのアプリケーション開発時にもおおいに役立ちました(アプリケーションと一緒に再配布できないライセンス条件のOSAXなどもあったため)。

正直なところ、ソートルーチンなんて一度作ってそこそこ満足できれば、見直すことなどほとんどない部品。最初のバージョンからここまでいろいろと高速化ができたのは、多くのScripterの方々の努力と経験によるところが大きく、1人でやっているだけでは、なかなか手が回らないところだと思います。

そういう意味では、こういうBlogを立ち上げて地道に活動してきた意義というのはあるのではないかと。この3月でスタートして4年が経過。掲載Scriptも1,000本を超えました。当初の、「サブルーチン資産に対するMac OS Xバージョンアップの影響検証」というねらいを超えて、技術的な交流の場として機能していけたらいいですね。

スクリプト名:(数値ソート) シェルソート_v2.scpt
set lst to {}
set lstr to (a reference to lst)
repeat 30000 times
  set lstr’s end to (random number 999)
end repeat
set t to (current date)

set res to my shellSort5(lst)

– 正誤確認用
(*set resr to (a reference to res)
repeat with i from 2 to (count resr)
  if (resr’s item (i - 1) > resr’s item i) then return false
end repeat*)

return {“” & ((current date) - t) & “秒”}

on shellSort1(lst) – 配列を使用した基本形
  set len to (count lst)
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {lst’s item (i + 1), i}
        
repeat while ((j gap) and (lst’s item (j - gap + 1) > temp))
          set {lst’s item (j + 1), j} to {lst’s item (j - gap + 1), j - gap}
        end repeat
        
set lst’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return lst
end shellSort1

on shellSort2(lst) – 参照 (a reference to…) を使用
  set {lstr, len, gap} to {a reference to lst, count lst, 1}
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {lstr’s item (i + 1), i}
        
repeat while ((j gap) and (lstr’s item (j - gap + 1) > temp))
          set {lstr’s item (j + 1), j} to {lstr’s item (j - gap + 1), j - gap}
        end repeat
        
set lstr’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return lst
end shellSort2

on shellSort3(lst) – レコードと参照、グローバル変数を併用
  global rec
  
set rec to {list:lst}
  
set {recr, len, gap} to {a reference to rec, count lst, 1}
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {recr’s list’s item (i + 1), i}
        
repeat while ((j gap) and (recr’s list’s item (j - gap + 1) > temp))
          set {recr’s list’s item (j + 1), j} to {recr’s list’s item (j - gap + 1), j - gap}
        end repeat
        
set recr’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return recr’s list
end shellSort3

on shellSort4(lst) – スクリプトオブジェクトを使用
  script o
    property list : lst
  end script
  
set {len, gap} to {count o’s list’s items, 1}
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {o’s list’s item (i + 1), i}
        
repeat while ((j gap) and (o’s list’s item (j - gap + 1) > temp))
          set {o’s list’s item (j + 1), j} to {o’s list’s item (j - gap + 1), j - gap}
        end repeat
        
set o’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return o’s list
end shellSort4

–プレーンなAppleScriptベースでは最速ソート
on shellSort5(aSortList) – スクリプトオブジェクトを使用
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (oBj’s list’s item (j - gap + 1) > temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSort5

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

2012/03/07 シェルソート高速化比較

AppleScriptにおけるシェルソートの高速化について、それぞれ検証するScriptをtsuki3さんから投稿していただきました。

3/3 の記事 “100倍速いシェルソートでリストをソート” 内、解説の項にて
高速化の計測を話題にされておりましたが、数年前に私が書いたスクリプトが
それを目的としたものでしたので、投稿いたします。

なお、拙作のスプリクトオブジェクトを用いたものの方が誤差程度ですが、
edama2さんのものより(当方の環境では)速いようです。
ただ、レギュレーションが違うので比較自体に意味が無いのかもしれませんが。

ちなみに私の経験上、リストの要素数を得る場合は “lenth of ~” を使うよりも
“count ~” を用いた方が速いはずです。また、私のスクリプトでは 複数の要素を纏めて set しておりますが、
これを別個にすればより速くなるはずです。

一度、きちんと比較しておかないと……とは思ってはいたのですが、ついついめんどくさくて手つかずの状態。ちょうどいいところに投稿していただけたので、実測値を計ってみることにしました。

計測するのは、以下の4つ。

 shell sort 1……高速化を一切行っていない、通常のシェルソート
 shell sort 2……オーソドックスな「a reference to」を使用して高速化
 shell sort 3……レコードと参照、グローバル変数を併用
 shell sort 4……スクリプトオブジェクトを使用

……shell sort 3は、ちょっとお目にかかったことのないタイプ。

ひととおり、MacBook Pro 2010 Core i7 2.66GHz, RAM 8GB, Mac OS X 10.6.8の環境でテストしてみると……

sort.jpg

スクリプトオブジェクトを使用するものが一番高速(AppleScriptObjCを使うと、そちらの方が速いですが)ということが客観的によく分りました。

スクリプト名:(数値ソート) シェルソート.scpt
set lst to {}
set lstr to (a reference to lst)
repeat 30000 times
  set lstr’s end to (random number 999)
end repeat
set t to (current date)

set res to my shellSort4(lst)

– 正誤確認用
(*set resr to (a reference to res)
repeat with i from 2 to (count resr)
  if (resr’s item (i - 1) > resr’s item i) then return false
end repeat*)

return {“” & ((current date) - t) & “秒”}

on shellSort1(lst) – 配列を使用した基本形
  set len to (count lst)
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {lst’s item (i + 1), i}
        
repeat while ((j gap) and (lst’s item (j - gap + 1) > temp))
          set {lst’s item (j + 1), j} to {lst’s item (j - gap + 1), j - gap}
        end repeat
        
set lst’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return lst
end shellSort1

on shellSort2(lst) – 参照 (a reference to…) を使用
  set {lstr, len, gap} to {a reference to lst, count lst, 1}
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {lstr’s item (i + 1), i}
        
repeat while ((j gap) and (lstr’s item (j - gap + 1) > temp))
          set {lstr’s item (j + 1), j} to {lstr’s item (j - gap + 1), j - gap}
        end repeat
        
set lstr’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return lst
end shellSort2

on shellSort3(lst) – レコードと参照、グローバル変数を併用
  global rec
  
set rec to {list:lst}
  
set {recr, len, gap} to {a reference to rec, count lst, 1}
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {recr’s list’s item (i + 1), i}
        
repeat while ((j gap) and (recr’s list’s item (j - gap + 1) > temp))
          set {recr’s list’s item (j + 1), j} to {recr’s list’s item (j - gap + 1), j - gap}
        end repeat
        
set recr’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return recr’s list
end shellSort3

on shellSort4(lst) – スクリプトオブジェクトを使用
  script o
    property list : lst
  end script
  
set {len, gap} to {count o’s list’s items, 1}
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set {temp, j} to {o’s list’s item (i + 1), i}
        
repeat while ((j gap) and (o’s list’s item (j - gap + 1) > temp))
          set {o’s list’s item (j + 1), j} to {o’s list’s item (j - gap + 1), j - gap}
        end repeat
        
set o’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return o’s list
end shellSort4

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

2012/03/07 InDesign CS3で指定のオプジェクトを、JPEG書き出ししてiPhoneへ

InDesign CS3上で指定したオブジェクトをJPEG書き出ししてiPhoneに転送するAppleScriptです。

ことのはじまりは、目下開発中のiPhoneアプリ(私はプロジェクト管理やら仕様書書きやらを)で、Welcome画面の表示を行うのに「文字詰めや行送りをいろいろ指定できないと!」という話になったこと。

……そもそも、iPhoneの文字表示部品に、そんな気の利いたものはありません。そこで、InDesignやらIllustrator上で気の済むまで行間や文字間にこだわっていただいて、それをそのまま「画像」として書き出して表示しようではないか、と。

ただし、その指定内容をすぐにiPhoneの実機で見たいという話に。

その場で10分もかけずにInDesign書類上の指定レイヤー(「コンテンツ」)上に存在する指定名称(スクリプトラベル「screen」)のグループをJPEG書き出しして、書き出したJPEG書類をiPhotoにインポートして、iTunesに命令して接続しているすべてのiOSデバイスにシンクロを行うようAppleScriptで指令を出すようにしてみました。

できた瞬間はかなりガッツポーズでしたが、冷静に考えるとInDesignから書き出されるJPEG画像のクオリティが「残念なレベル」です。また、シンクロが終わるまでにちょっと時間がかかるので、実用性がいまひとつ。

結局、Good Reader for iPhoneをインストールして、iTunes経由でGood Readerに対してInDesignから書き出したPDFを渡す、という方法に落ち着きました。本Scriptは何らかの「可能性」を感じさせてくれはしたのですが、結局おクラ入りに。

スクリプト名:InDesign CS3で指定のオプジェクトを、JPEG書き出ししてiPhoneへ
–v1 InDesign CS3から直接JPEG書き出し。画像クオリティが低くて難あり

set dtPath to (path to desktop) as string
set fName to do shell script “date +%Y%m%d%H%M%S”

set fullPath to dtPath & fName & “.jpg”
set fullPathPOSIX to POSIX path of fullPath

tell application “Adobe InDesign CS3″
  tell document 1
    tell layer “コンテンツ”
      set aList to every group whose label is equal to “screen”
    end tell
    
    
set expItem to contents of first item of aList
    
export expItem format JPG to fullPath without with grids
    
  end tell
end tell

–iPhotoに書き出したJPEGファイルをインポートする
tell application “iPhoto”
  import from fullPathPOSIX
end tell

–アップデート可能なiOSデバイスをアップデートする
tell application “iTunes”
  repeat with i in sources
    if (kind of i is iPod) then update i
  end repeat
end tell

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

2012/03/07 テキストへの色指定サンプル

テキストに色指定を行うサンプルのAppleScriptObjCプログラムです。

textcol.jpg

AppleScriptObjCファイル名:textcolorTestAppDelegate.applescript

– textcolorTestAppDelegate.applescript
– textcolorTest

– Created by 長野谷 隆昌 on 12/02/13.
– Copyright 2012 Piyomaru Software. All rights reserved.

script textcolorTestAppDelegate
  
property parent : class “NSObject”
  
  
property nsc : class “NSColor”
  
property tf : missing value
  
property aTextField : missing value
  
  
on applicationWillFinishLaunching_(aNotification)
    
    
–ひとつめのNSTextField(入力フィールド)
    
set aString to current application’s NSMutableAttributedString’s alloc()’s initWithString_(“これはテスト用の文字列ですよー”)
    
    
set colorArray to current application’s NSArray’s arrayWithObjects_(nsc’s redColor(), nsc’s orangeColor(), nsc’s yellowColor(), nsc’s greenColor(), nsc’s blueColor, nsc’s purpleColor(), missing value)
    
    
repeat with i from 0 to (aString’s |length|()) - 1
      
aString’s addAttribute_value_range_(current application’s NSForegroundColorAttributeName, colorArray’s objectAtIndex_(i mod 6), {i, 1})
    
end repeat
    
    
tf’s setAttributedStringValue_(aString)
    
    
    
–ふたつめのNSTextField(Label)
    
set bString to current application’s NSMutableAttributedString’s alloc()’s initWithString_(“●私のユーザー名”)
    
    
set colorArray to current application’s NSArray’s arrayWithObjects_(nsc’s redColor(), nsc’s blackColor())
    
    
set bLen to bString’s |length|()
    
    
bString’s addAttribute_value_range_(current application’s NSForegroundColorAttributeName, colorArray’s objectAtIndex_(0), {0, 1})
    
bString’s addAttribute_value_range_(current application’s NSForegroundColorAttributeName, colorArray’s objectAtIndex_(1), {1, (bLen - 1)})
    
    
aTextField’s setAttributedStringValue_(bString)
    
  
end applicationWillFinishLaunching_
  
  
  
  
on applicationShouldTerminate_(sender)
    
return current application’s NSTerminateNow
  
end applicationShouldTerminate_
  
  
end script

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

2012/03/07 指定のRGBカラーをGeneric CMYKプロファイルでCMYKに変換して……RGB値を取得

指定のRGBカラー値をGeneric CMYKプロファイルを用いてCMYK変換し、CMYK値を取り出そうとして……できなかったので仕方なくRGB値を取り出したAppleScriptObjCのプログラムです。

上のColorWellをクリックして任意の色(ここではライトグリーン)を選択。

asoc1.jpg

「Convert RGB to CMYK」ボタンをクリックすると、Mac OS XのGeneric CMYK Profileに基づいてCMYK変換を行い、下のColorWellに色を設定します。

asoc2.jpg

いい感じのCMYKっぽい色に変換されるのですが、ここからCMYK値を取り出すのに失敗(なんでだ〜)。仕方なくRGB値を取り出しています。

→ プロジェクトのダウンロード(Xcode 4.1 on Mac OS X 10.6.8)

AppleScriptObjCファイル名:rgb2cmykAppDelegate.applescript

– rgb2cmykAppDelegate.applescript
– rgb2cmyk

– Created by 長野谷 隆昌 on 12/01/26.
– Copyright 2012 Piyomaru Software. All rights reserved.

– generic CMYK color Spaceを用いて、RGB→CMYK変換を行い、ColorWellにCMYKベースで色をセットしたあとRGB値でその色を取り出す
– 

script rgb2cmykAppDelegate
  
  
property parent : class “NSObject”
  
  
property rgbWell : missing value
  
property rgbR : missing value
  
property rgbG : missing value
  
property rgbB : missing value
  
  
property cmykWell : missing value
  
property cmykC : missing value
  
property cmykM : missing value
  
property cmykY : missing value
  
property cmykK : 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)
    
    
–RGB Color Wellのカラー値を読み取って、TextFieldに文字を入れる
    
set {rNum, gNum, bNum, aNum} to retColData(rgbWell)
    
    
set rNumStr to (rNum as integer) as string
    
set gNumStr to (gNum as integer) as string
    
set bNumStr to (bNum as integer) as string
    
    
rgbR’s setStringValue_(rNumStr)
    
rgbG’s setStringValue_(gNumStr)
    
rgbB’s setStringValue_(bNumStr)
    
    
    
–RGB Colorwellからカラーを読み取る
    
set tmpColor to rgbWell’s |color|
    
    
–Generic ProfileでRGB to CMYK変換してColorWellに設定
    
set cmykColSpace to current application’s NSColorSpace’s genericCMYKColorSpace
    
set color1 to tmpColor’s colorUsingColorSpace_(cmykColSpace)
    
    
    
–cmykWell’s setColor_(color1)
    
tell cmykWell
      
setColor_(color1)
    
end tell
    
    
    
–とりあえずRGBAでデータを取り出してみる
    
set {temp21, temp22, temp23, temp24} to retColData(cmykWell)
    
    
set temp21 to temp21 as string
    
set temp22 to temp22 as string
    
set temp23 to temp23 as string
    
set temp24 to temp24 as string
    
    
–TextFieldにCMYKデータを入れる
    
cmykC’s setStringValue_(temp21)
    
cmykM’s setStringValue_(temp22)
    
cmykY’s setStringValue_(temp23)
    
cmykK’s setStringValue_(temp24)
    
  
end clicked_
  
  
  
  
–指定オブジェクトのカラー値を取得する
  
on retColData(aObject)
    
    
–色空間のコンバートを行ってカラー値を取得する(強制的にRGB)
    
set tmpColor to aObject’s |color|
    
set color1 to tmpColor’s colorUsingColorSpaceName_(current application’s NSCalibratedRGBColorSpace)
    
    
set temp11 to color1’s redComponent()
    
set temp12 to color1’s greenComponent()
    
set temp13 to color1’s blueComponent()
    
set temp14 to color1’s alphaComponent()
    
    
–RGBAの並びでデータを返す
    
set TheColor to {(temp11 * 255) as integer, (temp12 * 255) as integer, (temp13 * 255) as integer, (temp14 * 255) as integer}
    
    
return TheColor
  
end retColData
  
  
  
end script

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

2012/03/06 Excelの表中のデータを拾ってセルに色を付ける

Excelの表中のデータを拾ってセルに色を付けるAppleScriptです。

Excelの表の中にR,G,Bのデータが1〜5セット、空きのセットには-1,-1,-1が入っている状態で表のI〜W列を拾って、A〜E列のセルに色を付けます。行は1行目から41行目までサーチしますが、このあたりはお好きに直して使うとよろしいでしょう。

xls.jpg

スクリプト名:表中のデータを拾ってセルに色を付ける
set colCellList to {“A”, “B”, “C”, “D”, “E”}
set dataCellList to {{“I”, “J”, “K”}, {“L”, “M”, “N”}, {“O”, “P”, “Q”}, {“R”, “S”, “T”}, {“U”, “V”, “W”}}

tell application “Microsoft Excel”
  tell sheet 1
    repeat with i from 1 to 41
      
      
–1行分のループ
      
repeat with j from 1 to 5
        
        
set aColCell to (contents of item j of colCellList) & i as string
        
        
set aDataRangeBeginStr to (contents of first item of item j of dataCellList) & i as string
        
set aDataRangeEndStr to (contents of last item of item j of dataCellList) & i as string
        
        
set aRange to range (aDataRangeBeginStr & “:” & aDataRangeEndStr)
        
set aData to value of aRange
        
        
if aData = {{-1.0, -1.0, -1.0}} then –データが入っていない箇所には-1を入れてある
          exit repeat
        end if
        
        
set color of interior object of cell aColCell to first item of aData
        
      end repeat
      
    end repeat
  end tell
end tell

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

2012/03/05 AppleScriptObjCのプログラムリストも、色分け+リンクつきテキスト掲載へ

すでに、掲載記事で実用化テストを行ってありますが……AppleScriptObjCのプログラムの構文色分けテキストでの掲載を行うことにしました。

これまでは、Xcodeが正しいAppleScript構文色分けを行ってくれないために、仕方なく画面のスクリーンショット+プロジェクトのアーカイブをダウンロード、という形式でAppleScriptObjCのプログラムリストを掲載していましたが、掲載するのもめんどうですし、検索性もよくありませんでした。

そこで、Xcodeのスクリプトメニューから呼び出すと、正しい構文色分けを行ったテキストを出力するAppleScriptを作成。これで、AppleScriptObjCのリスト掲載の作業を大幅に減らしてみやすい記事を掲載することができるようになりました。

通常のAppleScriptのリストと見分けられるように、リストの背景色を変えています。通常のAppleScriptは青系統の色に指定していますが、AppleScriptObjCのリストは緑系統の色を指定しています。

▼AppleScriptObjCのプログラムリスト
asoclist.jpg

▼通常のAppleScriptのプログラムリスト
aslist.jpg

2012/03/04 Macworld Web、OS X 10.8の新セキュリティ基準がAppleScriptに与えるインパクトについて掲載

MacWorld Webにおいて、「How new Mac security measures will impact AppleScript」と題して「新しいセキュリティ基準がAppleScriptに与える衝撃」という記事を掲載しています。

要約すると……

・ユーザーがアプリ操作のために作ったScriptには、影響はないだろう

・アプリ内部で(ユーザーに見えないところで)AppleScriptを利用している箇所もあり、Sandbox化する場合には通信するアプリのIDをplistに登録しておく必要があり、リストにないアプリと新たに通信する必要がある場合には影響が出るだろう

・各アプリの専用Scriptメニューから呼び出すScriptについては、Scriptの保存先フォルダが厳密に規定されているので、好き勝手な場所には置けない(所定の場所に置けば大丈夫だろう)

・GateKeeperは、ユーザー自身が作ったScriptはともかく、オンラインで配布されているAppleScriptアプレットでAppleのデジタル署名のないものについてはアラートを表示するだろう。10.8で新たに採用される「XIP」形式のアーカイブにはデジタル署名が可能なので、これを利用するべき

といったところですが、残念ながら内容が「浅い」です。

これまで実際にPiyomaru Softwareが作成したAppleScriptやAppleScriptベースのアプリケーション、システムを「複雑さ」と「技術的なレベル」の2軸にもとづいてマッピングしてみると、下図のようになります。

chart1.jpg

そして、実際に影響が出そうなジャンルのものをピックアップしてみると、上図の黄色のボックスのあたりになります。

とくに、アプレットを動的に生成するようなタイプのAppleScriptは、ちょっと困ったことになりそうです。アプレットを自動生成するアプリケーション(FTP Droplet Toasterとか)や、並列処理を行うために動的にアプレットを作成するAppleScriptは、影響が出そうです。

ただ、さすがにそこまで凝ったことをやる場合にはユーザーが手動でGateKeeperのセキュリティポリシーを一時的にゆるめる設定を行うなど、まったく対処できないわけではありません。

問題は……AppleScriptに対して肝心の(平均的な)Appleのエンジニアの理解度が低いことであり、ユーザー側でさまざまなソリューションを開発しても、Appleのせいで問題に直面する可能性も否定できません。これは、Appleに対して文句を言っていくしかありません。

2012/03/03 100倍速いシェルソートでリストをソート

edama2さんよりの投稿です

基本的には掲載されている「シェルソートでリストをソート」をスプリクトオブジェクトで処理にしているだけです。サンプルでソートする数が100倍なだけで「100倍速い」という数字には特に根拠はありません。

スクリプト名:100倍速いシェルソートでリストをソート
set theList to {}
set i to 1
repeat 30000 times
  copy (random number from 100 to 99999) to the end of theList
  
set i to i + 1
end repeat

set s0Time to current date
set aRes to shellSort_order_(theList, false) of me
set s1Time to current date

display dialog (s1Time - s0Time) as string

–シェルソートでリストを昇順ソート(入れ子ではないリスト)
on shellSort_order_(a, isAsc)
  
  
script a_ref
    property contents : a
  end script
  
  
set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of contents of a_ref
        
set j to i
        
repeat while (j h) and ((item (j - h + 1) of contents of a_ref) > v)
          set (item (j + 1) of contents of a_ref) to (item (j - h + 1) of contents of a_ref)
          
set j to j - h
        end repeat
        
set item (j + 1) of contents of a_ref to v
      end repeat
    end if
  end repeat
  
  
if not isAsc then set a to a’s reverse
  
  
return a
end shellSort_order_

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

Piyomaru Softwareによる解説:

以前に掲載したシェルソートのルーチンの改良版です。ソートというか、巨大なリスト型変数(配列)の操作をAppleScriptで行うとスピードが低下するので、3,000〜4,000要素(Item)を超えるサイズのリスト型変数を扱う場合には、何らかの高速化を行うべきです。

AppleScriptにおけるソートの高速化手法にはおよそ3つあって、1つが「a reference to」による間接アクセスによる高速化。

著しく高速化するものの、データを格納する変数と間接アクセスする変数の2つをグローバル宣言する必要があり、効果は大きいものの、副作用も大きい(グローバル宣言した変数が他のルーチンの変数をぶつかっていないか確認が必要、など)ため、そのための作業コストが大きく「手軽」とはいえませんでした。

2つ目が、ここで活用されている「スクリプトオブジェクト内にプロパティを持つ」というアクセス方法で、a reference toと同程度ぐらいには(厳密に計測してはいないのですが)高速化することが知られています。

スクリプトオブジェクトの利用による高速化処理の前後で、サンプルの3万項目の乱数リストをソート所要時間を計測比較してみたところ(MacBook Pro Core i7 2.66GHz, Mac OS X 10.6.8, 8GB RAM)、

 高速化前:2967秒
 高速化後:8秒

と、370倍ぐらい高速になっていました。リストの項目が大きいほど高速化の効果が出やすいものと思われます。

3つめが、Mac OS X 10.6から使えるようになったAppleScript ObjCを用いること。この環境内でCocoaのソートルーチンを呼び出すと速いので、一度すべてのやりかたでどのソート方法が速いのか、比較をしておくべきでしょう。

追記(2012/3/4):

MacBook Air 2011 (Core i5 1.6GHz、Mac OS X 10.7.3、RAM 4GB)でこの乱数3万件のソートを試してみたところ……

 本ScriptをAppleScript Editor上で実行:7秒
 本ScriptをAppleScriptObjC on Xcodeのプロジェクトで実行:8秒
 AppleScriptObjC on XcodeのCocoaベースのソートでリスト(正確にはレコード)をScriptのオブジェクトに持たせた場合:129秒
 AppleScriptObjC on XcodeのCocoaベースのソートで何も高速化処理を行っていない場合:(計測不能)

Cocoaベースのソートがたいして速くない(純粋にリスト=NSArrayではないので、同じ処理ではないですが)ことに驚きました。AppleScriptObjCのプログラムも、ソート処理をAppleScriptネイティブのものに書き換えておいたほうがよさそうな……。

あるいは、3万件というデータ件数になると、AppleScriptObjCでもCoreDataを併用することを検討すべきなのかもしれません。データベースに入れてしまえば、3万件ごときのソートなど一瞬でしょうし。

さらに追記(2012/3/4):

AppleScriptObjCで以下のようなプログラム(単なるArrayをソート)にしてみたところ、3万件でもソートに要する時間は1秒以下でした(MacBook Pro Core i7 2.66GHz, Mac OS X 10.6.8, RAM 8GB)。

AppleScriptObjCファイル名:sortArrayAppDelegate.applescript

– sortArrayAppDelegate.applescript
– sortArray

– Created by Takaaki Naganoya on 12/03/04.
– Copyright 2012 Piyomaru Software. All rights reserved.

script aRef
  
property contents : {}
end script

script sortArrayAppDelegate
  
property parent : class “NSObject”
  
  
on applicationWillFinishLaunching_(aNotification)
    
– Nothing
  
end applicationWillFinishLaunching_
  
  
on applicationShouldTerminate_(sender)
    
return current application’s NSTerminateNow
  
end applicationShouldTerminate_
  
  
on clicked_(sender)
    
    
set aList to {}
    
repeat 30000 times
      
tell current application
        
set the end of (contents of aRef) to (random number from 1000 to 9999) as string
      
end tell
    
end repeat
    
    
tell current application
      
set sTime to current date
    
end tell
    
    
set theArray to current application’s class “NSMutableArray”’s arrayWithArray_(contents of aRef)
    
set bList to theArray’s sortedArrayUsingSelector_(“localizedCaseInsensitiveCompare:”)
    
    
tell current application
      
set eTime to current date
      
set totalTime to eTime - sTime
    
end tell
    
    
display dialog (totalTime as string)
    
  
end clicked_
  
end script

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

2012/03/01 curlでダウンロードv2

curlで指定URLから、指定フォルダにダウンロードを行うAppleScriptです。ファイル名はURLから自動取り出しを行います。

Mac OS X 10.7でURL Access Scriptingが廃止になりました。URL Access Scriptingは、たしかに手軽で便利ではありましたが、非同期ダウンロードができないため、かなり昔から個人的にはcurlを愛用していました。

URL Access ScriptingはMac OS 9の頃からの「負の遺産」(ダウンロード時のファイル名の長さに、いまだに32文字制限があったなど)ともいえる仕様を引きずっており、Appleに作り直す気がなければ消えることを宿命づけられていたものです。

で、一応curlでダウンロードを行うサブルーチンを、少し整備してみましたが……このあたり、人によってずいぶんと趣味が違うはずなので、もっとシンプルなものがいいとか、ゴージャスなものがいいとか、自分の趣味に応じて作り変えるべきだと思います。普段使っている処理では、ダウンロードを非同期で行わせることがよくあるので、そういう方向で強化してもよいと思われます。

スクリプト名:curlでダウンロードv2
–動作確認のためにダイアログ入力しているだけ
set aURL to text returned of (display dialog “URL to download” default answer “” buttons {“OK”} with icon 1)

set dlFolder to path to desktop –ダウンロード先フォルダ(Desktop)
set dRes to downloadFile(aURL, dlFolder, 3600) of me
–POSIX pathが返ってくる。あとでのんびりaliasに変換

–通常ダウンロード
on downloadFile(aURL, outPath, tOut)
  
  
set aFileName to getFNfromURL(aURL) of me
  
if aFileName = false then
    return “”
  end if
  
  
set dlPathStr to POSIX path of outPath
  
set aPOSIXpath to dlPathStr & aFileName
  
  
set dssText to “curl -s “ & aURL & ” -o “ & quoted form of aPOSIXpath
  
try
    with timeout of tOut seconds
      do shell script dssText
    end timeout
  on error
    return false
  end try
  
  
return aPOSIXpath
  
end downloadFile

on getFNfromURL(aURL)
  if aURL ends with “/” then
    –display dialog “与えられたURLの末尾がスラッシュで終了しているため、ファイルではありません。” buttons {”OK”} default button 1
    
return false
  end if
  
set aLen to length of aURL
  
set aR to reverse of (characters of aURL)
  
set aNstr to aR as string
  
set aLoc to offset of “/” in aNstr
  
set aRes to text (aLen - aLoc + 2) thru -1 of aURL
  
return aRes
end getFNfromURL

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