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

月: 2019年4月

各種GUI要素なしでSafari上に新規ウィンドウ表示

Posted on 4月 29, 2019 by Takaaki Naganoya

Safari上で操作ボタンなどのGUI要素を表示しないで新規ウィンドウ表示するAppleScriptです。

1つのウィンドウを表示するのはすぐにできましたが、複数表示が大変でした(ーー; 結局、適宜delayコマンドで時間待ちをする必要があったのでした。やれやれー。

現時点で用途はまったく不明なのですが、いつか必要になることもあるでしょう(そういうの多いな!)。「resizable=no」という指定をしているのに、ウィンドウがリサイズできるあたりはご愛嬌。

ちなみに、Safariのdocumentが1つ以上存在することを前提条件としていますが、そこは省略して明示していません(初心者がひっかかりがちな「不明確な前提条件」なのですが本説明をもってかえさせていただきます)。

Twitter上でロシアのMacユーザーが「だれかAppleScriptについて教えてくれー」と言っていたので、「Google翻訳の範囲でなら(込み入った話でなければ)いいぞ」と返信したら、マンツーマンでやりとり。

初のロシア人とのチャットです。

本ScriptのおおもとになったAppleScriptをAlfred.appを使ってキーボードショートカットで呼び出していたそうで、1アクションから1つのサイトをオープンするだけなのが不満で、複数のサイト(URL)をオープンするように変更したかったとのこと。

Google翻訳を使ってコミュニケーションしてみて、いろいろ理解しました。

(1)ロシア人、とっても普通

(2)話した相手がプログラミングわからない人だったので、いろいろ追加で話をされたが、プログラマーが一番嫌がる内容(最初からゴール地点が設定されていない)になってきたので「ここから先は仕事としてならやるが、ギャラなしだったらやらない」と明言して打ち切り

(3)Google翻訳を通じて「ロシア語に翻訳できない表現」がいろいろあって焦る。おそらく、英語ほどには日本語との間の翻訳の用例が多く蓄積されておらず、翻訳できなかったものと想像。一応、日本語→ロシア語に翻訳してから、その文章を再度日本語に再翻訳してチェック。トンでもない表現に翻訳されて驚愕するも、何例か日本語の表現を変えてリトライ

あとから振り返って考えると、「日本語からロシア語に翻訳するより、英語からロシア語に翻訳した方がよかった」、「ダスビダーニャ(До свидания)って挨拶は知っていたのに使えなかったよ、ハラショー」といったところでしょうか。

あとは、固定でプログラム中にURLのデータを入れておかないで、外部ファイル……たとえばNumbers書類上のデータであるとか、DragThingのURLランチャーに登録してある現在選択中のタブからURLを取得してオープンするとかいった処理が考えられると「お、頑張ったね」というレベルでしょうか。

AppleScript名:各種GUI要素なしでSafari上に新規ウィンドウ表示
set aURLstr to "http://piyocast.com/as"

tell application "Safari"
  tell front document
    set jsStr to "open(’" & aURLstr & "’, ’test’,’scrollbars=no,resizable=no,status=no,location=no," & "toolbar=no,menubar=no,width=1024,height=720,left=0,top=0’);"
    
do JavaScript jsStr
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:各種GUI要素なしでSafari上に新規ウィンドウを複数表示
set aURLarray to {"http://piyocast.com/as", "http://www.apple.com", "http://www.microsoft.com"}

repeat with i in aURLarray
  set j to contents of i
  
openNewWindowWithoutGUIElements(j) of me
  
delay 3
end repeat

on openNewWindowWithoutGUIElements(aURLstr)
  set aNum to random number from 1 to 999
  
tell application "Safari"
    tell front document
      set jsStr to ("open(’" & aURLstr & "’, ’test" & aNum as string) & "’,’scrollbars=no,resizable=no,status=no,location=no," & "toolbar=no,menubar=no,width=1024,height=720,left=0,top=0’);"
      
do JavaScript jsStr
    end tell
  end tell
end openNewWindowWithoutGUIElements

★Click Here to Open This Script 

Posted in JavaScript list URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Safari | Leave a comment

順序変更可能な項目選択ダイアログ

Posted on 4月 28, 2019 by Takaaki Naganoya

順序の変更が可能な項目選択(指定)ダイアログ表示AppleScriptです。

項目を行単位でドラッグ&ドロップして順番を変更できるようになっています。この機能を自前で作ろうとすると、筆舌に尽くし難いほど大変なのでMyriad Tables Libを利用して作ってみました。

Myriad Tables Libはたいへんに多機能なライブラリですが、あえて限定された機能だけを利用してみるというのもアリでしょう。

なにげに、仕事で実際に納品するプログラムによく使っています、Myriad Tables Lib。

AppleScript名:順序変更可能な項目選択ダイアログ.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/28
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions
use script "Myriad Tables Lib" version "1.0.9" –https://www.macosxautomation.com/applescript/apps/Script_Libs.html

set aTitle to "順番を指定してください"
set aPrompt to "各行はドラッグ&ドロップで順序を変更できます"
set origData to {"iMac 5K", "MacBook Pro", "Mac mini", "MacBook Air", "MacBook", "Mac Pro", "iMac Pro"}

set selRowList to dispDroppableTableViewDialog(aTitle, aPrompt, origData) of me
–>{"Mac mini", "MacBook Air", "MacBook", "Mac Pro", "MacBook Pro", "iMac 5K", "iMac Pro"}

–順序変更可能なダイアログを表示
on dispDroppableTableViewDialog(aTitle, aPrompt, origData)
  set someData to make1DListTo2D(origData) of me
  
  
set myTable to make new table with data someData with title aTitle with prompt aPrompt initially selected rows {1} with multiple selections allowed
  
set theAccessoryView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 400, 0))
  
modify table myTable accessory view theAccessoryView with row dragging
  
  
set theResult to (display table myTable)
  
  
set selList to values returned of theResult
  
set sel2List to FlattenList(selList) of me
  
  
return sel2List
end dispDroppableTableViewDialog

–1D Listを2D Listに変換
on make1DListTo2D(aList as list)
  set outList to {}
  
repeat with i in aList
    set j to contents of i
    
set the end of outList to {j}
  end repeat
  
return outList
end make1DListTo2D

on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {"????"}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

★Click Here to Open This Script 

Posted in dialog GUI | Tagged 10.11savvy 10.12savvy 10.13savvy NSView | Leave a comment

クリップボードに入れられた画像をNSImageに変換して1Dバーコード認識

Posted on 4月 28, 2019 by Takaaki Naganoya

クリップボードに入れたバーコード画像をNSImageに変換して1Dバーコード認識して内容をデコードするAppleScriptです。

–> Download ZXingObjC.framework(To ~/Library/Frameworks)

1Dバーコード認識には定番の「ZXingObjC」を利用しているのですが、同プログラムは派生プロジェクトが多く、いまひとつどれを使っているのか、自分自身も正確に把握していなかったりします。

カメラからの入力映像から1次元バーコード認識を行うプログラムは多いのですが、画像から認識するプログラムはそれほどみかけません。さらに、それに輪をかけて、入力画像形式がNSImageではなくCGImageである場合が多く、ZXingでも入力はCGImage。

AppleScriptから生成できないCGImage。NSImageから直接の変換メソッドをAppleScript上で利用できないCGImage。

そこで、SFPSDWriterのコメントに書いてあったコードを参考に、NSImageで入力した画像をCGImageに変換して処理するメソッドをObjective-Cで追加して、AppleScriptから呼び出しやすく書き換えて呼び出してみました(オリジナルに「initWithNSImage:」というメソッドは実装されていません)。

実際には、Adobe IllustratorやAdobe InDesignにリンクされたバーコード画像素材をチェックするような用途を想定しています(実際、やっているので)。QRコード画像をデコードするScriptは用意していたものの、1D Bar Code画像をデコードするものを用意していなかったので、再調査。JANはEANとほとんど同じなので大丈夫でしたが、その他の日本マイナーなバーコード規格(郵便コードとか)については未調査のためわかりません。

ちなみに、本FrameworkはQRコードをサポートしているため、JANコード(1Dバーコード)とQRコード(2Dバーコード)の両方を同一Scriptでデコードできました。Illustratorオブジェクトで作られたバーコードを適宜クリップボードを経由してPDF化したものをデコードしてみたのですが、1Dバーコードと2Dバーコードのチェックに別々のルーチンを用意しないとダメだろうと覚悟していたところに、両方とも同じメソッド呼び出しでデコードできてしまい拍子抜け。

macOS 10.14上ではScript Debuggerで実行するか、AppleScriptをバンドル形式で保存してバンドル内にFrameworkを入れアプレット書き出しするとか、SIPによるプロテクションを解除するなどの方法で呼び出せます(Script Debuggerを使うのが一番いいでしょう)。

AppleScript名:クリップボードに入れられた画像をNSImageに変換して1Dバーコード認識.scptd
— Created 2015-09-20 by Takaaki Naganoya
— Modified 2019-04-27 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "ZXingObjC" –https://github.com/TheLevelUp/ZXingObjC

–クリップボードの内容をNSImageに
set aNSIMage to my getClipboardASImage()

–NSImageをバーコードとして認識する
set aSource to current application’s ZXCGImageLuminanceSource’s alloc()’s initWithNSImage:aNSIMage
set aBitmap to current application’s ZXBinaryBitmap’s binaryBitmapWithBinarizer:(current application’s ZXHybridBinarizer’s binarizerWithSource:aSource)

set aHints to current application’s ZXDecodeHints’s hints()
set aReader to current application’s ZXMultiFormatReader’s reader()
set aResult to aReader’s decode:(aBitmap) hints:(aHints) |error|:(missing value)

if aResult is equal to missing value then return false
set aCon to (aResult’s |text|()) as string
set aFormat to aResult’s barcodeFormat()

return {aCon, aFormat}

— クリップボードの内容をNSImageとして取り出して返す
on getClipboardASImage()
  set theNSPasteboard to current application’s NSPasteboard’s generalPasteboard()
  
set theAttributedStringNSArray to theNSPasteboard’s readObjectsForClasses:({current application’s NSImage}) options:(missing value)
  
set theNSAttributedString to theAttributedStringNSArray’s objectAtIndex:0
  
return theNSAttributedString
end getClipboardASImage

★Click Here to Open This Script 

Posted in Clipboard Image | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSPasteboard | Leave a comment

Apitoreサービス終了のお知らせ

Posted on 4月 26, 2019 by Takaaki Naganoya

Web上で各種自然言語処理/機械学習系REST APIを提供されてきた「Apitore」さんが、2019年5月31日をもってサービスを終了するとのことです。

機械学習系のサービスについては、1つのサービスを提供するために8GBのメモリ容量を持つインスタンスを占有して回し続けるなど、単なるBlogなどとは比較にならないほどサーバー側の資源が要求されることも実感できました(そんなの、クライアント側でそのまま実装は無理じゃん! ^ー^;)。

機械学習モデルを利用して演算(判定など)を行うことは、IoT機器ぐらいでもできるので、そんなに計算機資源は必要とされませんが、機械学習モデルを作る(学習する)局面においてはそのかぎりではないということを実感できました。

学習モデルのメンテナンスも割と頻繁に行いつつ、極性判定で得られる演算結果を検証したりと、「個人で片手間でやるには手間がかかりすぎる」と思っておりました。

ApitoreさんのサービスではじめてKuromojiによる形態素解析サービスを使ってみて、コマンド解析用にも使い勝手がよかったのが印象的です(Kuromoji使ったことなかったもんで)。極性判定やWord2Vecあたりは、正直なところ、学習データの傾向が自分の用途とは合わなかったりで実用性はいまひとつでしたが、実際にそうしたサービスに触れてクオリティのレベルを体感できたのはよかったと思っています(いまだとwordどころかphrase2vecとか出てきています。doc2vecとかもやってるんでしょうね、、、、 ^ー^;)。

運営のご苦労はいろいろ伺っており、インフラ系のサービスって個人で提供し続けるのは大変なんだなーということと、Twitterなど各種サービスやRSS系のフィードなど代わりのものがないので、困ってしまうところです(^ー^;;。

実際の仕事でもApitoreのREST APIをいくつか使用している案件があるので、どうするのかといったところですが、本Blogに掲載しているREST API呼び出しサンプルはそのまま掲載しておきます。

Posted in Release | Leave a comment

Keynoteで指定IDのテキストフレームを縦書き化

Posted on 4月 26, 2019 by Takaaki Naganoya

macOS 10.13/10.14+Keynote 9.0.1で指定のIDのテキストフレームを縦書き化するAppleScriptです。

Keynote 9でサポートされた文字の縦書き表示。しかし、肝心のAppleScriptでこれを操作する機能が備わっていなかったので、強引にGUI側から操作して縦書き化させてみました。

実行前に「システム環境設定」の「セキュリティとプライバシー」>「アクセシビリティ」にて、スクリプトエディタあるいはScript Debuggerに対してアクセシビリティ機能(「下のアプリケーションにコンピュータの制御を許可」)を許可しておく必要があります。

また、macOS 10.14上にてはじめてScript DebuggerからKeynoteを動かそうとした場合には、「オートメーション」項目でScript Debuggerの操作を許可しておく必要があります。


▲Before


▲After


▲2D Bin PackingのAppleScriptに、本ルーチンを組み込んで想定矩形座標内に文字を詰め込んでみた。日本語はフレームの回転ではなく縦書き表示できたほうが可読性が上がるかも


▲Keynote上でオブジェクトを選択状態にしてテキストフレームの「枠」を表示させてみるとけっこう詰まっていることがわかる

AppleScript名:Keynoteで指定IDのテキストフレームを縦書き化
set tmpID to 1

selectTextItemID(tmpID) of me
set aRes to makeTextFrameVertival(tmpID, true) of me

on makeTextFrameVertival(anID, aFlag)
  tell application "System Events"
    activate
    
set aGSflag to UI elements enabled
    
if aGSflag = false then return false
  end tell
  
  
activate application "Keynote"
  
tell application "System Events"
    tell process "Keynote"
      tell radio button "フォーマット" of radio group 1 of toolbar 1 of window 1 –*Localized*
        set aVal to value
        
if aVal = 0 then
          click
        end if
      end tell
      
      
tell radio button "テキスト" of radio group 1 of window 1 –*Localized*
        click
      end tell
      
      
tell checkbox "縦書きテキスト" of scroll area 1 of window 1 –*Localized*
        set aVal to value
        
if (aVal = 0) and (aFlag = true) then
          click
        else if (aVal = 1) and (aFlag = false) then
          click
        end if
      end tell
      
    end tell
  end tell
  
return true
end makeTextFrameVertival

on selectTextItemID(anID)
  tell application "Keynote"
    tell front document
      tell current slide
        set anObj to a reference to text item anID
        
properties of anObj
      end tell
    end tell
  end tell
end selectTextItemID

★Click Here to Open This Script 

Posted in GUI Scripting | Tagged 10.13savvy 10.14savvy Keynote | Leave a comment

RectangleBinPackを用いて2D Bin Packを解く

Posted on 4月 23, 2019 by Takaaki Naganoya

オープンソースの「RectangleBinPack」を用いて2D Bin Packagingを解き、Keynote上のshapeオブジェクトを指定矩形内に詰め込むAppleScriptです。

–> Download Script bundle with RectangleBinPack in its bundle

# This AppleScript requires RectangleBinPack executable in its bundle. So, download the whole AppleScript bundle archive from the link above (↑)

オープン中のKeynote書類の表示中のスライド(ページ)上にある矩形オブジェクト(Shape)を指定の矩形エリア内に2D Packingします。

github上で調査してみたところ、2D Bin Packのプログラムの多くはCないしC++で記述されており(JavaScriptも多いですね)、コンパイルしてAppleScriptのバンドル内に入れて呼び出せます。

ただし、それらの多くがゲーム開発用のものらしく、オブジェクトの回転をサポートしていたり(実用性を考えると回転してほしくない)、面積の大きな順に渡しても無視したり(優先順位をサポートしない)と、実際のGUIアプリケーション上のオブジェクトの整列には向いていないものがほとんどです。


▲Before Packing


▲AFter Packing

唯一、タグクラウドの画像を作りたい場合に本プログラムは向いていると思います。とくに、Keynoteのスライド上にタグクラウドっぽいページを作って、発表内容を示すとかいうのは実用性もありそうです。


▲本Scriptを文字アイテム処理用に書き換えて2D Bin Packした処理結果


▲本ScriptをAdobe Illustrator CC 2018用に書き換えて2D Bin Packした処理結果

AppleScript名:rectBinPack v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/23
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

–Packaging Target Area
set binSizeX to 600
set binSizeY to 500

set {tList, a0List} to retRectsFromKeynote() of me
set aList to sortList2DDecending(a0List, {2, 4, 3}) of me –Sorting key is Width(main) and Area(sub) and Height(sub)
–> {{2, 340, 243, 82620}, {3, 340, 73, 24820}, {8, 340, 73, 24820}, {1, 155, 240, 37200}, {4, 147, 125, 18375}, {5, 147, 125, 18375}, {6, 147, 125, 18375}, {7, 147, 125, 18375}}

set aRes to twoDBinPacking(binSizeX, binSizeY, aList) of me
if aRes = false then return
–> {{myPos:{0, 0}, myID:1}, {myPos:{0, 340}, myID:2}, {myPos:{243, 0}, myID:3}, {myPos:{316, 0}, myID:4}, {myPos:{340, 240}, myID:5}, {myPos:{465, 240}, myID:6}, {myPos:{590, 0}, myID:7}, {myPos:{590, 125}, myID:8}}

tell application "Keynote"
  tell front document
    tell current slide
      repeat with i in aRes
        set {posX, posY} to myPos of i
        
set itemIndex to myID of i
        
set aDeg to myDegree of i
        
        
set anObjID to item 1 of (item itemIndex of aList)
        
        
set rotation of shape anObjID to aDeg
        
set position of shape anObjID to {posX, posY}
        
      end repeat
    end tell
  end tell
end tell

on twoDBinPacking(binSizeX as integer, binSizeY as integer, boxList as list)
  set aParamList to {binSizeX, binSizeY}
  
repeat with i in boxList
    copy i to {tmpID, tmpX, tmpY, tmpArea}
    
set aParamList to aParamList & tmpX
    
set aParamList to aParamList & tmpY
  end repeat
  
  
set aParam to retDelimitedText(aParamList, " ") of me
  
–> "800 800 340 243 340 73 340 73 155 240 147 125 147 125 147 125 147 125"
  
  
–Parameters for result parsing
  
set s1Str to "Packed to (x,y)=("
  
set s2Str to ")"
  
set s3Str to ","
  
  
–https://github.com/juj/RectangleBinPack
  
set aPath to POSIX path of (path to resource "BinPackTest") –cause error if "BinPackTest" is not present in this script bundle
  
try
    set aRes to do shell script quoted form of aPath & " " & aParam
  on error
    return false
  end try
  
  
if aRes does not end with "Done. All rectangles packed." then return false
  
  
set aList to paragraphs of aRes
  
  
set bList to {}
  
set aCount to 1
  
repeat with i in aList
    set j to contents of i
    
if j begins with "Packing rectangle of size " and j does not contain "Failed!" then
      set xyRes to pickUpFromToStrAndParse(j, s1Str, s2Str, s3Str) of me
      
      
–RectangleBinPackがオブジェクトの回転をサポートしているため、その対処
      
if xyRes is not equal to false then
        set s11Str to "(w,h)=("
        
set s12Str to ")"
        
set s13Str to ","
        
        
set whRes to pickUpFromToStrAndParse(j, s11Str, s12Str, s13Str) of me
        
set tmpBox to item aCount of boxList
        
copy tmpBox to {tmpID, tmpX, tmpY, tmpArea}
        
        
if whRes = {tmpX, tmpY} then
          set aDeg to 0
        else if whRes = {tmpY, tmpX} then
          set aDeg to 90
        else
          error
        end if
        
        
set the end of bList to {myPos:xyRes, myID:aCount, myDegree:aDeg}
      end if
      
set aCount to aCount + 1
    end if
  end repeat
  
  
return bList
end twoDBinPacking

on pickUpFromToStrAndParse(aStr as string, s1Str as string, s2Str as string, s3Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
set {x, y} to parseByDelim(cStr, s3Str) of me
  
  
return {x as integer, y as integer}
end pickUpFromToStrAndParse

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–リストを指定デリミタでテキスト化
on retDelimitedText(aList, aNewDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aNewDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retDelimitedText

on retRectsFromKeynote()
  tell application "Keynote"
    tell front document
      tell current slide
        set tList to every shape
        
set bList to {}
        
set iCount to 1
        
        
repeat with i in tList
          set aWidth to width of i
          
set aHeight to height of i
          
set {xPos, yPos} to position of i
          
set anArea to aWidth * aHeight
          
          
set the end of bList to {iCount, aWidth, aHeight, anArea}
          
set iCount to iCount + 1
        end repeat
        
        
return {tList, bList}
      end tell
    end tell
  end tell
end retRectsFromKeynote

–入れ子のリストを昇順ソート
on sortList2DAscending(a, keyItem)
  return sort2DList(a, keyItem, {true}) of me
end sortList2DAscending

–入れ子のリストを降順ソート
on sortList2DDecending(a, keyItem)
  return sort2DList(a, keyItem, {false}) of me
end sortList2DDecending

–2D Listをソート
on sort2DList(aList as list, sortIndexes as list, sortOrders as list)
  load framework
  
  
–index値をAS流(アイテムが1はじまり)からCocoa流(アイテムが0はじまり)に変換
  
set newIndex to {}
  
repeat with i in sortIndexes
    set j to contents of i
    
set j to j – 1
    
set the end of newIndex to j
  end repeat
  
  
–Sort TypeのListを作成(あえて外部から指定する内容でもない)
  
set sortTypes to {}
  
repeat (length of sortIndexes) times
    set the end of sortTypes to "compare:"
  end repeat
  
  
–Sort
  
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:newIndex ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as {missing value, list}
  
  
return resList
end sort2DList

★Click Here to Open This Script 

Posted in 2D Bin Packing list Record Sort | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote | 1 Comment

packit4meを利用して3D Bin Packingを解く

Posted on 4月 20, 2019 by Takaaki Naganoya

指定の広さの空間(Bin)に任意のサイズのブロックの組み合わせを最適化して詰め込むPackingの問題を解くAppleScriptです。

→ 別途、2D Bin PackingのAppleScriptを掲載しています「RectangleBinPackを用いて2D Bin Packを解く」

身の回りのさまざまな用途で利用されている2D/3D Bin Packing。ところが、実際に使ってみたいと思っても、使い勝手のよいプログラムが見当たりません。Cocoa Frameworkになっていて、NSRectをリストで渡すと結果を返してくれるようなものが個人的には理想的ですが、そういう仕様のものはほぼありません(完全にないわけではないものの、使い物にならない、、、)。

そこで、一応自分でも2D Bin Packing処理をAppleScriptで書いたものの、「ぴよまるソフトウェア」内で相談したところ外部公開はしにくい状況。

そうはいっても、2D Bin Packingを利用したあんな用途やこんな用途が山のようにあるので、外部のプログラムを呼び出してみるのがよいだろうかと(ふたたび)考え出したときに、まさかのREST APIで2D/3D Bin Packingの機能を提供しているpackit4meを発見(よく見つかったな)。

Web APIを呼び出して、3D Bin Packingを計算します。よくあるREST APIなので、プログラミングではなく「作業」のレベルで対処できます。

で、3D Bin Packingはいいものの、本命の2D Bin Packingを計算。

Keynote上のオブジェクトから情報を取得して….

packit4meで2D Bin Packを解かせてみると、Web上の3Dプレビュー(↑)はともかく、JSON(↓)で返してくる値が割とむちゃくちゃ。

[{"size": "40 x 30","id": "0","size_1": 40,"size_2": 30,"weight_limit": 3,"curr_weight": 3,"item_count": 3,"items": [{"id": "2","orig_size": "17 x 12","sp_size": "17 x 12","size_1": 17,"size_2": 12,"sp_size_1": 17,"sp_size_2": 12,"x_origin_in_bin": -11.5,"y_origin_in_bin": -9,"weight": 1,"constraints": 0},{"id": "1","orig_size": "7 x 12","sp_size": "7 x 12","size_1": 7,"size_2": 12,"sp_size_1": 7,"sp_size_2": 12,"x_origin_in_bin": 0.5,"y_origin_in_bin": -9,"weight": 1,"constraints": 0},{"id": "3","orig_size": "17 x 3","sp_size": "17 x 3","size_1": 17,"size_2": 3,"sp_size_1": 17,"sp_size_2": 3,"x_origin_in_bin": -11.5,"y_origin_in_bin": -1.5,"weight": 1,"constraints": 0}]}]

座標値にマイナスの値が含まれているなどうまく動いていない印象を受けます(制約条件が違うんだろか?)。

少なくとも、作者は2D Bin PackのJSON出力は検証していないのではないでしょうか、、、、残念!

AppleScript名:POST method REST API_packit4me
— Created 2019-04-20 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
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 NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

set aBinPack to "bins=0:50:5x5x5&items=0:0:0:1x2x3,0:0:0:1x2x3,0:0:0:1x2x3&binId=0"

set aRes to binPackByPackIt4me(aBinPack) of me
–> {size_1:5, size_2:5, size_3:5, |id|:"0", weight_limit:50, curr_weight:0, |size|:"5 x 5 x 5", item_count:3, |items|:{{|id|:"0", sp_size_3:3, x_origin_in_bin:-2, orig_size:"1 x 2 x 3", weight:0, sp_size:"1 x 2 x 3", y_origin_in_bin:-1.5, constraints:0, size_3:3, sp_size_1:1, z_origin_in_bin:1, size_2:2, sp_size_2:2, size_1:1}, {|id|:"0", sp_size_3:3, x_origin_in_bin:-1, orig_size:"1 x 2 x 3", weight:0, sp_size:"1 x 2 x 3", y_origin_in_bin:-1.5, constraints:0, size_3:3, sp_size_1:1, z_origin_in_bin:1, size_2:2, sp_size_2:2, size_1:1}, {|id|:"0", sp_size_3:3, x_origin_in_bin:-2, orig_size:"1 x 2 x 3", weight:0, sp_size:"1 x 2 x 3", y_origin_in_bin:0.5, constraints:0, size_3:3, sp_size_1:1, z_origin_in_bin:1, size_2:2, sp_size_2:2, size_1:1}}}

on binPackByPackIt4me(aBinPack as string)
  set tmpData to (do shell script "curl -X POST -H \"Content-Type: application/x-www-form-urlencoded\" -d \"" & aBinPack & "\" http://www.packit4me.com/api/call/raw")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
set aRec to aJsonDict as record
  
return aRec
end binPackByPackIt4me

★Click Here to Open This Script 

Posted in 2D Bin Packing list Record REST API | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSString NSURL NSUTF8StringEncoding | Leave a comment

Numbersで指定の2つの書類のデータのdiffを取る

Posted on 4月 19, 2019 by Takaaki Naganoya

指定の2つのNumbers書類(の中の現在表示中のシートのTable 1)同士のdiffを取るAppleScriptです。

# 書類内のシート内のどの表を処理するか、という階層化された対象選択を行うのにNSOutlineViewを用いたアラートダイアログを作っておきたい気持ちでいっぱいです

バージョン違いの書類間の差分を検出してレポートします。差分の評価は行単位で行なっており、同じデータでもカラムの順番を変えてあったりすると「別物」として検出します。

ただし、Numbersから2次元配列としてデータを抽出する際にすべてAppleScriptで処理するように書き換えた(macOS 10.14対策)ルーチンを使用しているので、大規模データの処理を行わせると(データ取得処理部分は)遅くなる可能性があります。

diffの計算部分はCocoaの機能に依存した(甘えまくった)処理を行なっているため、データが大きくてもそれほど遅くなりません。

612行の旧データと610行の新データをそれぞれ取得して差分を計算するのに、開発環境でだいたい3.5秒ぐらいです。同じ環境でBridgePlusを用いて1D List–> 2D List変換を行うバージョンを試してみたら、0.83秒ぐらいでした。

AppleScript名:Numbersで指定の2つの書類のデータのdiffを取る.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—

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

tell application "Numbers"
  set dList to name of every document
  
set oldDoc to contents of first item of (choose from list dList with prompt "古いデータを選択してください")
  
set newDoc to contents of first item of (choose from list dList with prompt "新しいデータを選択してください")
end tell

set oldData to get2DListFromADoc(oldDoc) of me
set newData to get2DListFromADoc(newDoc) of me

–List同士のDiffを計算する
set dRes to getDiffBetweenLists(oldData, newData) of me
–> {addItems:{{"キャッツアイ恵庭", 42.87588548, 141.5834606, "北海道 恵庭市 住吉町 2-9-1"}}, minusItems:{{"セガワールド白河", 37.11931521, 140.1944139, "福島県 白河市 新高山 1-1 メガステージ白河内"}, {"プレイアイシー", 35.3721071, 139.272272, "神奈川県 秦野市 南矢名 1-15-1"}, {"駅前スタジアムIII", 33.8395736, 132.7521903, "愛媛県 松山市 大手町 2-4-1"}}}

on get2DListFromADoc(aDocName)
  tell application "Numbers"
    tell document aDocName
      tell active sheet
        set theTable to table 1
        
        
tell theTable
          set selection range to cell range
          
          
set hcCount to header column count
          
set hrCount to header row count
          
set frCount to footer row count
          
          
set cCount to column count
          
set rCount to row count
          
          
set outList to {}
          
          
repeat with i from (hrCount + 1) to rCount
            tell row i
              set tmpList to value of cells (hcCount + 1) thru cCount
              
set the end of outList to tmpList
            end tell
          end repeat
        end tell
        
        
return outList
        
      end tell
    end tell
  end tell
end get2DListFromADoc

on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSMutableSet NSSet Numbers | Leave a comment

レコードのリストを複数Keyでソート

Posted on 4月 19, 2019 by Takaaki Naganoya

リストに入れたレコードを複数キー、キーごとのソート方向(ascending/descending)指定でソートするAppleScriptです。

ソート対象のラベルはサンプルのように階層構造ごと指定できます。キーとして列挙するラベルは、最初のものが主キーで、2番目以降はサブキーです。

AppleScript名:レコードのリストを複数Keyでソート.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

set aRecList to {{aName:"piyoko", aVal:10, bVal:{x:3, y:1}}, {aName:"piyomaru", aVal:20, bVal:{x:5, y:2}}, {aName:"piyoo", aVal:20, bVal:{x:4, y:5}}, {aName:"piyozo", aVal:10, bVal:{x:10, y:9}}}

set bList to sortRecListByLabel(aRecList, {"aVal", "bVal.x"}, {true, false}) of me
–> {{aName:"piyozo", aVal:10, bVal:{x:10, y:9}}, {aName:"piyoko", aVal:10, bVal:{x:3, y:1}}, {aName:"piyomaru", aVal:20, bVal:{x:5, y:2}}, {aName:"piyoo", aVal:20, bVal:{x:4, y:5}}}

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set aCount to length of aLabelStr
  
set sortDescArray to current application’s NSMutableArray’s new()
  
repeat with i from 1 to aCount
    set aLabel to (item i of aLabelStr)
    
set aKey to (item i of ascendF)
    
set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey)
    (
sortDescArray’s addObject:sortDesc)
  end repeat
  
  
return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list
end sortRecListByLabel

★Click Here to Open This Script 

Posted in list Record Sort | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSMutableArray NSSortDescriptor | Leave a comment

Numbersの表を回転

Posted on 4月 18, 2019 by Takaaki Naganoya

Numbers書類上の現在のシートの指定の表を回転させるAppleScriptです。

画像のようにぐるぐる回すわけではなく、90度回転状態と通常状態を切り替えるようです。


▲初期状態


▲transpose1回実行


▲transpose2回実行

AppleScript名:Numbersの表を回転
tell application "Numbers"
  tell front document
    tell active sheet
      tell table 1
        transpose
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in How To | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Numbers | 1 Comment

Google Sheets URLから正規表現でIDを抽出 v2

Posted on 4月 18, 2019 by Takaaki Naganoya

文字列で与えられたGoogle SpreadSheetsのURLから正規表現の機能を用いてSheets IDを抽出するAppleScriptです。

初回掲載時の内容にShane Stanleyから「長さが0の文字列」(zero length string)に対応できていないので、変更したほうがいいよ、という助言をもらったので書き換えました(Thanks Shane!)。

AppleScript名:Google Sheets URLから正規表現でIDを抽出 v2
— Created 2019-04-18 by Takaaki Naganoya
— Modified 2019-04-19 by Shane Stanley
use AppleScript version "2.5" –macOS 10.11 or later
use scripting additions
use framework "Foundation"

property NSString : a reference to current application’s NSString
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch

–https://developers.google.com/sheets/guides/concepts?hl=ja
set aURLText to "https://docs.google.com/spreadsheets/d/1qpyC0XzvTcKT6EISywvqESX3A0MwQoFDE8p-Bll4hps/edit#gid=0
"

set sheetsID to (stripGoogleSheetsIDFromURL(aURLText) of me) as string
–> "1qpyC0XzvTcKT6EISywvqESX3A0MwQoFDE8p-Bll4hps"

set aURLText to "" –Zero Length String
set sheetsID to (stripGoogleSheetsIDFromURL(aURLText) of me) as string
–> ""

on stripGoogleSheetsIDFromURL(aText as string)
  set sStrHead to "/spreadsheets/d/"
  
set regStr to sStrHead & "([a-zA-Z0-9-_]+)"
  
  
set anNSString to NSString’s stringWithString:aText
  
set aRange to anNSString’s rangeOfString:regStr options:(NSRegularExpressionSearch)
  
  
–if aRange = {location:0, length:0} then return ""–v1
  
if |length| of aRange = 0 then return "" –Prepare for zero length strings(Thanks Shane!)
  
  
set bStr to anNSString’s substringWithRange:aRange
  
set theString to bStr’s stringByReplacingOccurrencesOfString:sStrHead withString:"" options:(NSRegularExpressionSearch) range:{location:0, |length|:length of sStrHead}
  
  
return theString as string
end stripGoogleSheetsIDFromURL

★Click Here to Open This Script 

Posted in regexp Text URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSRegularExpressionSearch NSString | Leave a comment

Numbers書類の表のフィルタ状態のトグル切り替え

Posted on 4月 17, 2019 by Takaaki Naganoya

Numbers書類上の表のフィルタ状態のトグル切り替えを行うAppleScriptです。

Excelと異なりNumbersは割と静的なデータを保持する表計算ソフトです。他のシート上の値を参照するといった機能はなく、つい数年前までは関数もごく基本的なものしか搭載されていませんでした(現在はCephes Math Libraryを採用して関数を揃えています)。

そんなNumbersにも、動的な機能がいくつかあり、それが(1)並べ替え(ソート)(2)フィルタ の2つです。

Numbersのtableオブジェクト(表)には属性値「filtered」(boolean)が用意されており、

AppleScriptからの書き換えが許可されているため、ここにtrueを代入すればあらかじめ表に登録しておいたフィルタが機能しますし、falseを代入すればフィルタ状態を解除できるようになっています。

本Scriptはこの切り替えをテストしてみたものです。フィルタ状態を有効にしても、あらかじめ表(table)にフィルター内容が指定していなければ、何も動作は行いません。フィルタ内容をAppleScript側から指定することもできません。

AppleScript名:Numbers書類の表のフィルタ状態のトグル切り替え
tell application "Numbers"
  tell front document
    tell active sheet
      tell table 1
        set aFillF to filtered
        
set filtered to not aFillF
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in boolean | Tagged 10.12savvy 10.13savvy 10.14savvy Numbers | Leave a comment

Keynote上で選択中のオブジェクトのRectangleを合成

Posted on 4月 17, 2019 by Takaaki Naganoya

Keynoteでオープン中の書類の現在表示中の(選択中の)スライド(ページ)上のshapeオブジェクトの矩形領域をすべて合成したRectangleのshapeオブジェクトを作成するAppleScriptです。

本来はほかの動作を行うプログラムの試作品なのですが、いまのところNSRectの合成を行うのが目的になっています。

PlaneなAppleScriptとCocoaの機能の両方を組み合わせないと実現できない機能でもあり、もうひと押しですごい処理ができそうな気がしないでもありません。

Keynote v9.xであらたにAppleScript用語辞書に記載された「selection」はまだfront documentやcurrent slideのレベルでしか動作しておらず、slide上で選択中のiWork itemや各Object中のobject textの選択部分を取得できたりはしないので注意が必要です。


▲実行前


▲実行後

AppleScript名:Keynote上で選択中のオブジェクトのRectangleを合成
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/17
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property totalRect : missing value

tell application "Keynote"
  tell front document
    tell current slide
      –SelectionがまだKeynoteでうまく働いていないので、そのかわり
      
set aaList to every iWork item
      
set aList to {}
      
repeat with i in aaList
        if (class of i) is in {shape} then
          set the end of aList to contents of i
        end if
      end repeat
      
      
–最初のアイテムを取り出す
      
set aFirst to contents of first item of aList
      
set {x1Pos, y1Pos} to position of aFirst
      
set aHeight to height of aFirst
      
set aWidth to width of aFirst
      
set my totalRect to {origin:{x:x1Pos, y:y1Pos}, |size|:{|width|:aWidth, |height|:aHeight}}
      
      
–残りのアイテムをNSRectに変換しつつ加算      
      
set aList to rest of aList
      
      
repeat with i in aList
        set aProp to properties of i
        
set aHeight to height of aProp
        
set aWidth to width of aProp
        
set anArea to aHeight * aWidth
        
set {x2Pos, y2Pos} to position of i
        
        
set tmpRect to {origin:{x:x2Pos, y:y2Pos}, |size|:{|width|:aWidth, |height|:aHeight}}
        
calcUnionRect(tmpRect) of me –Rectangleの加算を行う        
      end repeat
      
      
–Rectangleを合成した大きさと位置でshapeを新規作成
      
set tRect to (totalRect as record)
      
set newProp to {position:{(x of origin of tRect), (y of origin of tRect)}, width:(|width| of |size| of tRect), height:(|height| of |size| of tRect)}
      
set newShape to make new shape with properties newProp
      
set opacity of newShape to 30
    end tell
    
  end tell
end tell

on calcUnionRect(addRect)
  set totalRect to current application’s NSUnionRect(totalRect, addRect)
end calcUnionRect

★Click Here to Open This Script 

Posted in list Record | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote NSRect | Leave a comment

TerminalですべてのテーマのWindowを新規作成する

Posted on 4月 15, 2019 by Takaaki Naganoya

Terminal.appで実行環境に登録されているすべてのTerminalのテーマのWindowを新規オープンするAppleScriptです。

実行環境のTerminal.appに登録されている「プロファイル」をリストアップし、各プロファイル(AppleScript用語辞書的には「settings set」)で新規Windowを作成します。

本プログラムは、Terminal.appの機能確認のためのものであって、これ自体に意味はありません。

AppleScript名:TerminalですべてのテーマのWindowを新規作成する
— Created 2019-04-14 by Takaaki Naganoya
— 2019 Piyomaru Software

tell application "Terminal"
  set nList to name of every settings set
  
  
repeat with i in nList
    set j to contents of i
    
changeSettingAndMakeNewWindow(j) of me
  end repeat
end tell

on changeSettingAndMakeNewWindow(aTheme as string)
  tell application "Terminal"
    set tmpID to settings set aTheme
    
set default settings to tmpID
    
set startup settings to tmpID
    
    
tell window 1
      do script ""
      
activate
    end tell
  end tell
end changeSettingAndMakeNewWindow

★Click Here to Open This Script 

Posted in How To | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Terminal | Leave a comment

指定MIME TypeのUTI文字列などを取得する

Posted on 4月 14, 2019 by Takaaki Naganoya

指定MIME TypeからUTIの文字列などのさまざまな情報を取得するAppleScriptです。

漠然と身の回りにファイル拡張子、UTI、MIME-typeなどの情報が転がっていますが、それぞれの意味を考え直すと、向き不向きというか想定されている利用シーンなどが大幅に異なります。

種類 内容説明
ファイル拡張子 ファイルの形式を一意に特定するもの。ただし、「.jpg」「.jpeg」など若干の表記ゆらぎを許容。詐称できてしまう
UTI ファイルのmacOS上での形式を一意に特定するもの。OS側が判断するものだが、拡張子次第。ただし、ゆらぎがない。UTI同士は階層構造を形成しており、上位のUTI(public.image)を指定することで下位UTIもまとめて指定できたりする
MIME-type 当該のファイルがインターネット上のファイル交換時にどのように受け取られるかを示す識別子。AppleScriptバンドルは拡張子「.scptd」で、UTIは「com.apple.applescript.script-bundle」だが、MIME-typeを取得すると「inode/directory」となる

と、ずいぶん違います。指定のファイルからMIME-typeを取得するだけであれば、こんな感じでしょうか。ただ、拡張子からMIME-typeを取得したり、MIME-typeからUTIを求めたりと、相互に変換する場合には(変換に意味がある場合には)いろいろと道具が必要です。

AppleScript名:指定ファイルからMIME-typeを取得する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/14
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—

set aFile to POSIX path of (choose file)
set mRes to do shell script "/usr/bin/file -b –mime-type " & quoted form of aFile
–> "text/html"

★Click Here to Open This Script 

UTI.frameworkを用いる場合にはこちら。

UTI.frameworkをビルドして使用しています。macOS 10.11/10.12/10.13では~/Library/Frameworksにインストールしてスクリプトエディタ上で本Scriptを実行すると記述どおりの結果が得られます。

macOS 10.14ではScript Debuggerを使用するか、あるいはSIPを解除してスクリプトエディタ上で実行することが可能です。自分でビルドして自分でCode Signしたコードぐらい、ホームディレクトリ下で勝手に実行させてほしいものです。

–> UTI.framework (To ~/Library/Frameworks)

AppleScript名:指定MIME TypeのUTI文字列などを取得する.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/12
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "UTI" –https://github.com/macmade/objc-uti
use scripting additions

set aUTIObj to (current application’s UTI’s UTIWithMIMEType:"image/gif")

set aRes to aUTIObj’s identifier()
–> com.compuserve.gif

set aRes to aUTIObj’s |description|() as string
–> "Graphics Interchange Format(GIF)"

set aRes to aUTIObj’s preferredOSType() as string
–> "GIFf"

set aRes to aUTIObj’s isDynamic() as boolean
–> false

set aRes to aUTIObj’s preferredFilenameExtension() as string
–> "gif"

set aRes to aUTIObj’s preferredMIMEType() as string
–> "image/gif"

set aRes to aUTIObj’s preferredNSPboardType() as string
–> "missing value"

set aRes to aUTIObj’s declaration() as record
–> {UTTypeIdentifier:"com.compuserve.gif", UTTypeDescription:"Graphics Interchange Format (GIF)", UTTypeTagSpecification:{|com.apple.ostype|:{"GIFf"}, |public.mime-type|:{"image/gif"}, |public.filename-extension|:{"gif"}}, UTTypeConformsTo:{"public.image"}}

set aRes to aUTIObj’s declaringBundleURL()’s |path|() as string
–> "/System/Library/CoreServices/CoreTypes.bundle"

set aRes to aUTIObj’s tagSpecifications() as record
–> {|com.apple.ostype|:{"GIFf"}, |public.mime-type|:{"image/gif"}, |public.filename-extension|:{"gif"}}

set aRes to aUTIObj’s conformsTo() as list
–> {"public.image"}

set aRes to aUTIObj’s referenceURL()
–> missing value

set aRes to aUTIObj’s |version|()
–> missing value

★Click Here to Open This Script 

Posted in file MIME UTI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy | Leave a comment

指定フォルダ内のファイルのうち、指定UTIに該当するものをすべて取得してフルパスを返す

Posted on 4月 13, 2019 by Takaaki Naganoya

指定フォルダ内のファイルのうち、指定のUTIに該当するものをすべて取得してフルパス(file/POSIX)で返すAppleScriptです。

指定フォルダの直下のみを走査し、サブフォルダ内は走査しません。調べてみるとUTIでファイルを絞り込む機能は存在していないようなので(見落としているだけ?)、すべてファイルを取得してからループでUTIを調べつつ該当するかどうかチェックしています。

書けば書くほど「それってSpotlightでよくね?」という気がしますが、確実に取得したい(Spotlightインデックスが破損していたり、サーバー上のファイルではSpotlightが効かない場合もある)場合に使うとよいでしょうか。

AppleScript名:指定フォルダ内のファイルのうち、指定UTIに該当するものをすべて取得してフルパスを返す
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/13
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set aUTI to "com.adobe.pdf"
set libPath to ((path to documents folder) as string)
set posixLibPath to POSIX path of libPath

set f1List to getFilepathListByUTI(posixLibPath, aUTI, "file") of me
–> {file "Cherry:Users:me:Documents:0718kenpo.pdf", file "Cherry:Users:me:Documents:2013-09Rekihaku.pdf", file "Cherry:Users:maro:Documents:airserver.pdf"}

set f2List to getFilepathListByUTI(posixLibPath, aUTI, "POSIX") of me
–> {"/Users/me/Documents/0718kenpo.pdf", "/Users/me/Documents/2013-09Rekihaku.pdf", "/Users/me/Documents/airserver.pdf"}

on getFilepathListByUTI(aFolPOSIX, aUTI as string, aFileType as string)
  script spdFile
    property urlList : {}
  end script
  
  
if aFileType is not in {"file", "POSIX"} then return {}
  
  
set aFM to NSFileManager’s defaultManager()
  
set aFolExt to (aFM’s fileExistsAtPath:aFolPOSIX isDirectory:true) as boolean
  
if aFolExt = false then return {} –フォルダ自体が存在しなければヌルリストを返す
  
  
set aURL to |NSURL|’s fileURLWithPath:aFolPOSIX
  
set theOptions to ((current application’s NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((current application’s NSDirectoryEnumerationSkipsHiddenFiles) as integer)
  
set urlArray to (aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value))
  
if urlArray = missing value then return {}
  
  
set (urlList of spdFile) to urlArray as list
  
set newList to {}
  
  
repeat with i in (urlList of spdFile)
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, aUTI)
    
    
if utiRes is not equal to {} then
      if aFileType = "POSIX" then
        set the end of newList to j
      else if aFileType = "file" then
        set the end of newList to POSIX file j
      end if
    end if
    
  end repeat
  
  
return newList
end getFilepathListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

★Click Here to Open This Script 

Posted in file File path list UTI | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSDirectoryEnumerationSkipsHiddenFiles NSFileManager NSPredicate NSURL NSURLTypeIdentifierKey | 3 Comments

指定フォルダ内のファイルのうち、指定拡張子リストに入っているものをすべて取得してフルパスを返す

Posted on 4月 12, 2019 by Takaaki Naganoya

指定フォルダに入っているファイルのうち、指定拡張子リストに該当するものをフルパスで返すAppleScriptです。

macOS 10.6以降の64ビット化されたFinderは動作が遅いため、大量のファイル情報を取得するなどの用途には不向きです。このため、「(ファイル選択を取得する以外の)ファイル処理にはFinderを使わない」のが現在のAppleScriptのセオリーとなっています。

本Scriptでは、~/Library/Script Libraries/フォルダの存在確認と、その中に格納されている「scpt」「scptd」の拡張子を持つAppleScript書類ファイルのリストアップを高速に行います。

AppleScript名:指定フォルダ内のファイルのうち、指定拡張子リストに入っているものをすべて取得してフルパスを返す
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set anExpList to {"scpt", "scptd"} — no dot
set libPath to (((path to library folder from user domain) as string) & "Script Libraries:")
set posixLibPath to POSIX path of libPath
set fList to getFilepathListByExt(posixLibPath, anExpList) of me

on getFilepathListByExt(aFol, aExtList as list)
  set aFM to NSFileManager’s defaultManager()
  
set aFolExt to (aFM’s fileExistsAtPath:aFol isDirectory:true) as boolean
  
if aFolExt = false then return {} –フォルダ自体が存在しなければヌルリストを返す
  
  
set aURL to |NSURL|’s fileURLWithPath:aFol
  
set theOptions to ((current application’s NSDirectoryEnumerationSkipsPackageDescendants) as integer) + ((current application’s NSDirectoryEnumerationSkipsHiddenFiles) as integer)
  
set urlArray to aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:theOptions |error|:(missing value)
  
set thePred to NSPredicate’s predicateWithFormat_("pathExtension.lowercaseString IN %@", aExtList)
  
set anArray to (urlArray’s filteredArrayUsingPredicate:thePred)
  
return anArray as {missing value, list}
end getFilepathListByExt

★Click Here to Open This Script 

Posted in file list | Tagged 10.12savvy 10.13savvy 10.14savvy NSFileManager NSPredicate NSURL | Leave a comment

PDFのしおり(TOC)の内容を取得する v3

Posted on 4月 11, 2019 by Takaaki Naganoya

指定のTOCつきPDFからTOCをrecord in listで取得するAppleScriptです。各TOC項目のページ数、アウトラインレベル、ラベル(ページ名称)を順次取得して配列に出力します。

先日発売したBlogアーカイブ本のTOCを本Scriptで取得すると、以下のようになります(抜粋)。

{{pageIndex:1, outlineLevel:1, outLabel:"表紙"}, {pageIndex:2, outlineLevel:1, outLabel:"商標について"}, {pageIndex:3, outlineLevel:1, outLabel:"本書をご覧になるために"}, ... {pageIndex:34, outlineLevel:1, outLabel:"2011/1"}, {pageIndex:35, outlineLevel:2, outLabel:"リスト同士のdiffをとる"}, {pageIndex:40, outlineLevel:2, outLabel:"日本の月呼称を返す"}, {pageIndex:42, outlineLevel:2, outLabel:"指定の月を1月分リスト化"},...... {pageIndex:450, outlineLevel:1, outLabel:"奥付"}}

あれ? 「本書について」(2P)という記事が掲載もれしているのを、TOC出力から見つけてしまった、、、、、、、、

AppleScript名:PDFのしおり(TOC)の内容を取得する v3
— Created 2017-01-09 by Takaaki Naganoya
— Modified 2019-04-10 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"

property |NSURL| : a reference to current application’s |NSURL|
property PDFDocument : a reference to current application’s PDFDocument
property titleList : {}

set my titleList to {}

set aFile to POSIX path of (choose file of type {"com.adobe.pdf"})

set fileURL to |NSURL|’s fileURLWithPath:aFile
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:fileURL

–TOCの読み込み
set parentOL to aPDFdoc’s outlineRoot() –あらかじめTOCが存在していないとmissing valueになる
if parentOL is equal to missing value then
  display dialog "本PDFにはTOCが添付されていないため、処理を終了します" with title "No TOC Error:"
  
return
end if

getChilds(parentOL) of me
return (my titleList)
–> {{pageIndex:1, outlineLevel:1, outLabel:"表紙"}, {pageIndex:2, outlineLevel:1, outLabel:"商標について"}, {pageIndex:3, outlineLevel:1, outLabel:"本書をご覧になるために"}, {pageIndex:5, outlineLevel:1, outLabel:"まえがき"},…… {pageIndex:33, outlineLevel:1, outLabel:"2011年"}, {pageIndex:34, outlineLevel:1, outLabel:"2011/1"}, {pageIndex:35, outlineLevel:2, outLabel:"リスト同士のdiffをとる"}, {pageIndex:40, outlineLevel:2, outLabel:"日本の月呼称を返す"},…….}

–PDFOutlineを再帰で取得する
on getChilds(parentOL)
  set outLineStr to parentOL’s label()
  
set outLineCount to (parentOL’s numberOfChildren()) as number
  
  
repeat with i from 0 to (outLineCount – 1)
    set anOut to (parentOL’s childAtIndex:i)
    
    
–Label (Page Title)
    
set tmpOut to (anOut’s label()) as string
    
    
–Page Indel Label
    
set tmpInd to (anOut’s destination()’s page()’s label()) as integer
    
    
–Outline Level
    
set outlevel to 0
    
copy anOut to aTmpOut
    
repeat
      set aTmpOut to aTmpOut’s |parent|()
      
if aTmpOut = missing value then exit repeat
      
set outlevel to outlevel + 1
    end repeat
    
    
set the end of my titleList to {pageIndex:tmpInd, outlineLevel:outlevel, outLabel:tmpOut}
    
    
set tmpChild to (anOut’s numberOfChildren()) as integer
    
    
if tmpChild is not equal to 0 then
      getChilds(anOut) of me
    end if
  end repeat
end getChilds

★Click Here to Open This Script 

Posted in list PDF Record recursive call | Tagged 10.12savvy 10.13savvy 10.14savvy NSURL PDFDocument | Leave a comment

PDFのしおり(TOC)の内容を取得する v2

Posted on 4月 10, 2019 by Takaaki Naganoya

指定のTOCつきPDFからTOCを1Dリスト(1次元配列)で取得するAppleScriptです。各TOC項目のlabelの文字列を順次取得して1次元配列に出力します。

AppleScript名:PDFのしおり(TOC)の内容を取得する v2
— Created 2017-01-09 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"

property |NSURL| : a reference to current application’s |NSURL|
property PDFDocument : a reference to current application’s PDFDocument
property titleList : {}

set my titleList to {}

set aFile to POSIX path of (choose file of type {"com.adobe.pdf"})

set fileURL to |NSURL|’s fileURLWithPath:aFile
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:fileURL

–TOCの読み込み
set parentOL to aPDFdoc’s outlineRoot() –あらかじめTOCが存在していないとmissing valueになる
if parentOL is equal to missing value then
  display dialog "本PDFにはTOCが添付されていないため、処理を終了します" with title "No TOC Error:"
  
return
end if

getChilds(parentOL) of me
return (my titleList)

–再帰処理してみた
on getChilds(parentOL)
  set outLineStr to parentOL’s label()
  
set outLineCount to (parentOL’s numberOfChildren()) as number
  
  
repeat with i from 0 to (outLineCount – 1)
    set anOut to (parentOL’s childAtIndex:i)
    
set tmpOut to (anOut’s label()) as string
    
set the end of my titleList to tmpOut
    
set tmpChild to (anOut’s numberOfChildren()) as integer
    
    
if tmpChild is not equal to 0 then
      getChilds(anOut) of me
    end if
  end repeat
end getChilds

★Click Here to Open This Script 

Posted in list PDF recursive call | Tagged 10.12savvy 10.13savvy 10.14savvy NSURL PDFDocument | Leave a comment

Appleがいまだに直さないPDFViewのバグを回避する

Posted on 4月 10, 2019 by Takaaki Naganoya

PDFViewからcurrentPage()が取れないという、最低最悪レベルのバグが放置されたOSがリリースされ続けて2年。Devlopper Supportに報告しても返事の1つもない今日このごろです。

Apple Developper Connectionのインシデントを消費して質問しても返答がないので、本当に頭にきています。

この、macOS 10.13のBetaでは存在しなかったのにRelease版で作られた画期的なバグを回避するために、いろいろ工夫をしてみました。

テストしてみたところ、Objective-CやSwiftでは発生していないため、Scripting Bridgeのみで発生しているらしきバグのようです。こんな基本的な箇所でバグを作って直さない連中の気が知れません。

AppleのDevelopper Supportが役立たずで仕事をしないのは今日にはじまった話ではないので(Mailing Listが落ちた状態で、報告しても1か月放置した事件など)、仕方なく回避策を検討してみました。

(1)PDFViewまわりのWrapping ClassをObjective-Cで書いて使う
(2)Objective-Cでユーティリティを書いて、パラメータとして与えたPDFViewからObjective-CでcurrentPageを取得する
(3)今後もAppleがバグを作り続けることが予想されるため、サードパーティのPSPDFKitを導入する

といった対策を検討していたのですが、最も手短なものとして、

(4)表示中のページを自前で管理して、PDFViewに指定ページの内容を随時切り出して表示する

という対処を行ってみました。

PDFをオープンしてPDFViewで表示させ、左右の矢印キーでページをめくることができます。なお、macOS 10.14.5beta+Xcode 10.2上でビルドと確認を行いましたが、内容的にはXcodeのバージョンは関係ありません。

–> Download Xcode Project Archive (pdfTestZ)

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— pdfTestZ
—
— Created by Takaaki Naganoya on 2019/04/09.
— Copyright © 2019 Piyomaru Software. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property aView : missing value
  
property maxPageNum : 0
  
property curPageIndex : 0
  
property aPDFDoc : missing value
  
property pLabelField : missing value
  
  
  
on applicationWillFinishLaunching:aNotification
  
end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  
on clicked:aSender
    set aTag to (tag of aSender) as integer
    
    
if aTag = 100 then
      set aPath to choose file of type {"com.adobe.pdf"}
      
      
set pPath to POSIX path of aPath
      
set aURL to current application’s |NSURL|’s fileURLWithPath:pPath
      
set my aPDFDoc to current application’s PDFDocument’s alloc()’s initWithURL:aURL
      
      
set myFileName to (current application’s NSString’s stringWithString:pPath)’s lastPathComponent()
      
theWindow’s setTitle:myFileName
      
      
set maxPageNum to ((aPDFDoc’s pageCount()) as integer) – 1
      
set curPageIndex to 0
      
      
log {"maxPageNum", maxPageNum}
      
      
aView’s setAutoScales:true
      
aView’s setDisplaysPageBreaks:true
      
      
my dispCurPageDoc()
      
set tmpStr to ((maxPageNum + 1) as string) & "/" & ((curPageIndex + 1) as string)
      
pLabelField’s setStringValue:tmpStr
      
    else if aTag = 200 then
      
      
set tmpPage to my (aPDFDoc’s pageAtIndex:(curPageIndex))
      
set curPageLabel to tmpPage’s label()
      
      
tell current application
        display dialog (curPageLabel as string)
      end tell
      
    else if aTag = 1000 then
      my decPage()
      
my dispCurPageDoc()
      
    else if aTag = 1010 then
      my incPage()
      
my dispCurPageDoc()
      
    end if
    
  end clicked:
  
  
on dispCurPageDoc()
    set tmpPage to my (aPDFDoc’s pageAtIndex:(curPageIndex))
    
set tmpDoc to (current application’s PDFDocument’s alloc()’s initWithData:(tmpPage’s dataRepresentation()))
    
aView’s setDocument:tmpDoc
    
    
set tmpStr to ((maxPageNum + 1) as string) & "/" & ((curPageIndex + 1) as string)
    
pLabelField’s setStringValue:tmpStr
  end dispCurPageDoc
  
  
  
on incPage()
    if curPageIndex = maxPageNum then
      –何もしない
    else if curPageIndex < maxPageNum then
      set curPageIndex to curPageIndex + 1
    end if
  end incPage
  
  
on decPage()
    if curPageIndex = 0 then
      –何もしない
    else if curPageIndex > 0 then
      set curPageIndex to curPageIndex – 1
    end if
  end decPage
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode PDF | Tagged 10.13savvy 10.14savvy NSString NSURL PDFDocument PDFPage | 1 Comment

Post navigation

  • Older posts

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

Google Search

Popular posts

  • macOS 13, Ventura(継続更新)
  • アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3
  • UI Browserがgithub上でソース公開され、オープンソースに
  • macOS 13 TTS Voice環境に変更
  • Xcode 14.2でAppleScript App Templateを復活させる
  • 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