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

月: 2018年6月

Skimで現在表示中のPDFのページをJPEG画像で書き出す

Posted on 6月 30, 2018 by Takaaki Naganoya

オープンソースのPDFビューワー「Skim」で現在表示中のPDFの現在表示中のページをJPEG画像で書き出すAppleScriptです。

macOS標準装備のPreview.appはつい最近AppleScriptからの制御が公式に行えるようになった程度で、対応度も最低限です。Skimであれば、こうした「現在オープン中のPDFの表示中のページ」の番号を取得することもできます。

macOS標準装備のScript Menuから呼び出して利用することを前提に作成してあります。

Skimでオープン中の最前面のPDFと同じフォルダに、元ファイル名に対してページの数値をゼロパディングして追加したものをJPEG画像のファイル名に指定しています。ファイル名の重複回避などは行っていません。

ただし、Skimで表示モードが「単一」(1ページ分のみビューワーに表示)以外になっていると、カレントページ(現在表示中のページ)が画面上とアプリケーション側で管理しているものがズレることがあるので、表示モードを「単一」に切り替えてから「このページでよいか?」といった確認をユーザーに対して行うとよいかもしれません。

AppleScript名:Skimで現在表示中のPDFのページをJPEG画像で書き出す
— Created 2018-06-30 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSNumber : a reference to current application’s NSNumber
property NSZeroPoint : a reference to current application’s NSZeroPoint
property PDFDocument : a reference to current application’s PDFDocument
property NSJPEGFileType : a reference to current application’s NSJPEGFileType
property NSCompositeCopy : a reference to current application’s NSCompositeCopy
property NSGraphicsContext : a reference to current application’s NSGraphicsContext
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSImageInterpolationHigh : a reference to current application’s NSImageInterpolationHigh

tell application "Skim"
  set docCount to count every document
  
if docCount = 0 then return
  
  
tell front document
    set curInd to index of current page
    
set docFile to file of it
  end tell
end tell

set aPOSIX to POSIX path of docFile
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()

set compFactor to 1.0 –1.0 — 0.0 = max jpeg compression, 1.0 = none

–Detect Retina Environment
set retinaF to NSScreen’s mainScreen()’s backingScaleFactor()
if retinaF = 1.0 then
  set aScale to 2.0 –Non Retina Env
else
  set aScale to 1.0 –Retina Env
end if

–PDFをページごとに分割してJPEGでファイル書き出し
set i to (curInd – 1) –AppleScript index (1 based) to Cocoa index (0 based) conversion

–Pick Up a PDF page as an image
set thisPage to (aPDFdoc’s pageAtIndex:(i))
set thisDoc to (NSImage’s alloc()’s initWithData:(thisPage’s dataRepresentation()))
if thisDoc = missing value then error "Error in getting imagerep from PDF in page:" & (i as string)

–Resize Image
set pointSize to thisDoc’s |size|()
set newSize to current application’s NSMakeSize((pointSize’s width) * aScale, (pointSize’s height) * aScale)
set newImage to (NSImage’s alloc()’s initWithSize:newSize)

newImage’s lockFocus()
(
thisDoc’s setSize:newSize)
(
NSGraphicsContext’s currentContext()’s setImageInterpolation:(NSImageInterpolationHigh))
(
thisDoc’s drawAtPoint:(NSZeroPoint) fromRect:(current application’s CGRectMake(0, 0, newSize’s width, newSize’s height)) operation:(NSCompositeCopy) fraction:2.0)
newImage’s unlockFocus()

–Save Image as JPEG
set theData to newImage’s TIFFRepresentation()
set newRep to (NSBitmapImageRep’s imageRepWithData:theData)
set targData to (newRep’s representationUsingType:(NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
set zText to retZeroPaddingText((i + 1), 4) of me
set outPath to addString_beforeExtensionIn_addingExtension_("_" & zText, aPOSIX, "jpg")

(targData’s writeToFile:outPath atomically:true) –書き出し

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。任意の拡張子を追加
on addString:extraString beforeExtensionIn:aPath addingExtension:aExt
  set pathString to NSString’s stringWithString:aPath
  
set theExtension to pathString’s pathExtension()
  
set thePathNoExt to pathString’s stringByDeletingPathExtension()
  
  
set newPath to (thePathNoExt’s stringByAppendingString:extraString)’s stringByAppendingPathExtension:aExt
  
return newPath as string
end addString:beforeExtensionIn:addingExtension:

on retZeroPaddingText(aNum as integer, aDigitNum as integer)
  if aNum > (((10 ^ aDigitNum) as integer) – 1) then return "" –Range Check
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setUsesGroupingSeparator:false
  
aFormatter’s setAllowsFloats:false
  
aFormatter’s setMaximumIntegerDigits:aDigitNum
  
aFormatter’s setMinimumIntegerDigits:aDigitNum
  
aFormatter’s setPaddingCharacter:"0"
  
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:aNum)
  
return aStr as string
end retZeroPaddingText

★Click Here to Open This Script 

Posted in Image PDF | Tagged 10.11savvy 10.12savvy 10.13savvy NSBitmapImageRep NSImage NSNumber NSNumberFormatter NSScreen NSString NSURL PDFDocument Skim | Leave a comment

日付テキストを年単位で集計

Posted on 6月 29, 2018 by Takaaki Naganoya

yyyy-MM-dd HH:mm:ss形式の日付テキストをdateオブジェクトに変換して日付を年単位で集計するAppleScriptです。

Blog Archiveのデータベースのダンプテキストを読み取って、年別の投稿記事本数の集計を行うために作成しました(といっても、既存のルーチンを組み合わせただけです)。

AppleScript名:日付テキストを年単位で集計
— Created 2018-06-28 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSLocale : a reference to current application’s NSLocale
property NSDictionary : a reference to current application’s NSDictionary
property NSCountedSet : a reference to current application’s NSCountedSet
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSDateFormatter : a reference to current application’s NSDateFormatter

set aList to {"2006-06-27 02:38:52", "2008-03-09 19:08:05", "2008-03-09 19:29:29"}
set aRes to totalDateStrByYear(aList, "yyyy-MM-dd HH:mm:ss") of me
–> {{aCount:1, aKey:2006}, {aCount:2, aKey:2008}}

–日付テキストを年単位で集計
on totalDateStrByYear(aList, strFormat)
  set theCountedSet to NSCountedSet’s |set|()
  
set newArray to NSMutableArray’s new()
  
  
repeat with i in aList
    set postDate to dateFromStringWithDateFormat(i, strFormat) of me –日付テキストをDate Objectに変換
    
set yearStr to (year of postDate) –「年」の数字
    (
newArray’s addObject:yearStr)
  end repeat
  
  
set resArray to countItemsByItsAppearance(newArray) of me
  
set bList to sortRecListByLabel(resArray, "aKey", true) of me –昇順ソート
  
return bList
end totalDateStrByYear

–日付文字列からdate objectを作成する
on dateFromStringWithDateFormat(dateString, dateFormat)
  set dStr to NSString’s stringWithString:dateString
  
set dateFormatStr to NSString’s stringWithString:dateFormat
  
  
set aDateFormatter to NSDateFormatter’s alloc()’s init()
  
aDateFormatter’s setDateFormat:dateFormatStr
  
aDateFormatter’s setLocale:(NSLocale’s alloc()’s initWithLocaleIdentifier:"en_US_POSIX")
  
  
set aDestDate to (aDateFormatter’s dateFromString:dStr)
  
  
return aDestDate as list of string or string
end dateFromStringWithDateFormat

–登場頻度でリストを集計する
on countItemsByItsAppearance(aList)
  set aSet to NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"aKey", "aCount"})
  end repeat
  
  
return bArray
end countItemsByItsAppearance

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean)
  set aArray to NSArray’s arrayWithArray:aRecList
  
  
set sortDesc to NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortDescArray to NSArray’s arrayWithObjects:sortDesc
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
  
  
set bList to (sortedArray) as list of string or string
  
return bList
end sortRecListByLabel

★Click Here to Open This Script 

Posted in Calendar list | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Recruit Tech Japanese Text Summarization API

Posted on 6月 28, 2018 by Takaaki Naganoya

Recruit techのA3RT機械学習ソリューションAPIのひとつ、「Text Summarization API」(日本語文章要約API)を呼び出すAppleScriptです。

APIの説明ページからAPI Keyを取得して本リストに記載して実行させてみてください。

他の2つのAPIが箸にも棒にもひっかからないレベルであるのとは異なり、本APIは割と使えます。

使えるというよりも、「日本語文章要約」という処理の結果が適切かどうか、その妥当性の評価が難しいので「とりあえずそれっぽく動いている」ように見えます。

論文やニュース記事のような要約に適した論理構造の文章というものが、一般的にはかなり「まれ」な存在であり、たいていは要約してみても納得しづらいものになりがちです。とくに論理ではなく情緒に訴えるような「くだけた」書き方をすると要約しづらいものになります。

AppleScript自体にも「summarize」という文章要約コマンドが標準装備されており、日本語の文章に対しても実行できますが、処理結果に100%納得できているわけではありません。半信半疑というところです。

本来、文章要約という処理を考えると、「主語」が何か、その主語がどのようなアクションを起こしたり、起こされたりしたのか、という処理を期待したいところですが、かならずしもそのような処理結果が得られるわけではありません。文章構造上、重要と思われるような箇所をそのまま抜き出すような処理が行われます。

そのため、大当たりという印象はないものの、大外しになることもなく「なんとなくそんな感じ?」という割り切れないものを感じてしまいがちです。

日本語文章の要約はいつの日か実用的な、納得できるレベルの処理ができるようになるのかもしれませんが、目下のところはこのレベルで満足するべきなのかもしれません。

AppleScript名:Recruit Tech Japanese Text Summarization API
— Created 2018-06-13 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–https://a3rt.recruit-tech.co.jp/product/TextSummarizationAPI/

set apiKeyStr to getAPIKey() of me
set targText to returnBody() of me

set sText to "curl -X POST -d ’apikey=" & apiKeyStr & "’ –data-urlencode ’sentences=" & targText & "’ ’https://api.a3rt.recruit-tech.co.jp/text_summarization/v1/’"
set aRes to do shell script sText
set jsonString to current application’s NSString’s stringWithString:aRes
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)
set aRec to aJsonDict as record
–>  {​​​​​message:"Summarization is completed", ​​​​​status:0, ​​​​​summary:{​​​​​​​"世間的には「Appleが新製品を発表するイベント」と見られているけれども、本来そんなイベントではありません"​​​​​}​​​}

on getAPIKey()
  return "xXXXXXXxXxxxXXxxXxXXXxXxXXxxxxxx"
end getAPIKey

on returnBody()
  return "WWDCというイベントがあります。World Wide Developpers Conference。Appleが1年に一度、開発者を集めて「これからこういう感じのOSにしまっせー」という発表を行う場です。WWDCは例年、カリフォルニア州のモスコーニュ・センターというバカでかいイベント会場で行われます。数千人単位で収容できる会場で、参加者は朝の4~5時ぐらいから並ぶと聞きました。遅く行くと後ろの方のスクリーンから遠い席になるのだとか。世間的には「Appleが新製品を発表するイベント」と見られているけれども、本来そんなイベントではありません。ほかにいろいろイベントがあったのが、WWDCだけ残ったのでたまたま新製品発表があったりするだけの話で、なにが言いたいかといえば、本来はハードウェア製品の発表の場ではなくてOSなどのソフトウェアの(開発者向けの)話をする発表会でした。"
end returnBody

★Click Here to Open This Script 

AppleScript名:summarize
set aStr to returnBody() of me
set bStr to summarize aStr in 1
–> "ほかにいろいろイベントがあったのが、WWDCだけ残ったのでたまたま新製品発表があったりするだけの話で、なにが言いたいかといえば、本来はハードウェア製品の発表の場ではなくてOSなどのソフトウェアの(開発者向けの)話をする発表会でした。"

on returnBody()
  return "WWDCというイベントがあります。World Wide Developpers Conference。Appleが1年に一度、開発者を集めて「これからこういう感じのOSにしまっせー」という発表を行う場です。WWDCは例年、カリフォルニア州のモスコーニュ・センターというバカでかいイベント会場で行われます。数千人単位で収容できる会場で、参加者は朝の4~5時ぐらいから並ぶと聞きました。遅く行くと後ろの方のスクリーンから遠い席になるのだとか。世間的には「Appleが新製品を発表するイベント」と見られているけれども、本来そんなイベントではありません。ほかにいろいろイベントがあったのが、WWDCだけ残ったのでたまたま新製品発表があったりするだけの話で、なにが言いたいかといえば、本来はハードウェア製品の発表の場ではなくてOSなどのソフトウェアの(開発者向けの)話をする発表会でした。"
end returnBody

★Click Here to Open This Script 

Posted in REST API Text URL | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Finder上で選択中のPDFのファイル名の数字部分で小さいものから大きなものへとソート

Posted on 6月 27, 2018 by Takaaki Naganoya

Finder上で選択中のPDFのうち、ファイル名中の数字が小さいものから大きなものへソートを行うAppleScriptです。

Finder上で選択中のPDFをファイル名順でソートするような用途に使用します。選択中のファイルのうちPDFに該当しないものは無視します。

Finderで選択中の各PDFファイルに数字以外の文字がファイル名に混入していても無視します。

ファイル名はいったん数値として評価してソートするため、ファイル名にゼロパディングしてある場合には無視します。

Finder上で選択中のPDFを連結するさいに、ファイル名順で連結するScriptがあったほうが便利なので、そのために作ったものです。

ソートを行う際に、ファイル名の中の数字以外の部分をすべて無視するようにしています。そのため、Finder上の並び順と関係なく、ファイル名の中の数字部分のみをピックアップしてソートします。Finder自体にもFinderのルールでファイル名をソートして返すAppleScriptの機能がありますが、あれに甘えているとまともな処理はできません。

「test1_0004.pdf」というファイル名があった場合には10004という数値を検出するため、こうしたケースに対応する必要があるかもしれませんが、現時点では無用な数字の除去はしていません(それこそ一括処理で行うものではなくユーザーの目で見て判断してもらうような処理なので)。

AppleScript名:Finder上で選択中のPDFの数字のファイル名で小さいものから大きなものへとソート
— Created 2018-06-26 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use mdLib : script "Metadata Lib" version "1.0.0" –https://www.macosxautomation.com/applescript/apps/
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

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 NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey

tell application "Finder"
  set inFiles to selection as alias list
end tell

if inFiles = {} then return

–指定のAlias listのうちPDFのみ抽出
set filRes1 to filterAliasListByUTI(inFiles, "com.adobe.pdf") of me

–ファイル名
set cList to {}
repeat with i in (filRes1 as list)
  set j to contents of i
  
set aFileName to ((current application’s NSString’s stringWithString:j)’s valueForKeyPath:"lastPathComponent.stringByDeletingPathExtension")
  
  
set aNumF to returnNumberCharsOnly(aFileName) of me
  
set the end of cList to {numDat:(aNumF as integer), pathDat:j}
end repeat

set aResList to sortRecListByLabel(cList, "numDat", true) of me –昇順ソート
set bResList to (aResList’s valueForKeyPath:"pathDat") as list of string or string
–>  {​​​​​"/Users/me/Pictures/243.pdf", ​​​​​"/Users/me/Pictures/244.pdf", ​​​​​"/Users/me/Pictures/245.pdf", ​​​​​"/Users/me/Pictures/246.pdf", ​​​​​"/Users/me/Pictures/247.pdf", ​​​​​"/Users/me/Pictures/248.pdf", ​​​​​"/Users/me/Pictures/249.pdf", ​​​​​"/Users/me/Pictures/250.pdf", ​​​​​"/Users/me/Pictures/251.pdf", ​​​​​"/Users/me/Pictures/252.pdf", ​​​​​"/Users/me/Pictures/253.pdf", ​​​​​"/Users/me/Pictures/254.pdf", ​​​​​"/Users/me/Pictures/255.pdf", ​​​​​"/Users/me/Pictures/256.pdf", ​​​​​"/Users/me/Pictures/257.pdf"​​​}

–文字列中から
on returnNumberCharsOnly(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:"[^0-9]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
return anNSString as text
end returnNumberCharsOnly

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean)
  –ListからNSArrayへの型変換
  
set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
–ソート
  
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
  
return sortedArray
end sortRecListByLabel

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定の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 PDF Sort | Tagged 10.11savvy 10.12savvy 10.13savvy Finder | Leave a comment

Recruit Tech Japanese Proofreading API

Posted on 6月 26, 2018 by Takaaki Naganoya

Recruit techのA3RT機械学習ソリューションAPIのひとつ、「Proofreading API」(日本語文章校正API)を呼び出すAppleScriptです。

APIの説明ページからAPI Keyを取得して本リストに記載して実行させてみてください。

「とりあえず作ってみました」レベルで実用性については皆無です。誤変換を指摘できるという触れ込みなのですが、助詞の多重入力、誤変換などほとんど見落としてくれます。

日本語の新語作成能力が高いのと、日本語自体がわりとずさんな運用が行われているといった事情もあり、日本語スペルチェックで完全なものを作れると言い切るには勇気が必要です。

日本語文章のスペルチェックという目的自体が壮大すぎて、実用レベルまで持っていくこと自体が大変です。ある程度の「割り切り」が必要になってくるものと思われます。ただ、このAPIがどういう割り切りを行なったのかが見えてきません、、、

AppleScript名:Recruit Tech Japanese Proofreading API
— Created 2018-06-13 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–https://a3rt.recruit-tech.co.jp/product/proofreadingAPI/

set apiKeyStr to getAPIKey() of me
set targText to returnBody() of me
set sensitivity to "high"

set sText to "curl -X POST -d ’apikey=" & apiKeyStr & "’ –data-urlencode ’sentence=" & targText & "’ ’sensitivity=" & sensitivity & "’ ’https://api.a3rt.recruit-tech.co.jp/proofreading/v2/typo’"
set aRes to do shell script sText
set jsonString to current application’s NSString’s stringWithString:aRes
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)
set aRec to aJsonDict as record
–>  {resultID:"0dee57af118a", status:1, inputSentence:"本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表貝でさた。", normalizedSentence:"本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表貝でさた。", alerts:{{|word|:"貝", suggestions:{"ま", "会", "す"}, score:1.0, pos:41}}, message:"pointed out", checkedSentence:"本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表 <<貝>> でさた。"}

on getAPIKey()
  return "XXXXxXxxXXXxXXXxxxXXxxXXxXXXXXXx"
end getAPIKey

on returnBody()
  return "本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表貝でさた。"
end returnBody

★Click Here to Open This Script 

Posted in Network REST API Text | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Recruit Tech Small Talk API

Posted on 6月 25, 2018 by Takaaki Naganoya

Recruit techのA3RT機械学習ソリューションAPIのひとつ、「Small Talk API」を呼び出すAppleScriptです。

エンタメ用に機械学習させたお手軽日本語チャットボット作成用のAPIとのこと。APIの説明ページからAPI Keyを取得して本リストに記載して実行させてみてください。

「おはよう」に「おはよう」で返したり、質問に質問で返すような「使えないチャットボットAPI」ですが、雑談系チャットボットに過剰な期待をするのは間違いなので、こんなもんなんでしょう。

AppleScript名:Recruit Tech Talk API
— Created 2018-06-13 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set apiKeyStr to getAPIKey() of me
set targText to text returned of (display dialog "Input Some text" default answer "")

set sText to "curl -X POST -d ’apikey=" & apiKeyStr & "’ –data-urlencode ’query=" & targText & "’ ’https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk’"
set aRes to do shell script sText
set jsonString to current application’s NSString’s stringWithString:aRes
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)
set aRec to aJsonDict as record
–>  {​​​​​status:0, ​​​​​message:"ok", ​​​​​results:{​​​​​​​{​​​​​​​​​perplexity:0.834903951818, ​​​​​​​​​reply:"何の事でしょう?"​​​​​​​}​​​​​}​​​}
–>  {​​​​​status:2000, ​​​​​message:"empty reply"​​​}

set curStat to status of aRec
if curStat is not equal to 0 then return false
set theAns to (aJsonDict’s valueForKeyPath:"results.reply") as list of string or string
say theAns using "Otoya" –"Kyoko" or "Otoya"

on getAPIKey()
  return "XXXXxxxXxxXXXxXXXxXxxXXxxxXxXxXX"
end getAPIKey

★Click Here to Open This Script 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Call Postmark’s spam detection API

Posted on 6月 21, 2018 by Takaaki Naganoya

PostmarkのSpamAssassin REST APIを呼び出してメールのスパム判定を行うAppleScriptです。

NSURLSessionを用いてPOST methodのREST APIを呼び出しています。

メール本文のソーステキストを渡すと、スパム度のスコアを計算して返してくれます。パラメータの「options」で「short」か「long」を指定でき、最終的な評価値のみ知りたい場合には前者を、詳細情報を知りたい場合には後者を指定することになります。

すでにMail.appにスパム判定の機能が標準搭載されているため、スパムフィルタ単体で利用する用途というのは減ってきましたが、メールの送信前にスパムフィルタに引っかからないかをチェックしておく(メールマガジン作成時など)ためには「あったほうが便利」な処理です。

本APIを利用するのに、事前のユーザー登録やAPI Keyを取得する必要はありません。このリストを実行するとそのまま結果が得られます。Mail.appのメッセージのソースを渡すのもたいして手間はかかりません。

ただし、本APIは継続して提供される保証もありませんし、トラブルが発生して動作が止まっていた場合に対処してくれたりはしません。実際の業務ほかシビアな用途で利用するのはためらわれるものがあります。

ローカルにSpamSieveをインストールしてAppleScriptで呼び出すと同様にスパム評価値を計算してくれるので、メールのSPAM判定のための用途にはこれも検討に値するでしょう。

AppleScript名:Call Postmark’s spam API
— Created 2018-06-20 by Takaaki Naganoya
— 2018 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 NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

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

set aBody to "raw dump of email"

–https://spamcheck.postmarkapp.com/doc/
set aURL to "https://spamcheck.postmarkapp.com/filter"
set aRec to {email:aBody, options:"long"}

set aRESTres to callRestPOSTAPIAndParseResults(aURL, aRec, 10) of me
set aRESTcode to retCode of aRESTres
–> 200

set aRESTheader to retHeaders of aRESTres
set aRESTres to retData of aRESTres
–> {success:true, rules:{{score:"1.2", |description|:"Missing To: header"}, {score:"-0.0", |description|:"Informational: message was not relayed via SMTP"}, {score:"1.4", |description|:"Missing Date: header"}, {score:"1.8", |description|:"Missing Subject: header"}, {score:"2.3", |description|:"Message appears to have no textual parts and no Subject: text"}, {score:"0.1", |description|:"Missing Message-Id: header"}, {score:"-0.0", |description|:"Informational: message has no Received headers"}, {score:"1.0", |description|:"Missing From: header"}, {score:"0.0", |description|:"Message appears to be missing most RFC-822 headers"}}, score:"7.9", report:" …."}

on callRestPOSTAPIAndParseResults(reqURLStr as string, aRec as record, timeoutSec as integer)
  set retData to missing value
  
set retCode to 0
  
set retHeaders to {}
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"POST"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:timeoutSec
  
–aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"–Does not work with this API & Method
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aRec options:0 |error|:(missing value)
  
aRequest’s setHTTPBody:dataJson
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
set hitF to false
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if retData is not equal to missing value then
      set hitF to true
      
exit repeat
    end if
    
delay ("0.001" as real)
  end repeat
  
  
if hitF = false then error "REST API Timeout Error"
  
  
return {retData:retData, retCode:retCode, retHeaders:retHeaders}
end callRestPOSTAPIAndParseResults

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

★Click Here to Open This Script 

Posted in JSON Network Record REST API URL | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Bash In Tokyoで音声認識コマンドプログラムをデモしてきました

Posted on 6月 17, 2018 by Takaaki Naganoya

6月15日(金)に渋谷で行われた「Bash In Tokyo」にて、急遽作成した音声認識コマンド実行プログラムをデモしてきました。

macOSの「音声認識コマンド」と「音声文字入力」の中間のような動きをしていて、シソーラス辞書(同義語辞書)を搭載しているため、パラメータの表現の「ゆらぎ」を許容する構造になっています。

GUI部分はXcode上のAppleScriptのプロジェクトであり、呼び出されるコマンド側も(編集可能な)AppleScriptのファイルです。現段階では、コマンド側のAppleScriptのファイル名にコマンドとパラメータを記述してあり、音声認識したテキストを形態素解析して、コマンドやパラメータに該当する品詞の単語をピックアップし、コマンド側の単語とのマッチングを行います。

本プログラムを作成する前に「Web APIでチャットボットなんか使えば楽をできるのでは?」と考えて調査はしてみたものの、結論からいえば「雑談暇つぶしボットぐらいしかできない」という印象でした。お金をかけて作り込めばMicrosoft Bot Frameworkにしても、NTT Communicatins 「COTOHA」にしても使えるとは思うのですが、特定のコマンドキーワードを認識したあとは急に業務系アプリっぽい挙動になったり、コマンド実行の演出とかはとくにないので、「自分で作ったほうがマシ」だということに、、、、デモの前日に気づきました。

# つまり、プログラムのコア部分は1日かけずに作ったという、、、、

もうちょっと調整して何かのデモに使ってみたいところです。

Posted in 未分類 | Leave a comment

GET method REST API v4.1

Posted on 6月 17, 2018 by Takaaki Naganoya

Web上のREST APIを、NSURLSessionを用いて呼び出すAppleScriptの改良版です。

status code、Response Header、処理結果をそれぞれ返すように改良してみました。これで、実際のプログラムに組み込むことができるようになりました。

Response Headerの各フィールドはスペースやハイフンを含んでいたりするので、CocoaのNSDictionaryからAppleScriptのrecordに変換すると値が取り出せなくなってしまいます。

そのため、NSDictionaryのまま返すようにしています。

AppleScript名:GET method REST API v4.1
— Created 2018-06-16 by Takaaki Naganoya
— 2018 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 NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

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

set reqURLStr to "http://jsonplaceholder.typicode.com/posts"
set aRESTres to callRestGETAPIAndParseResults(reqURLStr, 10) of me
set aRESTcode to retCode of aRESTres
–> 200

set aRESTheader to retHeaders of aRESTres
–>  (NSDictionary) {​​​​​Content-Type:"application/json; charset=utf-8", ​​​​​Pragma:"no-cache", ​​​​​X-Powered-By:"Express", ​​​​​Set-Cookie:"__cfduid=dc7a11359ba7f9518366108f4c2e2d7fb1529215907; expires=Mon, 17-Jun-19 06:11:47 GMT; path=/; domain=.typicode.com; HttpOnly", ​​​​​Server:"cloudflare", ​​​​​Via:"1.1 vegur", ​​​​​Content-Encoding:"gzip", ​​​​​Expires:"Sun, 17 Jun 2018 15:21:12 GMT", ​​​​​CF-Cache-Status:"HIT", ​​​​​Transfer-Encoding:"Identity", ​​​​​Cache-Control:"public, max-age=14400", ​​​​​Date:"Sun, 17 Jun 2018 11:21:12 GMT", ​​​​​Access-Control-Allow-Credentials:"true", ​​​​​Connection:"keep-alive", ​​​​​CF-RAY:"42c5219eb6f2a5cc-NRT", ​​​​​Etag:"W/"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM"", ​​​​​Vary:"Origin, Accept-Encoding", ​​​​​X-Content-Type-Options:"nosniff"​​​}

set aRESTres to retData of aRESTres
–>
(*
{​​​​​{​​​​​​​body:"quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto", ​​​​​​​id:1, ​​​​​​​title:"sunt aut facere repellat provident occaecati excepturi optio reprehenderit", ​​​​​​​userId:1​​​​​},….}
*)

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

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

★Click Here to Open This Script 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

GET method REST API v4

Posted on 6月 17, 2018 by Takaaki Naganoya

Web上のREST APIを、NSURLSessionを用いて呼び出すAppleScriptです。

各種REST APIをAppleScriptから呼び出して使うのは、もはや日常的な光景になっていますが、これまでNSURLConnectionを用いていたのが気になっていました。

現在の、Cocoa-BridgeされたAppleScriptではObjective-CのBlocks構文を用いるAPIを呼び出せないために、非同期処理ではなく同期処理を用いる必要があります。NSURLConnectionは明示的に同期処理を呼び出すことができますが、NSURLSessionのサンプルではもれなくBlocks構文が書かれていたので、使えないものかと思っていました。

ただ、それは私・長野谷の単なる思い込みであり、Xcodeでヘッダーファイルを調べてみたらBlocks構文を使わずに書けることがわかったので試してみたものです。呼び出しているのは動作確認用のREST APIで、毎回同じ値を返してきます。

まだ、status codeを受け取れていないので実際の処理に組み込むことはできませんが、きちんと動くコードが書けた意義は大きいでしょう。

AppleScript名:GET method REST API v4
— Created 2018-06-16 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

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

property retData : missing value

set retData to missing value

set reqURLStr to "http://jsonplaceholder.typicode.com/posts"
set aRESTres to callRestGETAPIAndParseResults(reqURLStr) of me
–>  
(*
{​​​​​{​​​​​​​body:"quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto", ​​​​​​​id:1, ​​​​​​​title:"sunt aut facere repellat provident occaecati excepturi optio reprehenderit", ​​​​​​​userId:1​​​​​}, ​​​​​{​​​​​​​body:"est rerum tempore vitae
sequi sint nihil reprehenderit dolor beatae ea dolores neque
fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis"}……}
*)

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

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

★Click Here to Open This Script 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Numbersのアクティブシート上の表の行数をデータに合わせる

Posted on 6月 13, 2018 by Takaaki Naganoya

Numbersの最前面の書類の選択中のシート(アクティブシート)上の「表」の行数をデータに合わせて変更するAppleScriptです。


▲Before


▲After

表データ上の空白部分を末尾(下)から先頭(上)に向かってサーチし、空白ではない箇所を見つけるまで繰り返します。

AppleScript名:Numbersのアクティブシート上の表の行数をデータに合わせる
— Created 2018-06-12 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

set tCount to getTableCount() of me

repeat with tableID from 1 to tCount
  
  
–Numbersからデータを取得する
  
set aList to getDataFromNumbersDoc(tableID) of me
  
if aList = false then error "No Data in table " & (tableID as string)
  
  
–Numbersの対象の表の情報を取得
  
set aWidth to getColumnCount(tableID) of me
  
set aHeaderCount to getHeaderCount(tableID) of me
  
set aFooterCount to getFooterCount(tableID) of me
  
  
–Numbersから取得した2D Listのデータからデータの末尾を見つける
  
set aDataRowCount to findDataEnd(aWidth, aHeaderCount, aFooterCount, aList) of me
  
  
tell application "Numbers"
    tell front document
      tell active sheet
        tell table tableID
          set row count to aDataRowCount
        end tell
      end tell
    end tell
  end tell
  
end repeat

–Numbersでオープン中の書類の選択中のシートの表1からデータを取得して2D Listに
on getDataFromNumbersDoc(tableNum as integer)
  
  
load framework
  
  
tell application "Numbers"
    if (count every document) = 0 then return false
    
    
tell front document
      if (count every sheet) = 0 then return false
      
      
tell active sheet
        tell table tableNum
          set colCount to column count
          
set rowCount to row count
          
set headerCount to header row count
          
set footerCount to footer row count
          
          
set dList to value of every cell of cell range
        end tell
      end tell
      
    end tell
  end tell
  
  
–Convert 1D List to 2D List
  
set bList to (current application’s SMSForder’s subarraysFrom:dList groupedBy:colCount |error|:(missing value)) as list
  
set sItem to 1 + headerCount
  
set eItem to rowCount – footerCount
  
set cList to items sItem thru eItem of bList
  
  
return cList
  
end getDataFromNumbersDoc

on getTableCount()
  tell application "Numbers"
    set dCount to count every document
    
if dCount = 0 then error "Numbers: There is No Document"
    
    
tell front document
      tell active sheet
        return (count every table)
      end tell
    end tell
  end tell
end getTableCount

on getHeaderCount(tableID as integer)
  tell application "Numbers"
    tell front document
      tell active sheet
        tell table tableID
          return (header row count)
        end tell
      end tell
    end tell
  end tell
end getHeaderCount

on getFooterCount(tableID as integer)
  tell application "Numbers"
    tell front document
      tell active sheet
        tell table tableID
          return (footer row count)
        end tell
      end tell
    end tell
  end tell
end getFooterCount

on getColumnCount(tableID as integer)
  tell application "Numbers"
    tell front document
      tell active sheet
        tell table tableID
          return (column count)
        end tell
      end tell
    end tell
  end tell
end getColumnCount

–Numbersから取得した2D Arrayのデータ末尾を見つける(ただし、高速化処理を一切していないのでデータ数が数千件を超えると遅くなる)
on findDataEnd(aWidth as integer, aHeaderCount as integer, aFooterCount as integer, aList as list)
  set rAList to reverse of aList –get reverse order list
  
  
set anItem to {}
  
repeat aWidth times
    set the end of anItem to missing value
  end repeat
  
  
set aCount to length of aList
  
set hitF to false
  
  
repeat with i in rAList
    set j to contents of i
    
if j is not equal to anItem then
      set hitF to true
      
exit repeat
    end if
    
set aCount to aCount – 1
  end repeat
  
  
if hitF = false then return false –すべて空(missing value)だった場合には処理打ち切り
  
  
return aCount + aHeaderCount + aFooterCount
end findDataEnd

★Click Here to Open This Script 

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

サーバーの移行を行います

Posted on 6月 12, 2018 by Takaaki Naganoya

移行前

Blogのサーバー移行を行います。2018年2月にWordPressの新バージョンに移行した後から、Blogの応答パフォーマンスが低下してきているので(大きな画像をWordPressまかせでサムネール作成させて表示しているのが問題なのか、WordPressそのものに問題があるのか)、高速なサーバーへの移行を行います。

放っておいても8月ぐらいには自動で移行というスケジュールのようですが、またホスティング会社側に全部おまかせで行うと、トラブルが発生すること必至です(状況をまともに説明する能力がないようなので、期待していません)。

なので、一括移行のタイミングよりも前のタイミングで移行の実験を行います。さっそく、1月末のトラブル中に作成したMySQLのユーザーアカウントのうちの1つのパスワードが読み取れないといったエラーが報告されました。

実験用に作成したアカウントだったのでアカウントごと消しましたが、ホスティング会社のWebフォーム上のメニューから作成したアカウントがホスティング会社側のプログラムから読み取れないとは実におかしな話です。

今回のサーバー移行は、同じホスティング会社の古いサーバーから、新しい高速(といわれる)サーバーに移行します。つまり、古いサーバーよりも新しく調達したサーバーの方が仕様的に上なのでアクセスが快適になる、、、、、、という話なのですが、実際に移行してみないとわかりません。

移行後

実際に移行してみましたが、とくに何も問題はないようです。ただ、サーバーを移行してもWordPressの応答速度がたいして上がらなかったので、WordPressのプラグインを外しまくりました。

プラグインによってずいぶんパフォーマンスが落ちていたようです。いまはかなり快適に? つまり、サーバー移行自体はあまり関係なかったようなのですが、あとでモメなくてよかった程度の話でしょうか。

ホスティングしているサーバーのアップデートが計画されているようですが、1台あたりの収容ユーザー数を増やせば、数値どおりのパフォーマンス向上を体感することは難しいことでしょう。

Posted in 未分類 | Leave a comment

Blog Archiveの電子書籍を計画しています

Posted on 6月 11, 2018 by Takaaki Naganoya

「AppleScriptの穴」の内容が、2018年の1月末にBlog開設10年目にして突然消滅。あの悪夢のBlog消失事件から半年近くが経過しました。

消失直後に、AppleScript書類をHTML化してXML-RPC経由でWordPressをコントロールして、BlogにアップロードするAppleScriptを書いて実戦投入。機械的に基礎的なサブルーチンをアップロードし、じょじょに説明文を付加したコンテンツをアップロード。

macOS 10.11以降のScriptを対象に迅速な復旧を行い、意図した範囲でのサイト復旧はできているのかな、という状況です。

一方で、もっと古い時期&OSバージョン向けの情報については、正直なところそれを検証する環境を整備・維持するのが難しい状況です。

そのため、本BlogでもmacOS 10.10以前の情報について再掲載するつもりはありません。

そこで、古い情報のみを集めたBlog Archive本を電子ブックで出版することを計画中です。AppleScriptの穴のフォーマットと同じく、構文色分けを行なったプログラムリストに、クリックすると内容がScript Editorに転送されるURLリンク付き。PDFによる出版のため全文検索で内容をサーチ可能です。

→ Blog Archive Vol.1〜6 発売中

とりあえず1か月分の見出しをリストアップしてみたら、130本ぐらいありました(Blog開設当初で、AppleScriptによる自動投稿プログラムにより連続アップしていました)。2008年3月9日から1年分を拾うだけでも500〜800ページぐらいにはなりそうです(×10年分)。

いまでもOS X 10.4〜10.9あたりを使い続けている方には見逃せない情報になるものと思われます。

なお、Blog復旧&再始動したあとのBlogアーカイブについては、新刊のCocoa Scripting Courseシリーズに各カテゴリのScriptをまとめて添付するため、これがアーカイブに該当することになります。

Posted in Books PRODUCTS Release | Leave a comment

Finderで選択中の画像を右に90度回転

Posted on 6月 11, 2018 by Takaaki Naganoya

Finder上で選択中の画像を右に(時計回りに)90度回転させるAppleScriptです。

Finder上で選択中のファイルのうち、UTIがpublic.imageに含まれるもの(JPEGとかPNGとかTIFFとか)を指定の角度に回転させます。

もともと、選択中のアイテムからファイル種別でオブジェクトを抽出する機能はFinderのものを利用していたのですが、最近のFinderは応答速度が下がっているため、選択中のファイルの取得以外は極力Finderを利用しないのが(macOS 10.10以降の)おすすめです。

macOS標準搭載のScript Menu(フォルダ構造がそのままメニューになり、Scriptをメニューから実行できる)に登録して実行しています。

AppleScript名:Finderで選択中の画像を右に90度回転
— Created 2017-11-21 by Takaaki Naganoya
— Modified 2018-04-06 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
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

set targDegree to 90 — targDegree have to be in {0, 90, 180, 270, 360} in clockwise

tell application "Finder"
  set inFiles to selection as alias list
end tell
if inFiles = {} then return

–指定のAlias listのうち画像のみ抽出
set filRes1 to filterAliasListByUTI(inFiles, "public.image") of me
if filRes1 = {} then return

–選択中のファイルのうちの1つから親フォルダを求め、出力先ファイルパスを組み立てる
set outPathTarg to POSIX path of (first item of filRes1)
set pathString to current application’s NSString’s stringWithString:outPathTarg
set newPath to (pathString’s stringByDeletingLastPathComponent()) as string

repeat with i in filRes1
  rotateImageandSaveIt(i, targDegree) of me
end repeat

–指定角度に画像を回転させて上書き保存
on rotateImageandSaveIt(this_file, aTargerRect)
  tell application "Image Events"
    launch
    
set this_image to open this_file
    
rotate this_image to angle aTargerRect
    
save this_image with icon
    
close this_image
  end tell
end rotateImageandSaveIt

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定の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 filter Image | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

数値演算ライブラリ「calcLibAS」v1.3(28倍速)

Posted on 6月 8, 2018 by Takaaki Naganoya

数値演算の関数を35個提供するAppleScript Libraries「calcLibAS」の高速版です。

–> Download calcLibAS (To ~/Library/Script Libraries/)

掘っ建て小屋とか犬小屋みたいな吹けば飛ぶような数値演算ライブラリだったものが、気づけば最初のバージョンから28倍速といったトンでもない状況になっています。ただ、前バージョンとくらべて少し安定性が損なわれているような気がしないでもありません。

計算に速度が求められる用途では、BridgePlusやSatimage OSAXなどを使うのがよいと思いますが、これらのライブラリやOSAXがサポートしていない数値関数が割とあるので(とくにatan2)それを埋めるためだけに本ライブラリは存在しています。

こうしてグラフで比較してみると、C++で書かれたSatimage OSAX、Objective-Cで書かれたCocoa Frameworkと1桁違うぐらいの処理速度でAppleScriptによる(JavaScript処理系呼んでますけど)数値演算ができているのは割とすごいと思います(自分ではなくCPUとかOSとかShane Stanleyの高速化とかが。割と他力本願ライブラリなので)。

本来であれば、AppleがNumbersの関数の充実のために導入した「Cephes Math Library」をNSNumberを介してAppleScriptから呼べるようにラッピングするのがよいのですが(Github上にあるObjectiveCephesは、単にCocoa Framework化しただけでC言語レベルでデータを扱っているのでAppleScriptからは使えない)、割と手間がかかるので「とりあえずJavaScriptの処理系の関数を使えるようにしてみよう」ということで(数時間で)でっち上げた、その場しのぎのためのライブラリです。

AppleScript名:testScript1
— Created 2018-06-06 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use mLib : script "calcLibAS"

set a01Res to calcAbs(-10) of mLib –> 10
set a02Res to calcAcos(-1) of mLib –> 3.14159265359
set a03Res to calcAcosh(10) of mLib –> 2.993222846126
set a04Res to calcAsin(-1) of mLib –> -1.570796326795
set a05Res to calcAsinh(10) of mLib –> 2.998222950298
set a06Res to calcAtan(10) of mLib –> 1.471127674304
set a07Res to calcAtan2(10, 20) of mLib –> 0.463647609001
set a08Res to calcAtanh(0.5) of mLib –> 0.549306144334
set a09Res to calcCbrt(3) of mLib –> 1.442249570307
set a10Res to calcCeil(0.95) of mLib –> 1
set a11Res to calcClz32(1) of mLib –> 31
set a12Res to calcCos(1) of mLib –> 0.540302305868
set a13Res to calcCosh(1) of mLib –> 1.543080634815
set a14Res to calcExp(1) of mLib –> 2.718281828459
set a15Res to calcExpm1(-1) of mLib –> -0.632120558829
set a16Res to calcFloor(45.95) of mLib –> 45
set a17Res to calcFround(1.337) of mLib –> 1.337000012398
set a18Res to calcHypot({3, 4, 5}) of mLib –> 7.071067811865
set a19Res to calcImul(2, 5) of mLib –> 10
set a20Res to calcLog(10) of mLib –> 2.302585092994
set a21Res to calcLog10(2) of mLib –> 0.301029995664
set a22Res to calcLog1p(1) of mLib –> 0.69314718056
set a23Res to calcLog2(3) of mLib –> 1.584962500721
set a24Res to calcMax({1, 2, 3, 4, 6, 2, 10}) of mLib –> 10
set a25Res to calcMin({1, 2, 3, 4, 6, 2, 10, 0}) of mLib –> 0
set a26Res to calcPow(7, 2) of mLib –>  49.0
set a27Res to calcRandom() of mLib –>  0.200867049467
set a28Res to calcRound(5.95) of mLib –>  6.0
set a29Res to calcSign(10) of mLib –> -1/0/1 –> -1.0/0.0/1.0
set a30Res to calcSin(pi / 2) of mLib –> 1–>  1.0
set a31Res to calcSinh(1) of mLib –> 1.175201193644
set a32Res to calcSqrt(2) of mLib –> 1.414213562373
set a33Res to calcTan(30) of mLib –> -6.405331196646
set a34Res to calcTanh(10) of mLib –> 0.999999995878
set a35Res to calcTrunc(13.37) of mLib –> 13 –>  13.0

★Click Here to Open This Script 

AppleScript名:calcLibAS
— Created 2018-06-06 by Takaaki Naganoya
— 2017 Piyomaru Software
–v1.0 First Version。run scriptでJXAを呼び出して計算。連続呼び出し時にクラッシュが頻発
–v1.1 JavaScriptCoreを使用。run script命令をフックして呼び出し。JXA呼び出しをやめて6倍の高速化
–v1.2 JavaScriptCoreを使用。run script命令のフックをやめて若干の高速化
–v1.3 Shane Stanleyによる高速化。JSContextをpropertyにキャッシュして高速化

— Created 2018-06-06 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "JavaScriptCore"

property theContext : missing value

–数値の絶対値を返す
on calcAbs(aNum as string)
  set aStr to "Math.abs(" & aNum & ")"
  
return exeJS(aStr)
end calcAbs

–アークコサインをラジアン単位で返す
on calcAcos(aNum as string)
  set aStr to "Math.acos(" & aNum & ")"
  
return exeJS(aStr)
end calcAcos

–ハイパーボリックアークコサインを返す
on calcAcosh(aNum as string)
  set aStr to "Math.acosh(" & aNum & ")"
  
return exeJS(aStr)
end calcAcosh

–アークサインをラジアン単位で返す
on calcAsin(aNum as string)
  set aStr to "Math.asin(" & aNum & ")"
  
return exeJS(aStr)
end calcAsin

–ハイパーボリックアークサインを返す
on calcAsinh(aNum as string)
  set aStr to "Math.asinh(" & aNum & ")"
  
return exeJS(aStr)
end calcAsinh

–アークタンジェントをラジアン単位で返す
on calcAtan(aNum as string)
  set aStr to "Math.atan(" & aNum & ")"
  
return exeJS(aStr)
end calcAtan

–アークタンジェントを返す
on calcAtan2(aNum as string, bNum as string)
  set aStr to "Math.atan2(" & aNum & ", " & bNum & ")"
  
return exeJS(aStr)
end calcAtan2

–ハイパーボリックアークタンジェントを返す
on calcAtanh(aNum as string)
  set aStr to "Math.atanh(" & aNum & ")"
  
return exeJS(aStr)
end calcAtanh

–引数として与えた数の立方根を返す
on calcCbrt(aNum as string)
  set aStr to "Math.cbrt(" & aNum & ")"
  
return exeJS(aStr)
end calcCbrt

–引数として与えた数以上の最小の整数を返す
on calcCeil(aNum as string)
  set aStr to "Math.ceil(" & aNum & ")"
  
return exeJS(aStr)
end calcCeil

–引数として与えた数以上の最小の整数を返す
on calcClz32(aNum as string)
  set aStr to "Math.clz32(" & aNum & ")"
  
return exeJS(aStr)
end calcClz32

–引数として与えた数のコサインを返す
on calcCos(aNum as string)
  set aStr to "Math.cos(" & aNum & ")"
  
return exeJS(aStr)
end calcCos

–引数として与えた数のハイパーボリックコサインを返す
on calcCosh(aNum as string)
  set aStr to "Math.cosh(" & aNum & ")"
  
return exeJS(aStr)
end calcCosh

–Ex を返す。ここでの x は引数、E は、自然対数の底であるネイピア数(オイラー数)
on calcExp(aNum as string)
  set aStr to "Math.exp(" & aNum & ")"
  
return exeJS(aStr)
end calcExp

–ex – 1 を返す。x は引数で、e は自然対数の底
on calcExpm1(aNum as string)
  set aStr to "Math.expm1(" & aNum & ")"
  
return exeJS(aStr)
end calcExpm1

–引数として与えた数以下の最大の整数を返す
on calcFloor(aNum as string)
  set aStr to "Math.floor(" & aNum & ")"
  
return exeJS(aStr)
end calcFloor

–引数として与えた数の最も近い単精度 floatを返す
on calcFround(aNum as string)
  set aStr to "Math.fround(" & aNum & ")"
  
return exeJS(aStr)
end calcFround

–引数の二乗和の平方根を返す
on calcHypot(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.hypot(" & bStr & ")"
  
return exeJS(aStr)
end calcHypot

— 2 つの引数をとり、C 言語の様な 32 ビット乗算の結果を返す
on calcImul(aNum as string, bNum as string)
  set aStr to "Math.imul(" & aNum & ", " & bNum & ")"
  
return exeJS(aStr)
end calcImul

— 引数として与えた数の自然対数 (底は e) を返す
on calcLog(aNum as string)
  set aStr to "Math.log(" & aNum & ")"
  
return exeJS(aStr)
end calcLog

— 引数として与えた数に対して、10を底とする対数を返す
on calcLog10(aNum as string)
  set aStr to "Math.log10(" & aNum & ")"
  
return exeJS(aStr)
end calcLog10

— 引数として与えた数と 1 の合計の自然対数(底 e)を返す
on calcLog1p(aNum as string)
  set aStr to "Math.log1p(" & aNum & ")"
  
return exeJS(aStr)
end calcLog1p

— 引数として与えた数の2を底とする対数を返す
on calcLog2(aNum as string)
  set aStr to "Math.log2(" & aNum & ")"
  
return exeJS(aStr)
end calcLog2

–引数として与えた複数の数の中で最大の数を返す
on calcMax(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.max(" & bStr & ")"
  
return exeJS(aStr)
end calcMax

–引数として与えた複数の数の中で最小の数を返す
on calcMin(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.min(" & bStr & ")"
  
return exeJS(aStr)
end calcMin

–引数として与えた複数の数の中で最小の数を返す
on calcPow(aNum as string, bNum as string)
  set aStr to "Math.pow(" & aNum & ", " & bNum & ")"
  
return exeJS(aStr)
end calcPow

–(0以上、1未満)の範囲で浮動小数点の擬似乱数を返す
on calcRandom()
  set aStr to "Math.random()"
  
return (run script aStr in "JavaScript")
end calcRandom

–引数として与えた数を四捨五入して、もっとも近似の整数を返す
on calcRound(aNum as string)
  set aStr to "Math.round(" & aNum & ")"
  
return exeJS(aStr)
end calcRound

–引数として与えた数が正、負、0 のどれであるか示す符号を返す
on calcSign(aNum as string)
  set aStr to "Math.sign(" & aNum & ")"
  
return exeJS(aStr)
end calcSign

–引数として与えた数のサイン(正弦)を返す
on calcSin(aNum as string)
  set aStr to "Math.sin(" & aNum & ")"
  
return exeJS(aStr)
end calcSin

–引数として与えた数のハイパーボリックサインを返す
on calcSinh(aNum as string)
  set aStr to "Math.sinh(" & aNum & ")"
  
return exeJS(aStr)
end calcSinh

–引数として与えた数の平方根を返す
on calcSqrt(aNum as string)
  set aStr to "Math.sqrt(" & aNum & ")"
  
return exeJS(aStr)
end calcSqrt

–引数として与えた数のタンジェントを返す
on calcTan(aNum as string)
  set aStr to "Math.tan(" & aNum & ")"
  
return exeJS(aStr)
end calcTan

–引数として与えた数のハイパーボリックタンジェントを返す
on calcTanh(aNum as string)
  set aStr to "Math.tanh(" & aNum & ")"
  
return exeJS(aStr)
end calcTanh

–引数として与えた数の小数部の桁を取り除いて整数部を返す
on calcTrunc(aNum as string)
  set aStr to "Math.trunc(" & aNum & ")"
  
return exeJS(aStr)
end calcTrunc

–Sub Routines

–リストを指定デリミタをはさんでテキスト化
on retArrowText(aList, aDelim) –自分のASでよく使うハンドラ名称なので、同じものを用意
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retArrowText

–JavaScriptCore版実行部
on exeJS(aStr)
  return (myContext()’s evaluateScript:aStr)’s toDouble()
end exeJS

on myContext()
  if theContext = missing value then set theContext to current application’s JSContext’s new()
  
return theContext
end myContext

★Click Here to Open This Script 

Posted in Number | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

数値演算ライブラリ「calcLibAS」v1.2(6倍速)

Posted on 6月 7, 2018 by Takaaki Naganoya

数値演算の関数を35個提供するAppleScript Libraries「calcLibAS」の高速・安定化版です。

–> Download calcLibAS (To ~/Library/Script Libraries/)


▲atan2 calculation comparison

前バージョンのv1.0よりも6倍高速で、JXAの利用をやめてJavaScript Coreに切り替えたため、数百回呼び出したときでもクラッシュすることがなくなりました(ひどい場合だと数回でクラッシュしていたため、JXAを外せて本当によかったです。run scriptコマンドがひどいのかもしれませんが)。

v1.1ではrun scriptコマンドをのっとってJavaScript Coreを呼び出していましたが、v1.2ではrun scriptコマンドの利用をやめてすべてサブルーチン呼び出しに書き換えたので、若干高速化しました。

JavaScript CoreのほかWebKit経由でもJavaScriptの実行は行えますが、WebKitではメインスレッドでの実行が求められたため、JavaScript Coreを使用しています。ただし、このためかどうかわかりませんが、macOS 10.13の環境で本Scriptを実行したときにSafariのJavaScriptデバッグ画面が実行回数だけオープンするという怪奇現象に直面しました。Safariを起動していない場合には発生しませんし、テスト環境では2度目以降は発生していません。ご注意ください。

AppleScript名:calcLibAS
— Created 2018-06-06 by Takaaki Naganoya
— 2017 Piyomaru Software
–v1.0 First Version。run scriptでJXAを呼び出して計算。連続呼び出し時にクラッシュが頻発
–v1.1 JavaScriptCoreを使用。run script命令をフックして呼び出し。JXA呼び出しをやめて6倍の高速化
–v1.2 JavaScriptCoreを使用。run script命令のフックをやめて若干の高速化
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "JavaScriptCore"

set a01Res to calcAbs(-10) of me –> 10
set a02Res to calcAcos(-1) of me –> 3.14159265359
set a03Res to calcAcosh(10) of me –> 2.993222846126
set a04Res to calcAsin(-1) of me –> -1.570796326795
set a05Res to calcAsinh(10) of me –> 2.998222950298
set a06Res to calcAtan(10) of me –> 1.471127674304
set a07Res to calcAtan2(10, 20) of me –> 0.463647609001
set a08Res to calcAtanh(0.5) of me –> 0.549306144334
set a09Res to calcCbrt(3) of me –> 1.442249570307
set a10Res to calcCeil(0.95) of me –> 1
set a11Res to calcClz32(1) of me –> 31
set a12Res to calcCos(1) of me –> 0.540302305868
set a13Res to calcCosh(1) of me –> 1.543080634815
set a14Res to calcExp(1) of me –> 2.718281828459
set a15Res to calcExpm1(-1) of me –> -0.632120558829
set a16Res to calcFloor(45.95) of me –> 45
set a17Res to calcFround(1.337) of me –> 1.337000012398
set a18Res to calcHypot({3, 4, 5}) of me –> 7.071067811865
set a19Res to calcImul(2, 5) of me –> 10
set a20Res to calcLog(10) of me –> 2.302585092994
set a21Res to calcLog10(2) of me –> 0.301029995664
set a22Res to calcLog1p(1) of me –> 0.69314718056
set a23Res to calcLog2(3) of me –> 1.584962500721
set a24Res to calcMax({1, 2, 3, 4, 6, 2, 10}) of me –> 10
set a25Res to calcMin({1, 2, 3, 4, 6, 2, 10, 0}) of me –> 0
set a26Res to calcPow(7, 2) of me –>  49.0
set a27Res to calcRandom() of me –>  0.200867049467
set a28Res to calcRound(5.95) of me –>  6.0
set a29Res to calcSign(10) of me –> -1/0/1 –> -1.0/0.0/1.0
set a30Res to calcSin(pi / 2) of me –> 1–>  1.0
set a31Res to calcSinh(1) of me –> 1.175201193644
set a32Res to calcSqrt(2) of me –> 1.414213562373
set a33Res to calcTan(30) of me –> -6.405331196646
set a34Res to calcTanh(10) of me –> 0.999999995878
set a35Res to calcTrunc(13.37) of me –> 13 –>  13.0

–数値の絶対値を返す
on calcAbs(aNum as string)
  set aStr to "Math.abs(" & aNum & ")"
  
return exeJS(aStr)
end calcAbs

–アークコサインをラジアン単位で返す
on calcAcos(aNum as string)
  set aStr to "Math.acos(" & aNum & ")"
  
return exeJS(aStr)
end calcAcos

–ハイパーボリックアークコサインを返す
on calcAcosh(aNum as string)
  set aStr to "Math.acosh(" & aNum & ")"
  
return exeJS(aStr)
end calcAcosh

–アークサインをラジアン単位で返す
on calcAsin(aNum as string)
  set aStr to "Math.asin(" & aNum & ")"
  
return exeJS(aStr)
end calcAsin

–ハイパーボリックアークサインを返す
on calcAsinh(aNum as string)
  set aStr to "Math.asinh(" & aNum & ")"
  
return exeJS(aStr)
end calcAsinh

–アークタンジェントをラジアン単位で返す
on calcAtan(aNum as string)
  set aStr to "Math.atan(" & aNum & ")"
  
return exeJS(aStr)
end calcAtan

–アークタンジェントを返す
on calcAtan2(aNum as string, bNum as string)
  set aStr to "Math.atan2(" & aNum & ", " & bNum & ")"
  
return exeJS(aStr)
end calcAtan2

–ハイパーボリックアークタンジェントを返す
on calcAtanh(aNum as string)
  set aStr to "Math.atanh(" & aNum & ")"
  
return exeJS(aStr)
end calcAtanh

–引数として与えた数の立方根を返す
on calcCbrt(aNum as string)
  set aStr to "Math.cbrt(" & aNum & ")"
  
return exeJS(aStr)
end calcCbrt

–引数として与えた数以上の最小の整数を返す
on calcCeil(aNum as string)
  set aStr to "Math.ceil(" & aNum & ")"
  
return exeJS(aStr)
end calcCeil

–引数として与えた数以上の最小の整数を返す
on calcClz32(aNum as string)
  set aStr to "Math.clz32(" & aNum & ")"
  
return exeJS(aStr)
end calcClz32

–引数として与えた数のコサインを返す
on calcCos(aNum as string)
  set aStr to "Math.cos(" & aNum & ")"
  
return exeJS(aStr)
end calcCos

–引数として与えた数のハイパーボリックコサインを返す
on calcCosh(aNum as string)
  set aStr to "Math.cosh(" & aNum & ")"
  
return exeJS(aStr)
end calcCosh

–Ex を返す。ここでの x は引数、E は、自然対数の底であるネイピア数(オイラー数)
on calcExp(aNum as string)
  set aStr to "Math.exp(" & aNum & ")"
  
return exeJS(aStr)
end calcExp

–ex – 1 を返す。x は引数で、e は自然対数の底
on calcExpm1(aNum as string)
  set aStr to "Math.expm1(" & aNum & ")"
  
return exeJS(aStr)
end calcExpm1

–引数として与えた数以下の最大の整数を返す
on calcFloor(aNum as string)
  set aStr to "Math.floor(" & aNum & ")"
  
return exeJS(aStr)
end calcFloor

–引数として与えた数の最も近い単精度 floatを返す
on calcFround(aNum as string)
  set aStr to "Math.fround(" & aNum & ")"
  
return exeJS(aStr)
end calcFround

–引数の二乗和の平方根を返す
on calcHypot(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.hypot(" & bStr & ")"
  
return exeJS(aStr)
end calcHypot

— 2 つの引数をとり、C 言語の様な 32 ビット乗算の結果を返す
on calcImul(aNum as string, bNum as string)
  set aStr to "Math.imul(" & aNum & ", " & bNum & ")"
  
return exeJS(aStr)
end calcImul

— 引数として与えた数の自然対数 (底は e) を返す
on calcLog(aNum as string)
  set aStr to "Math.log(" & aNum & ")"
  
return exeJS(aStr)
end calcLog

— 引数として与えた数に対して、10を底とする対数を返す
on calcLog10(aNum as string)
  set aStr to "Math.log10(" & aNum & ")"
  
return exeJS(aStr)
end calcLog10

— 引数として与えた数と 1 の合計の自然対数(底 e)を返す
on calcLog1p(aNum as string)
  set aStr to "Math.log1p(" & aNum & ")"
  
return exeJS(aStr)
end calcLog1p

— 引数として与えた数の2を底とする対数を返す
on calcLog2(aNum as string)
  set aStr to "Math.log2(" & aNum & ")"
  
return exeJS(aStr)
end calcLog2

–引数として与えた複数の数の中で最大の数を返す
on calcMax(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.max(" & bStr & ")"
  
return exeJS(aStr)
end calcMax

–引数として与えた複数の数の中で最小の数を返す
on calcMin(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.min(" & bStr & ")"
  
return exeJS(aStr)
end calcMin

–引数として与えた複数の数の中で最小の数を返す
on calcPow(aNum as string, bNum as string)
  set aStr to "Math.pow(" & aNum & ", " & bNum & ")"
  
return exeJS(aStr)
end calcPow

–(0以上、1未満)の範囲で浮動小数点の擬似乱数を返す
on calcRandom()
  set aStr to "Math.random()"
  
return (run script aStr in "JavaScript")
end calcRandom

–引数として与えた数を四捨五入して、もっとも近似の整数を返す
on calcRound(aNum as string)
  set aStr to "Math.round(" & aNum & ")"
  
return exeJS(aStr)
end calcRound

–引数として与えた数が正、負、0 のどれであるか示す符号を返す
on calcSign(aNum as string)
  set aStr to "Math.sign(" & aNum & ")"
  
return exeJS(aStr)
end calcSign

–引数として与えた数のサイン(正弦)を返す
on calcSin(aNum as string)
  set aStr to "Math.sin(" & aNum & ")"
  
return exeJS(aStr)
end calcSin

–引数として与えた数のハイパーボリックサインを返す
on calcSinh(aNum as string)
  set aStr to "Math.sinh(" & aNum & ")"
  
return exeJS(aStr)
end calcSinh

–引数として与えた数の平方根を返す
on calcSqrt(aNum as string)
  set aStr to "Math.sqrt(" & aNum & ")"
  
return exeJS(aStr)
end calcSqrt

–引数として与えた数のタンジェントを返す
on calcTan(aNum as string)
  set aStr to "Math.tan(" & aNum & ")"
  
return exeJS(aStr)
end calcTan

–引数として与えた数のハイパーボリックタンジェントを返す
on calcTanh(aNum as string)
  set aStr to "Math.tanh(" & aNum & ")"
  
return exeJS(aStr)
end calcTanh

–引数として与えた数の小数部の桁を取り除いて整数部を返す
on calcTrunc(aNum as string)
  set aStr to "Math.trunc(" & aNum & ")"
  
return exeJS(aStr)
end calcTrunc

–Sub Routines

–リストを指定デリミタをはさんでテキスト化
on retArrowText(aList, aDelim) –自分のASでよく使うハンドラ名称なので、同じものを用意
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retArrowText

–JavaScriptCore版実行部
on exeJS(aStr)
  set theContext to current application’s JSContext’s alloc()’s init()
  
set x to (theContext’s evaluateScript:aStr)’s toNumber()
  
return x as list of string or string –as anything
end exeJS

★Click Here to Open This Script 

Posted in Number | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Numbersで選択範囲のセルのデータを取得して重複データを抽出

Posted on 6月 7, 2018 by Takaaki Naganoya

Numbersの表データの選択範囲のセルのデータを取得し、重複データがあれば重複データのみ表示するAppleScriptです。

# NumbersというApple社製の表計算アプリケーションを操作する話であって、宝くじの話ではありません。また、本BlogはScriptでMac上のアプリケーションやOS内のサービスを呼び出して処理する話を紹介しているものであって、単に画面上から削除する方法を紹介するものではありません。また、データのユニーク化処理ができないわけがありません。とっくの昔に書いています。

macOS標準装備のScript Menuに入れて便利に使っています。Numbers上の選択範囲内に重複データがあれば、ダイアログでデータを表示します。

AppleScript名:Numbersで選択範囲のセルのデータを取得して重複データを抽出
— Created 2018-01-13 by Takaaki Naganoya
— Modified 2018-06-06 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property NSCountedSet : a reference to current application’s NSCountedSet

script spd
  property uniqList : {}
end script

set (uniqList of spd) to {}

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 (uniqList of spd) to value of cells of selection range
      end tell
    end tell
  end tell
end tell

if (uniqList of spd) = {} then
  display notification "Numbers: There is no selection"
  
return
end if

set aRes to returnDuplicatesOnly(uniqList of spd) of me
if aRes is not equal to {} then
  choose from list aRes with prompt "Duplicated Data:"
else
  display notification "No Duplicated Data"
end if

–1D Listから重複項目のみを抽出して返す
on returnDuplicatesOnly(aList as list)
  set aSet to NSCountedSet’s alloc()’s initWithArray:aList
  
set bList to (aSet’s allObjects()) as list
  
  
set dupList to {}
  
repeat with i in bList
    set aRes to (aSet’s countForObject:i)
    
if aRes > 1 then
      set the end of dupList to (contents of i)
    end if
  end repeat
  
  
return dupList
end returnDuplicatesOnly

★Click Here to Open This Script 

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

数値演算ライブラリ「calcLibAS」

Posted on 6月 7, 2018 by Takaaki Naganoya

数値演算の関数を35個提供するAppleScript Librariesです。

Cocoa Frameworkを呼び出して計算するよりも262倍、OSAXを呼び出して計算するよりも760倍遅いのですが、関数の数はたいへんに多いです。

スピードが遅い上に数百回連続で呼び出すとScript Editorがクラッシュする傾向があります(本当)。

run scriptコマンドでJavaScript(JXA)を呼び出して計算しているのですが、run script経由でJavaScript(JXA)を呼び出すのがこんなに危険だと思わなかったので、いっそJavaScript Coreを呼び出して実行してみてもよいのかもしれません(それでも高速にはならなさそうで)。

最初は「calcLib」というライブラリをJXAで試しに書いて、AppleScriptから呼び出せないかどうか実験してみたのですが、useコマンドでJXAのライブラリを指定したら「OSA言語が違うので呼び出せないよ」といったエラーになりました(AppleScript用語辞書を用意すれば複数のOSA言語間から利用できるのだと思います、まだやっていませんけれども)。

そのあとで作ったので「calcLibAS」という名前に。

AppleScript名:atan2をライブラリ呼び出しで計算する
— Created 2018-06-06 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use mLib : script "calcLibAS"

set aRes to calcAtan2(10, 20) of mLib

★Click Here to Open This Script 

本ライブラリは~/Library/Script Librariesフォルダなどに入れて呼び出してください。

AppleScript名:calcLibAS
— Created 2018-06-06 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

set a01Res to calcAbs(-10) of me –> 10
set a02Res to calcAcos(-1) of me –> 3.14159265359
set a03Res to calcAcosh(10) of me –> 2.993222846126
set a04Res to calcAsin(-1) of me –> -1.570796326795
set a05Res to calcAsinh(10) of me –> 2.998222950298
set a06Res to calcAtan(10) of me –> 1.471127674304
set a07Res to calcAtan2(10, 20) of me –> 0.463647609001
set a08Res to calcAtanh(0.5) of me –> 0.549306144334
set a09Res to calcCbrt(3) of me –> 1.442249570307
set a10Res to calcCeil(0.95) of me –> 1
set a11Res to calcClz32(1) of me –> 31
set a12Res to calcCos(1) of me –> 0.540302305868
set a13Res to calcCosh(1) of me –> 1.543080634815
set a14Res to calcExp(1) of me –> 2.718281828459
set a15Res to calcExpm1(-1) of me –> -0.632120558829
set a16Res to calcFloor(45.95) of me –> 45
set a17Res to calcFround(1.337) of me –> 1.337000012398
set a18Res to calcHypot({3, 4, 5}) of me –> 7.071067811865
set a19Res to calcImul(2, 5) of me –> 10
set a20Res to calcLog(10) of me –> 2.302585092994
set a21Res to calcLog10(2) of me –> 0.301029995664
set a22Res to calcLog1p(1) of me –> 0.69314718056
set a23Res to calcLog2(3) of me –> 1.584962500721
set a24Res to calcMax({1, 2, 3, 4, 6, 2, 10}) of me –> 10
set a25Res to calcMin({1, 2, 3, 4, 6, 2, 10, 0}) of me –> 0
set a26Res to calcPow(7, 2) of me
set a27Res to calcRandom() of me
set a28Res to calcRound(5.95) of me
set a29Res to calcSign(0) of me –> -1/0/1
set a30Res to calcSin(pi / 2) of me –> 1
set a31Res to calcSinh(1) of me –> 1.175201193644
set a32Res to calcSqrt(2) of me –> 1.414213562373
set a33Res to calcTan(30) of me –> -6.405331196646
set a34Res to calcTanh(10) of me –> 0.999999995878
set a35Res to calcTrunc(13.37) of me –> 13

–数値の絶対値を返す
on calcAbs(aNum as string)
  set aStr to "Math.abs(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAbs

–アークコサインをラジアン単位で返す
on calcAcos(aNum as string)
  set aStr to "Math.acos(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAcos

–ハイパーボリックアークコサインを返す
on calcAcosh(aNum as string)
  set aStr to "Math.acosh(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAcosh

–アークサインをラジアン単位で返す
on calcAsin(aNum as string)
  set aStr to "Math.asin(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAsin

–ハイパーボリックアークサインを返す
on calcAsinh(aNum as string)
  set aStr to "Math.asinh(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAsinh

–アークタンジェントをラジアン単位で返す
on calcAtan(aNum as string)
  set aStr to "Math.atan(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAtan

–アークタンジェントを返す
on calcAtan2(aNum as string, bNum as string)
  set aStr to "Math.atan2(" & aNum & ", " & bNum & ")"
  
return (run script aStr in "JavaScript")
end calcAtan2

–ハイパーボリックアークタンジェントを返す
on calcAtanh(aNum as string)
  set aStr to "Math.atanh(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcAtanh

–引数として与えた数の立方根を返す
on calcCbrt(aNum as string)
  set aStr to "Math.cbrt(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcCbrt

–引数として与えた数以上の最小の整数を返す
on calcCeil(aNum as string)
  set aStr to "Math.ceil(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcCeil

–引数として与えた数以上の最小の整数を返す
on calcClz32(aNum as string)
  set aStr to "Math.clz32(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcClz32

–引数として与えた数のコサインを返す
on calcCos(aNum as string)
  set aStr to "Math.cos(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcCos

–引数として与えた数のハイパーボリックコサインを返す
on calcCosh(aNum as string)
  set aStr to "Math.cosh(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcCosh

–Ex を返す。ここでの x は引数、E は、自然対数の底であるネイピア数(オイラー数)
on calcExp(aNum as string)
  set aStr to "Math.exp(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcExp

–ex – 1 を返す。x は引数で、e は自然対数の底
on calcExpm1(aNum as string)
  set aStr to "Math.expm1(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcExpm1

–引数として与えた数以下の最大の整数を返す
on calcFloor(aNum as string)
  set aStr to "Math.floor(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcFloor

–引数として与えた数の最も近い単精度 floatを返す
on calcFround(aNum as string)
  set aStr to "Math.fround(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcFround

–引数の二乗和の平方根を返す
on calcHypot(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.hypot(" & bStr & ")"
  
return (run script aStr in "JavaScript")
end calcHypot

— 2 つの引数をとり、C 言語の様な 32 ビット乗算の結果を返す
on calcImul(aNum as string, bNum as string)
  set aStr to "Math.imul(" & aNum & ", " & bNum & ")"
  
return (run script aStr in "JavaScript")
end calcImul

— 引数として与えた数の自然対数 (底は e) を返す
on calcLog(aNum as string)
  set aStr to "Math.log(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcLog

— 引数として与えた数に対して、10を底とする対数を返す
on calcLog10(aNum as string)
  set aStr to "Math.log10(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcLog10

— 引数として与えた数と 1 の合計の自然対数(底 e)を返す
on calcLog1p(aNum as string)
  set aStr to "Math.log1p(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcLog1p

— 引数として与えた数の2を底とする対数を返す
on calcLog2(aNum as string)
  set aStr to "Math.log2(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcLog2

–引数として与えた複数の数の中で最大の数を返す
on calcMax(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.max(" & bStr & ")"
  
return (run script aStr in "JavaScript")
end calcMax

–引数として与えた複数の数の中で最小の数を返す
on calcMin(aList as list)
  set bStr to retArrowText(aList, ", ") of me
  
set aStr to "Math.min(" & bStr & ")"
  
return (run script aStr in "JavaScript")
end calcMin

–引数として与えた複数の数の中で最小の数を返す
on calcPow(aNum as string, bNum as string)
  set aStr to "Math.pow(" & aNum & ", " & bNum & ")"
  
return (run script aStr in "JavaScript")
end calcPow

–(0以上、1未満)の範囲で浮動小数点の擬似乱数を返す
on calcRandom()
  set aStr to "Math.random()"
  
return (run script aStr in "JavaScript")
end calcRandom

–引数として与えた数を四捨五入して、もっとも近似の整数を返す
on calcRound(aNum as string)
  set aStr to "Math.round(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcRound

–引数として与えた数が正、負、0 のどれであるか示す符号を返す
on calcSign(aNum as string)
  set aStr to "Math.sign(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcSign

–引数として与えた数のサイン(正弦)を返す
on calcSin(aNum as string)
  set aStr to "Math.sin(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcSin

–引数として与えた数のハイパーボリックサインを返す
on calcSinh(aNum as string)
  set aStr to "Math.sinh(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcSinh

–引数として与えた数の平方根を返す
on calcSqrt(aNum as string)
  set aStr to "Math.sqrt(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcSqrt

–引数として与えた数のタンジェントを返す
on calcTan(aNum as string)
  set aStr to "Math.tan(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcTan

–引数として与えた数のハイパーボリックタンジェントを返す
on calcTanh(aNum as string)
  set aStr to "Math.tanh(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcTanh

–引数として与えた数の小数部の桁を取り除いて整数部を返す
on calcTrunc(aNum as string)
  set aStr to "Math.trunc(" & aNum & ")"
  
return (run script aStr in "JavaScript")
end calcTrunc

–Sub Routines

–リストを指定デリミタをはさんでテキスト化
on retArrowText(aList, aDelim) –自分のASでよく使うハンドラ名称なので、同じものを用意
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retArrowText

(*
–run scriptコマンドに問題が出た場合にはJavaScriptCoreなどで実行してもよさそう
on run script aStr in osaLangName
  display dialog aStr
end run script
*)

★Click Here to Open This Script 

Posted in JXA Number | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Tag CloudっぽいRTFの作成

Posted on 6月 6, 2018 by Takaaki Naganoya

指定のrecord in listからTag CloudっぽいRTFファイルをデスクトップに生成するAppleScriptです。

以前からTag Cloudを出力するフレームワークやObjective-Cのプログラムを探していたのですが、なかなか具合のいいものがありませんでした。

動作原理を考えたら割と簡単そうだったので、仕方なく自分で作ることに。

作ってみて「そんなに難しくない」ことはわかりましたが、まだまだ自分が望むようなものにはなっていません。とりあえず「まあそんなもんだよね」という程度のものです。

set tagList to {{tagname:”AirServer”, tagcount:2}, {tagname:”App Store”, tagcount:1}, {tagname:”Calendar”, tagcount:3}, {tagname:”Contacts”, tagcount:1}, {tagname:”CotEditor”, tagcount:27}, {tagname:”Dictionary”, tagcount:9}, {tagname:”Dock”, tagcount:7}, {tagname:”Evernote”, tagcount:2}, {tagname:”Finder”, tagcount:20}, {tagname:”HelpViewer”, tagcount:2}, {tagname:”HoudahSpot”, tagcount:1}, {tagname:”iBooks”, tagcount:1}, {tagname:”Image Events”, tagcount:1}, {tagname:”iTunes”, tagcount:12}, {tagname:”JeditΩ”, tagcount:3}, {tagname:”Keynote”, tagcount:14}, {tagname:”Mac Blu-ray Player”, tagcount:1}, {tagname:”MacDown”, tagcount:3}, {tagname:”Mail”, tagcount:6}, {tagname:”Maps”, tagcount:3}, {tagname:”mi”, tagcount:2}, {tagname:”Numbers”, tagcount:8}, {tagname:”Pages”, tagcount:2}, {tagname:”Preview.app”, tagcount:2}, {tagname:”QuickTime Player”, tagcount:8}, {tagname:”Reminders”, tagcount:1}, {tagname:”Safari”, tagcount:13}, {tagname:”Script Debugger”, tagcount:1}, {tagname:”Script Editor”, tagcount:7}, {tagname:”Sorting”, tagcount:5}, {tagname:”Spell check”, tagcount:3}, {tagname:”System Events”, tagcount:6}, {tagname:”Terminal”, tagcount:4}, {tagname:”TextEdit”, tagcount:12}, {tagname:”Twitter”, tagcount:1}, {tagname:”Xcode”, tagcount:2}}

という入力から、

というタグクラウドのRTFをデスクトップに書き出します。処理時間は開発環境(MacBook Pro Retina 2012 Core i7 2.66GHz)で0.08秒ぐらいです。

本当は、こんな1次元で連続した内容ではなく、2次元で各タグを分離したオブジェクトとして平面上に配置し、かつ、大きな文字の内容を中心部に配置するとか、間を詰めるために縦方向に回転させたタグも入れるとか、そういう感じの処理を(自動で)行いたいところなので、このレベルだと「ただタグとして並んでいるだけ」で満足できません。

最終的には、日本語のテキストを形態素解析して固有名詞のみ抽出し、出現頻度の高いものをタグクラウドで並べることで内容を把握しやすくする、といった処理を行いたいところです。

AppleScript名:Tag CloudっぽいRTFの作成
— Created 2018-06-06 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSFont : a reference to current application’s NSFont
property NSUUID : a reference to current application’s NSUUID
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property Board2D : a reference to current application’s Board2D
property Pathfinder : a reference to current application’s Pathfinder
property NSDictionary : a reference to current application’s NSDictionary
property NSLiteralSearch : a reference to current application’s NSLiteralSearch
property NSMutableArray : a reference to current application’s NSMutableArray
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
property NSDocumentTypeDocumentAttribute : a reference to current application’s NSDocumentTypeDocumentAttribute

set tagList to {{tagname:"AirServer", tagcount:2}, {tagname:"App Store", tagcount:1}, {tagname:"Calendar", tagcount:3}, {tagname:"Contacts", tagcount:1}, {tagname:"CotEditor", tagcount:27}, {tagname:"Dictionary", tagcount:9}, {tagname:"Dock", tagcount:7}, {tagname:"Evernote", tagcount:2}, {tagname:"Finder", tagcount:20}, {tagname:"HelpViewer", tagcount:2}, {tagname:"HoudahSpot", tagcount:1}, {tagname:"iBooks", tagcount:1}, {tagname:"Image Events", tagcount:1}, {tagname:"iTunes", tagcount:12}, {tagname:"JeditΩ", tagcount:3}, {tagname:"Keynote", tagcount:14}, {tagname:"Mac Blu-ray Player", tagcount:1}, {tagname:"MacDown", tagcount:3}, {tagname:"Mail", tagcount:6}, {tagname:"Maps", tagcount:3}, {tagname:"mi", tagcount:2}, {tagname:"Numbers", tagcount:8}, {tagname:"Pages", tagcount:2}, {tagname:"Preview.app", tagcount:2}, {tagname:"QuickTime Player", tagcount:8}, {tagname:"Reminders", tagcount:1}, {tagname:"Safari", tagcount:13}, {tagname:"Script Debugger", tagcount:1}, {tagname:"Script Editor", tagcount:7}, {tagname:"Sorting", tagcount:5}, {tagname:"Spell check", tagcount:3}, {tagname:"System Events", tagcount:6}, {tagname:"Terminal", tagcount:4}, {tagname:"TextEdit", tagcount:12}, {tagname:"Twitter", tagcount:1}, {tagname:"Xcode", tagcount:2}}

set targFontName to "Courier-Bold" –PostScript Name

set tagArray to current application’s NSMutableArray’s arrayWithArray:tagList
set aMax to (tagArray’s valueForKeyPath:"@max.tagcount") as list of string or string –as anything
set aMin to (tagArray’s valueForKeyPath:"@min.tagcount") as list of string or string –as anything

set strList to tagArray’s valueForKey:"tagname"
set strAll to retArrowText(strList, " ") of me
set strAll to " " & strAll & " "

set anAttr to current application’s NSMutableAttributedString’s alloc()’s initWithString:strAll

repeat with i in tagList
  set aName to (tagname of i) as string
  
set aNum to (tagcount of i) as number
  
if aNum > (aMax * 0.8) then
    set aFontSize to 48
    
set aColor to current application’s NSColor’s redColor()
  else if aNum > (aMax * 0.6) then
    set aFontSize to 36
    
set aColor to current application’s NSColor’s orangeColor()
  else if aNum > (aMax * 0.4) then
    set aFontSize to 22
    
set aColor to current application’s NSColor’s greenColor()
  else
    set aFontSize to 16
    
set aColor to current application’s NSColor’s blackColor()
  end if
  
  
set aFont to (current application’s NSFont’s fontWithName:targFontName |size|:aFontSize)
  
  
–Caution: Call by Reference
  
markCharOfAttributedString(anAttr, strAll, " " & aName & " ", aColor, aFont) of me
  
end repeat

–結果のRTFをデスクトップ上に書き出す。ファイル名はUUID.rtf
set targFol to current application’s NSHomeDirectory()’s stringByAppendingPathComponent:"Desktop"
set aRes to my saveStyledTextAsRTF(targFol, anAttr)

–指定のAttributed String内で指定文字列が含まれる箇所に指定の色をつける(結果はメイン側に参照渡し)
on markCharOfAttributedString(anAttr, origStr, aTargStr, aColor, aFont)
  set rList to searchWordWithRange(origStr, aTargStr) of me
  
repeat with ii in rList
    (anAttr’s addAttribute:(NSForegroundColorAttributeName) value:aColor range:ii)
    (
anAttr’s addAttribute:(NSFontAttributeName) value:aFont range:ii)
  end repeat
end markCharOfAttributedString

–指定の文字列をAttributed Stringに変換して任意のフォントを一括指定
on changeAttrStrsFontAttribute(aStr, aFontPSName, aFontSize)
  set tmpAttr to NSMutableAttributedString’s alloc()’s initWithString:aStr
  
set aRange to current application’s NSMakeRange(0, tmpAttr’s |length|())
  
set aVal1 to NSFont’s fontWithName:aFontPSName |size|:aFontSize
  
tmpAttr’s beginEditing()
  
tmpAttr’s addAttribute:(NSFontAttributeName) value:aVal1 range:aRange
  
tmpAttr’s endEditing()
  
return tmpAttr
end changeAttrStrsFontAttribute

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(targFol, aStyledString)
  set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to NSDictionary’s dictionaryWithObject:"NSRTFTextDocumentType" forKey:(NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
set theName to (NSUUID’s UUID()’s UUIDString())
  
set thePath to NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:"rtf"
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

–指定テキストデータ(atargText)内に、指定文字列(aSearchStr)が含まれる範囲情報(NSRange)をすべて取得する
on searchWordWithRange(aTargText, aSearchStr)
  set aStr to NSString’s stringWithString:aTargText
  
set bStr to NSString’s stringWithString:aSearchStr
  
set hitArray to NSMutableArray’s alloc()’s init()
  
set cNum to (aStr’s |length|()) as integer
  
  
set aRange to current application’s NSMakeRange(0, cNum)
  
  
repeat
    set detectedRange to aStr’s rangeOfString:bStr options:NSLiteralSearch range:aRange
    
set aLoc to (detectedRange’s location)
    
–CAUTION !!!! Sometimes aLoc returns not NSNotFound (-1) but a Very large number
    
if (aLoc > 9.999999999E+9) or (aLoc = (current application’s NSNotFound)) then exit repeat
    
    
hitArray’s addObject:detectedRange
    
    
set aNum to aLoc as integer
    
set bNum to (detectedRange’s |length|) as integer
    
    
set aRange to current application’s NSMakeRange(aNum + bNum, cNum – (aNum + bNum))
  end repeat
  
  
return hitArray
end searchWordWithRange

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as list of string or string
end retStrFromArrayWithDelimiter

on retArrowText(aList, aDelim) –自分のASでよく使うハンドラ名称なので、同じものを用意
  return my retStrFromArrayWithDelimiter(aList, aDelim)
end retArrowText

–テキストを指定デリミタでリスト化
on parseByDelim(aData, aDelim)
  set aText to current application’s NSString’s stringWithString:aData
  
set aList to aText’s componentsSeparatedByString:aDelim
  
return aList as list
end parseByDelim

★Click Here to Open This Script 

Posted in list Record RTF Text | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Finderで選択中のPDFを反時計方向に90°回転させる

Posted on 6月 4, 2018 by Takaaki Naganoya

Finder上で選択中のPDFを反時計方向に90°回転(=時計方向に270°回転)させるAppleScriptです。

Finder上で選択中の項目の中にPDF以外のものがあった場合には処理をスキップし、選択中のアイテムがない場合には処理を行いません。

実際には、macOS標準装備のScript Menuに、それぞれの角度(90°、180°、270°)への回転Scriptを個別に入れて使っています。1本のScriptで角度入力を行って回転させるよりも、あらかじめ固定の角度に回転させるものを複数用意しておいたほうが使い勝手がよいためです。

ドキュメントスキャナで紙の資料をPDFにスキャンするような時に、紙がヨレていて1枚ずつでないとスキャンできないような場合で、さらに穴が空いていたりヨレていて通常方向に紙を入れられなかった場合に、他の方向に入れてスキャンしておき、本Scriptのようなプログラムであとでまとめて回転させるなどの処理をよく行っています。

AppleScript名:Finderで選択中のPDFを反時計方向に90°回転させる
— Created 2018-05-26 by Takaaki Naganoya
— Modified 2018-06-02 by Takaaki Naganoya
— 2018 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 NSUUID : a reference to current application’s NSUUID
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSPredicate : a reference to current application’s NSPredicate
property PDFDocument : a reference to current application’s PDFDocument
property NSFileManager : a reference to current application’s NSFileManager
property NSURLPathKey : a reference to current application’s NSURLPathKey
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey
property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSURLContentModificationDateKey : a reference to current application’s NSURLContentModificationDateKey
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set targDegree to 270 — targDegree have to be in {0, 90, 180, 270, 360} in clockwise

–set inFiles to (choose file of type {"pdf"} with prompt "Choose your PDF files:" with multiple selections allowed)
tell application "Finder"
  set inFiles to selection as alias list
end tell
if inFiles = {} then return

–指定のAlias listのうちPDFのみ抽出
set filRes1 to filterAliasListByUTI(inFiles, "com.adobe.pdf") of me
if filRes1 = {} then return

–選択中のファイルのうちの1つから親フォルダを求め、出力先ファイルパスを組み立てる
set outPathTarg to POSIX path of (first item of filRes1)
set pathString to NSString’s stringWithString:outPathTarg
set newPath to (pathString’s stringByDeletingLastPathComponent()) as string

repeat with i in filRes1
  set destPosixPath to newPath & "/" & ((NSUUID’s UUID()’s UUIDString()) as string) & ".pdf"
  
rotatePDFandSaveAt(i, destPosixPath, targDegree) of me
end repeat

–与えられたPOSIX pathのPDFを指定の角度に回転させて新規指定パスに書き出す
on rotatePDFandSaveAt(oldPath as string, newPath as string, aDegree as integer)
  
  
–Error Check
  
if aDegree is not in {0, 90, 180, 270, 360} then error "Wrong Degree"
  
  
set aURL to current application’s |NSURL|’s fileURLWithPath:oldPath
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL
  
  
set pCount to aPDFdoc’s pageCount() –count pages
  
  
–Make Blank PDF
  
set newPDFdoc to PDFDocument’s alloc()’s init()
  
  
–Rotate Each Page
  
repeat with i from 0 to (pCount – 1)
    set aPage to (aPDFdoc’s pageAtIndex:i)
    
    
–Set Degree
    
set curDegree to aPage’s |rotation|() –Get Current Degree
    (
aPage’s setRotation:(aDegree + curDegree)) –Set New Degree
    
    (
newPDFdoc’s insertPage:aPage atIndex:i)
  end repeat
  
  
set aRes to newPDFdoc’s writeToFile:newPath
  
return aRes as boolean
  
end rotatePDFandSaveAt

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定の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 PDF | Tagged 10.11savvy 10.12savvy 10.13savvy Finder | Leave a 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