Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

タグ: NSURLSession

NSURLSessionでREST API呼び出しv4.4.2a

Posted on 4月 3, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。URLキャッシュが効くようになったような気がします。

–> GET method REST API v4.4.1
–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

前バージョンではmacOS 10.15上でクラッシュしないかわりにURLキャッシュが効かないという特徴がありました。ただ、edama2さんと協議した結果、macOS 10.15上でクラッシュする原因と考えられていた内容にあまり根拠がないことがわかってきました(人ごとではなく自分のことなのですが)。

可能な範囲でトライアル&エラーで調査を行なったところ、本バージョンのような処理に落ち着きました。AppleScriptからのCocoa利用については明確にドキュメントがAppleから出ているわけではないので、すでに存在するObjective-Cのプログラムの処理を参考にしつつ、Objective-CからAppleScriptへの置き換えが可能かを検討しています。

URLキャッシュについては、(当然のことながら)処理1回目には効きません。なぜか2回目も効きません。3回目とか4回目あたりから効いていることが実感できる感じです(回数ではなく、前回処理時からの経過時間を見ているのかも? GUIアプリケーションに入れて使うと2回目から効いたりします)。URLキャッシュが効いていない場合には1.5秒ぐらい、URLキャッシュが効き出すと0.02秒ぐらいで結果が返ってきています。

macOS 10.13/14/15で検証を行い、繰り返し処理を行ってもクラッシュしないことを確認しています。ただ、動作保証するというレベルではないので(本Blog掲載のScriptすべてそうですが)、問題があったら知らせてください。

ためしに、Xcode上で作成したGUIベースのAppleScriptアプリケーションに本処理を導入したところ、REST APIへの問い合わせがキャッシュされて著しい高速化を実現できました。

AppleScript名:GET method REST API v4.4.2a_wikipedia.scptd
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-04-03 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLCache : a reference to current application’s NSURLCache
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSOperationQueue : a reference to current application’s NSOperationQueue
property NSURLComponents : a reference to current application’s NSURLComponents
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration
property NSURLRequestReturnCacheDataElseLoad : a reference to current application’s NSURLRequestReturnCacheDataElseLoad

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false
property aSession : missing value
property aCache : missing value

on run
  set retData to missing value
  
set drecF to false
  
set aSession to missing value
  
  
set aQueryKeyTitle to "AppleScript"
  
set aRes to getWikiText(aQueryKeyTitle) of me
  
return aRes
end run

on getWikiText(aQueryKeyTitle)
  set reqURLStr to "https://en.wikipedia.org/w/api.php"
  
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
if aRes = missing value then return false
  
  
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
  
return bRes
end getWikiText

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
–if my aCache = missing value then
  
set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache"
  
set my aCache to NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath
  
–end if
  
NSURLCache’s setSharedURLCache:(my aCache)
  
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
aConfig’s setRequestCachePolicy:(NSURLRequestReturnCacheDataElseLoad)
  
  
aConfig’s setURLCache:(my aCache)
  
  
–どちらでも速度差がない
  
set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(NSOperationQueue’s mainQueue())
  
–set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) is not equal to false then
      exit repeat
    end if
    
delay "0.001" as real
  end repeat
  
  
–delegateの無効化
  
my aSession’s finishTasksAndInvalidate()
  
set my aSession to missing value
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError
  if tmpError = missing value then
    set (my drecF) to true
  else
    error "Donwload Failed"
  end if
end URLSession:task:didCompleteWithError:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in Internet JSON REST API URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSOperationQueue NSString NSURL NSURLCache NSURLComponents NSURLQueryItem NSURLRequestReturnCacheDataElseLoad NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

NSURLSessionでREST API呼び出しv4.4.1

Posted on 4月 2, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。macOS 10.15でクラッシュしないように書き換えています。

–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

前バージョンではmacOS 10.15上でクラッシュするかわりにmacOS 10.14上で高速という特徴がありました。ただ、macOS 10.15上でクラッシュしないように調整を行っていくと、処理速度については別段速くもなく(キャッシュがヒットしていない雰囲気)、よりいっそうキャッシュについて調べる必要が出てきています。

一応、キャッシュの作り方については調べてみたものの、

キャッシュが効いている雰囲気がまったくありません。

キャッシュの内容を確認してみると、からっぽですね(^ー^; もう少し(時間のあるときに)キャッシュの連携などを調べておくといいのかもしれません。最低限、macOS 10.15でクラッシュしなくなったので、NSURLConnectionを呼び出してリジェクトを喰らわないように準備しておくという感じでしょうか。

AppleScript名:GET method REST API v4.4.1_wikipedia.scptd
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-04-02 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false
property aSession : missing value
property aCache : missing value

on run
  set retData to missing value
  
set drecF to false
  
set aSession to missing value
  
  
set aQueryKeyTitle to "AppleScript"
  
set aRes to getWikiText(aQueryKeyTitle) of me
  
return aRes
end run

on getWikiText(aQueryKeyTitle)
  set reqURLStr to "https://en.wikipedia.org/w/api.php"
  
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
if aRes = missing value then return "Error"
  
  
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
  
return bRes
end getWikiText

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
–if my aCache = missing value then
  
set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache"
  
set my aCache to current application’s NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath
  
–end if
  
current application’s NSURLCache’s setSharedURLCache:(my aCache)
  
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set v2 to system attribute "sys2" –> 14
  
if v2 < 15 then
    –macOS 10.14まで
    
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  else
    –macOS 10.15以降。10.15でdefaultSessionConfigurationを使うとクラッシュしやすい???
    
set identifier to "BackgroundSessionConfiguration"
    
set aConfig to NSURLSessionConfiguration’s backgroundSessionConfiguration:(identifier)
  end if
  
  
aConfig’s setRequestCachePolicy:(current application’s NSURLRequestReturnCacheDataElseLoad)
  
  
aConfig’s setURLCache:(my aCache)
  
–aConfig’s setTimeoutIntervalForRequest:0.5
  
–aConfig’s setTimeoutIntervalForResource:timeoutSec
  
–aConfig’s setWaitsForConnectivity:false
  
  
–どちらでも速度差がない
  
set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(current application’s NSOperationQueue’s mainQueue())
  
–set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) is not equal to false then
      exit repeat
    end if
    
delay "0.001" as real
  end repeat
  
  
–aSession’s invalidateAndCancel() –delegateの無効化
  
my aSession’s finishTasksAndInvalidate()
  
set my aSession to missing value
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  set (my drecF) to true
end URLSession:dataTask:willCacheResponse:completionHandler:

on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError
  if tmpError = missing value then
    set (my drecF) to true
  else
    error "Donwload Failed"
  end if
end URLSession:task:didCompleteWithError:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in Internet REST API URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSString NSURL NSURLCache NSURLComponents NSURLQueryItem NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

NSURLSessionでREST API呼び出しv4.4

Posted on 3月 29, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。

–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

従来、NSURLConnectionを使って同期処理を行っていましたが、これがDepreceted扱いになりました。すぐになくなることはありませんが、いつかなくなる可能性があります。

このため、NSURLConnectionから動作原理の異なるNSURLSessionを使うよう移行する必要があります(curlコマンドを利用するというルートもあります)。

とはいえ、blocks構文の使えないAppleScriptでこのNSURLSessionを使えるようにするのは大変です。非同期通信を行うNSURLSessionを非同期処理のしにくいAppleScriptで、同期処理っぽく書かなくてはなりません。

NSURLSessionによる通信では、サーバーとの間で何回かのやりとりがあって、データを小分けに複数回受信する必要がありました。NSMutableDataというオブジェクトの存在を知ったのでいい感じに処理できるようになってきました。

NSURLSessionのメリットとして喧伝されている非同期処理は、AppleScriptから呼び出しているかぎりはそれほどメリットになりません。もう少し使い込めば活用できるかもしれませんが、まだそういう段階にはありません。

NSURLSessionの導入によって得られるメリットで最大のものは、キャッシュ機構です。NSURLConnectionでもキャッシュ機構は利用できましたが、NSURLSessionではよりAPIに深く統合されているものと理解しました。

キャッシュの効き方については、設定で何段階かに設定できるとAppleのオンラインドキュメントに書かれています。本Scriptでは、キャッシュ優先でキャッシュが存在している場合にはキャッシュ内のデータを返し、キャッシュが存在していない場合にはWebサーバーに問い合わせを行うように設定しています。

キャッシュが効いている状況なら、NSURLConnectionで1.8秒ぐらいの処理がNSURLSessionで0.1秒程度と大幅に速く処理できます。キャッシュが効いていない状況(初回実行時)だと、NSURLSessionのほうがやや処理に時間がかかるぐらいです。

処理結果について、NSURLConnection版とNSURLSession版で結果の比較を行ってみましたが、とくに差異は見られませんでした。

本サンプルScriptでは、Wikipedia(英語版)へのキーワードの問い合わせを行います。NSURLConnection版では複数回実行しても同じぐらいの速度で実行されますが、NSURLSession版では2度目から早く終わります(Script Debugger上で動かすと秒以下の精度の時間がわかります)。

macOS 10.14上で作ってmacOS 10.14.6/10.13.6上で動作確認しています(スクリプトエディタ、Script Debuggerで動作確認)。ただし、macOS 10.15上だとクラッシュします。Xcodeのプロジェクトに入れてみましたが、同様にmacOS 10.15上ではクラッシュします。

ただし、自分のmacOS 10.14.6環境はSIP解除しているのと、macOS 10.15環境のクラッシュログにSIP関連のメッセージが残っているので、OSバージョンではなくSIPのためかもしれません(macOS 10.14.6でもSIPを有効にするとクラッシュするかもしれない & macOS 10.15.xでもSIPを無効にするとクラッシュしないかもしれない)。

AppleScript名:GET method REST API v4.4_wikipedia
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-03-29 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false

set aQueryKeyTitle to "Steve Jobs" –キーワードの正規化が必要("戦場の絆"→"機動戦士ガンダム 戦場の絆" )
set reqURLStr to "https://en.wikipedia.org/w/api.php"
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
return bRes

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
aConfig’s setRequestCachePolicy:(current application’s NSURLRequestReturnCacheDataElseLoad)
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (10 * timeoutSec) times
    if (my drecF) = true then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession dataTask:tmpTask didCompleteWithError:tmpError
  set (my drecF) to true
end URLSession:dataTask:didCompleteWithError:

on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  set (my drecF) to true
end URLSession:dataTask:willCacheResponse:completionHandler:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as {list, missing value}
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

AppleScript名:GET method REST API_wikipedia
— Created 2016-03-03 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aQueryKeyTitle to "Steve Jobs" –キーワードの正規化が必要("戦場の絆"→"機動戦士ガンダム 戦場の絆" )
set reqURLStr to "https://en.wikipedia.org/w/api.php"
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
set aRESTres to json of aRes
set bRes to (aRESTres’s valueForKeyPath:"parse.wikitext.*") as string

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL, timeoutSec)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to (dRes’s statusCode()) as integer
  
  
–Get Response Header
  
set resHeaders to (dRes’s allHeaderFields()) as record
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as list
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

Posted in Internet REST API URL | Tagged 10.13savvy 10.14savvy NSArray NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSPredicate NSString NSURL NSURLComponents NSURLQueryItem NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 2 Comments

URLにリソースが存在するかチェック v5(NSURLSession)

Posted on 5月 24, 2019 by Takaaki Naganoya

指定URLの存在確認を行うAppleScriptです。

以前はNSURLConnectionを使って確認するものを使っていましたが、NSURLSessionへと移行しようかというところ。

もちろん、shellのcurlコマンドを使えば数行で済んでしまいますが、そこをあえてCocoaの機能を利用して、というよりはちょっと前に書いたREST API呼び出しのサブルーチンが絶好調で動いているので、これをそのまま流用してみました。

ライブラリ化して自分のScriptのバンドル内に入れておくとか、~/Library/Script Librariesフォルダに入れておくとか、そういう使い方になると思います。自分でもわざわざこれだけの機能のために、これだけの量のコードをゼロから書くことは……めったにありません。

AppleScript名:URLにリソースが存在するかチェック(curl版)_v2
set aURL to "http://www.apple.com/jp/"
set aRes to chekURLExistence(aURL) of me

on chekURLExistence(aURL)
  try
    set aRes to do shell script ("/usr/bin/curl -LI " & aURL)
  on error
    return false
  end try
  
return ((aRes contains "HTTP/1.1 200") or (aRes contains "HTTP/2 200")) as boolean
end chekURLExistence

★Click Here to Open This Script 

AppleScript名:URLにリソースが存在するかチェック v5(NSURLSession)
— Created 2019-05-24 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false

set aURL to "http://piyocast.com/as/"
set uRes to chekURLExistence(aURL) of me
–> true

on chekURLExistence(aURL as string)
  set webRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
return ((retCode of webRes) as integer = 200)
end chekURLExistence

— 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on callRestGETAPIAndParseResults(reqURLStr as string, timeOutSec as real)
  set (my retData) to false
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
set hitF to false
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeOutSec) times
    if (my drecF) = true then
      set hitF to true
      
exit repeat
    end if
    
delay ("0.001" as real)
  end repeat
  
  
if hitF = false then error "REST API Timeout Error"
  
  
return {retData:retData, retCode:retCode, retHeaders:retHeaders}
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  parseSessionResults(tmpSession, tmpTask, tmpData) of me
  
set (my drecF) to true
end URLSession:dataTask:didReceiveData:

–ないとエラーになるので足した。とくに何もしていない
on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  —
end URLSession:dataTask:willCacheResponse:completionHandler:

on parseSessionResults(aSession, aTask, tmpData)
  set aRes to aTask’s response()
  
set (my retCode) to aRes’s statusCode()
  
set (my retHeaders) to aRes’s allHeaderFields()
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set (my retData) to aJsonDict as anything
end parseSessionResults

★Click Here to Open This Script 

Posted in Network Record URL | Tagged 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableURLRequest NSString NSURL NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | Leave a comment

GET method REST API v4.3

Posted on 5月 1, 2019 by Takaaki Naganoya

クラウド系のサービスを呼び出すためのAPIとして一般的なREST APIを呼び出すAppleScriptの最新版(のスケルトン)です。

# v4.2からv4.3にバージョンアップしました(2019/05/02)

macOS 10.10でほぼすべてのAppleScriptランタイムでCocoaの機能が利用できるようになったため、Cocoaの機能を利用してクラウド系サービスを呼び出すことを、割と早い時期から調査していました。

「ほぼすべて」と書いているのは、アプリケーション内蔵のScript Menu(iTunesとか)や、Folder Actionなどの独特なランタイム、あるいはMessages(旧称iChat)のメッセージ受信イベントから呼び出されるAppleScriptランタイムなど、それぞれのアプリケーション独自で実装している処理系についてはCocoaの機能が使えるかどうかは保証のかぎりではないからです。

明確に、当初からクラウドと機械学習をAppleScriptから利用するために、苦労してCocoaの機能を追いかけてきたわけです。その途中でいろいろサードパーティのFrameworkを呼び出せたりして、期待よりも大きな成果を手にしている昨今です。OSの内部機能を直接利用できることのメリットは、処理速度や詳細な情報取得など枚挙にいとまがありません(日本語の慣用句表現なので翻訳しにくいかも?)。

話をクラウドにもどしましょう。REST APIを呼び出すには、同期で実行されるNSURLConnectionを使うのが最も簡単で確実でした。

しかし、同APIは非推奨(近い将来に廃止される)という位置付けになったため、その代わりを探す必要に迫られました。すでにNSURLConnectionを用いて記述したREST API呼び出しのScriptが大量に存在していたからです。

代替APIとしてNSURLSessionが提示されましたが、こちらは非同期実行のみで同期実行モードはありません。いろいろ実験してみたものの、数回に1回ぐらい、サーバーからの応答をつかまえ損ねることがあり、処理時間もNSURLConnection版より長くかかります。

このため、「do shell script経由でcurlコマンドを使って回避するか?」といった回避策を検討していたところです。

そんな中、冗談半分でNSURLSessionを利用したバージョンをほんの少し修正してみたところ、いままでの不安定さが嘘のように安定して結果を得られるようになってきました。これはいい兆候です。

ただし、同時に問題点も見つかってきました。macOS標準装備のScript Editor上で実行する分には問題ないのですが、Script Debugger上で実行すると、macOS 10.12/10.13/10.14共通でサーバーからの応答を取得できず、タイムアウトエラーになります。

初回掲載時(v4.2)にはScript Debugger上でデータ受信を検出できないという問題がありました。データの受信用のプロパティがmissing valueでなければデータを受信した、という判定ロジックがうまく動いていない(どういう仕組みかはわからないものの、missing valueと判断され続けた? ラベル値とproperty名でコンフリクト起こしたかも?)現象が見られました。そこで、データの受信プロパティとデータ受信完了検出のプロパティを明確に分けて判定してみたところ、Script DebuggerやmacOS 10.14上でも問題なく動作することを確認しました。

AppleScript名:GET method REST API v4.3
— Created 2019-05-01 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false

set reqURLStr to "http://jsonplaceholder.typicode.com/posts"
set aRESTres to callRestGETAPIAndParseResults(reqURLStr, 10) of me
–return retData of aRESTres

set aRESTcode to retCode of aRESTres
–return aRESTcode
–> 200

return retHeaders as record
–> {|content-type|:"application/json; charset=utf-8", Pragma:"no-cache", |x-powered-by|:"Express", |set-cookie|:"__cfduid=dd8b4572e0a59951cc7cf7a1120c368541554964103; expires=Fri, 10-Apr-20 06:28:23 GMT; path=/; domain=.typicode.com; HttpOnly", Server:"cloudflare", Via:"1.1 vegur", |content-encoding|:"gzip", Expires:"Wed, 01 May 2019 15:27:42 GMT", |cf-cache-status|:"HIT", |transfer-encoding|:"Identity", |cache-control|:"public, max-age=14400", |date|:"Wed, 01 May 2019 11:27:42 GMT", |access-control-allow-credentials|:"true", Connection:"keep-alive", |cf-ray|:"4d016861ac759413-NRT", Etag:"W/\"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM\"", Vary:"Origin, Accept-Encoding", |x-content-type-options|:"nosniff"}

on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to false
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
set hitF to false
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) = true then
      set hitF to true
      
exit repeat
    end if
    
delay ("0.001" as real)
  end repeat
  
  
if hitF = false then error "REST API Timeout Error"
  
  
return {retData:retData, retCode:retCode, retHeaders:retHeaders}
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  parseSessionResults(tmpSession, tmpTask, tmpData) of me
  
set (my drecF) to true
end URLSession:dataTask:didReceiveData:

–ないとエラーになるので足した。とくに何もしていない
on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  —
end URLSession:dataTask:willCacheResponse:completionHandler:

on parseSessionResults(aSession, aTask, tmpData)
  set aRes to aTask’s response()
  
set (my retCode) to aRes’s statusCode()
  
set (my retHeaders) to aRes’s allHeaderFields()
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set (my retData) to aJsonDict as list of string or string –as anything
end parseSessionResults

★Click Here to Open This Script 

Posted in REST API URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableURLRequest NSString NSURL NSURLSession NSURLSessionConfiguration | 3 Comments

note.muで指定のユーザーのノートを取得する

Posted on 7月 22, 2018 by Takaaki Naganoya

note.muの非公開REST API(でも、みんな知っている)を呼び出して、指定ユーザーのノート(投稿記事)を取得するAppleScriptです。

使い慣れたNSURLConnectionがmacOS 10.11で非推奨APIになって久しく、頻繁に使っているREST API呼び出し処理がいきなり動かなくなるのは困るため、NSURLSessionを用いてREST APIを呼び出すよう徐々に変更しています。

当初、REST APIの呼び出し部分は共通ルーチン化して、さまざまなREST APIを共通ルーチンで処理できるとよいだろうかと思っていました。実際にさまざまなREST APIを呼び出してみると、APIごとに意外なほど癖があって、なかなか「すべてのREST APIの共通処理ルーチン」というところまで共通化する段階までには至っていないところ。

左がNSURLSessionを用いた呼び出し、右がNSURLConnectionを用いた呼び出しを行なったものです。せっかくNSURLSessionを使ってみてはいるものの、同一の処理でもNSURLConnectionの方が40%ぐらい高速です。同一ネットワーク環境(iPhone経由のテザリング接続)でNSURLConnectionが0.4秒ぐらい、NSURLSessionでだいたい0.5から0.7秒といったところ。有線ネットワーク接続だともう少し速度が改善するかもしれません。

NSURLSessionに明示的な同期処理が存在しないため、NSURLSessionが受けわたすdelegateイベントをAppleScript側でループしつつ待っており、NSURLConnectionで素直に同期処理メソッドを呼び出すよりもオーバーヘッドが大きくなっているものと推測しています。

NSURLSessionでREST APIを呼び出すあたりの処理をまるごと独立したFrameworkにでも追い出すとよいのではないか、といったところです。

AppleScript名:(GET)指定のユーザーのノート v2
— Created 2018-06-16 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value

set retData to missing value

set reqURLStr to "https://note.mu/api/v1/notes"
set aRec to {urlname:"140software"} –note ID
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRESTres to callRestGETAPIAndParseResults(aURL) of me

on callRestGETAPIAndParseResults(reqURLStr)
  set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:10
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat 10000 times
    if retData is not equal to missing value then exit repeat
    
current application’s NSThread’s sleepForTimeInterval:("0.001" as real) –delay 0.001
  end repeat
  
  
retData
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  set aStat to (tmpTask’s state()) as list of string or string
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set retData to aJsonDict as list of string or string
end URLSession:dataTask:didReceiveData:

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in JSON list REST API URL | Tagged 10.11savvy 10.12savvy 10.13savvy NSJSONSerialization NSMutableURLRequest NSString NSURL NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • macOS 13, Ventura(継続更新)
  • アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3
  • UI Browserがgithub上でソース公開され、オープンソースに
  • Xcode 14.2でAppleScript App Templateを復活させる
  • macOS 13 TTS Voice環境に変更
  • 2022年に書いた価値あるAppleScript
  • ChatGPTで文章のベクトル化(Embedding)
  • 新発売:AppleScriptからSiriを呼び出そう!
  • iWork 12.2がリリースされた
  • 従来と異なるmacOS 13の性格?
  • 新発売:CotEditor Scripting Book with AppleScript
  • macOS 13対応アップデート:AppleScript実践的テクニック集(1)GUI Scripting
  • AS関連データの取り扱いを容易にする(はずの)privateDataTypeLib
  • macOS 13でNSNotFoundバグふたたび
  • macOS 12.5.1、11.6.8でFinderのselectionでスクリーンショット画像をopenできない問題
  • ChatGPTでchatに対する応答文を取得
  • 新発売:iWork Scripting Book with AppleScript
  • Finderの隠し命令openVirtualLocationが発見される
  • macOS 13.1アップデートでスクリプトエディタの挙動がようやくまともに
  • あのコン過去ログビューワー(暫定版)

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1390) 10.14savvy (586) 10.15savvy (434) 11.0savvy (277) 12.0savvy (185) 13.0savvy (55) CotEditor (60) Finder (47) iTunes (19) Keynote (98) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (56) Pages (37) Safari (41) Script Editor (20) WKUserContentController (21) WKUserScript (20) WKUserScriptInjectionTimeAtDocumentEnd (18) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC