Archive for the 'NSThread' Category

2017/10/16 並列ダウンロードのじっけん v2

AppleScriptによる狂気のthreadごっこ。並列ダウンロードの実験AppleScriptです。

昨日のScriptを実際に何度も実行してみて「Threadを生成しても順次実行されているようにしか見えないのはなぜだろう?」などと思いつつ、スレッドのオブジェクトを配列に突っ込んでおいて、一括で実行命令(start:)を行うように改良してみました。

また、スレッド内で実行する内容に単なるカウントという(安全ではあるものの)無意味な処理ではなく、ファイルのダウンロード実行を行なっています。

自分的にはいろいろとブレークスルーな内容ではあるものの、ダウンロードにしてもThread処理するよりも逐次実行したほうが速そうな感じであるのと、shellのcurlコマンドで並列でダウンロードしたほうが安全で速そうとか、かなり「不可能にチャレンジした以外にあまりほめるべき点がない」という雰囲気になっています。

ダウンロード先のURLが数個程度だと何も問題はないものの、数十個指定すると帰ってこなくなるなど、何か問題が起きているようなので、あくまで「実験」レベルの実装です。

AppleScript名:並列ダウンロードのじっけん v2
– Created 2015-08-20 by Takaaki Naganoya
– Created 2017-10-16 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4898

property aProp : {}
property aMax : {}

set aList to {“http://piyocast.com/as/wp-content/uploads/2016/08/xbook1_ver2.png.pagespeed.ic.1UE9W7-aVC.png”, “http://piyocast.com/as/wp-content/uploads/2016/08/xbook2_v2.png.pagespeed.ic.uWjZsXaLOP.png”, “http://piyocast.com/as/wp-content/uploads/2016/09/xscript_assistant.jpg.pagespeed.ic.fk8YHumFYV.jpg”}

set aProp to {}
set thList to current application’s NSMutableArray’s new()
set aMax to length of aList
set aCount to 1

repeat with i in aList
  set j to contents of i
  
set aURL to (current application’s |NSURL|’s URLWithString:j)
  
set aThread to (current application’s NSThread’s alloc()’s initWithTarget:me selector:“_threadLoop:” object:aURL)
  (
aThread’s setName:(“thread “ & (aCount as string)))
  (
thList’s addObject:aThread)
  
  
set noter1 to current application’s NSNotificationCenter’s defaultCenter()
  (
noter1’s addObserver:me selector:“_threadWillExit:” |name|:(current application’s NSThreadWillExitNotification) object:(thList’s lastObject()))
  
  
set aThread to “” –purge object from memory
  
set aCount to aCount + 1
end repeat

thList’s makeObjectsPerformSelector:“start” withObject:0

repeat 100000 times
  if length of aProp aMax then exit repeat
  
delay “0.0001″ as real
end repeat

–各Threadが実行するハンドラ
on _threadLoop:aInfo
  checkURLResourceExistence(aInfo, 10) of me
end _threadLoop:

–Threadが終了する際に呼ばれるハンドラ
on _threadWillExit:aNotification
  set tmpRes to aNotification’s object’s |name|()
  
log tmpRes as string
end _threadWillExit:

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
set the end of aProp to {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

2017/10/15 スレッド処理

AppleScriptでスレッドを生成して実行するサンプルです。

実際にスレッドを生成して、実行して、各スレッドの状態を調査することができます。

REST APIなど、実行に時間のかかるネットワーク系の処理で使えないかと思って試作を行なっていたものです。

書いてから2年以上も放置していたのは、「スレッドセーフなルーチンを頑張って書くよりも、個別にアプレットに書き出して同時実行したほうが安全だしお手軽」という理由によります。スレッド内で実行してクラッシュしないように書くのはとても大変です(ーー;

AppleScript名:スレッド処理
– Created 2015-08-20 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4897

set aThread to current application’s NSThread’s alloc()’s initWithTarget:me selector:“_threadLoop:” object:(current application’s NSString’s stringWithString:“Apple”)

set bThread to current application’s NSThread’s alloc()’s initWithTarget:me selector:“_threadLoop:” object:(current application’s NSString’s stringWithString:“Orange”)

set aRes to current application’s NSThread’s isMultiThreaded()
–>  true

set bRes to current application’s NSThread’s currentThread()
–>  (NSThread) {number = 1, name = main}

set a1Res to current application’s NSThread’s currentThread()’s threadDictionary()
–>  (NSDictionary) {NSAppleEventManagerHandlingStack:{}, NSDocumentsContinuingFileAccess:(NSSet) {}, OSADefaultComponentInstanceKey:(OSAComponentInstance) , OSADefaultLanguageKey:(OSALanguage) , OSAAvailableLanguagesKey:{(OSALanguage) , (OSALanguage) , (OSALanguage) }}

set cRes to current application’s NSThread’s callStackReturnAddresses()
–>  (NSArray) {140735481653180, 140735481652754, 140735559055105, 140735559057361, 4473123264, 4473263701, 4473142396, 4473141941, 4472935365, 4472916653, 140735705914913, 140735481264735, 4400422881, 4400227287, 140735611717816, 140735611717253, 140735611714364, 140735611713043, 140735453174803, 140735453224127, 140735482160121, 140735481878159, 140735481875416, 140735475504495, 140735475503850, 140735475503403, 140735666104491, 140735666101848, 140735666060019, 140735665521220, 140735553762761, 1}

set dRes to current application’s NSThread’s callStackSymbols()
–>  (NSArray) {”0 CoreFoundation 0×00007fff886427bc __invoking___ + 140″, ” …… (omit)

aThread’s setName:“Apple”
bThread’s setName:“Orange”

aThread’s |threadPriority|()
–> 0.5 –(0.0〜1.0)

set c1Res to aThread’s |name|()
–>  (NSString) “Apple”
set c2Res to bThread’s |name|()
–>  (NSString) “Orange”

aThread’s threadDictionary()
–>  (NSDictionary) {}

aThread’s stackSize()
–>  524288 –this depends on each machine’s memory configuration?

aThread’s isExecuting()
–>  false

aThread’s isFinished()
–>  false

aThread’s isCancelled()
–>  false

set noter1 to current application’s NSNotificationCenter’s defaultCenter()
noter1’s addObserver:me selector:“_threadWillExit:” |name|:(current application’s NSThreadWillExitNotification) object:aThread
noter1’s addObserver:me selector:“_threadWillExit:” |name|:(current application’s NSThreadWillExitNotification) object:bThread

aThread’s start()
bThread’s start()

–各Threadが実行するハンドラ
on _threadLoop:aInfo
  repeat 3 times
    set aText to aInfo as text
    
do shell script “logger -s “ & quoted form of aText & ” &”
    
set aNum to random number from 1 to 3
    
delay aNum
  end repeat
end _threadLoop:

–Threadが終了する際に呼ばれるハンドラ
on _threadWillExit:aNotification
  
  
set tmpRes to aNotification’s object’s |name|()
  
say ((tmpRes as text) & ” finished.”) using “Alex”
  
end _threadWillExit:

★Click Here to Open This Script 

2015/09/16 指定URLをロード WKWebView版

Cocoaの機能を用いて指定URLのページの内容を読み込んで、ページのタイトルを取得するAppleScriptです。

先のオフラインレンダラーのAppleScriptをMLに投稿してみたところ、ShaneよりYosemiteならWkWebViewが新たにWebViewの後継として用意されているので試してはどうか? という指摘があり、(知らなかったので)慌てて調べた次第です。

通常のAppleScriptでCocoaの機能が使えるといっても、さすがにKey Value Observation(キー値監視)はサポートしていないので、 そこはloading()プロパティをループで確認しています。ただ、このシンプルさゆえにフォアグランド実行(Control-Command-R)させる必要がありません。

一応、これで指定URLの内容は取得できているようなのですが、いまだその内容を画像化はできていません。いまのところ、綺麗な800×600ドットのサイズのグレーの画像が取得できています(つまり、明らかに失敗している)。

# El Capitanで動かしてみたら、実行が終了しませんでした。

AppleScript名:ASOCで指定URLをロード_WKWebView版
– Created 2015-09-16 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “WebKit”

property theWebView : missing value

set aURL to “http://www.apple.com/us/shop/browse/home/specialdeals/mac”
set aRes to getPage(aURL)
set aTitle to (theWebView)’s title()
return aTitle as text
–>  ”Refurbished Mac - Apple Certified - Apple”

–Download the URL page to WkWebView
on getPage(aURL)
  set thisURL to current application’s |NSURL|’s URLWithString:aURL
  
set theRequest to current application’s NSURLRequest’s requestWithURL:thisURL
  
  
set aConf to current application’s WKWebViewConfiguration’s alloc()’s init()
  
  
set (my theWebView) to current application’s WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 800, 600)) configuration:aConf –フレームの大きさは根拠レス
  (
my theWebView)’s setNavigationDelegate:me
  (
my theWebView)’s loadRequest:theRequest
  
  
set waitLoop to 1000 * 60 –60 seconds
  
  
set hitF to false
  
repeat waitLoop times
    set aLoadF to ((my theWebView)’s estimatedProgress()) as number
    
if aLoadF = 1.0 then
      set hitF to true
      
exit repeat
    end if
    
current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001
  end repeat
  
  
return hitF
end getPage

★Click Here to Open This Script 

2015/09/15 指定URLをロードして1枚ものの大きなPDFにレンダリング

Cocoaの機能を用いて、指定URLのページを読み込み、1枚ものの大きなPDFにレンダリングするAppleScriptです。

デスクトップ上に「outPdf_2.pdf」の名前で書き出します。実行には、Script Editor上でControl-Command-Rによるフォアグラウンド実行する必要があります。

まだまだ、完成にはほど遠い感じがしますが、とりあえずPDF出力できたので。

render2.png
▲本AppleScriptでレンダリングしたPDF

render1.png
▲同じページをSafariで表示させたところ

ページの上と下が「ものすごく残念な状態」になっています。一応、User AgentをSafariに合わせてみたのですが、あまり状況はよくなっていないようです。

まだまだ、本Blogを表示させると、右側のメニュー部分しか表示されなかったり、PDFの縦の長さをページ内容に合わせて自動調整できていなかったり、ページ上のグラフィックがロードされていない状態になることがあったり、、、と、前途多難な印象を受けます。

ただ、これまでこの手のオフラインレンダラーは有用な割にAppleScriptへの対応度が低く、「ならAppleScriptで自力でやっちゃえばいいじゃん」というアプローチは間違っていない(たぶん)はず。また、オフラインレンダラー自体のアップデートが割とおざなりで、OSのアップデートについてこられないことがままあります(便利なのに)。

AppleScript名:ASOCで指定URLをロードして1枚ものの大きなPDFにレンダリング
– Created 2015-09-15 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “WebKit”
use framework “Quartz”
use framework “AppKit”

property loadDone : false
property theWebView : missing value
property userAgentName : “Version/9.0 Safari/601.1.56″

set aOutPath to “~/Desktop/outPdf_2.pdf”
set aURL to “http://www.apple.com/jp/shop/browse/home/specialdeals/mac”
–set aURL to “http://piyocast.com/as”–このBlogをレンダリングすると悲惨な状態に、、、
set targX to 1024
set targY to 2000 –動的に変更できないか?

–Check If this script runs in foreground
if not (current application’s NSThread’s isMainThread()) as boolean then
  display alert “This script must be run from the main thread (Command-Control-R in Script Editor).” buttons {“Cancel”} as critical
  
error number -128
end if

set aPath to current application’s NSString’s stringWithString:aOutPath
set bPath to aPath’s stringByExpandingTildeInPath()

–URL Validation check
set aRes to validateURL(aURL)
if aRes = false then return
set aTitle to getURLandRender(aURL)
–>  ”AS Hole(AppleScriptの穴) By Piyomaru Software”
set aTargetView to (my theWebView)’s mainFrame()’s frameView()’s documentView()

set aScreen to current application’s NSScreen’s mainScreen()
set {scrX, scrY} to aScreen’s frame()’s |size|() as list

(*
set aWin to current application’s NSWindow’s alloc()’s init()
aWin’s setContentSize:{scrX, scrY}
aWin’s setContentView:(my theWebView)
aWin’s |center|()
*)

set aPrintInfo to current application’s NSPrintInfo’s sharedPrintInfo()
set newPrintOp to current application’s NSPrintOperation’s PDFOperationWithView:(aTargetView) insideRect:(current application’s NSMakeRect(0, 0, targX, targY)) toPath:bPath printInfo:aPrintInfo

set runPrint to newPrintOp’s runOperation()
return (runPrint as boolean)

–Download the URL page to WebView and get page title
on getURLandRender(aURL)
  
  
set my loadDone to false
  
set my theWebView to missing value
  
openURL(aURL)
  
  
set waitLoop to 1000 * 60 –60 seconds
  
  
set hitF to false
  
repeat waitLoop times
    if my loadDone = true then
      set hitF to true
      
exit repeat
    end if
    
current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001
  end repeat
  
if hitF = false then return
  
  
set jsText to “document.title”
  
set x to ((my theWebView)’s stringByEvaluatingJavaScriptFromString:jsText) as text
  
  
return x
end getURLandRender

–Down Load URL contents to WebView
on openURL(aURL)
  set noter1 to current application’s NSNotificationCenter’s defaultCenter()
  
set (my theWebView) to current application’s WebView’s alloc()’s init()
  (
my theWebView)’s setApplicationNameForUserAgent:userAgentName
  
noter1’s addObserver:me selector:“webLoaded:” |name|:(current application’s WebViewProgressFinishedNotification) object:(my theWebView)
  (
my theWebView)’s setMainFrameURL:aURL
end openURL

–Web View’s Event Handler:load finished
on webLoaded:aNotification
  set my loadDone to true
end webLoaded:

–URL Validation Check
on validateURL(anURL as text)
  set regEx1 to current application’s NSString’s stringWithString:“((https|http)://)((\\w|-)+)(([.]|[/])((\\w|-)+))+”
  
set predicate1 to current application’s NSPredicate’s predicateWithFormat_(“SELF MATCHES %@”, regEx1)
  
set aPredRes1 to (predicate1’s evaluateWithObject:anURL) as boolean
  
return aPredRes1
end validateURL

★Click Here to Open This Script 

2015/09/09 指定URLのファイルをダウンロード

Cocoaの機能を用いて、指定URLのファイルをダウンロードするAppleScriptです。

書いている途中でどうしてもNSURLErrorDomain Error 3001が出てダウンロードできなかったのですが、それはダウンロード先をファイル名まで指定していなかったからでした(Appleのサンプルどおりに書いたのに!)。

最初の掲載時にはcachePolicyにNSURLRequestUseProtocolCachePolicyを指定していたのですが、ネット非接続時も正常終了したり、キャッシュが効いて最新版が取得できないなどの問題を見かけたため、NSURLRequestReloadIgnoringLocalCacheDataに変更しました。

AppleScript名:ASOCで指定URLのファイルをダウンロード
– Created 2015-09-09 Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–https://developer.apple.com/library/mac/documentation/Cocoa/
– Conceptual/URLLoadingSystem/Tasks/UsingNSURLDownload.html

property dlF : false
property dlTimeOutSec : 60.0

set my dlF to false

–DL先はファイル名まで指定しないとエラー(Error 3001)になる
set theDLdir to (current application’s NSHomeDirectory())’s stringByAppendingPathComponent:“Desktop/index.html”
–>  (NSString) “/Users/me/Desktop”

downloadFrom(“http://www.apple.com/jp/index.html”, theDLdir) of me

set waitLoop to 1000 * dlTimeOutSec –60 seconds
set hitF to false
repeat waitLoop times
  if my dlF is not equal to false then
    set hitF to true
    
exit repeat
  end if
  
current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001
end repeat
if hitF = false then return
return dlF
–>  true

on downloadFrom(aURLstr, dlDir)
  
  
set aURL to current application’s |NSURL|’s URLWithString:aURLstr
  
–>  (NSURL) http://www.apple.com
  
  
set theReq to current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:dlTimeOutSec
  
–>  (NSURLRequest) { URL: http://www.apple.com }
  
  
set theDownload to current application’s NSURLDownload’s alloc()’s initWithRequest:theReq delegate:me
  
–>  (NSURLDownload) { request: { URL: http://www.apple.com } }
  
  
theDownload’s setDestination:dlDir allowOverwrite:true
  
end downloadFrom

–Download Error Event Handler
on download:aDownload didFailWithError:anError
  set anErrorStr to anError’s localizedDescription()
  
set errorReason to (anError’s userInfo())’s objectForKey:(current application’s NSURLErrorFailingURLStringErrorKey)
  
set my dlF to {anErrorStr, errorReason}
end download:didFailWithError:

–Download Finished Event Handler
on downloadDidFinish:aDownload
  set my dlF to true
end downloadDidFinish:

★Click Here to Open This Script 

2015/09/07 指定URLをロードしてtitleを取得

Cocoaの機能を用いて、指定URLのページのtitleを取得するAppleScriptです。

Script Editor上でControl-Command-Rの操作でforeground実行する必要があります。

動的にWebViewを作成し、そこに指定URLを読み込み。JavaScript経由でタイトルを取得するという、ひねりも工夫もないものです。ログインなどが必要なSNS内などのページではなく、普通にただオープンすれば見られるタイプのページを前提としています。

この手の処理を行う場合には、Safariをコントロールするのが定番でしたが、GUIベースのアプリケーションであるSafariの全機能を必要としない場合には、動的にWebViewを生成して情報取得するほうが便利なケースもあります。

AppleScript名:指定URLをロードしてtitleを取得
– Created 2015-09-07 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “WebKit”

property loadDone : false
property theWebView : missing value

set aURL to “https://www.youtube.com/watch?v=WuziqYptTyE”
set aTitle to getPageTitle(aURL)
–>  ”戦場の絆ポータブル【HD】鉱山都市 オンライン対戦 2015.09.04 - YouTube”

on getPageTitle(aURL)
  –Check If this script runs in foreground
  
if not (current application’s NSThread’s isMainThread()) as boolean then
    display alert “This script must be run from the main thread (Command-Control-R in Script Editor).” buttons {“Cancel”} as critical
    
error number -128
  end if
  
  
set my loadDone to false
  
set my theWebView to missing value
  
openURL(aURL)
  
  
set waitLoop to 1000 * 60 –60 seconds
  
  
set hitF to false
  
repeat waitLoop times
    if my loadDone = true then
      set hitF to true
      
exit repeat
    end if
    
current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001
  end repeat
  
if hitF = false then return
  
  
set jsText to “document.title”
  
set x to ((my theWebView)’s stringByEvaluatingJavaScriptFromString:jsText) as text
  
set my theWebView to missing value
  
  
return x
end getPageTitle

–WebViewにURLを読み込む
on openURL(aURL)
  set noter1 to current application’s NSNotificationCenter’s defaultCenter()
  
set my theWebView to current application’s WebView’s alloc()’s init()
  
noter1’s addObserver:me selector:“webLoaded:” |name|:(current application’s WebViewProgressFinishedNotification) object:(my theWebView)
  
my (theWebView’s setMainFrameURL:aURL)
end openURL

–Web Viewのローディング完了時に実行
on webLoaded:aNotification
  set my loadDone to true
end webLoaded:

★Click Here to Open This Script 

2015/09/05 秒以下の時間待ちを検証

Cocoaの機能を用いて、秒以下の時間待ちを行い、実際に指定時間だけ待っているかどうかを確認してみました。

比較のため、同一環境でdelay 0.001にあたる処理をコメントアウトして時間計測してみたところ、

–> 8.8036060333252E-5(指数表示)
–> 0.000088036060333252

–> 9.30428504943848E-5(指数表示)
–> 0.0000930428504943848

と、delayを指定していない場合にははるかに短い間隔で計測が呼び出され、delayがきちんと効力を発揮していることが見てとれました。

予想よりもちゃんと指定時間待っていて驚きました。積極的に使っていきたいところです。

AppleScript名:ASOCで秒以下の時間待ちを計測
– Created 2015-09-05 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001

set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat

–>  0.001403987408
–>  0.001309990883
–>  0.001239955425

★Click Here to Open This Script 

2015/09/05 ASOCでspotlight検索するじっけん v2

Cocoaの機能を用いてspotlight検索を行うAppleScriptです。Script Editor上でControl-Command-RでForeground実行する必要があります。

前バージョンでは、ファイル名しか取得できていませんでしたが、検索でヒットしたアイテムのフルパスを返すようにできたので、ようやくこれで実用レベルに達したと思います。

(1)検索対象フォルダを指定
(2)検索条件を設定

すると、実際にspotlight検索を行って結果を返します。

検索結果待ちループ側でdelayを極小にできるよう、試行錯誤してみましたが、

(1)delayを削除するとうまく動かない
(2)delay 0.01のとおりに本当に0.01秒待っているかはわからない
(3)手元の環境ではうまく動いているが、環境に応じたチューニングが必要?(2台で確認)

という印象を持っています。

ASOCで0.001という数値をプログラム内に記述するのにえっらい苦労しました。そのまま書くと指数表現されてしまい、Pure AppleScriptの世界ではエラーにならないんですが、Cocoaのオブジェクトに渡されるときにうまくブリッジされないのか、エラーに。NSSNumberでfloatValueを設定しようとしてもうまく行かないわで、結局、文字列で書いて強制的にcastするという強引な方法で解決。もっといい方法があるとよいのですが、相当苦労しました。

いろいろ条件を変えて検索の実験をしたところ、与えた検索条件でヒットがない場合には早々に{}を返してくるため、無限ループで処理が終わらないということはないようです。

これでもう、spotlight検索のためにshell commandのmdfindを呼び出す必要はなくなりました。

AppleScript Users MLの過去ログや、ShaneのEveryday AppleScriptObjC添付のサンプルコード、ASObjC Explorer 4添付のサンプルコードなども探し回ってspotlight検索のサンプルを探してみましたが、検索結果のフルパスを返すものはなかったので(ついでに言うとObjective-Cのプログラムを検索エンジンで探しても、けっこう見つからない)、これを書いておいた意義はあるものと思います。

AppleScript名:ASOCでmdfindするじっけん v2(フルパスを返す)
– Created 2015-09-03 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

property searchRes : {}

set searchRes to {} –initialize

set origPath to POSIX path of (choose folder)
initiateSearchForFullPath(“kMDItemDisplayName == ’ICON0.PNG’”, origPath) –Predicate & Scope Directory

–Waiting for the result
repeat while searchRes = {}
  current application’s NSThread’s sleepForTimeInterval:(“0.001″ as real) –delay 0.001
end repeat

set anObj to searchRes’s firstObject() –Pick up the first one for test
if anObj = missing value then return {} –No Result

–set anAttrList to anObj’s attributes() –”mdls” attributes
–>  (NSArray) {”kMDItemContentTypeTree”, “kMDItemContentType”, “kMDItemPhysicalSize”, …}

set resArray to current application’s NSMutableArray’s alloc()’s init()
repeat with anItem in searchRes
  (resArray’s addObject:(anObj’s valueForAttribute:“kMDItemPath”))
  
–>  (NSString) “/Users/me/Documents/機動戦士ガンダム戦場の絆 Folder/ULJS00181USERID_0000/ICON0.PNG”
end repeat

resArray
–>  (NSArray) {”/Users/me/Documents/機動戦士ガンダム戦場の絆 Folder/ULJS00181USERID_0000/ICON0.PNG”,……}

on initiateSearchForFullPath(aQueryStrings, origPath)
  
  
set aSearch to current application’s NSMetadataQuery’s alloc()’s init()
  
  
current application’s NSNotificationCenter’s defaultCenter()’s addObserver:(me) selector:“queryDidUpdate:” |name|:(current application’s NSMetadataQueryDidUpdateNotification) object:aSearch
  
current application’s NSNotificationCenter’s defaultCenter()’s addObserver:(me) selector:“initalGatherComplete:” |name|:(current application’s NSMetadataQueryDidFinishGatheringNotification) object:aSearch
  
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aQueryStrings
  
aSearch’s setPredicate:aPredicate
  
  
set aScope to current application’s NSArray’s arrayWithObjects:{origPath}
  
aSearch’s setSearchScopes:aScope
  
  
set sortKeys to current application’s NSSortDescriptor’s sortDescriptorWithKey:“kMDItemFSName” ascending:true
  
aSearch’s setSortDescriptors:(current application’s NSArray’s arrayWithObject:sortKeys)
  
  
aSearch’s startQuery()
  
end initiateSearchForFullPath

on queryDidUpdate:sender
  log sender
  
–> (NSConcreteNotification) NSConcreteNotification 0×7fa618450820 {name = NSMetadataQueryDidFinishGatheringNotification; object = }
end queryDidUpdate:

on initalGatherComplete:sender
  set anObject to sender’s object
  
anObject’s stopQuery()
  
current application’s NSNotificationCenter’s defaultCenter()’s removeObserver:me |name|:(current application’s NSMetadataQueryDidUpdateNotification) object:anObject
  
current application’s NSNotificationCenter’s defaultCenter()’s removeObserver:me |name|:(current application’s NSMetadataQueryDidFinishGatheringNotification) object:anObject
  
  
set my searchRes to anObject’s results()
end initalGatherComplete:

★Click Here to Open This Script 

2015/08/24 ASOCでPDFを印刷するテスト

Cocoaの機能を用いてPDFをAppleScriptだけでアプリケーションに依存しないで印刷するscriptです。

pdfprint1.png
▲Script Editor上でCommand-Control-「R」でforeground実行すると、PDFを選択し、印刷ダイアログを表示します(Window非表示)

pdfprint2.png
▲プリンタも選択可能

AppleScript名:ASOCでPDFを印刷するテスト
– Created 2015-08-24 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
use framework “AppKit”

–Check If this script runs in foreground
if not (current application’s NSThread’s isMainThread()) as boolean then
  display alert “This script must be run from the main thread (Command-Control-R in Script Editor).” buttons {“Cancel”} as critical
  
error number -128
end if

–Choose a PDF to print
set aDoc to POSIX path of (choose file of type {“com.adobe.pdf”})
set aDocPath to current application’s NSString’s stringWithString:aDoc
set aPDF to current application’s PDFDocument’s alloc()’s initWithURL:(current application’s |NSURL|’s fileURLWithPath:aDocPath)

–Make PDFView
set aPDFView to current application’s PDFView’s alloc()’s init()
aPDFView’s setDocument:aPDF
aPDFView’s setAutoScales:true
aPDFView’s setDisplaysPageBreaks:false

–Make Window
set aWin to current application’s NSWindow’s alloc()’s init()
aWin’s setContentSize:(aPDFView’s frame()’s |size|())
aWin’s setContentView:aPDFView
aWin’s |center|()

–Print PDF
set sharedPrintInfo to current application’s NSPrintInfo’s sharedPrintInfo()
aPDFView’s printWithInfo:sharedPrintInfo autoRotate:true

★Click Here to Open This Script 

2015/08/20 ASOCでdate pickerによる日付選択

Shane StanleyのScript Library「BridgePlus」の機能を用いた日付/時刻選択インタフェース「date picker」による日付/時刻選択を行うAppleScriptです。実行には、あらかじめBridgePlusをインストールしておく必要があります。

datepicker1.png
▲ASObjC Explorer 4での実行画面

datepicker2.png
▲Script Editorでの実行画面(Control-Command-R)

そうそう、こういうのが(OS標準で)欲しかったんですよね〜。あと、開始日と終了日の選択とか、休日を選択できないようにできるといいかも。

AppleScript名:ASOCでdate pickerによる日付選択
– Created 2015-08-20 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use script “BridgePlus” – for pre-10.11 compatibility

if not (current application’s NSThread’s isMainThread()) as boolean then
  display alert “This script must be run from the main thread.” buttons {“Cancel”} as critical
  
error number -128
end if

– create a view
set theView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 100, 200))

– create date picker
set datePicker to current application’s NSDatePicker’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 100, 100))

– set style: choices are NSTextFieldAndStepperDatePickerStyle, NSClockAndCalendarDatePickerStyle, or NSTextFieldDatePickerStyle
datePicker’s setDatePickerStyle:(current application’s NSClockAndCalendarDatePickerStyle)

– set elements: choices include NSHourMinuteDatePickerElementFlag, NSHourMinuteSecondDatePickerElementFlag, NSTimeZoneDatePickerElementFlag, NSYearMonthDatePickerElementFlag, and NSEraDatePickerElementFlag
datePicker’s setDatePickerElements:((current application’s NSYearMonthDayDatePickerElementFlag) + (current application’s NSHourMinuteSecondDatePickerElementFlag as integer))

– set initial date
datePicker’s setDateValue:(current application’s NSDate’s |date|())

– get the size it needs
set theSize to datePicker’s fittingSize()

–resize the picker and view accordingly
theView’s setFrameSize:theSize
datePicker’s setFrameSize:theSize

– add the picker to the view
theView’s setSubviews:{datePicker}

– create an alert
set theAlert to current application’s NSAlert’s alloc()’s init()

– set up alert
tell theAlert
  its setMessageText:“Pick a date”
  
its setInformativeText:“Any date”
  
its addButtonWithTitle:“OK”
  
its addButtonWithTitle:“Cancel”
  
its setAccessoryView:theView
end tell

– show alert in modal loop
set returnCode to theAlert’s runModal()
if returnCode = (current application’s NSAlertSecondButtonReturn) then error number -128

– retrieve date
set theDate to ASify from (datePicker’s dateValue()) – or simply coerce to date in 10.11

–>  date “2015年8月20日木曜日 19:43:58″

★Click Here to Open This Script 

2015/08/20 ASOCでスレッド処理?

Cocoaの機能を用いて、NSThreadによる並列処理のテストを行うAppleScriptです。

画像ファイルにCIFilterによるフィルタ処理を行ったのちにリサイズし、仕上げに再度CIFilterによるリサイズを行う・・・そういう処理を書いて、リサイズ前に画像にフィルタをかけるのにはそれなりに時間がかかったため、複数の画像ファイルを同時に並列で処理できるといいんじゃないか、というのがテストを行った趣旨です。

テストに用いたのがsyslogにコメントを残すという処理なので、このテスト用の処理自体があまりふさわしくないのかもしれないですが、期待していたよりも重い感じです。

とりあえず、100個(ぐらい)の画像のリサイズをシーケンシャルに順次処理する場合と、並列で(実行環境に存在するCPUのコア数を鑑みつつ並列数を決定)処理する場合とで、実際に速度を計測してみるとよいと思われます。

AppleScript名:ASOCでスレッド処理?
– Created 2015-08-20 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aThread to current application’s NSThread’s alloc()’s initWithTarget:me selector:“_threadLoop:” object:(current application’s NSString’s stringWithString:“Apple”)

set bThread to current application’s NSThread’s alloc()’s initWithTarget:me selector:“_threadLoop:” object:(current application’s NSString’s stringWithString:“Orange”)

set aRes to current application’s NSThread’s isMultiThreaded()
–>  true

set bRes to current application’s NSThread’s currentThread()
–>  (NSThread) {number = 1, name = main}

set a1Res to current application’s NSThread’s currentThread()’s threadDictionary()
–>  (NSDictionary) {NSAppleEventManagerHandlingStack:{}, NSDocumentsContinuingFileAccess:(NSSet) {}, OSADefaultComponentInstanceKey:(OSAComponentInstance) , OSADefaultLanguageKey:(OSALanguage) , OSAAvailableLanguagesKey:{(OSALanguage) , (OSALanguage) , (OSALanguage) }}

set cRes to current application’s NSThread’s callStackReturnAddresses()
–>  (NSArray) {140735481653180, 140735481652754, 140735559055105, 140735559057361, 4473123264, 4473263701, 4473142396, 4473141941, 4472935365, 4472916653, 140735705914913, 140735481264735, 4400422881, 4400227287, 140735611717816, 140735611717253, 140735611714364, 140735611713043, 140735453174803, 140735453224127, 140735482160121, 140735481878159, 140735481875416, 140735475504495, 140735475503850, 140735475503403, 140735666104491, 140735666101848, 140735666060019, 140735665521220, 140735553762761, 1}

set dRes to current application’s NSThread’s callStackSymbols()
–>  (NSArray) {”0 CoreFoundation 0×00007fff886427bc __invoking___ + 140″, ” …… (omit)

aThread’s setName:“Apple”
bThread’s setName:“Orange”

aThread’s |threadPriority|()
–> 0.5 –(0.0〜1.0)

set c1Res to aThread’s |name|()
–>  (NSString) “Apple”
set c2Res to bThread’s |name|()
–>  (NSString) “Orange”

aThread’s threadDictionary()
–>  (NSDictionary) {}

aThread’s stackSize()
–>  524288 –this depends on each machine’s memory configuration?

aThread’s isExecuting()
–>  false

aThread’s isFinished()
–>  false

aThread’s isCancelled()
–>  false

set noter1 to current application’s NSNotificationCenter’s defaultCenter()
noter1’s addObserver:me selector:“_threadWillExit:” |name|:(current application’s NSThreadWillExitNotification) object:aThread
noter1’s addObserver:me selector:“_threadWillExit:” |name|:(current application’s NSThreadWillExitNotification) object:bThread

aThread’s start()
bThread’s start()

–各Threadが実行するハンドラ
on _threadLoop:aInfo
  repeat 3 times
    set aText to aInfo as text
    
do shell script “logger -s “ & quoted form of aText & ” &”
    
set aNum to random number from 1 to 3
    
delay aNum
  end repeat
end _threadLoop:

–Threadが終了する際に呼ばれるハンドラ
on _threadWillExit:aNotification
  
  
set tmpRes to aNotification’s object’s |name|()
  
say ((tmpRes as text) & ” finished.”) using “Alex”
  
end _threadWillExit:

★Click Here to Open This Script