File Metadata Search Programming Guide

File Metadata Search
Programming Guide
Contents
About File Metadata Queries 4
Who Should Read This Document 4
Organization of This Document 5
See Also 5
Searching iCloud and the Desktop 6
OS X Search Capabilities 6
iOS Search Capabilities 6
Searching File Metadata with NSMetadataQuery 7
Creating a Static File Metadata Search 7
Defining a Search 8
Setting the Query Search 8
Setting the Sort Order 8
Limiting the Search Scope 9
Running the Search 10
Accessing the Returned Results 10
The Completed Static Search 11
Creating a Live Search 13
File Metadata Query Expression Syntax 14
Comparison Syntax 14
Time and Date Variables 16
Displaying the Finder’s Spotlight Search Window 18
Document Revision History 19
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
2
Tables and Listings
Searching File Metadata with NSMetadataQuery 7
Table 2-1
Listing 2-1
Supported Search Scopes 9
Static Spotlight search implementation 11
File Metadata Query Expression Syntax 14
Table 3-1
Table 3-2
Table 3-3
Table 3-4
Table 3-5
Comparison operators 14
Value Comparison modifiers 15
Value Comparison modifier examples 15
Using wildcards 16
$time variable expressions 17
Displaying the Finder’s Spotlight Search Window 18
Listing 4-1
Displaying the Finder Search Window 18
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
3
About File Metadata Queries
File metadata provides several application programming interfaces that allow it application to search for files
based on data that is part of the file or file system. The level of interaction your application requires with the
search results will often dictate the API that you chose.
The simplest way to provide metadata support in your Mac app is to use the Spotlight search window. Using
this API an application can display the standard Spotlight search window, optionally providing a search string.
The search results are presented directly to the user and are not available to the application. This is a good
choice if your application isn't search oriented, but you want to allow users to search for contextual terms
using Spotlight.
For applications that need to create queries and interact with the results there are two APIs available. The
Metadata framework provides a low-level query API, MDQuery, that allows an application to search for files
based on metadata values. MDQuery is completely configurable, allowing you to run synchronous and
asynchronous queries and provides fine-grain control of the frequency of results batching.
The Cocoa frameworks's NSMetadataQuery class provides a high-level Objective-C interface to the MDQuery
API. This class allows you to construct queries using a subset of the NSPredicate classes, and execute the
queries asynchronously. The NSMetadataQuery class allows an application to specify the grouping of the
results into multiple subcategories. NSMetadataQuery does not support synchronous queries and provides
minimal update notifications as data is collected. On OS X NSMetadataQuery supports Cocoa bindings,
allowing you to display the results without writing any significant amount of glue code.
Note: iOS provides only the Objective-C metadata search interface. The procedural C version is only
available on OS X.
Who Should Read This Document
Spotlight is a fundamental feature of OS X, and all developers should be familiar with its capabilities. Many
applications, at a minimum, should offer users the ability to search for selected text using the Spotlight search
window.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
4
About File Metadata Queries
Organization of This Document
Organization of This Document
The following articles cover key concepts in understanding how Spotlight can be used to query metadata:
●
“Searching File Metadata with NSMetadataQuery ” (page 7) provides a conceptual overview of searching
for files using file metadata.
●
“Displaying the Finder’s Spotlight Search Window” (page 18) describes how to present the standard
Spotlight search window.
●
“File Metadata Query Expression Syntax” (page 14) describes the metadata query language.
See Also
There are other technologies, not fully covered in this document, that are fundamental to integrating metadata
into your applications. Refer to these documents for more details:
●
Spotlight Overview covers the conceptual details surrounding Spotlight’s metadata usage.
●
Spotlight Importer Programming Guide describes the plug-ins that extract metadata from document files.
●
File Metadata Attributes Reference describe the metadata attributes provided by Apple.
The following sample code is available that shows how to generate Spotlight queries.
●
Spotlighter examples shows how to use Spotlight searches.
●
PredicateEditorSample shows how to use the rule editor and Spotlight.
●
PhotoSearch allows the search of images based on name. It allows multiple searches to run simultaneously.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
5
Searching iCloud and the Desktop
The Spotlight search capabilities are available on both iOS v5.0 and OS X. Using these search queries iOS can
search iCloud content and OS X can search both iCloud, desktop, and networked files.
OS X Search Capabilities
Spotlight is ubiquitous on OS X. The Finder uses it to search for allow the user to search for files. Mail uses
Spotlight to find messages during the search process, and any application can use Spotlight to search the
User’s home directory, the local file system, any attached networked file systems, and iCloud.
The OS X Objective-C interface to the Spotlight API includes classes to search (NSMetadataQuery), inspect
the file metadata (NSMetadataItem), and the ability to have the NSMetadataQuery return a more complicated
set of data using the NSMetadataQueryAttributeValueTuple class. In addition a Core Foundation API
exists that correspond to each of the Objective-C classes (in fact the classes are built upon the Core Foundation
base.
Note: Relying on file metadata is extremely useful. It allows you to retrieve information about a
variety of file attributes, for example, video frame size, sound file compression, the Finder comment,
the author of the file, and much more without needing to know how to read format of the file. Note
that users’ are able to disable Spotlight on a per-volume or folder basis.
iOS Search Capabilities
iOS allows metadata searches within iCloud to find files corresponding files. It provides only the Objective-C
interface to file metadata query, NSMetadataQuery and NSMetadataItem, as well as only supporting the
search scope that searches iCloud.
Unlike the desktop, the iOS application’s sandbox is not searchable using the metadata classes. In order to
search your application’s sandbox, you will need to traverse the files within the sandbox file system recursively
using the NSFileManager class. Once matching file or files is found, you can access that file in the manner
that you require. You are also able to use the NSMedatataItem class to retrieve metadata for that particular
file.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
6
Searching File Metadata with NSMetadataQuery
In order for your application to search Spotlight metadata, you must create a query using the NSMetadataQuery
class provided by the Foundation framework. Queries can be run in two modes: asynchronous, and asynchronous
with live updates. The first simply performs the search on the files that exist at the time of the initial search.
The latter continues to search. updating the data as the files that fulfill or no longer fulfill the search parameters
update.
There are four main steps for executing an asynchronous metadata query:
●
Defining and initializing the search.
●
Initiating the search.
●
Listen for batch notifications.
●
Listening for the completion notification.
●
Stopping the query.
●
Processing results.
A live asynchronous Spotlight query allows your application to monitor the specified scope for changes that
happen ‘on the fly’. The only significant difference in the code is that rather than stopping the query, you
simply suspend the query while processing the results, and then resume the search when processing is
completed.
Creating a Static File Metadata Search
A static Spotlight search is a search that simply runs, returns the results and quits. it is intended as a one-time
search that does not monitor changes (which is possible using live searches, discussed in “Creating a Live
Search.”
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
7
Searching File Metadata with NSMetadataQuery
Creating a Static File Metadata Search
Defining a Search
The first step in creating a query is defining a search expression that returns the desired results. If you are using
MDMetadataQuery to execute the query, create your search expression predicate using the syntax described
in “File Metadata Query Expression Syntax” (page 14). You must register a notification to inform you as data
batches are returned and when the initial search is complete. You can also optionally register the scope, sorting,
and a delegate.
To define a search
1.
Create an NSMetadataQuery instance.
2.
Register to receive the NSMetadataQueryDidUpdateNotification notification which is sent when
batches of search content is returned.
This notification may not be generated depending on the batch value.
3.
Register to receive the NSMetadataQueryDidFinishGatheringNotification notification which
is sent when the initial search is completed.
Setting the Query Search
The search predicate is created using the syntax specified in “File Metadata Query Expression Syntax” (page
14). The fields that can be searched are defined in the File Metadata Attributes Reference . The attributes
references lists the available metadata keys and the type of data that you must supply to search that attribute
(a string, number, an array of strings, a date, or a Uniform Type Identifier.
To create the query
●
Create an NSPredicate instance with the appropriate Spotlight query expression.
Setting the Sort Order
If you are using NSMetadataQuery, you can specify the sort order of the results by providing an array of sort
descriptors. The sorting is based on the metadata attribute key of each returned NSMetadataItem object.
To set the search order
●
Create an NSSortDescriptor with the desired metadata key for sorting, in this case
kMDItemDisplayName.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
8
Searching File Metadata with NSMetadataQuery
Creating a Static File Metadata Search
Limiting the Search Scope
An application limits where search results are collected from by specifying a search scope. The search scope
is provided to the query as an array of predefined location constants, URLs, and directory paths. The predefined
location constants provide convenient values for restricting a query to the user's home directory, locally
mounted volumes and the user's home directory, or remote mounted volumes.
The search scopes specify where the metadata query searches for the files. Table 2-1 lists the available scopes.
Table 2-1
Supported Search Scopes
Scope Constant
Supported
Description
Operating
Systems
NSMetadataQueryUbiquitousDocumentsScope
iOS and OS X
Search all files in the Documents directories
of the application’s iCloud container
directories.
NSMetadataQueryUbiquitousDataScope
iOS and OS X
Search all files not in the Documents
directories of the application’s iCloud
container directories.
NSMetadataQueryNetworkScope
OS X
Search all user-mounted remote volumes.
NSMetadataQueryLocalComputerScope
OS X
Search all local mounted volumes, including
the user home directory. The user’s home
directory is searched even if it is a remote
volume.
NSMetadataQueryUserHomeScope
OS X
Search the user’s home directory.
The search scopes are specified as an array of the scope constants.
To specify the search scope
●
Send your instance of NSMetadataSearch a setSearchScopes: message, passing an array of the
appropriate scopes.
This query will search the User’s directory on the computer as well as the iCloud Documents folder.
This same search code could be run on iOS by simply removing the unsupported
NSMetadataQueryUserHomeScope scope constant.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
9
Searching File Metadata with NSMetadataQuery
Creating a Static File Metadata Search
Note: It is important to remember that on OS X, while file-system metadata is available on all
volumes, other metadata attributes are not. CDs, DVDs, disk images and System directories are not
indexed by Spotlight.
Users can also explicitly exclude results from being returned for specific directories and document
types by using Spotlight preferences. On iOS only the document types can be removed from the
search results using the Spotlight Search option in the Settings application under General -> Spotlight
Search.
Running the Search
Once you have created and configured a query object, you can execute the query itself. When running, a query
typically has two phases: an initial results gathering phase and a live-update phase.
During the initial results gathering phase, the existing Spotlight system store is searched for files that match
the search expression. The query sends notifications as the results are returned in batches using the
NSMetadataQueryDidUpdateNotification. In a single query this can be useful for indicating the state of
the search progress, while in live searches it becomes more important.
The query sends the application a NSMetadataQueryDidFinishGatheringNotification notification
when the initial results gathering phase has completed.
To run the search, send a startQuery message to your instance of NSMetadataSearch.
Accessing the Returned Results
Before your application interacts with the returned results, it must first stop the query. You can disable updates
during the initial gathering phase of a search or during the live-update phase.
An application determines the number of results that have been returned by invoking the NSMetadataQuery
instance method resultCount. The application then accesses individual result items by their indexed position.
Rather than traversing the results (which is intended for use with Cocoa Bindings), it is better to request the
result item at desired index using the resultAtIndex: method.
The result items are returned as an object instance of type NSMetadataItem. Each object encapsulates the
metadata attributes for the file. Your application then retrieves the metadata attributes from these items by
passing each instance a valueForAttribute: message with the name of the desired metadata attribute.
To access the results
1.
Stop the query that is in progress.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
10
Searching File Metadata with NSMetadataQuery
Creating a Static File Metadata Search
2.
Iterate over the results, performing whatever action is appropriate for your application.
3.
Remove the observers for the notifications.
This step is optional if you intend to run the query multiple times. However if you intend to use the
same setup code, you may wish to remove the observers regardless.
The Completed Static Search
“Creating a Static File Metadata Search” shows the code required to implement a static search.
Listing 2-1
Static Spotlight search implementation
// Initialize Search Method
- (void)initiateSearch
{
// Create the metadata query instance. The metadataSearch @property is
// declared as retain
self.metadataSearch=[[[NSMetadataQuery alloc] init] autorelease];
// Register the notifications for batch and completion updates
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(queryDidUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:metadataSearch];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(initalGatherComplete:)
name:NSMetadataQueryDidFinishGatheringNotification
object:metadataSearch];
// Configure the search predicate to find all images using the
// public.image UTI
NSPredicate *searchPredicate;
searchPredicate=[NSPredicate predicateWithFormat:@"kMDItemContentTypeTree ==
'public.image'"];
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
11
Searching File Metadata with NSMetadataQuery
Creating a Static File Metadata Search
[metadataSearch setPredicate:searchPredicate];
// Set the search scope. In this case it will search the User's home directory
// and the iCloud documents area
NSArray *searchScopes;
searchScopes=[NSArray arrayWithObjects:NSMetadataQueryUserHomeScope,
NSMetadataQueryUbiquitousDocumentsScope,nil];
[metadataSearch setSearchScopes:searchScopes];
// Configure the sorting of the results so it will order the results by the
// display name
NSSortDescriptor *sortKeys=[[[NSSortDescriptor alloc]
initWithKey:(id)kMDItemDisplayName
ascending:YES]
autorelease];
[metadataSearch setSortDescriptors:[NSArray arrayWithObject:sortKeys]];
// Begin the asynchronous query
[metadataSearch startQuery];
}
// Method invoked when notifications of content batches have been received
- (void)queryDidUpdate:sender;
{
NSLog(@"A data batch has been received");
}
// Method invoked when the initial query gathering is completed
- (void)initalGatherComplete:sender;
{
// Stop the query, the single pass is completed.
[metadataSearch stopQuery];
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
12
Searching File Metadata with NSMetadataQuery
Creating a Live Search
// Process the content. In this case the application simply
// iterates over the content, printing the display name key for
// each image
NSUInteger i=0;
for (i=0; i < [metadataSearch resultCount]; i++) {
NSMetadataItem *theResult = [metadataSearch resultAtIndex:i];
NSString *displayName = [theResult valueForAttribute:(NSString
*)kMDItemDisplayName];
NSLog(@"result at %lu - %@",i,displayName);
}
// Remove the notifications to clean up after ourselves.
// Also release the metadataQuery.
// When the Query is removed the query results are also lost.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidUpdateNotification
object:metadataSearch];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:metadataSearch];
self.metadataSearch=nil;
}
@end
Creating a Live Search
A live search is configured in a manner virtual to an identical search with only a small number of changes.
●
The query must be suspended using disableUpdates before accessing the updated data.
●
Data is typically handled in the queryDidUpdate: method in some form.
●
The query is then restarted using enableUpdates to continue the search.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
13
File Metadata Query Expression Syntax
File metadata queries are constructed using a query language that is a subset of the predicate string format.
The metadata search expression syntax allows an application to construct searches ‘on the fly’, allow advanced
users to construct their own queries, or your application to store often used queries for easy use. The syntax
is relatively straightforward, including comparisons, language agnostic options, and time and date variables.
Comparison Syntax
The file metadata query expression syntax is a simplified form of filename globbing familiar to shell users.
Queries have the following format:
attribute == value
where attribute is a standard metadata attribute (see “File Metadata Attributes Reference ”) or a custom
metadata attribute defined by an importer.
For example, to query Spotlight for all the files authored by “Steve” the query would look like the following:
kMDItemAuthors ==[c] "Steve"
The available comparison operators are listed in Table 3-1.
Table 3-1
Comparison operators
Operator
Description
==
equal
!=
not equal
<
less than (available for numeric values and dates only)
>
greater than (available for numeric values and dates only)
<=
less than or equal (available for numeric values and dates only)
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
14
File Metadata Query Expression Syntax
Comparison Syntax
Operator
Description
>=
greater than or equal (available for numeric values and dates only)
InRange(attributeName,minValue,maxValue)
numeric values within the range of minValue through maxValue in the
specified attributeName
Characters such as " and ‘ in the value string should be escaped using the \ character.
The search value in the example has the modifier “c”. These are modifiers specify how the comparison is made.
Table 3-2 describes the available comparison modifiers.
Search modifiers should immediately follow the comparison operator and be surrounded by square brackets
[…].
Table 3-2
Value Comparison modifiers
Modifier
Description
c
The comparison is case insensitive.
d
The comparison is insensitive to diacritical marks.
Table 3-3 shows several examples that use the comparison modifiers.
Table 3-3
Value Comparison modifier examples
Query string
Results
kMDItemTextContent == "Paris"
Matches “Paris” but not “paris”.
kMDItemTextContent ==[c] "Paris"
Matches “Paris” and “paris”.
kMDItemTextContent ==[c] "*Paris*"
Matches “Paris”, “paris”, “I love Paris”, and
“paris-france.jpg””.
kMDItemTextContent == "Frédéric"
Matches “Frédéric” but not “Frederic”.
kMDItemTextContent ==[d] "Frédéric"
Matches “Frédéric” and “Frederic” regardless of the
word case.
Using the wildcard characters (* and ? ) you can match substrings at the beginning of a string, end of a string,
or anywhere within the string. Table 3-4 shows several common usages.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
15
File Metadata Query Expression Syntax
Time and Date Variables
The * character matches multiple characters whereas the ? wildcard character matches a single character.
Table 3-4
Using wildcards
Query string
Result
kMDItemTextContent == "paris*"
Matches attribute values that begin with “paris”. For
example, matches “paris”, but not “comparison”.
kMDItemTextContent == "*paris"
Matches attribute values that end with “paris”.
kMDItemTextContent == "*paris*"
Matches attributes that contain "paris" anywhere within
the value. For example, matches “paris” and “comparison”.
kMDItemTextContent == "paris"
Matches attribute values that are exactly equal to “paris”.
Queries can be combined using a C-like syntax for AND (&&) and OR (||). For example, to restrict a query to
audio files authored by “Steve” the query would be:
kMDItemAuthors ==[c] "Steve" && kMDItemContentType == "public.audio"
Parenthesis can be used to further group query matching. For example, to search for audio files authored by
“Steve” or “Daniel” the query would be:
(kMDItemAuthors ==[c] "Daniel" || kMDItemAuthors[c] == "Steve") &&
kMDItemContentType == "public.audio"
You can expand this search to include video files using the following query:
(kMDItemAuthors ==[c] "Daniel" || kMDItemAuthors ==[c] "Steve" ) &&
(kMDItemContentType == "public.audio" || kMDItemContentType == "public.video")
Time and Date Variables
You can also create queries that use the date and time as the search value. The date and time value is formatted
as a floating-point value that is compatible with CFDate, seconds relative to January 1, 2001.
Additionally, the $time variable is provided that can be used to specify values relative to the current time, as
shown in Table 3-5.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
16
File Metadata Query Expression Syntax
Time and Date Variables
Table 3-5
$time variable expressions
Time variable
Description
$time.now
The current date and time.
$time.today
The current date.
$time.yesterday
Yesterday’s date.
$time.this_week(-1)
Dates in the previous week.
$time.this_week
Dates in the current week.
$time.this_month
Dates in the current month.
$time.this_year
Dates in the current year.
$time.now(NUMBER)
The date and time by adding a positive or negative value, in
seconds, to the current time.
$time.today(NUMBER)
The date by adding a positive or negative value, in days, to the
current day
$time.this_week(NUMBER)
Dates by adding a positive or negative value, in weeks, to the
current week.
$time.this_month(NUMBER)
Dates by adding a positive or negative value, in months, to the
current month.
$time.this_year(NUMBER)
Dates by adding a positive or negative value, in years, to the current
year.
$time.iso(ISO-8601-STR)
The date by parsing the specified ISO-8601-STR compliant string.
Using the $time variable you can restrict a search to find only files that have been changed in the last week
using the following query:
((kMDItemAuthors ==[c] "Daniel" || kMDItemAuthors[c] == "Steve") &&
(kMDItemContentType == "public.audio" || kMDItemContentType == "public.video"))
&&
(kMDItemFSContentChangeDate == $time.this_week(-1))
Note: The value of the $time variable is set when the query is first executed. It does not update to
the current time as the query continues to run.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
17
Displaying the Finder’s Spotlight Search Window
Applications can provide users direct interaction with Spotlight by displaying the standard Finder search
interface.
The NSWorkspace method showSearchResultsForQueryString: provides a simple interface to the Finder
search window. This is the programmatic equivalent of the user switching to Finder, creating a new window,
and typing the search string into the search field.
The code fragment in “Displaying the Finder’s Spotlight Search Window” demonstrates extracting a string
value and displaying the search interface.
Listing 4-1
Displaying the Finder Search Window
resultCode=[[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:[sender
stringValue]];
if (resultCode == NO) {
// failed to open the panel
// present an error to the user
}
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
18
Document Revision History
This table describes the changes to File Metadata Search Programming Guide .
Date
Notes
2011-09-28
Added iCloud and iOS information.
2010-04-12
Corrected query wording and updated several query examples.
2009-07-14
Corrected query syntax.
2009-05-27
Replaced HISearchWindowShow() function recommendation with new
NSWorkspace showSearchResultsForQueryString: method.
2006-03-08
Added $time.last_week to the query expression table.
2005-08-11
Added usage note about inRange query expression. Corrected minor
typos.
2005-04-29
Added conceptual article that describes how to create Spotlight queries.
Added usage note about $time to "Query Expression Format."
New document that describes how to add Spotlight searching to your
applications.
2011-09-28 | Copyright © 2011 Apple Inc. All Rights Reserved.
19
Apple Inc.
Copyright © 2011 Apple Inc.
All rights reserved.
No part of this publication may be reproduced,
stored in a retrieval system, or transmitted, in any
form or by any means, mechanical, electronic,
photocopying, recording, or otherwise, without
prior written permission of Apple Inc., with the
following exceptions: Any person is hereby
authorized to store documentation on a single
computer for personal use only and to print
copies of documentation for personal use
provided that the documentation contains
Apple’s copyright notice.
No licenses, express or implied, are granted with
respect to any of the technology described in this
document. Apple retains all intellectual property
rights associated with the technology described
in this document. This document is intended to
assist application developers to develop
applications only for Apple-labeled computers.
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
408-996-1010
Apple, the Apple logo, Cocoa, Finder, Mac,
Objective-C, OS X, and Spotlight are trademarks
of Apple Inc., registered in the U.S. and other
countries.
iCloud is a service mark of Apple Inc., registered
in the U.S. and other countries.
IOS is a trademark or registered trademark of
Cisco in the U.S. and other countries and is used
under license.
Even though Apple has reviewed this document,
APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS
DOCUMENT, ITS QUALITY, ACCURACY,
MERCHANTABILITY, OR FITNESS FOR A PARTICULAR
PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED
“AS IS,” AND YOU, THE READER, ARE ASSUMING THE
ENTIRE RISK AS TO ITS QUALITY AND ACCURACY.
IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES RESULTING FROM ANY DEFECT OR
INACCURACY IN THIS DOCUMENT, even if advised of
the possibility of such damages.
THE WARRANTY AND REMEDIES SET FORTH ABOVE
ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL
OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,
agent, or employee is authorized to make any
modification, extension, or addition to this warranty.
Some states do not allow the exclusion or limitation
of implied warranties or liability for incidental or
consequential damages, so the above limitation or
exclusion may not apply to you. This warranty gives
you specific legal rights, and you may also have other
rights which vary from state to state.