Slides from Outline

Here’s a powerful example of app-to-app automation. An outline in OmniOutliner is used as the source material for a set of slides created in OmniGraffle.

Note the use of link-backs so that simply tapping an object on an OmniGraffle slide reveals the source item in the OmniOutliner outline.

Also note that when the outline is updated, the changes can be sent to the OmniGraffle document!

Retrieving Data

The example function (shown below) is designed to extract the properties of every item of the current OmniOutliner outline, and return them as an array of individual JavaScript objects.

function outlineToObjectsArray(){ var array = new Array() items = rootItem.descendents for(i = 0; i < items.length; i++){ item = items[i] obj = new Object() obj.level = item.level obj.index = item.index obj.topic = item.topic array.push(obj) } return array }

The function uses the OmniOutliner descendents property of the rootItem class to generate an ordered list of every item of the outline. This list is then iterated in order to create an array of JavaScript objects, each of which contains the values of the level, index, and topic properties of the outline item.

The result of function is an array similar in structure to this:

[{"level":1,"index":0,"content":"Aquire"},{"level":2,"index":0,"content":"Selection"},{"level":2,"index":1,"content":"Input"},{"level":2,"index":2,"content":"Prompt"},{"level":1,"index":1,"content":"Process"},{"level":2,"index":0,"content":"Flexible Workflow"},{"level":2,"index":1,"content":"User Interaction"},{"level":1,"index":2,"content":"Distribute"},{"level":2,"index":0,"content":"Local"},{"level":2,"index":1,"content":"Network"}]

To convert the resulting array of JavaScript objects into a data format suitable for passing from the function to the main script, the returning line of the function (line 12) is changed so that the array is converted into a string by using the stringify() method of the JSON class, and then the resulting string is encoded using the standard JavaScript encodeURIComponent() method. The encoded function result will be decoded in the main script (below: line 23).

Retrieve and Build

Here’s a script that uses Call and Response to create a set of slides in OmniGraffle based upon the contents of the current OmniOutliner document.

var alert = new Alert("Confirmation", "This script will import the topics from the current OmniOutliner document to OmniGraffle as canvas slides.\n\nShould the script continue?") alert.addOption("Continue") alert.addOption("Stop") alert.show(function(result){ if (result == 1){ throw new Error('script cancelled') } else { function outlineToObjectsArray(){ var array = new Array() items = rootItem.descendents for(i = 0; i < items.length; i++){ item = items[i] obj = new Object() obj.level = item.level obj.index = item.index obj.topic = item.topic array.push(obj) } return encodeURIComponent(JSON.stringify(array)) } var scriptURL = URL.tellScript("omnioutliner", outlineToObjectsArray.toString() + '\n' + 'outlineToObjectsArray()') scriptURL.call(function(reply){ reply = decodeURIComponent(reply) reply = JSON.parse(reply) // title and body size and position are based upon current canvas dimensions var cnvs = document.windows[0].selection.canvas var cnvsSize = cnvs.size var cW = cnvsSize.width var cH = cnvsSize.height var vM = Math.round(cH/12) var hM = Math.round(cW/12) var boxOffset = Math.round(cH/32) var titleSize = Math.round(cW/14) var bodySize = Math.round(cW/20) var lineHeightPercentage = 1.25 var titleBoxRect = new Rect(hM, vM, cW - hM*2, titleSize * lineHeightPercentage) var bodyBoxRect = new Rect(hM, vM + titleBoxRect.height + boxOffset, cW - hM*2, cH - vM*2 - boxOffset - titleBoxRect.height) // font family defaults var titleFontPSName = 'HelveticaNeue-Medium' var bodyFontPSName = 'HelveticaNeue' for(i = 0; i < reply.length; i++){ // retrieve item data obj = reply[i] objIndex = obj.index objLevel = obj.level objTopic = obj.topic // create new canvas for each top-level item if (objLevel == 1){ cnvs = addCanvas() cnvs.size = cnvsSize cnvs.canvasSizingMode = CanvasSizingMode.Fixed // create a slide title box shape = cnvs.addShape('Rectangle',titleBoxRect) shape.name = 'Slide Title' shape.textHorizontalPadding = 0 shape.textVerticalPadding = 0 shape.text = objTopic shape.fontName = titleFontPSName shape.autosizing = TextAutosizing.Overflow shape.textHorizontalAlignment = HorizontalTextAlignment.Left shape.textVerticalPlacement = VerticalTextPlacement.Middle shape.textSize = titleSize shape.fillColor = null shape.shadowColor = null shape.strokeColor = null // create a slide body box shape = cnvs.addShape('Rectangle',bodyBoxRect) shape.name = 'Slide Body' shape.textHorizontalPadding = 0 shape.textVerticalPadding = 0 shape.text = ' ' shape.fontName = bodyFontPSName shape.autosizing = TextAutosizing.Overflow shape.textHorizontalAlignment = HorizontalTextAlignment.Left shape.textVerticalPlacement = VerticalTextPlacement.Top shape.textSize = bodySize shape.fillColor = null shape.shadowColor = null shape.strokeColor = null } else if (objLevel == 2){ bodyShape = cnvs.graphicWithName('Slide Body') bodyText = bodyShape.text if (bodyText == '' || bodyText == ' '){ bodyShape.text = '•' + ' ' + objTopic } else { bodyShape.text = bodyText + '\n' + '•' + ' ' + objTopic } bodyShape.textSize = bodySize } } }) } })
omnigraffle:///omnijs-run?script=var%20alert%20%3D%20new%20Alert%28%22Confirmation%22%2C%20%22This%20script%20will%20import%20the%20topics%20from%20the%20current%20OmniOutliner%20document%20to%20OmniGraffle%20as%20canvas%20slides%2E%5Cn%5CnShould%20the%20script%20continue%3F%22%29%0Aalert%2EaddOption%28%22Continue%22%29%0Aalert%2EaddOption%28%22Stop%22%29%0Aalert%2Eshow%28function%28result%29%7B%0A%09if%20%28result%20%3D%3D%201%29%7B%0A%09%09throw%20new%20Error%28%27script%20cancelled%27%29%0A%09%7D%20else%20%7B%0A%09%09function%20outlineToObjectsArray%28%29%7B%0A%09%09%09var%20array%20%3D%20new%20Array%28%29%0A%09%09%09items%20%3D%20rootItem%2Edescendents%0A%09%09%09for%28i%20%3D%200%3B%20i%20%3C%20items%2Elength%3B%20i%2B%2B%29%7B%0A%09%09%09%09item%20%3D%20items%5Bi%5D%0A%09%09%09%09obj%20%3D%20new%20Object%28%29%0A%09%09%09%09obj%2Elevel%20%3D%20item%2Elevel%0A%09%09%09%09obj%2Eindex%20%3D%20item%2Eindex%0A%09%09%09%09obj%2Etopic%20%3D%20item%2Etopic%0A%09%09%09%09array%2Epush%28obj%29%0A%09%09%09%7D%0A%09%09%09return%20encodeURIComponent%28JSON%2Estringify%28array%29%29%0A%09%09%7D%0A%09%09var%20scriptURL%20%3D%20URL%2EtellScript%28%22omnioutliner%22%2C%20outlineToObjectsArray%2EtoString%28%29%20%2B%20%27%5Cn%27%20%2B%20%27outlineToObjectsArray%28%29%27%29%0A%09%09scriptURL%2Ecall%28function%28reply%29%7B%0A%09%09%09reply%20%3D%20decodeURIComponent%28reply%29%0A%09%09%09reply%20%3D%20JSON%2Eparse%28reply%29%0A%09%09%09%2F%2F%20title%20and%20body%20size%20and%20position%20are%20based%20upon%20current%20canvas%20dimensions%0A%09%09%09var%20cnvs%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%0A%09%09%09var%20cnvsSize%20%3D%20cnvs%2Esize%0A%09%09%09var%20cW%20%3D%20cnvsSize%2Ewidth%0A%09%09%09var%20cH%20%3D%20cnvsSize%2Eheight%0A%09%09%09var%20vM%20%3D%20Math%2Eround%28cH%2F12%29%0A%09%09%09var%20hM%20%3D%20Math%2Eround%28cW%2F12%29%0A%09%09%09var%20boxOffset%20%3D%20Math%2Eround%28cH%2F32%29%0A%09%09%09var%20titleSize%20%3D%20Math%2Eround%28cW%2F14%29%0A%09%09%09var%20bodySize%20%3D%20Math%2Eround%28cW%2F20%29%0A%09%09%09var%20lineHeightPercentage%20%3D%201%2E25%0A%09%09%09var%20titleBoxRect%20%3D%20new%20Rect%28hM%2C%20vM%2C%20cW%20-%20hM*2%2C%20titleSize%20*%20lineHeightPercentage%29%0A%09%09%09var%20bodyBoxRect%20%3D%20new%20Rect%28hM%2C%20vM%20%2B%20titleBoxRect%2Eheight%20%2B%20boxOffset%2C%20cW%20-%20hM*2%2C%20cH%20-%20vM*2%20-%20boxOffset%20-%20titleBoxRect%2Eheight%29%0A%09%09%09%2F%2F%20font%20family%20defaults%0A%09%09%09var%20titleFontPSName%20%3D%20%27HelveticaNeue-Medium%27%0A%09%09%09var%20bodyFontPSName%20%3D%20%27HelveticaNeue%27%0A%09%09%09for%28i%20%3D%200%3B%20i%20%3C%20reply%2Elength%3B%20i%2B%2B%29%7B%0A%09%09%09%09%2F%2F%20retrieve%20item%20data%0A%09%09%09%09obj%20%3D%20reply%5Bi%5D%0A%09%09%09%09objIndex%20%3D%20obj%2Eindex%0A%09%09%09%09objLevel%20%3D%20obj%2Elevel%0A%09%09%09%09objTopic%20%3D%20obj%2Etopic%0A%09%09%09%09%2F%2F%20create%20new%20canvas%20for%20each%20top-level%20item%0A%09%09%09%09if%20%28objLevel%20%3D%3D%201%29%7B%0A%09%09%09%09%09cnvs%20%3D%20addCanvas%28%29%0A%09%09%09%09%09cnvs%2Esize%20%3D%20cnvsSize%0A%09%09%09%09%09cnvs%2EcanvasSizingMode%20%3D%20CanvasSizingMode%2EFixed%0A%09%09%09%09%09%2F%2F%20create%20a%20slide%20title%20box%0A%09%09%09%09%09shape%20%3D%20cnvs%2EaddShape%28%27Rectangle%27%2CtitleBoxRect%29%0A%09%09%09%09%09shape%2Ename%20%3D%20%27Slide%20Title%27%0A%09%09%09%09%09shape%2EtextHorizontalPadding%20%3D%200%0A%09%09%09%09%09shape%2EtextVerticalPadding%20%3D%200%0A%09%09%09%09%09shape%2Etext%20%3D%20objTopic%0A%09%09%09%09%09shape%2EfontName%20%3D%20titleFontPSName%0A%09%09%09%09%09shape%2Eautosizing%20%3D%20TextAutosizing%2EOverflow%0A%09%09%09%09%09shape%2EtextHorizontalAlignment%20%3D%20HorizontalTextAlignment%2ELeft%0A%09%09%09%09%09shape%2EtextVerticalPlacement%20%3D%20VerticalTextPlacement%2EMiddle%0A%09%09%09%09%09shape%2EtextSize%20%3D%20titleSize%0A%09%09%09%09%09shape%2EfillColor%20%3D%20null%0A%09%09%09%09%09shape%2EshadowColor%20%3D%20null%0A%09%09%09%09%09shape%2EstrokeColor%20%3D%20null%0A%09%09%09%09%09%2F%2F%20create%20a%20slide%20body%20box%0A%09%09%09%09%09shape%20%3D%20cnvs%2EaddShape%28%27Rectangle%27%2CbodyBoxRect%29%0A%09%09%09%09%09shape%2Ename%20%3D%20%27Slide%20Body%27%0A%09%09%09%09%09shape%2EtextHorizontalPadding%20%3D%200%0A%09%09%09%09%09shape%2EtextVerticalPadding%20%3D%200%0A%09%09%09%09%09shape%2Etext%20%3D%20%27%20%27%0A%09%09%09%09%09shape%2EfontName%20%3D%20bodyFontPSName%0A%09%09%09%09%09shape%2Eautosizing%20%3D%20TextAutosizing%2EOverflow%0A%09%09%09%09%09shape%2EtextHorizontalAlignment%20%3D%20HorizontalTextAlignment%2ELeft%0A%09%09%09%09%09shape%2EtextVerticalPlacement%20%3D%20VerticalTextPlacement%2ETop%0A%09%09%09%09%09shape%2EtextSize%20%3D%20bodySize%0A%09%09%09%09%09shape%2EfillColor%20%3D%20null%0A%09%09%09%09%09shape%2EshadowColor%20%3D%20null%0A%09%09%09%09%09shape%2EstrokeColor%20%3D%20null%0A%09%09%09%09%7D%20else%20if%20%28objLevel%20%3D%3D%202%29%7B%0A%09%09%09%09%09bodyShape%20%3D%20cnvs%2EgraphicWithName%28%27Slide%20Body%27%29%0A%09%09%09%09%09bodyText%20%3D%20bodyShape%2Etext%0A%09%09%09%09%09if%20%28bodyText%20%3D%3D%20%27%27%20%7C%7C%20bodyText%20%3D%3D%20%27%20%27%29%7B%0A%09%09%09%09%09%09bodyShape%2Etext%20%3D%20%27%E2%80%A2%27%20%2B%20%27%20%27%20%2B%20objTopic%0A%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09bodyShape%2Etext%20%3D%20bodyText%20%2B%20%27%5Cn%27%20%2B%20%27%E2%80%A2%27%20%2B%20%27%20%27%20%2B%20objTopic%0A%09%09%09%09%09%7D%0A%09%09%09%09%09bodyShape%2EtextSize%20%3D%20bodySize%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%29%0A%09%7D%0A%7D%29
omnigraffle:///omnijs-run?script=var%20alert%20%3D%20new%20Alert%28%22Confirmation%22%2C%20%22This%20script%20will%20import%20the%20topics%20from%20the%20current%20OmniOutliner%20document%20to%20OmniGraffle%20as%20canvas%20slides%2E%5Cn%5CnShould%20the%20script%20continue%3F%22%29%0Aalert%2EaddOption%28%22Continue%22%29%0Aalert%2EaddOption%28%22Stop%22%29%0Aalert%2Eshow%28function%28result%29%7B%0A%09if%20%28result%20%3D%3D%201%29%7B%0A%09%09throw%20new%20Error%28%27script%20cancelled%27%29%0A%09%7D%20else%20%7B%0A%09%09function%20outlineToObjectsArray%28%29%7B%0A%09%09%09var%20array%20%3D%20new%20Array%28%29%0A%09%09%09items%20%3D%20rootItem%2Edescendents%0A%09%09%09for%28i%20%3D%200%3B%20i%20%3C%20items%2Elength%3B%20i%2B%2B%29%7B%0A%09%09%09%09item%20%3D%20items%5Bi%5D%0A%09%09%09%09obj%20%3D%20new%20Object%28%29%0A%09%09%09%09obj%2Elevel%20%3D%20item%2Elevel%0A%09%09%09%09obj%2Eindex%20%3D%20item%2Eindex%0A%09%09%09%09obj%2Etopic%20%3D%20item%2Etopic%0A%09%09%09%09obj%2Eidentifier%20%3D%20item%2Eidentifier%0A%09%09%09%09array%2Epush%28obj%29%0A%09%09%09%7D%0A%09%09%09return%20encodeURIComponent%28JSON%2Estringify%28array%29%29%0A%09%09%7D%0A%09%09var%20scriptURL%20%3D%20URL%2EtellScript%28%22omnioutliner%22%2C%20outlineToObjectsArray%2EtoString%28%29%20%2B%20%27%5Cn%27%20%2B%20%27outlineToObjectsArray%28%29%27%29%0A%09%09scriptURL%2Ecall%28function%28reply%29%7B%0A%09%09%09reply%20%3D%20decodeURIComponent%28reply%29%0A%09%09%09reply%20%3D%20JSON%2Eparse%28reply%29%0A%09%09%09%2F%2F%20setup%20canvas%20display%20to%2075%25%20centered%20view%0A%09%09%09var%20cnvs%20%3D%20document%2Ewindows%5B0%5D%2Eselection%2Ecanvas%0A%09%09%09document%2Ewindows%5B0%5D%2Ezoom%20%3D%200%2E75%0A%09%09%09document%2Ewindows%5B0%5D%2EcenterVisiblePoint%20%3D%20cnvs%2Ebackground%2Egeometry%2Ecenter%0A%09%09%09%2F%2F%20title%20and%20body%20size%20and%20position%20are%20based%20upon%20current%20canvas%20dimensions%0A%09%09%09var%20cnvsSize%20%3D%20cnvs%2Esize%0A%09%09%09var%20cW%20%3D%20cnvsSize%2Ewidth%0A%09%09%09var%20cH%20%3D%20cnvsSize%2Eheight%0A%09%09%09var%20cZoom%20%3D%20document%2Ewindows%5B0%5D%2Ezoom%0A%09%09%09var%20cCenterPoint%20%3D%20document%2Ewindows%5B0%5D%2EcenterVisiblePoint%0A%09%09%09var%20vM%20%3D%20Math%2Eround%28cH%2F12%29%0A%09%09%09var%20hM%20%3D%20Math%2Eround%28cW%2F12%29%0A%09%09%09var%20boxOffset%20%3D%20Math%2Eround%28cH%2F32%29%0A%09%09%09var%20titleSize%20%3D%20Math%2Eround%28cW%2F14%29%0A%09%09%09var%20bodySize%20%3D%20Math%2Eround%28cW%2F20%29%0A%09%09%09var%20lineHeightPercentage%20%3D%201%2E25%0A%09%09%09var%20titleBoxRect%20%3D%20new%20Rect%28hM%2C%20vM%2C%20cW%20-%20hM*2%2C%20titleSize%20*%20lineHeightPercentage%29%0A%09%09%09var%20bodyBoxRect%20%3D%20new%20Rect%28hM%2C%20vM%20%2B%20titleBoxRect%2Eheight%20%2B%20boxOffset%2C%20cW%20-%20hM*2%2C%20cH%20-%20vM*2%20-%20boxOffset%20-%20titleBoxRect%2Eheight%29%0A%09%09%09%2F%2F%20font%20family%20defaults%0A%09%09%09var%20titleFontPSName%20%3D%20%27HelveticaNeue-Medium%27%0A%09%09%09var%20bodyFontPSName%20%3D%20%27HelveticaNeue%27%0A%09%09%09for%28i%20%3D%200%3B%20i%20%3C%20reply%2Elength%3B%20i%2B%2B%29%7B%0A%09%09%09%09%2F%2F%20retrieve%20item%20data%0A%09%09%09%09obj%20%3D%20reply%5Bi%5D%0A%09%09%09%09objIndex%20%3D%20obj%2Eindex%0A%09%09%09%09objLevel%20%3D%20obj%2Elevel%0A%09%09%09%09objTopic%20%3D%20obj%2Etopic%0A%09%09%09%09objIdentifier%20%3D%20obj%2Eidentifier%0A%09%09%09%09%2F%2F%20create%20a%20link-back%20URL%20to%20outline%20item%0A%09%09%09%09objURLString%20%3D%20%27omnioutliner%3A%2F%2F%2Fopen%3Frow%3D%27%20%2B%20objIdentifier%0A%09%09%09%09objURL%20%3D%20URL%2EfromString%28objURLString%29%0A%09%09%09%09%2F%2F%20create%20new%20canvas%20for%20each%20top-level%20item%0A%09%09%09%09if%20%28objLevel%20%3D%3D%201%29%7B%0A%09%09%09%09%09cnvs%20%3D%20addCanvas%28%29%0A%09%09%09%09%09cnvs%2Esize%20%3D%20cnvsSize%0A%09%09%09%09%09cnvs%2EcanvasSizingMode%20%3D%20CanvasSizingMode%2EFixed%0A%09%09%09%09%09document%2Ewindows%5B0%5D%2EsetViewForCanvas%28cnvs%2C%20cZoom%2C%20cCenterPoint%29%0A%09%09%09%09%09%2F%2F%20create%20a%20slide%20title%20box%0A%09%09%09%09%09shape%20%3D%20cnvs%2EaddShape%28%27Rectangle%27%2CtitleBoxRect%29%0A%09%09%09%09%09%2F%2F%20tag%20container%20with%20ID%20of%20outline%20item%0A%09%09%09%09%09shape%2EsetUserData%28%27titleID%27%2CobjIdentifier%29%0A%09%09%09%09%09shape%2Ename%20%3D%20%27Slide%20Title%27%0A%09%09%09%09%09shape%2EtextHorizontalPadding%20%3D%200%0A%09%09%09%09%09shape%2EtextVerticalPadding%20%3D%200%0A%09%09%09%09%09shape%2Etext%20%3D%20objTopic%0A%09%09%09%09%09shape%2EfontName%20%3D%20titleFontPSName%0A%09%09%09%09%09shape%2Eautosizing%20%3D%20TextAutosizing%2EOverflow%0A%09%09%09%09%09shape%2EtextHorizontalAlignment%20%3D%20HorizontalTextAlignment%2ELeft%0A%09%09%09%09%09shape%2EtextVerticalPlacement%20%3D%20VerticalTextPlacement%2EMiddle%0A%09%09%09%09%09shape%2EtextSize%20%3D%20titleSize%0A%09%09%09%09%09shape%2EfillColor%20%3D%20null%0A%09%09%09%09%09shape%2EshadowColor%20%3D%20null%0A%09%09%09%09%09shape%2EstrokeColor%20%3D%20null%0A%09%09%09%09%09shape%2EactionURL%20%3D%20objURL%0A%09%09%09%09%09%2F%2F%20create%20a%20slide%20body%20box%0A%09%09%09%09%09shape%20%3D%20cnvs%2EaddShape%28%27Rectangle%27%2CbodyBoxRect%29%0A%09%09%09%09%09shape%2EsetUserData%28%27bodyID%27%2CobjIdentifier%29%0A%09%09%09%09%09shape%2Ename%20%3D%20%27Slide%20Body%27%0A%09%09%09%09%09shape%2EtextHorizontalPadding%20%3D%200%0A%09%09%09%09%09shape%2EtextVerticalPadding%20%3D%200%0A%09%09%09%09%09shape%2Etext%20%3D%20%27%20%27%0A%09%09%09%09%09shape%2EfontName%20%3D%20bodyFontPSName%0A%09%09%09%09%09shape%2Eautosizing%20%3D%20TextAutosizing%2EOverflow%0A%09%09%09%09%09shape%2EtextHorizontalAlignment%20%3D%20HorizontalTextAlignment%2ELeft%0A%09%09%09%09%09shape%2EtextVerticalPlacement%20%3D%20VerticalTextPlacement%2ETop%0A%09%09%09%09%09shape%2EtextSize%20%3D%20bodySize%0A%09%09%09%09%09shape%2EfillColor%20%3D%20null%0A%09%09%09%09%09shape%2EshadowColor%20%3D%20null%0A%09%09%09%09%09shape%2EstrokeColor%20%3D%20null%0A%09%09%09%09%7D%20else%20if%20%28objLevel%20%3D%3D%202%29%7B%0A%09%09%09%09%09bodyShape%20%3D%20cnvs%2EgraphicWithName%28%27Slide%20Body%27%29%0A%09%09%09%09%09bodyText%20%3D%20bodyShape%2Etext%0A%09%09%09%09%09if%20%28bodyText%20%3D%3D%20%27%27%20%7C%7C%20bodyText%20%3D%3D%20%27%20%27%29%7B%0A%09%09%09%09%09%09bodyShape%2Etext%20%3D%20%27%E2%80%A2%27%20%2B%20%27%20%27%20%2B%20objTopic%0A%09%09%09%09%09%7D%20else%20%7B%0A%09%09%09%09%09%09bodyShape%2Etext%20%3D%20bodyText%20%2B%20%27%5Cn%27%20%2B%20%27%E2%80%A2%27%20%2B%20%27%20%27%20%2B%20objTopic%0A%09%09%09%09%09%7D%0A%09%09%09%09%09bodyShape%2EtextSize%20%3D%20bodySize%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D%29%0A%09%7D%0A%7D%29

App-to-App Demo

Here’s a short video demonstrating App-to-App scripting between OmniGraffle and OmniOutliner (macOS). In the shown example, the topics from an OmniOutliner document are used to create slides in the current OmniGraffle document.

TIP: the video shows the use of Omni Automation scripts implemented as actions for the “Presentation Tools” OmniGraffle plug-in. TAP|CLICK to download the plug-in, and TAP|CLICK to download the demo outline.

UNDER CONSTRUCTION

This webpage is in the process of being developed. Any content may change and may not be accurate or complete at this time.

DISCLAIMER