jipe 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Jipe
2
+ VERSION = "2.0.0"
3
+ end
metadata CHANGED
@@ -1,75 +1,81 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: jipe
3
- version: !ruby/object:Gem::Version
4
- hash: 23
3
+ version: !ruby/object:Gem::Version
5
4
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- - 0
10
- version: 1.0.0
5
+ version: 2.0.0
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Nat Budin
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-03-15 00:00:00 -04:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- prerelease: false
23
- type: :development
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
12
+ date: 2013-06-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
27
17
  - - ~>
28
- - !ruby/object:Gem::Version
29
- hash: 23
30
- segments:
31
- - 1
32
- - 0
33
- - 0
34
- version: 1.0.0
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ none: false
35
21
  name: bundler
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
22
+ type: :development
38
23
  prerelease: false
24
+ requirement: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ version: '1.3'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ none: false
37
+ name: rake
39
38
  type: :development
40
- requirement: &id002 !ruby/object:Gem::Requirement
39
+ prerelease: false
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
41
45
  none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- hash: 7
46
- segments:
47
- - 1
48
- - 5
49
- - 2
50
- version: 1.5.2
51
- name: jeweler
52
- version_requirements: *id002
53
- description:
54
- email: natbudin@gmail.com
46
+ - !ruby/object:Gem::Dependency
47
+ version_requirements: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: 3.0.0
52
+ none: false
53
+ name: rails
54
+ type: :development
55
+ prerelease: false
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: 3.0.0
61
+ none: false
62
+ description: An in-place editor for Jester
63
+ email:
64
+ - natbudin@gmail.com
55
65
  executables: []
56
-
57
66
  extensions: []
58
-
59
- extra_rdoc_files:
60
- - README
61
- files:
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
62
70
  - Gemfile
63
71
  - Gemfile.lock
72
+ - LICENSE.txt
64
73
  - README
74
+ - README.md
65
75
  - Rakefile
66
- - VERSION
76
+ - app/assets/images/edit-field.png
77
+ - app/assets/javascripts/jipe.js
67
78
  - app/controllers/jipe_controller.rb
68
- - app/views/jipe/jester.js.erb
69
- - app/views/jipe/jipe.js.erb
70
- - assets/images/edit-field.png
71
- - assets/javascripts/jester.js
72
- - assets/javascripts/jipe.js
73
79
  - generators/jipe/USAGE
74
80
  - generators/jipe/jipe_generator.rb
75
81
  - generators/jipe/templates/edit-field.png
@@ -77,43 +83,35 @@ files:
77
83
  - install.rb
78
84
  - jipe.gemspec
79
85
  - lib/jipe.rb
86
+ - lib/jipe/version.rb
80
87
  - rails/init.rb
81
88
  - tasks/jipe_tasks.rake
82
- - test/jipe_test.rb
83
89
  - uninstall.rb
84
- has_rdoc: true
85
- homepage: http://github.com/nbudin/jipe
86
- licenses:
90
+ - vendor/assets/javascripts/jester.js
91
+ homepage: ''
92
+ licenses:
87
93
  - MIT
88
94
  post_install_message:
89
95
  rdoc_options: []
90
-
91
- require_paths:
96
+ require_paths:
92
97
  - lib
93
- required_ruby_version: !ruby/object:Gem::Requirement
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
94
103
  none: false
95
- requirements:
96
- - - ">="
97
- - !ruby/object:Gem::Version
98
- hash: 3
99
- segments:
100
- - 0
101
- version: "0"
102
- required_rubygems_version: !ruby/object:Gem::Requirement
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
103
109
  none: false
104
- requirements:
105
- - - ">="
106
- - !ruby/object:Gem::Version
107
- hash: 3
108
- segments:
109
- - 0
110
- version: "0"
111
110
  requirements: []
112
-
113
111
  rubyforge_project:
114
- rubygems_version: 1.5.0
112
+ rubygems_version: 1.8.23
115
113
  signing_key:
116
114
  specification_version: 3
117
- summary: RESTful In-place editors for Rails using Jester
118
- test_files:
119
- - test/jipe_test.rb
115
+ summary: A clone of Prototype's in-place edit controls for Thoughtbot's jester.js. You
116
+ might not wanna use this now that jQuery exists, but, in case you do, here it is.
117
+ test_files: []
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.0.0
@@ -1,877 +0,0 @@
1
- // Jester version 1.5
2
- // Released October 25th, 2007
3
-
4
- // Compatible, tested with Prototype 1.6.0.2
5
-
6
- // Copyright 2007, thoughtbot, inc.
7
- // Released under the MIT License.
8
-
9
- Jester = {}
10
- Jester.Resource = function(){};
11
-
12
- // Doing it this way forces the validation of the syntax but gives flexibility enough to rename the new class.
13
- Jester.Constructor = function(model){
14
- return (function CONSTRUCTOR() {
15
- this.klass = CONSTRUCTOR;
16
- this.initialize.apply(this, arguments);
17
- this.after_initialization.apply(this, arguments);
18
- }).toString().replace(/CONSTRUCTOR/g, model);
19
- }
20
-
21
- // universal Jester callback holder for remote JSON loading
22
- var jesterCallback = null;
23
-
24
- Object.extend(Jester.Resource, {
25
- model: function(model, options)
26
- {
27
- var new_model = null;
28
- new_model = eval(model + " = " + Jester.Constructor(model));
29
- new_model.prototype = new Jester.Resource();
30
- Object.extend(new_model, Jester.Resource);
31
-
32
- // We delay instantiating XML.ObjTree() so that it can be listed at the end of this file instead of the beginning
33
- if (!Jester.Tree) {
34
- Jester.Tree = new XML.ObjTree();
35
- Jester.Tree.attr_prefix = "@";
36
- }
37
- if (!options) options = {};
38
-
39
- var default_options = {
40
- format: "xml",
41
- singular: model.underscore(),
42
- name: model,
43
- defaultParams: {}
44
- }
45
- options = Object.extend(default_options, options);
46
- options.format = options.format.toLowerCase();
47
- options.plural = options.singular.pluralize(options.plural);
48
- options.singular_xml = options.singular.replace(/_/g, "-");
49
- options.plural_xml = options.plural.replace(/_/g, "-");
50
- options.remote = false;
51
-
52
- // Establish prefix
53
- var default_prefix = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ":" + window.location.port : "");
54
- if (options.prefix && options.prefix.match(/^https?:/))
55
- options.remote = true;
56
-
57
- if (!options.prefix)
58
- options.prefix = default_prefix;
59
-
60
- if (!options.prefix.match(/^(https?|file):/))
61
- options.prefix = default_prefix + (options.prefix.match(/^\//) ? "" : "/") + options.prefix;
62
-
63
- options.prefix = options.prefix.replace(/\b\/+$/,"");
64
-
65
- // Establish custom URLs
66
- options.urls = Object.extend(this._default_urls(options), options.urls);
67
-
68
- // Assign options to model
69
- new_model.name = model;
70
- new_model.options = options;
71
- for(var opt in options)
72
- new_model["_" + opt] = options[opt];
73
-
74
- // Establish custom URL helpers
75
- for (var url in options.urls)
76
- eval('new_model._' + url + '_url = function(params) {return this._url_for("' + url + '", params);}');
77
-
78
- if (options.checkNew)
79
- this.buildAttributes(new_model, options);
80
-
81
- if (window)
82
- window[model] = new_model;
83
-
84
- return new_model;
85
- },
86
-
87
- buildAttributes: function(model, options) {
88
- model = model || this;
89
- var async = options.asynchronous;
90
-
91
- if (async == null)
92
- async = true;
93
-
94
- var buildWork = bind(model, function(doc) {
95
- if (this._format == "json")
96
- this._attributes = this._attributesFromJSON(doc);
97
- else
98
- this._attributes = this._attributesFromTree(doc[this._singular_xml]);
99
- });
100
- model.requestAndParse(options.format, buildWork, model._new_url(), {asynchronous: async});
101
- },
102
-
103
- loadRemoteJSON : function(url, callback, user_callback) {
104
- // tack on user_callback if there is one, and only if it's really a function
105
- if (typeof(user_callback) == "function")
106
- jesterCallback = function(doc) {user_callback(callback(doc));}
107
- else
108
- jesterCallback = callback;
109
-
110
- var script = document.createElement("script");
111
- script.type = "text/javascript";
112
-
113
- if (url.indexOf("?") == -1)
114
- url += "?";
115
- else
116
- url += "&";
117
- url += "callback=jesterCallback";
118
- script.src = url;
119
-
120
- document.firstChild.appendChild(script);
121
- },
122
-
123
- requestAndParse : function(format, callback, url, options, user_callback, remote) {
124
- if (remote && format == "json" && user_callback)
125
- return this.loadRemoteJSON(url, callback, user_callback)
126
-
127
- parse_and_callback = null;
128
- if (format.toLowerCase() == "json") {
129
- parse_and_callback = function(transport) {
130
- if (transport.status == 500) return callback(null);
131
- eval("var attributes = " + transport.responseText); // hashes need this kind of eval
132
- return callback(attributes);
133
- }
134
- } else {
135
- parse_and_callback = function(transport) {
136
- if (transport.status == 500) return callback(null);
137
- return callback(Jester.Tree.parseXML(transport.responseText));
138
- }
139
- }
140
-
141
- // most parse requests are going to be a GET
142
- if (!(options.postBody || options.parameters || options.postbody || options.method == "post")) {
143
- options.method = "get";
144
- }
145
-
146
- return this.request(parse_and_callback, url, options, user_callback);
147
- },
148
-
149
- // Helper to aid in handling either async or synchronous requests
150
- request : function(callback, url, options, user_callback) {
151
- if (user_callback) {
152
- options.asynchronous = true;
153
- // if an options hash was given instead of a callback
154
- if (typeof(user_callback) == "object") {
155
- for (var x in user_callback)
156
- options[x] = user_callback[x];
157
- user_callback = options.onComplete;
158
- }
159
- }
160
- else
161
- user_callback = function(arg){return arg;}
162
-
163
- if (options.asynchronous) {
164
- options.onComplete = function(transport, json) {user_callback(callback(transport), json);}
165
- return new Ajax.Request(url, options).transport;
166
- }
167
- else
168
- {
169
- options.asynchronous = false; // Make sure it's set, to avoid being overridden.
170
- return callback(new Ajax.Request(url, options).transport);
171
- }
172
- },
173
-
174
- find : function(id, params, callback) {
175
- // allow a params hash to be omitted and a callback function given directly
176
- if (!callback && typeof(params) == "function") {
177
- callback = params;
178
- params = null;
179
- }
180
-
181
- var findAllWork = bind(this, function(doc) {
182
- if (!doc) return null;
183
-
184
- var collection = this._loadCollection(doc);
185
-
186
- if (!collection) return null;
187
-
188
- // This is better than requiring the controller to support a "limit" parameter
189
- if (id == "first")
190
- return collection[0];
191
-
192
- return collection;
193
- });
194
-
195
- var findOneWork = bind(this, function(doc) {
196
- if (!doc) return null;
197
-
198
- var base = this._loadSingle(doc);
199
-
200
- // if there were no properties, it was probably not actually loaded
201
- if (!base || base._properties.length == 0) return null;
202
-
203
- // even if the ID didn't come back, we obviously knew the ID to search with, so set it
204
- if (!base._properties.include("id")) base._setAttribute("id", parseInt(id))
205
-
206
- return base;
207
- });
208
-
209
- if (id == "first" || id == "all") {
210
- var url = this._list_url(params);
211
- return this.requestAndParse(this._format, findAllWork, url, {}, callback, this._remote);
212
- }
213
- else {
214
- if (isNaN(parseInt(id))) return null;
215
- if (!params) params = {};
216
- params.id = id;
217
-
218
- var url = this._show_url(params);
219
- return this.requestAndParse(this._format, findOneWork, url, {}, callback, this._remote);
220
- }
221
- },
222
-
223
- build : function(attributes) {
224
- return new this(attributes);
225
- },
226
-
227
- create : function(attributes, params, callback) {
228
- // allow a params hash to be omitted and a callback function given directly
229
- if (!callback && typeof(params) == "function") {
230
- callback = params;
231
- params = null;
232
- }
233
-
234
- var base = new this(attributes);
235
-
236
- createWork = bind(this, function(saved) {
237
- return callback(base);
238
- });
239
-
240
- if (callback) {
241
- return base.save(createWork);
242
- }
243
- else {
244
- base.save();
245
- return base;
246
- }
247
- },
248
-
249
- // Destroys a REST object. Can be used as follows:
250
- // object.destroy() - when called on an instance of a model, destroys that instance
251
- // Model.destroy(1) - destroys the Model object with ID 1
252
- // Model.destroy({parent: 3, id: 1}) - destroys the Model object with Parent ID 3 and ID 1
253
- //
254
- // Any of these forms can also be passed a callback function as an additional parameter and it works as you expect.
255
- destroy : function(params, callback) {
256
- if (typeof(params) == "function") {
257
- callback = params;
258
- params = null;
259
- }
260
- if (typeof(params) == "number") {
261
- params = {id: params};
262
- }
263
- params.id = params.id || this.id;
264
- if (!params.id) return false;
265
-
266
- var destroyWork = bind(this, function(transport) {
267
- if (transport.status == 200) {
268
- if (!params.id || this.id == params.id)
269
- this.id = null;
270
- return this;
271
- }
272
- else
273
- return false;
274
- });
275
-
276
- return this.request(destroyWork, this._destroy_url(params), {method: "delete"}, callback);
277
- },
278
-
279
- _interpolate: function(string, params) {
280
- if (!params) return string;
281
-
282
- var result = string;
283
- params.each(function(pair) {
284
- var re = new RegExp(":" + pair.key, "g");
285
- if (result.match(re)) {
286
- result = result.replace(re, pair.value);
287
- params.unset(pair.key);
288
- }
289
- });
290
- return result;
291
- },
292
-
293
- _url_for : function(action, params) {
294
- if (!this._urls[action]) return "";
295
- // if an integer is sent, it's assumed just the ID is a parameter
296
- if (typeof(params) == "number") params = {id: params}
297
-
298
- params = Object.extend(Object.clone(this._defaultParams), params);
299
-
300
- if (params) params = $H(params);
301
-
302
- var url = this._interpolate(this._prefix + this._urls[action], params)
303
- return url + (params && params.any() ? "?" + params.toQueryString() : "");
304
- },
305
-
306
- _default_urls : function(options) {
307
- urls = {
308
- 'show' : "/" + options.plural + "/:id." + options.format,
309
- 'list' : "/" + options.plural + "." + options.format,
310
- 'new' : "/" + options.plural + "/new." + options.format
311
- }
312
- urls.create = urls.list;
313
- urls.destroy = urls.update = urls.show;
314
-
315
- return urls;
316
- },
317
-
318
- // Converts a JSON hash returns from ActiveRecord::Base#to_json into a hash of attribute values
319
- // Does not handle associations, as AR's #to_json doesn't either
320
- // Also, JSON doesn't include room to store types, so little auto-transforming is done here (just on 'id')
321
- _attributesFromJSON : function(json) {
322
- if (!json || json.constructor != Object) return false;
323
- if (json.attributes) json = json.attributes;
324
-
325
- var attributes = {};
326
- var i = 0;
327
- for (var attr in json) {
328
- var value = json[attr];
329
- if (attr == "id")
330
- value = parseInt(value);
331
- else if (attr.match(/(created_at|created_on|updated_at|updated_on)/)) {
332
- var date = Date.parse(value);
333
- if (date && !isNaN(date)) value = date;
334
- }
335
- attributes[attr] = value;
336
- i += 1;
337
- }
338
- if (i == 0) return false; // empty hashes should just return false
339
-
340
- return attributes;
341
- },
342
-
343
- // Converts the XML tree returned from a single object into a hash of attribute values
344
- _attributesFromTree : function(elements) {
345
- var attributes = {}
346
- for (var attr in elements) {
347
- // pull out the value
348
- var value = elements[attr];
349
- if (elements[attr] && elements[attr]["@type"]) {
350
- if (elements[attr]["#text"])
351
- value = elements[attr]["#text"];
352
- else
353
- value = undefined;
354
- }
355
-
356
- // handle empty value (pass it through)
357
- if (!value) {}
358
-
359
- // handle scalars
360
- else if (typeof(value) == "string") {
361
- // perform any useful type transformations
362
- if (elements[attr]["@type"] == "integer") {
363
- var num = parseInt(value);
364
- if (!isNaN(num)) value = num;
365
- }
366
- else if (elements[attr]["@type"] == "boolean")
367
- value = (value == "true");
368
- else if (elements[attr]["@type"] == "datetime") {
369
- var date = Date.parse(value);
370
- if (!isNaN(date)) value = date;
371
- }
372
- }
373
- // handle arrays (associations)
374
- else {
375
- var relation = value; // rename for clarity in the context of an association
376
-
377
- // first, detect if it's has_one/belongs_to, or has_many
378
- var i = 0;
379
- var singular = null;
380
- var has_many = false;
381
- for (var val in relation) {
382
- if (i == 0)
383
- singular = val;
384
- i += 1;
385
- }
386
-
387
- // has_many
388
- if (relation[singular] && typeof(relation[singular]) == "object" && i == 1) {
389
- var value = [];
390
- var plural = attr;
391
- var name = singular.camelize().capitalize();
392
-
393
- // force array
394
- if (!(elements[plural][singular].length > 0))
395
- elements[plural][singular] = [elements[plural][singular]];
396
-
397
- elements[plural][singular].each( bind(this, function(single) {
398
- // if the association hasn't been modeled, do a default modeling here
399
- // hosted object's prefix and format are inherited, singular and plural are set
400
- // from the XML
401
- if (eval("typeof(" + name + ")") == "undefined") {
402
- Jester.Resource.model(name, {prefix: this._prefix, singular: singular, plural: plural, format: this._format});
403
- }
404
- var base = eval(name + ".build(this._attributesFromTree(single))");
405
- value.push(base);
406
- }));
407
- }
408
- // has_one or belongs_to
409
- else {
410
- singular = attr;
411
- var name = singular.capitalize();
412
-
413
- // if the association hasn't been modeled, do a default modeling here
414
- // hosted object's prefix and format are inherited, singular is set from the XML
415
- if (eval("typeof(" + name + ")") == "undefined") {
416
- Jester.Resource.model(name, {prefix: this._prefix, singular: singular, format: this._format});
417
- }
418
- value = eval(name + ".build(this._attributesFromTree(value))");
419
- }
420
- }
421
-
422
- // transform attribute name if needed
423
- attribute = attr.replace(/-/g, "_");
424
- attributes[attribute] = value;
425
- }
426
-
427
- return attributes;
428
- },
429
-
430
- _loadSingle : function(doc) {
431
- var attributes;
432
- if (this._format == "json")
433
- attributes = this._attributesFromJSON(doc);
434
- else
435
- attributes = this._attributesFromTree(doc[this._singular_xml]);
436
-
437
- return this.build(attributes);
438
- },
439
-
440
- _loadCollection : function(doc) {
441
- var collection;
442
- if (this._format == "json") {
443
- collection = doc.map( bind(this, function(item) {
444
- return this.build(this._attributesFromJSON(item));
445
- }));
446
- }
447
- else {
448
- // if only one result, wrap it in an array
449
- if (!Jester.Resource.elementHasMany(doc[this._plural_xml]))
450
- doc[this._plural_xml][this._singular_xml] = [doc[this._plural_xml][this._singular_xml]];
451
-
452
- collection = doc[this._plural_xml][this._singular_xml].map( bind(this, function(elem) {
453
- return this.build(this._attributesFromTree(elem));
454
- }));
455
- }
456
- return collection;
457
- }
458
-
459
- });
460
-
461
- Object.extend(Jester.Resource.prototype, {
462
- initialize : function(attributes) {
463
- // Initialize no attributes, no associations
464
- this._properties = [];
465
- this._associations = [];
466
-
467
- this.setAttributes(this.klass._attributes || {});
468
- this.setAttributes(attributes);
469
-
470
- // Initialize with no errors
471
- this.errors = [];
472
-
473
- // Establish custom URL helpers
474
- for (var url in this.klass._urls)
475
- eval('this._' + url + '_url = function(params) {return this._url_for("' + url + '", params);}');
476
- },
477
- after_initialization: function(){},
478
-
479
- new_record : function() {return !(this.id);},
480
- valid : function() {return ! this.errors.any();},
481
-
482
- reload : function(callback) {
483
- var reloadWork = bind(this, function(copy) {
484
- this._resetAttributes(copy.attributes(true));
485
-
486
- if (callback)
487
- return callback(this);
488
- else
489
- return this;
490
- });
491
-
492
- if (this.id) {
493
- if (callback)
494
- return this.klass.find(this.id, {}, reloadWork);
495
- else
496
- return reloadWork(this.klass.find(this.id));
497
- }
498
- else
499
- return this;
500
- },
501
-
502
- // Destroys a REST object. Can be used as follows:
503
- // object.destroy() - when called on an instance of a model, destroys that instance
504
- // Model.destroy(1) - destroys the Model object with ID 1
505
- // Model.destroy({parent: 3, id: 1}) - destroys the Model object with Parent ID 3 and ID 1
506
- //
507
- // Any of these forms can also be passed a callback function as an additional parameter and it works as you expect.
508
- destroy : function(params, callback) {
509
- if (params === undefined) {
510
- params = {};
511
- }
512
- if (typeof(params) == "function") {
513
- callback = params;
514
- params = {};
515
- }
516
- if (typeof(params) == "number") {
517
- params = {id: params};
518
- }
519
- if (!params.id) {
520
- params.id = this.id;
521
- }
522
- if (!params.id) return false;
523
-
524
- // collect params from instance if we're being called as an instance method
525
- if (this._properties !== undefined) {
526
- (this._properties).each( bind(this, function(value, i) {
527
- if (params[value] === undefined) {
528
- params[value] = this[value];
529
- }
530
- }));
531
- }
532
-
533
- var destroyWork = bind(this, function(transport) {
534
- if (transport.status == 200) {
535
- if (!params.id || this.id == params.id)
536
- this.id = null;
537
- return this;
538
- }
539
- else
540
- return false;
541
- });
542
-
543
- return this.klass.request(destroyWork, this._destroy_url(params), {method: "delete"}, callback);
544
- },
545
-
546
- save : function(params, callback) {
547
- // allow a params hash to be omitted and a callback function given directly
548
- if (!callback && typeof(params) == "function") {
549
- callback = params;
550
- params = null;
551
- }
552
-
553
- var saveWork = bind(this, function(transport) {
554
- var saved = false;
555
-
556
- if (transport.responseText && (transport.responseText.strip() != "")) {
557
- var errors = this._errorsFrom(transport.responseText);
558
- if (errors)
559
- this._setErrors(errors);
560
- else {
561
- var attributes;
562
- if (this.klass._format == "json") {
563
- attributes = this._attributesFromJSON(transport.responseText);
564
- }
565
- else {
566
- var doc = Jester.Tree.parseXML(transport.responseText);
567
- if (doc[this.klass._singular_xml])
568
- attributes = this._attributesFromTree(doc[this.klass._singular_xml]);
569
- }
570
- if (attributes)
571
- this._resetAttributes(attributes);
572
- }
573
- }
574
-
575
- // Get ID from the location header if it's there
576
- if (this.new_record() && transport.status == 201) {
577
- loc = transport.getResponseHeader("location");
578
- if (loc) {
579
- id = parseInt(loc.match(/\/([^\/]*?)(\.\w+)?$/)[1]);
580
- if (!isNaN(id))
581
- this._setProperty("id", id)
582
- }
583
- }
584
-
585
- return (transport.status >= 200 && transport.status < 300 && this.errors.length == 0);
586
- });
587
-
588
- // reset errors
589
- this._setErrors([]);
590
-
591
- var url = null;
592
- var method = null;
593
-
594
- // collect params
595
- var objParams = {};
596
- var urlParams = Object.clone(this.klass._defaultParams);
597
- if (params) {
598
- Object.extend(urlParams, params);
599
- }
600
- (this._properties).each( bind(this, function(value, i) {
601
- objParams[this.klass._singular + "[" + value + "]"] = this[value];
602
- urlParams[value] = this[value];
603
- }));
604
-
605
- // distinguish between create and update
606
- if (this.new_record()) {
607
- url = this._create_url(urlParams);
608
- method = "post";
609
- }
610
- else {
611
- url = this._update_url(urlParams);
612
- method = "put";
613
- }
614
-
615
- // send the request
616
- return this.klass.request(saveWork, url, {parameters: objParams, method: method}, callback);
617
- },
618
-
619
- setAttributes : function(attributes)
620
- {
621
- $H(attributes).each(bind(this, function(attr){ this._setAttribute(attr.key, attr.value) }));
622
- return attributes;
623
- },
624
-
625
- updateAttributes : function(attributes, callback)
626
- {
627
- this.setAttributes(attributes);
628
- return this.save(callback);
629
- },
630
-
631
- // mimics ActiveRecord's behavior of omitting associations, but keeping foreign keys
632
- attributes : function(include_associations) {
633
- var attributes = {}
634
- for (var i=0; i<this._properties.length; i++)
635
- attributes[this._properties[i]] = this[this._properties[i]];
636
- if (include_associations) {
637
- for (var i=0; i<this._associations.length; i++)
638
- attributes[this._associations[i]] = this[this._associations[i]];
639
- }
640
- return attributes;
641
- },
642
-
643
- /*
644
- Internal methods.
645
- */
646
-
647
- _attributesFromJSON: function()
648
- {
649
- return this.klass._attributesFromJSON.apply(this.klass, arguments);
650
- },
651
-
652
- _attributesFromTree: function()
653
- {
654
- return this.klass._attributesFromTree.apply(this.klass, arguments);
655
- },
656
-
657
- _errorsFrom : function(raw) {
658
- if (this.klass._format == "json")
659
- return this._errorsFromJSON(raw);
660
- else
661
- return this._errorsFromXML(raw);
662
- },
663
-
664
- // Pulls errors from JSON
665
- _errorsFromJSON : function(json) {
666
- try {
667
- json = eval(json); // okay for arrays
668
- } catch(e) {
669
- return false;
670
- }
671
-
672
- if (!(json && json.constructor == Array && json[0] && json[0].constructor == Array)) return false;
673
-
674
- return json.map(function(pair) {
675
- return pair[0].capitalize() + " " + pair[1];
676
- });
677
- },
678
-
679
- // Pulls errors from XML
680
- _errorsFromXML : function(xml) {
681
- if (!xml) return false;
682
- var doc = Jester.Tree.parseXML(xml);
683
-
684
- if (doc && doc.errors) {
685
- var errors = [];
686
- if (typeof(doc.errors.error) == "string")
687
- doc.errors.error = [doc.errors.error];
688
-
689
- doc.errors.error.each(function(value, index) {
690
- errors.push(value);
691
- });
692
-
693
- return errors;
694
- }
695
- else return false;
696
- },
697
-
698
- // Sets errors with an array. Could be extended at some point to include breaking error messages into pairs (attribute, msg).
699
- _setErrors : function(errors) {
700
- this.errors = errors;
701
- },
702
-
703
-
704
- // Sets all attributes and associations at once
705
- // Deciding between the two on whether the attribute is a complex object or a scalar
706
- _resetAttributes : function(attributes) {
707
- this._clear();
708
- for (var attr in attributes)
709
- this._setAttribute(attr, attributes[attr]);
710
- },
711
-
712
- _setAttribute : function(attribute, value) {
713
- if (value && typeof(value) == "object" && value.constructor != Date)
714
- this._setAssociation(attribute, value);
715
- else
716
- this._setProperty(attribute, value);
717
- },
718
-
719
- _setProperties : function(properties) {
720
- this._clearProperties();
721
- for (var prop in properties)
722
- this._setProperty(prop, properties[prop])
723
- },
724
-
725
- _setAssociations : function(associations) {
726
- this._clearAssociations();
727
- for (var assoc in associations)
728
- this._setAssociation(assoc, associations[assoc])
729
- },
730
-
731
- _setProperty : function(property, value) {
732
- this[property] = value;
733
- if (!(this._properties.include(property)))
734
- this._properties.push(property);
735
- },
736
-
737
- _setAssociation : function(association, value) {
738
- this[association] = value;
739
- if (!(this._associations.include(association)))
740
- this._associations.push(association);
741
- },
742
-
743
- _clear : function() {
744
- this._clearProperties();
745
- this._clearAssociations();
746
- },
747
-
748
- _clearProperties : function() {
749
- for (var i=0; i<this._properties.length; i++)
750
- this[this._properties[i]] = null;
751
- this._properties = [];
752
- },
753
-
754
- _clearAssociations : function() {
755
- for (var i=0; i<this._associations.length; i++)
756
- this[this._associations[i]] = null;
757
- this._associations = [];
758
- },
759
-
760
- // helper URLs
761
- _url_for : function(action, params) {
762
- if (!params) params = this.id;
763
- if (typeof(params) == "object" && !params.id)
764
- params.id = this.id;
765
-
766
- return this.klass._url_for(action, params);
767
- }
768
-
769
- });
770
-
771
- // Returns true if the element has more objects beneath it, or just 1 or more attributes.
772
- // It's not perfect, this would mess up if an object had only one attribute, and it was an array.
773
- // For now, this is just one of the difficulties of dealing with ObjTree.
774
- Jester.Resource.elementHasMany = function(element) {
775
- var i = 0;
776
- var singular = null;
777
- var has_many = false;
778
- for (var val in element) {
779
- if (i == 0)
780
- singular = val;
781
- i += 1;
782
- }
783
-
784
- return (element[singular] && typeof(element[singular]) == "object" && element[singular].length != null && i == 1);
785
- }
786
-
787
- // This bind function is a modification of the standard Prototype bind function.
788
- // Use this instead of Prototype's when running in XULRunner due to a longstanding
789
- // bug in the javascript interpreter.
790
-
791
- function bind(context, func) {
792
- var __method = func, args = $A(func.arguments), object = context;
793
-
794
- return function() {
795
- return __method.apply(object, args.concat($A(arguments)));
796
- }
797
- }
798
-
799
- // If there is no object already called Resource, we define one to make things a little cleaner for us.
800
- if(typeof(Resource) == "undefined")
801
- Resource = Jester.Resource;
802
-
803
-
804
-
805
-
806
- /*
807
- Inflector library, contributed graciously to Jester by Ryan Schuft.
808
- The library in full is a complete port of Rails' Inflector, though Jester only uses its pluralization.
809
- Its home page can be found at: http://code.google.com/p/inflection-js/
810
- */
811
-
812
- if (!String.prototype.pluralize) String.prototype.pluralize = function(plural) {
813
- var str=this;
814
- if(plural)str=plural;
815
- else {
816
- var uncountable_words=['equipment','information','rice','money','species','series','fish','sheep','moose'];
817
- var uncountable=false;
818
- for(var x=0;!uncountable&&x<uncountable_words.length;x++)uncountable=(uncountable_words[x].toLowerCase()==str.toLowerCase());
819
- if(!uncountable) {
820
- var rules=[
821
- [new RegExp('(m)an$','gi'),'$1en'],
822
- [new RegExp('(pe)rson$','gi'),'$1ople'],
823
- [new RegExp('(child)$','gi'),'$1ren'],
824
- [new RegExp('(ax|test)is$','gi'),'$1es'],
825
- [new RegExp('(octop|vir)us$','gi'),'$1i'],
826
- [new RegExp('(alias|status)$','gi'),'$1es'],
827
- [new RegExp('(bu)s$','gi'),'$1ses'],
828
- [new RegExp('(buffal|tomat)o$','gi'),'$1oes'],
829
- [new RegExp('([ti])um$','gi'),'$1a'],
830
- [new RegExp('sis$','gi'),'ses'],
831
- [new RegExp('(?:([^f])fe|([lr])f)$','gi'),'$1$2ves'],
832
- [new RegExp('(hive)$','gi'),'$1s'],
833
- [new RegExp('([^aeiouy]|qu)y$','gi'),'$1ies'],
834
- [new RegExp('(x|ch|ss|sh)$','gi'),'$1es'],
835
- [new RegExp('(matr|vert|ind)ix|ex$','gi'),'$1ices'],
836
- [new RegExp('([m|l])ouse$','gi'),'$1ice'],
837
- [new RegExp('^(ox)$','gi'),'$1en'],
838
- [new RegExp('(quiz)$','gi'),'$1zes'],
839
- [new RegExp('s$','gi'),'s'],
840
- [new RegExp('$','gi'),'s']
841
- ];
842
- var matched=false;
843
- for(var x=0;!matched&&x<=rules.length;x++) {
844
- matched=str.match(rules[x][0]);
845
- if(matched)str=str.replace(rules[x][0],rules[x][1]);
846
- }
847
- }
848
- }
849
- return str;
850
- };
851
-
852
- /*
853
-
854
- This is a lighter form of ObjTree, with parts Jester doesn't use removed.
855
- Compressed using http://dean.edwards.name/packer/.
856
- Homepage: http://www.kawa.net/works/js/xml/objtree-e.html
857
-
858
- XML.ObjTree -- XML source code from/to JavaScript object like E4X
859
-
860
- Copyright (c) 2005-2006 Yusuke Kawasaki. All rights reserved.
861
- This program is free software; you can redistribute it and/or
862
- modify it under the Artistic license. Or whatever license I choose,
863
- which I will do instead of keeping this documentation like it is.
864
-
865
- */
866
-
867
- eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('5(p(o)==\'w\')o=v(){};o.r=v(){m 9};o.r.1i="0.1b";o.r.u.14=\'<?L 1s="1.0" 1o="1n-8" ?>\\n\';o.r.u.Y=\'-\';o.r.u.1c=\'1a/L\';o.r.u.N=v(a){6 b;5(W.U){6 c=K U();6 d=c.1r(a,"1p/L");5(!d)m;b=d.A}q 5(W.10){c=K 10(\'1k.1h\');c.1g=z;c.1e(a);b=c.A}5(!b)m;m 9.E(b)};o.r.u.1d=v(c,d,e){6 f={};y(6 g 19 d){f[g]=d[g]}5(!f.M){5(p(f.18)=="w"&&p(f.17)=="w"&&p(f.16)=="w"){f.M="15"}q{f.M="13"}}5(e){f.X=V;6 h=9;6 i=e;6 j=f.T;f.T=v(a){6 b;5(a&&a.x&&a.x.A){b=h.E(a.x.A)}q 5(a&&a.J){b=h.N(a.J)}i(b,a);5(j)j(a)}}q{f.X=z}6 k;5(p(S)!="w"&&S.I){f.1q=c;6 l=K S.I(f);5(l)k=l.12}q 5(p(Q)!="w"&&Q.I){6 l=K Q.I(c,f);5(l)k=l.12}5(e)m k;5(k&&k.x&&k.x.A){m 9.E(k.x.A)}q 5(k&&k.J){m 9.N(k.J)}};o.r.u.E=v(a){5(!a)m;9.H={};5(9.P){y(6 i=0;i<9.P.t;i++){9.H[9.P[i]]=1}}6 b=9.O(a);5(9.H[a.F]){b=[b]}5(a.B!=11){6 c={};c[a.F]=b;b=c}m b};o.r.u.O=v(a){5(a.B==7){m}5(a.B==3||a.B==4){6 b=a.G.1j(/[^\\1f-\\1l]/);5(b==1m)m z;m a.G}6 c;6 d={};5(a.D&&a.D.t){c={};y(6 i=0;i<a.D.t;i++){6 e=a.D[i].F;5(p(e)!="Z")C;6 f=a.D[i].G;5(!f)C;e=9.Y+e;5(p(d[e])=="w")d[e]=0;d[e]++;9.R(c,e,d[e],f)}}5(a.s&&a.s.t){6 g=V;5(c)g=z;y(6 i=0;i<a.s.t&&g;i++){6 h=a.s[i].B;5(h==3||h==4)C;g=z}5(g){5(!c)c="";y(6 i=0;i<a.s.t;i++){c+=a.s[i].G}}q{5(!c)c={};y(6 i=0;i<a.s.t;i++){6 e=a.s[i].F;5(p(e)!="Z")C;6 f=9.O(a.s[i]);5(f==z)C;5(p(d[e])=="w")d[e]=0;d[e]++;9.R(c,e,d[e],f)}}}m c};o.r.u.R=v(a,b,c,d){5(9.H[b]){5(c==1)a[b]=[];a[b][a[b].t]=d}q 5(c==1){a[b]=d}q 5(c==2){a[b]=[a[b],d]}q{a[b][a[b].t]=d}};',62,91,'|||||if|var|||this|||||||||||||return||XML|typeof|else|ObjTree|childNodes|length|prototype|function|undefined|responseXML|for|false|documentElement|nodeType|continue|attributes|parseDOM|nodeName|nodeValue|__force_array|Request|responseText|new|xml|method|parseXML|parseElement|force_array|Ajax|addNode|HTTP|onComplete|DOMParser|true|window|asynchronous|attr_prefix|string|ActiveXObject||transport|post|xmlDecl|get|parameters|postbody|postBody|in|text|24|overrideMimeType|parseHTTP|loadXML|x00|async|XMLDOM|VERSION|match|Microsoft|x20|null|UTF|encoding|application|uri|parseFromString|version'.split('|'),0,{}))
868
-
869
- /*
870
-
871
- This is a Date parsing library by Nicholas Barthelemy, packed to keep jester.js light.
872
- Homepage: https://svn.nbarthelemy.com/date-js/
873
- Compressed using http://dean.edwards.name/packer/.
874
-
875
- */
876
-
877
- eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('N.q.F||(N.q.F=t(a){o u.1d().F(a)});O.q.F||(O.q.F=t(a){o\'0\'.1H(a-u.K)+u});O.q.1H||(O.q.1H=t(a){v s=\'\',i=0;2k(i++<a){s+=u}o s});N.q.1j||(N.q.1j=t(){o u.1d().1j()});O.q.1j||(O.q.1j=t(){v n=u,l=n.K,i=-1;2k(i++<l){u.20(i,i+1)==0?n=n.20(1,n.K):i=l}o n});k.1m="2H 2F 2z 2y 2x 2u 2r 3q 3n 3k 3i 3d".1x(" ");k.1o="38 35 2Y 2U 2Q 2O 2M".1x(" ");k.2K="31 28 31 30 31 30 31 31 30 31 30 31".1x(" ");k.1A={2G:"%Y-%m-%d %H:%M:%S",2w:"%Y-%m-%2v%H:%M:%S%T",2s:"%a, %d %b %Y %H:%M:%S %Z",3p:"%d %b %H:%M",3o:"%B %d, %Y %H:%M"};k.3l=-1;k.3j=-2;(t(){v d=k;d["3h"]=1;d["2i"]=1t;d["2h"]=d["2i"]*19;d["2e"]=d["2h"]*19;d["P"]=d["2e"]*24;d["37"]=d["P"]*7;d["34"]=d["P"]*31;d["1q"]=d["P"]*2X;d["2W"]=d["1q"]*10;d["2R"]=d["1q"]*23;d["2P"]=d["1q"]*1t})();k.q.1D||(k.q.1D=t(){o D k(u.1k())});k.q.26||(k.q.26=t(a,b){u.1F(u.1k()+((a||k.P)*(b||1)));o u});k.q.2a||(k.q.2a=t(a,b){u.1F(u.1k()-((a||k.P)*(b||1)));o u});k.q.1Z||(k.q.1Z=t(){u.1Y(0);u.1X(0);u.1U(0);u.1T(0);o u});k.q.1I||(k.q.1I=t(a,b){C(1i a==\'1p\')a=k.1J(a);o 18.2l((u.1k()-a.1k())/(b|k.P))});k.q.1N||(k.q.1N=k.q.1I);k.q.2n||(k.q.2n=t(){d=O(u);o d.1f(-(18.1y(d.K,2)))>3&&d.1f(-(18.1y(d.K,2)))<21?"V":["V","17","16","1a","V"][18.1y(N(d)%10,4)]});k.q.1w||(k.q.1w=t(){v f=(D k(u.1h(),0,1)).1e();o 18.2t((u.1n()+(f>3?f-4:f+3))/7)});k.q.1M=t(){o u.1d().1v(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").1v(/^.*?\\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\\)$/,"$1$2$3")};k.q.2p=t(){o(u.1u()>0?"-":"+")+O(18.2l(u.1u()/19)).F(2)+O(u.1u()%19,2,"0").F(2)};k.q.1n||(k.q.1n=t(){o((k.2o(u.1h(),u.1c(),u.1b()+1,0,0,0)-k.2o(u.1h(),0,1,0,0,0))/k.P)});k.q.2m||(k.q.2m=t(){v a=u.1D();a.15(a.1c()+1);a.L(0);o a.1b()});k.2j||(k.2j=t(a,b){a=(a+12)%12;C(k.1K(b)&&a==1)o 29;o k.3g.3f[a]});k.1K||(k.1K=t(a){o(((a%4)==0)&&((a%23)!=0)||((a%3e)==0))});k.q.1B||(k.q.1B=t(c){C(!u.3c())o\'&3b;\';v d=u;C(k.1A[c.2g()])c=k.1A[c.2g()];o c.1v(/\\%([3a])/g,t(a,b){39(b){E\'a\':o k.1l(d.1e()).1f(0,3);E\'A\':o k.1l(d.1e());E\'b\':o k.13(d.1c()).1f(0,3);E\'B\':o k.13(d.1c());E\'c\':o d.1d();E\'d\':o d.1b().F(2);E\'H\':o d.1G().F(2);E\'I\':o((h=d.1G()%12)?h:12).F(2);E\'j\':o d.1n().F(3);E\'m\':o(d.1c()+1).F(2);E\'M\':o d.36().F(2);E\'p\':o d.1G()<12?\'33\':\'32\';E\'S\':o d.2Z().F(2);E\'U\':o d.1w().F(2);E\'W\':R Q("%W 2V 2T 2S 25");E\'w\':o d.1e();E\'x\':o d.1r("%m/%d/%Y");E\'X\':o d.1r("%I:%M%p");E\'y\':o d.1h().1d().1f(2);E\'Y\':o d.1h();E\'T\':o d.2p();E\'Z\':o d.1M()}})});k.q.1r||(k.q.1r=k.q.1B);k.22=k.1J;k.1J=t(a){C(1i a!=\'1p\')o a;C(a.K==0||(/^\\s+$/).1E(a))o;2N(v i=0;i<k.1g.K;i++){v r=k.1g[i].J.2L(a);C(r)o k.1g[i].G(r)}o D k(k.22(a))};k.13||(k.13=t(c){v d=-1;C(1i c==\'2J\'){o k.1m[c.1c()]}2I C(1i c==\'27\'){d=c-1;C(d<0||d>11)R D Q("1s 1C 2b 2q 1W 1V 2d 1 2c 12:"+d);o k.1m[d]}v m=k.1m.1S(t(a,b){C(D 1O("^"+c,"i").1E(a)){d=b;o 1R}o 2f});C(m.K==0)R D Q("1s 1C 1p");C(m.K>1)R D Q("1Q 1C");o k.1m[d]});k.1l||(k.1l=t(c){v d=-1;C(1i c==\'27\'){d=c-1;C(d<0||d>6)R D Q("1s 1z 2b 2q 1W 1V 2d 1 2c 7");o k.1o[d]}v m=k.1o.1S(t(a,b){C(D 1O("^"+c,"i").1E(a)){d=b;o 1R}o 2f});C(m.K==0)R D Q("1s 1z 1p");C(m.K>1)R D Q("1Q 1z");o k.1o[d]});k.1g||(k.1g=[{J:/(\\d{1,2})\\/(\\d{1,2})\\/(\\d{2,4})/,G:t(a){v d=D k();d.1L(a[3]);d.L(14(a[2],10));d.15(14(a[1],10)-1);o d}},{J:/(\\d{4})(?:-?(\\d{2})(?:-?(\\d{2})(?:[T ](\\d{2})(?::?(\\d{2})(?::?(\\d{2})(?:\\.(\\d+))?)?)?(?:Z|(?:([-+])(\\d{2})(?::?(\\d{2}))?)?)?)?)?)?/,G:t(a){v b=0;v d=D k(a[1],0,1);C(a[2])d.15(a[2]-1);C(a[3])d.L(a[3]);C(a[4])d.1Y(a[4]);C(a[5])d.1X(a[5]);C(a[6])d.1U(a[6]);C(a[7])d.1T(N("0."+a[7])*1t);C(a[9]){b=(N(a[9])*19)+N(a[10]);b*=((a[8]==\'-\')?1:-1)}b-=d.1u();1P=(N(d)+(b*19*1t));d.1F(N(1P));o d}},{J:/^2E/i,G:t(){o D k()}},{J:/^2D/i,G:t(){v d=D k();d.L(d.1b()+1);o d}},{J:/^2C/i,G:t(){v d=D k();d.L(d.1b()-1);o d}},{J:/^(\\d{1,2})(17|16|1a|V)?$/i,G:t(a){v d=D k();d.L(14(a[1],10));o d}},{J:/^(\\d{1,2})(?:17|16|1a|V)? (\\w+)$/i,G:t(a){v d=D k();d.L(14(a[1],10));d.15(k.13(a[2]));o d}},{J:/^(\\d{1,2})(?:17|16|1a|V)? (\\w+),? (\\d{4})$/i,G:t(a){v d=D k();d.L(14(a[1],10));d.15(k.13(a[2]));d.1L(a[3]);o d}},{J:/^(\\w+) (\\d{1,2})(?:17|16|1a|V)?$/i,G:t(a){v d=D k();d.L(14(a[2],10));d.15(k.13(a[1]));o d}},{J:/^(\\w+) (\\d{1,2})(?:17|16|1a|V)?,? (\\d{4})$/i,G:t(a){v d=D k();d.L(14(a[2],10));d.15(k.13(a[1]));d.1L(a[3]);o d}},{J:/^3m (\\w+)$/i,G:t(a){v d=D k();v b=d.1e();v c=k.1l(a[1]);v e=c-b;C(c<=b){e+=7}d.L(d.1b()+e);o d}},{J:/^2B (\\w+)$/i,G:t(a){R D Q("2A 25 3r");}}]);',62,214,'||||||||||||||||||||Date||||return||prototype|||function|this|var|||||||if|new|case|zf|handler|||re|length|setDate||Number|String|DAY|Error|throw||||th||||||||parseMonth|parseInt|setMonth|nd|st|Math|60|rd|getDate|getMonth|toString|getDay|substr|__PARSE_PATTERNS|getFullYear|typeof|rz|getTime|parseDay|MONTH_NAMES|getDayOfYear|DAY_NAMES|string|YEAR|format|Invalid|1000|getTimezoneOffset|replace|getWeek|split|min|day|FORMATS|strftime|month|clone|test|setTime|getHours|str|diff|parse|isLeapYear|setYear|getTimezone|compare|RegExp|time|Ambiguous|true|findAll|setMilliseconds|setSeconds|be|must|setMinutes|setHours|clearTime|substring||__native_parse|100||yet|increment|number|||decrement|index|and|between|HOUR|false|toLowerCase|MINUTE|SECOND|daysInMonth|while|floor|lastDayOfMonth|getOrdinal|UTC|getGMTOffset|value|July|rfc822|round|June|dT|iso8601|May|April|March|Not|last|yes|tom|tod|February|db|January|else|object|DAYS_PER_MONTH|exec|Saturday|for|Friday|MILLENNIUM|Thursday|CENTURY|supported|not|Wednesday|is|DECADE|365|Tuesday|getSeconds|||PM|AM|MONTH|Monday|getMinutes|WEEK|Sunday|switch|aAbBcdHIjmMpSUWwxXyYTZ|nbsp|valueOf|December|400|DAYS_IN_MONTH|Convensions|MILLISECOND|November|ERA|October|EPOCH|next|September|long|short|August|implemented'.split('|'),0,{}))