2016-09-07 17:35:04 +00:00
|
|
|
#import "RCTStatus.h"
|
2017-04-24 14:50:16 +00:00
|
|
|
#import "React/RCTBridge.h"
|
|
|
|
#import "React/RCTEventDispatcher.h"
|
2016-09-07 17:35:04 +00:00
|
|
|
#import <Statusgo/Statusgo.h>
|
|
|
|
|
2016-09-16 15:30:19 +00:00
|
|
|
static bool isStatusInitialized;
|
2016-10-11 14:24:52 +00:00
|
|
|
static RCTBridge *bridge;
|
2016-09-12 08:16:07 +00:00
|
|
|
@implementation Status{
|
|
|
|
}
|
|
|
|
|
2016-10-11 14:24:52 +00:00
|
|
|
-(RCTBridge *)bridge
|
|
|
|
{
|
|
|
|
return bridge;
|
|
|
|
}
|
|
|
|
|
|
|
|
-(void)setBridge:(RCTBridge *)newBridge
|
|
|
|
{
|
|
|
|
bridge = newBridge;
|
|
|
|
}
|
2016-09-07 17:35:04 +00:00
|
|
|
|
|
|
|
RCT_EXPORT_MODULE();
|
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - Jails functions
|
|
|
|
//////////////////////////////////////////////////////////////////// initJail
|
2016-09-07 17:35:04 +00:00
|
|
|
RCT_EXPORT_METHOD(initJail: (NSString *) js
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
2016-09-12 08:16:07 +00:00
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"InitJail() method called");
|
2016-09-12 08:16:07 +00:00
|
|
|
#endif
|
2016-09-23 14:14:43 +00:00
|
|
|
InitJail((char *) [js UTF8String]);
|
2016-09-07 17:35:04 +00:00
|
|
|
callback(@[[NSNull null]]);
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
//////////////////////////////////////////////////////////////////// parseJail
|
2016-09-07 17:35:04 +00:00
|
|
|
RCT_EXPORT_METHOD(parseJail:(NSString *)chatId
|
|
|
|
js:(NSString *)js
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"ParseJail() method called");
|
2016-09-07 17:35:04 +00:00
|
|
|
#endif
|
2016-09-23 14:14:43 +00:00
|
|
|
char * result = Parse((char *) [chatId UTF8String], (char *) [js UTF8String]);
|
2016-09-12 08:16:07 +00:00
|
|
|
callback(@[[NSString stringWithUTF8String: result]]);
|
2016-09-07 17:35:04 +00:00
|
|
|
}
|
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
//////////////////////////////////////////////////////////////////// callJail
|
2016-09-07 17:35:04 +00:00
|
|
|
RCT_EXPORT_METHOD(callJail:(NSString *)chatId
|
|
|
|
path:(NSString *)path
|
|
|
|
params:(NSString *)params
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"CallJail() method called");
|
2016-09-07 17:35:04 +00:00
|
|
|
#endif
|
2016-10-11 14:24:52 +00:00
|
|
|
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
|
|
char * result = Call((char *) [chatId UTF8String], (char *) [path UTF8String], (char *) [params UTF8String]);
|
|
|
|
dispatch_async( dispatch_get_main_queue(), ^{
|
|
|
|
callback(@[[NSString stringWithUTF8String: result]]);
|
|
|
|
});
|
|
|
|
});
|
2016-09-12 08:16:07 +00:00
|
|
|
}
|
|
|
|
|
2016-12-11 06:35:36 +00:00
|
|
|
|
|
|
|
const int STATE_ACTIVE = 0;
|
|
|
|
const int STATE_LOCKED_WITH_ACTIVE_APP = 1;
|
|
|
|
const int STATE_BACKGROUND = 2;
|
|
|
|
const int STATE_LOCKED_WITH_INACTIVE_APP = 3;
|
|
|
|
int wozniakConstant = STATE_ACTIVE;
|
|
|
|
|
|
|
|
|
|
|
|
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
|
|
|
|
{
|
|
|
|
// the "com.apple.springboard.lockcomplete" notification will always come after the "com.apple.springboard.lockstate" notification
|
|
|
|
CFStringRef nameCFString = (CFStringRef)name;
|
|
|
|
NSString *lockState = (__bridge NSString*)nameCFString;
|
|
|
|
NSLog(@"Darwin notification NAME = %@",name);
|
|
|
|
|
|
|
|
NSString* sm = [NSString stringWithFormat:@"%i", wozniakConstant];
|
|
|
|
NSString *s1 = [NSString stringWithFormat:@"%@ %@", @"LOCK MAGIC", sm];
|
|
|
|
NSLog(s1);
|
|
|
|
if([lockState isEqualToString:@"com.apple.springboard.lockcomplete"])
|
|
|
|
{
|
|
|
|
NSLog(@"DEVICE LOCKED");
|
|
|
|
// User locks phone when application is active
|
|
|
|
if(wozniakConstant == STATE_ACTIVE){
|
|
|
|
wozniakConstant = STATE_LOCKED_WITH_ACTIVE_APP;
|
|
|
|
StopNodeRPCServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Here lockcomplete event comes when app is unlocked
|
|
|
|
// because it couldn't come when locking happened
|
|
|
|
// as application was not active (it could not handle callback)
|
|
|
|
if (wozniakConstant == STATE_LOCKED_WITH_INACTIVE_APP) {
|
|
|
|
wozniakConstant = STATE_ACTIVE;
|
|
|
|
StopNodeRPCServer();
|
|
|
|
StartNodeRPCServer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSLog(@"LOCK STATUS CHANGED");
|
|
|
|
NSString *s = [NSString stringWithFormat:@"%@ %@", @"LOCK", lockState];
|
|
|
|
NSLog(s);
|
|
|
|
|
|
|
|
// if lockstate happens before lockcomplete it means
|
|
|
|
// that phone was locked when application was not active
|
|
|
|
if(wozniakConstant == STATE_ACTIVE){
|
|
|
|
wozniakConstant = STATE_LOCKED_WITH_INACTIVE_APP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(wozniakConstant == STATE_BACKGROUND){
|
|
|
|
wozniakConstant = STATE_ACTIVE;
|
|
|
|
StartNodeRPCServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
// one more lockstate event comes along with lockcomplete
|
|
|
|
// when phone is locked with active application
|
|
|
|
if(wozniakConstant == STATE_LOCKED_WITH_ACTIVE_APP){
|
|
|
|
wozniakConstant = STATE_BACKGROUND;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - startNode
|
|
|
|
//////////////////////////////////////////////////////////////////// startNode
|
2016-09-16 15:30:19 +00:00
|
|
|
RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
|
2016-09-12 08:16:07 +00:00
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"StartNode() method called");
|
2016-09-12 08:16:07 +00:00
|
|
|
#endif
|
|
|
|
if (!isStatusInitialized){
|
|
|
|
isStatusInitialized = true;
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
NSURL *folderName =[[[[NSFileManager defaultManager]
|
|
|
|
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
|
|
|
|
lastObject]
|
2017-03-18 13:45:54 +00:00
|
|
|
URLByAppendingPathComponent:@"ethereum/testnet"];
|
2016-09-12 08:16:07 +00:00
|
|
|
|
|
|
|
if (![[NSFileManager defaultManager] fileExistsAtPath:folderName.path])
|
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:folderName.path withIntermediateDirectories:NO attributes:nil error:&error];
|
2017-04-12 09:49:26 +00:00
|
|
|
NSURL *flagFolderUrl = [[[[NSFileManager defaultManager]
|
|
|
|
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
|
|
|
|
lastObject]
|
|
|
|
URLByAppendingPathComponent:@"ropsten_flag"];
|
2017-04-04 07:15:57 +00:00
|
|
|
|
2017-04-12 09:49:26 +00:00
|
|
|
if(![[NSFileManager defaultManager] fileExistsAtPath:flagFolderUrl.path]){
|
2017-04-04 07:15:57 +00:00
|
|
|
NSURL *lightChainData = [folderName URLByAppendingPathComponent:@"StatusIM/lightchaindata"];
|
|
|
|
[[NSFileManager defaultManager] removeItemAtPath:lightChainData.path
|
|
|
|
error:nil];
|
|
|
|
NSString *content = @"";
|
|
|
|
NSData *fileContents = [content dataUsingEncoding:NSUTF8StringEncoding];
|
2017-04-12 09:49:26 +00:00
|
|
|
[[NSFileManager defaultManager] createDirectoryAtPath:flagFolderUrl.path
|
|
|
|
withIntermediateDirectories:NO
|
|
|
|
attributes:nil
|
|
|
|
error:&error];
|
2017-04-04 07:15:57 +00:00
|
|
|
}
|
2016-09-12 08:16:07 +00:00
|
|
|
|
|
|
|
if (error){
|
|
|
|
NSLog(@"error %@", error);
|
|
|
|
}else
|
|
|
|
NSLog(@"folderName: %@", folderName);
|
2016-10-11 14:24:52 +00:00
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
|
|
|
|
^(void) {
|
2017-03-18 13:45:54 +00:00
|
|
|
char *config = GenerateConfig([folderName.path UTF8String], 3);
|
|
|
|
StartNode(config);
|
2016-09-12 08:16:07 +00:00
|
|
|
});
|
|
|
|
onResultCallback(@[[NSNull null]]);
|
2016-12-11 06:35:36 +00:00
|
|
|
//Screen lock notifications
|
|
|
|
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
|
|
|
|
NULL, // observer
|
|
|
|
displayStatusChanged, // callback
|
|
|
|
CFSTR("com.apple.springboard.lockcomplete"), // event name
|
|
|
|
NULL, // object
|
|
|
|
CFNotificationSuspensionBehaviorDeliverImmediately);
|
|
|
|
|
|
|
|
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
|
|
|
|
NULL, // observer
|
|
|
|
displayStatusChanged, // callback
|
|
|
|
CFSTR("com.apple.springboard.lockstate"), // event name
|
|
|
|
NULL, // object
|
|
|
|
CFNotificationSuspensionBehaviorDeliverImmediately);
|
2016-09-12 08:16:07 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-07 17:29:59 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - shouldMoveToInternalStorage
|
|
|
|
//////////////////////////////////////////////////////////////////// shouldMoveToInternalStorage
|
|
|
|
RCT_EXPORT_METHOD(shouldMoveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) {
|
|
|
|
// Android only
|
|
|
|
onResultCallback(@[[NSNull null]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - moveToInternalStorage
|
|
|
|
//////////////////////////////////////////////////////////////////// moveToInternalStorage
|
|
|
|
RCT_EXPORT_METHOD(moveToInternalStorage:(RCTResponseSenderBlock)onResultCallback) {
|
|
|
|
// Android only
|
|
|
|
onResultCallback(@[[NSNull null]]);
|
|
|
|
}
|
|
|
|
|
2016-12-11 06:35:36 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - StartNodeRPCServer method
|
|
|
|
//////////////////////////////////////////////////////////////////// createAccount
|
|
|
|
RCT_EXPORT_METHOD(startNodeRPCServer) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"StartNodeRPCServer() method called");
|
|
|
|
#endif
|
|
|
|
StartNodeRPCServer();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - StopNodeRPCServer method
|
|
|
|
//////////////////////////////////////////////////////////////////// createAccount
|
|
|
|
RCT_EXPORT_METHOD(stopNodeRPCServer) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"StopNodeRPCServer() method called");
|
|
|
|
#endif
|
|
|
|
StopNodeRPCServer();
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
RCT_EXPORT_METHOD(stopNode:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"stopNode() method called");
|
|
|
|
#endif
|
|
|
|
// TODO: stop node
|
|
|
|
|
|
|
|
callback(@[[NSNull null]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - Accounts method
|
|
|
|
//////////////////////////////////////////////////////////////////// createAccount
|
|
|
|
RCT_EXPORT_METHOD(createAccount:(NSString *)password
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"CreateAccount() method called");
|
2016-09-12 08:16:07 +00:00
|
|
|
#endif
|
|
|
|
char * result = CreateAccount((char *) [password UTF8String]);
|
|
|
|
callback(@[[NSString stringWithUTF8String: result]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////// recoverAccount
|
|
|
|
RCT_EXPORT_METHOD(recoverAccount:(NSString *)passphrase
|
|
|
|
password:(NSString *)password
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"RecoverAccount() method called");
|
2016-09-12 08:16:07 +00:00
|
|
|
#endif
|
|
|
|
char * result = RecoverAccount((char *) [password UTF8String], (char *) [passphrase UTF8String]);
|
|
|
|
callback(@[[NSString stringWithUTF8String: result]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////// login
|
|
|
|
RCT_EXPORT_METHOD(login:(NSString *)address
|
|
|
|
password:(NSString *)password
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
2016-09-23 14:14:43 +00:00
|
|
|
NSLog(@"Login() method called");
|
2016-09-12 08:16:07 +00:00
|
|
|
#endif
|
|
|
|
char * result = Login((char *) [address UTF8String], (char *) [password UTF8String]);
|
|
|
|
callback(@[[NSString stringWithUTF8String: result]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2017-04-25 01:51:52 +00:00
|
|
|
#pragma mark - Complete Transactions
|
|
|
|
//////////////////////////////////////////////////////////////////// completeTransactions
|
|
|
|
RCT_EXPORT_METHOD(completeTransactions:(NSString *)hashes
|
2016-09-12 08:16:07 +00:00
|
|
|
password:(NSString *)password
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
#if DEBUG
|
2017-04-25 01:51:52 +00:00
|
|
|
NSLog(@"CompleteTransactions() method called");
|
2016-09-12 08:16:07 +00:00
|
|
|
#endif
|
2017-04-25 01:51:52 +00:00
|
|
|
char * result = CompleteTransactions((char *) [hashes UTF8String], (char *) [password UTF8String]);
|
2016-09-12 08:16:07 +00:00
|
|
|
callback(@[[NSString stringWithUTF8String: result]]);
|
2016-09-07 17:35:04 +00:00
|
|
|
}
|
|
|
|
|
2016-11-01 16:08:16 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - Discard Transaction
|
2017-04-25 01:51:52 +00:00
|
|
|
//////////////////////////////////////////////////////////////////// discardTransaction
|
2016-11-01 16:08:16 +00:00
|
|
|
RCT_EXPORT_METHOD(discardTransaction:(NSString *)id) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"DiscardTransaction() method called");
|
|
|
|
#endif
|
|
|
|
DiscardTransaction((char *) [id UTF8String]);
|
|
|
|
}
|
|
|
|
|
2016-09-12 08:16:07 +00:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma mark - only android methods
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2016-09-07 17:35:04 +00:00
|
|
|
RCT_EXPORT_METHOD(setAdjustResize) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"setAdjustResize() works only on Android");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setAdjustPan) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"setAdjustPan() works only on Android");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) {
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"setSoftInputMode() works only on Android");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-01-16 21:16:55 +00:00
|
|
|
RCT_EXPORT_METHOD(clearCookies) {
|
|
|
|
NSHTTPCookie *cookie;
|
|
|
|
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
|
|
|
|
for (cookie in [storage cookies]) {
|
|
|
|
[storage deleteCookie:cookie];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RCT_EXPORT_METHOD(clearStorageAPIs) {
|
|
|
|
[[NSURLCache sharedURLCache] removeAllCachedResponses];
|
|
|
|
|
|
|
|
NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
|
|
|
|
NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
|
|
|
|
for (NSString *string in array) {
|
|
|
|
NSLog(@"Removing %@", [path stringByAppendingPathComponent:string]);
|
|
|
|
if ([[string pathExtension] isEqualToString:@"localstorage"])
|
|
|
|
[[NSFileManager defaultManager] removeItemAtPath:[path stringByAppendingPathComponent:string] error:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-18 14:22:05 +00:00
|
|
|
RCT_EXPORT_METHOD(sendWeb3Request:(NSString *)host
|
|
|
|
password:(NSString *)payload
|
|
|
|
callback:(RCTResponseSenderBlock)callback) {
|
|
|
|
|
|
|
|
NSData *postData = [payload dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
|
|
|
|
|
|
|
|
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
|
|
|
|
|
|
|
|
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
|
|
|
|
[request setURL:[NSURL URLWithString:host]];
|
|
|
|
[request setHTTPMethod:@"POST"];
|
|
|
|
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
|
|
|
|
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
|
|
|
[request setHTTPBody:postData];
|
|
|
|
[request setTimeoutInterval:310];
|
|
|
|
|
|
|
|
NSError *error;
|
|
|
|
|
|
|
|
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
|
|
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
|
|
|
|
|
|
|
|
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
|
|
NSString *strResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
|
|
NSString *trimmedResponse = [strResponse stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
|
|
|
|
|
|
callback(@[trimmedResponse]);
|
|
|
|
}];
|
|
|
|
|
|
|
|
[postDataTask resume];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-12-14 11:58:17 +00:00
|
|
|
+ (void)signalEvent:(const char *) signal
|
2016-10-11 14:24:52 +00:00
|
|
|
{
|
2016-11-09 10:40:17 +00:00
|
|
|
if(!signal){
|
2016-12-14 11:58:17 +00:00
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"SignalEvent nil");
|
|
|
|
#endif
|
2016-11-09 10:40:17 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-12-14 11:58:17 +00:00
|
|
|
|
2016-10-11 14:24:52 +00:00
|
|
|
NSString *sig = [NSString stringWithUTF8String:signal];
|
|
|
|
#if DEBUG
|
|
|
|
NSLog(@"SignalEvent");
|
|
|
|
NSLog(sig);
|
|
|
|
#endif
|
|
|
|
[bridge.eventDispatcher sendAppEventWithName:@"gethEvent"
|
|
|
|
body:@{@"jsonEvent": sig}];
|
2016-12-14 11:58:17 +00:00
|
|
|
|
|
|
|
return;
|
2016-10-11 14:24:52 +00:00
|
|
|
}
|
|
|
|
|
2016-09-07 17:35:04 +00:00
|
|
|
@end
|