text changes to registration mail content
[namibia] / public / ape-source / Core / JSON.js
1 /*
2     http://www.JSON.org/json2.js
3     2009-09-29
4
5     Public Domain.
6
7     NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8
9     See http://www.JSON.org/js.html
10
11     This file creates a global JSON object containing two methods: stringify
12     and parse.
13
14         JSON.stringify(value, replacer, space)
15             value       any JavaScript value, usually an object or array.
16
17             replacer    an optional parameter that determines how object
18                         values are stringified for objects. It can be a
19                         function or an array of strings.
20
21             space       an optional parameter that specifies the indentation
22                         of nested structures. If it is omitted, the text will
23                         be packed without extra whitespace. If it is a number,
24                         it will specify the number of spaces to indent at each
25                         level. If it is a string (such as '\t' or ' '),
26                         it contains the characters used to indent at each level.
27
28             This method produces a JSON text from a JavaScript value.
29
30             When an object value is found, if the object contains a toJSON
31             method, its toJSON method will be called and the result will be
32             stringified. A toJSON method does not serialize: it returns the
33             value represented by the name/value pair that should be serialized,
34             or undefined if nothing should be serialized. The toJSON method
35             will be passed the key associated with the value, and this will be
36             bound to the value
37
38             For example, this would serialize Dates as ISO strings.
39
40                 Date.prototype.toJSON = function (key) {
41                     function f(n) {
42                         // Format integers to have at least two digits.
43                         return n < 10 ? '0' + n : n;
44                     }
45
46                     return this.getUTCFullYear()   + '-' +
47                          f(this.getUTCMonth() + 1) + '-' +
48                          f(this.getUTCDate())      + 'T' +
49                          f(this.getUTCHours())     + ':' +
50                          f(this.getUTCMinutes())   + ':' +
51                          f(this.getUTCSeconds())   + 'Z';
52                 };
53
54             You can provide an optional replacer method. It will be passed the
55             key and value of each member, with this bound to the containing
56             object. The value that is returned from your method will be
57             serialized. If your method returns undefined, then the member will
58             be excluded from the serialization.
59
60             If the replacer parameter is an array of strings, then it will be
61             used to select the members to be serialized. It filters the results
62             such that only members with keys listed in the replacer array are
63             stringified.
64
65             Values that do not have JSON representations, such as undefined or
66             functions, will not be serialized. Such values in objects will be
67             dropped; in arrays they will be replaced with null. You can use
68             a replacer function to replace those with JSON values.
69             JSON.stringify(undefined) returns undefined.
70
71             The optional space parameter produces a stringification of the
72             value that is filled with line breaks and indentation to make it
73             easier to read.
74
75             If the space parameter is a non-empty string, then that string will
76             be used for indentation. If the space parameter is a number, then
77             the indentation will be that many spaces.
78
79             Example:
80
81             text = JSON.stringify(['e', {pluribus: 'unum'}]);
82             // text is '["e",{"pluribus":"unum"}]'
83
84
85             text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
86             // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
87
88             text = JSON.stringify([new Date()], function (key, value) {
89                 return this[key] instanceof Date ?
90                     'Date(' + this[key] + ')' : value;
91             });
92             // text is '["Date(---current time---)"]'
93
94
95         JSON.parse(text, reviver)
96             This method parses a JSON text to produce an object or array.
97             It can throw a SyntaxError exception.
98
99             The optional reviver parameter is a function that can filter and
100             transform the results. It receives each of the keys and values,
101             and its return value is used instead of the original value.
102             If it returns what it received, then the structure is not modified.
103             If it returns undefined then the member is deleted.
104
105             Example:
106
107             // Parse the text. Values that look like ISO date strings will
108             // be converted to Date objects.
109
110             myData = JSON.parse(text, function (key, value) {
111                 var a;
112                 if (typeof value === 'string') {
113                     a =
114 /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
115                     if (a) {
116                         return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
117                             +a[5], +a[6]));
118                     }
119                 }
120                 return value;
121             });
122
123             myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
124                 var d;
125                 if (typeof value === 'string' &&
126                         value.slice(0, 5) === 'Date(' &&
127                         value.slice(-1) === ')') {
128                     d = new Date(value.slice(5, -1));
129                     if (d) {
130                         return d;
131                     }
132                 }
133                 return value;
134             });
135
136
137     This is a reference implementation. You are free to copy, modify, or
138     redistribute.
139
140     This code should be minified before deployment.
141     See http://javascript.crockford.com/jsmin.html
142
143     USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
144     NOT CONTROL.
145 */
146
147 /*jslint evil: true, strict: false */
148
149 /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
150     call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
151     getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
152     lastIndex, length, parse, prototype, push, replace, slice, stringify,
153     test, toJSON, toString, valueOf
154 */
155
156
157 // Create a JSON object only if one does not already exist. We create the
158 // methods in a closure to avoid creating global variables.
159
160 if (!this.JSON) {
161     this.JSON = {};
162 }
163
164 (function () {
165
166     var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
167         escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
168         gap,
169         indent,
170         rep;
171
172
173     function quote(string) {
174
175 // If the string contains no control characters, no quote characters, and no
176 // backslash characters, then we can safely slap some quotes around it.
177 // Otherwise we must also replace the offending characters with safe escape
178 // sequences.
179
180                 return '"'+string+'"';
181     }
182
183
184     function str(key, holder) {
185
186 // Produce a string from holder[key].
187
188         var i,          // The loop counter.
189             k,          // The member key.
190             v,          // The member value.
191             length,
192             mind = gap,
193             partial,
194             value = holder[key];
195
196 // If the value has a toJSON method, call it to obtain a replacement value.
197
198         //if (value && typeof value === 'object' &&
199         //        typeof value.toJSON === 'function') {
200         //    value = value.toJSON(key);
201         //}
202
203 // If we were called with a replacer function, then call the replacer to
204 // obtain a replacement value.
205
206         if (typeof rep === 'function') {
207             value = rep.call(holder, key, value);
208         }
209
210 // What happens next depends on the value's type.
211
212         switch (typeof value) {
213         case 'string':
214             return quote(value);
215
216         case 'number':
217
218 // JSON numbers must be finite. Encode non-finite numbers as null.
219
220             return isFinite(value) ? String(value) : 'null';
221
222         case 'boolean':
223         case 'null':
224
225 // If the value is a boolean or null, convert it to a string. Note:
226 // typeof null does not produce 'null'. The case is included here in
227 // the remote chance that this gets fixed someday.
228
229             return String(value);
230
231 // If the type is 'object', we might be dealing with an object or an array or
232 // null.
233
234         case 'object':
235
236 // Due to a specification blunder in ECMAScript, typeof null is 'object',
237 // so watch out for that case.
238
239             if (!value) {
240                 return 'null';
241             }
242
243 // Make an array to hold the partial results of stringifying this object value.
244
245             gap += indent;
246             partial = [];
247
248 // Is the value an array?
249
250             if (Object.prototype.toString.apply(value) === '[object Array]') {
251
252 // The value is an array. Stringify every element. Use null as a placeholder
253 // for non-JSON values.
254
255                 length = value.length;
256                 for (i = 0; i < length; i += 1) {
257                     partial[i] = str(i, value) || 'null';
258                 }
259
260 // Join all of the elements together, separated with commas, and wrap them in
261 // brackets.
262
263                 v = partial.length === 0 ? '[]' :
264                     gap ? '[\n' + gap +
265                             partial.join(',\n' + gap) + '\n' +
266                                 mind + ']' :
267                           '[' + partial.join(',') + ']';
268                 gap = mind;
269                 return v;
270             }
271
272 // If the replacer is an array, use it to select the members to be stringified.
273
274
275 // Otherwise, iterate through all of the keys in the object.
276
277                 for (k in value) {
278                     if (Object.hasOwnProperty.call(value, k)) {
279                         v = str(k, value);
280                         if (v) {
281                             partial.push(quote(k) + (gap ? ': ' : ':') + v);
282                         }
283                     }
284                 }
285
286 // Join all of the member texts together, separated with commas,
287 // and wrap them in braces.
288
289             v = partial.length === 0 ? '{}' :
290                 gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
291                         mind + '}' : '{' + partial.join(',') + '}';
292             gap = mind;
293             return v;
294         }
295     }
296
297 // If the JSON object does not yet have a stringify method, give it one.
298
299     if (
300                 typeof JSON.stringify !== 'function' || 
301                 (
302                         navigator.product == 'Gecko' && 
303                         //There is a know bug with some version of FF 3.5 with the replacer parameters, this test, is to check if the browser havent a bugy version of JSON.stringify 
304                         (function() {
305                                 var tmp = JSON.stringify({x:1}, function (k,v) {
306                                         return typeof v === 'number' ? 3 : v;
307                                 });
308                                 return tmp.x == 1 ? true : false; 
309                         })
310                 )
311         ) {
312
313         JSON.stringify = function (value, replacer, space) {
314                         rep = replacer;
315             return str('', {'': value});
316         };
317     }
318
319
320 // If the JSON object does not yet have a parse method, give it one.
321
322     if (typeof JSON.parse !== 'function') {
323         JSON.parse = function (text, reviver) {
324
325 // The parse method takes a text and an optional reviver function, and returns
326 // a JavaScript value if the text is a valid JSON text.
327
328             var j;
329
330             function walk(holder, key) {
331
332 // The walk method is used to recursively walk the resulting structure so
333 // that modifications can be made.
334
335                 var k, v, value = holder[key];
336                 if (value && typeof value === 'object') {
337                     for (k in value) {
338                         if (Object.hasOwnProperty.call(value, k)) {
339                             v = walk(value, k);
340                             if (v !== undefined) {
341                                 value[k] = v;
342                             } else {
343                                 delete value[k];
344                             }
345                         }
346                     }
347                 }
348                 return reviver.call(holder, key, value);
349             }
350
351
352 // Parsing happens in four stages. In the first stage, we replace certain
353 // Unicode characters with escape sequences. JavaScript handles many characters
354 // incorrectly, either silently deleting them, or treating them as line endings.
355
356             cx.lastIndex = 0;
357             if (cx.test(text)) {
358                 text = text.replace(cx, function (a) {
359                     return '\\u' +
360                         ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
361                 });
362             }
363
364 // In the second stage, we run the text against regular expressions that look
365 // for non-JSON patterns. We are especially concerned with '()' and 'new'
366 // because they can cause invocation, and '=' because it can cause mutation.
367 // But just to be safe, we want to reject all unexpected forms.
368
369 // We split the second stage into 4 regexp operations in order to work around
370 // crippling inefficiencies in IE's and Safari's regexp engines. First we
371 // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
372 // replace all simple value tokens with ']' characters. Third, we delete all
373 // open brackets that follow a colon or comma or that begin the text. Finally,
374 // we look to see that the remaining characters are only whitespace or ']' or
375 // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
376
377             if (/^[\],:{}\s]*$/.
378 test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
379 replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
380 replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
381
382 // In the third stage we use the eval function to compile the text into a
383 // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
384 // in JavaScript: it can begin a block or an object literal. We wrap the text
385 // in parens to eliminate the ambiguity.
386
387                 j = eval('(' + text + ')');
388
389 // In the optional fourth stage, we recursively walk the new structure, passing
390 // each name/value pair to a reviver function for possible transformation.
391
392                 return typeof reviver === 'function' ?
393                     walk({'': j}, '') : j;
394             }
395
396 // If the text is not JSON parseable, then a SyntaxError is thrown.
397
398             throw new SyntaxError('JSON.parse');
399         };
400     }
401 }());