TweetFollow Us on Twitter

CGIs in 4D
Volume Number:12
Issue Number:5
Column Tag:Internet Development

Writing CGI Applications With 4D

Beam your web pages into the 4th DIMENSION

By Mike Cohen, Casper, WY

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

In previous articles [in, for example, MacTech Magazine 11.7, 11.8, 11.9, 11.12, and 12.1 - man], you were shown how WebSTAR or MacHTTP can interface with CGI applications. In this article, I’ll demonstrate how to use this same CGI interface to have your Web server communicate with 4th DIMENSION, using System 7 Pack from ISIS International.

About System 7 Pack

System 7 Pack, from ISIS International, is a 4th DIMENSION external package that lets you send and receive Apple events in your databases. With System 7 Pack, 4D applications can control other applications, such as Microsoft Excel or QuarkXPress, and can be accessed by other local or remote applications. Once it possesses an Apple event handler, your 4D database can act as a CGI application for WebSTAR or MacHTTP.

CGI Applications

If you’ve read previous articles in this series, you probably know the basics of CGI applications, but I’ll review them here. When a Web client requests a file, WebSTAR (or MacHTTP) uses the filename’s suffix to determine how the file should be handled. In most cases, the file will simply be returned to the client. However, for a file type of .cgi or .acgi, the application will be launched, if it isn’t already running, and an Apple event will be sent to it with information passed from the client. After processing that event, the CGI application returns HTML text to WebSTAR.

Using 4D to Write CGI Applications

The first thing you need to do is to put a copy or alias of either 4D itself or a compiled 4D database merged with Runtime into your WebSTAR folder and give it a name ending in .cgi or .acgi. If you use the suffix .acgi, your application will be called asynchronously: WebSTAR won’t wait for an Apple event to complete before sending additional requests. Such an application must be prepared to have multiple outstanding requests, and may need to use semaphores to prevent simultaneous access to global variables or data files.

Install an Apple Event Handler

The first thing your CGI application must do when 4D starts up is to install a handler for the Apple event WebSTAR sends you. The following line of code in our startup procedure will take care of that:

 $Err := HandleAEVT ("WWW ";"sdoc";"CGI Handler")

This System 7 Pack function tells 4D to call the procedure named CGI Handler whenever it receives an Apple event of class 'WWW ' and ID 'sdoc', which is the event that WebSTAR sends to CGI applications. The full startup procedure (see Listing 1) also initializes several global variables that the rest of the application will use.

Since many of our global variables will be used by the Apple event handlers, which run in a separate process, we use interprocess variables identified by a name beginning with the diamond character ( ). The most important variables, ae_headRslt, ae_TextHdr, and ae_PictHdr, contain standard HTTP headers that must be returned along with any data we send back to WebSTAR.

When 4D receives an Apple event, it automatically starts a process called Apple Event Manager, in which all event handler procedures run. With some versions of 4D (most notably 4D Server 1.0.5 and any non-server version earlier than 3.0.5), the first Apple event received is discarded or takes a long time to handle. To avoid these problems, we have our startup procedure send a dummy Apple event to itself.

Listing 1: STARTUP
    ` let’s define a few global variables here
 crlf:=Char(13)+Char(10)
 q:=Char(34)  ` double quote
 nl:="<br>" ` html line break

    ` standard HTML header
 ae_headRslt:=
 "HTTP/1.0 200 OK"+ crlf+"Server: WebSTAR"+ crlf
 ae_headRslt:=
  ae_headRslt+"MIME-Version: 1.0"+ crlf
 ae_TextHdr:=
  ae_headRslt+"Content-type: text/html"+ crlf+ crlf
 ae_PictHdr:=
  ae_headRslt+"Content-type:image/gif"+ crlf+ crlf

    ` install our Apple event handlers
$Err:=HandleAEVT ("WWW ";"sdoc";"CGI Handler")

    ` some versions of 4D lose the first Apple event or take unusually long
    ` to process it, so we’ll send ourselves a bogus event to start the
    ` AppleEvent Manager process which will handle all incoming events
$Err:=MakeAddress("4D05";$myself)
$Err:=SendAEVT($myself;"XXXX";"XXXX";"-")
$Err:=DisposeDesc($myself)

Hand Off the Apple Event

Next, you need to write a procedure that will be executed in response to the Apple event. It’s important for this procedure to run as quickly as possible, since each incoming Apple event is queued and dispatched to this single process. A good approach is to simply call AESuspend (a function introduced in System 7 Pack 3.8.3) and pass the event returned from it to another process. For the sake of simplicity, I merely start a new process here, but for better performance, you should start the process when the application starts up, suspend it, and wake it up each time an event comes in.

Listing 2: CGI Handler
$Err := AESuspend ( theEvent; theReply)
New process("CGI Script";32000;"CGI Script Handler")

The function AESuspend makes a copy of the incoming event and reply, and informs the AppleEvent Manager that it shouldn’t (as it normally does) automatically send the reply when the procedure finishes. Note that you must use interprocess variables (indicated by a variable name that begins with ), since the event will later be handled in a separate process.

The New Process command then starts up a separate process called CGI Script Handler that will run the procedure CGI Script to do the actual event handling. Once this procedure finishes, 4D will then be free to receive additional Apple events while the CGI Script Handler process finishes handling the event.

Process the Apple Event

Finally, the function CGI Script (see Listing 3), which will be run in a separate process, finishes handling the request and sends the reply to WebSTAR. The first thing we do is to save the Apple event and reply in process variables, since a new Apple event coming in at this time would modify the interprocess variables. Next, we initialize several variables we use to extract data from the incoming Apple event. We then extract the path argument, sent as the direct object using the System 7 Pack function GetTextParam. The additional arguments sent by WebSTAR, including the method, search, and post arguments, are also extracted by calling GetTextParam. Next, we inspect the various arguments to decide how to handle the request. In this procedure, we handle all POST requests by adding a record to the database.When we receive a GET request, if no PATH argument is given, we simply return a list of all records containing the search string. If the PATH argument begins with rec, we assume the search argument is a record number and return the full record. If the PATH argument begins with pict, we use the search argument as a record number and return a picture field from that record as a GIF image.

Listing 3: CGI Script
evt:= theEvent
rep:= theReply

` assume the reply format will be TEXT
$hdr:= ae_TextHdr

C_TEXT(http_meth) `the method - either “GET” or “POST”
C_TEXT(http_srcha)`the search arguments
C_TEXT(http_post) `the post argument
C_TEXT(http_path) `the path argument
C_TEXT(use_address) `the user issuing this request

$err:=GetTextParam (evt;"----";http_path)
    `extracts the “direct object” parameter of the
    `Apple event which caused this procedure to be launched
    `the “direct” object of an Apple event passed from WebSTAR is the
    `“path” argument

    `get other pieces from this apple event
$err:=GetTextParam (evt;"meth";http_meth)
$err:=GetTextParam (evt;"kfor";http_srcha)
$err:=GetTextParam (evt;"post";http_post)
$err:=GetTextParam (evt;"addr";use_email)

Case of 
 : (http_meth="post")` handle a post request
 $ostr:=DoPost (http_post)
 : ((http_srcha="") & (http_path=""))` all blank
 $ostr:="No search terms were given."+
 "What do I search for?"+ crlf
 : http_path="rec@") ` handle a record # detail request
 $ostr:=GetRecord (http_srcha)
 : (http_path="pict@")  ` handle an image request
 $ostr:=GetImage (http_srcha)
 $hdr:= ae_PictHdr
 : (http_path="")`it’s a simple search
 $ostr:=DoSearch (http_srcha)
  
 Else 
 $ostr:="ERROR- The path '"+http_path+
 "' is not supported."+ crlf
End case 

    ` now, send the reply back to WebSTAR for this Apple event
$err:=PutTextParam (rep;"----";$hdr+$ostr)

    ` finish processing this event and send the reply
$err:=AEResume (evt;rep)

Let’s take a closer look at this procedure.

The first two lines copy the event and reply from interprocess variables into process variables, both for convenience and to avoid trouble if they get changed by another process. If you expect to have many incoming events, you should probably use an array into which the Apple event handler pushes values, and use this function to pop them out.

We then use GetTextParam to extract the parameters that WebSTAR passed to the CGI script. The direct object is the path value (the text that follows the $ in your HTML request). The other important values are the method (http_meth, or the 'meth' descriptor in the Apple event), which is either GET or POST, the post argument (http_post, or the 'post' descriptor in the Apple event), which contains the data entered in the form which uses a POST method, and the search argument (http_srcha, or the 'kfor' descriptor in the Apple event), which contains the text that follows the ? in your HTML request.

Next, we use a case to determine what type of request we got and take the appropriate action for it. If we got a POST request, we call the function DoPost, which parses the post arguments and updates the database with the new data. The other requests we handle are: a simple GET request with no path value, in which case we simply do a search and return a list of matching records; a GET request with a path value of REC, for which we return the full details of a record specified by number; and a GET request with a path value of PICT, for which we return a picture field from a record specifed by number. Note that string comparisons are case insensitive and can include 4D’s wildcard character (@).

Finally, we call PutTextParam to place the text to be returned into the reply event, and call the function AEResume, which informs the AppleEvent Manager that we’re finished handling the event that we previously suspended and sends the reply event back to WebSTAR.

Process POST Data

The procedure DoPost handles a POST request. In this case, we simply add a record to the database. Your system should probably check to see if the record already exists before it adds a new record.

The POST arguments, which provide the data to be saved in the record, are sent as a string of field names and values, such as lname=Mike&fname=Cohen&city=Casper&state=WY. Spaces are replaced with plus signs [only for Netscape and Mosaic; other browsers replace spaces with '%20' - jaw], and other special characters are encoded as hexadecimal values. You could write a procedure to parse the string in 4D, but it would be very slow. The easiest way to handle the POST string is to use the Parse Post Args function of Wayne K. Walrath’s excellent Acme Script Widgets OSAX.

AppleScript OSAXen are additions to the AppleScript language that work by installing a system-level event handler. You can call any scripting addition by sending the appropriate Apple event either to your own application or to the system, without having to call AppleScript. In this case, I send an event to the system, since some versions of 4D seem to have problems with re-entrancy when sending an Apple event to themselves.

Listing 4: DoPost
    `create a new record
CREATE RECORD([Names])

    `call the parse post args function of Acme Script Widgets
$err:=MakeAddress ("MACS";$system)
$err:=CreateAEVT ("zCGI";"ppar";$system;$aevt)
$err:=PutTextParam ($aevt;"----";$1)
$err:=SendAppleEvent ($aevt;$reply;kAEWaitReply ;-1)
$err:=GetList ($reply;"----";MyArray)

    ` examine the array of fields and values to determine
    ` where to place each piece of data
For ($i;1;Size of array(myArray))
 $err:=GetNthItem (MyArray{$i};1;$aKey;$aType;$theField)
 $err:=GetNthItem (MyArray{$i};2;$aKey;$aType;$theValue)
 Case of 
 : ($theField="fname")
 [Names]First Name:=$theValue
 : ($theField="lname")
 [Names]Last Name:=$theValue
 : ($theField="address")
 [Names]Address 1:=$theValue
 : ($theField="city")
 [Names]City:=$theValue
 : ($theField="state")
 [Names]State:=$theValue
 : ($theField="zip")
 [Names]Zip:=$theValue
 : ($theField="country")
 [Names]Country:=$theValue
 : ($theField="email")
 [Names]Email:=$theValue
 End case 
End for 

    ` clean up everything we allocated
$err:=DisposeDesc ($reply)
$err:=DisposeDesc ($aevt)
$err:=DisposeDesc ($system)

SAVE RECORD([Names])
UNLOAD RECORD([Names])
$0:="Record Added."

The first thing we do with this code is to create a new record. Next, we parse the POST arguments passed to our script by calling the ACME Script Widgets OSAX. The function MakeAddress is used to create a target address referring to the system process. We use that target address to create an Apple event of class 'zCGI' and ID 'ppar', which invokes the Parse Post Args function. After we send the event, we extract the array of field name and value pairs it returns.

Next, we examine each name/value pair and use the data to update the record. The array we got back from Parse Post Args consists of a series of sub-arrays containing a field name and value. We inspect each field name and use it to determine which data field the value should be placed into.

After we finish processing the data, we dispose of all the Apple event records and other descriptors we created, to avoid any memory leaks.

Finally, we save and unload the new record. Our procedure returns the text “Record Added”. This will be sent back to WebSTAR and displayed in the browser as an acknowledgement that the form was accepted.

Process SEARCH Data

The procedure DoSearch handles a simple search request by returning a 
formatted list of all records which match the search string.  Each item 
is returned as a URL that will display the entire record if it is clicked. 
 This procedure will be passed the search argument and will use it to 
do a substring search.  If any records match the search string (in this 
case, we use the last name field), they will be returned as a formatted 
list of first and last name.  Clicking one of them in your browser will 
display the full details for that record.
Listing 5: DoSearch
` our search form has a single unnamed field, so we strip off the
` equal sign for the label that precedes the search value
If ($1¾1 ="=")
 $1:=Substring($1;2)
End if 
SEARCH([Names];[Names]Last Name=$1)
If (Records in selection([Names])=0)
 $reply:="<strong>No matching items.</strong>"
Else 
 $reply:="<Title>Search Results</Title>"+
 "<b>Matching items:</b>"+ crlf+"<ul>"+ crlf
 FIRST RECORD([Names])
 For ($i;1;Records in selection([Names]))
 $fn:=[Names]First Name
 $ln:=[Names]Last Name
 $reply:=$reply+
 "<li> <A HREF="+ q+"4d.acgi$recno?"+
 String(Record number([Names]))
 $reply:=$reply+ q+">"+$fn+" "+$ln+"</A>"+ crlf
 UNLOAD RECORD([Names])
 NEXT RECORD([Names])
 End for 
 $reply:=$reply+"</ul>  "
End if 
$0:=$reply

The search result is returned as HTML text. If any matching records are found, we format them as a list. Each item is a clickable link that will send a new request back to our application, which will display the full details of our record. The URLs will look something like this:

 <li><A HREF="4d.acgi$recno?1">Mike Cohen</A>

Retrieving Detailed Records

The next procedure, GetRecord, is called from the main Apple event handler in response to a record number detail request. It takes a record number passed as the search argument, goes directly to that record, and returns a formatted name and address label for that record.

Listing 6: GetRecord
$fn:=Num($1)
DEFAULT FILE([Names])
GOTO RECORD($fn)
$reply:="<Title>Search Results</Title>"+
 "<STRONG>Client Info:</STRONG><p>"+ crlf
If ([Names]showImage)
 $reply:=$reply+
 "<img src="+ q+"4d.acgi$pict?"+$1+ q+">"+ crlf
End if 
$reply:=$reply+[Names]First Name+" "+[Names]Last Name+ nl
$reply:=$reply+[Names]Title+ nl+[Names]Company+ nl
$reply:=$reply+[Names]Address 1+ nl+[Names]Address 2+ nl
$reply:=$reply+[Names]City+", "+[Names]State+
 "  "+[Names]Zip+ nl
$reply:=$reply+[Names]Phone 1+ nl+[Names]Phone 2+ nl
If ([Names]Email#"")
 $reply:=$reply+"<A HREF=mailto:"+
 [Names]Email+">"+[Names]Email+"</A>"+ crlf
End if 
UNLOAD RECORD([Names])
$0:=$reply

This procedure will go directly to the specified record and return the data formatted as HTML text. If an image is present, it will be passed as another ACGI request that will be sent back to our application to display that image. If an email address is available, it will be returned as a clickable mailto URL.

Handling Requests for Images

Images in a 4D database are stored as PICT fields. Since PICT isn’t supported by most Web browsers, we must convert it to GIF format before we return it to WebSTAR. The procedure GetImage will return a PICT field from the specified record as a GIF image to be displayed, using Yves Piguet’s freeware Clip2Gif utility. As in the previous procedure, we use the search string as a record number and go directly to that record.

Listing 7: GetImage
$fn:=Num($1)
DEFAULT FILE([Names])
GOTO RECORD($fn)
$gifText:=""
 ` if Clip2Gif isn’t running, launch it now
If (IsRunning ("c2gf")=0)
 $err:=Launch ("c2gf";"")
End if 
 ` send a “save” event to clip2gif to convert PICT to GIF
$err:=MakeAddress ("c2gf";$Clip2Gif)
If ($err=0)
 $err:=CreateAEVT ("core";"save";$Clip2Gif;$aevt)
 If ($err=0)
 $err:=PutPicParam ($aevt;"----";1;[Names]Logo)
 $err:=PutLongParam ($aevt;"fltp";"type";Long ("GIFf"))
 $err:=PutLongParam ($aevt;"kfil";"type";Long ("itxt"))
 $err:=SendAppleEvent ($aevt;$reply;kAEWaitReply ;-2)
 If ($err=0)
 $err:=GetTextParam ($reply;"----";$gifText)
 End if 
 $err:=DisposeDesc ($reply)
 $err:=DisposeDesc ($aevt)
 End if 
 $err:=DisposeDesc ($Clip2Gif)
End if 
UNLOAD RECORD([Names])
$0:=$gifText

Again, let’s review. First, we make sure Clip2Gif is running, and if it isn’t, we launch it. Next, we send a 'save' event with the PICT data and ask to have it returned in GIF format. Clip2GIF has several options for creating GIF images, including transparency and interlacing. (Information about these options and how to access them via Apple events is included with the software.) We then extract the GIF data from the reply and return it as the result of this procedure, to be sent back to WebSTAR.

Sample HTML Forms

Now that we have the code for our CGI application, here are some sample HTML forms that can be used to drive it. The DBSearch.html form (Listing 8) will start a search of the database and return a list of links to matching records.

Listing 8: DBSearch.html
<HTML>
<HEAD><TITLE>Search Database</TITLE></HEAD>
<BODY>
<FORM ACTION="4d.acgi" METHOD=GET>
Item to search for:<INPUT name="" TYPE="text" SIZE=32>
(use '@' as a wildcard)
<p>
<INPUT TYPE="submit" VALUE="Search">
<INPUT TYPE="reset" VALUE="Cancel">
</FORM>
</BODY>
</HTML>

The DBUpdate.html form (Listing 9) will send a POST request to create a new record in the database.

Listing 9: DBUpdate.html
<HTML>
<HEAD><TITLE>Update Database Entry</TITLE></HEAD>
<BODY>
<FORM ACTION="4d.acgi" METHOD=POST>
Name:<INPUT TYPE="text" NAME="fname" SIZE=20>
<INPUT TYPE="text" NAME="lname" SIZE=20><P>
Address:<INPUT TYPE="text" NAME="address" SIZE=40><P>
City:<INPUT TYPE="text" NAME="city" SIZE=15>
State:<INPUT TYPE="text" NAME="state" SIZE=2>
Zip:<INPUT TYPE="text" NAME="zip" SIZE=10><p>
Country:<INPUT TYPE="text" NAME="country" SIZE=15><p>
Email:<INPUT TYPE="text" NAME="email" SIZE=20><p>
<SELECT NAME="System Type">
<OPTION>Macintosh II series
<OPTION>Macintosh Quadra
<OPTION>PowerMac
<OPTION>Powerbook or Duo
<OPTION>PC
<OPTION>Other
</SELECT><P>
<INPUT TYPE="submit" VALUE="Update">
<INPUT TYPE="reset" VALUE="Cancel">
</FORM>
</BODY>
</HTML>

Conclusion

For most Web sites, the most important function of the server is to deliver information to users. If you already have data in a 4D database, you can now easily make this information available directly from your Web pages. You can also develop Web-based front ends to your 4D applications for uses such as kiosks, where the 4D user interface is inappropriate or too complex. Once you get started I am sure that you will find dozens of ways that you can use a 4D CGI application to improve your Web site.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Live Home 3D Pro 3.2.2 - $69.99
Live Home 3D Pro, a successor of Live Interior 3D, is the powerful yet intuitive home design software that lets you build the house of your dreams right on your Mac. It has every feature of Live Home... Read more
FileZilla 3.27.0.1 - Fast and reliable F...
FileZilla (ported from Windows) is a fast and reliable FTP client and server with lots of useful features and an intuitive interface. Version 3.27.0.1: MSW: Add misssing file to .zip binary package... Read more
Spotify 1.0.59.395. - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
Sierra Cache Cleaner 11.0.6 - Clear cach...
Sierra Cache Cleaner is an award-winning general purpose tool for macOS X. SCC makes system maintenance simple with an easy point-and-click interface to many macOS X functions. Novice and expert... Read more
DiskCatalogMaker 7.1.2 - 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
Live Home 3D Pro 3.1.2 - $69.99
Live Home 3D Pro, a successor of Live Interior 3D, is the powerful yet intuitive home design software that lets you build the house of your dreams right on your Mac. It has every feature of Live Home... Read more
Deeper 2.2.1 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
Pinegrow 3.04 - Mockup and design webpag...
Pinegrow (was Pinegrow Web Designer) is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation,... Read more
Deeper 2.2.1 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
Spotify 1.0.59.395. - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more

Latest Forum Discussions

See All

The best deals on the App Store this wee...
There are quite a few truly superb games on sale on the App Store this week. If you haven't played some of these, many of which are true classics, now's the time to jump on the bandwagon. Here are the deals you need to know about. [Read more] | Read more »
Realpolitiks Mobile (Games)
Realpolitiks Mobile 1.0 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0 (iTunes) Description: PLEASE NOTE: The game might not work properly on discontinued 1GB of RAM devices (iPhone 5s, iPhone 6, iPhone 6 Plus, iPad... | Read more »
Layton’s Mystery Journey (Games)
Layton’s Mystery Journey 1.0.0 Device: iOS Universal Category: Games Price: $15.99, Version: 1.0.0 (iTunes) Description: THE MUCH-LOVED LAYTON SERIES IS BACK WITH A 10TH ANNIVERSARY INSTALLMENT! Developed by LEVEL-5, LAYTON’S... | Read more »
Full Throttle Remastered (Games)
Full Throttle Remastered 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Originally released by LucasArts in 1995, Full Throttle is a classic graphic adventure game from industry legend Tim... | Read more »
Stunning shooter Morphite gets a new tra...
Morphite is officially landing on iOS in September. The game looks like the space shooter we've been needing on mobile, and we're going to see if it fits the bill quite shortly. The game's a collaborative effort between Blowfish Studios, We're Five... | Read more »
Layton's Mystery Journey arrives to...
As you might recall, Layton's Mystery Journey is headed to iOS and Android -- tomorrow! To celebrate the impending launch, Level-5's released a new trailer, complete with an adorable hamster. [Read more] | Read more »
Sidewords (Games)
Sidewords 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Grab a cup of coffee and relax with Sidewords. Sidewords is part logic puzzle, part word game, all original. No timers. No... | Read more »
Noodlecake Games' 'Leap On!...
Noodlecake Games is always good for some light-hearted arcade fun, and its latest project, Leap On! could carry on that tradition. It's a bit like high stakes tetherball in a way. Your job is to guide a cute little blob around a series of floating... | Read more »
RuneScape goes mobile later this year
Yes, RuneScape still exists. In fact, it's coming to iOS and Android in just a few short months. Jagex, creators of the hit fantasy MMORPG of yesteryear, is releasing RuneScape Mobile and Old School RuneScape for mobile devices, complete with... | Read more »
Crash of Cars wants you to capture the c...
Crash of Cars is going full on medieval in its latest update, introducing castles and all manner of new cars and skins fresh from the Dark Ages. The update introduces a new castle-themed map (complete with catapults) and a gladiator-style battle... | Read more »

Price Scanner via MacPrices.net

Save or Share
FotoJet Designer, is a simple but powerful new graphic design apps available on both Mac and Windows. With FotoJet Designer’s 900+ templates, thousands of resources, and powerful editing tools you... Read more
Logo Maker Shop iOS App Lets Businesses Get C...
A newly released app is designed to help business owners to get creative with their branding by designing their own logos. With more than 1,000 editable templates, Logo Maker Shop 1.0 provides the... Read more
Sale! New 15-inch MacBook Pros for up to $150...
Amazon has the new 2017 15″ MacBook Pros on sale for up to $150 off MSRP including free shipping: – 15″ 2.8GHz MacBook Pro Space Gray: $2249 $150 off MSRP – 15″ 2.89Hz MacBook Pro Space Gray: $2779 $... Read more
DEVONthink To Go 2.1.7 For iOS Brings Usabili...
DEVONtechnologies has updated DEVONthink To Go, the iOS companion to DEVONthink for Mac, with enhancements and bug fixes. Version 2.1.7 adds an option to clear the Global Inbox and makes the grid... Read more
15-inch 2.2GHz Retina MacBook Pro, Apple refu...
Apple has Certified Refurbished 2015 15″ 2.2GHz Retina MacBook Pros available for $1699. That’s $300 off MSRP, and it’s the lowest price available for a 15″ MacBook Pro. An Apple one-year warranty is... Read more
13-inch 2.3GHz Silver MacBook Pro on sale for...
B&H Photo has the new 2017 13″ 2.3GHz/256GB Silver MacBook Pro (MPXU2LL/A) on sale for $1399 including free shipping plus NY & NJ sales tax only. Their price is $100 off MSRP. Read more
Apple Tackles Distracted Driving With iOS 11...
One of the most important new features coming in iOS 11 is Do Not Disturb while driving, intended to help drivers stay more focused on the road. With Do Not Disturb while driving, your iPhone can... Read more
iMazing Mini for Mac: Free Automatic and Priv...
Geneva, Switzerland-based indie developer DigiDNA has released iMazing Mini, their free macOS utility designed to automatically back up iOS devices over any local Wi-Fi network. The app offers users... Read more
Clearance 2016 13-inch MacBook Airs, Apple re...
Apple dropped prices recently on Certified Refurbished 2016 13″ MacBook Airs, with models now available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is... Read more
9.7-inch 2017 iPads available for $299, save...
B&H Photo has 2017 9.7″ 32GB WiFi iPads on sale for $30 off MSRP for a limited time. Shipping is free, and pay sales tax in NY & NJ only: – 32GB iPad WiFi: $299, $30 off Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple...
SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions - Apple...
SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Senior Payments Architect - *Apple* Pay - A...
Changing the world is all in a day's work at Apple . If you love innovation, here's your chance to make a career of it. You'll work hard. But the job comes with more Read more
Frameworks Engineering Manager, *Apple* Wat...
Frameworks Engineering Manager, Apple Watch Job Number: 41632321 Santa Clara Valley, California, United States Posted: Jun. 15, 2017 Weekly Hours: 40.00 Job Summary Read more
Manager, *Apple* Media Products - Apple Inc...
Job Summary The Apple Media Products Discovery, Fraud and Abuse team is responsible for protecting the integrity of Apple services. As a manager of the team, you Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.