sproutcore 1.4.3.1 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ *SproutCore 1.4.4 (November 12, 2010)*
2
+
3
+ * Support for custom mime-types
4
+ * Pass in SC.build_mode to the app
5
+
6
+
1
7
  *SproutCore 1.4.3 (October 19, 2010)*
2
8
 
3
9
  * Better handling of Proxy Redirect
@@ -17,6 +23,7 @@
17
23
  * Fixed redundancy in sc-init description
18
24
  * Fixes to allow uppercase files to be found by sc_require.
19
25
 
26
+
20
27
  *SproutCore 1.4.1 (September 21, 2010)*
21
28
 
22
29
  * Fixed string escaping issue in call to YUI Compressor [PDW]
data/VERSION.yml CHANGED
@@ -1,7 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
3
  :minor: 4
4
- :patch: 3.1
5
- :digest: e038ba5746bb757cd0ff2391828c5f03496fbb64
6
- :dist:
7
- frameworks/sproutcore: 7174adeb47aa0930c95ddae79e2c9cf042fded45
4
+ :patch: 4
data/lib/Buildfile CHANGED
@@ -93,7 +93,10 @@ mode :all do
93
93
  # causes the default index.html file to add an overflow:hidden statement
94
94
  # to the body tag. This is usually preferred since it makes drag and drop
95
95
  # look nicer
96
- :hide_body_overflow => true
96
+ :hide_body_overflow => true,
97
+
98
+ # A hash of additional MIME types, i.e. { '.m4a' => 'audio/mp4a-latm' }
99
+ :mime_types => {}
97
100
 
98
101
  end
99
102
 
@@ -1,3 +1,24 @@
1
+ *SproutCore 1.4.4 (November 12, 2010)*
2
+
3
+ * Fix SC.platform.touch for Chrome 9
4
+ * Better docs for setIfChanged
5
+ * Minor documentation fix
6
+ * Minor cleanup to SC.platform
7
+ * Added support for Chrome Frame with :chrome_frame flag in Buildfile
8
+ * Can now parse '1/1/01 1:1:1'-formatted date times. Thanks timgaleckas.
9
+ * Remove unused code in SC.Store#removeDataHash
10
+ * Removed deep flag for clone method
11
+ * Replaced some instances of true with YES
12
+ * Datastore makes deep copies of data hashes instead of shallow copies
13
+ * Added support for making deep copies of an object into SC.copy and into SC.Copyable.copy
14
+ * SC.clone makes deep copies of objects of type SC.T_HASH
15
+ * Removed unnecessary variable declaration and method invokation in writeAttribute
16
+ * Fixed an incorrect statement in the SC.CollectionContent inline documentation.
17
+ * Fixed typo in SC.Animatable fixes
18
+ * Added safety check for SC.Touch.allowDefault
19
+ * Animatable should check that transitions exist before using special case
20
+ * Typos prevent accelerating anything with a right or bottom even if it also has a top/height or left/width
21
+
1
22
  *SproutCore 1.4.3 (October 19, 2010)*
2
23
 
3
24
  * Send a warning to the console when using SC.RecordArray#indexOf or SC.RecordArray#lastIndexOf and providing an object that is
@@ -379,13 +379,16 @@ SC.Animatable = {
379
379
 
380
380
  var nT = newStyle['top'],
381
381
  nB = newStyle['bottom'],
382
+ nH = newStyle['height'],
382
383
  nL = newStyle['left'],
383
- nR = newStyle['right'];
384
+ nR = newStyle['right'],
385
+ nW = newStyle['width'];
384
386
 
385
387
  // NOTE: This needs to match exactly the conditions in layoutStyles
386
388
  if (
387
- (SC.empty(nT) || (!SC.isPercentage(nT) && SC.empty(nB))) &&
388
- (SC.empty(nL) || (!SC.isPercentage(nL) && SC.empty(nR)))
389
+ (SC.empty(nT) || (!SC.isPercentage(nT) && !SC.empty(nH))) &&
390
+ (SC.empty(nL) || (!SC.isPercentage(nL) && !SC.empty(nW))) &&
391
+ (this.transitions && (this.transitions['top'] || this.transitions['left']))
389
392
  ) {
390
393
  specialTransform = YES;
391
394
  this._useSpecialCaseTransform = YES;
@@ -196,7 +196,7 @@ SC.Record = SC.Object.extend(
196
196
  storeKey = this.storeKey,
197
197
  ret = store.readDataHash(storeKey);
198
198
 
199
- if (ret) ret = SC.clone(ret);
199
+ if (ret) ret = SC.clone(ret, YES);
200
200
 
201
201
  return ret;
202
202
  }.property(),
@@ -341,7 +341,6 @@ SC.Record = SC.Object.extend(
341
341
  writeAttribute: function(key, value, ignoreDidChange) {
342
342
  var store = this.get('store'),
343
343
  storeKey = this.storeKey,
344
- status = store.peekStatus(storeKey),
345
344
  attrs;
346
345
 
347
346
  attrs = store.readEditableDataHash(storeKey);
@@ -288,7 +288,7 @@ SC.NestedStore = SC.Store.extend(
288
288
  }
289
289
 
290
290
  if (pstore && editState === SC.Store.EDITABLE) {
291
- this.dataHashes[storeKey] = SC.clone(pstore.dataHashes[storeKey]);
291
+ this.dataHashes[storeKey] = SC.clone(pstore.dataHashes[storeKey], YES);
292
292
  if (!editables) editables = this.editables = [];
293
293
  editables[storeKey] = 1 ; // mark as editable
294
294
 
@@ -326,7 +326,7 @@ SC.Store = SC.Object.extend( /** @scope SC.Store.prototype */ {
326
326
  if (!editables) editables = this.editables = [];
327
327
  if (!editables[storeKey]) {
328
328
  editables[storeKey] = 1 ; // use number to store as dense array
329
- ret = this.dataHashes[storeKey] = SC.clone(ret);
329
+ ret = this.dataHashes[storeKey] = SC.clone(ret, YES);
330
330
  }
331
331
  return ret;
332
332
  },
@@ -408,12 +408,9 @@ SC.Store = SC.Object.extend( /** @scope SC.Store.prototype */ {
408
408
  @returns {SC.Store} reciever
409
409
  */
410
410
  removeDataHash: function(storeKey, status) {
411
- var rev ;
412
-
413
411
  // don't use delete -- that will allow parent dataHash to come through
414
412
  this.dataHashes[storeKey] = null;
415
413
  this.statuses[storeKey] = status || SC.Record.EMPTY;
416
- rev = this.revisions[storeKey] = this.revisions[storeKey]; // copy ref
417
414
 
418
415
  // hash is gone and therefore no longer editable
419
416
  var editables = this.editables;
@@ -35,8 +35,7 @@ SC.LEAF_NODE = 0x0020;
35
35
  or enabled state.
36
36
 
37
37
  You can apply this mixin to a class that you set as a delegate or to the
38
- object you set as content. SC.ArrayControllers automatically implement
39
- this mixin.
38
+ object you set as content.
40
39
 
41
40
  @since SproutCore 1.0
42
41
  */
@@ -104,15 +104,21 @@ SC.Scanner = SC.Object.extend(
104
104
  /**
105
105
  Reads some characters from the string and interprets it as an integer.
106
106
 
107
- @param {integer} len the amount of characters to read
107
+ @param {integer} min_len the minimum amount of characters to read
108
+ @param {integer} max_len optionally the maximum amount of characters to read (defaults to the minimum)
108
109
  @throws {SC.SCANNER_INT_ERROR} if asked to read non numeric characters
109
110
  @returns {integer} the scanned integer
110
111
  */
111
- scanInt: function(len) {
112
- var str = this.scan(len);
113
- var re = new RegExp("\\d{"+len+"}");
114
- if (!str.match(re)) throw SC.SCANNER_INT_ERROR;
115
- return parseInt(str, 10);
112
+ scanInt: function(min_len, max_len) {
113
+ if (max_len === undefined) max_len = min_len;
114
+ var str = this.scan(max_len);
115
+ var re = new RegExp("^\\d{" + min_len + "," + max_len + "}");
116
+ var match = str.match(re);
117
+ if (!match) throw SC.SCANNER_INT_ERROR;
118
+ if (match[0].length < max_len) {
119
+ this.scanLocation += match[0].length - max_len;
120
+ }
121
+ return parseInt(match[0], 10);
116
122
  },
117
123
 
118
124
  /**
@@ -908,14 +914,14 @@ SC.DateTime.mixin(SC.Comparable,
908
914
  case 'b': opts.month = scanner.scanArray(this.abbreviatedMonthNames) + 1; break;
909
915
  case 'B': opts.month = scanner.scanArray(this.monthNames) + 1; break;
910
916
  case 'c': throw "%c is not implemented";
911
- case 'd': opts.day = scanner.scanInt(2); break;
912
- case 'H': opts.hour = scanner.scanInt(2); break;
913
- case 'I': opts.hour = scanner.scanInt(2); break;
917
+ case 'd': opts.day = scanner.scanInt(1, 2); break;
918
+ case 'H': opts.hour = scanner.scanInt(1, 2); break;
919
+ case 'I': opts.hour = scanner.scanInt(1, 2); break;
914
920
  case 'j': throw "%j is not implemented";
915
- case 'm': opts.month = scanner.scanInt(2); break;
916
- case 'M': opts.minute = scanner.scanInt(2); break;
921
+ case 'm': opts.month = scanner.scanInt(1, 2); break;
922
+ case 'M': opts.minute = scanner.scanInt(1, 2); break;
917
923
  case 'p': opts.meridian = scanner.scanArray(['AM', 'PM']); break;
918
- case 'S': opts.second = scanner.scanInt(2); break;
924
+ case 'S': opts.second = scanner.scanInt(1, 2); break;
919
925
  case 'U': throw "%U is not implemented";
920
926
  case 'W': throw "%W is not implemented";
921
927
  case 'w': throw "%w is not implemented";
@@ -23,7 +23,7 @@ SC.platform = {
23
23
 
24
24
  @property {Boolean}
25
25
  */
26
- touch: ('createTouch' in document),
26
+ touch: ('createTouch' in document) && !navigator.userAgent.match('Chrome/9'), // Ugly hack for Chrome 9 issue
27
27
 
28
28
  bounceOnScroll: (/iPhone|iPad|iPod/).test(navigator.platform),
29
29
  pinchToZoom: (/iPhone|iPad|iPod/).test(navigator.platform),
@@ -58,7 +58,8 @@ SC.platform = {
58
58
  screen on an iPhone OS-based device, this property will be true.
59
59
  @property {Boolean}
60
60
  */
61
- standalone: navigator.standalone,
61
+ standalone: !!navigator.standalone,
62
+
62
63
 
63
64
  /**
64
65
  Prefix for browser specific CSS attributes. Calculated later.
@@ -10,7 +10,7 @@ sc_require('system/response');
10
10
  /**
11
11
  @class
12
12
 
13
- Implements support for Ajax requests using XHR, JSON-P and other prototcols.
13
+ Implements support for Ajax requests using XHR and other prototcols.
14
14
 
15
15
  SC.Request is much like an inverted version of the request/response objects
16
16
  you receive when implementing HTTP servers.
@@ -1981,7 +1981,7 @@ SC.Touch.prototype = {
1981
1981
  the hasCustomEventHandling property to YES but does not cancel the event.
1982
1982
  */
1983
1983
  allowDefault: function() {
1984
- this.event.hasCustomEventHandling = YES ;
1984
+ if (this.event) this.event.hasCustomEventHandling = YES ;
1985
1985
  },
1986
1986
 
1987
1987
  /**
@@ -20,18 +20,24 @@ module("SC.DateTime", {
20
20
  }
21
21
  });
22
22
 
23
- function timeShouldBeEqualToHash(t, h) {
23
+ function timeShouldBeEqualToHash(t, h, message) {
24
24
  if (h === undefined) h = options;
25
25
  if (h.timezone === undefined) h.timezone = SC.DateTime.timezone;
26
+ if (message === undefined) message = "%@ of time should be equal to hash";
26
27
 
27
- equals(t.get('year'), h.year , 'year');
28
- equals(t.get('month'), h.month, 'month');
29
- equals(t.get('day'), h.day, 'day');
30
- equals(t.get('hour'), h.hour, 'hour');
31
- equals(t.get('minute'), h.minute, 'minute');
32
- equals(t.get('second'), h.second, 'second');
33
- equals(t.get('millisecond'), h.millisecond, 'millisecond');
34
- equals(t.get('timezone'), h.timezone, 'timezone');
28
+ if (t === null) {
29
+ ok(false, 'Time should not be null');
30
+ return;
31
+ }
32
+
33
+ equals(t.get('year'), h.year , message.fmt('year'));
34
+ equals(t.get('month'), h.month, message.fmt('month'));
35
+ equals(t.get('day'), h.day, message.fmt('day'));
36
+ equals(t.get('hour'), h.hour, message.fmt('hour'));
37
+ equals(t.get('minute'), h.minute, message.fmt('minute'));
38
+ equals(t.get('second'), h.second, message.fmt('second'));
39
+ equals(t.get('millisecond'), h.millisecond, message.fmt('millisecond'));
40
+ equals(t.get('timezone'), h.timezone, message.fmt('timezone'));
35
41
  }
36
42
 
37
43
  function formatTimezone(offset) {
@@ -278,6 +284,21 @@ test('parse', function() {
278
284
  ok(
279
285
  SC.DateTime.parse('Tue 08 May 1985 01:00:22 AM', '%a %d %b %Y %H:%M:%S %p')
280
286
  === null, '1985-05-08 is not a tuesday');
287
+ ok(
288
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
289
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
290
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
291
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
292
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
293
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
294
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
295
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null &&
296
+ SC.DateTime.parse('07/01/20201 18:33:22 %a Z', '%d/%m/%Y %H:%M:%S %%a %Z') === null
297
+ , 'Should be able to fail to parse multiple times');
298
+ timeShouldBeEqualToHash(
299
+ SC.DateTime.parse('1/1/01 0:0:0', '%m/%d/%y %H:%M:%S'),
300
+ { year: 2001, month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 },
301
+ 'Should be able to have single digit for month, day, hour, minute, second');
281
302
  timeShouldBeEqualToHash(
282
303
  SC.DateTime.parse('70-01-01 00:00:00', '%y-%m-%d %H:%M:%S'),
283
304
  { year: 2070, month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 });
@@ -2499,7 +2499,7 @@ SC.View = SC.Responder.extend(SC.DelegateSupport,
2499
2499
  if (!SC.none(lL)) {
2500
2500
  if(SC.isPercentage(lL)) {
2501
2501
  ret.left = (lL*100)+"%"; //percentage left
2502
- } else if (hasAcceleratedLayer && SC.empty(lR)) {
2502
+ } else if (hasAcceleratedLayer && !SC.empty(lW)) {
2503
2503
  translateLeft = Math.floor(lL);
2504
2504
  ret.left = 0;
2505
2505
  } else {
@@ -2581,7 +2581,7 @@ SC.View = SC.Responder.extend(SC.DelegateSupport,
2581
2581
  if (!SC.none(lT)) {
2582
2582
  if(SC.isPercentage(lT)) {
2583
2583
  ret.top = (lT*100)+"%";
2584
- } else if (hasAcceleratedLayer && SC.empty(lB)) {
2584
+ } else if (hasAcceleratedLayer && !SC.empty(lH)) {
2585
2585
  translateTop = Math.floor(lT);
2586
2586
  ret.top = 0;
2587
2587
  } else {
@@ -528,7 +528,6 @@ SC.mixin(/** @scope SC */ {
528
528
 
529
529
  // ..........................................................
530
530
  // OBJECT MANAGEMENT
531
- //
532
531
 
533
532
  /**
534
533
  Empty function. Useful for some operations.
@@ -597,29 +596,32 @@ SC.mixin(/** @scope SC */ {
597
596
  will simply call that method and return the result.
598
597
 
599
598
  @param object {Object} the object to clone
599
+ @param deep {Boolean} if true, a deep copy of the object is made
600
600
  @returns {Object} the cloned object
601
601
  */
602
- copy: function(object) {
603
- var ret = object ;
604
-
602
+ copy: function(object, deep) {
603
+ var ret = object, idx ;
604
+
605
605
  // fast path
606
- if (object && object.isCopyable) return object.copy();
607
-
606
+ if (object) {
607
+ if (object.isCopyable) return object.copy(deep);
608
+ if (object.clone && SC.typeOf(object.clone) === SC.T_FUNCTION) return object.clone();
609
+ }
610
+
608
611
  switch (SC.typeOf(object)) {
609
612
  case SC.T_ARRAY:
610
- if (object.clone && SC.typeOf(object.clone) === SC.T_FUNCTION) {
611
- ret = object.clone() ;
612
- } else ret = object.slice() ;
613
+ ret = object.slice() ;
614
+ if (deep) {
615
+ idx = ret.length;
616
+ while (idx--) ret[idx] = SC.copy(ret[idx], true);
617
+ }
613
618
  break ;
614
619
 
615
620
  case SC.T_HASH:
616
621
  case SC.T_OBJECT:
617
- if (object.clone && SC.typeOf(object.clone) === SC.T_FUNCTION) {
618
- ret = object.clone() ;
619
- } else {
620
- ret = {} ;
621
- for(var key in object) ret[key] = object[key] ;
622
- }
622
+ ret = {};
623
+ for (var key in object) ret[key] = deep ? SC.copy(object[key], true) : object[key];
624
+ break ;
623
625
  }
624
626
 
625
627
  return ret ;
@@ -31,10 +31,11 @@ SC.Copyable = {
31
31
  /**
32
32
  Override to return a copy of the receiver. Default implementation raises
33
33
  an exception.
34
-
34
+
35
+ @param deep {Boolean} if true, a deep copy of the object should be made
35
36
  @returns {Object} copy of receiver
36
37
  */
37
- copy: function() {
38
+ copy: function(deep) {
38
39
  throw "%@.copy() is not implemented";
39
40
  },
40
41
 
@@ -61,4 +62,11 @@ SC.Copyable = {
61
62
 
62
63
  // Make Array copyable
63
64
  SC.mixin(Array.prototype, SC.Copyable);
64
- Array.prototype.copy = Array.prototype.slice;
65
+ Array.prototype.copy = function(deep) {
66
+ var ret = this.slice(), idx;
67
+ if (deep) {
68
+ idx = ret.length;
69
+ while (idx--) ret[idx] = SC.copy(ret[idx], true);
70
+ }
71
+ return ret;
72
+ }
@@ -1149,7 +1149,11 @@ SC.Observable = {
1149
1149
  Sets the property only if the passed value is different from the
1150
1150
  current value. Depending on how expensive a get() is on this property,
1151
1151
  this may be more efficient.
1152
-
1152
+
1153
+ NOTE: By default, the set() method will not set the value unless it has
1154
+ changed. However, this check can skipped by setting .property().indempotent(NO)
1155
+ setIfChanged() may be useful in this case.
1156
+
1153
1157
  @param key {String} the key to change
1154
1158
  @param value {Object} the value to change
1155
1159
  @returns {SC.Observable}
@@ -61,7 +61,31 @@ test("should return a cloned array ", function() {
61
61
  var resultArray = object.clone(arrayA);
62
62
  equals(resultArray[0], arrayA[0], 'check first array item');
63
63
  equals(resultArray[1], arrayA[1], 'check first array item');
64
-
64
+ });
65
+
66
+ test("should return a deeply cloned arrays", function() {
67
+ var original = [{value: 'value1'}, SC.Object.create({value: 'value2'})] ;
68
+ var cloned = SC.clone(original, true);
69
+ original[0].value = 'bogus';
70
+ equals(cloned[0].value, 'value1');
71
+ original[1].set('value', 'bogus');
72
+ equals(cloned[1].get('value'), 'value2');
73
+ });
74
+
75
+ test("should return shallow clones of hashes", function() {
76
+ var original = { foo: 'bar', nested: { key: 'value'}} ;
77
+ var cloned = SC.clone(original) ;
78
+ same(original, cloned);
79
+ cloned.nested.key = 'another value' ;
80
+ equals(original.nested.key, 'another value') ;
81
+ });
82
+
83
+ test("should return deep clones of hashes", function() {
84
+ var original = { foo: 'bar', nested: { key: 'value'}} ;
85
+ var cloned = SC.clone(original, true) ;
86
+ same(original, cloned);
87
+ cloned.nested.key = 'another value' ;
88
+ equals(original.nested.key, 'value') ;
65
89
  });
66
90
 
67
91
  test("should use copy() if isCopyable", function() {
@@ -12,7 +12,7 @@
12
12
  <html<% unless @content_for_html5_manifest.blank? %> manifest="app.manifest"<% end %>>
13
13
  <head>
14
14
  <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
15
- <meta http-equiv="X-UA-Compatible" content="IE=8" />
15
+ <meta http-equiv="X-UA-Compatible" content="IE=8<%= config.chrome_frame ? ',chrome=1' : '' %>" />
16
16
  <meta http-equiv="Content-Script-Type" content="text/javascript" />
17
17
  <meta name="apple-mobile-web-app-capable" content="yes" />
18
18
  <meta name="apple-mobile-web-app-status-bar-style" content="<%= config.status_bar_style || 'default' %>" />
@@ -135,6 +135,8 @@ module SC
135
135
  end
136
136
  end
137
137
 
138
+ ret << %(<script type="text/javascript">SC.buildMode = "#{SC.build_mode}";</script>)
139
+
138
140
  return ret * "\n"
139
141
  end
140
142
 
@@ -149,7 +149,7 @@ module SC
149
149
  headers = {
150
150
  #"Last-Modified" => File.mtime(build_path).httpdate,
151
151
  #"Etag" => File.mtime(build_path).to_i.to_s,
152
- "Content-Type" => mime_type(build_path),
152
+ "Content-Type" => mime_type(build_path, target.config[:mime_types]),
153
153
  "Content-Length" => file_size.to_s,
154
154
  "Expires" => (cacheable ? (Time.now + ONE_YEAR) : Time.now).httpdate
155
155
  }
@@ -324,7 +324,7 @@ module SC
324
324
 
325
325
  # Returns the mime type. Basically this is the Rack mime mapper with
326
326
  # a few bug fixes.
327
- def mime_type(build_path)
327
+ def mime_type(build_path, custom = {})
328
328
  ext = File.extname(build_path)
329
329
 
330
330
  case ext
@@ -333,7 +333,7 @@ module SC
333
333
  when '.ttf'
334
334
  'font/ttf'
335
335
  else
336
- ::Rack::Mime.mime_type(ext, 'text/plain')
336
+ custom[ext] || ::Rack::Mime.mime_type(ext, 'text/plain')
337
337
  end
338
338
 
339
339
  end
metadata CHANGED
@@ -5,9 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 4
8
- - 3
9
- - 1
10
- version: 1.4.3.1
8
+ - 4
9
+ version: 1.4.4
11
10
  platform: ruby
12
11
  authors:
13
12
  - Strobe, Inc., Sprout Systems, Inc. Apple Inc. and contributors
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-11-04 00:00:00 -07:00
17
+ date: 2010-11-12 00:00:00 -08:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency