I am new in iPhone Please tell me anyone if i want to download 100 images at 1st time,then for 2 nd time in all 100 images only the 10 images will modified,i want to overwrite that 10 images how to do this??
At the first time synchronisation store synchronisation time. And pass this time in web service in next synchronisation. So, In this response you will get only those records which will updated after last synchronisation time and only update that images. But for this you have to add time tag in your web service.
If the server response giving the image attribute except url for e.g. let us consider image having unique ID .Then save imageurl and image id into dictionary while saving all the image i.e.during the first download .
If server has modification then in that response you will get modified images using some of the attribute. Now store that modified image id and download them .
Ot you can you follow the SO question answered here .
iOS - Download file only if modified (NSURL & NSData)
which has the code
I ended up using this method to detect the modified date on the file:
*Found on HERE
-(bool)isThumbnailModified:(NSURL *)thumbnailURL forFile:(NSString *)thumbnailFilePath{
// create a HTTP request to get the file information from the web server
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:thumbnailURL];
[request setHTTPMethod:#"HEAD"];
NSHTTPURLResponse* response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
// get the last modified info from the HTTP header
NSString* httpLastModified = nil;
if ([response respondsToSelector:#selector(allHeaderFields)])
{
httpLastModified = [[response allHeaderFields]
objectForKey:#"Last-Modified"];
}
// setup a date formatter to query the server file's modified date
// don't ask me about this part of the code ... it works, that's all I know :)
NSDateFormatter* df = [[NSDateFormatter alloc] init];
df.dateFormat = #"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
df.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
df.timeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
// get the file attributes to retrieve the local file's modified date
NSFileManager *fileManager = [NSFileManager defaultManager];
NSDictionary* fileAttributes = [fileManager attributesOfItemAtPath:thumbnailFilePath error:nil];
// test if the server file's date is later than the local file's date
NSDate* serverFileDate = [df dateFromString:httpLastModified];
NSDate* localFileDate = [fileAttributes fileModificationDate];
NSLog(#"Local File Date: %# Server File Date: %#",localFileDate,serverFileDate);
//If file doesn't exist, download it
if(localFileDate==nil){
return YES;
}
return ([localFileDate laterDate:serverFileDate] == serverFileDate);
}
Hope this will help.
First you have to track which images are modified and than download only those.
For that you have 2 ways :
1) You can set different name of the image at server side when it will be modified and than at the time of downloading first call one webservice that lists the name of images. Than compare those names with the downloaded images name (i.e which are in your document dir). If they are different than download else not.
2) You can make local database that stores information of previously downloaded images and at the 2nd time of downloading compare those values. If different than download else not .
Related
1) I want to download the data of any kind like the files of type .text, .png, .jpg, .docx, .xls, .pdf, .mp4, or whatever be the kind of files, Then i want to save it to the application sandboxs document directorys any of the sub directories that i have created under document directory of application sandbox.
2) Again whenever the user want to upload the files saved in the subdirectories of the application sandboxs document directory, The user will be able to browse through the data in the different directories of application sandboxs document directory, For that i have listed the data in the subdirectories of document directory of application sandbox in UITableView so that the user should be able to choose any of the file from the particular directory.
Problems/ things where i have stucked
I am using ASIHttpRequest for the upload and download , Where
1) For first need , means for downloading data i am using the methods -(void)grabURLInBackground to download the data from web and if its downloaded successfully then in the method -(void)requestFinished:(ASIHTTPRequest *)request i am saving that data to the subdirectory of the document directory of application sandbox with the particular name. The working code is below
-(void)grabURLInBackground
{
NSURL *url = [NSURL URLWithString:#"http://wordpress.org/plugins/about/readme.txt"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
NSLog(#"responseString:%#",responseString);
UIAlertView *alt = [[UIAlertView alloc] initWithTitle:#"Download Status" message:#"Download finished" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alt show];
//Use when fetching binary data
//NSData *responseData = [request responseData];
//NSLog(#"responseData:%#",responseData);
//For storing the data to the subdirectory of the document directory named Doc the following code is used.
NSArray *paths;
NSString *documentsDirectory,*docDirectoryPath,*docFilePath;
//NSString *imageCachePath,*imageDicPath;
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSLog(#"documentsDirectory:%#",documentsDirectory);
docDirectoryPath = [documentsDirectory stringByAppendingPathComponent:#"/Docs"];
NSLog(#"docDirectoryPath:%#",docDirectoryPath);
docFilePath = [docDirectoryPath stringByAppendingPathComponent:#"textFileTwo"];
NSLog(#"docFilePath:%#",docFilePath);
if (![[NSFileManager defaultManager] fileExistsAtPath:docFilePath])
[[NSFileManager defaultManager] createFileAtPath:docFilePath
contents:[NSData dataWithContentsOfFile:responseString]
attributes:nil];
//************************************//
Here what i want after the download finishes we have the two option the way to fetch the text data and the way to fetch the binary data, Thats what is the thing , Here in my case the data will be of any kind, And i want to save that to particular directory, I will save it on my own but i want the Unique way to fetch the any kind of data and to save it to particular directory .
//************************************//
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error];
NSLog(#"error:%#",error);
}
2) For the 2nd need means for the uploading data to any URL m using the same ASIHttpRequest like
-(void)uploadData {
//Suppose i want to upload the file that i have juz downloaded by the download code above.
// i fetched the path of the file i just saved with download code above, See the code below.
NSArray *paths;
NSString *documentsDirectory,*docDirectoryPath,*docFilePath;
//NSString *imageCachePath,*imageDicPath;
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSLog(#"documentsDirectory:%#",documentsDirectory);
docDirectoryPath = [documentsDirectory stringByAppendingPathComponent:#"/Docs"];
NSLog(#"docDirectoryPath:%#",docDirectoryPath);
docFilePath = [docDirectoryPath stringByAppendingPathComponent:#"textFileTwo"];
NSLog(#"docFilePath:%#",docFilePath);
// Upload Code
NSString *strURL = #"http://192.168.1.201/MyLegalNetMobile/MyLegalNetService.svc/FileUpload";
ASIFormDataRequest *uploadRequest = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:strURL]]; // Upload a file on disk
// Upload image data using asihttprequest
//UIImage *tempImg=[UIImage imageWithContentsOfFile:[NSString stringWithContentsOfURL:[NSURL URLWithString:imageCachePath] encoding:NSUTF8StringEncoding error:nil]];
//NSData *imageData1=UIImageJPEGRepresentation(tempImg, 1.0);
NSString *fetchedDataOfTxtFiles = [NSString stringWithContentsOfURL:[NSURL URLWithString:docFilePath] encoding:NSUTF8StringEncoding error:nil];
NSData *textData = [NSData dataWithContentsOfFile:fetchedDataOfTxtFiles];
NSLog(#"fetchedDataOfTxtFiles:%#",fetchedDataOfTxtFiles);
NSLog(#"textData:%#",textData);
[uploadRequest setData:textData withFileName:#"textFileTrialThree" andContentType:#"txt" forKey:#"txtData"];
[uploadRequest setRequestMethod:#"POST"];
[uploadRequest setDelegate:self];
[uploadRequest setTimeOutSeconds:10.0];
uploadRequest.shouldAttemptPersistentConnection = NO;
[uploadRequest setDidFinishSelector:#selector(uploadRequestFinished:)];
[uploadRequest setDidFailSelector:#selector(uploadRequestFailed:)];
[uploadRequest startAsynchronous];
//************************************//
Here again i have the different ways to upload the different kind of data, like for uploading the text data, different, ways is there same for the pdf, and image data is also, here i want the unique way to upload any kind of data to server, Also here I tried the image data uploading and text data uploading , Means i uploaded the files that i download from the any url. At the time of saving that downloaded files i converted them to NSData and saved to particular path of application sandboxs belonging directories. So while uploading again i got that path and for image data i converted the nsdata to uiimage , for the text file i only gave the path of file and uploaded the fiels to somewhere , The Files get uploaded on server, but there size was 0 bytes only, and the formate was different.
//************************************//
}
-(void)uploadRequestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
NSLog(#"Upload response %#", responseString);
}
-(void)uploadRequestFailed:(ASIHTTPRequest *)request{
NSLog(#" Error - Statistics file upload failed: \"%#\"",[[request error] localizedDescription]);
}
// Exact Problem.
/*
Any data that we download from the web using ASIHttpRequest before saving it to any path to application sandbox we convert some kind of data to NSData, And it get saved .
On the click of Browse button i have populated the data from different different subdirectories of the Document directory of the application sandbox in the UITableView, So I want to show the names of files with their extensions means with type that files were downloaded [as we save all data with converting to NSData it get saved with the names we give while saving only].
And then the time comes for the users to upload that data to any of the URL at that time also the files should get stored with their original formates means with which we downloaded the, */
To get list of files in directory try
- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error
To get file extension take a look on responce headers. They can contain ContentType which was downloaded.
why not use the request property called downloadDestinationPath?? If you use it, you don´t need to do anything in RequestFinished method because the ASIHTTPRequest library keeps the type of the files what you have downloaded.
The request finished method is always for doing something with the data you have downloaded, as parsing an html file for remove the html headers. If you don´t want to modify the file that you are downloading you should use this method for show download status only.
Edit the download path before start the request:
NSArray *paths;
NSString *documentsDirectory,*docDirectoryPath,*docFilePath;
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
docDirectoryPath = [documentsDirectory stringByAppendingPathComponent:#"Docs"];// Remove the "/" from the string paths because you are using "stringByAppendingPathComponent"
docFilePath = [docDirectoryPath stringByAppendingPathComponent:#"textFileTwo"];
request = [ASIHTTPRequest requestWithURL:YOUR URL];
[request setDownloadDestinationPath:docFilePath];
[request startAsynchronous];
To list the content:
NSArray *directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&error2];
for (int i = 0; i<[directoryContent count]; i++){
NSLog(#"content == %d", [directoryContent objectAtIndex:i];
}
I have searched and read the docs, but I cannot seem to find a solution to this (seemingly-simple) issue I've run into. I have songs exporting working fine from the user's iTunes library, and it downloads into the user's documents folder with no issues every time, but videos just don't seem to work.
I have it showing an MPMediaPickerController (allowsPickingMultipleItems = YES) to allow the user to select either videos or songs from their downloaded library. When done, here is the relavent code I'm using:
- (void)mediaPicker:(MPMediaPickerController*)mediaPicker didPickMediaItems:(MPMediaItemCollection*)mediaItemCollection {
AVAssetExportSession *exportSession;
for (MPMediaItem *item in mediaItemCollection.items) {
NSURL *assetUrl = [item valueForProperty:MPMediaItemPropertyAssetURL];
MPMediaType type = [[item valueForProperty:MPMediaItemPropertyMediaType] intValue];
if (type >= MPMediaTypeMovie) {
exportSession = [[AVAssetExportSession alloc] initWithAsset:[AVAsset assetWithURL:assetUrl] presetName:AVAssetExportPreset640x480];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
filePath = [title stringByAppendingString:#".mov"];
exportSession.outputURL = [NSURL fileURLWithPath:[[NSFileManager documentDirectory] stringByAppendingPathComponent:filePath]];
} // .. check for song-types here and set session up appropriately
[exportSession exportAsynchronouslyWithCompletionHandler:^{
// never gets into AVAssetExportSessionStatusCompleted here for videos
}
}
}
The error I get every time is the following:
Error Domain=AVFoundationErrorDomain Code=-11820 "Cannot Complete Export" UserInfo=0x1e1a2180 {NSLocalizedRecoverySuggestion=Try exporting again., NSLocalizedDescription=Cannot Complete Export}
Not very helpful. :( I feel like I may be potentially missing something obvious here. Am I going about this the correct way? Is it potentially a problem with me trying to "force" it to MOV-format? Or perhaps needing a different way of setting up the export session?
For reference, I'm using iOS 6.0.1 on my iPhone 5 for testing, with a baseSDK of 6.0. Thanks in advance for any guidance that can be offered on this!
Additional Info #1: something that's odd. It seems to crash immediately with a "SIGTRAP" if I set the outputFileType to "AVFileTypeAppleM4V".. I wanted to try M4V, because when I do a log output of the assetURL, I see something like: ipod-library://item/item.m4v?id=12345. Don't know if that makes a difference or not, but odd that it just crashes like that if I try m4v format. Probably because it's not in the supported filetypes list (see next info point).
Additional Info #2: The supported file types I get (from calling the "supportedFileTypes" method are: "com.apple.quicktime-movie" and "public.mpeg-4". The "exportPresetsCompatibleWithAsset" include all of the video ones, including m4a, low/med/high quality, and the specific dimensions ones. I have tried EVERY combination of all these, such as AVFileTypeQuickTimeMovie and AVFileTypeMPEG4 for fileTypes, and all of the presets, including the low/med/high, and all of the dimension ones. It never fails that I get the "Cannot Complete Export" error.
Additional Info #3: I am also using a Deployment Target of 5.1. But yes, I have tried 6.0, and it gives the same error. :(
Additional Info #4: If needed to know, the movie I'm testing with is a "Pilot" TV show, one video, the first one I saw in iTunes that was free. So I downloaded it for use in this app.
Additional Info #5: Not sure if this is important, but the "hasProtectedContent" method returns YES for the AVAsset (and AVURLAsset if I convert). May not make a difference, but thought I'd throw it out there.
After trying to replicate the issue and doing some testing, I strongly suspect the protected content is an issue. Here's why:
I copied your code, and tested it on my iPod Touch (5th gen, iOS 6.0.1), though instead of coming from a media picker, I just let it loop through all the videos I have on the device (7 of them.) It worked great, and called the completion handler and made proper .mov files in the documents directory of the app sandbox. I moved the .mov files to my Mac and they all played.
These video files had the hasProtectedContent as NO.
So I placed a video file I got from the iTunes store, and confirmed it had the hasProtectedContent as YES. Interestingly, when I try to get the URL from MPMediaItemPropertyAssetURL, I get nil for the protected/iTunes obtained video.
I strongly suspect the media protection is the problem.
Here's the variation of code that I used. I didn't change your conversion code at all, just how the URLs are supplied:
// select all the video files
MPMediaPropertyPredicate *predicate = [MPMediaPropertyPredicate predicateWithValue:[NSNumber numberWithInteger:MPMediaTypeMovie] forProperty:MPMediaItemPropertyMediaType];
MPMediaQuery *query = [[MPMediaQuery alloc] init];
[query addFilterPredicate:predicate];
NSArray *items = [query items];
// now go through them all to export them
NSString* title;
NSURL * url;
AVAssetExportSession *exportSession;
NSString *storePath;
AVAsset *theAsset;
// we fill put the output at this path
NSString *applicationDocumentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
// loop through the items and export
for (MPMediaItem* item in items)
{
title = [item valueForProperty:MPMediaItemPropertyTitle];
url = [item valueForProperty:MPMediaItemPropertyAssetURL];
NSLog(#"Title: %#, URL: %#",title,url);
theAsset = [AVAsset assetWithURL:url];
if ([theAsset hasProtectedContent]) {
NSLog(#"%# is protected.",title);
} else {
NSLog(#"%# is NOT protected.",title);
}
exportSession = [[AVAssetExportSession alloc] initWithAsset:theAsset presetName:AVAssetExportPreset640x480];
storePath = [applicationDocumentsDir stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mov",title]];
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
exportSession.outputURL = [NSURL fileURLWithPath:storePath];
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog(#"done!");
}];
}
Out of curiosity, are you checking the AVAsset exportable flag?
I have a plist file in my application data that i want to update from a webserver every 24 hours. Is there a way to check when the file is last modified or should i, in some way register the date and time when i update the file, and use that to compare to?
if (lastMod > currentDate){
[arrayFromXml writeToFile:path atomically:YES];
}
You can use NSFileManager for this:
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:#"path/to/my/file" error:nil];
NSDate *date = [attributes fileModificationDate];
// compare 'date'
// date > now
if ([date compareTo:[NSDate date]] == 1)
{
[arrayFromXML writeToFile:#"path/to/my/file" atomically:YES];
}
you can store the NSDate in NSUserDefaults when saving..and then compare it with current time to check the difference,,
using iphone sdk 4.0. The callback for an http request gives data as an NSData object
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the data received to our data
[theData appendData:data];
}
In my php script on the server i am returning an array as follows
var_dump($array).
How do i get my array back from the NSMutableData object 'theData' obove on my iphone.
Thanks
You have a string describing your array (or maybe several arrays?) stored as a sequence of bytes in your NSMutableData object. In order to turn it back into an array you're going to need to parse the var_dump output, which is likely to be arduous.
If you can find a library (or roll your own code) to return your data in Apple plist format, your task will be much easier: you can use
[NSPropertyListSerialization propertyListFromData:mutabilityOption:format:errorDescription:]
which takes an NSData (or NSMutableData) pointer as its first argument. Try http://code.google.com/p/cfpropertylist/ for a starting point.
From the example code at the cfpropertylist page:
$plist = new CFPropertyList();
$td = new CFTypeDetector();
$guessedStructure = $td->toCFType( $array );
$plist->add( $guessedStructure );
// and then return the plist content with
$plist->toXML()
and in your iOS code:
NSString *errorString = nil;
NSArray *array = [[NSPropertyListSerialization
propertyListFromData:theData
mutabilityOption:NSPropertyListImmutable
format:nil
errorDescription:&errorString] retain];
I would likely use YAJL on iOS, and $var = json_encode($array); in the PHP. Then in the iOS, I would parse that content from the NSData input like:
YAJLParser *parser = [[YAJLParser alloc] initWithParserOptions:YAJLParserOptionsAllowComments | YAJLParserOptionsCheckUTF8];
parser.delegate = [[[MyArrayParserDelegate alloc] init] autorelease];
[parser parse:data];
NSArray *thePhpArrayReceived = parser.delegate.resultantArray;
Please check out how to structure the delegate, and get YAJL here : Get YAJL + Readme
PHP outputs text so you will have to read that NSData as NSString and then parse out the array data according to the format specified by var_dump. As a starting point, the following code snippet should print out the array (as text) to your console:
NSString * dump = [[NSString alloc] initWithData:theData
encoding:NSUTF8StringEncoding];
NSLog(#"%#", dump);
[dump release];
As Seamus Campbell points out, there are better ways of doing this. Another option would be to output XML from your PHP script, and then use Cocoa's XML parsing methods to retreive the array.
Whenever I build & run my program I notice that a new directory gets created in:
/Users/Username/Library/Application Support/iPhone Simulator/User/Applications
Therefore, there's no way for me to persist core data between application builds. The way I thought to get around this issue (from a testing point of view) was to just use the iphone simulator to exit the application by pressing the circular menu button and re-run my app. I.e., not build it but just rerun it via the simulator to see if the data is persisted in core data.
Now I wanted to check if the data is persisting each time the application is run. The event that I'm using is:
(void)applicationDidFinishLaunching:(UIApplication *)application
But it only fires after I build & run the application but doesn't get fired each time i restart the application - via iphone simulator (i.e., pressing menu button then rerunning my program).
Is there another event I should be using?? If I had an event that gets fired every time the application loaded I think I could just check to see if core data has data in it, if it doesn't i just populate it with an xml file to initialize it, if it does have data I don't do anything. Sound right? If so, what is that event called?
-applicationDidFinishLaunching: will be called EVERY time your app launches, whether from the debugger, hitting the icon in the Springboard (launcher), or either of these on the device.
On the sim, a folder in the .../Applications directory is created for your app, and any data stored in there will be persisted. The actual name of the folder will change each time you build-and-run your app, but the contents will remain the same, so you can store data there.
Ben's right. The reason you aren't seeing -applicationDidFinishLaunching is because the debugger doesn't run when you launch from the simulator, the method is still firing.
It sounds like you're still early in the Core Data development process. You'd probably benefit from turning on Lightweight Migration.
NSError *error;
NSURL *storeURL = <#The URL of a persistent store#>;
NSPersistentStoreCoordinator *psc = <#The coordinator#>;
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![psc addPersistentStoreWithType:<#Store type#>
configuration:<#Configuration or nil#> URL:storeURL
options:options error:&error]) {
// Handle the error.
}
Instead of having to destroy your data store each time you make changes to the data model, this should allow Core Data to intelligently update the model for you.
Sorry this is a little off-topic, but I've spent a lot of time erasing and re-loading my data store because I didn't realize there was such a thing as this lightweight migration.
As vfn writes, you either need to attach the debugger or persist the log values to the disk.
I was doing OAuth and that requires the simulator to leave the app and do some authentication is Safari and then Safari will reopen the app using an URL Scheme. This meant I could not get a log of the different authentication steps logged after the app had quit.
Anyways, I wrote this class that will log messages to "log.txt" situated in ~/user*/library/application support/iPhone Simulator/user/yourapp*/documents
*user and yourapp is of course variable names.
//
// LogFile.m
//
//
// Created by RickiG on 11/30/09.
// Copyright 2009 www.rickigregersen.com.. All rights reserved.
//
#import "LogFile.h"
#implementation LogFile
+ (void) stringToLog:(NSString *) str {
NSDate *now = [NSDate date];
NSDateFormatter *logTimeFormatter = [[[NSDateFormatter alloc] init] autorelease];
[logTimeFormatter setDateFormat:#"HH:mm:ss"];
NSString *timeStr = [NSString stringWithFormat:#"%#", [logTimeFormatter stringFromDate:now]];
NSString *logMsg = [NSString stringWithFormat:#"%#\n%#\n\n", timeStr, str];
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path = [docsDirectory stringByAppendingPathComponent:#"log.txt"];
NSData *dataToWrite = [[NSString stringWithString:logMsg] dataUsingEncoding:NSUTF8StringEncoding];
// Check if file exists
NSFileManager *fileManager = [NSFileManager defaultManager];
if([fileManager fileExistsAtPath:path]) { // Returns a BOOL
NSData *dataFromFile = [[NSData alloc] initWithContentsOfFile:path];
NSMutableData *combinedDataToWrite = [NSMutableData dataWithData:dataFromFile];
[combinedDataToWrite appendData:dataToWrite];
[combinedDataToWrite writeToFile:path atomically:YES];
[dataFromFile release];
} else {
[fileManager createFileAtPath:path contents:dataToWrite attributes:nil];
}
}
#end
Have you tried working with
-(void)applicationDidBecomeActive {
}