TweetFollow Us on Twitter

File Finder DA for HFS
Volume Number:2
Issue Number:3
Column Tag:C Workshop

Lost File Finder DA for HFS

By Mike Schuster, Software Engineer, MacTutor Contributing Editor

Apple designed the new Macintosh Plus Standard File dialog package to provide an easy method for finding files nested within the hierarchical file structure of a mounted volume. At any given time, the dialog displays a sorted list of the files and folders contained within a "current folder". If the desired file is not in that folder, and therefore not in the displayed list, you must first find the folder that contains the desired file.

If you believe that the desired file is in one of the "sibling folders" listed, you select that sibling and click on the Open button. The selected folder becomes the new current folder, and its contents are displayed. You may have to repeat this process if the file is nested several levels deep.

On the other hand, if the file is not contained within any sibling of the current folder, then you choose some "ancestor" as a new current folder from the pop-up menu at the top of the dialog. You then either select the desired file from the list, or repeatedly open sibling and/or ancestor folders until you find the file.

Fig. 1 Moving up to an ancestor

This manual traversal of the hierarchy can be quite tedious if you have forgotten your file's location within the hierarchy. It reminds me of an Easter Egg hunt. When working with files in several folders, I find it quite easy to accidently save a file without noticing which folder the file was placed, especially after quickly typing its name and and an Enter key. Obviously, some sort of global search function would be handy. This is the subject of this month's article.

A User Interface for Global Search

Here's what I have in mind. As soon as an application displays an Open file dialog, I'd like to type the first few letters of my file's name. If the file is contained in the current folder, an Enter key is sufficently to complete the dialog. Otherwise, I'd like to enter some command key combination to force standard file to search the hierarchy for a file whose name matches the letters I've already typed.

As soon as standard file finds a candidate, it should automatically make the folder containing the candidate the current folder as well as select the candidate. At this point, I can either accept the candidate by typing an Enter key, or resume the search by entering the command key combination once again. I'd like to be able to repeat this process until either standard file has exhaustively searched the whole file hierarchy, or until I find the desired file.

In retrospect, such a scheme might take a while on a large file system, so some way of aborting the search should be available. That way, if I get tired waiting, I can always go back and hunt for eggs myself.

A Design using a Dialog Hook

When I first considered an implementation for such a global search, it seemed that rather large changes and additions to the standard file package might be required. This turned out not to be the case. I was able to implement all of the above user interface without any modifications to the standard file package using a C language routine passed as the filterProc argument to the SFPGetFile trap!

My filterProc routine implements the search by generating a series of "synthetic" events that cause standard file to sequentially traverse the file hierarchy until a candidate match is found. You can think of it as a simple state machine that methodically selects each file and folder from the list one at a time in turn. Periodically, the machine uses the Open button and pop-up menu at appropriate times to select new folders in which to continue the search. As soon as a candidate file is found, filterProc stops creating synthetic events and begins sending null events through unchanged, allowing the user to accept the selection, continue the search, or use any of the dialog's buttons and controls in the standard way.

Rather than generating a sequence of mouse down events in the appropriate dialog controls, the filterProc generates the following set of cursor key events, which are understood by the new standard file package:

Fig. 2 Command key selections

Typing a Tab key is equivalent to clicking on the Drive button. Typing an down or up arrow key is equivalent to scrolling the list of files and folders and selecting the next item below, or previous item above in the list, respectively. If the currently selected item is a folder, then the Command Ø combination is equivalent to clicking on the Open button. Similarly, the Command combination is equivalent to selecting the current folder's immediate parent from the pull-down menu.

In addition to implementing cursor keys, the new standard file package dynamically updates the fields of its standard file reply record argument while the dialog is open:

Fig. 3 Standard File Reply Record Argument

If the currently selected item in the dialog is a file, then the reply's file type and file name length fields are both postive. In this case, the file type field contains the four letter finder document type of the file. If the selected item is a folder, only the file type field is positive. It contains the folder's file catalog directory identifier. Finally, if neither a file nor a folder is selected, both the file type and name length fields are zero.

This information, combined with the directory identifier of the current folder (which is contained in a low memory global location), provide filterProc with just enough information to allow it to traverse the hierarchy via a sequence of cursor keys. It accomplishes the global search without a single I/O call to the file system! One nice side effect of this scheme is the animation of the dialog as folders are opened and closed and as the item's themselves are selected and scrolled.

The "Lost File Finder" Desk Accessory

The Lost File Finder desk accessory contains an implementation of my global search scheme. The accessory presents a standard file dialog listing all of the files in the current folder. After typing a few letters, you enter the Command-space combination to begin (or continue) a search. The Command-period combination aborts a search. Since standard file displays the last current folder when opening a new dialog, you can use the accessory first to find the folder containing your file, and then use your application's open command to open it.

The filterProc routine in the accessory is composed of three parts. The first parts saves key events in a key buffer. This buffer is used to find potential candidate files. The second part handles the Command-space and Command-period commands. The third part is a simple state machine that generates the approprate cursor key events needed to traverse the file catalog.

The state machine is built from three states, named NULLSTATE, NEXTSTATE, and SEARCHSTATE. In NULLSTATE, null events are sent through unchanged. In NEXTSTATE, successive items in the current folder are selected. If the selected item is a file, its name is compared with the contents of the key buffer. If the selected item is a folder, then it is made the new current folder. When the end of the item list is encountered, the current folder is closed and its parent is opened. At this time, the state machine moves to SEARCHSTATE, in which successive items in the parent's folder are skipped until the just closed folder is encountered. Then the state machine returns to NEXTSTATE, and once again begins considering successive items. Of course, the root folder is handled as a special case.

In NEXTSTATE, when a file item is selected, filterProc compares its name with the contents of the key buffer. If they match, the state machine moves to NULLSTATE, and filterProc waits for further input from the user. Otherwise, the state machine stays in NEXTSTATE and continues the search.

The filterProc routine maintains two extra reply records named lastreply and startreply. Lastreply contains information on the previous item selected. It is used to detect the end of the item list, and is required since a Ø at when the last item in the list is selected has no effect. Startreply contains information on the item that was selected when the global search was begun. It is used to terminate the search when the file hierarchy has been completely traversed.

The accessory accesses three global low memory values. ISHFS is nonzero if the Hierarchical File System is installed on the Macintosh.

SFFolder contains the directory identifier of the current folder. KEYTHRESH contains the current keyboard repeat threshold value, which is used to flush the contents of the key buffer at approprate intervals.

In addition to these values, the accessory modifies the location

*(int *) (thedialog->refcon - 624)

where thedialog is a pointer to standard file's dialog window. The event record's modifiers field is returned by filterProc in this location. The dialog's refcon contains a copy of standard file's frame pointer register A6. I discovered the proper offset value by disassembling the routine that standard file passes to ModalDialog as its own filterProc.

The accessory will only work with the standard file and system folder distributed with the Macintosh Plus. The system folder distributed with the original HD-20 apparently does not contain the recent extensions to standard file. You can use the Mac Plus system folder on an original 512K Mac, but not on a 128K Mac. I'm using the system folder contained on the "Macintosh Plus Programmer's Package, Mac Disk 1, Jan 1986" distributed by Apple at the January Developers Conference. It works find in the startup drawer of my General Computer HyperDrive internal hard disk.

The following is the C language implementation of the Lost File Finder accessory. Since it contains no assembly language routines, it should be easy to port to your personal development system. One thing to watch out for, however, is that the accessory's open routine closes the accessory with a call on CloseDeskAcc. Make sure that your development system's desk accessory interface glue can handle this gracefully.


char keys[MAXKEYS + 1]; /* key buffer (pascal string) */

extern boolean getreplyeventfilter();

/* desk accessory open routine */
int accopen(dctl, pb)
 dctlentry *dctl;
 ptr pb;
 {
 point where;
 
 /* initialize state machine */
 state = NULLSTATE;
 *keys = 0;
 keywhen = 0l;
 
 /* display dialog */
 where.a.h = 82; 
 where.a.v = 50;
 sfpgetfile(&where, "", 0l, -1, 0l, 0l, &reply, -4000, &getreplyeventfilter);
 
 /* close ourselves */
 closedeskacc(dctl->dctlrefnum);
 
 return 0;
/*
 * lost file finder, version 1.0
 * find lost files with standard file
 *
 * copyright (c) 1986 by mike schuster for MacTutor.
 * all rights reserved.
 */

/* macintosh headers */
#include <acc.h> /* This file published last month  */
#include <dialog.h>
#include <device.h>
#include <event.h>
#include <qdvars.h>

/* c headers */
#include <string.h>
#include <ctype.h>

/* desk accessory header */
ACC
 (
 0x0400,/* accctl */
 0,/* no seconds */
 0,/* no events */
 0,/* no menu */
 16,    /* length */
 "Lost File Finder " /* title */
 )

/* standard file key event offset */
#define KEYOFFSET 4096

/* states for filtering machinery */
#define NULLSTATE 0
#define NEXTSTATE 1
#define SEARCHSTATE 2

/* standard cursor control keys */
#define NEXTKEY 0x1f
#define PREVKEY 0x1e
#define DOWNKEY -0x1f
#define UPKEY -0x1e
#define HOMEKEY 0x1d
#define SEARCHKEY ' '
#define QUITKEY '.'


#define isfile(reply) (reply)->fname[0]
 /* nonzero if file selected */
#define isfolder(reply) !(reply)->fname[0]   
 /* nonzero if folder selected */
#define isnull(reply) (!(reply)->ftype && !(reply)->fname[0]) 
 /* nonzero if nothing selected */
#define ISHFS (*(int *) 0x3f6 > 0) 
 /* nonzero if hfs installed */
#define SFFOLDER *(long *) 0x398   
 /* current standard file folder */
#define KEYTHRESH *(int *) 0x18e   
 /* keyboard repeat threshold */
#define ROOTFOLDER 2 
 /* directory id of root folder */

/* standard file reply typedef, with ftype defined as long */
typedef struct
 {
 boolean good;
 boolean copy;
 long ftype;
 int vrefnum;
 int version;
 char fname[64];
 } sfreply;

sfreply reply;   /* current standard file reply */
sfreply lastreply; /* last standard file reply */
sfreply startreply;/* starting standard file reply */
long startfolder;/* starting folder */
long searchfolder; /* folder to search for */
int state;/* current state of filtering machinery */

#define MAXKEYS 24 /* maximum length of key buffer */
long keywhen;    /* time of last keydown */
char keys[MAXKEYS + 1]; /* key buffer (pascal string) */


extern boolean getreplyeventfilter();

/* desk accessory open routine */
int accopen(dctl, pb)
 dctlentry *dctl;
 ptr pb;
 {
 point where;
 
 /* initialize state machine */
 state = NULLSTATE;
 *keys = 0;
 keywhen = 0l;
 
 /* display dialog */
 where.a.h = 82; 
 where.a.v = 50;
 sfpgetfile(&where, "", 0l, -1, 0l, 0l, &reply, -4000, &getreplyeventfilter);
 
 /* close ourselves */
 closedeskacc(dctl->dctlrefnum);
 
 return 0;
 }

/* null desk accessory close routine */
int accclose(dctl, pb)
 dctlentry *dctl;
 ptr pb;
 {
 return 0;
 }

/* null desk accessory control routine */
int accctl(dctl, pb)
 dctlentry *dctl;
 ptr pb;
 {
 return 0;
 }

/* null desk accessory prime routine */
int accprime(dctl, pb)
 dctlentry *dctl;
 ptr pb;
 {
 return 0;
 }

/* null desk accessory status routine */
int accstatus(dctl, pb)
 dctlentry *dctl;
 ptr pb;
 {
 return 0;
 }


/* case insensitive pascal string compare, return zero */
/* if equal. If prefix is nonzero, then a and b are equal  */
/* if a is a prefix of b */
int pstrcmp(a, b, prefix)
 register char *a;
 register char *b;
 int prefix;
 {
 register int n;
 
 if (prefix ? *a > *b : *a != *b)
 return 1;
 for (n = *a++ & 0xff, b++; n && tolower(*a++) == tolower(*b++); n--)
 ;
 return n;
 }

/* copy a standard file reply */
sfreply *replycpy(a, b)
 sfreply *a;
 sfreply *b;
 {
 blockmove(b, a, (long) sizeof(sfreply));
 return a;
 }

/* compare two standard file replies, return zero if equal */
int replycmp(a, b)
 sfreply *a;
 sfreply *b;
 {
 return (a->ftype == b->ftype) ? pstrcmp(a->fname, b->fname, 0) : 1;
 }

/* indicate a failure by sounding off */
int fail(thestate)
 int thestate;
 {
 sysbeep(4);
 return thestate;
 }

/* return a key to standard file, and update the current state */
int theitemhit(thedialog, itemhit, thekey, thestate)
 windowrecord *thedialog;
 int *itemhit;
 int thekey;
 int thestate;
 {
/* save synthetic event modifiers word in proper place */
*(int *) (thedialog->refcon - 624) = thekey < 0 ? cmdkey : 0;

/* return the desired key with the appropriate itemhit offset */
*itemhit = KEYOFFSET + (thekey < 0 ? -thekey : thekey);

 /* update the current state and return */
 state = thestate;
 return -1;
 }

/* get standard file reply event filter */
pascal boolean getreplyeventfilter(thedialog, theevent, itemhit)
 windowrecord *thedialog;
 eventrecord *theevent;
 int *itemhit;
 {
 int c;
 
 switch (theevent->what)
 {
 case nullevent:
 switch (state)
 {
 /* look for the last opened folder in parent's item list */
 /* change to NEXTSTATE when found */
 case SEARCHSTATE:
 if (isfolder(&reply) && reply.ftype == searchfolder)
 {
 replycpy(&lastreply, &reply);
 state = NEXTSTATE;
 }
 return theitemhit(thedialog, itemhit, NEXTKEY, state);
 break;
 
 /* search for candidate files */
 case NEXTSTATE:
 /* handle end of file/folder list */
 if (isnull(&reply) || !replycmp(&reply, &lastreply))
 {
 /* return to first item in list in a flat file catalog */
 if (!ISHFS)
 return theitemhit(thedialog, itemhit, HOMEKEY, fail(NULLSTATE));

 /* return to first item in list if in root of a hierarchical file catalog 
*/
 else if (SFFOLDER == ROOTFOLDER)
 {
 if (SFFOLDER == startfolder && !replycmp(&reply, &startreply))
 state = fail(NULLSTATE);
 replycpy(&lastreply, &reply);
 return theitemhit(thedialog, itemhit, HOMEKEY, state);
 }

 /* otherwise return to parent folder and search for current folder */
 else
 {
 searchfolder = SFFOLDER;
 return theitemhit(thedialog, itemhit, UPKEY, SEARCHSTATE);
 }
 }
 
 /* handle a selected file */
 else if (isfile(&reply))
 {
 /* check to see if complete catalog was searched */
 if (SFFOLDER == startfolder && !replycmp(&reply, &startreply))
 state = fail(NULLSTATE);

 /* check to see if a candiate was found */
 else if (!pstrcmp(keys, reply.fname, 1))
 state = NULLSTATE;

 /* otherwise, continue the search */
 else
 {
 replycpy(&lastreply, &reply);
 if (isnull(&startreply))
 replycpy(&startreply, &reply);
 return theitemhit(thedialog, itemhit, NEXTKEY, state);
 }
 }
 
 /* handle a selected folder */
 else
 {
 /* check to see if complete catalog was searched */
 if (reply.ftype == startfolder && !replycmp(&reply, &startreply))
 state = fail(NULLSTATE);

 /* otherwise, open the sibling folder and continue the search */
 else
 {
 if (isnull(&startreply))
 replycpy(&startreply, &reply);
 return theitemhit(thedialog, itemhit, DOWNKEY, state);
 }
 }
 break;
 default:
 break;
 }
 break;
 
     case keydown:
 /* handle keydown event */
 c = theevent->message & 0xff;
 
 /* if not command key, place in key buffer */
 if (!(theevent->modifiers & cmdkey))
 {
 /* reset buffer if threshold has expired */
 if (theevent->when > keywhen + KEYTHRESH)
 *keys = 0;
 
 /* add to key buffer */
 if ((*keys & 0xff) < MAXKEYS)
 {
 keys[(*keys & 0xff) + 1] = c;
 (*keys)++;
 }
 
 /* update time */
 keywhen = theevent->when;
 }
 
 /* handle the initiation of a search */
 else if (c == SEARCHKEY)
 {
 /* initialize last reply, starting folder and reply */
 replycpy(&lastreply, &reply);
 startfolder = SFFOLDER;
 replycpy(&startreply, &reply);
 
 /* force nextkey and initialize state machine */
 return theitemhit(thedialog, itemhit, NEXTKEY, NEXTSTATE);
 }
 
 /* handle the termination of a search */
 else if (c == QUITKEY)
 return theitemhit(thedialog, itemhit, NEXTKEY, fail(NULLSTATE));
 break;
 }
 return 0;
 }

A New Standard File

Since my global search requires the addition of a dialog hook, it can't be easily retrofitted into existing applications like MacWrite and MacPaint. The obvious solution is to append the filterProc code to the end of the standard file package resource and insert in the interface the appropriate interface calls to it. Of course, if a search capability were build directly into standard file, it might be nice, for speed, to avoid the dialog animation as the search proceeds.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

iClock Pro 3.8 - Customize your menubar...
iClock Pro is a menu-bar replacement for Apple's default clock. iClock Pro is an update, total rewrite, and improvement to the popular iClock. Have the day, date, and time in different fonts and... Read more
VirtualBox 5.2.0 - x86 virtualization so...
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers... Read more
Dropbox 37.4.29 - Cloud backup and synch...
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
Google Chrome 62.0.3202.62 - Modern and...
Google Chrome is a Web browser by Google, created to be a modern platform for Web pages and applications. It utilizes very fast loading of Web pages and has a V8 engine, which is a custom built... Read more
Chromium 62.0.3202.62 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. Version 62.0.3202.62: High CVE-2017-5124: UXSS with... Read more
Fantastical 2.4.3 - Create calendar even...
Fantastical 2 is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event... Read more
Things 3.2.1 - Elegant personal task man...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more
A Better Finder Attributes 6.06 - Change...
A Better Finder Attributes is the ultimate file-tweaking tool for OS X. It combines photo-shooting date and file date changing along with a few unique tricks of its own. Change EXIF Timestamps at... Read more
MacCleanse 6.0.5 - $29.95
MacCleanse is the product of thousands of hours of intense research and development. It meticulously scans all of the nooks and crannies of a computer for unnecessary junk that can take up huge... Read more
Smultron 10.0.2 - Easy-to-use, powerful...
Smultron 10 is an elegant and powerful text editor that is easy to use. You can use Smultron 10 to create or edit any text document. Everything from a web page, a note or a script to any single piece... Read more

4 of the best Halloween updates for mobi...
Halloween is certainly one of our favorite times for mobile game updates. Many popular titles celebrate this spooky season with fun festivities that can stretch from one week to even the whole month. As we draw closer and closer to Halloween, we'... | Read more »
Fire Rides guide - how to swing to succe...
It's another day, which means another Voodoo game has come to glue our hands to our mobile phones. Yes, it's been an especially prolific month for this particular mobile publisher, but we're certainly not complaining. Fire Rides is yet another... | Read more »
Time Recoil (Games)
Time Recoil 1.0.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.1 (iTunes) Description: Time Recoil is a top-down shooter where you kill to slow time, dominate slow motion gunfights, and trigger devastating special... | Read more »
Campfire Cooking (Games)
Campfire Cooking 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: | Read more »
Returner 77 (Games)
Returner 77 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Returner 77 is a cinematic space mystery puzzle game. You are in a giant alien spaceship hovering above Earth, after everything... | Read more »
Dune! guide - how to toe the line and ge...
Publisher Voodoo is at it again with an all new high score chaser -- Dune! In this fast-paced arcade game, you have to propel yourself along sand dunes, gaining enough momentum to jump above the line to score points, while making sure you have... | Read more »
The best deals on the App Store this wee...
Happy Tuesday, dear readers. Your favorite part of the week as officially arrived. It's time to take a look at the best deals in games. Things are admittedly a bit sparse, but there are a few diamonds in the rough to see you through if you're... | Read more »
Be the last person standing in Legacy of...
Yoozoo Games’ popular action MMO Legacy of Discord is getting a huge new update to celebrate its first anniversary. Perhaps the biggest change is the addition of an exciting survival mode titled Last Guardian. This new survival mode will pit you... | Read more »
Home Street guide - how to make friends...
From the creators of Food Street comes Home Street, a new simulation game that tasks you with building a social network and designing a beautiful home. It's a bit like The Sims, but you won't have to worry about the daily chores involved (feeding,... | Read more »
Color Ballz guide - how to bounce to the...
Color Ballz is an addictive new arcade title from Ketchapp Studios. It takes old school mechanics from games like Brickles and puts a fun twist on it. Your job? To catch balls with a paddle and send them back into a chute to be carried back to... | Read more »

Price Scanner via MacPrices.net

13″ MacBook Pros on sale for up to $120 off M...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for up to $120 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
15″ MacBook Pros on sale for up to $200 off M...
B&H Photo has 15″ MacBook Pros on sale for up to $200 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2249, $150... Read more
Roundup of Apple Certified Refurbished iMacs,...
Apple has a full line of Certified Refurbished 2017 21″ and 27″ iMacs available starting at $1019 and ranging up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free... Read more
Sale! 27″ 3.8GHz 5K iMac for $2098, save $201...
Amazon has the 27″ 3.8GHz 5K iMac (MNED2LL/A) on sale today for $2098 including free shipping. Their price is $201 off MSRP, and it’s the lowest price available for this model (Apple’s $1949... Read more
Sale! 10″ Apple WiFi iPad Pros for up to $100...
B&H Photo has 10.5″ WiFi iPad Pros in stock today and on sale for $50-$100 off MSRP. Each iPad includes free shipping, and B&H charges sales tax in NY & NJ only: – 10.5″ 64GB iPad Pro: $... Read more
Apple iMacs on sale for up to $130 off MSRP w...
B&H Photo has 21-inch and 27-inch iMacs in stock and on sale for up to $130 off MSRP including free shipping. B&H charges sales tax in NY & NJ only: – 27″ 3.8GHz iMac (MNED2LL/A): $2179 $... Read more
2017 3.5GHz 6-Core Mac Pro on sale for $2799,...
B&H Photo has the 2017 3.5GHz 6-Core Mac Pro (MD878LL/A) on sale today for $2799 including free shipping plus NY & NJ sales tax only . Their price is $200 off MSRP. Read more
12″ 1.2GHz Space Gray MacBook on sale for $11...
Amazon has the 2017 12″ 1.2GHz Space Gray Retina MacBook on sale for $100 off MSRP. Shipping is free: 12″ 1.2GHz Space Gray MacBook: $1199.99 $100 off MSRP Read more
Bare Bones Software Releases macOS High Sierr...
Bare Bones Software has announced the release and immediate availability of BBEdit 12.0, a significant upgrade to its professional strength text and code editor. BBEdit 12 introduces a new foundation... Read more
Yale Announces Availability of Apple HomeKit-...
Yale Locks & Hardware has announced that Apple HomeKit support for its Assure Lock family is available this month. The new Yale iM1 Network Module, which provides support for the Apple Home app... Read more

Jobs Board

*Apple* News Product Marketing Mgr., Publish...
Job Summary The Apple News Product Marketing Manager will work closely with a cross-functional group to assist in defining and marketing new features and services. Read more
Fraud Analyst, *Apple* Advertising Platform...
Job Summary Apple Ad Platforms has an opportunity to redefine advertising on mobile devices. Apple reaches hundreds of millions of iPhone, iPod touch, and iPad Read more
*Apple* Information Security - Security Data...
Job Summary This role is responsible for helping to strengthen Apple 's information security posture through the identification and curation of security event data. Read more
Lead *Apple* Solution Consultant - Apple In...
…develop a team of diverse partner employees focusing on excellence to deliver the Apple story. Even when you're not present, you will maintain a consistent influence Read more
watchOS Frameworks Engineering Manager, *App...
Job Summary Join the team that is shaping the future of software development for Apple Watch! Apple is looking for an exceptional software engineering leader to Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.