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

タグ: 10.13savvy

Xcode上で作成したアプリケーション上でDark Mode検出

Posted on 4月 22, 2020 by Takaaki Naganoya

Xcode上で作成したAppleScriptアプリケーションでDark Modeの検出を行いたいときに、NSAppearance’s currentAppearance()で取得したら、正しくModeの検出が行えませんでした。同じコードをスクリプトエディタ/Script Debugger上で動かした場合には正しくModeの判定が行えているのですが。

そこで、System Eventsの機能を用いてMode判定を行うように処理を書き換えたりしてみたのですが、Mac App Storeに出すアプリケーションでこの処理を記述していたら、これを理由にリジェクトされてしまいました。

仕方なく解決策を探してみたところ、macOS 10.13用に書いたshell scriptによる迂回処理を、そのまま他のOSバージョンでも動かせばよいのではないかと気づき、結局そこに落ち着きました。

AppleScript名:Dark Modeの検出(Xcode上でも正しく判定)
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/04/22
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set apRes to retLightOrDark() of me
–> true (Dark), false (Light)

on retLightOrDark()
  try
    set sRes to (do shell script "defaults read -g AppleInterfaceStyle")
    
return (sRes = "Dark") as boolean
  on error
    return false
  end try
end retLightOrDark

★Click Here to Open This Script 

Posted in shell script System | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Sandbox環境で封じられる処理

Posted on 4月 22, 2020 by Takaaki Naganoya

ふだん、AppleScriptの処理はOSによる制約の少ない環境で処理を行っています。サンドボックスによる制約がない、あるいはきわめて少ない環境であるといえます。

そうした自由な環境に慣れていると、Sandbox環境下で(Xcode上で)アプリケーションを作成したときに、あっと驚く制約が存在していて驚かされることが多々あります。

他のアプリケーションを操作するScriptは書き込み禁止に

Sandbox環境下では、他のアプリケーションを操作するAppleScriptについては、実行専用形式で保存したうえでファイル書き込み不可の状態にしておく必要があります。Scriptのプロパティ(resultもプロパティ)を書き換えられてはいけないので、この措置が必要になります。Sandbox環境ではこのプロパティの書き換えが、自己書き換えと判定され、禁則事項に該当してしまうためです。

ファイルの新規保存時のchoose file nameコマンド(+拡張子追加)が抵触

ファイルの新規保存時にchoose file nameコマンドで保存先のパス+ファイル名をユーザーに指定させるような処理を行っています。このときに、ファイルの拡張子が指定されていない場合には、choose file nameから返ってきたパスを文字列に変換して、拡張子を文字列で追加するような処理もよく行っています。

これが、Sandbox環境下では禁じ手になります。

最初に遭遇したときには「意味がわからない!」と、イラつきまくりましたが、落ち着いて考えつつ追試を行ってみたところ理解できました。

Sandbox化したアプリケーションでファイル保存を行うためには、Xcode上でentitlementsファイルを編集し、「com.apple.security.files.user-selected.read-write」といったエントリに「YES」を設定しておくことになります。ユーザーが選択したファイルの読み書きを許可するという設定です。

このとき、choose file nameコマンドで入力されなかった拡張子の部分をAppleScript側で勝手に補ってしまうと、「ユーザーが指定したファイル」以外のファイルを処理することになるわけで、(拡張子を文字列操作で補ったようなパスは)ファイル保存することができませんでした。

そこで、NSSavePanelを用いてファイル保存ダイアログを作成する必要に迫られます。事前に補うべき拡張子の情報を渡してダイアログ表示を行うので、ユーザーが拡張子まで入力しなくても、拡張子がついたファイルパスが返ってきます。

ほかにもいろいろありますが、作成するAppleScriptのプログラム全体の数から見ると、Sandbox環境下で動かすAppleScriptはごく一部であるため、あまりノウハウが蓄積されていません。たまーにSandboxの制約に抵触して驚かされるといったところでしょうか。

Posted in How To Sandbox | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

新型アプリケーション「Kamenoko」をMac App Storeレビューに提出

Posted on 4月 21, 2020 by Takaaki Naganoya

本Blogにちょくちょく、その作例を掲載している6角形図形を組み合わせた図でアイデアを練るソフトウェア「Kamenoko」をMac App Storeのレビューに送信しました。2作目なので、レビューの概要もわかっており(1発で通ることはないので)前回のように却下に対して24時間即時対応、みたいな体勢にはしていません。しばらくApp Storeの審査とやりとりする必要があることを理解しています(1週間ぐらいでしょうか)。

目下App Store系の審査の担当者の人数が少ないために審査にかかる時間が長くなっているとの噂がありますが、これまでもMac App Storeの審査は時間がかかっていたので(前回1か月かかったし)、そんなもんだと思っています。

このKamenoko v1.0はAppleScriptからのスクリプティングには対応していません。ただ、中身はほとんど(99.9%)AppleScriptで書いてあるので、対応は難しくはありません。

難しくはないものの、このアプリケーションはAppleScriptによって操作してもあまり意味がないので(アイデアを練るためのアプリケーション)、書類の作成とか書類の内容取得、書類の内容変更などが行えるライブラリをアプリケーションに同梱する方向でAppleScriptサポート機能の実装を検討しています。

■リジェクト1発目

System Eventsを呼んでいることを問題視されているようです。当初、このアプリケーションでSystem Eventsを呼び出す必要はなかったのですが、Dark Modeの検出がmacOS 10.13でうまく働かなかったので、System EventsでDark Modeの検出を行わせるようにしていました。

Mac App Storeのレビューでは、指摘事項同士の矛盾については考慮されていません。(A)という指摘をされたので(B)という対応をしたら、説明の仕方を変更するだけで実は(A)の状態のままでよかった、ということがままあります。また、アプリケーション全体で複数の指摘項目があったとしても、1回のレビューで指摘されるのはだいたい1項目だけです。

なので、1項目の指摘事項があったので即時修正したとしても、さみだれ式に次々と指摘事項が(枝葉末節の問題から、徐々にセキュリティ系の事項へと)上がってくるものなので、「そういうもんだ」と割り切っていないとやりきれません。

System Eventsに依存しないAppearanceの判定を行わせると、macOS 10.13でDark Modeの検出ができなくなる可能性があり、macOS 10.13でDark Modeの検出ができなくなると、macOS 10.13対応が不適切であるという指摘が未来のタイミングで行われ、結局macOS 10.13対応を行うためにはSystem Eventsを呼ぶしかなかった、という結論に落ち着きそうな感じがとっても嫌な雰囲気です。

ただ、これまで1発目のレビュー(リジェクト)とかいうと、10分ぐらいであっという間に終わっていたので(溢れる「流れ作業」感)、1時間もかかったのは新記録ではないでしょうか。お茶飲みながらの1時間かもしれませんけれども。

■リジェクト2発目(2020/5/1)

のちのちのバージョンでやりたい(実現できるとは言っていない)機能のために宣言しておいたEntitlementsが、アプリケーションの機能に存在していないので却下、と判断されました。

あれ? AppleのWeb側にもXcode上にもそんな設定は(残ってい)ないのですがー(ーー;;;

Posted in PRODUCTS | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

プログラムで作ったアラートダイアログ上のTextViewをフォーカスする

Posted on 4月 14, 2020 by Takaaki Naganoya

AppleScriptでダイナミックに(動的に)生成したアラートダイアログ上にテキストビューを生成し、そのテキストビュー上にテキスト入力用のキャレットを移動させる(フォーカスする)AppleScriptです。

Xcode上でAppleScriptでGUIアプリケーションを作っていて、文字サイズの大きなテキスト入力フィールドを動的に生成。さらに、テキスト入力フィールドにテキスト入力用のキャレットを移動させようとして、割と手こずっていました。

テキスト入力を受け付けるGUI部品に対して、入力フォーカスを与え、テキスト入力のキャレットが置かれた状態を再現するには、GUIの画面上からはマウスカーソルでクリック操作するとできます。同じ状態をプログラム側から作る場合にはFirstResponderにセットするという処理になります。

この、FirstResponderに指定することは理解でき、Xcode(Interface Builder)上で配置した部品に対して実行する処理は昔からやっています。NSTextFieldに強制的に入力フォーカスを置いた上でバーコードリーダーからのテキスト入力を受け付けるといった処理です。

一方、プログラムから動的に生成したGUI部品に対して、Cocoaが用意しているAPIのどれを用いて、どのように指定すべきなのかで困りました。

親WindowのFirstResponderにしてみたり、アラートウィンドウのFirstResponderにしてみたり、いろいろ試した末に、

parentWin's setInitialFirstResponder:aView

で、Alert DialogのWindowをparentWinに、alert dialog上のテキストビューをaViewに代入した状態で実行して、入力キャレットをテキストビュー上に移動できました。本Xcode Projectは上記の1行の記述の検証を行うためのテストプロジェクトです。

–> Download Xcode Project

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— dialogCarret
—
— Created by Takaaki Naganoya on 2020/04/14.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
property NSFont : a reference to current application’s NSFont
  
property NSView : a reference to current application’s NSView
  
property NSAlert : a reference to current application’s NSAlert
  
property NSColor : a reference to current application’s NSColor
  
property NSTextView : a reference to current application’s NSTextView
  
property NSScrollView : a reference to current application’s NSScrollView
  
property NSRunningApplication : a reference to current application’s NSRunningApplication
  
  
— IBOutlets
  
property theWindow : missing value
  
  
property returnCode : 0
  
property resStr : ""
  
  
  
on applicationWillFinishLaunching:aNotification
    —
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:sender
    set tmpStr to "TEST"
    
set paramObj to {myMessage:"Input Text", mySubMessage:"", mes1:(tmpStr), mesWidth:400, mesHeight:200}
    
my performSelectorOnMainThread:"dispTextViewWithAlertdialog:" withObject:paramObj waitUntilDone:true
    
set aResText to (my resStr) as string
    
    
display dialog aResText
  end clicked:
  
  
on dispTextViewWithAlertdialog:paramObj
    –Receive Parameters
    
set aMainMes to (myMessage of paramObj) as string –Main Message
    
set aSubMes to (mySubMessage of paramObj) as string –Sub Message
    
set mesStr to (mes1 of paramObj) as string –Text Input field 1 Label
    
set aWidth to (mesWidth of paramObj) as integer –TextView width
    
set aHeight to (mesHeight of paramObj) as integer –TextView height
    
    
set vNum to system attribute "sys2"
    
if vNum > 13 then
      set apRes to retLightOrDark() of me
      
if apRes = true then
        set textColor to (current application’s NSColor’s cyanColor())
      else
        set textColor to (current application’s NSColor’s blackColor())
      end if
    else
      set textColor to (current application’s NSColor’s blackColor())
    end if
    
    
    
— Create a TextView with Scroll View
    
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
    
set aView to NSTextView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
    
aView’s setDelegate:me
    
aView’s setRichText:true
    
aView’s useAllLigatures:true
    
aView’s setTextColor:textColor
    
aView’s setFont:(current application’s NSFont’s systemFontOfSize:90.0)
    
set aColor to current application’s NSColor’s colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.1
    
    
aView’s setBackgroundColor:aColor
    
aView’s setString:mesStr
    
aScroll’s setDocumentView:aView
    
aView’s enclosingScrollView()’s setHasVerticalScroller:true
    
    
— set up alert
    
set theAlert to NSAlert’s alloc()’s init()
    
tell theAlert
      its setMessageText:aMainMes
      
its setInformativeText:aSubMes
      
its addButtonWithTitle:"OK"
      
–its addButtonWithTitle:"Cancel"
      
its setAccessoryView:aScroll
      
set parentWin to its |window|()
    end tell
    
    
parentWin’s setAlphaValue:0.8
    
–parentWin’s setOpaque:(false)
    
parentWin’s setLevel:(current application’s NSScreenSaverWindowLevel)
    
    
parentWin’s setInitialFirstResponder:aView —Place Input Carret to Alert Dialog
    
    
— show alert in modal loop
    
NSRunningApplication’s currentApplication()’s activateWithOptions:0
    
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
    
    
if (my returnCode as number) = 1001 then
      —
    else
      set my resStr to aView’s |string|()
    end if
  end dispTextViewWithAlertdialog:
  
  
  
on doModal:aParam
    set (my returnCode) to aParam’s runModal()
  end doModal:
  
  
  
on retLightOrDark()
    return true
  end retLightOrDark
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode dialog How To | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSColor NSFont NSMakeRect NSRunningApplication NSScrollView NSTextView | Leave a comment

システムフォントの名称を取得

Posted on 4月 13, 2020 by Takaaki Naganoya

システムフォントの名称を取得するAppleScriptです。

GUIベースのアプリケーションを作っているときに、「もう、無難なフォントなんでもいいからとりあえず指定できるものがあれば指定しておこうよ」という局面はあります。ないフォントを指定するとクラッシュすることもあるので、とりあえずコレ指定しておけば大丈夫だから!

という「安全パイ」のフォントとしてSystem Fontを取得&指定したいという時に書いたScriptでもあります。プログラム内容がつまらない割には、切実なニーズを満たすためのものです。

AppleScript名:システムフォントの名称を取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/04/06
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set aFont to current application’s NSFont’s systemFontOfSize:24.0
set aInfo to aFont’s fontDescriptor()
set aSize to (aInfo’s pointSize()) as real
set aPSName to (aInfo’s postscriptName()) as string
–> ".SFNSDisplay"

set bFont to current application’s NSFont’s boldSystemFontOfSize:24.0
set bInfo to bFont’s fontDescriptor()
set bSize to (bInfo’s pointSize()) as real
set bPSName to (bInfo’s postscriptName()) as string
–> ".SFNSDisplay-Bold"

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Font | Tagged 10.13savvy 10.14savvy 10.15savvy NSFont | Leave a comment

NSFontPanelでフォントを選択

Posted on 4月 7, 2020 by Takaaki Naganoya

自前でメニューを作ってフォントおよびサイズの選択を行おうとするとめんどくさい(時間がかかるし管理も大変)ので、NSFontPanelを用いてフォントを選択する試作品を作ってみました。

ただし、まだ完全ではなく「1つ前の状態が取得できる」という状態なので、修正が必要です。作成はmacOS 10.14.6+Xcode 11.3.1上で行っています。

–> Download Xcode Project

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— fontPanel
—
— Created by Takaaki Naganoya on 2020/03/12.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theField : missing value
  
  
property aFontNameField : missing value
  
property aFontSizeField : missing value
  
  
property aFontManager : missing value
  
  
property font : missing value
  
property aFP : missing value
  
  
on applicationWillFinishLaunching:aNotification
    set aFontManager to current application’s NSFontManager’s sharedFontManager()
    
aFontManager’s setAction:"appSpecificChangeFont:"
    
set aFP to current application’s NSFontPanel’s sharedFontPanel()
    
set aFont to current application’s NSFont’s fontWithName:"Helvetica" |size|:16
    
aFontManager’s setSelectedFont:aFont isMultiple:false
    
    
theField’s setStringValue:"ぴよまるソフトウエア, Piyomaru Software"
  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:aSender
    theWindow’s makeFirstResponder:theField
    
aFP’s makeKeyAndOrderFront:me
  end clicked:
  
  
on appSpecificChangeFont:sender
    set aSelFont to sender’s selectedFont()
    
set aDesc to aSelFont’s fontDescriptor()
    
set aPSID to (aDesc’s postscriptName()) as string
    
set aSize to (aDesc’s pointSize()) as real
    
theField’s setFont:aSelFont
    
aFontNameField’s setStringValue:aPSID
    
aFontSizeField’s setStringValue:(aSize as string)
  end appSpecificChangeFont:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode Font | Tagged 10.13savvy 10.14savvy 10.15savvy NSFont NSFontManager NSFontPanel | 1 Comment

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

マウスカーソルを変更

Posted on 3月 24, 2020 by Takaaki Naganoya

Xcode上で記述するAppleScriptアプリケーションにおいて、マウスカーソルを変更するAppleScriptです。

NSCursorにアクセスして、macOS側で用意しているカーソルにマウスカーソルのイメージを変更します。

–> Watch Demo Movie

あらかじめmacOSが用意しているカーソルはいくつかあるわけですが、これで満足するわけがなくて……任意のNSImageをカーソルに指定する方法について調べていたものの、なかなかうまくいかなかったので、このOS側で用意しているカーソルへの切り替えのみまとめておきました。

–> Download Xcode Project

他のアプリケーションに切り替えると通常のカーソルに戻ってしまうので、本プロジェクト側でアプリケーション切り替えのイベントハンドラでカーソルの再変更などを行うべきなのかも。

  set aImage to current application's NSImage's  imageNamed:(current application's NSImageNameComputer)
  set tmpCursor to current application's NSCursor's alloc()'s initWithImage:aImage hotSpot:{0,15}
tmpCursor's |set|()

結局、コンピュータのアイコンをマウスカーソルに指定するというところまでは持って行けた(カーソル画像の差し替えができた)わけなんですが、NSCursorの挙動を評価してみたら、カーソルが標準のものに戻るタイミングがバラバラ(他のディスプレイにカーソルが移動したとき、というわけでもない)で、挙動が謎すぎであります。

その後、対象のビュー(NSViewなど、その派生クラス)にマウスカーソルが入った/出たことを検出するイベントハンドラでマウスカーソルの形状変更を明示的に指定するような実装で落ち着きました(Edama2さんから教えていただきました。ありがとうございます)。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— CursorTest
—
— Created by Takaaki Naganoya on 2020/03/24.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : 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 NSTerminateNoww
  end applicationShouldTerminate:
  
  
on clicked:aSender
    set aTag to (aSender’s tag) as integer
    
if aTag = 100 then
      current application’s NSCursor’s arrowCursor()’s |set|()
    else if aTag = 101 then
      current application’s NSCursor’s disappearingItemCursor()’s |set|()
    else if aTag = 102 then
      current application’s NSCursor’s contextualMenuCursor()’s |set|()
    else if aTag = 103 then
      current application’s NSCursor’s openHandCursor()’s |set|()
    end if
  end clicked:
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode System | Tagged 10.13savvy 10.14savvy 10.15savvy NSCursor NSImage | Leave a comment

指定画像をICNSに変換

Posted on 3月 19, 2020 by Takaaki Naganoya

指定画像をICNS書類に変換するAppleScriptです。

ICNS書類自体は、Classic Mac OS時代にあったアイコンの画像リソースである「icn#」リソースをファイル化したもの、と理解しています(位置付け的に、データ形式とか厳密なレベルで比較したわけではなくて)。

現在では、ICNS書類を作ってアプリケーションアイコンに指定したり、

Xcode上で解像度の異なる画像ファイルをドラッグ&ドロップすると、アプリケーションのICNSファイルを作ってくれます。

Finder上で解像度の異なる画像をフォルダ構造に入れてフォルダの拡張子をつけかえるだけでICNSと認識してくれたような記憶もあります。

そのため、ICNS書類をわざわざScriptから作る需要もないだろうと考えて掲載してこなかったのですが、意外なところでICNS書類の作成を求められました。

自作アプリケーションのカスタム書類を定義して、書類にカスタムアイコンをつけようとしたところ、PNGなどの画像では認識されず、結局ICNS書類を指定する必要に迫られました(意外)。

そんなわけで、いろいろICNS作成Scriptをまとめておきました。

こちらのScriptは実際には実行していませんが、/usr/bin/tiff2icnsコマンドがmacOS 10.15にも含まれていることを確認しています。

AppleScript名:TIFF画像をicnsに変換 v2scpt
tell application "Finder"
  set a to choose file
end tell
set theTiffPath to POSIX path of a
–128 x 128のtiff画像が必要
do shell script "/usr/bin/tiff2icns -noLarge " & (quoted form of theTiffPath)

★Click Here to Open This Script 

こちらは、オープンソースの「IcnsFactory」をフレームワーク化したIconFactory.frameworkを呼び出すバージョンです。自分が実際に使ったのはこちらです。

macOS 10.14以降ではScript Debugger上で実行するか、Script Debuggerから書き出したアプレット(Application(Enhanced))で実行するか、あるいはMacのSIPを解除して実行するなどの方法で実行できます。

Xcode上のAppleScript Applicationプロジェクトに突っ込んで呼び出せば、SIPの解除やScript Debuggerのインストールは必要ありません。

–> Download iconFactory.framework

AppleScript名:画像をICNS書類に
— Created 2017-04-14 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "IconFactory" –https://github.com/kgn/IcnsFactory

set aFile to POSIX path of (choose file)
set outFile to POSIX path of (choose file name)
set anImage to current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile
set iconFam to current application’s IcnsFactory’s writeICNSToFile:outFile withImages:anImage

★Click Here to Open This Script 

Posted in file Image | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

WebKit Utilities v2

Posted on 3月 16, 2020 by Takaaki Naganoya

AppleScriptで指定URLのページを表示する「WebKit Utilities」がmacOS 10.13以降の環境で動かなくなっていたので、書き換えて動くようにしておきました。

–> Download WebKit Utilities_archive v2

これ自体が役に立ったということはなく、単にAppleScript Librariesの書き方のサンプルと理解しています。Webサイトの表示を行うよりも1枚ものの画像やPDFにレンダリングする処理のほうがバッチ処理の中では相性がいいと思います。

また、このScriptはWkWebViewではなく古いWebViewを使っているので、じきに動かなくなります。

AppleScript名:WebKit Utilitiesで指定URLをウィンドウ表示
— Created 2017-03-24 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use webLib : script "WebKit Utilities"

set targetURL to "http://www.piyocast.com/"
display URL targetURL window size {1024, 1024}

★Click Here to Open This Script 

AppleScript名:WebKit Utilities
— An example AppleScript/Objective-C library that uses the WebKit framework.

use AppleScript
use framework "AppKit"
use framework "WebKit"

property NSURL : a reference to current application’s NSURL
property WebView : a reference to current application’s WebView
property NSScreen : a reference to current application’s NSScreen
property NSThread : a reference to current application’s NSThread
property NSWindow : a reference to current application’s NSWindow
property NSURLRequest : a reference to current application’s NSURLRequest
property NSMutableDictionary : a reference to current application’s NSMutableDictionary

on _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
  — Create and display a horizontally centered window with a WebView
  
  
set {thisWindowWidth, thisWindowHeight} to theWindowSize
  
set screenBounds to the NSScreen’s mainScreen’s visibleFrame as any
  
  
if class of screenBounds = record then
    set screenWidth to screenBounds’s |size|’s width
    
set screenHeight to screenBounds’s |size|’s height
    
set windowLeft to ((screenWidth – thisWindowWidth) / 2) + (screenBounds’s origin’s x)
    
set windowBottom to screenHeight – thisWindowHeight + (screenBounds’s origin’s y) – 40
  else
    copy screenBounds to {{originX, originY}, {screenWidth, screenHeight}}
    
set windowLeft to ((screenWidth – thisWindowWidth) / 2) + originX
    
set windowBottom to screenHeight – thisWindowHeight + originY – 40
  end if
  
  
set theStyleMask to (get current application’s NSTitledWindowMask) + (get current application’s NSClosableWindowMask) + (get current application’s NSMiniaturizableWindowMask) + (get current application’s NSResizableWindowMask)
  
set webWindow to NSWindow’s alloc()’s initWithContentRect:(current application’s NSMakeRect(windowLeft, windowBottom, thisWindowWidth, thisWindowHeight)) ¬
    styleMask:theStyleMask backing:(current application’s NSBackingStoreBuffered) defer:false
  — set webWindow’s title to "WebView Created with AppleScript – " & theURLString
  
  
set theWebView to WebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, thisWindowWidth, thisWindowHeight)) ¬
    frameName:"WebKit Frame" groupName:"WebKit Group"
  set webWindow’s contentView to theWebView
  
  
tell webWindow to makeKeyAndOrderFront:(missing value)
  
  
— Start loading the URL
  
  
set theURL to NSURL’s URLWithString:theURLString
  
set theURLRequest to NSURLRequest’s requestWithURL:theURL
  
tell theWebView’s mainFrame to loadRequest:theURLRequest
  
  
webWindow
end _DisplayWebWindowWithURL:windowSize:

— The following two handlers exist to deal with running on a background thread.
— If we’re on a background thread, we have to run the UI code on the main thread.

on _DisplayWebWindowMainThread:parameterDictionary
  try
    set theURLString to parameterDictionary’s objectForKey:"url string"
    
set theWindowSize to parameterDictionary’s objectForKey:"window size"
    
    
set webWindow to my _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
    
    
tell parameterDictionary to setObject:webWindow forKey:"result"
  on error errMsg number errNum
    using terms from scripting additions
      display alert "Error!" message errMsg & " (" & errNum & ")"
    end using terms from
    
tell parameterDictionary to setObject:{errMsg, errNum} forKey:"error"
  end try
end _DisplayWebWindowMainThread:

on display URL theURLString window size theWindowSize
  — All UI methods must be invoked on the main thread.
  
if (NSThread’s isMainThread) then
    my _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
  else
    — Parameters, results and error information are communicated between threads via a dictionary.
    
set parameterDictionary to NSMutableDictionary’s dictionary()
    
tell parameterDictionary to setObject:theURLString forKey:"url string"
    
tell parameterDictionary to setObject:theWindowSize forKey:"window size"
    
    
its performSelectorOnMainThread:"_DisplayWebWindowMainThread:" withObject:parameterDictionary waitUntilDone:true
    
    
— Propagate errors from the other thread
    
    
set errInfo to parameterDictionary’s objectForKey:"error"
    
if errInfo is not missing value then error errInfo’s first item number errInfo’s second item
    
    
parameterDictionary’s objectForKey:"result"
  end if
end display URL

★Click Here to Open This Script 

Posted in GUI Internet URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSMutableDictionary NSScreen NSThread NSURL NSURLRequest NSWindow WebView | Leave a comment

正方形セルの表データで指定セルに隣接するセルブロックを検出

Posted on 3月 11, 2020 by Takaaki Naganoya

正方形セルの表を形成する1次元配列上で、指定セルに隣接する指定データの入っているセルブロックを検出するAppleScriptです。

テストデータは11×11のサイズで作ってみました。本Scriptを作ることが最終目的ではないので、実戦投入はしていませんが、それなりに動いているようです。11セルの対象データを検出するのに、0.002秒ぐらい(10回実行時の平均値)。

本プログラムではセルアドレス=58のセルと隣接する「9」のデータが入っているセルのアドレスをすべて求めています。基準セルの8方向のセルアドレスを計算したうえでデータにアクセスして、「9」が入っているセルを検出。それらをまとめてすべての検出セルの8方向のアドレスを検査し、それ以上検出セル数が増加しない状態までループ処理を続けています。

本プログラムは本番プログラムを作るための習作だったので、ものすごくオーソドックスな組み方をしています。本番のプログラムでは、この「無駄に長い」処理を大幅に簡略化して3分の1ぐらいの長さになりました。

AppleScript名:findBlock2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/10
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property dataWidth : 11
property dataHeight : 11
property dataMax : 121

property testData : {"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "9", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "9", "9", "9", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "9", "9", "9", "9", "1", "1", "1", "1", "1", "1", ¬
  
"1", "9", "9", "9", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", ¬
  
"1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"}

set foundList to {58}

set prevFound to 1
repeat
  set foundList to findAllDirection(foundList) of me
  
set aLen to length of foundList
  
if aLen = prevFound then
    return foundList
  else
    copy aLen to prevFound
  end if
end repeat

return foundList
–> {58, 69, 68, 70, 80, 79, 81, 82, 91, 90, 92}

on findAllDirection(foundList)
  repeat with sCanCell in foundList
    
    
set nRes to findN(sCanCell) of me
    
set sRes to findS(sCanCell) of me
    
set eRes to findE(sCanCell) of me
    
set wRes to findW(sCanCell) of me
    
set nwRes to findNW(sCanCell) of me
    
set neRes to findNE(sCanCell) of me
    
set swRes to findSW(sCanCell) of me
    
set seRes to findSE(sCanCell) of me
    
    
if nRes is not equal to false then
      set newAddr to contents of (item 2 of nRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set nRes to false
      end if
    end if
    
    
if sRes is not equal to false then
      set newAddr to contents of (item 2 of sRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set sRes to false
      end if
    end if
    
    
if eRes is not equal to false then
      set newAddr to contents of (item 2 of eRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set eRes to false
      end if
    end if
    
    
if wRes is not equal to false then
      set newAddr to contents of (item 2 of wRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set wRes to false
      end if
    end if
    
    
if nwRes is not equal to false then
      set newAddr to contents of (item 2 of nwRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set nwRes to false
      end if
    end if
    
    
if neRes is not equal to false then
      set newAddr to contents of (item 2 of neRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set neRes to false
      end if
    end if
    
    
if swRes is not equal to false then
      set newAddr to contents of (item 2 of swRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set swRes to false
      end if
    end if
    
    
if seRes is not equal to false then
      set newAddr to contents of (item 2 of seRes)
      
if newAddr is not in foundList then
        set the end of foundList to newAddr
      else
        set seRes to false
      end if
    end if
    
  end repeat
  
return foundList
end findAllDirection

—————————————

on findS(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findS

on findN(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findN

on findE(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findE

on findW(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findW

on findNW(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to decCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findNW

on findNE(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to decLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to incCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findNE

on findSW(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to decCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findSW

on findSE(anAddress)
  copy anAddress to tmpAddr
  
set tmpAddr to incLine(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpAddr to incCell(tmpAddr) of me
  
if tmpAddr = false then return false
  
set tmpCon to contents of item tmpAddr of testData
  
if tmpCon = "1" then return false
  
return {true, tmpAddr}
end findSE

—————————————

on incLine(anAddress)
  if anAddress + dataWidth > dataMax then
    set anAddress to false
  else
    set anAddress to anAddress + dataWidth
  end if
  
return anAddress
end incLine

on decLine(anAddress)
  if anAddress – dataWidth < 1 then
    set anAddress to false
  else
    set anAddress to anAddress – dataWidth
  end if
  
return anAddress
end decLine

on incCell(anAddress)
  set tmpMax to anAddress div dataWidth
  
if ((anAddress + 1) div dataWidth) is not equal to tmpMax then
    set anAddress to false
  else
    if anAddress + 1 < dataMax then
      set anAddress to anAddress + 1
    else
      return false
    end if
  end if
  
return anAddress
end incCell

on decCell(anAddress)
  set tmpMax to anAddress div dataWidth
  
set tmp2Max to (anAddress – 1) div dataWidth
  
if anAddress – 1 > 0 then
    if (tmp2Max is equal to tmpMax) then
      set anAddress to anAddress – 1
    end if
  else
    set anAddress to false
  end if
  
return anAddress
end decCell

★Click Here to Open This Script 

Posted in list | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

Numbersの表の選択範囲をシーケンシャル番号で埋める

Posted on 3月 11, 2020 by Takaaki Naganoya

Numbersの最前面の書類で選択中の表の選択範囲を1からはじまるシーケンシャル番号で埋めるAppleScriptです。

Numbers書類のセルを埋めるのは、それなりにコストの高い(処理時間が長い)処理なので、数十とか百ぐらいの要素だと、このように悠長にループで埋めても大丈夫ですが、数千とか数万セルを相手にする場合には途方もない時間がかかります。

要素数が多い場合には、CSVのファイルを組み立ててオープンする処理方法をおすすめします(一瞬で終わるので)。

この手の処理は、ほぼ「書き捨て」で保存すらしないことが多いのですが、たまたま気が向いたので保存しておきました。

本ScriptはmacOS 10.14.6/10.15.3+Numbers v6.2.1、macOS 10.13.6+Numbers v6.2で動作確認しています。

AppleScript名:Numbersの表の選択範囲をシーケンシャル番号で埋める
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/10
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

tell application "Numbers"
  tell front document
    tell active sheet
      try
        set theTable to first table whose class of selection range is range
      on error
        display notification "Numbers: There is no selection"
        
return
      end try
      
      
tell theTable
        set aRes to value of cells of selection range
      end tell
      
      
set aLen to length of aRes
      
set newList to makeSequential1DList(aLen) of me
      
      
tell theTable
        set cList to cells of selection range
      end tell
      
      
repeat with i from 1 to aLen
        set anObj to contents of item i of cList
        
set aVal to contents of item i of newList
        
        
ignoring application responses
          set value of anObj to aVal
        end ignoring
        
      end repeat
    end tell
  end tell
end tell

on makeSequential1DList(itemLen)
  set outList to {}
  
repeat with i from 1 to itemLen
    set the end of outList to i
  end repeat
  
return outList
end makeSequential1DList

★Click Here to Open This Script 

Posted in list Number | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

mirroringの設定と解除

Posted on 3月 11, 2020 by Takaaki Naganoya

自分はディスプレイのミラーリング機能は日常的にあまり使っていません。実際にやってみたらどうだったのかをまとめてみました。

この手の処理をAppleScriptで書こうとしても、そのための命令が標準で内蔵されていないため、アプローチの方法はかぎられています。

 (1)思いっきりハードウェア寄りのプログラム(Cとかで書いた)を呼び出す
 (2)アクセシビリティ系の機能(GUI Scripting)を使ってシステム環境設定を操作する

の2つです。(2)は、画面上の要素の些細な変更によりプログラムを書き換える必要が出てくるうえに、信頼性が高くないので、あまりやりたくありません。もちろん、画面上の要素を検索しながら処理する方法もあるわけですが、それなりに(画面要素の検索に)時間がかかります。

そうなると、(1)を採用することになります。探すと………すぐにみつかりました。「mirror-displays」というコマンドラインアプリケーションです。ソースコードを読んでみると、CoreGraphics系の各種フレームワークを呼び出している、Objective-Cで書かれた(ほとんどCのコード)プログラムです。

これをスクリプトバンドルの中に入れて呼び出してみました。1回実行するとメインモニタの内容が他のモニタにミラーリングされます。もう1回実行すると、ミラーリングが解除されます。

–> Download mirroring_toggle (Script Bundle with executable command in its bundle)

mirrorコマンドのオプションには、「どのモニタをミラーリングさせるか」といった指定ができるようですが、試していないのでとくに凝った指定も何もしていません。

mirrorコマンドはmacOS 10.14でビルドして10.10以降をターゲットにしてみましたが、そこまで古い環境は手元に残っていないのでテストしていません。また、macOS 10.15のマシンには複数台のモニタをつないでいないので、macOS 10.15上でのテストも行っていません。

AppleScript名:mirroringの設定と解除
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/11
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

–https://github.com/hydra/mirror-displays
–バンドルの中に入れたmirrorコマンドをただ呼んでるだけ
set myPath to POSIX path of (path to me)
set comPath to myPath & "/Contents/Resources/mirror"
do shell script quoted form of comPath

★Click Here to Open This Script 

Posted in shell script System | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

マウス充電用AppleScript

Posted on 3月 6, 2020 by Takaaki Naganoya

本Scriptはいつも書き捨てにするAppleScriptですが、使用頻度はそれなりに高いものです。

AppleのMagic Mouse 2を充電するには、裏返してLightningケーブルを挿す必要があります。

STEP1:コンピュータをスリープさせる
STEP2:マウスを裏返す
STEP3:ケーブルを挿して充電する

という手順になるわけですが、、、マウスを裏返した時点でボタンが押されたりして、充電できないケースが多々あります。

そこで、本Scriptをスクリプトエディタ上で実行して、10秒以内にマウスに充電ケーブルを挿すと、あとからコンピュータがスリープ。問題なくマウスを充電できます。

AppleScript名:マウス充電用Script
delay 10

tell application "System Events" to sleep

★Click Here to Open This Script 

Posted in How To System | Tagged 10.13savvy 10.14savvy 10.15savvy System Events | Leave a comment

common elements Libの評価アプリケーションを配布

Posted on 3月 5, 2020 by Takaaki Naganoya

ライブラリのインストール方法やらスクリプトエディタの使い方やらがわかっていないとcommon elements Libを実際に使って試すことができないので、実際に機能を評価できるよう最低限のGUIをつけてみました。

–> Download GUI App Executable(Zip archive, 57KB)

macOS 10.13,10.14, 10.15上で動作します。実行にはインターネット接続を必要とします。

Posted in AppleScript Application on Xcode Script Libraries | Tagged 10.13savvy 10.14savvy 10.15savvy | Leave a comment

common elements Libをロシア語などのクエリーで呼び出す

Posted on 3月 3, 2020 by Takaaki Naganoya

WikipediaのREST APIを呼び出して、2つの単語の共通項を計算する「common elements Lib」を作って実際にいろいろ評価していますが、ロシア語を指定したときに結果が得られないという現象に直面していました。

ロシア語を記述するキリル文字のエンコーディング指定がよくなかったのか、Wikipediaのロシア語サーバーの問題なのか、どこに問題点があるのかよくわかっていませんでした(そういう問題のあぶり出しのためにリリースしてみた事情があります)。

とりあえず人名をGoogle翻訳でロシア語+キリル文字に翻訳してロシア語Wikipediaに突っ込んでみても結果が得られず首をひねっていましたが、ロシア語の人名表記が、

First name Family name

ではなく、

Family name, First name

のフォーマットであることに気づきました。この語順で人名を突っ込んでみたところ、無事結果が得られることを確認しました。

AppleScript名:sample_russian
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/03
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use comLib : script "common elements Lib"

–"Family Name, First Name" in Russian Language

–"George Lucas" and "Steven Spielberg"
set cRes to list up common elements with {"Лукас, Джордж", "Спилберг, Стивен"} with language "ru"
–> {"Награда имени Ирвинга Тальберга", "Индиана Джонс", "Кинофантастика", "Золотой глобус", "Монтажёр", "Industrial Light & Magic", "Форд, Харрисон", "DreamWorks", "Премия «Сатурн» за лучший сценарий", "Сиквел", "Продюсер", "Кинорежиссёр", "Калифорния", "Сценарист", "Премия «Сатурн» за лучшую режиссуру", "Оскар (кинопремия)"}

–"Larry Tesler" and "Steve Jobs"
set dRes to list up common elements with {"Теслер, Ларри ", "Джобс, Стив"} with language "ru"
–> {"Apple Computer", "Xerox PARC", "Smalltalk", "Стэнфордский университет"}

★Click Here to Open This Script 

ウクライナ語の人名は、

First name Family name

となっているので、そのように書けば結果が得られます。登録記事数がそれほど多くないので、かなり検索語句を選ぶ印象ではあります。

AppleScript名:sample_Ukrainian
–Українська (Ukrainian)
use comLib : script "common elements Lib"

–"Bill Gates" and "Steve Jobs"
set dRes to list up common elements with {"Білл Гейтс", "Стів Джобс"} with language "uk"
–> {"США", "IBM", "Долар США", "Майкрософт", "Головний виконавчий директор", "Стенфордський університет", "Персональний комп’ютер"}

★Click Here to Open This Script 

Posted in Natural Language Processing REST API Script Libraries | Tagged 10.10savvy 10.12savvy 10.13savvy 10.14savvy 10.15savvy | 1 Comment

指定文字列ではじまるURLをオープン中のTabをクローズ

Posted on 3月 1, 2020 by Takaaki Naganoya

Safariでオープン中のウィンドウ/Tabのうち、指定URLではじまるもの(この場合にはGoogle翻訳)をオープン中のものだけをクローズする掃除用のAppleScriptです。

TabのIDを取得して、1から処理するとナンバリングがおかしくなるので、後ろから処理しているあたりが「ワザ」とでもいうべきものでしょうか。

AppleScript名:指定文字列ではじまるURLをオープン中のTabをクローズ
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/03/01
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

set targURL to "https://translate.google.co.jp" –Google翻訳
closeSafariTabsBeginsWithAURL(targURL) of me

on closeSafariTabsBeginsWithAURL(targURL)
  tell application "Safari"
    set wCount to (every window whose visible is true)
    
    
repeat with w in wCount
      set aWin to contents of w
      
      
tell aWin
        set tabCount to count every tab
        
repeat with t from tabCount to 1 by -1
          tell tab t
            set aURL to URL of it
            
if aURL begins with targURL then
              close
            end if
          end tell
        end repeat
      end tell
      
    end repeat
  end tell
end closeSafariTabsBeginsWithAURL

★Click Here to Open This Script 

Posted in URL | Tagged 10.13savvy 10.14savvy 10.15savvy Safari | Leave a comment

Wikipedia経由で2つの単語の共通要素を計算するcommon elements Lib Script Library

Posted on 2月 28, 2020 by Takaaki Naganoya

現在作成中のアプリケーションの副産物として生まれた「common elements Lib」AppleScript Libraryです。2つの単語の共通要素を計算して返します。

# v1.1にアップデートしました(ダウンロード先URLはかわらず)。ページ下部のテンプレート部分の余計なリンクを拾わないように改善したため、テンプレート部分のリンクが多い項目に対して大きな効果を発揮します

–> Download archive

アーカイブをダウンロードして展開し、~/Library/Script Librariesフォルダに「common elements Lib.scptd」を入れるとAppleScriptから呼び出せるようになります。

macOS 10.10以降で動作するはずですが、開発は10.14上で、動作確認は10.13/10.14/10/15上でのみ行なっています。

この、2つのキーワードの共通要素を求める処理は「マッキー演算」と呼んでおり、男性アイドルグループ「SMAP」と、男性シンガーソングライター「槇原敬之」(マッキー)氏の共通要素を演算で求めることを目的として企画されました。「SMAP」はWikipedia上でも最大級の要素数を持つ項目であり、1,400項目以上のリンク要素を擁しています。

Wikipedia REST APIの仕様ではリンク要素を500項目までしか一度に取得できません。SMAPを処理するためには、複数ページにまたがるリンク取得の処理をこなすことが必要であり、「マッキー演算」は言葉のバカっぽさとは裏腹に、それなりの技術力が要求される、そこそこむずかしい処理なのです。

本ライブラリを用いて、WikipeidaにREST API経由で検索司令を出すわけですが、英語のスペルの単語を受け付けるWikipediaもあれば、日本語やアラビア語Wikipediaなどのようにその言語向けの書き換えを行ったデータで検索するものもあり、割とまちまちであることがわかりました。そのあたりは、sdefに書いておいたサンプルScriptを見ていただくのがよいでしょう。

本ライブラリでは、演算対象とする単語はWikipediaに掲載されているものに限られています。実際に、日本語環境で「スティーブ・ジョブズ」と「ラリー・テスラー」の共通項目を計算すると、

--> {"パロアルト研究所", "Smalltalk", "アメリカ合衆国", "Lisa (コンピュータ)", "アップル・ニュートン", "Macintosh", "アップル (企業)", "Macworld", "スタンフォード大学"}

「スティーブ・ジョブズ」と「ロス・ペロー」の共通項目を計算すると、

--> {"NeXT", "アル・ゴア", "統合典拠ファイル", "実業家", "IBM", "ゼネラルモーターズ", "SNAC", "アメリカ合衆国", "国際標準名称識別子", "孫正義", "ソフトバンク", "国立国会図書館", "フランス国立図書館", "アメリカ議会図書館管理番号", "CiNii", "バーチャル国際典拠ファイル"}

のような結果を返してきます。

冒頭で述べた「SMAP」と「槇原敬之」の共通項目を計算すると、

--> {"スポーツニッポン", "ABO式血液型", "テレビ朝日", "東京都", "社長", "エフエム東京", "ミュージックステーション", "J-POP", "第42回NHK紅白歌合戦", "大阪城ホール", "日本", "We are SMAP!", "ミリオンセラー", "小倉博和", "インターネットアーカイブ", "日本武道館", "ニッポン放送", "リクルートホールディングス", "日刊スポーツ", "第58回NHK紅白歌合戦", "フジテレビジョン", "世界に一つだけの花"}

のようになります。

おおよその主要言語に対応していますが、ロシア語をはじめとするキリル文字の言語を指定すると、なぜか結果が返ってきません。これが、キリル文字のエンコーディングに関する(こちら側の実装がまずい)問題なのか、サーバー側がREST APIをサポートしていないのか(Wikipediaサーバー側の問題)はわかりません。
→ ロシア語のクエリーも処理できることを確認しました

ここでは、だいたいの「いい感じのキーワード」を例として出していますが「George Lucas」と「Steven Spielberg」などの近い単語を指定すると結果が400個以上返ってきます。
→ v1.1における改良により、400個以上のリンクを66個まで減少させました(不要なフッター部分のリンクを拾わないようにした)

膨大な項目から必要な要素を選択するInterfaceをみつくろってテストをしてはいるのですが、iOS上でよさそうに見えてもMac上で動かすといまひとつだったり、なかなか合うものが見つかりません(超多項目選択UI)。

–> Watch Demo

こうした計算結果をもっと減らす方法や、これらの多項目の計算結果からGUI上で項目選択する方法などが自分たちでは見つからなかったので、ライブラリとして公開して広く意見やアイデアを募ろうと考えました。多言語のWikipediaへの問い合わせを行ったり、問題点を洗い出すことも目的の1つです。前述のとおり、ロシア語系のWikipediaに対するアクセスに問題がある点については調査が必要です。

余談ですが、Steve JobsとLarry Teslerの関連項目演算を行おうとしても、Larry Teslerの項目がなかったり、Xerox PARCへのリンクがないために演算結果にこれが含まれない言語のWikipediaがいくつか見られました。コンピュータ史上重要な偉人への敬意をこめ、ぜひ追記していただきたいと考えるものです(という話を日本語で書いても意味がない?)。

AppleScript name:sample.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/02/28
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
— http://www.piyocast.com

use comLib : script "common elements Lib"

–English
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResEN to list up common elements with {aWord, bWord} with language "en"
–> {"The New York Times", "Computer History Museum", "Alan Kay", "International Standard Book Number", "California", "Steve Jobs", "Computer mouse", "John Markoff", "Ethernet", "Stanford University", "Counterculture of the 1960s", "Fortune (magazine)", "Tablet computer", "Apple Lisa", "Apple Inc.", "Associated Press", "Graphical user interface", "International Standard Serial Number", "Apple Computer", "Macintosh 128K", "Xerox Alto"}

–日本語(Japanese)
set aWord to "スティーブ・ジョブズ" –Steve Jobs
set bWord to "ラリー・テスラー" –Larry Tesler
set commonResJP to list up common elements with {aWord, bWord} with language "jp"
–> {"パロアルト研究所", "Smalltalk", "アメリカ合衆国", "Lisa (コンピュータ)", "アップル・ニュートン", "Macintosh", "アップル (企業)", "Macworld", "スタンフォード大学"}

–中文(Simplified Chinese)
set aWord to "史蒂夫·乔布斯" –Steve Jobs
set bWord to "拉里·泰斯勒" –Larry Tesler
set commonResZH to list up common elements with {aWord, bWord} with language "zh"
–> {"母校", "美國", "帕羅奧多研究中心"}

—한국어(Korean)
set aWord to "스티브 잡스" –Steve Jobs
set bWord to "빌 게이츠" –Bill Gates
set commonResKO to list up common elements with {aWord, bWord} with language "ko"
—> {"가상 국제 전거 파일", "위키인용집", "게마인자메 노름다타이", "네덜란드 왕립도서관", "국제 표준 도서 번호", "IBM", "SNAC", "CiNii", "개인용 컴퓨터", "BIBSYS", "영어", "국제 표준 명칭 식별자", "오스트레일리아 국립도서관", "LIBRIS", "체코 국립도서관", "미국", "스페인 국립도서관", "뮤직브레인즈", "프랑스 국립도서관", "이스라엘 국립도서관", "일본 국립국회도서관", "미국 의회도서관 제어 번호", "전거 통제", "국립중앙도서관", "WorldCat Identities", "실리콘 밸리의 신화", "프랑스 대학도서관 종합목록", "위키미디어 공용"}

–svenska
set aWord to "Steve Jobs"
set bWord to "Ross Perot"
set commonResSV to list up common elements with {aWord, bWord} with language "sv"
–> {"USA", "IBM", "Forbes", "Entreprenör", "Libris (bibliotekskatalog)"}

–Deutsch
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResDE to list up common elements with {aWord, bWord} with language "de"
–> {"Objektorientierte Programmierung", "Apple", "Apple Macintosh", "Xerox PARC", "Virtual International Authority File", "The New York Times", "Kalifornien", "Apple Lisa"}

–français
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResFR to list up common elements with {aWord, bWord} with language "fr"
–> {"The New York Times", "Palo Alto Research Center", "Informaticien", "Californie", "Apple", "États-Unis", "Autorité (sciences de l’information)"}

–Nederlands
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResNL to list up common elements with {aWord, bWord} with language "nl"
–> {"Verenigde Staten (hoofdbetekenis)", "Palo Alto Research Center", "Apple Macintosh", "Xerox", "Apple Inc.", "Apple Lisa", "Apple Newton"}

–italiano
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResIT to list up common elements with {aWord, bWord} with language "it"
–>{"Apple", "Stati Uniti d’America", "Xerox Palo Alto Research Center", "Informatico"}

–español
set aWord to "Steve Jobs"
set bWord to "Ross Perot"
set commonResES to list up common elements with {aWord, bWord} with language "es"
–> {"Emprendedor", "Library of Congress Control Number", "Wikidata", "IBM", "Enciclopedia Británica", "Wikimedia Commons", "Empresario", "CiNii", "National Diet Library", "Estados Unidos", "National Library of the Czech Republic", "Virtual International Authority File", "Bibliothèque nationale de France", "International Standard Name Identifier", "Integrated Authority File", "Système universitaire de documentation", "ISBN"}

–polski
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResPL to list up common elements with {aWord, bWord} with language "pl"
–> {"Apple Inc.", "Virtual International Authority File", "Xerox PARC"}

–Tiếng Việt
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResVI to list up common elements with {aWord, bWord} with language "vi"
–> {"Hoa Kỳ", "Apple Lisa", "California", "Apple Inc."}

–Arabic
set aWord to "ستيف جوبز"
set bWord to "روس بيرو"
set commonResAR to list up common elements with {aWord, bWord} with language "ar"
–> {"مكتبة البرلمان الوطني", "رقم الضبط في مكتبة الكونغرس", "رائد أعمال", "المكتبة الوطنية لجمهورية التشيك", "ملف استنادي متكامل", "ملف استنادي دولي افتراضي", "المكتبة الوطنية الفرنسية", "سايني", "ديل", "آي بي إم", "لغة إنجليزية", "ضبط استنادي", "حزب سياسي", "مهنة", "مدرسة أم", "واي باك مشين", "الولايات المتحدة", "المحدد المعياري الدولي للأسماء", "دولار أمريكي"}

–português
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResPT to list up common elements with {aWord, bWord} with language "pt"
–> {"Macintosh", "Alan Kay", "Apple Newton", "Povo dos Estados Unidos", "Língua inglesa", "Estados Unidos", "Ciência da computação", "Apple", "Califórnia", "Base Virtual Internacional de Autoridade"}

–Català
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResCA to list up common elements with {aWord, bWord} with language "ca"
–> {"Control d’autoritats", "Virtual International Authority File", "Apple Macintosh", "Apple Inc", "Interfície gràfica d’usuari"}

–Bahasa Indonesia
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResNO to list up common elements with {aWord, bWord} with language "id"
–> {"California", "Biografi", "Amerika Serikat"}

–magyar
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResHU to list up common elements with {aWord, bWord} with language "hu"
–> {"Amerikai Egyesült Államok", "Informatikus", "Wikimédia Commons", "Stanford Egyetem", "Nemzetközi Virtuális Katalógustár"}

–euskara
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResEU to list up common elements with {aWord, bWord} with language "eu"
–> {"Xerox", "Informatikari", "Ingeles", "Apple Inc.", "Ameriketako Estatu Batuak", "Wikidata", "Smalltalk", "Virtual International Authority File", "Stanford Unibertsitatea", "Wikimedia Commons"}

–Türkçe
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResTR to list up common elements with {aWord, bWord} with language "tr"
–> {"The New York Times", "Apple", "Amerika Birleşik Devletleri", "Kaliforniya"}

★Click Here to Open This Script 

AppleScript name:sample2
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/02/28
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
— http://www.piyocast.com

use comLib : script "common elements Lib"

set sList to supported lang codes
–> {"en", "ceb", "sv", "de", "fr", "nl", "ru", "it", "es", "pl", "war", "vi", "jp", "zh", "ar", "pt", "uk", "fa", "ca", "sr", "no", "id", "ko", "fi", "hu", "sh", "cs", "ro", "eu", "tr", "ms", "eo", "hy", "bg", "he", "da", "ce", "zh-min-nan", "sk", "kk", "min", "hr", "et", "lt", "be", "el", "azb", "sl", "gl", "az", "simple", "ur", "nn", "hi", "th", "ka", "uz", "la", "ta", "vo", "arz", "cy", "mk", "tg", "lv", "ast", "mg", "tt", "af", "oc", "bs", "bn", "ky", "sq", "zh-yue", "tl", "new", "te", "be-tarask", "br", "ml", "pms", "nds", "su", "ht", "lb", "jv", "sco", "mr", "sw", "pnb", "ga", "szl", "ba", "is", "my", "fy", "cv", "lmo", "an", "ne", "pa", "yo", "bar", "io", "gu", "wuu", "als", "ku", "scn", "kn", "ckb", "bpy", "ia", "qu", "mn", "bat-smg", "vec", "wa", "si", "or", "cdo", "gd", "yi", "am", "nap", "ilo", "bug", "xmf", "mai", "hsb", "map-bms", "fo", "diq", "mzn", "sd", "li", "eml", "sah", "nv", "os", "sa", "ps", "ace", "mrj", "frr", "zh-classical", "mhr"}

–"ru", "uk", "sh", "bg" seems not to work… "ms" or later codes seems not to work (depends on Wikipedia Server spec)….

★Click Here to Open This Script 

Posted in Internet Language Natural Language Processing REST API Script Libraries sdef | Tagged 10.10savvy 10.11savvy 10.12savvy 10.13savvy 10.14savvy 10.15savvy | 1 Comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AppleScriptによる並列処理
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • macOS 15でも変化したText to Speech環境
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • macOS 15 リモートApple Eventsにバグ?
  • 【続報】macOS 15.5で特定ファイル名パターンのfileをaliasにcastすると100%クラッシュするバグ
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • Script Debuggerの開発と販売が2025年に終了
  • NSObjectのクラス名を取得 v2.1
  • macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
  • 有害ではなくなっていたSpaces
  • AVSpeechSynthesizerで読み上げテスト

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (147) 15.0savvy (135) CotEditor (66) Finder (51) iTunes (19) Keynote (119) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (76) Pages (55) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • date
  • dialog
  • diff
  • drive
  • Droplet
  • 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
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • process
  • 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)
  • 未分類

アーカイブ

  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 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