TweetFollow Us on Twitter

Packaging Special Payloads with PackageMaker

Volume Number: 24
Issue Number: 10
Column Tag: PackageMaker

Packaging Special Payloads with PackageMaker

Bringing drivers, libraries, and plug-ins to the OS X target

by José R.C. Cruz

Introduction

One task that some developers face is to deliver special payloads such as device drivers, frameworks, and codecs to their users. Unlike applications or files, these payloads must reside in specific locations on the target system. They must have the right settings for permissions, UID, and GID. Some payloads require specific hardware to operate. Some require authentication or a specific post-install action.

In this article, we will explore the issues behind delivering these special payloads. First, we will list each payload and look at how to handle each one. Then, we will learn how to check for specific hardware on the target system. Next, we will build a demo package with three payloads, two of which are special. We will then test this package and study its behavior.

As always, the installer project featured here is available from the MacTech website. To get a copy of the project, go to the following URL.:

ftp.mactech.com/src/mactech/volume24_2008/24.10.sit

The Special Payloads

As stated earlier, special payloads need special handling. To correctly install this payload, first know what its needs are and how to address them. Doing so will help avoid any post-install issues such as system hangs, freezes, or even a kernel panic.

The following are three basic groups of special payloads that you will encounter most. Some payloads do not fit into any these groups, but those are few and far between.

Drivers

The job of a driver is to add or extend system functionality. Drivers in OS X are often in the form of a kernel extension. You can place the driver inside an application bundle or in the directory /System/Library/Extensions. If the latter, prepare each driver as follows.

  • First, set the bundle's UID and GID to root and wheel. Make sure to use the same UID and GID to the bundle's subdirectories and component files.

  • Next, set its permission flags to rwxr-xr-x. Use the same flags for the bundle's subdirectories and executable items. For the component files, however, use the flags rw-r-r-.

Now some drivers work only if the target system has the correct hardware. Others need the system restarted in order to become active. Lastly, since access to /System/Library/Extensions is restricted, users must authenticate the install session.

Libraries

Libraries carry code and data that provide services to various OS X applications. They can come in several formats, with the most common being the framework bundle.

There are several places wherein to store a framework. Choosing which one to use depends on the framework at hand. For most frameworks, use the directory /Library/Frameworks. This location gives all applications access to the framework code. To limit access only to applications that the user owns, use the directory ~/Library/Frameworks. Both directories are public and as such do not need users to authenticate the install session.

For frameworks that provide system-wide services, use /System/Library/Frameworks. For those meant only for in-house or private use, use the location /System/Library/PrivateFrameworks. Both locations, however, will require users to authenticate the install session. Also, Apple reserves the right to modify either location during every OS X upgrade. Make sure to provide a way to backup any custom frameworks in these locations.

Frameworks that go into the /Library or ~/Library locations can use the user's login name and admin as their UID and GID. Those that go into the /System/Library locations must use root and wheel. As for permission flags, use rwxr-xr-x for the framework, its subdirectories, and its binary files. For any text files inside the framework, set their permission flags to rw-r-r-.

Other libraries use a proprietary file format. They also have their own locations on the target volume. For instance, Python packages use either /Library/Python or ~/Library/Python as their locations. Perl modules, on the other hand, go into either /Library/Ruby or ~/Library/Ruby. And POSIX libraries use the "invisible" directory /usr/lib. The UID and GID for these libraries are root and wheel. Their permissions flags are always set to rwxr-x-r-x.

Plug-ins

Plug-ins add custom features or functions to a software client, which can be either an application or a system service. The client loads a plug-in on demand and after its host system has booted up.

Most plug-ins go in specific directories inside either /Library or ~/Library. Each plug-in directory is named after the plug-in service or after the plug-in's client. For instance, osax plug-ins, used by the AppleScript runtime, go into the directory ScriptingAdditions. QuickTime codecs use the similarly named QuickTime directory. Preferences panels are stored in the PreferencesPanes directory. And Dashboard widgets go in the Widgets directory. Consult your project guidelines for the correct directory for your plug-ins.

Also, most plug-ins use the user's login name as their UID, and admin as their GID. As for permission flags, these vary with the type of plug-in. For example, osax plug-ins use rwxrwxrwx for their bundle directories and files. QuickTime codecs use rwxr-xr-x for its subdirectories and binary files, but rw-r-r- for its support files. Again, check your project guidelines for the correct settings.

Checking For Hardware

As stated earlier, some special payloads need the right hardware present on the target platform. So, if you let the package to check the target's hardware, you can reduce the number of unwanted files stored on the target. Fewer unwanted files means more space to store user data. It also means a leaner and more responsive system.

You can perform the hardware check in a number of ways. One way is to use one of the preset conditions in the Requirements Editor. Another way is to use a script to do a sysctl query. A more elegant way is to query the IORegistry with JavaScript.

Using preset conditions

Figure 1 shows the two sets of conditions that you can use for a hardware check. When creating a package with PackageMaker, choose the Requirements tab to specify requirements that this package must meet. The first set (shaded in green) focuses entirely on the host's hardware traits. To use one of the conditions, first select them from the If pop-up menu. Then choose the Boolean operator from the is menu. Next, enter the desired value to the field provided. Or if the condition provides a menu of Boolean flags, choose the right flag from that menu.


Figure 1. The preset conditions for hardware checks

For example, Figure 2 shows two hardware checks using the preset conditions. The one on the left checks to see if there are at least two CPUs present. And the one on the right checks if the hardware supports 64-bit instructions.


Figure 2. Two sample hardware checks

The second set of conditions (shaded in blue) focuses on devices attached to the host platform. Each condition looks for the device by examining one of three hardware buses: FireWire, USB, and PCI. If the device is present on the bus, the condition returns a TRUE; otherwise, it returns a FALSE.

To illustrate, assume your payload uses the FlashGO! USB card reader from Imation Corp. To look for this device, setup the hardware check as shown in Figure 3. If the device is absent, the check can either disable the payload or display an error dialog. Note the name used in the device field. This is the name under which the device appears in the IORegistry. It is not always the same as the product name.


Figure 3. Checking for a USB device

Using system.sysctl()

You can also use the Requirements Editor to run a sysctl query. To do so, choose Results of Sysctl as the check condition. Enter the sysctl node and value in the fields provided, and then choose the Boolean operator from the is pop-up menu. For example, assume your payload works only if the host has a bus frequency of at least 100 MHz. For this check, setup the editor dialog as shown in Figure 4. Here, the sysctl node hw.busfrequency goes in the field labeled value. Then the sysctl value of 100000000 goes in the field next to the Boolean pop-up menu.


Figure 4. Checking the system bus frequency

You can also add several sysctl queries using the Requirements Editor. The package, however, treats the check results in an all or nothing manner. If at least one sysctl check fails, then the entire group of checks also fails. For a more complex check logic, use a custom JavaScript function to do the query.

Listing 1 shows one example of such a function. This function first checks if the host platform has more than one CPU. If the check proves false, the function then checks if the CPU can handle 64-bit processes. Now if the CPU can handle 64-bit tasks, the function returns a TRUE when the CPU speed is greater than 100 MHz. But if the CPU handles only 32-bit tasks, the function returns TRUE only when the CPU speed is at least 200 MHz.

Listing 1. Checking the hardware with system.sysctl()

function check_sysctl() {
   tCPU = system.sysctl('hw.ncpu');
   if (tCPU == 1) {
      tTyp = system.sysctl('hw.cpu64bit_capable');
      tClk = system.sysctl('hw.cpufrequency');
      if (tTyp = 1)
         return (tClk > 1000000000);
      else
         return (tClk > 2000000000);
   }
   else if (tCPU > 1)
      return true;
   else
      return false;
}

To use the above function, first add the script to the project's Script Repository. Then choose Result of JavaScript as the check condition. Enter the function's name into the function field. Set the Boolean operator and value as shown in Figure 5.


Figure 5. Calling the custom function check_sysctl()

Checking The IORegistry

Sometimes, you want hardware checks that are difficult to do using either a preset condition or a sysctl query. So to do these checks, you will access the IORegistry directly. The IORegistry is a database of services nodes on OS X. Each node can be an active hardware or driver. The IORegistry is also dynamic by design. It updates its list of nodes each time hardware or driver is added or removed. Equally important, the IORegistry shows how the nodes related to each other.

Viewing the IORegistry

To view the IORegistry, use the Xcode utility tool IORegistryExplorer. This tool displays the entire IORegistry as a hierarchical tree on the left panel (Figure 6). Selecting a node on the tree displays that node's properties on the right panel. Nodes that have a triangle widget have child nodes under it. Clicking the widget hides or shows the children for that node.


Figure 6. Main window of the IORegistry tool

The top pane on the window controls how the tool displays the IORegistry. By default, the tool shows all the active nodes on the tree. To view only nodes that belong to a specific category, choose the category from the upper-left pop-up menu (Figure 7). Your choices include IODeviceTree (default), IOFireWire, IOPower, and IOUSB. Also, as stated earlier, the tool uses a hierarchical tree to view the IORegistry. To switch to a columnar view, click the second button near the upper-left corner.


Figure 7. Controls on the IORegistryExplorer tool

The second pop-up menu displays the absolute path of the selected node on the IORegistry. If there is only one instance of the node, this menu displays only one path. But if there are multiple instances of the same node, the menu will show multiple paths. For example, on the iBook/G4 system, selecting the node CHUDProf displays only one path.

   IOService:/IOResources/CHUDProf

But selecting the IONetworkStack node displays four possible paths (Figure 8). Here, a checkmark precedes the path of the selected node. Each instance of IONetworkStack belongs to a different network device. Selecting the path to each instance also selects that node on the IORegistry.


Figure 8. Multiple instances of IONetworkStack

Finally, on the upper-right corner of the pane is the filter field. Use this to show only those nodes that have a certain string. Assume, for example, your target platform has a number of Macally hardware products. To display the nodes for those products, type the string "Macally" into the filter field. The tool then updates its IORegistry display as shown in Figure 9. Note the matching nodes are in bold, whereas their parent nodes are in grey text.


Figure 9. Filtering the IORegistry display

Querying the IORegistry

Use the system.ioregistry() property to query the IORegistry data from the installer package. This property is an instance of the JavaScript object, also named IORegistry (Figure 10). It is available only to the InstallationCheck phase of the install session.


Figure 10. The IORegistry object

The IORegistry object has three sets of functions, all of which return an associative Array as their results. Some functions take the node's name or class as input, but most take the absolute path to the node. You can get this path by using the IORegistryExplorer tool.

The first set of IORegistry functions returns the parents or children of a specific node. For example, assume you want to query the node com_apple_driver_AudioIPCDevice. To get a list of children for this node, use the childrenOf() function. Pass the absolute path to the node as the input string.

   tChild = system.ioregistry("IOService:/IOResources/¬
      com_apple_driver_AudioIPCDevice")

To get a list of parent nodes, use the parentOf() function.

   tParents = system.ioregistry("IOService:/IOResources/¬
      com_apple_driver_AudioIPCDevice")

If the node has neither children nor parents, both functions will return a NULL.

The second set of functions searches for a node in the IORegistry. They serve the same task as the filter field on the IORegistryExplorer tool. Use the function matchingName() to search for a node with a given name. Pass the name string as the function's input. For example, the snippet below searches for all nodes with the string "Macally".

   tMacally = system.ioregistry.matchingName("Macally")

If, however, you want nodes belonging to a specific class, use the matchingClass() function. Again, pass the class name as the input string. To illustrate, the following snippet will search for all FireWire nodes.

   t1394 = system.ioregistry.matchingClass("FireWire")

If either search fails, the functions will return a NULL.

The third set consists one function that retrieves the properties for a given node. This function, fromPath(), takes one argument, which is the absolute path to the node. For example, to read the properties of the node CHUDProf, use the function as follows.

   tCHUD = system.ioregistry.fromPath("IOService:/IOResources/CHUDProf")

Again, if the node is absent, the function returns a NULL.

Now, you can read the Array elements in two ways. One way is to access each element via indices. Assume you want to examine all the child nodes of AppleACPIPlatformExpert. Listing 2 shows how you can do so using a for block. You can also use a do...while or a while block to do the same task.

Listing 2. Reading the children nodes of AppleACPIPlatformExpert

   var tSib = 
      system.ioregistry.childrenOf("IOService:/AppleACPIPlatformExpert");
   if (tSib != null) {
      for (var tIdx = 0; tIdx < tSib.length; tIdx++) {
         var tNod = tSib[tIdx];
         // - process each child node
      }
   }

Another way is to iterate through each Array element using a for...in iterator. This method works best if the Array data is a list of properties. For example, assume you want to examine the properties of CHUDProf. Listing 3 shows how you can do so with the iterator.

Listing 3. Reading the properties of CHUDProf

   var tDev = 
      system.ioregistry.fromPath('IOService:/IOResources/CHUDProf');
   if (tDev != null) {
      for (var tInf in tDev) {
         var tProp = tDev[tInf]
         // - process each node property         
      }
   }

Building The Package

In this section, you will build a basic installer package of special payloads. You will setup the package using the some of the information featured earlier. For a realistic touch, the payloads will be support software for the Macally USB product, the IceCad graphics tablet. These payloads are as follows.

  • a configuration utility named Macally IceCad.app
  • a StartupItem bundle named TabletApp

  • a kernel driver named TabletDrv.kext

Due to copyright restrictions, the installer project will not include the Macally software. But you can get your copy of the software at the following URL:

http://www.macally.com/en/Techsupport/Drivers.asp

Adding payloads

Start by creating a new installer project. On the Install Properties dialog, choose 10.4 as the minimum target platform. You can also try 10.5, though you will find little, if any, change in behavior. For now, the rest of the article assumes a 10.4 target. It also assumes the payloads are inside a directory named macally.

Save the project file as Foobar_Macally. Click the package icon on the payload list to get the Configuration panel for the entire package. Update the panel as shown in Figure 11. Here, the package will display the Custom Install panel to the user. And it will allow users to choose a target volume for the payloads. Save your changes by choosing Save from the File menu.

Now click the + button on the lower-left corner of the payload list. Use the Open File dialog to go to the macally directory and to select the utility Macally IceCad.app. Click the Choose button to add the utility to the list. Then display the Configuration panel for that payload (Figure 12). Notice the payload gets /Applications as its destination. Change this to /Applications/Macally IceCad.app. Leave the rest of the panel at their default settings. Save your changes when done.


Figure 11. Configuring the entire package


Figure 12. Configuring the application payload Macally IceCad.app

Click the + button again, and add the StartupItem bundle TabletApp to the project. Then bring up the Configuration panel for that payload (Figure 13). This time, the payload gets / as its destination. Since this is incorrect, change the path to /Library/StartupItems. Also, a StartupItem bundle must be loaded at boot-time. So, go to the Restart Action pop-up menu and choose Require Restart as the action. Leave the rest of the settings unchanged and save your changes.

Next, use the same steps to add TabletDrv.kext to the project. Then display the Configuration panel for this payload (Figure 14). Since the payload is a kernel extension, it gets /System/Library/Extensions as its destination. As that location has restricted access, make sure to set the checkbox Require admin authentication. But leave the restart action to None. OS X loads this extension only when it finds the Macally graphics table plugged in.


Figure 13. Configuring the StartupItem payload TabletApp


Figure 14. Configuring the driver payload TabletDrv.kext

Making checks

Next, you will add two simple checks to the package. Start by displaying the Requirements panel for the entire package. Then click the + button to get the editor dialog window. Update the dialog as shown in Figure 15. This check scans the USB bus for the Macally IceCad tablet. If the tablet exists, the check allows the install session to continue. Otherwise, it displays the specified error message.

To add the second check, select the choice for the payload TabletApp. Go to its Configuration panel and make sure the checkboxes Selected and Enabled are set. Now go to the Requirements panel for that choice. Click the + button to get the editor dialog. Update the dialog as shown in Figure 16. This checks examines the system version of the target platform. If the system happens to be 10.4 or older, the check leaves the choice's state unchanged. Otherwise, it disables and deselects the choice. The reason for this check is that StartupItem bundles are now deprecated on 10.5, in favor of LaunchAgents and LaunchDaemons. Since the package also supports 10.4 targets, it must know when to correctly disable this choice.


Figure 15. Checking for the graphics tablet


Figure 16. Checking for the target system

Setting up

Now it is time to set the permission flags, UIDs and GIDs of each payload. Start by selecting the payload Macally IceCad from the payload list. Then click the Contents tab to display that payload's Contents panel. Click the triangle widget next to the payload's name. Repeat the same step until you see all the files contained in the bundle (Figure 17). Select all the files and directories by choosing Select All from the Edit menu.


Figure 17. Setting the permissions, UID, and GID for Macally IceCad.

To set the payload's UID, choose root from the Owner pop-up menu. Conversely, let the GID be the default Group value of admin. Next, carefully select only the directories and bundles that make up the payload. Set the checkboxes Read, Write, and Execute for both Owner and Group. For Others, however, set only the checkboxes Read and Write. Use the same settings for the executable file inside Contents/MacOS. For the rest of the files, set the checkboxes Read and Write for both Owner and Group, but only the Read checkbox for Others. Save your changes when you are done.

Next, select TabletApp from the payload list. Use the Contents panel to display all the directories and files in that payload. Then choose Select All from the Edit menu. For the payload's UID, choose root from the Owner pop-up menu; for the GID, choose wheel from the Group menu. Then set the checkboxes Read, Write, and Execute for the Owner. But set only the Read and Execute checkboxes for both Group and Others.

Finally, select the payload TabletDrv.kext from the list. Go to its Contents panel and display all the items belonging to this payload. Select all the items and set their UID and GID to root and wheel. Next, select only the directories and bundles in the payload. Set the checkboxes Read, Write, and Execute for the Owner, but only Read and Execute for the Group and Others. Now select just the files in the payload. Set the checkboxes Read and Write for the Owner, but only Read for Group and Others. Save your changes immediately.

Package testing

You are now read to test your installer package. Start by choosing Build and Run from the Project menu. When prompt for a package name, enter the name Macally_Demo. PackageMaker then builds a distribution package with the three payloads. It sets the correct permissions, UID, and GID for each payload. Once done, it tells the Installer core utility to open the package and start the install session.

At the start of the session, the first panel you see is the Welcome panel (Figure 18). But this panel appears only when the target has the IceCad graphics tablet attached. If the tablet is absent, an error dialog appears on top of the panel (Figure 19). Clicking the Close button then ends the install session.


Figure 18. The Welcome panel

You can disable the InstallationCheck phase if you do not have the right graphics tablet. First, bring up the check for the tablet into the Requirements Editor (see Figure 3). Then change the check results from TRUE to FALSE.


Figure 19. When the IceCad tablet is absent

Let us assume that you do have the graphics tablet. Click the Continue button to switch to the Destination Select panel (Figure 20). Note the panel presents two possible locations for the payload. For this test, select the first location on the list. Click Continue to proceed to the Custom Install panel.

BUG ALERT:

Sometimes, the package will not display the Destination Select panel, proceeding instead to the next panel. This happens even if there are several mounted volumes and the package allows users to choose one of the volumes as the target. This appears to be a bug in version 3.0.1 of the Installer utility. It is unknown if this same bug is present in later versions.


Figure 20. Choosing a destination

On the Custom Install panel (Figure 21), you will see a list of three payload choices. Note the second choice, TabletApp, is disabled and unselected. In this case, the host system happens to be Leopard (10.5). If the host uses Tiger (10.4), the TabletApp choice will be both enabled and selected by default.

Leave the selections as is and click the Install button. First, the package prompts you to authenticate the install session. Then it installs the two selected payloads onto their respective locations. Once it displays the Conclusion panel, choose Quit Installer from the Installer menu. Switch to the Finder and locate the /Applications directory. In there, you will find the utility Macally IceCad.app. Now go to the directory /System/Library/Extensions. Here, you will find the kernel extension TabletDrv.kext. Select each installed payload and choose Get Info from the File menu. Examine the UID, GID, and permission flags for each payload. They should match the ones you have set in the Contents panel for each payload.

Finally, go to the directory /Library/Receipts. Here, you will find two receipt bundles, one for each installed payload. Now if you built package using the new flat-file format, you will not find any receipts for your payloads. Instead, the Installer tool will log the session in its private database named areceipt.db. This makes verifying and undoing an installation more challenging. But that is a topic for another time.


Figure 21. A list of payloads

Concluding Remarks

Special payloads need extra handling when added to an installer package. Otherwise, they may cause problems in the target if they are installed incorrectly. Some payloads need to be in the right location on the target. Some need the right hardware present. Some must have the right permissions set, others the right UID and GID. PackageMaker 3 gives you the means to address these needs. You can set the right permissions, UID, and GID of each payload via the Contents panel. You can use the Requirements Editor to add a simple hardware check or an external script to do complex checks. And you can set the right location and restart action on each payload's Configuration panel.

In the next article, I will explore the concept of an installer plug-in. I will show how to write a simple plug-in and add it to an installer package. Until then, I bid you well.

Bibliography and References

Apple Computers. PackageMaker Users Guide. 2007 Jul 23. Copyright 2007. Apple Computers, Inc. Online:

http://developer.apple.com/DOCUMENTATION/DeveloperTools/Conceptual/PackageMakerUserGuide

Apple Computers. Software Delivery Guide. 2006 Jul 24. Copyright 2007. Apple Computers, Inc. Online:

http://developer.apple.com/documentation/DeveloperTools/Conceptual/SoftwareDistribution

Apple Computers. "IORegistry Class Reference". Installer JavaScript Reference. 2007 Jul 23. Copyright 2007. Apple Computers, Inc. Online:

http://developer.apple.com/documentation/DeveloperTools/Reference/InstallerJavaScriptRef/ioregistry/ioregistry.html

Apple Computers. "The I/O Registry Explorer". I/O Kit Fundamentals. 2007 May 17. Copyright 2001-2007. Apple Computers, Inc. Online:

http://developer.apple.com/documentation/DeviceDrivers/Conceptual/IOKitFundamentals/TheRegistry/chapter_4_section_3.html/P>

Apple Computers. "Installing Your Framework". Framework Programming Guide. 2006 Nov 07. Copyright 2007. Apple Computers, Inc. Online:

http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/InstallingFrameworks.html


JC is a freelance engineering writer from North Vancouver, British Columbia. He spends his time writing technical articles; tinkering with Cocoa, REALbasic, and Python; and visiting his foster nephew. He can be reached at anarakisware@gmail.com.

 
AAPL
$442.14
Apple Inc.
+0.79
MSFT
$34.15
Microsoft Corpora
-0.46
GOOG
$882.79
Google Inc.
-6.63

MacTech Search:
Community Search:

Software Updates via MacUpdate

Evernote 5.1.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
SketchUp 13.0.3688 - Create 3D design co...
SketchUp is an easy-to-learn 3D modeling program that enables you to explore the world in 3D. With just a few simple tools, you can create 3D models of houses, sheds, decks, home additions,... Read more
GarageSale 6.6b10 - Create outstanding e...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease With GarageSale, you can create, edit, track, and manage... Read more
Twitter 2.2.1 - Official Twitter client...
Twitter (was Tweetie) is a Twitter client with a variety of features. Important Note: As of January 2011, AteBit's Tweetie application has been acquired and renamed by Twitter. Version 1.2.8 of the... Read more
SteerMouse 4.1.6 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
Google Chrome 27.0.1453.93 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Labels & Addresses 1.6.5 - Powerful...
Labels & Addresses is a home and office tool for printing all sorts of labels, envelopes, inventory labels, and price tags. Merge-printing capability makes the program a great tool for holiday... Read more
Delicious Library 3.0.2 - Import, browse...
Delicious Library allows you to import, browse, and share all your books, movies, music, and video games with Delicious Library. Run your very own library from your home or office using our... Read more
KeyCue 6.5 - Displays all menu shortcut...
KeyCue helps you to use your OS X applications more effectively. Just hold down the Command key for a while - KeyCue comes to help and shows a table of all currently available keyboard shortcuts.... Read more
HoudahSpot 3.7.8 - Advanced front-end fo...
HoudahSpot is a flexible file-search tool based on Apple's powerful Spotlight engine. Keep frequently used files within reach Retrieve the files you didn't know you still had Don't waste time... Read more

Evernote Update Keeps You Notified, Adds...
Evernote Update Keeps You Notified, Adds New Reminders Feature Posted by Andrew Stevens on May 23rd, 2013 [ permalink ] | Read more »
Clear Shakes Up A New Update: Email Your...
Clear Shakes Up A New Update: Email Your Lists Posted by Andrew Stevens on May 23rd, 2013 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
Regular Show: Best Park in the Universe...
Regular Show: Best Park in the Universe Review By Carter Dotson on May 23rd, 2013 Our Rating: :: SLACKERSUniversal App - Designed for iPhone and iPad This park has some good ideas, but a lot of work needs to go into it to make it... | Read more »
Angry Birds Space Launches You Into Spac...
Angry Birds Space Launches You Into Space For Free Posted by Andrew Stevens on May 23rd, 2013 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
Mailbox Shows Some Tablet Love, Gets Opt...
Mailbox Shows Some Tablet Love, Gets Optimized For iPad Posted by Andrew Stevens on May 23rd, 2013 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
Ayopa Games Offers Their Titles For Free...
Ayopa Games Offers Their Titles For Free This Memorial Day Weekend Posted by Andrew Stevens on May 23rd, 2013 [ permalink ] Ayopa Games is celebrating this Mem | Read more »
Greedy Grub Review
Greedy Grub Review By Rob Rich on May 23rd, 2013 Our Rating: :: A CUTE CRAWLUniversal App - Designed for iPhone and iPad Greedy Grub is certainly adorable, but it’s not particularly ground-breaking.   | Read more »
Finger Tied Jr Review
Finger Tied Jr Review By Jennifer Allen on May 23rd, 2013 Our Rating: :: FINGER TWISTING FUNiPhone App - Designed for the iPhone, compatible with the iPad Finger Tied brought Twister-style gaming to the iPad, and Jr does much the... | Read more »
Zynga’s Battlestone – Mobile Hack ‘n’ Sl...
Zynga’s Battlestone – Mobile Hack ‘n’ Slash Arcade Action Posted by Rob LeFebvre on May 23rd, 2013 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Developer Spotlight: Infinite Dreams
With its latest title, Can Knockdown 3, recently earning a coveted Editor’s Choice award here, I took the time to learn a bit more about Polish game developer, Infinite Dreams. Who is Infinite Dreams? Based in the Southern Polish city of Gliwice,... | Read more »

Price Scanner via MacPrices.net

Economic Conservatives Defend Apple’s Tax Strategy
Given Apple’s longtime reputation as the particular darling of the liberal lefty end of the spectrum, it’s been facinating to see mostly prominant conservatives rallying to the defense of Apple’s... Read more
Is Apple Losing Its “Cool” Cachet With The Popular...
SMH’s Steve Colquhoun notes that while Apple has again been rated as the world’s top brand this week, a leading social researcher warns the company and its products are losing touch with Generation Y... Read more
New Rugged Smartphone From…. Caterpillar?!
Bullitt Mobile Ltd., global licensee of Cat phones for Caterpillar Inc., has introduced the new Cat B15 smartphone in North America. The Cat B15 is designed to be the most progressive, durable and... Read more
Mac mini on sale for $25 off, free shipping, NY ta...
B&H Photo has the 2.5GHz Mac mini available for $574.98 including free shipping and NY sales tax only. Their price is $25 off MSRP. B&H will include free copies of Parallels Desktop and Bento... Read more
Updated iPad Price Trackers
We’ve updated our iPad Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers. Read more
Take $20 off with Apple refurbished iPod nanos
The Apple Store has Apple Certified Refurbished 16GB iPod nanos available for $129 including free shipping and Apple’s standard one-year warranty. That’s $20, or 13%, off the cost of new nanos. All... Read more
Apple TV (refurbished) available for $85, 14% off
The Apple Store has Apple Certified Refurbished 2012 Apple TVs available for $85 including free shipping. That’s $14 off the cost of new models. Apple’s one-year warranty is standard. Read more
27″ iMacs on sale for $100 off MSRP
Amazon has 27-inch iMacs on sale for $100 off MSRP: - 27″ 3.2GHz iMac: $1899.99 - 27″ 2.9GHz iMac: $1699.98 Shipping is free Read more
Platform Wars: Tablets Triumphant, But Don’t Write...
The Register’s Paul Kunert says it’s finally official – the epic battle of legendary Apple CEO Steve Jobs is finally won, now that he has toppled the PC platform from beyond the grave, in the UK, at... Read more
Apple Tops 100 Most Valuable Global Brands 2013 Su...
MarketingWeek’s Lou Cooper reports that this years BrandZ ranking of the top 100 valuable global brands sees Apple maintain its reign as number one, ahead of Google and IBM in second and third and... Read more

Jobs Board

*Apple* Retail - Manager - Apple Inc. (...
Job Summary Keeping an Apple Store thriving requires a diverse set of leadership skills, and as a Manager, you’re a master of them all. In the store’s fast-paced, Read more
*Apple* Account Executive - CompuCom (U...
Apple Account Executive Job Location US-IL-Des Plaines Posted Date 3/27/2013 Req # 2013-4905 Apply/Socialize: * Apply Now! * Email this opportunity to a friend or Read more
*Apple* - Solution Architect - CompuCom...
Apple - Solution Architect Job Location US-TX-Dallas Posted Date 4/18/2013 Req # 2013-4932 Apply/Socialize: * Apply Now! * Email this opportunity to a friend or Read more
Mac/ *Apple* Specialist Needed - Enterp...
Mac/ Apple Specialist Needed - Enterprise iPad Deployment A prominent Robert Half client is seeking out a Mac/ Apple Specialist to assist with an iPad deployment Read more
Mac/ *Apple* Specialist Needed | Enterp...
Mac/ Apple Specialist Needed | Enterprise iPad Deployment A prominent Robert Half client is seeking out a Mac/ Apple Specialist to assist with an iPad deployment Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.