TweetFollow Us on Twitter

Uninstalling with AppleScript

Volume Number: 23 (2007)
Issue Number: 05
Column Tag: Scripting

Uninstalling with AppleScript

Building an uninstaller with AppleScript Studio

By José R.C. Cruz

Introduction

In a previous MacTech article, we learned how to use the PackageMaker tool to build a distribution package. We also learned how to localize that package for different languages, and how to customize it with scripts. But the one thing we were unable to do with the tool is to build an uninstaller.

Third-party tools such as ViseX and InstallerMaker can add an uninstall option to their installers. This feature is sadly missing from PackageMaker, though not without reason. In fact, most products are easy to remove -- they are contained in a single folder, and trashing that folder completely uninstalls the product. But some products will have multiple files installed in different directories. Others will create custom directories to store the files. A good example of such a product is Xcode. Its installer creates the custom directory Developer to contain its files. The installer also stores files in other directories such as /System/Library and /Library/Application Support. As a result, removing Xcode from the system can be a laborious process. In these situations, an uninstaller tool can be useful.

This article will demonstrate how to use AppleScript Studio to build an uninstaller. To get readers started on their own uninstallers, the Xcode project Uninstall is made available for downloading. A copy of this project can be obtained at the following URL: ftp://ftp.mactech.com/src/mactech/volume23_2007/23.05.sit.

The Receipts Bundle

After the Installer installs a software payload, it creates a copy of the package in the Receipts directory. The path to this directory is /Library/Receipts on the boot volume.

The copy of the installer package is known as a receipt bundle. Its presence indicates that a product has been installed successfully. It also tells the installer package if the latter has to do an upgrade, as opposed to an installation.

Figure 1 shows the internal structure of a typical receipt bundle. Notice that the bundle has most of the same files as an installer package. What is missing is the .paz.gz file containing the actual payload. Also missing are the two aliases to that file from the Resources subdirectory.


Figure 1. Structure of a typical receipts bundle.

There are software tools that purge the contents of the Receipts directory. This is often done to reclaim extra space, especially when the product associated with the receipt no longer exists. But removing a receipt, without removing the product, creates a new problem. Without the right receipt to guide it, an installer for a new product version may be unable to upgrade the current product correctly.

The BOM File

The BOM file is a list of all the files that comprise the software payload. It also defines the locations of each file on the target volume. This file is present in both the installer package and receipts bundle.

The BOM file format has its origins in the NeXTStep operating system. It is also a binary format and, as a result, is not directly readable. To read its contents, use the command-line tool lsbom to preprocess the BOM file.

The lsbom tool

The lsbom tool takes a BOM file as its input and renders its contents into human readable text. It then outputs the text to another file, or to stdout by default. The tool is a standard addition to the BSD subsystem of MacOS X. Its counterpart is the mkbom tool, which creates a BOM file for a given directory.

To use the lsbom tool, simply pass the path to the BOM file as its input. For example, to process the BOM file for the Sample.pkg receipt, type the following statement at the Terminal prompt.

   lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom

The tool will then parse the file and display its contents at lightning speed on the Terminal speed. To better read the output, pipe the results of the lsbom tool to the less tool.

   lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom | less

less will display the first N lines of text from lsbom. The number of lines displayed is dictated by the height of the Terminal window. To display the next N lines of text, tap on the Space bar. To display the previous N lines of text, tap on the B key while holding down the <CTRL> key.

Another way of handling the lsbom output is to save it to a file. To save the output to the file Sample.log, use the I/O redirection token '>'.

   lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom > Sample.log

Notice that, in both examples, the BOM file is always inside the Contents subdirectory of the receipt bundle. Also, the name of the BOM file is always Archive.bom. Most receipt bundles will follow the same conventions. Though it is possible for a BOM file to be located elsewhere in the bundle, this is rarely done.

The lsbom output

Listing 1 shows a sample output from the lsbom tool. Each entry corresponds to a file or directory installed by the package. The first three items of the BOM entry are arranged as follows.

directory_path file_modes user_id/group_id.

Each item is separated from the other by a single tab character (0x09). Now, if the entry is for a regular file, it will have two more items as shown below.

   directory_path file_modes user_id/group_id number_of_bytes crc_32

If it is for a symbolic link, its last item will be the path to the original file or directory.

   directory_path file_modes user_id/group_id number_of_bytes ¬
         original_path

Finally, if the entry is for a device file, its last item will be the assigned device number.

   directory_path file_modes user_id/group_id device_number

Listing 1. Sample output of the lsbom tool

.   40755   501/80
./Sample.app   40755   501/80
./Sample.app/Contents   40755   501/80
./Sample.app/Contents/Info.plist   100644   501/80   947 ¬
      1163649540
./Sample.app/Contents/MacOS   40755   501/80
./Sample.app/Contents/MacOS/Sample   100755   501/80   51956 ¬
      3193247409
./Sample.app/Contents/PkgInfo   100644   501/80   8 ¬
742937289
./Sample.app/Contents/Resources   40755   501/80
./Sample.app/Contents/Resources/Appearance.tiff   100644   501/80   4850 ¬
1276692542
...
./Sample.app/Contents/Resources/English.lproj   40755   501/80
./Sample.app/Contents/Resources/English.lproj/Credits.rtf   100644   501/80 ¬  
3163   3602318773
./Sample.app/Contents/Resources/English.lproj/Errors.strings   100644 ¬  
501/80   2978   2815210102
...

Most BOM file listings consist mostly of directories and regular files. Device files and symbolic links are seldom found. Also, the file_modes item is essentially the three permission flags written in octal form. Each of the lower three numbers represents the permission for world, group, and owner. The upper set of numbers represent the type of item in question. They are set to 40 for a directory, 100 for a generic file.

Notice that each directory_path item starts with a dot (.) character. This character is replaced by the IFPkgRelocatedPath value set in the Info.plist file. If that value is not set, the directory path is assumed to be relative to the OS X boot volume.

Also, if the package has installed payloads in other directories, the BOM listing will show these payloads. For example, if Sample.pkg has installed two files in the /usr/bin directory, the BOM listing may show these files as follows.

   ./usr/bin            40755      0/0
   ./usr/bin/foo      100755   0/0   12606   2275820725
   ./usr/bin/fubar      100755   0/0   12606   2275820725

Notice that both user_id and group_id items are set to 0 in the above example. This means that the owner of the two files and the directory is root. Removing the two files will require authentication. Do not, however, remove any directories or subdirectories with a root owner. Doing so may remove important files, and render the entire OS X platform unusable.

The lsbom options

The lsbom tool also provides a number of output options. Use these options to display specific entries from the BOM file as follows.

To display only the directories accessed or created during installation, use the -d option.

   lsbom -d /Library/Receipts/Sample.pkg/Contents/Archive.bom

The output listing will also include bundles such as .app, .bundle, and .lproj. To display only the paths of files that were installed or updated, use the -f option.

   lsbom -f /Library/Receipts/Sample.pkg/Contents/Archive.bom

To display only the paths of each directory and file, use the --s option.

   lsbom -s /Library/Receipts/Sample.pkg/Contents/Archive.bom

The lsbom tool also has options other than the ones shown above. To view a list of options, type the command lsbom -h at the Terminal prompt. Also, to view the tool's electronic manual, type info lsbom at the prompt.

AppleScript and the Shell

AppleScript is the native scripting language of the MacOS platform. First introduced in the 1990s, it is one of the first few languages that work in a GUI environment. It also uses a natural language syntax, which makes its scripts easy to read and write.

Another feature of AppleScript is that it can be extended using plug-ins. These plug-ins, or scripting additions, allow AppleScript to do tasks that are slow or impossible to do using the core language. The OS X version of AppleScript comes bundled with the plug-in named Standards Additions. With this plug-in, an AppleScript script can display simple dialogs and perform basic file I/O tasks. The script can also run Unix shell scripts using the do shell script function.

,b>The do shell script function

The do shell script function is AppleScript's gateway to the BSD subsystem of MacOS X. With this function, an AppleScript script can execute command-line tools or shell script files. It can also run a single-line shell script using this function. The function returns any results from the script as a string.

The function uses the interpreter set by the SHELL environment variable to do its tasks. To find out the current interpreter, launch the Script Editor tool, which is located in /Applications/AppleScripts. On the script window, type do shell script "printenv SHELL" and click on the Run button. If the current interpreter is bash, the function will return the string value of SHELL=/bin/bash on the Results pane.

Working with file paths

When using the do shell script function to manipulate files, it requires the file paths expressed using the POSIX format. In short, a forward slash character </> must separate each path name. For example, to parse the BOM file for Sample.pkg, pass the script to the function as follows.

   do shell script ¬
      "lsbom /Library/Receipts/Sample.pkg/Contents/Archive.bom"

Now if a path name contains any spaces, a reverse slash <\> character must precede each space. For example, to parse the BOM file for Test Sample.pkg, pass the script as follows.

   do shell script ¬
      "lsbom /Library/Receipts/Test\\ Sample.pkg/Contents/Archive.bom"

Notice that two reverse slashes precede the space in Test Sample.pkg. This is necessary due to a little quirk in AppleScript. The first reverse slash tells AppleScript to treat the second slash is part of the string. The second slash tells the shell interpreter to treat the space as part of the script text.

AppleScript, however, expresses its file paths using the MacOS format. Instead of a forward slash, each path name is separated by a colon <:> character. Also, each path name can contain spaces without the need for any reverse slashes. For example, the file path to the BOM file for Test Sample.pkg is written in MacOS format as follows.

   OS X:Library:Receipts:Test Sample.pkg:Contents:Archive.bom

Converting between file path formats can be quite tedious. To address this issue, the Standards Additions plug-in provides the POSIX file class. To convert the MacOS file path to Sample.pkg to the POSIX format, type the following statement in the Script Editor window.

   POSIX path of alias "OS X:Library:Receipts:Sample.pkg"

This will return the converted path as /Library/Receipts/Sample.pkg. To convert it back to a MacOS format, type the following on the editor window.

   POSIX file "/Library/Receipts/Sample.pkg"

Both examples have file paths set relative to the boot volume. Both also assume that the MacOS name of the boot volume is OS X. Now if a file path is set relative to a volume other than boot, the conversion will reflect that volume. For example, if the MacOS file path is set to Users:Applications:Public:, it will be /Volumes/Users/Applications/Public/ in POSIX format.

Authenticating a command

Some shell commands require authentication in order to perform their tasks. They are usually invoked in the Terminal window using the sudo command. For example, to create the subdirectory foo in /usr, type the following line at the Terminal prompt.

   sudo mkdir /usr/foo

The sudo command first prompts the user for an administrative password. When the correct password is entered, sudo then executes the mkdir command. Otherwise, it aborts after the user fails to enter the right password thrice in a row.

Using the sudo command through the do shell script function is both tedious and unnecessary. Instead, the function can authenticate the desired command by itself. For example, to create the same subdirectory shown above, type the following line on the Script Editor window.

   do shell script "mkdir /usr/foo" with administrator privileges

The function first prompts the user for a password using the dialog shown in Figure 2. Again, when the user enters the correct username and password, the function then executes the mkdir command. Otherwise, it aborts with an error message after the user fails to enter the right information three times in a row. The same also happens if the user clicks on the Cancel button.


Figure 2. The authentication dialog.

To use either approach, make sure that you have a user account with administrative privileges. To learn how to create such an account, consult one of the references listed at the end of this article.

Building with AppleScript Studio

There are many ways to build an uninstaller. One way is to build it as a shell script. One example is Xcode, which comes with a Perl script to uninstall its various components. This approach is easy to implement and test. It does, however, require the use of the Terminal window. It also provides very poor user interaction and feedback, if any.

Another way is to build the uninstaller as a Cocoa application. Cocoa gives the uninstaller a better way of interacting with the user. It also allows the uninstaller to perform tasks not possible with a shell command. But this approach requires too much resources and time to implement. It also has a very high learning curve.

A more practical way is to build the uninstaller as an AppleScript application. This is now easy to do with AppleScript Studio. The uninstaller gets a decent interface with which to interact with the user. It will be easy to build and test due to AppleScript's user-friendly syntax. This is the approach used for the Xcode project Uninstall.

Laying out the user interface

The Uninstall project has a single main window named Uninstall Demo. The window is subdivided into two panels by an NSTabView control. Both panels contain a single NSTableView control. The first table displays the contents of the Receipts directory (Figure 3). The second table displays the contents of the BOM file for the selected receipt (Figure 4).


Figure 3. The Uninstall window, Receipts panel.


Figure 4. The Uninstall window, Files panel.

The entire window layout is that of a basic Assistant. On the lower right corner are two pushbuttons, Prev and Next. The Next button is also set as the default button.

Both buttons are disabled by default. The Next button is enabled when the Receipts table has a selected entry. The Prev button is enabled when the current panel is the one with the Files table. Also, when the Files table has a selected entry, the Next button becomes the Uninstall button.

On the lower left corner of the window is the Cancel button. This button is set to respond to the <Esc> key. It also sends a performClose: message to the window when clicked.

Binding the widgets

The window and some of the controls are then bound to specific AppleScript handlers. The bindings are set in the AppleScript panel of the Show Inspector dialog (Figure 5). To display the dialog, choose Show Inspector from the Tools menu. Then select AppleScript from the drop-down list at the top of the dialog.


Figure 5. The Show Inspector dialog, AppleScript panel.

Table 1 is a list of the bindings set for each interface widget. The handlers shown in this table are all defined in the source file Uninstall.applescript. Notice that some widgets are bound to the same handlers. To identify which widget called the handler, check its name property. For instance, the following code fragment shows how to determine which button was clicked.

on clicked theObject
   local tBtn
   
   set tBtn to the (name of theObject) as string
   if (tBtn is equal to "prev") then
      -- the Previous button has been clicked
   else if (tBtn is equal to "next") then
      -- the Next button has been clicked
   end if -- (tBtn is equal to "prev")
end clicked -- theObject

Widget Name Class AppleScript Settings
Name Event Handler
Uninstall Demo NSWindow demo Nib awake from nib
Prev NSButton prev Action clicked
Next NSButton image/next Action clicked
Receipts NSTableView rcpt Nib awake from nib
Data View selection changed
Lists NSTableView list Nib awake from nib
Data View selection changed

Table 1. AppleScript settings for the Uninstall UI widgets.

Not shown in the table are the bindings for the application itself. To bind the application, select the File's Owner icon on the MainMenu.nib window. Then, from the Show Inspector dialog, click on the Application checkbox. Then set the bindings as shown in Figure 6.


Figure 6. Binding the AppleScript application.

Binding the Cancel button

On the other hand, the Cancel button is not bound to any AppleScript handler. Instead, it is bound directly to an action handler.

To set the binding, control-drag a line from the button to the main window. This will display the Show Inspector dialog with the Connections panel view active. Click on the Target/Action tab on the dialog. Then choose performClose: from the list of window actions (Figure 7).


Figure 7. Selecting the performClose: action.

The Quit Uninstall menu item is also bound in the same way. But this will be left as an exercise to the readers.

Building with Xcode

The Xcode project Uninstall contains three AppleScript source files. The Uninstall.applescript file has all the handlers called by the UI widgets. The Receipts.applescript file has the code to access the Receipts directory. Finally, the Files.applescript file has the code for processing the BOM file. It also has the code that will do the uninstall task.

For reasons of length, this article will only show code that is relevant and interesting. Readers can always view the entire source files by downloading the project from the MacTech website.

Accessing the Receipts directory

Shown in Listing 2 is the function handler that retrieves the contents of the Receipts directory. It takes a path to the directory as its input argument. It returns the results of the retrieval as a list of records.

First, the handler calls the list folder function to read the directory contents. The function responds by returning the contents as a list of filenames. Next, the handler parses each filename in the list. If the name belongs to a receipt bundle, the handler retrieves its bundle signature. Otherwise, the handler proceeds to the next name.

The handler uses the bundle signature to create a record together with the name. When done, it appends the record to the return list tPkg.

Listing 2. Retrieving a list of receipt bundles (Receipts.applescript).

property pRcptRec : {bnom:"", bsig:""}
to getBundles from aPath
   local tLst, tPkgs
   local tItem, tNom
   local isPkg
   
   -- read the contents of the directory
   set tLst to (list folder aPath)
   
   -- parse the list results
   set tPkgs to {}
   copy pRcptRec to tRec
   
   repeat with tNom in tLst
      -- prepare a path to a list item
      set tItem to aPath & ":" & tNom
      get info for file tItem
      
      -- is the item a bundle?
      set isPkg to package folder of result
      
      if (isPkg) then
         -- retrieve the bundle signature
         set tSig to (getBundleSignature for tItem)
         
         -- update the record template
         set bnom of tRec to tNom
         set bsig of tRec to tSig
         
         -- add the updated record to the list
         copy tRec to the end of tPkgs
      end if -- (isPkg)
   end repeat -- with tNom in tLst
   
   -- return the retrieval results
   return (tPkgs)
end getBundles -- from aPath

Reading the BOM file

Listing 3 shows the function handler used to convert the BOM file. It also shows how to use the do shell script function to call the lsbom tool. The handler takes a path to the receipt bundle as its input argument. If successful, it returns the file path to a temp file; otherwise, it returns an empty string.

First, the handler gets a path to the TemporaryItems directory. It converts the path to a POSIX formant, and appends the name of the temp file bom.out. This file will store the output results of the lsbom tool.

The handler then prepares the script to be executed with the do shell script function. The script consists of the file path to the BOM file, as well as the path to bom.out. For example, if the target receipt is Sample.pkg, the script will read as follows.

   lsbom --p fs /Library/Receipts/Sample.pkg/Contents/Archive.bom ¬ 
               > ~/Library/TemporaryFiles/bom.out

Note that, in actual practice, the entire script will consists only of a single line. It will also state the full path to the bom.out file on the user home directory.

Notice as well that a --p fs option is passed to the lsbom tool. This option tells the tool to display only the file paths and sizes of each BOM item. If the item happens to be a directory, its entry in the bom.out file will not have any size data.

Listing 3. Generating a BOM file for a given receipt (Files.applescript).

property pBOMPath : "/Contents/Archive.bom"
property pBOMTemp : "bom.out"
property pCmd : "lsbom "
property pOpts : "-p fs "
to getBOM for aRcpt
   local tTmp, tCmd
   
   -- retrieve a path to a temp directory
   set tTmp to path to temporary items from user domain
   set tTmp to POSIX path of tTmp
   
   -- prepare the output file path
   set tTmp to tTmp & "/" & pBOMTemp
   
   -- prepare the shell command
   set tCmd to pCmd & pOpts
   set tCmd to tCmd & aRcpt & pBOMPath
   set tCmd to tCmd & " > " & tTmp
   
   -- execute the shell command
   do shell script tCmd
   
   -- was it successful?
   try
      set tTmp to (POSIX file tTmp) as string
      alias tTmp
      return (tTmp)
   on error tErr number tTyp
      display dialog ("[FATAL]" & tErr as string)
      return ("")
   end try
end getBOM -- for aRcpt

Listing 4 shows the function handler used to parse the contents of the bom.out file. It takes the path to that file as its input argument. When done, it returns a list of records, each record representing a BOM entry.

The handler first opens a read-only access to the bom.out file. It reads all the entries in the file, and then closes the access.

The entries consist of a list of strings. Each entry alternates between the file path and size of a BOM item. The handler creates a BOM record for each entry. It then appends the record to the list variable tBOM, which is returned to the calling handler.

Listing 4. Reading the BOM file (Files.applescript).

property pBOMRec : {fnom:"", fsiz:""}
property pLF : 10
property pHT : 9
to loadBOMItems from theFile
   local tSrc, tSiz, tPos, tLen
   local tLst, tBOM, tDat, tRec, tNom
   local tTkn, tOdd
   
   -- initialize the following locals
   set tBOM to {}
   set tTkn to {}
   set tTkn to tTkn & (ASCII character pLF)
   set tTkn to tTkn & (ASCII character pHT)
   
   try
      -- start a read-only access to the file
      open for access theFile without write permission
      set tSrc to result
      if (tSrc > 0) then
         -- read the contents of the file
         read tSrc using delimiter tTkn
         set tLst to result
         
         -- close the read-only access to the file
         close access tSrc
      end if -- (tSrc > 0)
      
      -- parse the BOM entries
      copy pBOMRec to tRec
      set tLen to the length of tLst
      
      if (tLen > 0) then
         repeat with tPos from 1 to tLen by 2
            -- retrieve the following BOM items
            set tNom to item tPos of tLst
            set tSiz to item (tPos + 1) of tLst
            if (tSiz is equal to "") then
               set tSiz to "-1"
            end if -- (tSiz is equal to "")
            
            -- prepare the BOM record
            set fnom of tRec to (tNom as string)
            set fsiz of tRec to (tSiz as string)
            
            -- append the record to the return list
            copy tRec to the end of tBOM
         end repeat -- with tPos from 1 to tLen by 2
         
         -- remove the first two items
         set tLen to length of tBOM
         set tBOM to items 3 thru tLen of tBOM
end if -- (tSiz > 0)
   on error tErr
      -- something wrong has happened
      display dialog ("[FATAL] loadBOMItems:" & tErr as string)
   end try
   
   -- return a list of BOM entries
   return (tBOM)
end loadBOMItems -- theFile

Removing a BOM item

There are a many ways to remove a software product. The direct way is to locate the topmost directory from the BOM, and delete it together with its contents. Another way is to select specific items from the BOM for deletion. Choosing the right approach depends on the aim of the uninstaller. The Uninstall project, for instance, uses a variant of the second approach.

Shown in Listing 5 is the function handler that will remove a BOM item. It is called after the user selected an item from the Files listbox, and clicked on the Uninstall button.

The handler first creates an Uninstall folder in the TemporaryItems directory. Next, it moves the BOM item from its original path to the folder. It also deletes the item at the specified path. Once the handler completes its task, it returns a true to the calling handler. Otherwise, it returns a false if any errors occurred.

Listing 5. Removing a BOM item (Files.applescript).

   property pDirTrash : "Uninstall"
   to removeTheItem given path:aTgt, folder:aDir
      local tTmp, tBin, tCmd
      
      -- initialize the following locals
      set tTmp to path to temporary items from user domain as string
      set tBin to tTmp & pDirTrash
      
      -- create the temporary uninstall directory
      tell application "Finder"
         try
            if not (exists alias tBin) then
               make new folder at folder tTmp ¬
                  with properties {name:"Uninstall"}
            end if -- (exists alias tBin)
         on error tErr
            display dialog ¬
               "[FATAL] Failed to create the Uninstall directory"
            return false
         end try
      end tell -- application "Finder"
      
      -- attempt to remove the item
      tell application "Finder"
         try
            -- is the item a directory or a file?
            if (aDir) then -- it is a directory
               -- test delete the directory
               move folder aTgt to folder tBin with replacing
               delete folder aTgt
            else -- it is a file
               -- test delete the file
               move file aTgt to folder tBin with replacing
               delete file aTgt
            end if -- (aDir)
         on error tErr
            display dialog "[ERROR] " & tErr
            return false
         end try
      end tell -- application "Finder"
      
      -- the removal was successful
      return (true)
   end removeTheItem -- given path:aTgt, type:aTyp

Notice that the handler uses the Finder to delete the BOM item. While this works in most cases, it will fail if the item is inside a restricted directory such as /usr. For that case, replace the delete code with the following script statements.

   set aTgt to the POSIX path of alias aTgt
   set tCmd to "rm -Rf " & aTgt
   do shell script tCmd with administrator privileges

The above statements will prompt the user to validate the deletion that is about to occur.

Also, notice that the handler first makes a copy of the BOM item it is about to delete. This gives the user a chance to restore the deleted item back to its former location.

Final Thoughts

Product removal is just as important as product installation. Though most products are easy to remove manually, some require the use of an uninstaller tool. The tool will peruse the receipt package for the product, and delete all the files that belong to that product. This will help ensure that future products installations will be more successful.

AppleScript Studio makes it quite easy to build an uninstaller tool. It has a much lower learning curve compared to Cocoa. This alone makes for a faster build and deployment cycle. It allows the addition of a user-friendly interface, which is not possible through shell scripts.

Hopefully, this article helps to get you started in writing your own uninstaller. Until Apple adds an uninstall option to the Installer tool, writing your own is, for now, the next best solution.

Bibliography and References

Apple Computers. AppleScript Resources. Retrieved 2007 Feb 24. Online: http://www.apple.com/applescript/resources.

Apple Computers. "do shell script in AppleScript". Technical Note TN2065. Copyright 2003, 2005, 2006. Apple Computers, Inc.

Apple Computers. "Administrative Accounts". An Introduction to MacOS X Security for Web Developers. Copyright 2007. Apple Computers, Inc. 2004 Aug 25. Online: http://developer.apple.com/internet/security/securityintro.html

Apple Computers. "lsbom -- list contents of a bom file". Mac OS X Man Pages. Copyright 2003. Apple Computers, Inc. 2003 Apr 16. Online: http://developer.apple.com/documentation/Darwin/Reference/Manpages/man8/lsbom.8.html.


JC is a freelance engineering consultant and writer currently residing in North Vancouver, British Columbia. He divides his time between writing technical articles, and teaching origami at his local district's public library. He can be reached at anarakisware@cashette.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Ableton Live 9.7.5 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
Maintenance 2.3.5 - System maintenance u...
Maintenance is a system maintenance and cleaning utility. It allows you to run miscellaneous tasks of system maintenance: Check the status of the hard disk Repair permissions Run periodic scripts... Read more
OnyX 3.3.8 - Maintenance and optimizatio...
OnyX is a multifunction utility that you can use to verify the startup disk and the structure of its system files, to run miscellaneous maintenance and cleaning tasks, to configure parameters in the... Read more
Merlin Project 4.3.1 - $289.00
Merlin Project is the leading professional project management software for OS X. If you plan complex projects on your Mac, you won’t get far with a simple list of tasks. Good planning raises... Read more
WhatsApp 0.2.6426 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
DiskCatalogMaker 7.2.5 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
BBEdit 12.0.1 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
Hazel 4.2.2 - Create rules for organizin...
Hazel is your personal housekeeper, organizing and cleaning folders based on rules you define. Hazel can also manage your trash and uninstall your applications. Organize your files using a familiar... Read more
Hopper Disassembler 4.3.3- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
Adobe InCopy CC 2018 13.0.0.123 - Create...
InCopy CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous InCopy customer). Adobe InCopy CC 2018, ideal for large team projects... Read more

Guns Royale guide - beginner tips and tr...
If you've been itching to find a mobile battle royale game like Player Unknown's Battlegrounds, you're finally in luck. Guns Royale is a new survival shooter that takes all of the things you love about good ol' PUBG and puts it in a tidy mobile... | Read more »
What we know about Animal Crossing on mo...
At last, we'll be receiving some news about the mobile version of Animal Crossing in a special Nintendo Director at11 PM on October 24. There's been little word on the game since it was first announced, having been met with a series of delays.... | Read more »
Darts of Fury guide - how to rise in the...
Darts of Fury is a new, immensely absorbing darts game from indie studio Yakuto. It's darts in its purest form, but collectible darts and other upgrades give this game an addictive edge that's hard to shake. As your progress out of the beginner... | Read more »
ICEY (Games)
ICEY 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ICEY is a 2D side-scrolling action game. As you follow the narrator's omnipresent voice, you will see through ICEY's eyes and learn the... | Read more »
The best new games we played this week -...
We've made it, folks. Another weekend is upon us. It's time to sit back and relax with the best new releases of the week. Puzzles, strategy RPGs, and arcade games abound this week. There's a lot of quality stuff to unpack this week, so let's hop... | Read more »
Wheels of Aurelia (Games)
Wheels of Aurelia 1.0.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.1 (iTunes) Description: | Read more »
Halcyon 6: Starbase Commander guide - ti...
Halcyon 6 is a well-loved indie RPG with stellar tactical combat and some pretty good writing, too. It's now landed on the App Store, so mobile fans, if you're itching for a good intergalactic adventure, here's your game. Being a strategy RPG, the... | Read more »
Game of Thrones: Conquest guide - how to...
Fans of base building games might be excited to know that yet another entry in the genre has materialized - Game of Thrones: Conquest. Yes, you can now join the many kingdoms of the famed book series, or create your own, as you try to conquer... | Read more »
Halcyon 6: Starbase Commander (Games)
Halcyon 6: Starbase Commander 1.4.2.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.4.2.0 (iTunes) Description: An epic space strategy RPG with base building, deep tactical combat, crew management, alien diplomacy,... | Read more »
Legacy of Discord celebrates its 1 year...
It’s been a thrilling first year for fans of Legacy of Discord, the stunning PvP dungeon-crawling ARPG from YOOZOO Games, and now it’s time to celebrate the game’s first anniversary. The developers are amping up the festivities with some exciting... | Read more »

Price Scanner via MacPrices.net

27″ 3.4GHz iMac on sale for $1699, save $100
Amazon has the 27″ 3.4GHz iMac (MNE92LL/A) on sale today for $1699 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model (except for Apple’s $1529... Read more
Clearance 2016 15″ MacBook Pros available for...
B&H Photo has leftover 2016 15″ MacBook Pros available for up to $700 off original MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: – 15″ 2.7GHz Touch Bar MacBook Pro Space... Read more
Save $100 on 13″ MacBook Airs, prices start a...
Adorama has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. Adorama charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off MSRP... Read more
1.4GHz Mac mini available for $399, $100 off...
TigerDirect has the 1.4GHz Mac mini on sale today for $399 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Although currently out of stock,... Read more
21″ 2.3GHz iMac on sale for $999, save $100
MacMall has the 21″ 2.3GHz iMac (MMQA2LL/A) on sale today for $999 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
12″ iPad Pros on sale for $50 off MSRP, no ta...
Adorama has 12″ iPad Pros on sale today for $50 off MSRP. Shipping is free, and Adorama charges sales tax in NY & NJ only: – 12″ 64GB iPad Pro: $749, save $50 – 12″ 256GB iPad Pro: $899, save $50... Read more
9″ iPads on sale for $30 off, starting at $29...
MacMall has 9″ iPads on sale for $30 off including free shipping: – 9″ 32GB iPad: $299 – 9″ 128GB iPad: $399 Read more
Apple restocks full line of refurbished 13″ M...
Apple has restocked a full line of Apple Certified Refurbished 2017 13″ MacBook Pros for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
13″ 3.1GHz/256GB MacBook Pro on sale for $167...
Amazon has the 2017 13″ 3.1GHz/256GB Space Gray MacBook Pro on sale today for $121 off MSRP including free shipping: – 13″ 3.1GHz/256GB Space Gray MacBook Pro (MPXV2LL/A): $1678 $121 off MSRP Keep an... Read more
13″ MacBook Pros on sale for up to $120 off M...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for up to $120 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Project Engineer, *Apple* Education Profess...
Project Engineer, Apple Education Professional Services Job Number: 113143353New York City, New York, United StatesPosted: Oct. 17, 2017Weekly Hours: 40.00 Job Read more
Commerce Software Engineer, *Apple* Media P...
Commerce Software Engineer, Apple Media Products Job Number: 113092072New York City, New York, United StatesPosted: Oct. 19, 2017Weekly Hours: 40.00 Job Summary With Read more
Engineering Manager, *Apple* Retail Enginee...
# Engineering Manager, Apple Retail Engineering Job Number: 58139948 Santa Clara Valley, California, United States Posted: 20-Oct-2017 Weekly Hours: 40.00 **Job Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.