TweetFollow Us on Twitter

Object Flow System
Volume Number:12
Issue Number:2
Column Tag:OpenDoc

Using OpenDoc With

Object Flow System (OFS)

Get up and running with OpenDoc

By Gerry Kenner, University of Utah, and David Kenner, Phone Directories

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

Introduction

OK. You have taken your CD containing OpenDoc, downloaded the necessary documents, and have used PartMaker to create a generic program named HelloPart. You definitely have a warm feeling of competence because this could not have been done without doing everything precisely as the instructions called for (remember that SOM file which you failed to name in version 1 because you overlooked the instruction to do it?). What do you do now? Start reading the documentation? Heaven forbid. At least not until you have a better idea about what OpenDoc is and what it can do.

We propose to teach OpenDoc using the following steps:

1. Define OFS.

2. Explain what OpenDoc is and provide a glossary of major terms.

3. Do an overview of Apple’s SamplePart (C++) project.

4. Outline a tutorial project which will create a module consisting of two parts. When completed, this project will show a menu bar with an item for selecting the name of a PICT file (ImagePart). A SFGetFile dialog boxwill appear (SelectPart) asking for the name. The name will then be placed into persistent storage for access by the ImagePart. The name will be retrieved by the ImagePart and displayed in its window.

OFS

OFS (Object Flow System) is an intuitive method for doing program design. As our CAD tools, we use a flow-charting program (MacFlow™, Mainstay) and a word processing program with outlining capabilities. An introduction to OFS can be found in the December, 1993 issue of MacTech (see Bibliography, below). Three unpublished articles dealing with the subject can be obtained upon request via email. The details of the outlining level of OFS are given in Appendix A at the end of the article.

OpenDoc

OpenDoc is a development platform which takes binary code fragments (objects) and integrates them so they will interact with each other. Basically, there are four types of code fragments involved: user, third-party, libraries and platform-specific (drivers). What is earth-shaking about the OpenDoc concept is that it does not require source-level code. Translated, this means that (1) you can program with whatever language you wish as long as the OpenDoc interface rules are followed; (2) changes can be made in OpenDoc without having to recompile the entire program; and (3) the code is portable and can be distributed in binary form.

Where to Find OpenDoc

The latest version of OpenDoc can be obtained by sending a message to opendoc@applelink.apple.com. Additional information about OpenDoc is available via the World Wide Web pages at http://www.info.apple.com/opendoc/. The home pages of the Component Integration Laboratories (CI Labs, http:// www.cilabs.org) are a rich source of information about all aspects of OpenDoc. [And, there’s the CD in this issue!]

OpenDoc and SOM

Figure 1 shows an oversimplified view of the relationship between OpenDoc and the other components of the Macintosh system. The figure was derived empirically and is probably not completely accurate, but it is useful as a working model. Note that “SOM stubs” refers to the SOM interface.

Figure 1. OpenDoc, SOM and user-created parts.

Glossary

Here are some terms you will need to know to understand the material which follows.

OpenDoc - A development platform designed to seamlessly coordinate binary code fragments into larger entities corresponding to present day applications. Although OpenDoc is serviceable as a name, a functional name such as Object Manager or Object Integrator would have been better.

Document - Collection of parts or objects. Basic units used by OpenDoc.

Part - Corresponds to the term “object”. Consists of content (definition) and part editor (executable code).

Content - Also “part content”. The portion of a part which describes its data, i.e. the object definition.

Part editor - Executable code of a part or object.

Frame - Total virtual area which can be used to display a part. A facet is displayed in some or all of the frame.

Facet - Total actual area which can be used to display a part. A facet corresponds to a portion of a window or printing canvas where a part is expected to image itself.

Focus - Designation of ownership. A focused window is one which is selected and ready to be drawn in.

Storage unit - An object for storing persistent data, i.e., data which is shared between parts.

Draft - Versions of a document maintained with incremental deltas.

Module - A group of parts.

SamplePart

We will now look at how an OpenDoc part is put together and executed. We will do this by looking at the contents of the SamplePart project, followed by some diagrams which show how the different components of an OpenDoc project interact with each other.

SamplePart Project Window

Figure 2 shows the Symantec project window for the SamplePart part. What are all these files? The System libraries are the PowerPC equivalents of the MacTraps, ANSI, Sane, etc. libraries of the 68k Macintoshes. The OpenDoc libraries and OpenDoc utilities provide code which OpenDoc needs in order to operate. We can safely ignore these at this time. The resource directory contains the resources used by the SamplePart part. These include the About SamplePart dialog box, and some strings and information required for external accessing of the part and its storage. This leaves the Sample Part and SOM interface directories.

Figure 2. Symantec C++ project window for SamplePart.

The code which is of concern to us in this article are som_SamplePart.cpp, located in the SOM Interface directory, and SamplePart.cpp, in the Sample Part directory. Examination of the contents of the som_SamplePart.cpp file shows that it consists mainly of interface or stub calls to the corresponding C++ methods in the SamplePart.cpp file.

Reference to Figure 3 shows how this works. The SOM interfaces are the clearing points for receiving and sending messages to SOM. This is done by programming in the IDL (Interface Definition Language). The programmer can write the entire part in IDL, or alternatively, write interface code which relays the SOM messages to code written in higher level languages, such as C++. Figure 4 shows an example of how this works.

Figure 3. Closer look at SOM relationships.

In this case, SOM sends a message to the SOM interface requesting that the SamplePart part be instantiated. Thus:

Figure 4. Program flow for instantiating SamplePart.

Other files in the SOM interface and the Sample part include SampleCollections.cpp, SamplePartUtils.cpp, SamplePart Init.cpp and som_SamplePartInit.cpp. SampleCollections.cpp and SamplePartUtils.cpp contain functions and classes with methods for doing things such as copying strings and making conversions between global and local coordinate systems. These classes do not interact directly with the SOM interface code. As their names imply, som_SamplePartInit.cpp and SamplePart Init.cpp contain some short initialization sequences.

Startup Code

Let’s take a closer look at what happens when an OpenDoc part is started up. This is illustrated in Figure 5. The first column denotes messages received from SOM. The second column denotes the instantiation of an object of SOM class som_SamplePart and shows execution of some of its methods. Similarly, the right-hand column shows the instantiation of an object of the C++ class SamplePart and the execution of many of its methods. The diagram has been simplified by omitting some messages.

Figure 5. Start-up sequence for SamplePart.

Except where method calls are made from within the SamplePart object (e.g. Initialize is called by InitPartFromStorage), all activity proceeds from left to right. For example, the first message received results in the instantiation of an object of the SOM class som_SamplePart. The second message then calls the somInit method of the som_SamplePart class which instantiates an object of the C++ class SamplePart. Calling of constructor methods is not shown as it is assumed this happens when an object is instantiated.

Everything is pretty straightforward here. The steps for creating and displaying a part are opening it followed by creating a window. Space for displaying the frame is added, after which a facet is created. The part is then fine-tuned and a copy is sent out to memory (Externalize). The program then goes into idle (HandleEvent). The screen is drawn as an update event during idle (Figure 6).

Figure 6. The SamplePart display.

Shutdown Code

Figure 7 shows the operations which occur when the SamplePart part is shut down. Note that the objects of classes som_SamplePart and SamplePart were instantiated at startup and the process is not repeated.

Figure 7. Shutdown operations (simplified for clarity).

In this case, the window (not shown), frame and part are all activated, and the facet is removed. Storage is then released and the destructor method is called.

Tutorial

Our next step is to design and create a module named KSS using OFS. The module will have two parts named ImagePart and SelectPart respectively. This is the first step towards creating a full-fledged image analysis program for measuring surfaces and areas. Hence the name of the ImagePart part, which will eventually become the container for the completed project.

Intuitive logic plus a general perusal of program design books indicates that there are approximately four levels of programming. These are:

• Planning level

• Prototyping level

• Flow diagramming level

• Programming level

Using terminology borrowed from Goldstein and Alger (see Bibliography), we break the planning level into two further divisions, the reference and solution sublevels. See Figure 8; the border shadow denotes the presence of subcharts.

Figure 8. The uppermost level of the OFS system.

Planning Level

Reference sublevel. The template for building the ImagePart and SelectPart parts is the SamplePart part of the Symantec C++, version 8 demo projects.

Solution sublevel. The ImagePart part will be placed in the Apple container part or else run as a standalone part. The frame of the ImagePart part will contain the words “Hello World”. ImagePart will add an additional menu to the menu bar containing a single item, Open Pict. When the menu item Open Pict is selected, the SelectPart part will be instantiated. The SelectPart part will display a SFGetFile dialog box from which the user will select the name of a file. The name of the file will be stored in SelectPart’s persistent storage. Program execution will then return to the ImagePart part which will retrieve the name from SelectPart’s persistent storage after which it will dispose of SelectPart.

The ImagePart part will then display the name of the selected file in its frame.

Prototyping Level

The prototyping level is where the project begins to get some substance. In practice, prototyping is done in many ways. These range from the use of prototyping programs such as Marksman™, AppBuilder™, Visual Architect™ and Rational Rose™ through various CAD-type systems such as the one we use here, to miscellaneous notes and ideas kept on napkins, scraps of paper or the brain of the program designer.

The root chart of the prototyping level is shown in Figure 9. It has separate boxes for the two parts of the module. The menu bar, display and diagram categories of the ImagePart and the diagram category of the SelectPart are shown in Figures 10 to 13.

Figure 9. Root display of the prototyping level.

Figures 10 and 11 provide general ideas of what the menu bar and the screen display will look like. The layout of the menu bar is particularly important because much of the program’s flow is determined by the layout. In a full-scale part, there would also be diagrams showing the layout of various windows and dialog boxes.

Figure 10. Proposed menu bar add-on.

Figure 11. Proposed display.

Figure 12 shows the proposed program flow for the ImagePart when the Select File item of the Image menu is selected. Note the instantiation of the SelectPart part.

Figure 12. Program flow for ImagePart.

When the SelectPart part is instantiated, it is initialized, followed by the sequence of events shown in Figure 13.

Figure 13. Program flow for SelectPart.

Flow Diagramming Level

At this point, it is time to start laying out how the module is to be implemented. This is where we take our existing and third-party code and combine it with a knowledge of what types of programming we know how to do, and lay the program out in detail. When we get done, we should have all our classes and methods identified and how they interact with each other.

Figure 14 shows how ImagePart will be implemented. The main points of interest here are that the MyOpenPict method is called from HandleEvent, and the use of operations A (CreatePart) and B (GetStorageUnit) where SelectPart is instantiated and the file name is retrieved from persistent storage.

Figure 14. Flowchart for ImagePart.

Figure 15 shows that the GetFileName method is called from the InitPartFromStorage method.

Figure 15. Flowchart for SelectPart.

Programming Level

This is where the actual code is written. Ordinarily, this section is empty because the programmer would refer directly to the project files for information. This is particularly the case since the browsers and editors which are provided with the compilers, greatly simplify the task of finding one’s way around the code.

In this case we have made an exception because we are demonstrating how to set up a simple program showing how to use multi-parts as well as accessing persistent storage. As was done above, the presentation is made in two parts, one each for ImagePart and SelectPart.

ImagePart

Build the project using PartMaker or the procedure given in Appendix B. Use ImagePart and KSS as the class and module identifiers, respectively.

First we need to modify the header declarations. Add the following lines to the end of the ImagePart.h file. Put these lines at the end of the methods declaration:

    // • User methods •
 void   MyOpenPict(Environment *ev);

Put this line in the private variable declarations:

 Str255 fTextData;

Now we come to displaying a message on the screen. Add the following lines to the end of the Initialize method

 strcpy((char*)fTextData, "Hello World!");
 c2pstr((char*)fTextData);

The screen is redrawn in response to update events during idling. The code for doing this is located in the FrameDrawView method.

In the FrameDrawView method, remove the code after

 frameWidth = (**frameRgn).rgnBBox.right - 
 (**frameRgn).rgnBBox.left;

and replace it with the following:

 ODSLong rfRef;
 {
 CUsingLibraryResources fil;
 PenState penState;
 GetPenState(&penState);
 PenNormal();
 ShowPen();
 
 Rect   rct;
 short  x, y;
 rct = (**frameRgn).rgnBBox;
 ::FrameRoundRect(&rct, 40, 40);
 x = (rct.right - rct.left - 
 ::StringWidth(fTextData)) / 2;
 y = (rct.bottom - rct.top - 12) / 2;
 ::MoveTo(x, y);
 ::DrawString(fTextData);
 SetPenState(&penState);
 }
 frameShape->Release(ev);

Next, we need to implement our menu item. The following changes are necessary in order to be able to choose the Open Pict File item of the Image menu.

Open the ImagePartOtherResources.rsrc file with ResEdit and add the Image menu (resource item 5000) with a single item named Open Pict File (see Figure 10).

Add the following items to the ImagePartDef.h file.

    // The “Picture” menu’s resource and menu ID:
 #define kImagePartMenuID 5000

    // Menu item IDs.
 #define kOpenPictItem    1

    // Menu command numbers.  Must start at 20000
 #define kOpenPictCmd20000

    // SelectPart items
 #define kSelectPartKind
 "Apple:Kind:SelectPart"

    // Storage type
 const  ODPropertyName  kPropSelectPartName = 
 "SelectPart:Property:Name";

kSelectPartKind is an identifier for SelectPart so that it can be found and used.

Add the following items to the end of the Initialize method. Be sure gMenuBar = session -> GetWindowState(ev) -> CopyBaseMenuBar(ev) is called before this code.

 {
 CUsingLibraryResources fil;
 fMenu = ::GetMenu(kImagePartMenuID);
 if (fMenu)
 ::DetachResource((Handle)fMenu);
 }
 if (!fMenu)
 DebugStr("\pGetMenu failed");
 gMenuBar->AddMenuLast(ev, kImagePartMenuID, fMenu, 
 fSelf);
 {
 CUsingLibraryResources fil;
 gMenuBar->RegisterCommand(ev, kOpenPictCmd,
 kImagePartMenuID, kOpenPictItem);
 }

Add to the HandleMenuEvent method:

 case kOpenPictCmd:
 MyOpenPict(ev);
 break; 

Now we add the MyOpenPict method. It will have the following code:

 void ImagePart::MyOpenPict(Environment *ev)
 {
 ODPart *selectFile;
 ODStorageUnit *su;
 ODStorageUnit *pbSU;
 Str255 str;
 unsigned long size;
 
 su = fSelf->GetStorageUnit(ev);
 selectFile = su->GetDraft(ev)->CreatePart(ev, 
 kSelectPartKind, kODNULL); 
 if (selectFile != kODNULL)
 {
 pbSU = selectFile->GetStorageUnit(ev);
 pbSU->Focus(ev, kPropSelectPartName, 
 kODPosSame, kODISOStr, 1, kODPosFirstSib);
 size = pbSU->GetSize(ev);
 StorageUnitGetValue(pbSU, ev, size, str);
 strcpy((char*)fTextData, (char*)str);
 c2pstr((char*)fTextData);
    // Notify program that window is invalid.
 }
 else 
 DebugStr("\pCannot Create Select Part");
 selectFile->Release(ev);
 }

Now we come to the matter of creating and disposing of a part and accessing its persistent data. To create a new part you must first get a reference pointer to your storage unit. The new part is instantiated and initialized by calling the GetDraft method of the storage unit which in turn calls the CreatePart method. These calls return a reference pointer to the part.

An external part’s persistent data is accessed by getting an object reference to it by calling the external part’s GetStorageUnit method. The storage unit’s focus method is then used to pinpoint the desired data. GetSize is used when the size of the data is unknown. Finally, the data is retrieved by calling the OpenDoc GetStorageUnit method.

Create a new project named SelectPart using PartMaker. Use the identifiers SelectPart and KSS. Name the folder SelectPart.

First, the header declaration. Add the following line to SelectPart.h.

 
void GetFileName(Environment *ev);

Now we set up the persistent variable. Add the following three lines to the end of the Initialize method.

 
 ODStorageUnit *storageUnit;
 storageUnit = fSelf->GetStorageUnit(ev);
 storageUnit = AddProperty
 (ev, kPropSelectPartName)->
 AddValue(ev, kODISOStr);

The AddProperty()->AddValue() complex reserves space in the parts storage unit for a kODISOStr of the kPropSelectName type. kPropSelectName is defined arbitrarily by the programmer in the SelectDef.h file as:

 const ODPropertyName kPropSelectName = 
 "Select:Property:Name";

where Select is the part identifier and Property is an Apple term which is defined below. The term Name was selected by the programmer.

It is time for a few more definitions. The term “Property” is defined in the OpenDoc Class Reference as an element of a storage unit. It defines a kind of information, such as a name or a piece of data, and contains one or more values (data streams containing one or more bytes). In the case given above, the term “Property” is used as follows:

 Part identifier:Property:User
  or Apple defined selected name of identifier.

Note how the term kPropSelectName is put together based upon its definition.

It is strongly recommended that the programmer use the above conventions, as they facilitate identifications of tokens and reduce the chances of creating duplicate names.

Another term which it would be helpful to learn at this time is kODISOStr. This is a null-terminated string made up of 7-bit ascii characters. Note that it is a subset of a C string.

Observe that it is crucial that the proper CI Labs ISOString prefix be used for all ISOStrings (such as kSelectPartKind).

This completes the changes to the MyCommonInitPart method. Next, we need to deal with the method GetFileName; add the following line to the ends of the InitPart and InitPartFromStorage methods.

 this->GetFileName(ev);

Add the code for the GetFileName method to the end of the SelectPart.cp file.

 void SelectPart::GetFileName(Environment* ev)
 {
 Point  where;
 SFTypeList typeList;
 SFReplyreply;
 int    vRefNum;
 unsigned long len;
 Str255 str;
 ODStorageUnit storageUnit;
 
 storageUnit = fSelf->GetStorageUnit(ev);
 
 where.h = 40;
 where.v = 40;
 {
 CUsingLibraryResources fil;
 {
 ::SetCursor(&ODQDGlobals.arrow);
 ::SFGetFile(where, 0L, 0L, -1, typeList, 0L, 
 &reply);
 }
 }
 if ((reply.good == true) && (fDirty != kODFalse))
 {
 vRefNum = reply.vRefNum;
 p2cstr(reply.fName);
 strcpy((char*)str, (const char*)reply.fName);
 len = strlen((char*)str);
 storageUnit->Focus(ev, kPropSelectPartName, 
 kODPosSame, kODISOStr, 1, kODPosFirstSib);
 StorageUnitSetValue(storageUnit, ev, len, 
 (ODValue)&str);
 ODSUForceFocus(ev, storageUnit,
 kPropSelectPartName, kODISOStr);
 }
 }

Now for the matter of storing persistent data. There are two steps in storing persistent data. First, space must be allocated. As shown above in the code for the Initialize method, this is done by getting an object reference to the part’s storage unit and then calling its AddProperty method with name and size information.

An example of the second step is shown in the code for GetFileName. First, you get an object reference to the storage unit and focus on it by providing name, type and position information for the variable. Next, the OpenDoc method SetTheValue is called and the value is forced into storage by calling the ODSUForceFocus method.

Where To Go From Here

We had originally intended to show how global parameters could be passed from the ImagePart to the SelectPart. Specifically, we wanted to pass in the information that only the names of PICT files were to appear in the dialog box. Unfortunately, we ran out of time and were unable to do this. This should be a good exercise for the reader.

The reader has no doubt noticed that we put a comment into the MyOpenPict method saying, in effect, “Let OpenDoc know the screen needs to be refreshed.” Implementing this instruction would result in an immediate screen refresh. As it stands, you must do something like put a Microsoft Word screen on top of the window and then switch back to OpenDoc to get the screen refreshed.

The next logical thing to do with ImagePart is to make it a container for other parts.

Finally, figure out how to deallocate the persistent memory used to store the file name.

Further Reading

The serious acolyte will want to read the following articles.

Alfke, J.P., “Learning to Love SOM,” MacTech Magazine, 11:1 (1995) 12-17.

Alfke, J.P., and J. Mattson, “Opening Up OpenDoc,” MacTech Magazine, 11:1 (1995) 52-65.

Apple Computer, “OpenDoc Cookbook for the Macintosh,” OpenDoc Developer CD #3 and Apple Developer CDs.

Apple Computer, “OpenDoc Programmer’s Guide for the Mac OS,” OpenDoc Developer CD #3 and Apple Developer CDs.

Campagnoni, F.R., “IBM’s System Object Model,” Dr. Dobb’s Journal (“Special Report”), Winter 1994/1995, 24-29.

Curbow, D., and E. Dystra-Erickson, “The OpenDoc User Experience,” Develop, 22 (1995) 83-93.

Goldstein, N., and J. Alger, Developing Object-Oriented Software for the Macintosh, Addison Wesley, 1992.

Kenner, G., and D. Kenner, Object Flow System (OFS) for Visual C++, unpublished manuscript, 1995. (Request via email).

Kenner, G., and D. Kenner, “Outlining the Art Class Tools Menu,” MacTech Magazine, 9:12 (1993) 56-63.

Lloyd, J., “The OpenDoc Development Framework,” MacTech Magazine, 11:11 (1995) 35-57.

Piersol, K., “Building an OpenDoc Part Handler,” Develop, 19 (1994) 6-16. Though outdated, this is still the best introductory article on the subject.

Piersol, K., “Getting Started with OpenDoc Graphics,” Develop, 21 (1995) 5-22.

Rush, J., “OpenDoc,” Dr. Dobb’s Journal (“Special Report”), Winter 1994/1995, 30-35.

Appendix A:
OFS Programming at the Flow Diagram Level

An example of the topmost chart of the flow diagram level is shown in Figure A1. The symbols contain shortened names of subprojects. Other names for subprojects are subjects or program components. Each subproject is linked to a subchart containing names of component subprojects or a flow diagram showing program execution flow. The flow diagram is the lowest level.

Figure A1. Example of the topmost chart of flow diagram level.

There are two types of flow-charting, object flow and method flow. Figure A2 shows the bare notation of object flow diagramming.

Figure A2. Object level notation: objects and methods.

The object flow level is based on the use of a hexagonal symbol containing the name of the class of which the object is an instance, and the name of the object reference, if used. If the symbol has a plain border then the object was instantiated somewhere on the page which contains the symbol. If the symbol has a heavy border, then the object was instantiated elsewhere and is being used on the present page. The bottom part of Figure A2 shows how a method call is symbolized. Note that there are no directional arrows. These were deleted to simplify diagramming.

Figure A3 shows how to execute some common operations at the object flow level. Several examples of how to do this are given in the main text of the article.

Figure A3. Object level notation: common operations.

Figure A4 shows examples of the numbering system used to keep track of the order in which operations occur. Capitalized roman numerals are not used because they take up too much space. The hierarchy is: capitalized arabic letters, arabic numbers, lowercase arabic letters, lowercase roman numerals. The sequence is repeated if more sublevels are needed.

Figure A4. Object level notation: hierarchy.

In our system, method flow-charting is the lowest level before coding begins (Figure A5). At this level, operations are shown in sequence. The screen is divided into two unequal parts. The left-most quarter holds the execution start points and the emblems containing class names and object references. The right-most three-quarters contains the programming operations. A comments box is usually present at the bottom.

Figure A5. Method level flow-charting example.

Figure A6 shows the symbolization used in method flow-charting. Most of these are self explanatory.

Figure A6. Symbols used by OFS for method level flow-charting.

Appendix B: Converting the SamplePart Template

This is how to create a project folder named ImagePart. It requires about thirty minutes to do a conversion. Make copies of the SamplePart and Build Support folders onto your hard drive. The Build Support folder does not need any changes. Using a good editor such as BBEdit™ or BBEditLite™ (BareBones Software), find and replace all instances of the following words in the files of the SamplePart folder.

SampleCode Change to your company identifier.
In our case, this is KSS.

SamplePart Change to the new class name. In
this case, ImagePart. Image or
any other name will also work as
long as it is distinctive.

SampleCollections Change to ImageCollections.
Case is not important.

Close the editor and go to the SamplePart folder. Change all instances of the word Sample to Image in the names of the folders and files. For instance, change the name of the main folder from SamplePart (C++) to ImagePart (C++).

Open the resource file ImagePartOtherResources.rsrc and remove the 'vers' resource. It causes a conflict when the project resource is rebuilt.

Using SARez (from Pascal compiler folder) or Rez, recompile the project resource. The source file is ImagePart.r in the source folder and the target file is ImagePart.PPC.rsrc located in the Object:PPC: directory. Use replace to create a new ImagePart.PPC.rsrc file. The pathway to the headers files is OpenDoc:Interfaces:Rez:. Load all the files.

Open the ImagePart project file and replace all instances of sample files with the renamed Image files.

Build the project.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

MYStuff Pro 2.0.25 - Create inventories...
MYStuff Pro is the most flexible way to create detail-rich inventories for your home or small business. Add items to MYStuff by dragging and dropping existing information, uploading new images, or... Read more
Viber 6.2.0 - Send messages and make cal...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device, so... Read more
Data Rescue 4.2.3 - Powerful hard drive...
Use Data Rescue to recover: crashed, corrupted or non-mounting hard drive deleted, damaged, or lost files reformatted or erased hard drive One powerful new feature found in Data Rescue 4 is... Read more
Microsoft Remote Desktop 8.0.34 - Connec...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
Microsoft Remote Desktop 8.0.34 - Connec...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
Data Rescue 4.2.3 - Powerful hard drive...
Use Data Rescue to recover: crashed, corrupted or non-mounting hard drive deleted, damaged, or lost files reformatted or erased hard drive One powerful new feature found in Data Rescue 4 is... Read more
Viber 6.2.0 - Send messages and make cal...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device, so... Read more
Lyn 1.7.2 - Lightweight image browser an...
Lyn is a fast, lightweight image browser and viewer designed for photographers, graphic artists, and Web designers. Featuring an extremely versatile and aesthetically pleasing interface, it delivers... Read more
Lyn 1.7.2 - Lightweight image browser an...
Lyn is a fast, lightweight image browser and viewer designed for photographers, graphic artists, and Web designers. Featuring an extremely versatile and aesthetically pleasing interface, it delivers... Read more
Tunnelblick 3.6.7beta02 - GUI for OpenVP...
Tunnelblick is a free, open source graphic user interface for OpenVPN on OS X. It provides easy control of OpenVPN client and/or server connections. It comes as a ready-to-use application with all... Read more

Naruto Shippuden: Ultimate Ninja Blazing...
I'm not sure if it's possible to say you are an anime fan but also never have seen one episode of Naruto. If it is, then I resemble that remark, and if not, I offer a hearty apology. [Read more] | Read more »
5 mobile games that let you explore spac...
No Man's Sky hasn't exactly turned out to be everything it was promised. Though its core concept of exploring an unimaginably vast universe of different planets is an intriguing one, the execution has left many PS4 and PC gamers feeling like they... | Read more »
Mummy madness in new action game Tomb He...
Hot on the tail of Bump Hero, ZPlay is giving gamers another reason to get screen bashing with a brand new release. Tomb Heroes is a challenging action game in which you battle enemies in various tombs around the world. You can select from nine... | Read more »
Siralim 2 (RPG / Roguelike) (Games)
Siralim 2 (RPG / Roguelike) 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Siralim 2 is an old-school monster catching RPG. Summon and customize hundreds of creatures to fight for you as... | Read more »
Clean Text (Productivity)
Clean Text 1.0 Device: iOS Universal Category: Productivity Price: $3.99, Version: 1.0 (iTunes) Description: | Read more »
Gemini - A Journey of Two Stars (Games)
Gemini - A Journey of Two Stars 1.0.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.1 (iTunes) Description: *** SPECIAL LAUNCH SALE: $2.99 (25% off) *** "A mesmerizing and unexpectedly emotional journey." -- Los... | Read more »
How to get four NFL superstars for your...
Even though you're probably well on your way to building a top notch squad for the new season in Madden NFL Mobile, let's say you could beef it up by adding Rob Gronkowski, Antonio Brown, Von Miller, and Todd Gurley to your roster. That's... | Read more »
Cartoon Network Superstar Soccer: Goal!!...
Cartoon Network Superstar Soccer: Goal!!! – Multiplayer Sports Game Starring Your Favorite Characters 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Become a soccer superstar with your... | Read more »
NFL Huddle: What's new in Topps NFL...
Can you smell that? It's the scent of pigskin in the air, which either means that cliches be damned, pigs are flying in your neck of the woods, or the new NFL season is right around the corner. [Read more] | Read more »
FarmVille: Tropic Escape tips, tricks, a...
Maybe farming is passé in mobile games now. Ah, but farming -- and doing a lot of a other things too -- in an island paradise might be a little different. At least you can work on your tan and sip some pina coladas while tending to your crops. [... | Read more »

Price Scanner via MacPrices.net

9-inch 32GB iPad Pros on sale for $70 off MSR...
B&H Photo has 9″ 32GB WiFi Apple iPad Pros on sale for $70 off MSRP, each including free shipping. B&H charges sales tax in NY only: - 9″ Space Gray 32GB WiFi iPad Pro: $529 $70 off MSRP - 9... Read more
Mac minis on sale for up to $140 off MSRP
Adorama has Mac minis on sale for up to $100 off MSRP including free shipping plus NY & NJ sales tax only: - 1.4GHz Mac mini: $449 $50 off MSRP - 2.6GHz Mac mini: $649 $50 off MSRP Amazon has the... Read more
Back To School with OtterBox Essentials
Back to school means back to an environment that is tough on tech. OtterBox has the back to school essentials you need to keep tech safe from drops, bumps, scratches and hallway havoc. Check out the... Read more
VRS Design Releases New iPhone 7 Plus Case Li...
With a device as large and costly as the iPhone 7 Plus, it is primal instinct to protect it from potential damage. According to a study by SquareTrade in 2012, iPhone damages cost Americans roughly $... Read more
MacBook Airs on sale for up to $101 off MSRP
Amazon has 11″ and 13″ MacBook Airs on sale for up to $101 off MSRP for a limited time. Shipping is free: - 11″ 1.6GHz/128GB MacBook Air (model MJVM2LL/A): $798 $101 off MSRP - 11″ 1.6GHz/256GB... Read more
Apple certified refurbished iPad mini 4s avai...
Apple has certified refurbished iPad mini 4s now available for up to $120 off the cost of new models. An Apple one-year warranty is included with each iPad, and shipping is free. The following models... Read more
Apple price trackers, updated continuously
Scan our Apple Price Trackers for the latest information on sales, bundles, and availability on systems from Apple’s authorized internet/catalog resellers. We update the trackers continuously: - 15″... Read more
Global Tablet Shipments Projected to Increase...
Digitimes’ Jim Hsiao reports that global tablet shipments will increase by 16.3 percent sequentially to reach nearly 47 million units in 2016′s third quarter, but that volume will still be down over... Read more
Apple’s 2016 Back to School promotion: Free B...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free, and... Read more
Apple refurbished iPad Air 2s available start...
Apple has Certified Refurbished iPad Air 2 available starting at $339. Apple’s one-year warranty is included with each model, and shipping is free: - 128GB Wi-Fi iPad Air 2: $499 - 64GB Wi-Fi iPad... Read more

Jobs Board

*Apple* /Mac Support Engineer - GFI Digital,...
FI Digital, Inc. is currently seeking candidates for a full time Apple Support Engineer to add to our Maryland Heights, Missouri IT team. Candidates must be dynamic Read more
*Apple* Solutions Consultant - Apple (United...
Apple Solutions ConsultantJob Number: 51218534Pleasant Hill, California, United StatesPosted: Aug. 18, 2016Weekly Hours: 40.00Job SummaryAs an Apple Solutions Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 51443201 Mishawaka, Indiana, United States Posted: Aug. 25, 2016 Weekly Hours: 40.00 **Job Summary** As an Apple Read more
*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 51218354 Fredericksburg, Virginia, United States Posted: Aug. 18, 2016 Weekly Hours: 40.00 **Job Summary** As an Apple Read more
*Apple* Retail - Multiple Positions Birmingh...
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.