TweetFollow Us on Twitter

Jul 96 Challenge
Volume Number:12
Issue Number:7
Column Tag:Programmer’s Challenge

Programmer’s Challenge

By Bob Boonstra

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

Connect IV

This month, your Challenge is to write code for a well-known game that will compete against other Challenge entries, as well as against the clock. The game board consists of an NxM array into which two players alternate inserting pieces. Pieces are inserted into the top of a column in the vertically oriented board, so that they drop into the lowest unoccupied cell of that column. The objective is to be the first player to arrange 4 or more pieces into a vertical, horizontal, or diagonal line.

The winner of this Challenge will be determined by a round-robin tournament in which each entry competes against each other entry an even number of times, half of the time playing with the first move, and half playing with the second move. (If the number of entries makes a full round-robin tournament impractical, I’ll use another fair tournament scheme.) Each tournament victory will earn two points for the winning entry, and each tie earns one point. The entry with the greatest number of tournament points wins the Challenge. Ties will be broken by execution time, code size, etc.

The prototype for the code you should write is:

long /*yourMove*/ ConnectMove (
 long numCols,   /* number of columns in the game board */
 long numRows,   /* number of rows in the game board */
 void *privStorage,/* preallocated storage for your use */
 long prevMove,  /* column where opponent last moved, 0 ..  numCols-1 */
 Boolean newGame,/* TRUE if this is your first move in a new game */
 Boolean *victory/* set to TRUE if you claim victory */
    /*   this move, otherwise set to FALSE */
);

For your first move in a new game, your ConnectMove code will be called with newGame set to TRUE. If your opponent made the first move in this game, prevMove will be set to the (origin zero) column that the opponent selected as the first move. If you are to make the first move, prevMove will be set to -1. In the call for the first move of a new game, you will also be provided with a pointer privStorage to 1MB of memory, already initialized to zero, for your use during that game. Finally, the initial call will provide the number of columns (numCols) and rows (numRows) in the board for that game. The number of rows and columns will each be larger than 6 and less than 64.

Alternating calls will be made to your ConnectMove routine and the opposing ConnectMove routine. For the second and subsequent moves in each game, newGame will be set to FALSE, and the values of numCols, numRows, and privStorage will be the same as in the initial call. Each time ConnectMove is called, you should evaluate the move made by your opponent (provided in prevMove) and return the column into which you make your move as the function result. If you believe you have won the game, you should set *victory to TRUE; otherwise you should set *victory to FALSE. Falsely claiming victory or making an illegal move, such as trying to insert a game piece into a column that is already filled, will result in forfeiting that game.

For this Challenge, you may dynamically allocate additional storage beyond that provided by privStorage, provided you deallocate it before returning after each move. You may not use any static storage beyond that provided by privStorage.

To conduct the tournament, the code for multiple entries will be compiled into a single application. In case you are wondering, I will append a unique integer to the name of each routine before compiling so that each ConnectMove routine will be named uniquely.

This will be a native PowerPC Challenge, scored using the Symantec environment. Solutions may be coded in C or C++.

Two Months Ago Winner

Perhaps the earlier Challenge deadline caught people a little off guard this month. Whatever the reason, only three people chose to enter the Edge Detector Challenge this month. Congratulations to Ernst Munter (Kanata, ON, Canada) for submitting the fastest entry to the Edge Detector Challenge. This is Ernst’s third win in the last four contests, and it brings him within 2 points of the lead in our Top Contestants point total.

Contestants were required to process PixMap images in 8-bit, 16-bit, or 32-bit color and identify pixels where the color difference with adjacent pixels exceeded a specified threshold in the specified color component (or combination of components). The second place solution by Miguel Cruz Picao was actually faster than the winning solution in two of the three color depth cases, but was slower in the third case and slower overall. Miguel elected to implement entirely separate code for each of the three color depth cases, while Ernst sacrificed some processing time for smaller code size by testing for color depth while processing each line of the image, using common code for the rest of the three cases. On the other hand, Ernst used the EdgeType provided as a parameter to select, outside of any loops, the edge detection routine to use for the entire image, while Miguel’s code tested the EdgeType for each pixel. Ernst elected to make four passes through each pair of adjacent image lines, comparing pixels that were adjacent horizontally, diagonally in each direction, and vertically, allowing compact and efficient comparison loops. The overall result was that the winning solution was some 25% faster than the second-place solution in the 32-bit case, which was enough to make it about 5% faster overall.

Table 1 summarizes the results for each entry, including code size, data size, execution time for each of the three color depth cases, and the overall score based on total execution time. Numbers in parentheses after a person’s name indicate that person’s cumulative point total for all previous Challenges, not including this one.

Name Code Data Time Time Time Score

(32) (16) (8)

Ernst Munter (154) 1492 116 833 912 723 2467

Miguel Cruz Picao (11) 3420 20 1120 899 582 2600

Greg Cooper 1872 28 1830 1902 1802 5534

Table 1. Results for each entry

Rank Name Points Rank Name Points

1. [Name deleted] 176 11. Mallett, Jeff 44

2. Munter, Ernst 174 12. Kasparian, Raffi 42

3. Gregg, Xan 92 13. Vineyard, Jeremy 42

4. Karsh, Bill 90 14. Lengyel, Eric 40

5. Larsson, Gustav 87 15. Darrah, Dave 31

6. Stenger, Allen 65 16. Brown, Jorg 30

7. Cutts, Kevin 57 17. Lewis, Peter 30

8. Riha, Stepan 51 18. Landry, Larry 29

9. Goebel, James 49 19. Beith, Gary 24

10. Nepsund, Ronald 47 20. Elwertowski, Tom 24

Table 2. Top 20 contestants

Top 20 Contestants of All Time

Table 2 shows the Top 20 Contestants for the Programmer’s Challenges to date The numbers below include points awarded for this month’s entrants.

There are three ways to earn points: (1) scoring in the top 5 of any Challenge, (2) being the first person to find a bug in a published winning solution or, (3) being the first person to suggest a Challenge that I use. The points you can win are:

1st place 20 points 5th place 2 points

2nd place 10 points finding bug 2 points

3rd place 7 points suggesting Challenge 2 points

4th place 4 points

Here is Ernst’s winning solution:

EdgeDetector.c

Copyright 1996, Ernst Munter

/*
Problem Statement
---------
Given a Pixmap image, create a Bitmap which shows the edges in the image.

Pixmaps may have 8, 16, or 32 bit colors. Parameters control which colors should contribute to the edge 
detection, and a threshold for the color space difference (an RMS value) to be considered an edge.

All 16 bits of the individual color values must be considered, which can result in 32-bit overflow when squares 
are added.

Solution
----
The general idea is to process 2-row strips of the image through an intermediate ColorSpec stage in which 
the “value” fields are used to mark edge pixels. 

Step1:

We allocate a small amount of memory, sufficient to hold two rows of pixels in ColorSpec format (8 bytes 
per pixel). Pixels from each row in the Pixmap are converted to ColorSpec format (RGB + “value”).

Step2:

The two lines are scanned with 4 different patterns to determine edges:  given 2 rows with pixels as shown

 A B C D E F G H ...
 a b c d e f g h ...

We compare pixel pairs in four separate runs of EdgePairs():
 a-b, b-c, c-d, d-e ...  (WEST - EAST)
 A-b, B-c, C-d, D-e ...  (NORTH-WEST - SOUTH-EAST)
 B-a, C-b, D-c, E-d ...  (NORTH-EAST - SOUTH-WEST)
 A-a, B-b, C-c, D-d ...  (NORTH - SOUTH)

This procedure is repeated for rows 0 and 1, then 1 and 2, 2 and 3, and so on.  (Plus an West-East run for 
row 0).

During each run, the “value” field of every pair of pixels found to be part of an edge is set to -1 (0xFFFF). 
All other values remain at 0.

Step 3:

Before shifting down to the next row, the ColorSpecs of the upper row are scanned to construct a row of 
the Bitmap.

Optimizations
-------
The combinations of pixel size and edge types are dealt with as follows:

All pixel types are normalized to a single ColorSpec format by the GetLine procedure.

Different edge types call for different series of tests.  Specifically, 1, 2, or 3 colors can be optimized separately. 
On of a set of 7 separate short functions is selected at runtime.  This requires the edge type to be evaluated 
only once, to select the EdgeXXX procedure that will be used many times as the image is scanned from top 
to bottom.

Comparing an RMS (root of sum of squares) value with a threshold is equivalent to comparing the sum of 
squares with the square of the threshold value.  This avoids the need to compute square roots.

In the case of a single color edge type, the square of the difference would not need to be formed.  A simple 
comparison of the threshold with the absolute difference would suffice.  However, the runtime difference 
between a multiply and computing the absolute value would depend on CPU type etc, and would tend to be 
small.  I opted for uniformity, and square all differences.

The dynamically allocated storage should typically fit inside the CPU cache, and not slow things down as 
it is read and written continuously.

Assumptions
------
Bitmap is large enough to hold the result.  eType is within the range of redOnly to redGreenAndBlue, otherwise 
the call will certainly crash.

Amount of static memory = 8 pointers (32 bytes)
Amount of dynamic memory required is for 2 rows of
ColorSpec records (a 1024 pix wide image -> 16K of storage).

*/

#include <QDOffscreen.h>
// Contains PixMap, BitMap and EdgeType defs

#include <stdlib.h>

Definitions
typedef enum
{
 redOnly = 1,
 greenOnly,
 redAndGreen,
 blueOnly,
 redAndBlue,
 greenAndBlue,
 redGreenAndBlue
} EdgeType;

typedef void EdgeProc(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

Function Prototypes
void EdgeDetect(
 PixMapHandle    pMapH,
 BitMap *bMap,
 unsigned short  threshold,
 EdgeType eType);

void Get1Line(
 ColorSpec* line,
 void*  pix,
 int    size,
 ColorSpec* CT,
 int    pixelSize);

void EdgeRed(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

void EdgeGreen(
 ColorSpec* P,
 ColorSpec*    Q,
 int    size,
 unsigned long   TH);

void EdgeRedGreen(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

void EdgeBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

void EdgeRedBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

void EdgeGreenBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

void EdgeRedGreenBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH);

void Copy2Bitmap(
 ColorSpec* P,
 unsigned char*  bits,
 int    size);

Static Allocations
static EdgeProc* EdgeProcedure[8] = {
 0,
 EdgeRed,
 EdgeGreen,
 EdgeRedGreen,
 EdgeBlue,
 EdgeRedBlue,
 EdgeGreenBlue,
 EdgeRedGreenBlue};

EdgeDetect
void EdgeDetect(
 PixMapHandle    pMapH,
 BitMap *bMap,
 unsigned short  threshold,
 EdgeType eType) {
PixMap* pm=*pMapH;

unsigned char*   pix=(unsigned char*)GetPixBaseAddr(pMapH);
unsigned char*   bits=(unsigned char*)bMap->baseAddr;
unsigned long  TH=(unsigned long)threshold*threshold;
int     y;
int     pixelSize=pm->pixelSize;
int     pixRowBytes=pm->rowBytes & 0x3FFF;
int     pixInRow=pm->bounds.right-pm->bounds.left;
int     bitRowBytes=bMap->rowBytes;

ColorSpec*  allocated;
ColorSpec*  line0;
ColorSpec*  line1;
ColorSpec*  CTable=(*(pm->pmTable))->ctTable;
EdgeProc* EP;

// Get memory for a 2-row strip of pixels:
  if (0==(allocated=(ColorSpec*)malloc(
 2*sizeof(ColorSpec)*pixInRow))) return;
  line0=allocated-1;  //(we always use pre-increment later)
  line1=line0+pixInRow;

// Determine EdgeProc to use:
  EP=EdgeProcedure[eType];

// Prepare first row:
  Get1Line(line0,pix,pixInRow,CTable,pixelSize);
  (*EP)(line0,line0+1,pixInRow-1,TH);    //W-E

// Process remaining rows:
  for (y=pm->bounds.top+1;y<pm->bounds.bottom;y++) {
    pix+=pixRowBytes;
    Get1Line(line1,pix,pixInRow,CTable,pixelSize);
                                                             
    (*EP)(line1,  line1+1,pixInRow-1,TH);  //W-E
    (*EP)(line0,  line1+1,pixInRow-1,TH);  //NW-SE
    (*EP)(line0+1,line1,  pixInRow-1,TH);  //NE-SW
    (*EP)(line0,  line1,  pixInRow,TH);    //N-S

// Convert ColorSpec.values to Bitmap.bits:
    Copy2Bitmap(line0,bits,bitRowBytes);

// Swap line0 with line1:
    {ColorSpec* temp=line0;line0=line1;line1=temp;}
    bits+=bitRowBytes;
  }

// Convert the last row;
  Copy2Bitmap(line0,bits,bitRowBytes);

// Release dynamic memory:
  free(allocated);
}

Get1Line
/***************** Local Functions ************************/
void Get1Line(
 ColorSpec* line,
 void*  pix,
 int    size,
 ColorSpec* CT,
 int    pixelSize){
inti,r,g,b;
unsigned long  x;
  if (pixelSize==8) {
    unsigned char*   PIX =((unsigned char*)pix);
    for (i=0;i<size;i++) {
      x=*PIX++;
      line++;
      *((double*)(line))=*((double*)(CT+x));
      line->value=0;
    }
  } else if (pixelSize==16) {
    unsigned short*  PIX =((unsigned short*)pix);
    for (i=0;i<size;i++) {
      x=*PIX++;
      line++;
      r=((x & 0x7C00) << 1)  | ((x & 0x7C00) >> 4) |
 ((x & 0x7C00) >> 9)  | ((x & 0x7C00) >> 14);
      g=((x & 0x03E0) << 6)  | ((x & 0x03E0) << 1) |
 ((x & 0x03E0) >> 4)  | ((x & 0x03E0) >> 9);
      b=((x & 0x001F) << 11) | ((x & 0x001F) << 6) |
 ((x & 0x001F) << 1)  | ((x & 0x001F) >> 4);
      line->value=0;
      line->rgb.red=  (unsigned short)r;
      line->rgb.green=(unsigned short)g;
      line->rgb.blue= (unsigned short)b;
    }
  } else { //pixelSize not 8 or 16, so it must be 32
    unsigned long* PIX =((unsigned long*)pix);
    for (i=0;i<size;i++) {
      x=*PIX++;
      line++;
      r=((x & 0xFF0000) >> 8) | ((x & 0xFF0000) >> 16);
      g= (x & 0x00FF00)       | ((x & 0x00FF00) >> 8);
      b= (x & 0x0000FF)       | ((x & 0x0000FF) << 8);
      line->value=0;
      line->rgb.red=  (unsigned short)r;
      line->rgb.green=(unsigned short)g;
      line->rgb.blue= (unsigned short)b;
    }
  }
}

Copy2Bitmap
void Copy2Bitmap(
 ColorSpec* P,
 unsigned char*  bits,
 int    size) {
int     i;
  P++;
  for (i=0;i<size;i++) {
    *bits = (unsigned char) (
     (P[0].value & 0x80) |
     (P[1].value & 0x40) |
     (P[2].value & 0x20) |
     (P[3].value & 0x10) |
     (P[4].value & 0x08) |
     (P[5].value & 0x04) |
     (P[6].value & 0x02) |
     (P[7].value & 0x01) );
    P+=8;
    bits++;
  }
}

EdgeRedGreenBlue
void EdgeRedGreenBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  delta,acc;
  for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.red-Q->rgb.red;
    acc*=acc;
    delta=(unsigned long)P->rgb.green-Q->rgb.green;
    delta*=delta;
    acc+=delta;
    if (acc<delta) {P->value=Q->value=-1;continue;}
    delta=(unsigned long)P->rgb.blue-Q->rgb.blue;
    delta*=delta;
    acc+=delta;
    if ((acc>=TH) || (acc<delta)) P->value=Q->value=-1;
  }
}

EdgeGreenBlue
void EdgeGreenBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  delta,acc;
  for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.green-Q->rgb.green;
    acc*=acc;
    delta=(unsigned long)P->rgb.blue-Q->rgb.blue;
    delta*=delta;
    acc+=delta;
    if ((acc>=TH) || (acc<delta)) P->value=Q->value=-1;
  }
}


EdgeRedBlue
void EdgeRedBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  delta,acc;
  for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.red-Q->rgb.red;
    acc*=acc;
    delta=(unsigned long)P->rgb.blue-Q->rgb.blue;
    delta*=delta;
    acc+=delta;                                    
    if ((acc>=TH) || (acc<delta)) P->value=Q->value=-1;
  }
}

EdgeRedGreen
void EdgeRedGreen(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  delta,acc;
   for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.red-Q->rgb.red;
    acc*=acc;
    delta=(unsigned long)P->rgb.green-Q->rgb.green;
    delta*=delta;
    acc+=delta;
    if ((acc>=TH) || (acc<delta)) P->value=Q->value=-1;
  }
}

EdgeBlue
void EdgeBlue(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  acc;
  for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.blue-Q->rgb.blue;
    acc*=acc;
    if (acc>=TH) P->value=Q->value=-1;
  }
}

EdgeGreen
void EdgeGreen(
 ColorSpec* P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  acc;
  for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.green-Q->rgb.green;
    acc*=acc;
    if (acc>=TH) P->value=Q->value=-1;;
  }
}

EdgeRed
void EdgeRed(
 ColorSpec*    P,
 ColorSpec* Q,
 int    size,
 unsigned long   TH) {
int     i;
unsigned long  acc;
  for (i=0;i<size;i++) {
    P++;Q++;
    acc=(unsigned long)P->rgb.red-Q->rgb.red;
    acc*=acc;
    if (acc>=TH) P->value=Q->value=-1;
  }
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Minecraft 302 - Popular sandbox building...
Minecraft allows players to build constructions out of textured cubes in a 3D procedurally generated world. Other activities in the game include exploration, gathering resources, crafting, and combat... Read more
FotoMagico 5.2b8 - Powerful slideshow cr...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more
TeamViewer 11.0.65452 - Establish remote...
TeamViewer gives you remote control of any computer or Mac over the Internet within seconds, or can be used for online meetings. Find out why more than 200 million users trust TeamViewer! Free for... Read more
Dropbox 9.4.49 - Cloud backup and synchr...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keep them up-to-date between systems... Read more
Geekbench 4.0.0 - Measure processor and...
Geekbench provides a comprehensive set of benchmarks engineered to quickly and accurately measure processor and memory performance. Designed to make benchmarks easy to run and easy to understand,... Read more
Nisus Writer Pro 2.1.5 - Multilingual wo...
Nisus Writer Pro is a powerful multilingual word processor, similar to its entry level products, but brings new features such as table of contents, indexing, bookmarks, widow and orphan control,... Read more
Default Folder X 5.0.6 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click on... Read more
Alfred 3.1 - Quick launcher for apps and...
Alfred is an award-winning productivity application for OS X. Alfred saves you time when you search for files online or on your Mac. Be more productive with hotkeys, keywords, and file actions at... Read more
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
OmniOutliner Pro 4.6 - Pro version of th...
OmniOutliner Pro is a flexible program for creating, collecting, and organizing information. Give your creativity a kick start by using an application that's actually designed to help you think. It's... Read more

Six! Tips, tricks, and hints for beginne...
There's nothing pretentious about Six!, the latest release from Gram Games. As puzzlers go, it's so unassuming that it took me some time to even realize why it was called what it was. Somewhere, my high school geometry teacher is now sobbing... | Read more »
Mobius Final Fantasy: Multiplayer update...
Up until now, Mobius Final Fantasy has been about as single-player an experience as an RPG can be. Not only do you play solo, but you are literally one among a seemingly unending wave of faceless warriors on the road toward the same goal. [Read... | Read more »
Find out the story behind League of Ange...
If you’re looking for a new thrilling MMORPG to play with your friends then you’ll be excited to hear that there is a sequel to one of the most well known titles in the genre – namely League of Angels 2. With a brand new 3D engine offering... | 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 »

Price Scanner via MacPrices.net

Apple refurbished 12-inch iPad Pros available...
Apple has Certified Refurbished 12″ iPad Pros available for up to $160 off the cost of new iPads. An Apple one-year warranty is included with each model, and shipping is free: - 32GB 12″ iPad Pro... Read more
Tim Cook Posts Open Letter To The Apple Commu...
Apple Inc. CEO Tim Cook has posted an open letter commenting on the European Commission’s bizarre demand that Apple pay more than $14 billion in allegedly underpaid back taxes on its Irish... Read more
Streetwise Drivers Club App Now Features Open...
Streetwise Drivers Club, an app that rewards drivers with deals on everything from dining and gift cards to tires and insurance, has announced the launch of a new enhancement connecting app users... Read more
15-inch Retina MacBook Pros on sale for up to...
B&H Photo has 15″ Retina Apple MacBook Pros on sale for up to $200 off MSRP. Shipping is free, and B&H charges NY tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799 $200 off MSRP - 15″ 2.5GHz... Read more
RESCUECOM 2016 Semi-Annual Computer Reliabili...
The beginning of a new school year is upon us again, in which students and parents have some very important choices to make, often including the purchase of a computer or tablet. Whether you are... Read more
VRS Design Damda Glide Series iPhone 7 and 7...
What makes the Damda Glide Series for the iPhone 7 and iPhone 7 Plus special? Case maker VRS Design says its Damda Glide Series is the first mobile case to incorporate a semi-automatic mechanism for... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more
Clearance 2015 13-inch MacBook Airs available...
B&H Photo has clearance 2015 13″ MacBook Airs available for $350 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 1.6GHz/4GB/128GB MacBook Air (MJVE2LL/A): $829... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
Save $120 with Apple refurbished Time Capsule...
Apple has certified refurbished Time Capsules available for $120 off MSRP. Apple’s one-year warranty is included with each Time Capsule, and shipping is free: - 2TB Time Capsule: $179, $120 off (not... Read more

Jobs Board

*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: 51218354 Fredericksburg, Virginia, United States Posted: Aug. 18, 2016 Weekly Hours: 40.00 **Job Summary** As an Apple Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.