rhodes 2.4.0 → 2.4.1.beta.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ ## 2.4.1
2
+ * iPhone: fix production build
3
+ * Android: fix 2.1 version
4
+ * Sync: do not stop sync on source with pending create objects
5
+
1
6
  ## 2.4
2
7
  * Android: support old sdk(s)
3
8
  * Blackberry: encryption for hsql database
@@ -1,6 +1,6 @@
1
1
  module Rhodes
2
2
  unless defined? Rhodes::VERSION
3
- VERSION = '2.4.0'
3
+ VERSION = '2.4.1'
4
4
  end
5
5
  unless defined? Rhodes::DBVERSION
6
6
  DBVERSION = '2.2.0'
@@ -1,6 +1,6 @@
1
1
  module RhodesFramework
2
2
  unless defined? RhodesFramework::VERSION
3
- VERSION = '2.4.0'
3
+ VERSION = '2.4.1'
4
4
  end
5
5
  unless defined? RhodesFramework::DBVERSION
6
6
  DBVERSION = '2.2.2'
data/lib/rhodes.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Rhodes
2
2
  unless defined? Rhodes::VERSION
3
- VERSION = '2.4.0'
3
+ VERSION = '2.4.1'
4
4
  end
5
5
  unless defined? Rhodes::DBVERSION
6
6
  DBVERSION = '2.2.0'
@@ -2,8 +2,8 @@
2
2
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
3
  package="com.rhomobile.rhodes"
4
4
  android:installLocation="auto"
5
- android:versionCode="30"
6
- android:versionName="2.4.0">
5
+ android:versionCode="31"
6
+ android:versionName="2.4.1">
7
7
 
8
8
  <uses-sdk android:minSdkVersion="4" />
9
9
 
@@ -564,9 +564,9 @@ RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_RhodesService_doSyncSource
564
564
  }
565
565
 
566
566
  RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_RhodesApplication_setStartParameters
567
- (JNIEnv *, jclass, jstring strUrl)
567
+ (JNIEnv *env, jclass, jstring strUrl)
568
568
  {
569
- std::string const &url = rho_cast<std::string>(strUrl);
569
+ std::string url = rho_cast<std::string>(env, strUrl);
570
570
  RHODESAPP().setStartParameters(url.c_str());
571
571
  }
572
572
 
@@ -76,19 +76,6 @@ public class RhodesActivity extends BaseActivity {
76
76
  Thread ct = Thread.currentThread();
77
77
  //ct.setPriority(Thread.MAX_PRIORITY);
78
78
  uiThreadId = ct.getId();
79
-
80
- Intent intent = getIntent();
81
- //intent.putExtra(RHO_URL_START_KEY, "/app/BrowserStart");
82
- //intent.putExtra(RHO_URL_PARAMS_KEY, "param1=value1&param2=value2");
83
- //Log.d(TAG, "MY URI: " + intent.toUri(Intent.URI_INTENT_SCHEME));
84
-
85
- // Check if we really started through URI
86
- if(intent.getData() != null)
87
- {
88
- //Workaround to get URI string from intent since intent.getData() badly initialized
89
- Log.d(TAG, "Application URI: " + intent.toUri(0));
90
- RhodesApplication.setStartParameters(intent.toUri(0).toString());
91
- }
92
79
 
93
80
  if (!RhodesService.isEnableTitle()) {
94
81
  requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -356,30 +343,34 @@ public class RhodesActivity extends BaseActivity {
356
343
  @Override
357
344
  public void onServiceConnected(ComponentName name, IBinder service) {
358
345
  super.onServiceConnected(name, service);
359
-
360
- Bundle startParams = null;
361
- Object params = getIntent().getExtras();
362
- if (params != null && params instanceof Bundle)
363
- startParams = (Bundle)params;
364
-
365
- String rhoStartParams = null;
366
- if (startParams != null)
367
- rhoStartParams = startParams.getString(RHO_START_PARAMS_KEY);
368
- if (rhoStartParams == null)
369
- rhoStartParams = "";
370
-
371
- if (!RhodesService.canStartApp(rhoStartParams, ", ")) {
372
- Logger.E(TAG, "This is hidden app and can be started only with security key.");
373
- getRhodesApplication().exit();
374
- return;
375
- }
376
-
377
- String urlStart = startParams == null ? null : startParams.getString(RHO_URL_START_KEY);
378
- if (urlStart != null) {
379
- Logger.D(TAG, "PROCESS URL START: " + urlStart);
380
- RhoConf.setString("start_path", Uri.decode(urlStart));
381
- }
382
-
346
+
347
+ Logger.D(TAG, "onServiceConnected: " + name.toShortString());
348
+
349
+ Intent intent = getIntent();
350
+ String startParams = (intent.getData() != null) ? intent.toUri(0) : "";
351
+ Uri uri = Uri.parse(startParams);
352
+ String scheme = uri.getScheme();
353
+ if(startParams.compareTo("") != 0)
354
+ {
355
+ startParams = startParams.substring(scheme.length() + 1);
356
+ if(startParams.startsWith("//"))
357
+ startParams = startParams.substring(2);
358
+ }
359
+
360
+ if(!RhodesService.canStartApp(startParams, "&#"))
361
+ {
362
+ Logger.E(TAG, "This is hidden app and can be started only with security key.");
363
+ getRhodesApplication().exit();
364
+ return;
365
+ }
366
+
367
+ String urlStart = uri.getPath();
368
+ if (urlStart.compareTo("") != 0)
369
+ {
370
+ Logger.D(TAG, "PROCESS URL START: " + urlStart);
371
+ RhoConf.setString("start_path", Uri.decode(urlStart));
372
+ }
373
+
383
374
  ENABLE_LOADING_INDICATION = !RhoConf.getBool("disable_loading_indication");
384
375
  }
385
376
 
@@ -39,7 +39,7 @@ def setup_ndk(ndkpath,apilevel)
39
39
  $ndktools = nil
40
40
  $ndkabi = "unknown"
41
41
  $ndkgccver = "unknown"
42
- ["arm-linux-androideabi-4.4.3", "arm-eabi-4.4.0", "arm-eabi-4.2.1"].each do |abi|
42
+ ["arm-eabi-4.4.0", "arm-eabi-4.2.1"].each do |abi|
43
43
  variants = []
44
44
  variants << File.join(ndkpath, "toolchains", abi, "prebuilt", $ndkhost)
45
45
  variants << File.join(ndkpath, "build/prebuilt", $ndkhost, abi)
@@ -578,7 +578,7 @@ public class SyncEngine implements NetRequest.IRhoSession
578
578
  {
579
579
  Hashtable/*<String, int>*/ hashPassed = new Hashtable();
580
580
 
581
- for( int nCurSrc = m_sources.size()-1; nCurSrc > 0 ; )
581
+ for( int nCurSrc = m_sources.size()-1; nCurSrc >= 0 ; )
582
582
  {
583
583
  SyncSource oCurSrc = (SyncSource)m_sources.elementAt(nCurSrc);
584
584
  if ( oCurSrc.getAssociations().size() == 0 || hashPassed.containsKey(oCurSrc.getName()) )
@@ -590,6 +590,9 @@ public class SyncEngine implements NetRequest.IRhoSession
590
590
  {
591
591
  SyncSource.CAssociation oAssoc = (SyncSource.CAssociation)oCurSrc.getAssociations().elementAt(i);
592
592
  int nAssocSrcIndex = findSrcIndex( m_sources, oAssoc.m_strSrcName);
593
+ if ( nAssocSrcIndex >= 0 )
594
+ ((SyncSource)m_sources.elementAt(nAssocSrcIndex)).addBelongsTo( oAssoc.m_strAttrib, oCurSrc.getID() );
595
+
593
596
  if ( nAssocSrcIndex >=0 && nAssocSrcIndex < nSrc )
594
597
  {
595
598
  m_sources.removeElementAt( nSrc );
@@ -91,6 +91,8 @@ public class SyncSource
91
91
  Vector/*<CAssociation>*/ m_arAssociations = new Vector();
92
92
  Vector/*Ptr<net::CMultipartItem*>*/ m_arMultipartItems = new Vector();
93
93
  Vector/*<String>*/ m_arBlobAttrs = new Vector();
94
+ Hashtable/*<String,int>*/ m_hashIgnorePushObjects = new Hashtable();
95
+ Hashtable/*<String,int>*/ m_hashBelongsTo = new Hashtable();
94
96
 
95
97
  Integer getID() { return m_nID; }
96
98
  String getName() { return m_strName; }
@@ -215,10 +217,14 @@ public class SyncSource
215
217
  {
216
218
  if ( isEmptyToken() )
217
219
  processToken(1);
218
-
220
+
221
+ syncClientChanges();
222
+ syncServerChanges();
223
+ /*
219
224
  boolean bSyncedServer = syncClientChanges();
220
225
  if ( !bSyncedServer )
221
226
  syncServerChanges();
227
+ */
222
228
  }
223
229
  }catch(Exception exc)
224
230
  {
@@ -233,7 +239,23 @@ public class SyncSource
233
239
  new Integer(m_bGetAtLeastOnePage?1:0), new Integer(m_nRefreshTime), getID() );
234
240
  }
235
241
  }
242
+
243
+ void syncClientChanges()throws Exception
244
+ {
245
+ PROF.START("Pull");
246
+
247
+ boolean bSyncClient = false;
248
+ {
249
+ IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? and sent<=1 LIMIT 1 OFFSET 0", getID());
250
+ bSyncClient = !res.isEnd();
251
+ }
252
+ if ( bSyncClient )
253
+ doSyncClientChanges();
236
254
 
255
+ PROF.STOP("Pull");
256
+ }
257
+
258
+ /*
237
259
  boolean syncClientChanges()throws Exception
238
260
  {
239
261
  boolean bSyncedServer = false;
@@ -274,8 +296,69 @@ public class SyncSource
274
296
  {
275
297
  IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? and update_type='create' and sent>1 LIMIT 1 OFFSET 0", getID());
276
298
  return !res.isEnd();
299
+ }*/
300
+
301
+ void addBelongsTo(String strAttrib, Integer nSrcID)
302
+ {
303
+ m_hashBelongsTo.put(strAttrib, nSrcID);
304
+ }
305
+
306
+ Integer getBelongsToSrcID(String strAttrib)
307
+ {
308
+ if ( m_hashBelongsTo.containsKey(strAttrib) )
309
+ return (Integer)m_hashBelongsTo.get(strAttrib);
310
+
311
+ return new Integer(-1);
277
312
  }
278
313
 
314
+ void checkIgnorePushObjects()throws Exception
315
+ {
316
+ // ignore changes in pending creates
317
+ {
318
+ IDBResult res = getDB().executeSQL("SELECT distinct(object) FROM changed_values where source_id=? and sent>=2", getID() );
319
+ for( ; !res.isEnd(); res.next() )
320
+ {
321
+ String strObject = res.getStringByIdx(0);
322
+ m_hashIgnorePushObjects.put(strObject, new Integer(1));
323
+ }
324
+ }
325
+
326
+ //check for belongs_to
327
+ String strAttribQuests = "";
328
+ Vector/*<String>*/ arValues = new Vector();
329
+ arValues.addElement(getID());
330
+ Enumeration keys = m_hashBelongsTo.keys();
331
+ while (keys.hasMoreElements())
332
+ {
333
+ if ( strAttribQuests.length() > 0 )
334
+ strAttribQuests += ",";
335
+
336
+ strAttribQuests += "?";
337
+ arValues.addElement(keys.nextElement());
338
+ }
339
+
340
+ if ( strAttribQuests.length() > 0 )
341
+ {
342
+ IDBResult res = getDB().executeSQLEx( "SELECT object, attrib, value FROM changed_values where source_id=? and sent<=1 and attrib IN ( " + strAttribQuests + " )",
343
+ arValues );
344
+
345
+ for( ; !res.isEnd(); res.next() )
346
+ {
347
+ String strObject = res.getStringByIdx(0);
348
+ String strAttrib = res.getStringByIdx(1);
349
+ String strValue = res.getStringByIdx(2);
350
+
351
+ IDBResult res2 = getDB().executeSQL(
352
+ "SELECT object FROM changed_values where source_id=? and sent>=2 and object=? LIMIT 1 OFFSET 0",
353
+ getBelongsToSrcID(strAttrib), strValue );
354
+
355
+ if (!res2.isEnd())
356
+ m_hashIgnorePushObjects.put(strObject, new Integer(1) );
357
+
358
+ }
359
+ }
360
+ }
361
+
279
362
  void doSyncClientChanges()throws Exception
280
363
  {
281
364
  String arUpdateTypes[] = {"create", "update", "delete"};
@@ -286,32 +369,41 @@ public class SyncSource
286
369
  String strBody = "{\"source_name\":" + JSONEntry.quoteValue(getName()) + ",\"client_id\":" + JSONEntry.quoteValue(getSync().getClientID());
287
370
  boolean bSend = false;
288
371
  int i = 0;
289
- for( i = 0; i < 3 && getSync().isContinueSync(); i++ )
372
+
373
+ getDB().Lock();
374
+ try{
375
+ checkIgnorePushObjects();
376
+
377
+ for( i = 0; i < 3 && getSync().isContinueSync(); i++ )
378
+ {
379
+ String strBody1;
380
+ strBody1 = makePushBody_Ver3(arUpdateTypes[i], true);
381
+ if (strBody1.length() > 0)
382
+ {
383
+ strBody += "," + strBody1;
384
+
385
+ String strBlobAttrs = "";
386
+ for ( int j = 0; j < (int)m_arBlobAttrs.size(); j++)
387
+ {
388
+ if ( strBlobAttrs.length() > 0 )
389
+ strBlobAttrs += ",";
390
+
391
+ strBlobAttrs += JSONEntry.quoteValue((String)m_arBlobAttrs.elementAt(j));
392
+ }
393
+
394
+ if ( strBlobAttrs.length() > 0 )
395
+ strBody += ",\"blob_fields\":[" + strBlobAttrs + "]";
396
+
397
+ arUpdateSent[i] = true;
398
+ bSend = true;
399
+ }
400
+ }
401
+ strBody += "}";
402
+ }finally
290
403
  {
291
- String strBody1;
292
- strBody1 = makePushBody_Ver3(arUpdateTypes[i], true);
293
- if (strBody1.length() > 0)
294
- {
295
- strBody += "," + strBody1;
296
-
297
- String strBlobAttrs = "";
298
- for ( int j = 0; j < (int)m_arBlobAttrs.size(); j++)
299
- {
300
- if ( strBlobAttrs.length() > 0 )
301
- strBlobAttrs += ",";
302
-
303
- strBlobAttrs += JSONEntry.quoteValue((String)m_arBlobAttrs.elementAt(j));
304
- }
305
-
306
- if ( strBlobAttrs.length() > 0 )
307
- strBody += ",\"blob_fields\":[" + strBlobAttrs + "]";
308
-
309
- arUpdateSent[i] = true;
310
- bSend = true;
311
- }
404
+ getDB().Unlock();
312
405
  }
313
- strBody += "}";
314
-
406
+
315
407
  if ( bSend )
316
408
  {
317
409
  LOG.INFO( "Push client changes to server. Source: " + getName() + "Size :" + strBody.length() );
@@ -399,6 +491,9 @@ public class SyncSource
399
491
  String value = res.getStringByIdx(2);
400
492
  String attribType = res.getStringByIdx(3);
401
493
 
494
+ if ( m_hashIgnorePushObjects.containsKey(strObject) )
495
+ continue;
496
+
402
497
  if ( attribType.compareTo("blob.file") == 0 )
403
498
  {
404
499
  MultipartItem oItem = new MultipartItem();
@@ -38,7 +38,7 @@
38
38
  <key>CFBundleSignature</key>
39
39
  <string>????</string>
40
40
  <key>CFBundleVersion</key>
41
- <string>2.4.0</string>
41
+ <string>2.4.1</string>
42
42
  <key>LSRequiresIPhoneOS</key>
43
43
  <true/>
44
44
  <key>UILaunchImageFile</key>
@@ -471,6 +471,7 @@
471
471
  );
472
472
  PRODUCT_NAME = rholib;
473
473
  SDKROOT = iphoneos;
474
+ SKIP_INSTALL = YES;
474
475
  SYMROOT = ../build;
475
476
  USER_HEADER_SEARCH_PATHS = "../../shared/curl/include ../../shared";
476
477
  };
@@ -491,6 +492,7 @@
491
492
  );
492
493
  PRODUCT_NAME = rholib;
493
494
  SDKROOT = iphoneos;
495
+ SKIP_INSTALL = YES;
494
496
  SYMROOT = ../build;
495
497
  USER_HEADER_SEARCH_PATHS = "../../shared/curl/include ../../shared";
496
498
  };
@@ -552,6 +554,7 @@
552
554
  );
553
555
  PRODUCT_NAME = rholib;
554
556
  SDKROOT = iphoneos;
557
+ SKIP_INSTALL = YES;
555
558
  SYMROOT = ../build;
556
559
  USER_HEADER_SEARCH_PATHS = "../../shared/curl/include ../../shared";
557
560
  };
@@ -643,7 +643,11 @@
643
643
  isa = PBXProject;
644
644
  buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "curl" */;
645
645
  compatibilityVersion = "Xcode 3.1";
646
+ developmentRegion = English;
646
647
  hasScannedForEncodings = 1;
648
+ knownRegions = (
649
+ en,
650
+ );
647
651
  mainGroup = 08FB7794FE84155DC02AAC07 /* curl */;
648
652
  projectDirPath = "";
649
653
  projectRoot = "";
@@ -757,7 +761,9 @@
757
761
  );
758
762
  PRODUCT_NAME = curl;
759
763
  SDKROOT = iphoneos;
764
+ SKIP_INSTALL = YES;
760
765
  SYMROOT = ../build;
766
+ TARGETED_DEVICE_FAMILY = "1,2";
761
767
  };
762
768
  name = Debug;
763
769
  };
@@ -775,7 +781,9 @@
775
781
  );
776
782
  PRODUCT_NAME = curl;
777
783
  SDKROOT = iphoneos;
784
+ SKIP_INSTALL = YES;
778
785
  SYMROOT = ../build;
786
+ TARGETED_DEVICE_FAMILY = "1,2";
779
787
  };
780
788
  name = Release;
781
789
  };
@@ -834,7 +842,9 @@
834
842
  );
835
843
  PRODUCT_NAME = curl;
836
844
  SDKROOT = iphoneos;
845
+ SKIP_INSTALL = YES;
837
846
  SYMROOT = ../build;
847
+ TARGETED_DEVICE_FAMILY = "1,2";
838
848
  };
839
849
  name = Distribution;
840
850
  };
@@ -119,7 +119,11 @@
119
119
  isa = PBXProject;
120
120
  buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "rhoextlib" */;
121
121
  compatibilityVersion = "Xcode 3.1";
122
+ developmentRegion = English;
122
123
  hasScannedForEncodings = 1;
124
+ knownRegions = (
125
+ en,
126
+ );
123
127
  mainGroup = 0867D691FE84028FC02AAC07 /* rhoextlib */;
124
128
  productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
125
129
  projectDirPath = "";
@@ -161,6 +165,7 @@
161
165
  ONLY_ACTIVE_ARCH = YES;
162
166
  PRODUCT_NAME = rhoextlib;
163
167
  SDKROOT = iphoneos;
168
+ SKIP_INSTALL = YES;
164
169
  TARGETED_DEVICE_FAMILY = "1,2";
165
170
  };
166
171
  name = Debug;
@@ -179,6 +184,7 @@
179
184
  ONLY_ACTIVE_ARCH = YES;
180
185
  PRODUCT_NAME = rhoextlib;
181
186
  SDKROOT = iphoneos;
187
+ SKIP_INSTALL = YES;
182
188
  TARGETED_DEVICE_FAMILY = "1,2";
183
189
  };
184
190
  name = Release;
@@ -249,6 +255,7 @@
249
255
  ONLY_ACTIVE_ARCH = YES;
250
256
  PRODUCT_NAME = rhoextlib;
251
257
  SDKROOT = iphoneos;
258
+ SKIP_INSTALL = YES;
252
259
  TARGETED_DEVICE_FAMILY = "1,2";
253
260
  };
254
261
  name = Distribution;
@@ -834,6 +834,7 @@
834
834
  ONLY_ACTIVE_ARCH = YES;
835
835
  PRODUCT_NAME = rhorubylib;
836
836
  SDKROOT = iphoneos;
837
+ SKIP_INSTALL = YES;
837
838
  SYMROOT = ../build;
838
839
  };
839
840
  name = Debug;
@@ -855,6 +856,7 @@
855
856
  ONLY_ACTIVE_ARCH = YES;
856
857
  PRODUCT_NAME = rhorubylib;
857
858
  SDKROOT = iphoneos;
859
+ SKIP_INSTALL = YES;
858
860
  SYMROOT = ../build;
859
861
  };
860
862
  name = Release;
@@ -917,6 +919,7 @@
917
919
  ONLY_ACTIVE_ARCH = YES;
918
920
  PRODUCT_NAME = rhorubylib;
919
921
  SDKROOT = iphoneos;
922
+ SKIP_INSTALL = YES;
920
923
  SYMROOT = ../build;
921
924
  };
922
925
  name = Distribution;
@@ -255,7 +255,11 @@
255
255
  isa = PBXProject;
256
256
  buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "rhosynclib" */;
257
257
  compatibilityVersion = "Xcode 3.1";
258
+ developmentRegion = English;
258
259
  hasScannedForEncodings = 1;
260
+ knownRegions = (
261
+ en,
262
+ );
259
263
  mainGroup = 08FB7794FE84155DC02AAC07 /* rhosynclib */;
260
264
  projectDirPath = "";
261
265
  projectRoot = "";
@@ -311,6 +315,7 @@
311
315
  );
312
316
  PRODUCT_NAME = rhosynclib;
313
317
  SDKROOT = iphoneos;
318
+ SKIP_INSTALL = YES;
314
319
  };
315
320
  name = Debug;
316
321
  };
@@ -329,6 +334,7 @@
329
334
  );
330
335
  PRODUCT_NAME = rhosynclib;
331
336
  SDKROOT = iphoneos;
337
+ SKIP_INSTALL = YES;
332
338
  };
333
339
  name = Release;
334
340
  };
@@ -393,6 +399,7 @@
393
399
  );
394
400
  PRODUCT_NAME = rhosynclib;
395
401
  SDKROOT = iphoneos;
402
+ SKIP_INSTALL = YES;
396
403
  };
397
404
  name = Distribution;
398
405
  };
@@ -52,17 +52,11 @@ String CRhodesAppBase::canonicalizeRhoUrl(const String& strUrl)
52
52
  if (strUrl.length() == 0 )
53
53
  return m_strHomeUrl;
54
54
 
55
- if ( strncmp("http://", strUrl.c_str(), 7 ) == 0 ||
56
- strncmp("https://", strUrl.c_str(), 8 ) == 0 ||
57
- strncmp("javascript:", strUrl.c_str(), 11 ) == 0 ||
58
- strncmp("mailto:", strUrl.c_str(), 7) == 0 ||
59
- strncmp("tel:", strUrl.c_str(), 4) == 0 ||
60
- strncmp("wtai:", strUrl.c_str(), 5) == 0 ||
61
- strncmp("sms:", strUrl.c_str(), 4) == 0
62
- )
63
- return strUrl;
64
-
65
- return CFilePath::join(m_strHomeUrl,strUrl);
55
+ size_t pos = strUrl.find_first_of(":#");
56
+ if((pos == String::npos) || (strUrl.at(pos) == '#'))
57
+ return CFilePath::join(m_strHomeUrl,strUrl);
58
+
59
+ return strUrl;
66
60
  }
67
61
 
68
62
  } //namespace common
@@ -446,7 +446,7 @@ void CSyncEngine::checkSourceAssociations()
446
446
  {
447
447
  Hashtable<String, int> hashPassed;
448
448
 
449
- for( int nCurSrc = m_sources.size()-1; nCurSrc > 0 ; )
449
+ for( int nCurSrc = m_sources.size()-1; nCurSrc >= 0 ; )
450
450
  {
451
451
  CSyncSource& oCurSrc = *(m_sources.elementAt(nCurSrc));
452
452
  if ( oCurSrc.getAssociations().size() == 0 || hashPassed.containsKey(oCurSrc.getName()) )
@@ -458,6 +458,9 @@ void CSyncEngine::checkSourceAssociations()
458
458
  {
459
459
  const CSyncSource::CAssociation& oAssoc = oCurSrc.getAssociations().elementAt(i);
460
460
  int nAssocSrcIndex = findSrcIndex( m_sources, oAssoc.m_strSrcName);
461
+ if ( nAssocSrcIndex >= 0 )
462
+ m_sources.elementAt(nAssocSrcIndex)->addBelongsTo( oAssoc.m_strAttrib, oCurSrc.getID() );
463
+
461
464
  if ( nAssocSrcIndex >=0 && nAssocSrcIndex < nSrc )
462
465
  {
463
466
  m_sources.removeElementAt( nSrc, false );
@@ -123,9 +123,13 @@ void CSyncSource::sync()
123
123
  if ( isEmptyToken() )
124
124
  processToken(1);
125
125
 
126
+ syncClientChanges();
127
+ syncServerChanges();
128
+ /*
126
129
  boolean bSyncedServer = syncClientChanges();
127
130
  if ( !bSyncedServer )
128
131
  syncServerChanges();
132
+ */
129
133
  }
130
134
 
131
135
  CTimeInterval endTime = CTimeInterval::getCurrentTime();
@@ -137,6 +141,22 @@ void CSyncSource::sync()
137
141
  getID() );
138
142
  }
139
143
 
144
+ void CSyncSource::syncClientChanges()
145
+ {
146
+ PROF_START("Pull");
147
+
148
+ boolean bSyncClient = true;
149
+ {
150
+ IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? and sent<=1 LIMIT 1 OFFSET 0", getID());
151
+ bSyncClient = !res.isEnd();
152
+ }
153
+ if ( bSyncClient )
154
+ doSyncClientChanges();
155
+
156
+ PROF_STOP("Pull");
157
+ }
158
+
159
+ /*
140
160
  boolean CSyncSource::syncClientChanges()
141
161
  {
142
162
  boolean bSyncedServer = false;
@@ -177,6 +197,66 @@ boolean CSyncSource::isPendingClientChanges()
177
197
  {
178
198
  IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? and update_type='create' and sent>1 LIMIT 1 OFFSET 0", getID());
179
199
  return !res.isEnd();
200
+ }*/
201
+
202
+ void CSyncSource::addBelongsTo(const String& strAttrib, int nSrcID)
203
+ {
204
+ m_hashBelongsTo.put(strAttrib, nSrcID);
205
+ }
206
+
207
+ int CSyncSource::getBelongsToSrcID(const String& strAttrib)
208
+ {
209
+ if ( m_hashBelongsTo.containsKey(strAttrib) )
210
+ return m_hashBelongsTo.get(strAttrib);
211
+
212
+ return -1;
213
+ }
214
+
215
+ void CSyncSource::checkIgnorePushObjects()
216
+ {
217
+ // ignore changes in pending creates
218
+ {
219
+ IDBResult res = getDB().executeSQL("SELECT distinct(object) FROM changed_values where source_id=? and sent>=2", getID() );
220
+ for( ; !res.isEnd(); res.next() )
221
+ {
222
+ String strObject = res.getStringByIdx(0);
223
+ m_hashIgnorePushObjects.put(strObject, 1);
224
+ }
225
+ }
226
+
227
+ //check for belongs_to
228
+ String strAttribQuests = "";
229
+ Vector<String> arValues;
230
+ arValues.addElement(convertToStringA(getID()));
231
+ for ( Hashtable<String,int>::iterator it = m_hashBelongsTo.begin(); it != m_hashBelongsTo.end(); ++it )
232
+ {
233
+ if ( strAttribQuests.length() > 0 )
234
+ strAttribQuests += ",";
235
+
236
+ strAttribQuests += "?";
237
+ arValues.addElement(it->first);
238
+ }
239
+
240
+ if ( strAttribQuests.length() > 0 )
241
+ {
242
+ IDBResult res = getDB().executeSQLEx( (String("SELECT object, attrib, value FROM changed_values where source_id=? and sent<=1 and attrib IN ( ") + strAttribQuests + " )").c_str(),
243
+ arValues );
244
+
245
+ for( ; !res.isEnd(); res.next() )
246
+ {
247
+ String strObject = res.getStringByIdx(0);
248
+ String strAttrib = res.getStringByIdx(1);
249
+ String strValue = res.getStringByIdx(2);
250
+
251
+ IDBResult res2 = getDB().executeSQL(
252
+ "SELECT object FROM changed_values where source_id=? and sent>=2 and object=? LIMIT 1 OFFSET 0",
253
+ getBelongsToSrcID(strAttrib), strValue );
254
+
255
+ if (!res2.isEnd())
256
+ m_hashIgnorePushObjects.put(strObject, 1);
257
+
258
+ }
259
+ }
180
260
  }
181
261
 
182
262
  void CSyncSource::doSyncClientChanges()
@@ -189,6 +269,10 @@ void CSyncSource::doSyncClientChanges()
189
269
  String strBody = "{\"source_name\":" + CJSONEntry::quoteValue(getName()) + ",\"client_id\":" + CJSONEntry::quoteValue(getSync().getClientID());
190
270
  boolean bSend = false;
191
271
  int i = 0;
272
+
273
+ getDB().Lock();
274
+ checkIgnorePushObjects();
275
+
192
276
  for( i = 0; i < 3 && getSync().isContinueSync(); i++ )
193
277
  {
194
278
  String strBody1;
@@ -215,6 +299,8 @@ void CSyncSource::doSyncClientChanges()
215
299
  }
216
300
  strBody += "}";
217
301
 
302
+ getDB().Unlock();
303
+
218
304
  if ( bSend )
219
305
  {
220
306
  LOG(INFO) + "Push client changes to server. Source: " + getName() + "Size :" + strBody.length();
@@ -308,6 +394,9 @@ void CSyncSource::makePushBody_Ver3(String& strBody, const String& strUpdateType
308
394
  String value = res.getStringByIdx(2);
309
395
  String attribType = res.getStringByIdx(3);
310
396
 
397
+ if ( m_hashIgnorePushObjects.containsKey(strObject) )
398
+ continue;
399
+
311
400
  if ( attribType.compare("blob.file") == 0 )
312
401
  {
313
402
  CMultipartItem* pItem = new CMultipartItem();
@@ -62,6 +62,8 @@ private:
62
62
  Vector<CAssociation> m_arAssociations;
63
63
  VectorPtr<net::CMultipartItem*> m_arMultipartItems;
64
64
  Vector<String> m_arBlobAttrs;
65
+ Hashtable<String,int> m_hashIgnorePushObjects;
66
+ Hashtable<String,int> m_hashBelongsTo;
65
67
 
66
68
  public:
67
69
  int m_nErrCode;
@@ -70,7 +72,7 @@ public:
70
72
  public:
71
73
  CSyncSource(int id, const String& strName, const String& strSyncType, db::CDBAdapter& db, CSyncEngine& syncEngine );
72
74
  virtual void sync();
73
- virtual boolean syncClientChanges();
75
+ virtual void syncClientChanges();
74
76
 
75
77
  int getID()const { return m_nID; }
76
78
  String getName() { return m_strName; }
@@ -100,7 +102,11 @@ public:
100
102
  CSyncSource(CSyncEngine& syncEngine, db::CDBAdapter& db );
101
103
 
102
104
  void doSyncClientChanges();
103
- boolean isPendingClientChanges();
105
+ void checkIgnorePushObjects();
106
+ int getBelongsToSrcID(const String& strAttrib);
107
+ void addBelongsTo(const String& strAttrib, int nSrcID);
108
+
109
+ //boolean isPendingClientChanges();
104
110
 
105
111
  void syncServerChanges();
106
112
  void makePushBody_Ver3(String& strBody, const String& strUpdateType, boolean isSync);
@@ -30,12 +30,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "syncengine", "syncengine\sy
30
30
  Release.AspNetCompiler.Debug = "False"
31
31
  EndProjectSection
32
32
  EndProject
33
- Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tcmalloc", "tcmalloc\tcmalloc.vcproj", "{DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}"
34
- ProjectSection(WebsiteProperties) = preProject
35
- Debug.AspNetCompiler.Debug = "True"
36
- Release.AspNetCompiler.Debug = "False"
37
- EndProjectSection
38
- EndProject
39
33
  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RhoLib", "RhoLib\RhoLib.vcproj", "{F196A418-11F1-4067-9F4F-BCC7D70E6EC5}"
40
34
  ProjectSection(WebsiteProperties) = preProject
41
35
  Debug.AspNetCompiler.Debug = "True"
@@ -210,34 +204,6 @@ Global
210
204
  {6F57C60E-C083-4D46-A3B9-E17948A33518}.Release|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I)
211
205
  {6F57C60E-C083-4D46-A3B9-E17948A33518}.Release|Windows Mobile 6 Professional SDK (ARMV4I).Build.0 = Release|Windows Mobile 6 Professional SDK (ARMV4I)
212
206
  {6F57C60E-C083-4D46-A3B9-E17948A33518}.Release|Windows Mobile 6 Standard SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I)
213
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Mixed Platforms.ActiveCfg = Debug|RhodesCE6 (ARMV4I)
214
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Mixed Platforms.Build.0 = Debug|RhodesCE6 (ARMV4I)
215
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Mixed Platforms.Deploy.0 = Debug|RhodesCE6 (ARMV4I)
216
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Pocket PC 2003 (ARMV4).ActiveCfg = Debug|RhodesCE6 (ARMV4I)
217
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|RhodesCE6 (ARMV4I).ActiveCfg = Debug|RhodesCE6 (ARMV4I)
218
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|RhodesCE6 (ARMV4I).Build.0 = Debug|RhodesCE6 (ARMV4I)
219
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|RhodesCE6 (ARMV4I).Deploy.0 = Debug|RhodesCE6 (ARMV4I)
220
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Smartphone 2003 (ARMV4).ActiveCfg = Debug|RhodesCE6 (ARMV4I)
221
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Win32.ActiveCfg = Debug|Win32
222
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Win32.Build.0 = Debug|Win32
223
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 6 Professional SDK (ARMV4I)
224
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Windows Mobile 5.0 Smartphone SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 6 Professional SDK (ARMV4I)
225
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 6 Professional SDK (ARMV4I)
226
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Debug|Windows Mobile 6 Standard SDK (ARMV4I).ActiveCfg = Debug|Windows Mobile 6 Professional SDK (ARMV4I)
227
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Mixed Platforms.ActiveCfg = Release|RhodesCE6 (ARMV4I)
228
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Mixed Platforms.Build.0 = Release|RhodesCE6 (ARMV4I)
229
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Mixed Platforms.Deploy.0 = Release|RhodesCE6 (ARMV4I)
230
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Pocket PC 2003 (ARMV4).ActiveCfg = Release|RhodesCE6 (ARMV4I)
231
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|RhodesCE6 (ARMV4I).ActiveCfg = Release|RhodesCE6 (ARMV4I)
232
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|RhodesCE6 (ARMV4I).Build.0 = Release|RhodesCE6 (ARMV4I)
233
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|RhodesCE6 (ARMV4I).Deploy.0 = Release|RhodesCE6 (ARMV4I)
234
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Smartphone 2003 (ARMV4).ActiveCfg = Release|RhodesCE6 (ARMV4I)
235
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Win32.ActiveCfg = Release|Win32
236
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Win32.Build.0 = Release|Win32
237
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I)
238
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Windows Mobile 5.0 Smartphone SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I)
239
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Windows Mobile 6 Professional SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I)
240
- {DCD9FEEA-AEB5-4787-AF75-B8D66C1CDC3B}.Release|Windows Mobile 6 Standard SDK (ARMV4I).ActiveCfg = Release|Windows Mobile 6 Professional SDK (ARMV4I)
241
207
  {F196A418-11F1-4067-9F4F-BCC7D70E6EC5}.Debug|Mixed Platforms.ActiveCfg = Debug|RhodesCE6 (ARMV4I)
242
208
  {F196A418-11F1-4067-9F4F-BCC7D70E6EC5}.Debug|Mixed Platforms.Build.0 = Debug|RhodesCE6 (ARMV4I)
243
209
  {F196A418-11F1-4067-9F4F-BCC7D70E6EC5}.Debug|Mixed Platforms.Deploy.0 = Debug|RhodesCE6 (ARMV4I)
data/rhodes.gemspec CHANGED
@@ -3,7 +3,7 @@ require "lib/rhodes.rb"
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = %q{rhodes}
6
- s.version = Rhodes::VERSION
6
+ s.version = "2.4.1.beta.1"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
9
  s.authors = ["Rhomobile"]
@@ -100,6 +100,7 @@ if !defined?(RHO_WP7)
100
100
  Rho::RhoConfig.syncserver.should == saveSrv
101
101
  end
102
102
  end
103
+
103
104
  it "should not sync without login" do
104
105
  SyncEngine.logged_in.should == 0
105
106
 
@@ -107,6 +108,7 @@ end
107
108
  res['error_code'].to_i.should == ::Rho::RhoError::ERR_CLIENTISNOTLOGGEDIN
108
109
 
109
110
  end
111
+
110
112
  =begin
111
113
  it "should update sources from database" do
112
114
  uniq_sources = Rho::RhoConfig::sources.values
@@ -636,6 +638,102 @@ end
636
638
 
637
639
  end
638
640
 
641
+ it "should NOT push pending created objects" do
642
+ item = getProduct.create({:name => 'Test', :brand => "Rho"})
643
+ records = getTestDB().select_from_table('changed_values','*', 'update_type' => 'create')
644
+ records.length.should == 1
645
+ records[0]['attrib'].should == 'object'
646
+
647
+ err_resp = "[{\"version\":3},{\"token\":\"\"},{\"count\":0},{\"progress_count\":0},{\"total_count\":0},{\"create-error\":{\"" + item.object + "\":{\"name\":\"wrongname\",\"an_attribute\":\"error create\"},\"" + item.object + "-error\":{\"message\":\"error create\"}}}]"
648
+
649
+ SyncEngine.set_source_property(getProduct().get_source_id.to_i(), "rho_server_response", err_resp )
650
+ res = ::Rho::RhoSupport::parse_query_parameters getProduct.sync( "/app/Settings/sync_notify")
651
+
652
+ item.update_attributes({:price => "123"})
653
+
654
+ records2 = getTestDB().select_from_table('changed_values','*', 'update_type' => 'create')
655
+ records2.length.should == ($spec_settings[:schema_model] ? 7 : 2)
656
+
657
+ records2 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'create', "sent"=>0})
658
+ records2.length.should == 0
659
+
660
+ records3 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'update', "sent"=>0})
661
+ records3.length.should == 1
662
+
663
+ SyncEngine.set_source_property(getProduct().get_source_id.to_i(), "rho_server_response", err_resp )
664
+ res = ::Rho::RhoSupport::parse_query_parameters getProduct.sync( "/app/Settings/sync_notify")
665
+
666
+ records3 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'update', "sent"=>1})
667
+ records3.length.should == 1
668
+
669
+ end
670
+
671
+ it "should push when pending created objects" do
672
+ item = getProduct.create({:name => 'Test', :brand => "Rho"})
673
+ records = getTestDB().select_from_table('changed_values','*', 'update_type' => 'create')
674
+ records.length.should == 1
675
+ records[0]['attrib'].should == 'object'
676
+
677
+ err_resp = "[{\"version\":3},{\"token\":\"\"},{\"count\":0},{\"progress_count\":0},{\"total_count\":0},{\"create-error\":{\"" + item.object + "\":{\"name\":\"wrongname\",\"an_attribute\":\"error create\"},\"" + item.object + "-error\":{\"message\":\"error create\"}}}]"
678
+
679
+ SyncEngine.set_source_property(getProduct().get_source_id.to_i(), "rho_server_response", err_resp )
680
+ res = ::Rho::RhoSupport::parse_query_parameters getProduct.sync( "/app/Settings/sync_notify")
681
+
682
+ item2 = getProduct.create({:name => 'Test2', :brand => "Rho2"})
683
+ records2 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'create', "sent"=>0} )
684
+ records2.length.should == 1
685
+ records2[0]['attrib'].should == 'object'
686
+
687
+ SyncEngine.set_source_property(getProduct().get_source_id.to_i(), "rho_server_response", "" )
688
+ res = ::Rho::RhoSupport::parse_query_parameters getProduct.sync( "/app/Settings/sync_notify")
689
+ res['status'].should == 'ok'
690
+ res['error_code'].to_i.should == ::Rho::RhoError::ERR_NONE
691
+
692
+ records2 = getTestDB().select_from_table('changed_values','*')
693
+ records2.length.should == 0
694
+
695
+ item3 = getProduct.find(item2.object)
696
+ item3.should be_nil
697
+
698
+ end
699
+
700
+ it "should NOT push when children pending created objects" do
701
+ cust1 = getCustomer.create( {:first => "CustTest1"})
702
+ cust2 = getCustomer.create( {:first => "CustTest2"})
703
+
704
+ @product_test_name = Rho::RhoConfig.generate_id().to_s
705
+ item = getProduct.create({:name => @product_test_name, :quantity => cust1.object, :sku => cust2.object})
706
+ item2 = getProduct.find(item.object)
707
+ item2.vars.should == item.vars
708
+
709
+ err_resp = "[{\"version\":3},{\"token\":\"\"},{\"count\":0},{\"progress_count\":0},{\"total_count\":0},{\"create-error\":{\"" + cust1.object + "\":{\"name\":\"wrongname\",\"an_attribute\":\"error create\"},\"" + cust1.object + "-error\":{\"message\":\"error create\"}}}]"
710
+ SyncEngine.set_source_property(getCustomer().get_source_id.to_i(), "rho_server_response", err_resp )
711
+ res = ::Rho::RhoSupport::parse_query_parameters getCustomer.sync( "/app/Settings/sync_notify")
712
+
713
+ records2 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'create',
714
+ 'source_id'=>getCustomer().get_source_id.to_i(), 'sent'=>2})
715
+ records2.length.should > 0
716
+ records2 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'create',
717
+ 'source_id'=>getProduct().get_source_id.to_i(), 'sent'=>0})
718
+ records2.length.should > 0
719
+
720
+ SyncEngine.set_source_property(getCustomer().get_source_id.to_i(), "rho_server_response", "" )
721
+ res = ::Rho::RhoSupport::parse_query_parameters getProduct.sync( "/app/Settings/sync_notify")
722
+ res['status'].should == 'ok'
723
+ res['error_code'].to_i.should == ::Rho::RhoError::ERR_NONE
724
+
725
+ getTestDB().select_from_table('changed_values','*')
726
+ records2 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'create',
727
+ 'source_id'=>getCustomer().get_source_id.to_i(), 'sent'=>2})
728
+ records2.length.should > 0
729
+ records2 = getTestDB().select_from_table('changed_values','*', {'update_type' => 'create',
730
+ 'source_id'=>getProduct().get_source_id.to_i(), 'sent'=>1})
731
+ records2.length.should > 0
732
+
733
+ item2 = getProduct.find(item.object)
734
+ item2.vars.should_not be_nil
735
+ end
736
+
639
737
  it "should logout" do
640
738
  SyncEngine.logout()
641
739
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: phone_spec
3
- bbver: 5.0
3
+ bbver: 6.0
4
4
  sdk: /Users/crystax/work/rhomobile/rhodes
5
5
  #applog: rholog.txt
6
6
  version: 1.0.0
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhodes
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease: false
4
+ hash: 62196393
5
+ prerelease: 6
6
6
  segments:
7
7
  - 2
8
8
  - 4
9
- - 0
10
- version: 2.4.0
9
+ - 1
10
+ - beta
11
+ - 1
12
+ version: 2.4.1.beta.1
11
13
  platform: ruby
12
14
  authors:
13
15
  - Rhomobile
@@ -15,8 +17,7 @@ autorequire:
15
17
  bindir: bin
16
18
  cert_chain: []
17
19
 
18
- date: 2011-04-19 00:00:00 -07:00
19
- default_executable:
20
+ date: 2011-04-20 00:00:00 Z
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
22
23
  name: templater
@@ -6268,7 +6269,6 @@ files:
6268
6269
  - spec/phone_spec/Rakefile
6269
6270
  - spec/phone_spec/rhoconfig.txt
6270
6271
  - spec/phone_spec/server.rb
6271
- has_rdoc: true
6272
6272
  homepage: http://www.rhomobile.com
6273
6273
  licenses: []
6274
6274
 
@@ -6299,7 +6299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
6299
6299
  requirements: []
6300
6300
 
6301
6301
  rubyforge_project: rhodes
6302
- rubygems_version: 1.3.7
6302
+ rubygems_version: 1.7.2
6303
6303
  signing_key:
6304
6304
  specification_version: 2
6305
6305
  summary: The Rhodes framework is the easiest way to develop NATIVE apps with full device capabilities (GPS, PIM, camera, etc.) for any smartphone.